Skip to content

Commit 698935a

Browse files
committed
Merge pull request #338 from dotty-staging/fix/t3152-findMember
Fix/t3152 find member
2 parents a822fc1 + 57b616c commit 698935a

13 files changed

+79
-19
lines changed

src/dotty/tools/dotc/core/TypeComparer.scala

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -140,21 +140,14 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi
140140

141141
private def firstTry(tp1: Type, tp2: Type): Boolean = tp2 match {
142142
case tp2: NamedType =>
143-
def compareHKOrAlias(info1: Type) =
144-
tp2.name == tpnme.Apply && {
145-
val lambda2 = tp2.prefix.LambdaClass(forcing = true)
146-
lambda2.exists && !tp1.isLambda &&
147-
tp1.testLifted(lambda2.typeParams, isSubType(_, tp2.prefix))
148-
} || {
149-
tp2.info match {
150-
case info2: TypeAlias => isSubType(tp1, info2.alias)
151-
case _ => info1 match {
152-
case info1: TypeAlias => isSubType(info1.alias, tp2)
153-
case NoType => secondTry(tp1, tp2)
154-
case _ => thirdTryNamed(tp1, tp2)
155-
}
156-
}
143+
def compareAlias(info1: Type) = tp2.info match {
144+
case info2: TypeAlias => isSubType(tp1, info2.alias)
145+
case _ => info1 match {
146+
case info1: TypeAlias => isSubType(info1.alias, tp2)
147+
case NoType => secondTry(tp1, tp2)
148+
case _ => thirdTryNamed(tp1, tp2)
157149
}
150+
}
158151
def compareNamed = {
159152
implicit val ctx: Context = this.ctx // Dotty deviation: implicits need explicit type
160153
tp1 match {
@@ -183,9 +176,12 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi
183176
!tp1.isInstanceOf[WithFixedSym] &&
184177
!tp2.isInstanceOf[WithFixedSym]
185178
) ||
186-
compareHKOrAlias(tp1.info)
179+
compareHK(tp1, tp2, inOrder = true) ||
180+
compareHK(tp2, tp1, inOrder = false) ||
181+
compareAlias(tp1.info)
187182
case _ =>
188-
compareHKOrAlias(NoType)
183+
compareHK(tp2, tp1, inOrder = false) ||
184+
compareAlias(NoType)
189185
}
190186
}
191187
compareNamed
@@ -243,7 +239,9 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi
243239
case tp1: NamedType =>
244240
tp1.info match {
245241
case info1: TypeAlias => isSubType(info1.alias, tp2)
246-
case _ => thirdTry(tp1, tp2)
242+
case _ => compareHK(tp1, tp2, inOrder = true) || thirdTry(tp1, tp2)
243+
// Note: If we change the order here, doing compareHK first and following aliases second,
244+
// we get a -Ycheck error when compiling dotc/transform. Need to investigate.
247245
}
248246
case tp1: PolyParam =>
249247
def flagNothingBound = {
@@ -460,6 +458,18 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi
460458
false
461459
}
462460

461+
/** If `projection` is of the form T # Apply where `T` is an instance of a Lambda class,
462+
* and `other` is not a type lambda projection, then convert `other` to a type lambda `U`, and
463+
* continue with `T <:< U` if `inOrder` is true and `U <:< T` otherwise.
464+
*/
465+
def compareHK(projection: NamedType, other: Type, inOrder: Boolean) =
466+
projection.name == tpnme.Apply && {
467+
val lambda = projection.prefix.LambdaClass(forcing = true)
468+
lambda.exists && !other.isLambda &&
469+
other.testLifted(lambda.typeParams,
470+
if (inOrder) isSubType(projection.prefix, _) else isSubType(_, projection.prefix))
471+
}
472+
463473
/** Returns true iff either `tp11 <:< tp21` or `tp12 <:< tp22`, trying at the same time
464474
* to keep the constraint as wide as possible. Specifically, if
465475
*
@@ -524,7 +534,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi
524534
case mbr: SingleDenotation => qualifies(mbr)
525535
case _ => mbr hasAltWith qualifies
526536
}
527-
/*>|>*/ ctx.traceIndented(i"hasMatchingMember($tp1 . $name :? ${tp2.refinedInfo}) ${tp1.member(name).info.show} $rinfo2", subtyping) /*<|<*/ {
537+
/*>|>*/ ctx.traceIndented(i"hasMatchingMember($base . $name :? ${tp2.refinedInfo}) ${base.member(name).info.show} $rinfo2", subtyping) /*<|<*/ {
528538
memberMatches(base member name) ||
529539
tp1.isInstanceOf[SingletonType] &&
530540
{ // special case for situations like:

src/dotty/tools/dotc/core/Types.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,8 @@ object Types {
419419
if mt.paramTypes.isEmpty && (tp.symbol is Stable) => mt.resultType
420420
case tp1 => tp1
421421
})
422+
case tp: PolyParam =>
423+
goParam(tp)
422424
case tp: TypeProxy =>
423425
go(tp.underlying)
424426
case tp: ClassInfo =>
@@ -460,6 +462,16 @@ object Types {
460462
// loadClassWithPrivateInnerAndSubSelf in ShowClassTests
461463
go(tp.cls.typeRef) orElse d
462464
}
465+
def goParam(tp: PolyParam) = {
466+
val next = tp.underlying
467+
ctx.typerState.constraint.entry(tp) match {
468+
case bounds: TypeBounds if bounds ne next =>
469+
ctx.typerState.ephemeral = true
470+
go(bounds.hi)
471+
case _ =>
472+
go(next)
473+
}
474+
}
463475
def goAnd(l: Type, r: Type) = go(l) & (go(r), pre)
464476
def goOr(l: Type, r: Type) = go(l) | (go(r), pre)
465477
go(this)

src/dotty/tools/dotc/typer/ErrorReporting.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ object ErrorReporting {
9696
def patternConstrStr(tree: Tree): String = ???
9797

9898
def typeMismatch(tree: Tree, pt: Type, implicitFailure: SearchFailure = NoImplicitMatches): Tree = {
99-
errorTree(tree, typeMismatchStr(tree.tpe, pt) + implicitFailure.postscript)
99+
errorTree(tree, typeMismatchStr(normalize(tree.tpe, pt), pt) + implicitFailure.postscript)
100100
}
101101

102102
/** A subtype log explaining why `found` does not conform to `expected` */
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

tests/pos/t8023.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
class C[K]
2+
class D[K]
3+
4+
object Test3 {
5+
def foo = (null: Any) match {
6+
case a: C[k] => new C[k]() // this one worked before as the info of `A` was complete
7+
// ()
8+
}
9+
}

tests/pos/t9004.scala

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
object Main {
2+
trait AA[RR] { type R = RR; def r: R }
3+
4+
def test1(a: AA[_]) = {
5+
val f = () => a.r
6+
// The tree a.r is given the type `a.R` which normalizes
7+
// to B', where B' is a distinct symbol ("captured existential skolem")
8+
// to substitute for the reference to an existential skolem of B.
9+
//
10+
// inference of the result type of the function computes the
11+
// packed type of tree `a.r` to make sure that terms and types
12+
// local to the body of the function don't leak into its result
13+
// type. The captured existential skolem is considered to be local
14+
// so it is abstracted to its upper bound, Any.
15+
//
16+
// However, the packedType transformation need not have even considered
17+
// B', as it is clear that the type `a.R` is not local to the function
18+
// body!
19+
f: (() => a.R)
20+
21+
// The workaround is to annotate the function type, rather than
22+
// relying in inference.
23+
val g: (() => a.R) = () => a.r
24+
val g2 = () => a.r
25+
26+
()
27+
}
28+
// typer debug trace: http://rawgit.com/retronym/d5aeaf8e0a4a2e6eef4b/raw/out.html
29+
}

0 commit comments

Comments
 (0)