Skip to content

Commit 4086a6c

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 scala#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 d9aa4dc commit 4086a6c

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
@@ -554,6 +554,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
554554
val acc = new TreeAccumulator[List[Symbol]] {
555555
def apply(syms: List[Symbol], tree: Tree)(implicit ctx: Context) = tree match {
556556
case Bind(_, body) => apply(tree.symbol :: syms, body)
557+
case Annotated(tree, id @ Ident(tpnme.BOUNDTYPE_ANNOT)) => apply(id.symbol :: syms, tree)
557558
case _ => foldOver(syms, tree)
558559
}
559560
}

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
@@ -554,8 +554,8 @@ class Typer extends Namer
554554
def typedTpt = checkSimpleKinded(typedType(tree.tpt))
555555
def handlePattern: Tree = {
556556
val tpt1 = typedTpt
557-
// special case for an abstract type that comes with a class tag
558557
if (!ctx.isAfterTyper) tpt1.tpe.<:<(pt)(ctx.addMode(Mode.GADTflexible))
558+
// special case for an abstract type that comes with a class tag
559559
tryWithClassTag(ascription(tpt1, isWildcard = true), pt)
560560
}
561561
cases(
@@ -998,37 +998,29 @@ class Typer extends Namer
998998
if (!gadtCtx.gadt.bounds.contains(sym))
999999
gadtCtx.gadt.setBounds(sym, TypeBounds.empty)
10001000

1001-
/** - replace all references to symbols associated with wildcards by their GADT bounds
1001+
/** - strip all instantiated TypeVars from pattern types.
1002+
* run/reducable.scala is a test case that shows stripping typevars is necessary.
10021003
* - enter all symbols introduced by a Bind in current scope
10031004
*/
10041005
val indexPattern = new TreeMap {
1005-
val elimWildcardSym = new TypeMap {
1006-
def apply(t: Type) = t match {
1007-
case ref: TypeRef if ref.name == tpnme.WILDCARD && gadtCtx.gadt.bounds.contains(ref.symbol) =>
1008-
gadtCtx.gadt.bounds(ref.symbol)
1009-
case TypeAlias(ref: TypeRef) if ref.name == tpnme.WILDCARD && gadtCtx.gadt.bounds.contains(ref.symbol) =>
1010-
gadtCtx.gadt.bounds(ref.symbol)
1011-
case _ =>
1012-
mapOver(t)
1013-
}
1006+
val stripTypeVars = new TypeMap {
1007+
def apply(t: Type) = mapOver(t)
10141008
}
10151009
override def transform(trt: Tree)(implicit ctx: Context) =
1016-
super.transform(trt.withType(elimWildcardSym(trt.tpe))) match {
1010+
super.transform(trt.withType(stripTypeVars(trt.tpe))) match {
10171011
case b: Bind =>
10181012
val sym = b.symbol
1019-
if (sym.exists) {
1013+
if (sym.name != tpnme.WILDCARD)
10201014
if (ctx.scope.lookup(b.name) == NoSymbol) ctx.enter(sym)
10211015
else ctx.error(new DuplicateBind(b, tree), b.pos)
1022-
sym.info = elimWildcardSym(sym.info)
1023-
b
1024-
}
1025-
else {
1026-
assert(b.name == tpnme.WILDCARD)
1027-
b.body
1016+
if (!ctx.isAfterTyper) {
1017+
val bounds = ctx.gadt.bounds(sym)
1018+
if (bounds != null) sym.info = bounds
10281019
}
1020+
b
10291021
case t => t
10301022
}
1031-
}
1023+
}
10321024

10331025
def caseRest(pat: Tree)(implicit ctx: Context) = {
10341026
val pat1 = indexPattern.transform(pat)
@@ -1264,7 +1256,7 @@ class Typer extends Namer
12641256
assignType(cpy.ByNameTypeTree(tree)(result1), result1)
12651257
}
12661258

1267-
def typedTypeBoundsTree(tree: untpd.TypeBoundsTree)(implicit ctx: Context): Tree = track("typedTypeBoundsTree") {
1259+
def typedTypeBoundsTree(tree: untpd.TypeBoundsTree, pt: Type)(implicit ctx: Context): Tree = track("typedTypeBoundsTree") {
12681260
val TypeBoundsTree(lo, hi) = tree
12691261
val lo1 = typed(lo)
12701262
val hi1 = typed(hi)
@@ -1279,8 +1271,12 @@ class Typer extends Namer
12791271
// with an expected type in typedTyped. The type symbol and the defining Bind node
12801272
// are eliminated once the enclosing pattern has been typechecked; see `indexPattern`
12811273
// in `typedCase`.
1282-
val wildcardSym = ctx.newPatternBoundSymbol(tpnme.WILDCARD, tree1.tpe, tree.pos)
1283-
untpd.Bind(tpnme.WILDCARD, tree1).withType(wildcardSym.typeRef)
1274+
//val ptt = if (lo.isEmpty && hi.isEmpty) pt else
1275+
if (ctx.isAfterTyper) tree1
1276+
else {
1277+
val wildcardSym = ctx.newPatternBoundSymbol(tpnme.WILDCARD, tree1.tpe & pt, tree.pos)
1278+
untpd.Bind(tpnme.WILDCARD, tree1).withType(wildcardSym.typeRef)
1279+
}
12841280
}
12851281
else tree1
12861282
}
@@ -1749,7 +1745,7 @@ class Typer extends Namer
17491745
case tree: untpd.AppliedTypeTree => typedAppliedTypeTree(tree)
17501746
case tree: untpd.LambdaTypeTree => typedLambdaTypeTree(tree)(localContext(tree, NoSymbol).setNewScope)
17511747
case tree: untpd.ByNameTypeTree => typedByNameTypeTree(tree)
1752-
case tree: untpd.TypeBoundsTree => typedTypeBoundsTree(tree)
1748+
case tree: untpd.TypeBoundsTree => typedTypeBoundsTree(tree, pt)
17531749
case tree: untpd.Alternative => typedAlternative(tree, pt)
17541750
case tree: untpd.PackageDef => typedPackageDef(tree)
17551751
case tree: untpd.Annotated => typedAnnotated(tree, pt)

0 commit comments

Comments
 (0)