diff options
-rw-r--r-- | src/dotty/tools/dotc/core/TypeComparer.scala | 46 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Types.scala | 12 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/ErrorReporting.scala | 2 | ||||
-rw-r--r-- | tests/pos/t3020.scala (renamed from tests/pending/pos/t3020.scala) | 0 | ||||
-rw-r--r-- | tests/pos/t3037.scala (renamed from tests/pending/pos/t3037.scala) | 0 | ||||
-rw-r--r-- | tests/pos/t304.scala (renamed from tests/pending/pos/t304.scala) | 0 | ||||
-rw-r--r-- | tests/pos/t3106.scala (renamed from tests/pending/pos/t3106.scala) | 0 | ||||
-rw-r--r-- | tests/pos/t3137.scala (renamed from tests/pending/pos/t3137.scala) | 0 | ||||
-rw-r--r-- | tests/pos/t3152.scala (renamed from tests/pending/pos/t3152.scala) | 0 | ||||
-rwxr-xr-x | tests/pos/t3174.scala (renamed from tests/pending/pos/t3174.scala) | 0 | ||||
-rw-r--r-- | tests/pos/t3177.scala (renamed from tests/pending/pos/t3177.scala) | 0 | ||||
-rw-r--r-- | tests/pos/t8023.scala | 9 | ||||
-rw-r--r-- | tests/pos/t9004.scala | 29 |
13 files changed, 79 insertions, 19 deletions
diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala index 9826a23ea..fd4ef0bc7 100644 --- a/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/src/dotty/tools/dotc/core/TypeComparer.scala @@ -140,21 +140,14 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi private def firstTry(tp1: Type, tp2: Type): Boolean = tp2 match { case tp2: NamedType => - def compareHKOrAlias(info1: Type) = - tp2.name == tpnme.Apply && { - val lambda2 = tp2.prefix.LambdaClass(forcing = true) - lambda2.exists && !tp1.isLambda && - tp1.testLifted(lambda2.typeParams, isSubType(_, tp2.prefix)) - } || { - tp2.info match { - case info2: TypeAlias => isSubType(tp1, info2.alias) - case _ => info1 match { - case info1: TypeAlias => isSubType(info1.alias, tp2) - case NoType => secondTry(tp1, tp2) - case _ => thirdTryNamed(tp1, tp2) - } - } + def compareAlias(info1: Type) = tp2.info match { + case info2: TypeAlias => isSubType(tp1, info2.alias) + case _ => info1 match { + case info1: TypeAlias => isSubType(info1.alias, tp2) + case NoType => secondTry(tp1, tp2) + case _ => thirdTryNamed(tp1, tp2) } + } def compareNamed = { implicit val ctx: Context = this.ctx // Dotty deviation: implicits need explicit type tp1 match { @@ -183,9 +176,12 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi !tp1.isInstanceOf[WithFixedSym] && !tp2.isInstanceOf[WithFixedSym] ) || - compareHKOrAlias(tp1.info) + compareHK(tp1, tp2, inOrder = true) || + compareHK(tp2, tp1, inOrder = false) || + compareAlias(tp1.info) case _ => - compareHKOrAlias(NoType) + compareHK(tp2, tp1, inOrder = false) || + compareAlias(NoType) } } compareNamed @@ -243,7 +239,9 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi case tp1: NamedType => tp1.info match { case info1: TypeAlias => isSubType(info1.alias, tp2) - case _ => thirdTry(tp1, tp2) + case _ => compareHK(tp1, tp2, inOrder = true) || thirdTry(tp1, tp2) + // Note: If we change the order here, doing compareHK first and following aliases second, + // we get a -Ycheck error when compiling dotc/transform. Need to investigate. } case tp1: PolyParam => def flagNothingBound = { @@ -460,6 +458,18 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi false } + /** If `projection` is of the form T # Apply where `T` is an instance of a Lambda class, + * and `other` is not a type lambda projection, then convert `other` to a type lambda `U`, and + * continue with `T <:< U` if `inOrder` is true and `U <:< T` otherwise. + */ + def compareHK(projection: NamedType, other: Type, inOrder: Boolean) = + projection.name == tpnme.Apply && { + val lambda = projection.prefix.LambdaClass(forcing = true) + lambda.exists && !other.isLambda && + other.testLifted(lambda.typeParams, + if (inOrder) isSubType(projection.prefix, _) else isSubType(_, projection.prefix)) + } + /** Returns true iff either `tp11 <:< tp21` or `tp12 <:< tp22`, trying at the same time * to keep the constraint as wide as possible. Specifically, if * @@ -524,7 +534,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling wi case mbr: SingleDenotation => qualifies(mbr) case _ => mbr hasAltWith qualifies } - /*>|>*/ ctx.traceIndented(i"hasMatchingMember($tp1 . $name :? ${tp2.refinedInfo}) ${tp1.member(name).info.show} $rinfo2", subtyping) /*<|<*/ { + /*>|>*/ ctx.traceIndented(i"hasMatchingMember($base . $name :? ${tp2.refinedInfo}) ${base.member(name).info.show} $rinfo2", subtyping) /*<|<*/ { memberMatches(base member name) || tp1.isInstanceOf[SingletonType] && { // special case for situations like: diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index a36dda7e3..18f854f12 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -419,6 +419,8 @@ object Types { if mt.paramTypes.isEmpty && (tp.symbol is Stable) => mt.resultType case tp1 => tp1 }) + case tp: PolyParam => + goParam(tp) case tp: TypeProxy => go(tp.underlying) case tp: ClassInfo => @@ -460,6 +462,16 @@ object Types { // loadClassWithPrivateInnerAndSubSelf in ShowClassTests go(tp.cls.typeRef) orElse d } + def goParam(tp: PolyParam) = { + val next = tp.underlying + ctx.typerState.constraint.entry(tp) match { + case bounds: TypeBounds if bounds ne next => + ctx.typerState.ephemeral = true + go(bounds.hi) + case _ => + go(next) + } + } def goAnd(l: Type, r: Type) = go(l) & (go(r), pre) def goOr(l: Type, r: Type) = go(l) | (go(r), pre) go(this) diff --git a/src/dotty/tools/dotc/typer/ErrorReporting.scala b/src/dotty/tools/dotc/typer/ErrorReporting.scala index 8e8cf58f9..2ed720f83 100644 --- a/src/dotty/tools/dotc/typer/ErrorReporting.scala +++ b/src/dotty/tools/dotc/typer/ErrorReporting.scala @@ -96,7 +96,7 @@ object ErrorReporting { def patternConstrStr(tree: Tree): String = ??? def typeMismatch(tree: Tree, pt: Type, implicitFailure: SearchFailure = NoImplicitMatches): Tree = { - errorTree(tree, typeMismatchStr(tree.tpe, pt) + implicitFailure.postscript) + errorTree(tree, typeMismatchStr(normalize(tree.tpe, pt), pt) + implicitFailure.postscript) } /** A subtype log explaining why `found` does not conform to `expected` */ diff --git a/tests/pending/pos/t3020.scala b/tests/pos/t3020.scala index 016563e27..016563e27 100644 --- a/tests/pending/pos/t3020.scala +++ b/tests/pos/t3020.scala diff --git a/tests/pending/pos/t3037.scala b/tests/pos/t3037.scala index b71ffe041..b71ffe041 100644 --- a/tests/pending/pos/t3037.scala +++ b/tests/pos/t3037.scala diff --git a/tests/pending/pos/t304.scala b/tests/pos/t304.scala index 76da44157..76da44157 100644 --- a/tests/pending/pos/t304.scala +++ b/tests/pos/t304.scala diff --git a/tests/pending/pos/t3106.scala b/tests/pos/t3106.scala index a9591d0aa..a9591d0aa 100644 --- a/tests/pending/pos/t3106.scala +++ b/tests/pos/t3106.scala diff --git a/tests/pending/pos/t3137.scala b/tests/pos/t3137.scala index cb7317af0..cb7317af0 100644 --- a/tests/pending/pos/t3137.scala +++ b/tests/pos/t3137.scala diff --git a/tests/pending/pos/t3152.scala b/tests/pos/t3152.scala index 3d1dcbd6f..3d1dcbd6f 100644 --- a/tests/pending/pos/t3152.scala +++ b/tests/pos/t3152.scala diff --git a/tests/pending/pos/t3174.scala b/tests/pos/t3174.scala index 8d9b2578d..8d9b2578d 100755 --- a/tests/pending/pos/t3174.scala +++ b/tests/pos/t3174.scala diff --git a/tests/pending/pos/t3177.scala b/tests/pos/t3177.scala index 12dfce6ee..12dfce6ee 100644 --- a/tests/pending/pos/t3177.scala +++ b/tests/pos/t3177.scala diff --git a/tests/pos/t8023.scala b/tests/pos/t8023.scala new file mode 100644 index 000000000..66d478abd --- /dev/null +++ b/tests/pos/t8023.scala @@ -0,0 +1,9 @@ +class C[K] +class D[K] + +object Test3 { + def foo = (null: Any) match { + case a: C[k] => new C[k]() // this one worked before as the info of `A` was complete + // () + } +} diff --git a/tests/pos/t9004.scala b/tests/pos/t9004.scala new file mode 100644 index 000000000..d591bc852 --- /dev/null +++ b/tests/pos/t9004.scala @@ -0,0 +1,29 @@ +object Main { + trait AA[RR] { type R = RR; def r: R } + + def test1(a: AA[_]) = { + val f = () => a.r + // The tree a.r is given the type `a.R` which normalizes + // to B', where B' is a distinct symbol ("captured existential skolem") + // to substitute for the reference to an existential skolem of B. + // + // inference of the result type of the function computes the + // packed type of tree `a.r` to make sure that terms and types + // local to the body of the function don't leak into its result + // type. The captured existential skolem is considered to be local + // so it is abstracted to its upper bound, Any. + // + // However, the packedType transformation need not have even considered + // B', as it is clear that the type `a.R` is not local to the function + // body! + f: (() => a.R) + + // The workaround is to annotate the function type, rather than + // relying in inference. + val g: (() => a.R) = () => a.r + val g2 = () => a.r + + () + } + // typer debug trace: http://rawgit.com/retronym/d5aeaf8e0a4a2e6eef4b/raw/out.html +} |