Skip to content

Commit b991e1f

Browse files
committed
Error when type variables that an argument depends on are not captured in a hoas pattern
1 parent ba2c8e1 commit b991e1f

File tree

2 files changed

+42
-23
lines changed

2 files changed

+42
-23
lines changed

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

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -27,50 +27,70 @@ object QuotePatterns:
2727

2828
/** Check for restricted patterns */
2929
def checkPattern(quotePattern: QuotePattern)(using Context): Unit =
30-
new tpd.TreeTraverser {
31-
def traverse(tree: Tree)(using Context): Unit = tree match {
32-
case _: SplicePattern =>
30+
val typevars = new tpd.TreeAccumulator[Set[Symbol]] {
31+
override def apply(typevars: Set[Symbol], tree: tpd.Tree)(using Context): Set[Symbol] = tree match {
32+
case _: SplicePattern => typevars
33+
case tree @ DefDef(_, paramss, _, _) =>
34+
val newTypevars = paramss.flatMap{ params => params match
35+
case TypeDefs(tdefs) => tdefs.map(_.symbol)
36+
case _ => List.empty
37+
}.toSet
38+
foldOver(typevars union newTypevars, tree.rhs)
3339
case tdef: TypeDef if tdef.symbol.isClass =>
3440
val kind = if tdef.symbol.is(Module) then "objects" else "classes"
3541
report.error(em"Implementation restriction: cannot match $kind", tree.srcPos)
42+
typevars
3643
case tree: NamedDefTree =>
3744
if tree.name.is(NameKinds.WildcardParamName) then
3845
report.warning(
3946
"Use of `_` for lambda in quoted pattern. Use explicit lambda instead or use `$_` to match any term.",
4047
tree.srcPos)
4148
if tree.name.isTermName && !tree.nameSpan.isSynthetic && tree.name != nme.ANON_FUN && tree.name.startsWith("$") then
4249
report.error("Names cannot start with $ quote pattern", tree.namePos)
43-
traverseChildren(tree)
50+
foldOver(typevars, tree)
4451
case _: Match =>
4552
report.error("Implementation restriction: cannot match `match` expressions", tree.srcPos)
53+
typevars
4654
case _: Try =>
4755
report.error("Implementation restriction: cannot match `try` expressions", tree.srcPos)
56+
typevars
4857
case _: Return =>
4958
report.error("Implementation restriction: cannot match `return` statements", tree.srcPos)
50-
case _ =>
51-
traverseChildren(tree)
59+
typevars
60+
case _ => foldOver(typevars, tree)
5261
}
62+
}.apply(Set.empty, quotePattern.body)
5363

54-
}.traverse(quotePattern.body)
5564
// TODO-18271: Refactor this
56-
new tpd.TreeAccumulator[List[Symbol]] {
57-
override def apply(typevars: List[Symbol], tree: tpd.Tree)(using Context): List[Symbol] = tree match {
65+
new tpd.TreeTraverser {
66+
override def traverse(tree: tpd.Tree)(using Context): Unit = tree match {
5867
case tree: SplicePattern =>
68+
def uncapturedTypeVars(arg: tpd.Tree, capturedTypeVars: List[tpd.Tree]) =
69+
val capturedTypeVarsSet = capturedTypeVars.map(_.symbol).toSet
70+
println("--- uncapturedTypeVars")
71+
println(s"typevars = ${typevars.map(_.show)}")
72+
println(s"capturedTypevars = ${capturedTypeVarsSet.map(_.show)}")
73+
new TypeAccumulator[Set[Type]] {
74+
def apply(x: Set[Type], tp: Type): Set[Type] =
75+
if typevars.contains(tp.typeSymbol) && !capturedTypeVarsSet.contains(tp.typeSymbol) then
76+
foldOver(x + tp, tp)
77+
else
78+
foldOver(x, tp)
79+
}.apply(Set.empty, arg.tpe)
80+
81+
// Type arguments to a splice patterns must be type variables that are introduced
82+
// inside the quote pattern
5983
for (typearg <- tree.typeargs)
6084
do
6185
if !typevars.contains(typearg.symbol) then
62-
report.error("Type parameters to a hoas pattern needs to be introduced in the quoted pattern", typearg.srcPos)
63-
typevars
64-
case tree @ DefDef(_, paramss, _, _) =>
65-
val newTypevars = paramss flatMap { params => params match
66-
case TypeDefs(tdefs) => tdefs map (_.symbol)
67-
case _ => List.empty
68-
}
69-
foldOver(typevars ++: newTypevars, tree.rhs)
70-
typevars
71-
case _ => foldOver(typevars, tree)
86+
report.error("Type arguments of a hoas pattern needs to be introduced in the quoted pattern", typearg.srcPos)
87+
for (arg <- tree.args)
88+
do
89+
if !uncapturedTypeVars(arg, tree.typeargs).isEmpty then
90+
report.error("Type variables that this argument depends on are not captured in this hoas pattern", arg.srcPos)
91+
case _ => traverseChildren(tree)
7292
}
73-
}.apply(List.empty, quotePattern.body)
93+
}.traverse(quotePattern.body)
7494

7595
/** Encode the quote pattern into an `unapply` that the pattern matcher can handle.
7696
*
@@ -272,8 +292,6 @@ object QuotePatterns:
272292
case Apply(patternHole, SeqLiteral(args, _) :: Nil) if patternHole.symbol == defn.QuotedRuntimePatterns_higherOrderHole =>
273293
cpy.SplicePattern(tree)(patternIterator.next(), Nil, args)
274294
case Apply(TypeApply(patternHole, List(_, targsTpe)), SeqLiteral(args, _) :: Nil) if patternHole.symbol == defn.QuotedRuntimePatterns_higherOrderHoleWithTypes =>
275-
// TODO-18271: error on ill-formed typed arguments?
276-
// TODO-18271: test case?
277295
cpy.SplicePattern(tree)(patternIterator.next(), unrollHkNestedPairsTypeTree(targsTpe), args)
278296
case _ => super.transform(tree)
279297
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,8 @@ class QuoteMatcher(debug: Boolean) {
649649
val hoasClosure = Closure(meth, bodyFn)
650650
new ExprImpl(hoasClosure, spliceScope)
651651
else
652+
// TODO-18271: This implementation fails Typer.assertPositioned.
653+
// We want to find safe way to generate poly function
652654
val names: List[TermName] = argIds.map(_.symbol.name.asTermName)
653655
val paramTypes = argTypes.map(tpe => mapTypeHoles(tpe.widenTermRefExpr))
654656

@@ -662,7 +664,6 @@ class QuoteMatcher(debug: Boolean) {
662664
}
663665
val methTpe = PolyType(typeArgs1)(_ => bounds, resultTypeExp)
664666
val meth = newAnonFun(ctx.owner, methTpe)
665-
// TODO-18271
666667
def bodyFn(lambdaArgss: List[List[Tree]]): Tree = {
667668
val typeArgs = lambdaArgss.head
668669
val argsMap = argIds.view.map(_.symbol).zip(lambdaArgss.tail.head).toMap

0 commit comments

Comments
 (0)