Skip to content

Commit 7801c57

Browse files
committed
Treat wildcard args and pattern type variables the same
In a type pattern, a wildcard argument and a type variable needs to be treated the same. I.e. it should make no difference if I have C[_ >: L <: H] or C[t >: L <: H] where `t` is unused. Previously, the two constructs had largely different codepaths with different things that failed and worked. This fix is necessary to mitigate the fix for #1754. The latter fix uncovered several problems with the way wildcard arguments in patterns were treated. The change also uncovered a problem in transforms: FirstTransform eliminates all type nodes wnd with it any binders bound type symbols. This means that subsequently patVars is wrong, and therefore a TreeTypeMap over a pattern will no longer duplicate pattern- bound type variables. This caused Ycheck to fail after TailRec. The fix is to keep pattern bound type variables around in an internal annotation, which is understood by patVars.
1 parent 6086d78 commit 7801c57

File tree

4 files changed

+44
-26
lines changed

4 files changed

+44
-26
lines changed

compiler/src/dotty/tools/dotc/ast/TreeInfo.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
556556
val acc = new TreeAccumulator[List[Symbol]] {
557557
def apply(syms: List[Symbol], tree: Tree)(implicit ctx: Context) = tree match {
558558
case Bind(_, body) => apply(tree.symbol :: syms, body)
559+
case Annotated(tree, id @ Ident(tpnme.BOUNDTYPE_ANNOT)) => apply(id.symbol :: syms, tree)
559560
case _ => foldOver(syms, tree)
560561
}
561562
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ object StdNames {
143143
val INITIALIZER_PREFIX: N = "initial$"
144144
val COMPANION_MODULE_METHOD: N = "companion$module"
145145
val COMPANION_CLASS_METHOD: N = "companion$class"
146+
val BOUNDTYPE_ANNOT: N = "$boundType$"
146147
val QUOTE: N = "'"
147148
val TYPE_QUOTE: N = "type_'"
148149
val TRAIT_SETTER_SEPARATOR: N = str.TRAIT_SETTER_SEPARATOR

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

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import dotty.tools.dotc.ast.tpd
77
import dotty.tools.dotc.core.Phases.NeedsCompanions
88
import dotty.tools.dotc.transform.MegaPhase._
99
import ast.Trees._
10+
import ast.untpd
1011
import Flags._
1112
import Types._
1213
import Constants.Constant
@@ -188,8 +189,27 @@ class FirstTransform extends MiniPhase with InfoTransformer { thisPhase =>
188189
override def transformStats(trees: List[Tree])(implicit ctx: Context): List[Tree] =
189190
ast.Trees.flatten(reorderAndComplete(trees)(ctx.withPhase(thisPhase.next)))
190191

191-
private def toTypeTree(tree: Tree)(implicit ctx: Context) =
192-
TypeTree(tree.tpe).withPos(tree.pos)
192+
private object collectBinders extends TreeAccumulator[List[Ident]] {
193+
def apply(annots: List[Ident], t: Tree)(implicit ctx: Context): List[Ident] = t match {
194+
case t @ Bind(_, body) =>
195+
val annot = untpd.Ident(tpnme.BOUNDTYPE_ANNOT).withType(t.symbol.typeRef)
196+
apply(annot :: annots, body)
197+
case _ =>
198+
foldOver(annots, t)
199+
}
200+
}
201+
202+
/** Replace type tree `t` of type `T` with `TypeTree(T)`, but make sure all
203+
* binders in `t` are maintained by rewrapping binders around the type tree.
204+
* E.g. if `t` is `C[t @ (>: L <: H)]`, replace with
205+
* `t @ TC[_ >: L <: H]`. The body of the binder `t` is now wrong, but this does
206+
* not matter, as we only need the info of `t`.
207+
*/
208+
private def toTypeTree(tree: Tree)(implicit ctx: Context) = {
209+
val binders = collectBinders.apply(Nil, tree)
210+
val result: Tree = TypeTree(tree.tpe).withPos(tree.pos)
211+
(result /: binders)(Annotated(_, _))
212+
}
193213

194214
override def transformOther(tree: Tree)(implicit ctx: Context) = tree match {
195215
case tree: Import => EmptyTree

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -568,8 +568,8 @@ class Typer extends Namer
568568
def typedTpt = checkSimpleKinded(typedType(tree.tpt))
569569
def handlePattern: Tree = {
570570
val tpt1 = typedTpt
571-
// special case for an abstract type that comes with a class tag
572571
if (!ctx.isAfterTyper) tpt1.tpe.<:<(pt)(ctx.addMode(Mode.GADTflexible))
572+
// special case for an abstract type that comes with a class tag
573573
tryWithClassTag(ascription(tpt1, isWildcard = true), pt)
574574
}
575575
cases(
@@ -1012,37 +1012,29 @@ class Typer extends Namer
10121012
if (!gadtCtx.gadt.bounds.contains(sym))
10131013
gadtCtx.gadt.setBounds(sym, TypeBounds.empty)
10141014

1015-
/** - replace all references to symbols associated with wildcards by their GADT bounds
1015+
/** - strip all instantiated TypeVars from pattern types.
1016+
* run/reducable.scala is a test case that shows stripping typevars is necessary.
10161017
* - enter all symbols introduced by a Bind in current scope
10171018
*/
10181019
val indexPattern = new TreeMap {
1019-
val elimWildcardSym = new TypeMap {
1020-
def apply(t: Type) = t match {
1021-
case ref: TypeRef if ref.name == tpnme.WILDCARD && gadtCtx.gadt.bounds.contains(ref.symbol) =>
1022-
gadtCtx.gadt.bounds(ref.symbol)
1023-
case TypeAlias(ref: TypeRef) if ref.name == tpnme.WILDCARD && gadtCtx.gadt.bounds.contains(ref.symbol) =>
1024-
gadtCtx.gadt.bounds(ref.symbol)
1025-
case _ =>
1026-
mapOver(t)
1027-
}
1020+
val stripTypeVars = new TypeMap {
1021+
def apply(t: Type) = mapOver(t)
10281022
}
10291023
override def transform(trt: Tree)(implicit ctx: Context) =
1030-
super.transform(trt.withType(elimWildcardSym(trt.tpe))) match {
1024+
super.transform(trt.withType(stripTypeVars(trt.tpe))) match {
10311025
case b: Bind =>
10321026
val sym = b.symbol
1033-
if (sym.exists) {
1027+
if (sym.name != tpnme.WILDCARD)
10341028
if (ctx.scope.lookup(b.name) == NoSymbol) ctx.enter(sym)
10351029
else ctx.error(new DuplicateBind(b, tree), b.pos)
1036-
sym.info = elimWildcardSym(sym.info)
1037-
b
1038-
}
1039-
else {
1040-
assert(b.name == tpnme.WILDCARD)
1041-
b.body
1030+
if (!ctx.isAfterTyper) {
1031+
val bounds = ctx.gadt.bounds(sym)
1032+
if (bounds != null) sym.info = bounds
10421033
}
1034+
b
10431035
case t => t
10441036
}
1045-
}
1037+
}
10461038

10471039
def caseRest(pat: Tree)(implicit ctx: Context) = {
10481040
val pat1 = indexPattern.transform(pat)
@@ -1277,7 +1269,7 @@ class Typer extends Namer
12771269
assignType(cpy.ByNameTypeTree(tree)(result1), result1)
12781270
}
12791271

1280-
def typedTypeBoundsTree(tree: untpd.TypeBoundsTree)(implicit ctx: Context): Tree = track("typedTypeBoundsTree") {
1272+
def typedTypeBoundsTree(tree: untpd.TypeBoundsTree, pt: Type)(implicit ctx: Context): Tree = track("typedTypeBoundsTree") {
12811273
val TypeBoundsTree(lo, hi) = tree
12821274
val lo1 = typed(lo)
12831275
val hi1 = typed(hi)
@@ -1292,8 +1284,12 @@ class Typer extends Namer
12921284
// with an expected type in typedTyped. The type symbol and the defining Bind node
12931285
// are eliminated once the enclosing pattern has been typechecked; see `indexPattern`
12941286
// in `typedCase`.
1295-
val wildcardSym = ctx.newPatternBoundSymbol(tpnme.WILDCARD, tree1.tpe, tree.pos)
1296-
untpd.Bind(tpnme.WILDCARD, tree1).withType(wildcardSym.typeRef)
1287+
//val ptt = if (lo.isEmpty && hi.isEmpty) pt else
1288+
if (ctx.isAfterTyper) tree1
1289+
else {
1290+
val wildcardSym = ctx.newPatternBoundSymbol(tpnme.WILDCARD, tree1.tpe & pt, tree.pos)
1291+
untpd.Bind(tpnme.WILDCARD, tree1).withType(wildcardSym.typeRef)
1292+
}
12971293
}
12981294
else tree1
12991295
}
@@ -1762,7 +1758,7 @@ class Typer extends Namer
17621758
case tree: untpd.AppliedTypeTree => typedAppliedTypeTree(tree)
17631759
case tree: untpd.LambdaTypeTree => typedLambdaTypeTree(tree)(localContext(tree, NoSymbol).setNewScope)
17641760
case tree: untpd.ByNameTypeTree => typedByNameTypeTree(tree)
1765-
case tree: untpd.TypeBoundsTree => typedTypeBoundsTree(tree)
1761+
case tree: untpd.TypeBoundsTree => typedTypeBoundsTree(tree, pt)
17661762
case tree: untpd.Alternative => typedAlternative(tree, pt)
17671763
case tree: untpd.PackageDef => typedPackageDef(tree)
17681764
case tree: untpd.Annotated => typedAnnotated(tree, pt)

0 commit comments

Comments
 (0)