Skip to content

Commit bc086fd

Browse files
committed
Fix binding bounds
1 parent 739f999 commit bc086fd

File tree

4 files changed

+73
-16
lines changed

4 files changed

+73
-16
lines changed

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -810,10 +810,17 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
810810

811811
/** The variables defined by a pattern, in reverse order of their appearance. */
812812
def patVars(tree: Tree)(using Context): List[Symbol] = {
813-
val acc = new TreeAccumulator[List[Symbol]] {
813+
val acc = new TreeAccumulator[List[Symbol]] { outer =>
814814
def apply(syms: List[Symbol], tree: Tree)(using Context) = tree match {
815815
case Bind(_, body) => apply(tree.symbol :: syms, body)
816816
case Annotated(tree, id @ Ident(tpnme.BOUNDTYPE_ANNOT)) => apply(id.symbol :: syms, tree)
817+
case QuotePattern(bindings, body, _) =>
818+
new TreeAccumulator[List[Symbol]] {
819+
def apply(syms: List[Symbol], tree: Tree)(using Context) = tree match {
820+
case SplicePattern(pat, _) => outer.apply(syms, pat)
821+
case _ => foldOver(syms, tree)
822+
}
823+
}.apply(bindings.map(_.symbol) ::: syms, body)
817824
case _ => foldOver(syms, tree)
818825
}
819826
}

compiler/src/dotty/tools/dotc/quoted/QuotePatterns.scala

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,18 +64,21 @@ object QuotePatterns:
6464
val shape1 =
6565
if quotePattern.bindings.isEmpty then shape0
6666
else
67-
val patternTypes = quotePattern.bindings.map { binding =>
67+
val oldBindings = quotePattern.bindings.map(_.symbol)
68+
val newBindings = quotePattern.bindings.map { binding =>
6869
val sym = binding.symbol
6970
val typeSym = newSymbol(ctx.owner, sym.name ++ "$inPattern" /* TODO remove $inPattern */, EmptyFlags, sym.info, NoSymbol, binding.span)
7071
typeSym.addAnnotation(defn.QuotedRuntimePatterns_patternTypeAnnot)
7172
for fromAbove <- sym.getAnnotation(defn.QuotedRuntimePatterns_fromAboveAnnot) do
7273
typeSym.addAnnotation(fromAbove)
73-
TypeDef(typeSym.asType).withSpan(binding.span)
74+
typeSym.asType
7475
}
75-
new TreeTypeMap(
76-
substFrom = quotePattern.bindings.map(_.symbol),
77-
substTo = patternTypes.map(_.symbol)
78-
).transform(Block(patternTypes, shape0))
76+
var newBindingsRefs = newBindings.map(_.typeRef)
77+
for newBinding <- newBindings do
78+
newBinding.info = newBinding.info.subst(oldBindings, newBindingsRefs)
79+
80+
val patternTypes = newBindings.map(sym => TypeDef(sym).withSpan(sym.span))
81+
Block(patternTypes, shape0.subst(oldBindings, newBindings))
7982

8083

8184
val quotedShape =

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

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -206,13 +206,7 @@ trait QuotesAndSplices {
206206
private def splitQuotePattern(quoted: Tree)(using Context): (collection.Map[Symbol, Bind], Tree, List[Tree]) = {
207207
val ctx0 = ctx
208208

209-
val typeBindings: mutable.Map[Symbol, Bind] = mutable.LinkedHashMap.empty
210-
def getBinding(sym: Symbol): Bind =
211-
typeBindings.getOrElseUpdate(sym, {
212-
val bindingBounds = sym.info
213-
val bsym = newPatternBoundSymbol(sym.name.toString.stripPrefix("$").toTypeName, bindingBounds, quoted.span)
214-
Bind(bsym, untpd.Ident(nme.WILDCARD).withType(bindingBounds)).withSpan(quoted.span)
215-
})
209+
val bindSymMapping: collection.Map[Symbol, Bind] = unapplyBindingsMapping(quoted)
216210

217211
object splitter extends tpd.TreeMap {
218212
private var variance: Int = 1
@@ -292,13 +286,14 @@ trait QuotesAndSplices {
292286
report.error(IllegalVariableInPatternAlternative(tdef.symbol.name), tdef.srcPos)
293287
if variance == -1 then
294288
tdef.symbol.addAnnotation(Annotation(New(ref(defn.QuotedRuntimePatterns_fromAboveAnnot.typeRef)).withSpan(tdef.span)))
295-
val bindingType = getBinding(tdef.symbol).symbol.typeRef
289+
val bindingType = bindSymMapping(tdef.symbol).symbol.typeRef
296290
val bindingTypeTpe = AppliedType(defn.QuotedTypeClass.typeRef, bindingType :: Nil)
297291
val sym = newPatternBoundSymbol(nameOfSyntheticGiven, bindingTypeTpe, tdef.span, flags = ImplicitVal)(using ctx0)
298292
buff += Bind(sym, untpd.Ident(nme.WILDCARD).withType(bindingTypeTpe)).withSpan(tdef.span)
299293
super.transform(tdef)
300294
}
301295
}
296+
302297
val shape0 = splitter.transform(quoted)
303298
val patterns = (splitter.typePatBuf.iterator ++ splitter.freshTypePatBuf.iterator ++ splitter.patBuf.iterator).toList
304299
val freshTypeBindings = splitter.freshTypeBindingsBuff.result()
@@ -329,7 +324,42 @@ trait QuotesAndSplices {
329324
new TreeTypeMap(typeMap = typeMap).transform(shape1)
330325
}
331326

332-
(typeBindings, shape2, patterns)
327+
(bindSymMapping, shape2, patterns)
328+
}
329+
330+
private def unapplyBindingsMapping(quoted: Tree)(using Context): collection.Map[Symbol, Bind] = {
331+
val mapping = mutable.LinkedHashMap.empty[Symbol, Symbol]
332+
new tpd.TreeTraverser {
333+
def traverse(tree: Tree)(using Context): Unit = tree match {
334+
case _: SplicePattern =>
335+
case Select(pat: Bind, _) if tree.symbol.isTypeSplice =>
336+
val sym = tree.tpe.dealias.typeSymbol
337+
if sym.exists then registerNewBindSym(sym)
338+
case tdef: TypeDef =>
339+
if tdef.symbol.hasAnnotation(defn.QuotedRuntimePatterns_patternTypeAnnot) then
340+
registerNewBindSym(tdef.symbol)
341+
traverseChildren(tdef)
342+
case _ =>
343+
traverseChildren(tree)
344+
}
345+
private def registerNewBindSym(sym: Symbol): Unit =
346+
if !mapping.contains(sym) then
347+
mapping(sym) = newSymbol(ctx.owner, sym.name.toString.stripPrefix("$").toTypeName, Case | sym.flags, sym.info, coord = quoted.span)
348+
}.traverse(quoted)
349+
350+
// Replace symbols in `mapping` in the infos of the new symbol and register GADT bounds.
351+
// GADT bounds need to be added after the info is updated to avoid references to the old symbols.
352+
var oldBindings: List[Symbol] = mapping.keys.toList
353+
var newBindingsRefs: List[Type] = mapping.values.toList.map(_.typeRef)
354+
for newBindings <- mapping.values do
355+
newBindings.info = newBindings.info.subst(oldBindings, newBindingsRefs)
356+
ctx.gadtState.addToConstraint(newBindings)
357+
358+
// Map into Bind nodes retaining the original order
359+
val mapping2: mutable.Map[Symbol, Bind] = mutable.LinkedHashMap.empty
360+
for (oldSym, newSym) <- mapping do
361+
mapping2(oldSym) = Bind(newSym, untpd.Ident(nme.WILDCARD).withType(newSym.info)).withSpan(quoted.span)
362+
mapping2
333363
}
334364

335365
/** Type a quote pattern `case '{ <quoted> } =>` qiven the a current prototype. Typing the pattern
@@ -451,6 +481,11 @@ trait QuotesAndSplices {
451481

452482
val decoded = QuotePatterns.decode(patternUnapply)
453483
decoded.foreach(QuotePatterns.checkPattern)
484+
// val encoded = QuotePatterns.encode(decoded.get)
485+
// println(patternUnapply.show)
486+
// println(encoded.show)
487+
// println(decoded.get.show)
488+
454489
decoded.getOrElse(patternUnapply)
455490
}
456491
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import quoted.*
2+
3+
def foo(using Quotes)(x: Expr[Int]) =
4+
x match
5+
case '{ type t; type u <: `t`; f[`t`, `u`] } =>
6+
case '{ type u <: `t`; type t; f[`t`, `u`] } =>
7+
case '{ type t; type u <: `t`; g[F[`t`, `u`]] } =>
8+
case '{ type u <: `t`; type t; g[F[`t`, `u`]] } =>
9+
10+
def f[T, U <: T] = ???
11+
def g[T] = ???
12+
type F[T, U <: T]

0 commit comments

Comments
 (0)