@@ -247,22 +247,29 @@ trait SpaceLogic {
247
247
}
248
248
249
249
object SpaceEngine {
250
- private sealed trait Implementability
251
- private object ClassOrTrait extends Implementability
250
+ private sealed trait Implementability {
251
+ def show (implicit ctx : Context ) = this match {
252
+ case SubclassOf (classSyms) => s " SubclassOf( ${classSyms.map(_.show)}) "
253
+ case other => other.toString
254
+ }
255
+ }
256
+ private case object ClassOrTrait extends Implementability
252
257
private case class SubclassOf (classSyms : List [Symbol ]) extends Implementability
253
- private object Unimplementable extends Implementability
258
+ private case object Unimplementable extends Implementability
254
259
}
255
260
256
261
/** Scala implementation of space logic */
257
262
class SpaceEngine (implicit ctx : Context ) extends SpaceLogic {
258
263
import SpaceEngine ._
259
264
import tpd ._
260
265
261
- /** Checks if `tp` can be implemented by a new class/trait .
266
+ /** Checks if it's possible to create a trait/class which is a subtype of `tp` .
262
267
*
263
- * - doesn't handle member collisions (assumes they don't happen )
268
+ * - doesn't handle member collisions (will not declare a type unimplementable because of one )
264
269
* - expects that neither Any nor Object reach it
265
270
* (this is currently true due to both isSubType and and/or type simplification)
271
+ *
272
+ * See [[intersectUnrelatedAtomicTypes ]].
266
273
*/
267
274
private def implementability (tp : Type ): Implementability = tp.dealias match {
268
275
case AndType (tp1, tp2) =>
@@ -293,20 +300,37 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
293
300
case (_, SubclassOf (classSyms)) => SubclassOf (classSyms)
294
301
case _ => Unimplementable
295
302
}
296
- case tp : RefinedType => implementability(tp.parent)
303
+ case _ : SingletonType =>
304
+ // singleton types have no instantiable subtypes
305
+ Unimplementable
306
+ case tp : RefinedType =>
307
+ // refinement itself is not considered - it would at most make
308
+ // a type unimplementable because of a member collision
309
+ implementability(tp.parent)
297
310
case other =>
298
311
val classSym = other.classSymbol
299
- val isOpen =
300
- ! classSym.is(Sealed | Final ) && ! other.termSymbol.is(Module )
301
-
302
- if (isOpen) {
303
- if (classSym is Trait ) ClassOrTrait else SubclassOf (List (classSym))
304
- } else Unimplementable
312
+ if (classSym.exists) {
313
+ if (classSym is Final ) Unimplementable
314
+ else if (classSym is Trait ) ClassOrTrait
315
+ else SubclassOf (List (classSym))
316
+ } else {
317
+ // if no class symbol exists, conservatively say that anything
318
+ // can implement `tp`
319
+ ClassOrTrait
320
+ }
305
321
}
306
322
307
323
override def intersectUnrelatedAtomicTypes (tp1 : Type , tp2 : Type ) = {
308
324
val and = AndType (tp1, tp2)
309
- implementability(and) match {
325
+ // Precondition: !(tp1 <:< tp2) && !(tp2 <:< tp1)
326
+ // Then, no leaf of the and-type tree `and` is a subtype of `and`.
327
+ // Then, to create a value of type `and` you must instantiate a trait (class/module)
328
+ // which is a subtype of all the leaves of `and`.
329
+ val imp = implementability(and)
330
+
331
+ debug.println(s " atomic intersection: ${and.show} ~ ${imp.show}" )
332
+
333
+ imp match {
310
334
case Unimplementable => Empty
311
335
case _ => Typ (and, true )
312
336
}
0 commit comments