Skip to content

Commit 2731ec5

Browse files
committed
Fix captured references to singleton types
When we had a reference to a `x.type` we mistakenly captured `x` instead of `x.type`. This was caused because `SingletonTypeTree` was not handled in `Splicing`. Fixing this uncovered some inconsistencies with the types in the encoding of the hole captured types and contents.
1 parent 965818a commit 2731ec5

File tree

4 files changed

+21
-7
lines changed

4 files changed

+21
-7
lines changed

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

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ class Splicing extends MacroTransform:
209209
// Dealias references to captured types
210210
TypeTree(tree.tpe.dealias)
211211
else super.transform(tree)
212-
case tree: TypeTree =>
212+
case _: TypeTree | _: SingletonTypeTree =>
213213
if containsCapturedType(tree.tpe) && level >= 1 then getTagRefFor(tree)
214214
else tree
215215
case tree @ Assign(lhs: RefTree, rhs) =>
@@ -314,10 +314,7 @@ class Splicing extends MacroTransform:
314314
)
315315

316316
private def capturedType(tree: Tree)(using Context): Symbol =
317-
val tpe = tree.tpe.widenTermRefExpr
318-
val bindingSym = refBindingMap
319-
.getOrElseUpdate(tree.symbol, (TypeTree(tree.tpe), newQuotedTypeClassBinding(tpe)))._2
320-
bindingSym
317+
refBindingMap.getOrElseUpdate(tree.symbol, (TypeTree(tree.tpe), newQuotedTypeClassBinding(tree.tpe)))._2
321318

322319
private def capturedPartTypes(quote: Quote)(using Context): Tree =
323320
val (tags, body1) = inContextWithQuoteTypeTags {

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -727,7 +727,7 @@ object TreeChecker {
727727
// Check that we only add the captured type `T` instead of a more complex type like `List[T]`.
728728
// If we have `F[T]` with captured `F` and `T`, we should list `F` and `T` separately in the args.
729729
for arg <- args do
730-
assert(arg.isTerm || arg.tpe.isInstanceOf[TypeRef], "Expected TypeRef in Hole type args but got: " + arg.tpe)
730+
assert(arg.isTerm || arg.tpe.isInstanceOf[TypeRef] || arg.tpe.isInstanceOf[TermRef] || arg.tpe.isInstanceOf[ThisType], "Expected TypeRef in Hole type args but got: " + arg.tpe)
731731

732732
// Check result type of the hole
733733
if isTerm then assert(tree1.typeOpt <:< pt)
@@ -743,7 +743,7 @@ object TreeChecker {
743743
defn.AnyType
744744
case tpe => tpe
745745
defn.QuotedExprClass.typeRef.appliedTo(tpe)
746-
else defn.QuotedTypeClass.typeRef.appliedTo(arg.typeOpt.widenTermRefExpr)
746+
else defn.QuotedTypeClass.typeRef.appliedTo(arg.typeOpt)
747747
}
748748
val expectedResultType =
749749
if isTerm then defn.QuotedExprClass.typeRef.appliedTo(tree1.typeOpt)
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import scala.quoted.*
2+
3+
inline def test = ${ testExpr }
4+
5+
def testExpr(using Quotes): Expr[Unit] =
6+
'{
7+
trait C
8+
val c: C = ???
9+
${
10+
val expr = '{
11+
val cRef: c.type = ???
12+
()
13+
}
14+
expr
15+
}
16+
}

tests/pos-macros/i17103c/Test_2.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
def Test = test

0 commit comments

Comments
 (0)