Skip to content

Commit bc4312e

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 d8bec0a commit bc4312e

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
@@ -2972,7 +2972,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
29722972
typedExpr(_, tpt1.tpe.widenExpr)
29732973
val vdef1 = assignType(cpy.ValDef(vdef)(name, tpt1, rhs1), sym)
29742974
postProcessInfo(vdef1, sym)
2975-
vdef1.setDefTree
2975+
if (!ctx.isAfterInlining) vdef1.setDefTree
29762976

29772977
migrate(ImplicitToGiven.valDef(vdef1))
29782978

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

31003101
def typedTypeDef(tdef: untpd.TypeDef, sym: Symbol)(using Context): Tree = ctx.profiler.onTypedDef(sym) {
31013102
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)