Skip to content

Commit f5d582e

Browse files
committed
Fix #11178: remove unsound tweak for F-bounds
This reverts #9789. We have made several improvements to F-bounds, the unsound tweak is no longer needed.
1 parent e64d3d1 commit f5d582e

File tree

5 files changed

+58
-27
lines changed

5 files changed

+58
-27
lines changed

compiler/src/dotty/tools/dotc/core/PatternTypeConstrainer.scala

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ trait PatternTypeConstrainer { self: TypeComparer =>
7373
* scrutinee and pattern types. This does not apply if the pattern type is only applied to type variables,
7474
* in which case the subtyping relationship "heals" the type.
7575
*/
76-
def constrainPatternType(pat: Type, scrut: Type): Boolean = trace(i"constrainPatternType($scrut, $pat)", gadts) {
76+
def constrainPatternType(pat: Type, scrut: Type, widenParams: Boolean = true): Boolean = trace(i"constrainPatternType($scrut, $pat)", gadts) {
7777

7878
def classesMayBeCompatible: Boolean = {
7979
import Flags._
@@ -135,7 +135,7 @@ trait PatternTypeConstrainer { self: TypeComparer =>
135135
case _ => NoType
136136
}
137137
if (upcasted.exists)
138-
constrainSimplePatternType(pat, upcasted) || constrainUpcasted(upcasted)
138+
constrainSimplePatternType(pat, upcasted, widenParams) || constrainUpcasted(upcasted)
139139
else true
140140
}
141141
}
@@ -155,7 +155,7 @@ trait PatternTypeConstrainer { self: TypeComparer =>
155155
case pat: RefinedOrRecType =>
156156
constrainPatternType(stripRefinement(pat), scrut)
157157
case pat =>
158-
constrainSimplePatternType(pat, scrut) || classesMayBeCompatible && constrainUpcasted(scrut)
158+
constrainSimplePatternType(pat, scrut, widenParams) || classesMayBeCompatible && constrainUpcasted(scrut)
159159
}
160160
}
161161
}
@@ -194,7 +194,7 @@ trait PatternTypeConstrainer { self: TypeComparer =>
194194
* case classes without also appropriately extending the relevant case class
195195
* (see `RefChecks#checkCaseClassInheritanceInvariant`).
196196
*/
197-
def constrainSimplePatternType(patternTp: Type, scrutineeTp: Type): Boolean = {
197+
def constrainSimplePatternType(patternTp: Type, scrutineeTp: Type, widenParams: Boolean): Boolean = {
198198
def refinementIsInvariant(tp: Type): Boolean = tp match {
199199
case tp: ClassInfo => tp.cls.is(Final) || tp.cls.is(Case)
200200
case tp: TypeProxy => refinementIsInvariant(tp.underlying)
@@ -213,7 +213,8 @@ trait PatternTypeConstrainer { self: TypeComparer =>
213213

214214
val widePt =
215215
if migrateTo3 || refinementIsInvariant(patternTp) then scrutineeTp
216-
else widenVariantParams(scrutineeTp)
216+
else if widenParams then widenVariantParams(scrutineeTp)
217+
else scrutineeTp
217218
val narrowTp = SkolemType(patternTp)
218219
trace(i"constraining simple pattern type $narrowTp <:< $widePt", gadts, res => s"$res\ngadt = ${ctx.gadt.debugBoundsDescription}") {
219220
isSubType(narrowTp, widePt)

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2687,8 +2687,8 @@ object TypeComparer {
26872687
def dropTransparentTraits(tp: Type, bound: Type)(using Context): Type =
26882688
comparing(_.dropTransparentTraits(tp, bound))
26892689

2690-
def constrainPatternType(pat: Type, scrut: Type)(using Context): Boolean =
2691-
comparing(_.constrainPatternType(pat, scrut))
2690+
def constrainPatternType(pat: Type, scrut: Type, widenParams: Boolean = true)(using Context): Boolean =
2691+
comparing(_.constrainPatternType(pat, scrut, widenParams))
26922692

26932693
def explained[T](op: ExplainingTypeComparer => T, header: String = "Subtype trace:")(using Context): String =
26942694
comparing(_.explained(op, header))

compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -77,19 +77,6 @@ object TypeTestsCasts {
7777
}
7878
}.apply(tp)
7979

80-
/** Approximate type parameters depending on variance */
81-
def stripTypeParam(tp: Type)(using Context) = new ApproximatingTypeMap {
82-
val boundTypeParams = util.HashMap[TypeRef, TypeVar]()
83-
def apply(tp: Type): Type = tp match {
84-
case _: MatchType =>
85-
tp // break cycles
86-
case tp: TypeRef if !tp.symbol.isClass =>
87-
boundTypeParams.getOrElseUpdate(tp, newTypeVar(tp.underlying.toBounds))
88-
case _ =>
89-
mapOver(tp)
90-
}
91-
}.apply(tp)
92-
9380
/** Returns true if the type arguments of `P` can be determined from `X` */
9481
def typeArgsTrivial(X: Type, P: AppliedType)(using Context) = inContext(ctx.fresh.setExploreTyperState().setFreshGADTBounds) {
9582
val AppliedType(tycon, _) = P
@@ -102,6 +89,7 @@ object TypeTestsCasts {
10289
val tvars = constrained(typeLambda, untpd.EmptyTree, alwaysAddTypeVars = true)._2.map(_.tpe)
10390
val P1 = tycon.appliedTo(tvars)
10491

92+
debug.println("before " + ctx.typerState.constraint.show)
10593
debug.println("P : " + P.show)
10694
debug.println("P1 : " + P1.show)
10795
debug.println("X : " + X.show)
@@ -111,18 +99,23 @@ object TypeTestsCasts {
11199
// conforms to the type skeleton pre.F[_]. Then it goes on to check
112100
// if P1 <: P, which means the type arguments in P are trivial,
113101
// thus no runtime checks are needed for them.
114-
P1 <:< X
102+
withMode(Mode.GadtConstraintInference) {
103+
TypeComparer.constrainPatternType(P1, X, widenParams = false)
104+
debug.println(TypeComparer.explained(_.constrainPatternType(P1, X, widenParams = false)))
105+
true
106+
}
115107

116108
// Maximization of the type means we try to cover all possible values
117109
// which conform to the skeleton pre.F[_] and X. Then we have to make
118110
// sure all of them are actually of the type P, which implies that the
119111
// type arguments in P are trivial (no runtime check needed).
120112
maximizeType(P1, span, fromScala2x = false)
121113

114+
debug.println("after " + ctx.typerState.constraint.show)
115+
122116
val res = P1 <:< P
123117

124118
debug.println(TypeComparer.explained(_.isSubType(P1, P)))
125-
126119
debug.println("P1 : " + P1.show)
127120
debug.println("P1 <:< P = " + res)
128121

@@ -151,10 +144,8 @@ object TypeTestsCasts {
151144
case _ =>
152145
// always false test warnings are emitted elsewhere
153146
X.classSymbol.exists && P.classSymbol.exists &&
154-
!X.classSymbol.asClass.mayHaveCommonChild(P.classSymbol.asClass) ||
155-
// first try without striping type parameters for performance
156-
typeArgsTrivial(X, tpe) ||
157-
typeArgsTrivial(stripTypeParam(X), tpe)
147+
!X.classSymbol.asClass.mayHaveCommonChild(P.classSymbol.asClass)
148+
|| typeArgsTrivial(X, tpe)
158149
}
159150
case AndType(tp1, tp2) => recur(X, tp1) && recur(X, tp2)
160151
case OrType(tp1, tp2) => recur(X, tp1) && recur(X, tp2)

compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -748,7 +748,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
748748
tpd.Closure(meth, tss => xCheckMacroedOwners(xCheckMacroValidExpr(rhsFn(meth, tss.head.map(withDefaultPos))), meth))
749749

750750
def unapply(tree: Block): Option[(List[ValDef], Term)] = tree match {
751-
case Block((ddef @ DefDef(_, TermParamClause(params) :: Nil, _, Some(body))) :: Nil, Closure(meth, _))
751+
case Block((ddef @ DefDef(_, tpd.ValDefs(params) :: Nil, _, Some(body))) :: Nil, Closure(meth, _))
752752
if ddef.symbol == meth.symbol =>
753753
Some((params, body))
754754
case _ => None
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
trait Box[+T]
2+
case class Foo[+S](s: S) extends Box[S]
3+
4+
def unwrap2[A](b: Box[A]): A =
5+
b match
6+
case _: Foo[Int] => 0 // error
7+
8+
object Test1 {
9+
// Invariant case, OK
10+
sealed trait Bar[A]
11+
12+
def test[A](bar: Bar[A]) =
13+
bar match {
14+
case _: Bar[Boolean] => ??? // error
15+
case _ => ???
16+
}
17+
}
18+
19+
object Test2 {
20+
// Covariant case
21+
sealed trait Bar[+A]
22+
23+
def test[A](bar: Bar[A]) =
24+
bar match {
25+
case _: Bar[Boolean] => ??? // error
26+
case _ => ???
27+
}
28+
}
29+
30+
object Test3 {
31+
// Contravariant case
32+
sealed trait Bar[-A]
33+
34+
def test[A](bar: Bar[A]) =
35+
bar match {
36+
case _: Bar[Boolean] => ??? // error
37+
case _ => ???
38+
}
39+
}

0 commit comments

Comments
 (0)