Skip to content

Commit 4fdb6a3

Browse files
committed
Do not update Symbol defTrees when retyping after Inlining
The scaladoc for the defTree method in Symbol states: "The tree defining the symbol at pickler time ...", but that was never really true. Previously, since the setDefTree method was used in Typer, in any retyping procedure those methods would be called again, with the main example being erasure, where we would lose parts of type information from those trees. Usually this was not an issue, since they weren't used after Erasure. However, the suspend mechanism used when compiling macros with calls to them can cause the macro tree to go through erasure, have their defTrees updated there, and then used for earlier phases, with the problematic phase here being the init-checker, which uses defTree calls extensively. In the issue minimisation, init-checker was expecting a MethodType (due to the missing TypeApply there), and instead got a PolyType, causing a crash. Coincidentally in the past we would sometimes also get issues about .tree method in Quotes returning unexpected stuff due to the same issue, so this should also help there.
1 parent 7fe6ea4 commit 4fdb6a3

File tree

6 files changed

+26
-3
lines changed

6 files changed

+26
-3
lines changed

compiler/src/dotty/tools/dotc/core/Contexts.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,7 @@ object Contexts {
367367

368368
/** Is current phase after TyperPhase? */
369369
final def isAfterTyper = base.isAfterTyper(phase)
370+
final def isAfterInlining = base.isAfterInlining(phase)
370371
final def isTyper = base.isTyper(phase)
371372

372373
/** Is this a context for the members of a class definition? */

compiler/src/dotty/tools/dotc/core/Phases.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,8 @@ object Phases {
305305
}
306306

307307
final def isAfterTyper(phase: Phase): Boolean = phase.id > typerPhase.id
308+
final def isAfterInlining(phase: Phase): Boolean =
309+
inliningPhase != NoPhase && phase.id > inliningPhase.id
308310
final def isTyper(phase: Phase): Boolean = phase.id == typerPhase.id
309311
}
310312

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2974,7 +2974,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
29742974
typedExpr(_, tpt1.tpe.widenExpr)
29752975
val vdef1 = assignType(cpy.ValDef(vdef)(name, tpt1, rhs1), sym)
29762976
postProcessInfo(vdef1, sym)
2977-
vdef1.setDefTree
2977+
if (!ctx.isAfterInlining) vdef1.setDefTree
29782978

29792979
migrate(ImplicitToGiven.valDef(vdef1))
29802980

@@ -3097,7 +3097,8 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
30973097
if (!sym.isOneOf(Synthetic | InlineProxy | Param) && sym.info.finalResultType.isRepeatedParam)
30983098
report.error(em"Cannot return repeated parameter type ${sym.info.finalResultType}", sym.srcPos)
30993099
mdef.ensureHasSym(sym)
3100-
mdef.setDefTree
3100+
if (!ctx.isAfterInlining) mdef.setDefTree
3101+
else mdef
31013102

31023103
def typedTypeDef(tdef: untpd.TypeDef, sym: Symbol)(using Context): Tree = ctx.profiler.onTypedDef(sym) {
31033104
val TypeDef(name, rhs) = tdef

tests/pos-macros/i22584/Macro.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ object Macros {
2222
}
2323
}
2424

25-
val expected = "List(DefDef(boolean,List(List()),TypeTree[TypeRef(ThisType(TypeRef(NoPrefix,module class scala)),class Boolean)],Select(This(Ident(MyClass1)),boolean)), DefDef(finalVal,List(List()),TypeTree[TypeRef(ThisType(TypeRef(NoPrefix,module class lang)),class String)],Select(This(Ident(MyClass1)),finalVal)), DefDef(int,List(List()),TypeTree[TypeRef(ThisType(TypeRef(NoPrefix,module class scala)),class Int)],Select(This(Ident(MyClass1)),int)), DefDef(string,List(List()),TypeTree[TypeRef(ThisType(TypeRef(NoPrefix,module class lang)),class String)],Select(This(Ident(MyClass1)),string)))"
25+
val expected = "List(ValDef(boolean,TypeTree[TypeRef(TermRef(ThisType(TypeRef(NoPrefix,module class <root>)),object scala),class Boolean)],EmptyTree), ValDef(finalVal,Ident(String),Literal(Constant(result))), ValDef(int,TypeTree[TypeRef(TermRef(ThisType(TypeRef(NoPrefix,module class <root>)),object scala),class Int)],EmptyTree), ValDef(string,TypeTree[TypeRef(TermRef(ThisType(TypeRef(NoPrefix,module class scala)),object Predef),type String)],EmptyTree))"
2626
assert(caseFieldValOrDefDefs.toString == expected)
2727

2828
'{ () }

tests/pos/i21176-a/Macro.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//> using options -Wsafe-init
2+
import scala.quoted.*
3+
4+
class Macro:
5+
def tuple[T](name: String): (String, List[T]) = (name, List[T]())
6+
inline def nameTuple[T]: (String, List[T]) = tuple(Macro.named)
7+
8+
object Macro:
9+
def namedMacro(using q: Quotes): Expr[String] =
10+
Expr("test")
11+
12+
inline def named: String = ${Macro.namedMacro}

tests/pos/i21176-a/Main.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
//> using options -Wsafe-init
2+
class Test extends Macro:
3+
val abc = nameTuple[Int]
4+
5+
@main
6+
def run(): Unit =
7+
println(new Test().abc)

0 commit comments

Comments
 (0)