Skip to content

Commit 2214f5a

Browse files
committed
Fix problem in unapply typing.
GADT bound resetting may only be applied when comparing <pattern type> <: <expected type>, not when comparing the other way around. The fix revealed an error in a test case (t1048) which looks like a real error. Therefore the test got moved to neg.
1 parent 6a5505d commit 2214f5a

File tree

6 files changed

+34
-21
lines changed

6 files changed

+34
-21
lines changed

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,7 @@ class TypeComparer(initctx: Context) extends DotClass {
364364

365365
private def traceInfo(tp1: Type, tp2: Type) =
366366
s"${tp1.show} <:< ${tp2.show}" +
367-
(if (ctx.settings.verbose.value) s"${tp1.getClass} ${tp2.getClass}" else "")
367+
(if (ctx.settings.verbose.value) s" ${tp1.getClass} ${tp2.getClass}${if (frozenConstraint) " frozen" else ""}" else "")
368368

369369
def isSubType(tp1: Type, tp2: Type): Boolean = /*>|>*/ ctx.traceIndented(s"isSubType ${traceInfo(tp1, tp2)}", subtyping) /*<|<*/ {
370370
if (tp2 eq NoType) false
@@ -592,7 +592,8 @@ class TypeComparer(initctx: Context) extends DotClass {
592592
NamedType(tp1.prefix, tp1.name, sd.derivedSingleDenotation(sd.symbol, tp))
593593
secondTry(OrType.make(derivedRef(tp11), derivedRef(tp12)), tp2)
594594
case TypeBounds(lo1, hi1) =>
595-
if ((tp1.symbol is GADTFlexType) && !isSubTypeWhenFrozen(hi1, tp2))
595+
if ((ctx.mode is Mode.GADTflexible) && (tp1.symbol is GADTFlexType) &&
596+
!isSubTypeWhenFrozen(hi1, tp2))
596597
trySetType(tp1, TypeBounds(lo1, hi1 & tp2))
597598
else if (lo1 eq hi1) isSubType(hi1, tp2)
598599
else tryRebase2nd
@@ -610,7 +611,8 @@ class TypeComparer(initctx: Context) extends DotClass {
610611
}
611612
def compareNamed: Boolean = tp2.info match {
612613
case TypeBounds(lo2, hi2) =>
613-
if ((tp2.symbol is GADTFlexType) && !isSubTypeWhenFrozen(tp1, lo2))
614+
if ((ctx.mode is Mode.GADTflexible) && (tp2.symbol is GADTFlexType) &&
615+
!isSubTypeWhenFrozen(tp1, lo2))
614616
trySetType(tp2, TypeBounds(lo2 | tp1, hi2))
615617
else
616618
((frozenConstraint || !isCappable(tp1)) && isSubType(tp1, lo2)

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -655,7 +655,7 @@ trait Applications extends Compatibility { self: Typer =>
655655
/** Can `subtp` be made to be a subtype of `tp`, possibly by dropping some
656656
* refinements in `tp`?
657657
*/
658-
def isSubTypeOfParent(subtp: Type, tp: Type): Boolean =
658+
def isSubTypeOfParent(subtp: Type, tp: Type)(implicit ctx: Context): Boolean =
659659
if (subtp <:< tp) true
660660
else tp match {
661661
case RefinedType(parent, _) => isSubTypeOfParent(subtp, parent)
@@ -672,7 +672,7 @@ trait Applications extends Compatibility { self: Typer =>
672672
fullyDefinedType(unapplyArgType, "extractor argument", tree.pos)
673673
unapp.println(i"case 1 $unapplyArgType ${ctx.typerState.constraint}")
674674
pt
675-
} else if (isSubTypeOfParent(unapplyArgType, wpt)) {
675+
} else if (isSubTypeOfParent(unapplyArgType, wpt)(ctx.addMode(Mode.GADTflexible))) {
676676
maximizeType(unapplyArgType) match {
677677
case Some(tvar) =>
678678
def msg =

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,5 +48,8 @@ object Mode {
4848
*/
4949
val FutureDefsOK = newMode(7, "FutureDefsOK")
5050

51+
/** Allow GADTFlexType labelled types to have their bounds adjusted */
52+
val GADTflexible = newMode(8, "GADTflexible")
53+
5154
val PatternOrType = Pattern | Type
5255
}

test/dotc/tests.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class tests extends CompilerTest {
1515

1616
implicit val defaultOptions = noCheckOptions ++ List("-Ycheck:literalize,constructors")
1717

18-
val twice = List("#runs", "2", "-YnoDoubleBindings", "-Ystop-before:terminal")
18+
val twice = List("#runs", "2", "-YnoDoubleBindings")
1919
val doErase = List("-Ystop-before:terminal")
2020

2121
val posDir = "./tests/pos/"
@@ -83,7 +83,8 @@ class tests extends CompilerTest {
8383
@Test def neg_tailcall = compileFile(negDir, "tailcall/tailrec", xerrors = 7)
8484
@Test def neg_tailcall2 = compileFile(negDir, "tailcall/tailrec-2", xerrors = 2)
8585
@Test def neg_tailcall3 = compileFile(negDir, "tailcall/tailrec-3", xerrors = 2)
86-
@Test def nef_t1279a = compileFile(negDir, "t1279a", xerrors = 1)
86+
@Test def neg_t1048 = compileFile(negDir, "t1048", xerrors = 1)
87+
@Test def neg_t1279a = compileFile(negDir, "t1279a", xerrors = 1)
8788
@Test def neg_t1843 = compileFile(negDir, "t1843", xerrors = 1)
8889
@Test def neg_t1843_variances = compileFile(negDir, "t1843-variances", xerrors = 1)
8990
@Test def neg_t2660_ambi = compileFile(negDir, "t2660", xerrors = 2)

tests/neg/t1048.scala

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
trait T[U] {
2+
def x: T[_ <: U]
3+
}
4+
5+
object T {
6+
def unapply[U](t: T[U]): Option[T[_ <: U]] = Some(t.x)
7+
}
8+
9+
object Test {
10+
def f[W](t: T[W]) = t match {
11+
case T(T(_)) => ()
12+
// Gives:
13+
// t1048.scala:11: error: There is no best instantiation of pattern type T[Any']
14+
// that makes it a subtype of selector type T[_ <: W].
15+
// Non-variant type variable U cannot be uniquely instantiated.
16+
// case T(T(_)) => ()
17+
// ^
18+
// one error found
19+
}
20+
}
21+

tests/pos/t1048.scala

Lines changed: 0 additions & 14 deletions
This file was deleted.

0 commit comments

Comments
 (0)