@@ -231,17 +231,27 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
231
231
}
232
232
}
233
233
234
- def singleBounds (tp : Type ): List [Type ] = tp.widenExpr.dealias match
235
- case tp1 : SingletonType => tp1 :: Nil
236
- case AndType (tp11, tp12) => singleBounds(tp1) ::: singleBounds(tp2)
237
- case _ => Nil
238
-
239
- def isSingletonAlias (tp : Type ): Boolean = tp match
240
- case tp : TermRef => singleBounds(tp).nonEmpty || isSingletonAlias(tp.prefix)
241
- case _ => false
242
-
243
- // THIS IS STILL PROVISIONAL
244
- def canDropAlias (tp : NamedType ): Boolean = ! isSingletonAlias(tp.prefix)
234
+ /** Given an alias type `type A = B` where a recursive comparison with `B` yields
235
+ * `false`, can we conclude that the comparison is definitely false?
236
+ * This could not be the case if `A` overrides some abstract type. Example:
237
+ *
238
+ * class C { type A }
239
+ * class D { type A = Int }
240
+ * val c: C
241
+ * val d: D & c.type
242
+ * c.A <:< d.A ?
243
+ *
244
+ * The test should return true, by performing the logic in the bottom half of
245
+ * firstTry (where we check the names of types). But just following the alias
246
+ * from d.A to Int reduces the problem to `c.A <:< Int`, which returns `false`.
247
+ * So we can't drop the alias here, we need to do the backtracking to the name-
248
+ * based tests.
249
+ */
250
+ def canDropAlias (tp : NamedType ): Boolean =
251
+ val sym = tp.symbol
252
+ ! sym.canMatchInheritedSymbols
253
+ || ! tp.prefix.baseClasses.exists(
254
+ _.info.nonPrivateDecl(sym.name).symbol.is(Deferred ))
245
255
246
256
def firstTry : Boolean = tp2 match {
247
257
case tp2 : NamedType =>
@@ -258,17 +268,7 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
258
268
tp1.info match {
259
269
case info1 : TypeAlias =>
260
270
if recur(info1.alias, tp2) then return true
261
- if tp1.prefix.isStable && canDropAlias(tp1) then return false
262
- // If tp1.prefix is stable, the alias does contain all information about the original ref, so
263
- // there's no need to try something else. (This is important for performance).
264
- // To see why we cannot in general stop here, consider:
265
- //
266
- // trait C { type A }
267
- // trait D { type A = String }
268
- // (C & D)#A <: C#A
269
- //
270
- // Following the alias leads to the judgment `String <: C#A` which is false.
271
- // However the original judgment should be true.
271
+ if canDropAlias(tp1) then return false
272
272
case _ =>
273
273
}
274
274
val sym2 = tp2.symbol
0 commit comments