Skip to content

Commit d96d4f3

Browse files
committed
Fix quotes with references to path dependent types
1 parent 693e5b9 commit d96d4f3

File tree

3 files changed

+117
-22
lines changed

3 files changed

+117
-22
lines changed

compiler/src/dotty/tools/dotc/staging/HealType.scala

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -30,38 +30,41 @@ class HealType(pos: SrcPos)(using Context) extends TypeMap {
3030
*/
3131
def apply(tp: Type): Type =
3232
tp match
33-
case tp: TypeRef =>
34-
healTypeRef(tp)
35-
case tp @ TermRef(NoPrefix, _) if !tp.symbol.isStatic && level > levelOf(tp.symbol) =>
36-
levelError(tp.symbol, tp, pos)
33+
case tp @ TypeRef(NoPrefix, _) if tp.typeSymbol.hasAnnotation(defn.QuotedRuntime_SplicedTypeAnnot) =>
34+
tp
35+
case tp @ TypeRef(prefix: TermRef, _) if tp.symbol.isTypeSplice && level > 0 =>
36+
checkNotWildcardSplice(tp)
37+
getQuoteTypeTags.getTagRef(prefix)
38+
case tp @ TypeRef(_: NamedType | _: ThisType | NoPrefix, _) =>
39+
if levelInconsistentRootOfPath(tp).exists then
40+
val tp1 = tp.dealias
41+
if tp1 != tp then apply(tp1)
42+
else tryHeal(tp.symbol, tp, pos)
43+
else
44+
tp
45+
case tp: TermRef =>
46+
val inconsistentRoot = levelInconsistentRootOfPath(tp)
47+
if inconsistentRoot.exists then levelError(inconsistentRoot, tp, pos)
48+
else tp
3749
case tp: AnnotatedType =>
3850
derivedAnnotatedType(tp, apply(tp.parent), tp.annot)
3951
case _ =>
4052
mapOver(tp)
4153

42-
private def healTypeRef(tp: TypeRef): Type =
43-
tp.prefix match
44-
case prefix: TermRef if tp.symbol.isTypeSplice =>
45-
checkNotWildcardSplice(tp)
46-
if level == 0 then tp else getQuoteTypeTags.getTagRef(prefix)
47-
case prefix: TermRef if !prefix.symbol.isStatic && level > levelOf(prefix.symbol) =>
48-
dealiasAndTryHeal(prefix.symbol, tp, pos)
49-
case NoPrefix if level > levelOf(tp.symbol) && !tp.typeSymbol.hasAnnotation(defn.QuotedRuntime_SplicedTypeAnnot) =>
50-
dealiasAndTryHeal(tp.symbol, tp, pos)
51-
case prefix: ThisType if level > levelOf(prefix.cls) && !tp.symbol.isStatic =>
52-
dealiasAndTryHeal(tp.symbol, tp, pos)
53-
case _ =>
54-
mapOver(tp)
55-
5654
private def checkNotWildcardSplice(splice: TypeRef): Unit =
5755
splice.prefix.termSymbol.info.argInfos match
5856
case (tb: TypeBounds) :: _ => report.error(em"Cannot splice $splice because it is a wildcard type", pos)
5957
case _ =>
6058

61-
private def dealiasAndTryHeal(sym: Symbol, tp: TypeRef, pos: SrcPos): Type =
62-
val tp1 = tp.dealias
63-
if tp1 != tp then apply(tp1)
64-
else tryHeal(tp.symbol, tp, pos)
59+
/** Return the root of this path if it is a variable defined in a previous level.
60+
* If the path is consistent, return NoSymbol.
61+
*/
62+
private def levelInconsistentRootOfPath(tp: Type)(using Context): Symbol =
63+
tp match
64+
case tp @ NamedType(NoPrefix, _) if level > levelOf(tp.symbol) => tp.symbol
65+
case tp: NamedType if !tp.symbol.isStatic => levelInconsistentRootOfPath(tp.prefix)
66+
case tp: ThisType if level > levelOf(tp.cls) => tp.cls
67+
case _ => NoSymbol
6568

6669
/** Try to heal reference to type `T` used in a higher level than its definition.
6770
* Returns a reference to a type tag generated by `QuoteTypeTags` that contains a
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import scala.quoted.*
2+
3+
trait A:
4+
type T
5+
val b: B
6+
7+
trait B:
8+
type T
9+
def f: Unit
10+
11+
trait C0:
12+
type U
13+
val d: D0
14+
trait D0:
15+
type U
16+
def h: Unit
17+
object Macro:
18+
inline def generateCode: Unit = ${ generateCodeExpr }
19+
20+
def generateCodeExpr(using Quotes): Expr[Unit] =
21+
'{
22+
$testLocalPathsGlobalClasses
23+
$testLocalPathsLocalClasses
24+
// $testThisPaths // FIXME java.lang.ClassCastException: class scala.quoted.runtime.impl.ExprImpl cannot be cast to class scala.quoted.Type
25+
}
26+
27+
def testLocalPathsGlobalClasses(using Quotes): Expr[Unit] =
28+
'{
29+
type T
30+
val a: A = ???
31+
${
32+
val expr = '{
33+
val t: T = ???
34+
val aT: a.T = ???
35+
val abT: a.b.T = ???
36+
val aRef: a.type = ???
37+
aRef.b
38+
aRef.b.f
39+
val abRef: a.b.type = ???
40+
abRef.f
41+
}
42+
expr
43+
}
44+
}
45+
46+
def testLocalPathsLocalClasses(using Quotes): Expr[Unit] =
47+
'{
48+
type U
49+
trait C extends C0:
50+
type U
51+
val d: D
52+
trait D extends D0:
53+
type U
54+
def h: Unit
55+
val c: C = ???
56+
${
57+
val expr = '{
58+
val u: U = ???
59+
val cU: c.U = ???
60+
val cdU: c.d.U = ???
61+
val cRef: c.type = ???
62+
// cRef.d // FIXME
63+
// cRef.d.h // FIXME
64+
val cdRef: c.d.type = ???
65+
// cdRef.h // FIXME
66+
}
67+
expr
68+
}
69+
}
70+
71+
// def testThisPaths(using Quotes): Expr[Unit] =
72+
// '{
73+
// trait E:
74+
// type V
75+
// val f: F
76+
// ${
77+
// val expr = '{
78+
// val _: Any = this
79+
// val _: Any = f
80+
// val _: this.type = ???
81+
// val _: V = ???
82+
// val _: this.V = ???
83+
// val _: this.f.V = ???
84+
// val _: this.type = ???
85+
// val _: this.f.type = ???
86+
// }
87+
// expr
88+
// }
89+
// trait F:
90+
// type V
91+
// }
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@main def test = Macro.generateCode

0 commit comments

Comments
 (0)