@@ -278,21 +278,8 @@ trait SpaceLogic {
278278 }
279279}
280280
281- object SpaceEngine {
282- private sealed trait Implementability {
283- def show (implicit ctx : Context ) = this match {
284- case SubclassOf (classSyms) => s " SubclassOf( ${classSyms.map(_.show)}) "
285- case other => other.toString
286- }
287- }
288- private case object ClassOrTrait extends Implementability
289- private case class SubclassOf (classSyms : List [Symbol ]) extends Implementability
290- private case object Unimplementable extends Implementability
291- }
292-
293281/** Scala implementation of space logic */
294282class SpaceEngine (implicit ctx : Context ) extends SpaceLogic {
295- import SpaceEngine ._
296283 import tpd ._
297284
298285 private val scalaSomeClass = ctx.requiredClass(" scala.Some" )
@@ -301,77 +288,15 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
301288 private val scalaNilType = ctx.requiredModuleRef(" scala.collection.immutable.Nil" )
302289 private val scalaConsType = ctx.requiredClassRef(" scala.collection.immutable.::" )
303290
304- /** Checks if it's possible to create a trait/class which is a subtype of `tp`.
305- *
306- * - doesn't handle member collisions (will not declare a type unimplementable because of one)
307- * - expects that neither Any nor Object reach it
308- * (this is currently true due to both isSubType and and/or type simplification)
309- *
310- * See [[intersectUnrelatedAtomicTypes ]].
311- */
312- private def implementability (tp : Type ): Implementability = tp.dealias match {
313- case AndType (tp1, tp2) =>
314- (implementability(tp1), implementability(tp2)) match {
315- case (Unimplementable , _) | (_, Unimplementable ) => Unimplementable
316- case (SubclassOf (classSyms1), SubclassOf (classSyms2)) =>
317- (for {
318- sym1 <- classSyms1
319- sym2 <- classSyms2
320- result <-
321- if (sym1 isSubClass sym2) List (sym1)
322- else if (sym2 isSubClass sym1) List (sym2)
323- else Nil
324- } yield result) match {
325- case Nil => Unimplementable
326- case lst => SubclassOf (lst)
327- }
328- case (ClassOrTrait , ClassOrTrait ) => ClassOrTrait
329- case (SubclassOf (clss), _) => SubclassOf (clss)
330- case (_, SubclassOf (clss)) => SubclassOf (clss)
331- }
332- case OrType (tp1, tp2) =>
333- (implementability(tp1), implementability(tp2)) match {
334- case (ClassOrTrait , _) | (_, ClassOrTrait ) => ClassOrTrait
335- case (SubclassOf (classSyms1), SubclassOf (classSyms2)) =>
336- SubclassOf (classSyms1 ::: classSyms2)
337- case (SubclassOf (classSyms), _) => SubclassOf (classSyms)
338- case (_, SubclassOf (classSyms)) => SubclassOf (classSyms)
339- case _ => Unimplementable
340- }
341- case _ : SingletonType =>
342- // singleton types have no instantiable subtypes
343- Unimplementable
344- case tp : RefinedType =>
345- // refinement itself is not considered - it would at most make
346- // a type unimplementable because of a member collision
347- implementability(tp.parent)
348- case other =>
349- val classSym = other.classSymbol
350- if (classSym.exists) {
351- if (classSym is Final ) Unimplementable
352- else if (classSym is Trait ) ClassOrTrait
353- else SubclassOf (List (classSym))
354- } else {
355- // if no class symbol exists, conservatively say that anything
356- // can implement `tp`
357- ClassOrTrait
358- }
359- }
360-
361291 override def intersectUnrelatedAtomicTypes (tp1 : Type , tp2 : Type ) = {
362292 val and = AndType (tp1, tp2)
363293 // Precondition: !(tp1 <:< tp2) && !(tp2 <:< tp1)
364294 // Then, no leaf of the and-type tree `and` is a subtype of `and`.
365- // Then, to create a value of type `and` you must instantiate a trait (class/module)
366- // which is a subtype of all the leaves of `and`.
367- val imp = implementability(and)
295+ val res = inhabited(and)
368296
369- debug.println(s " atomic intersection: ${and.show} ~ ${imp.show }" )
297+ debug.println(s " atomic intersection: ${and.show} = ${res }" )
370298
371- imp match {
372- case Unimplementable => Empty
373- case _ => Typ (and, true )
374- }
299+ if (res) Typ (and, true ) else Empty
375300 }
376301
377302 /* Whether the extractor is irrefutable */
@@ -574,21 +499,97 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
574499
575500 /** Can this type be inhabited by a value?
576501 *
577- * Intersection between singleton types and other types is always empty
578- * the singleton type is not a subtype of the other type.
579- * See patmat/i3573.scala for an example.
502+ * Check is based on the following facts:
503+ *
504+ * - single inheritance of classes
505+ * - final class cannot be extended
506+ * - intersection of a singleton type with another irrelevant type (patmat/i3574.scala)
507+ *
580508 */
581- def inhabited (tpe : Type )(implicit ctx : Context ): Boolean = {
582- val emptySingletonIntersection = new ExistsAccumulator ({
583- case AndType (s : SingletonType , t) =>
584- ! (s <:< t)
585- case AndType (t, s : SingletonType ) =>
586- ! (s <:< t)
587- case x =>
588- false
589- })
590-
591- ! emptySingletonIntersection(false , tpe)
509+ def inhabited (tp : Type )(implicit ctx : Context ): Boolean = {
510+ // convert top-level type shape into "conjunctive normal form"
511+ def cnf (tp : Type ): Type = tp match {
512+ case AndType (OrType (l, r), tp) =>
513+ val tp1 = cnf(tp)
514+ val l1 = cnf(l)
515+ val r1 = cnf(r)
516+ OrType (cnf(AndType (l1, tp1)), cnf(AndType (r1, tp1)))
517+ case AndType (tp, o : OrType ) =>
518+ cnf(AndType (o, tp))
519+ case AndType (l, r) =>
520+ val l1 = cnf(l)
521+ val r1 = cnf(r)
522+ if (l1.ne(l) || r1.ne(r)) cnf(AndType (l1, r1))
523+ else AndType (l1, r1)
524+ case OrType (l, r) =>
525+ OrType (cnf(l), cnf(r))
526+ case tp @ RefinedType (OrType (tp1, tp2), _, _) =>
527+ OrType (
528+ cnf(tp.derivedRefinedType(tp1, refinedName = tp.refinedName, refinedInfo = tp.refinedInfo)),
529+ cnf(tp.derivedRefinedType(tp2, refinedName = tp.refinedName, refinedInfo = tp.refinedInfo))
530+ )
531+ case tp : RefinedType =>
532+ val parent1 = cnf(tp.parent)
533+ val tp1 = tp.derivedRefinedType(parent1, refinedName = tp.refinedName, refinedInfo = tp.refinedInfo)
534+
535+ if (parent1.ne(tp.parent)) cnf(tp1) else tp1
536+ case tp : TypeAlias =>
537+ cnf(tp.alias)
538+ case _ =>
539+ tp
540+ }
541+
542+ def isSingleton (tp : Type ): Boolean = tp.dealias match {
543+ case AndType (l, r) => isSingleton(l) || isSingleton(r)
544+ case OrType (l, r) => isSingleton(l) && isSingleton(r)
545+ case tp => tp.isSingleton
546+ }
547+
548+ def superType (tp : Type ): Type = tp match {
549+ case tp : TypeProxy => tp.superType
550+ case OrType (tp1, tp2) => OrType (superType(tp1), superType(tp2))
551+ case AndType (tp1, tp2) => AndType (superType(tp1), superType(tp2))
552+ case _ => tp
553+ }
554+
555+ def recur (tp : Type ): Boolean = tp.dealias match {
556+ case AndType (tp1, tp2) =>
557+ recur(tp1) && recur(tp2) && {
558+ val bases1 = tp1.widenDealias.classSymbols
559+ val bases2 = tp2.widenDealias.classSymbols
560+
561+ debug.println(s " bases of ${tp1.show}: " + bases1)
562+ debug.println(s " bases of ${tp2.show}: " + bases2)
563+
564+ val noClassConflict =
565+ bases1.forall(sym1 => sym1.is(Trait ) || bases2.forall(sym2 => sym2.is(Trait ) || sym1.isSubClass(sym2))) ||
566+ bases1.forall(sym1 => sym1.is(Trait ) || bases2.forall(sym2 => sym2.is(Trait ) || sym2.isSubClass(sym1)))
567+
568+ debug.println(s " class conflict for ${tp.show}? " + ! noClassConflict)
569+
570+ noClassConflict &&
571+ (! isSingleton(tp1) || tp1 <:< tp2) &&
572+ (! isSingleton(tp2) || tp2 <:< tp1) &&
573+ (! bases1.exists(_ is Final ) || tp1 <:< superType(tp2)) &&
574+ (! bases2.exists(_ is Final ) || tp2 <:< superType(tp1))
575+ }
576+ case OrType (tp1, tp2) =>
577+ recur(tp1) || recur(tp2)
578+ case tp : RefinedType =>
579+ recur(tp.parent)
580+ case tp : TypeRef =>
581+ recur(tp.prefix) &&
582+ ! (tp.classSymbol.is(Sealed ) && tp.classSymbol.is(AbstractOrTrait ) && tp.classSymbol.children.isEmpty) &&
583+ ! (tp.classSymbol.is(AbstractFinal ))
584+ case _ =>
585+ true
586+ }
587+
588+ val res = recur(cnf(tp))
589+
590+ debug.println(s " ${tp.show} inhabited? " + res)
591+
592+ res
592593 }
593594
594595 /** Instantiate type `tp1` to be a subtype of `tp2`
0 commit comments