Skip to content

Commit a0a0bce

Browse files
committed
Fix scala#7405: Allow types references at a lower level
To be able to have references to type tags of types defined in a higher level we need to generalize the concept of type healing. In this case we instead of needing to keep a type tag for the next stage it should be possible to refer to types for a next level. This is already the case inside of top level splices in inline methods (macros) but it should be possible to do in any code.
1 parent 3a7dfd2 commit a0a0bce

File tree

5 files changed

+38
-3
lines changed

5 files changed

+38
-3
lines changed

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
215215
assert(ctx.inInlineMethod)
216216
None
217217
}
218-
else {
218+
else if (levelOf(sym).getOrElse(0) < level) {
219219
val reqType = defn.QuotedTypeClass.typeRef.appliedTo(tp)
220220
val tag = ctx.typer.inferImplicitArg(reqType, pos.span)
221221
tag.tpe match {
@@ -233,6 +233,8 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
233233
|
234234
| The access would be accepted with an implict $reqType""")
235235
}
236+
} else {
237+
None
236238
}
237239
case _ =>
238240
levelError(sym, tp, pos, "")

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,14 @@ class Staging extends MacroTransform {
4444
case PackageDef(pid, _) if tree.symbol.owner == defn.RootClass =>
4545
val checker = new PCPCheckAndHeal(freshStagingContext) {
4646
override protected def tryHeal(sym: Symbol, tp: Type, pos: SourcePosition)(implicit ctx: Context): Option[tpd.Tree] = {
47+
4748
def symStr =
4849
if (!tp.isInstanceOf[ThisType]) sym.show
4950
else if (sym.is(ModuleClass)) sym.sourceModule.show
5051
else i"${sym.name}.this"
5152

5253
val errMsg = s"\nin ${ctx.owner.fullName}"
53-
assert(false,
54+
assert(levelOf(sym).getOrElse(0) >= level,
5455
em"""access to $symStr from wrong staging level:
5556
| - the definition is at level ${levelOf(sym).getOrElse(0)},
5657
| - but the access is at level $level.$errMsg""")

docs/docs/reference/metaprogramming/macros.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,8 @@ is legal because it is spliced, then quoted.
164164
### Types and the PCP
165165

166166
In principle, The phase consistency principle applies to types as well
167-
as for expressions. This might seem too restrictive. Indeed, the
167+
as for expressions. But it only acts on types that are used in higher levels.
168+
This might seem too restrictive. Indeed, the
168169
definition of `reflect` above is not phase correct since there is a
169170
quote but no splice between the parameter binding of `T` and its
170171
usage. But the code can be made phase correct by adding a binding

tests/pos/i7405.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import scala.quoted._
2+
class Foo {
3+
def f(given QuoteContext): Expr[Any] = {
4+
'{
5+
type X = Int // Level 1
6+
val x: X = ???
7+
${
8+
val t: Type[X] = '[X] // Level 0
9+
'{ val y: $t = x }
10+
}
11+
}
12+
}
13+
}

tests/pos/i7405b.scala

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import scala.quoted._
2+
3+
class Foo {
4+
def f(given QuoteContext): Expr[Any] = {
5+
'{
6+
trait X {
7+
type Y
8+
def y: Y = ???
9+
}
10+
val x: X = ???
11+
type Z = x.Y
12+
${
13+
val t: Type[Z] = '[Z]
14+
'{ val y: $t = x.y }
15+
}
16+
}
17+
}
18+
}

0 commit comments

Comments
 (0)