@@ -278,21 +278,8 @@ trait SpaceLogic {
278
278
}
279
279
}
280
280
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
-
293
281
/** Scala implementation of space logic */
294
282
class SpaceEngine (implicit ctx : Context ) extends SpaceLogic {
295
- import SpaceEngine ._
296
283
import tpd ._
297
284
298
285
private val scalaSomeClass = ctx.requiredClass(" scala.Some" )
@@ -301,77 +288,15 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
301
288
private val scalaNilType = ctx.requiredModuleRef(" scala.collection.immutable.Nil" )
302
289
private val scalaConsType = ctx.requiredClassRef(" scala.collection.immutable.::" )
303
290
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
-
361
291
override def intersectUnrelatedAtomicTypes (tp1 : Type , tp2 : Type ) = {
362
292
val and = AndType (tp1, tp2)
363
293
// Precondition: !(tp1 <:< tp2) && !(tp2 <:< tp1)
364
294
// 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)
368
296
369
- debug.println(s " atomic intersection: ${and.show} ~ ${imp.show }" )
297
+ debug.println(s " atomic intersection: ${and.show} = ${res }" )
370
298
371
- imp match {
372
- case Unimplementable => Empty
373
- case _ => Typ (and, true )
374
- }
299
+ if (res) Typ (and, true ) else Empty
375
300
}
376
301
377
302
/* Whether the extractor is irrefutable */
@@ -574,21 +499,97 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
574
499
575
500
/** Can this type be inhabited by a value?
576
501
*
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
+ *
580
508
*/
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
592
593
}
593
594
594
595
/** Instantiate type `tp1` to be a subtype of `tp2`
0 commit comments