Skip to content

Commit

Permalink
Fix captured references to singleton types
Browse files Browse the repository at this point in the history
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. These have been
fixed as well.
  • Loading branch information
nicolasstucki committed Mar 15, 2023
1 parent bc90b96 commit ec65eb3
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 5 deletions.
9 changes: 8 additions & 1 deletion compiler/src/dotty/tools/dotc/transform/PickleQuotes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -157,13 +157,20 @@ class PickleQuotes extends MacroTransform {
override def apply(tp: Type): Type = tp match
case tp: TypeRef if tp.typeSymbol.isTypeSplice =>
apply(tp.dealias)
case tp @ TypeRef(pre, _) if pre == NoPrefix || pre.termSymbol.isLocal =>
case tp @ TypeRef(pre, _) if isLocalPath(pre) =>
val hiBound = tp.typeSymbol.info match
case info: ClassInfo => info.parents.reduce(_ & _)
case info => info.hiBound
apply(hiBound)
case tp @ TermRef(pre, _) if isLocalPath(pre) =>
apply(tp.widenTermRefExpr)
case tp =>
mapOver(tp)

private def isLocalPath(tp: Type): Boolean = tp match
case NoPrefix => true
case tp: TermRef if !tp.symbol.is(Package) => isLocalPath(tp.prefix)
case tp => false
}

/** Remove references to local types that will not be defined in this quote */
Expand Down
5 changes: 2 additions & 3 deletions compiler/src/dotty/tools/dotc/transform/Splicing.scala
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ class Splicing extends MacroTransform:
// Dealias references to captured types
TypeTree(tree.tpe.dealias)
else super.transform(tree)
case tree: TypeTree =>
case _: TypeTree | _: SingletonTypeTree =>
if containsCapturedType(tree.tpe) && level >= 1 then getTagRefFor(tree)
else tree
case tree @ Assign(lhs: RefTree, rhs) =>
Expand Down Expand Up @@ -361,9 +361,8 @@ class Splicing extends MacroTransform:
)

private def capturedType(tree: Tree)(using Context): Symbol =
val tpe = tree.tpe.widenTermRefExpr
val bindingSym = refBindingMap
.getOrElseUpdate(tree.symbol, (TypeTree(tree.tpe), newQuotedTypeClassBinding(tpe)))._2
.getOrElseUpdate(tree.symbol, (TypeTree(tree.tpe), newQuotedTypeClassBinding(tree.tpe)))._2
bindingSym

private def capturedPartTypes(tpt: Tree)(using Context): Tree =
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/transform/TreeChecker.scala
Original file line number Diff line number Diff line change
Expand Up @@ -658,7 +658,7 @@ object TreeChecker {
// Check that we only add the captured type `T` instead of a more complex type like `List[T]`.
// If we have `F[T]` with captured `F` and `T`, we should list `F` and `T` separately in the args.
for arg <- args do
assert(arg.isTerm || arg.tpe.isInstanceOf[TypeRef], "Expected TypeRef in Hole type args but got: " + arg.tpe)
assert(arg.isTerm || arg.tpe.isInstanceOf[TypeRef] || arg.tpe.isInstanceOf[TermRef], "Expected TypeRef or TermRef in Hole type args but got: " + arg.tpe)

// Check result type of the hole
if isTermHole then assert(tpt.typeOpt <:< pt)
Expand Down
16 changes: 16 additions & 0 deletions tests/neg-macros/i17103.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import scala.quoted.*

def test(using Quotes): Expr[Unit] =
'{
trait C:
def d: Int
val c: C = ???
${
val expr = '{
val cRef: c.type = ???
cRef.d // error
()
}
expr
}
}
21 changes: 21 additions & 0 deletions tests/pos-macros/i17103b.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import scala.quoted.*

trait C0:
def d: Int

def test(using Quotes): Expr[Unit] =
'{
trait C1 extends C0:
def d: Int
trait C extends C1:
def d: Int
val c: C = ???
${
val expr = '{
val cRef: c.type = ???
cRef.d // calls C0.d
()
}
expr
}
}

0 comments on commit ec65eb3

Please sign in to comment.