@@ -233,54 +233,45 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
233233
234234 def firstTry : Boolean = tp2 match {
235235 case tp2 : NamedType =>
236- def compareNamed (tp1 : Type , tp2 : NamedType ): Boolean = {
236+ def compareNamed (tp1 : Type , tp2 : NamedType ): Boolean =
237237 implicit val ctx : Context = this .ctx
238- tp2.info match {
238+ val info2 = tp2.info
239+ info2 match
239240 case info2 : TypeAlias =>
240- recur(tp1, info2.alias)
241- case _ => tp1 match {
242- case tp1 : NamedType =>
243- tp1.info match {
244- case info1 : TypeAlias =>
245- if (recur(info1.alias, tp2)) return true
246- if (tp1.prefix.isStable) return false
247- // If tp1.prefix is stable, the alias does contain all information about the original ref, so
248- // there's no need to try something else. (This is important for performance).
249- // To see why we cannot in general stop here, consider:
250- //
251- // trait C { type A }
252- // trait D { type A = String }
253- // (C & D)#A <: C#A
254- //
255- // Following the alias leads to the judgment `String <: C#A` which is false.
256- // However the original judgment should be true.
257- case _ =>
258- }
259- val sym2 = tp2.symbol
260- var sym1 = tp1.symbol
261- if (sym1.is(ModuleClass ) && sym2.is(ModuleVal ))
262- // For convenience we want X$ <:< X.type
263- // This is safe because X$ self-type is X.type
264- sym1 = sym1.companionModule
265- if ((sym1 ne NoSymbol ) && (sym1 eq sym2))
266- ctx.erasedTypes ||
267- sym1.isStaticOwner ||
268- isSubType(tp1.prefix, tp2.prefix) ||
269- thirdTryNamed(tp2)
270- else
271- ( (tp1.name eq tp2.name)
272- && tp1.isMemberRef
273- && tp2.isMemberRef
274- && isSubType(tp1.prefix, tp2.prefix)
275- && tp1.signature == tp2.signature
276- && ! (sym1.isClass && sym2.isClass) // class types don't subtype each other
277- ) ||
278- thirdTryNamed(tp2)
279- case _ =>
280- secondTry
281- }
282- }
283- }
241+ if recur(tp1, info2.alias) then return true
242+ if tp2.asInstanceOf [TypeRef ].canDropAlias then return false
243+ case _ =>
244+ tp1 match
245+ case tp1 : NamedType =>
246+ tp1.info match {
247+ case info1 : TypeAlias =>
248+ if recur(info1.alias, tp2) then return true
249+ if tp1.asInstanceOf [TypeRef ].canDropAlias then return false
250+ case _ =>
251+ }
252+ val sym2 = tp2.symbol
253+ var sym1 = tp1.symbol
254+ if (sym1.is(ModuleClass ) && sym2.is(ModuleVal ))
255+ // For convenience we want X$ <:< X.type
256+ // This is safe because X$ self-type is X.type
257+ sym1 = sym1.companionModule
258+ if ((sym1 ne NoSymbol ) && (sym1 eq sym2))
259+ ctx.erasedTypes ||
260+ sym1.isStaticOwner ||
261+ isSubType(tp1.prefix, tp2.prefix) ||
262+ thirdTryNamed(tp2)
263+ else
264+ ( (tp1.name eq tp2.name)
265+ && tp1.isMemberRef
266+ && tp2.isMemberRef
267+ && isSubType(tp1.prefix, tp2.prefix)
268+ && tp1.signature == tp2.signature
269+ && ! (sym1.isClass && sym2.isClass) // class types don't subtype each other
270+ ) ||
271+ thirdTryNamed(tp2)
272+ case _ =>
273+ secondTry
274+ end compareNamed
284275 compareNamed(tp1, tp2)
285276 case tp2 : ProtoType =>
286277 isMatchedByProto(tp2, tp1)
@@ -753,20 +744,16 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
753744 case tp1 @ AppliedType (tycon1, args1) =>
754745 compareAppliedType1(tp1, tycon1, args1)
755746 case tp1 : SingletonType =>
756- /** if `tp2 == p.type` and `p: q.type` then try `tp1 <:< q.type` as a last effort.*/
757- def comparePaths = tp2 match {
747+ def comparePaths = tp2 match
758748 case tp2 : TermRef =>
759- tp2.info.widenExpr.dealias match {
760- case tp2i : SingletonType =>
761- recur(tp1, tp2i)
762- // see z1720.scala for a case where this can arise even in typer.
763- // Also, i1753.scala, to show why the dealias above is necessary.
764- case _ => false
749+ compareAtoms(tp1, tp2, knownSingletons = true ).getOrElse(false )
750+ || { // needed to make from-tasty work. test cases: pos/i1753.scala, pos/t839.scala
751+ tp2.info.widenExpr.dealias match
752+ case tp2i : SingletonType => recur(tp1, tp2i)
753+ case _ => false
765754 }
766- case _ =>
767- false
768- }
769- isNewSubType(tp1.underlying.widenExpr) || comparePaths
755+ case _ => false
756+ comparePaths || isNewSubType(tp1.underlying.widenExpr)
770757 case tp1 : RefinedType =>
771758 isNewSubType(tp1.parent)
772759 case tp1 : RecType =>
@@ -1177,8 +1164,18 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
11771164
11781165 /** If both `tp1` and `tp2` have atoms information, compare the atoms
11791166 * in a Some, otherwise None.
1167+ * @param knownSingletons If true, we are coming from a comparison of two singleton types
1168+ * This influences the comparison as shown below:
1169+ *
1170+ * Say you have singleton types p.type and q.type the atoms of p.type are `{p.type}..{p.type}`,
1171+ * and the atoms of `q.type` are `{}..{p.type}`. Normally the atom comparison between p's
1172+ * atoms and q's atoms gives false. But in this case we know that `q.type` is an alias of `p.type`
1173+ * so we are still allowed to conclude that `p.type <:< q.type`. A situation where this happens
1174+ * is in i6635.scala. Here,
1175+ *
1176+ * p: A, q: B & p.type and we want to conclude that p.type <: q.type.
11801177 */
1181- def compareAtoms (tp1 : Type , tp2 : Type ): Option [Boolean ] =
1178+ def compareAtoms (tp1 : Type , tp2 : Type , knownSingletons : Boolean = false ): Option [Boolean ] =
11821179
11831180 /** Check whether we can compare the given set of atoms with another to determine
11841181 * a subtype test between OrTypes. There is one situation where this is not
@@ -1212,9 +1209,12 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
12121209 case Atoms .Range (lo2, hi2) if canCompareAtoms && canCompare(hi2) =>
12131210 tp1.atoms match
12141211 case Atoms .Range (lo1, hi1) =>
1215- if hi1.subsetOf(lo2) then Some (verified(true ))
1216- else if ! lo1.subsetOf(hi2) then Some (verified(false ))
1217- else None
1212+ if hi1.subsetOf(lo2) || knownSingletons && hi2.size == 1 && hi1 == hi2 then
1213+ Some (verified(true ))
1214+ else if ! lo1.subsetOf(hi2) then
1215+ Some (verified(false ))
1216+ else
1217+ None
12181218 case _ => Some (verified(recur(tp1, NothingType )))
12191219 case _ => None
12201220
0 commit comments