Skip to content

Commit 9e266e4

Browse files
authored
Make sure definition tree has the defined symbol (#21851)
It turns out it could have the wrong symbol referring to a same-named definition in the superclass under some recursive definition of a self type. This caused a crash in pickler in #21755 because we now have two different definitions in two different classes that have the same symbol. Fixes #21755
2 parents caac72a + 03ee583 commit 9e266e4

File tree

4 files changed

+34
-3
lines changed

4 files changed

+34
-3
lines changed

Diff for: compiler/src/dotty/tools/dotc/ast/tpd.scala

+16
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import Symbols.*, StdNames.*, Annotations.*, Trees.*, Symbols.*
1111
import Decorators.*, DenotTransformers.*
1212
import collection.{immutable, mutable}
1313
import util.{Property, SourceFile}
14+
import config.Printers.typr
1415
import NameKinds.{TempResultName, OuterSelectName}
1516
import typer.ConstFold
1617

@@ -1165,6 +1166,21 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
11651166
tree
11661167
}
11671168

1169+
/** Make sure tree has given symbol. This is called when typing or unpickling
1170+
* a ValDef or DefDef. It turns out that under very rare circumstances the symbol
1171+
* computed for a tree is not correct. The only known test case is i21755.scala.
1172+
* Here we have a self type that mentions a supertype as well as a type parameter
1173+
* upper-bounded by the current class and it turns out that we compute the symbol
1174+
* for a member method (named `root` in this case) in a subclass to be the
1175+
* corresponding symbol in the superclass. It is not known what are the precise
1176+
* conditions where this happens, but my guess would be that it's connected to the
1177+
* recursion in the self type.
1178+
*/
1179+
def ensureHasSym(sym: Symbol)(using Context): Unit =
1180+
if sym.exists && sym != tree.symbol then
1181+
typr.println(i"correcting definition symbol from ${tree.symbol.showLocated} to ${sym.showLocated}")
1182+
tree.overwriteType(NamedType(sym.owner.thisType, sym.asTerm.name, sym.denot))
1183+
11681184
def etaExpandCFT(using Context): Tree =
11691185
def expand(target: Tree, tp: Type)(using Context): Tree = tp match
11701186
case defn.ContextFunctionType(argTypes, resType) =>

Diff for: compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

+1
Original file line numberDiff line numberDiff line change
@@ -999,6 +999,7 @@ class TreeUnpickler(reader: TastyReader,
999999
}
10001000
}
10011001

1002+
tree.ensureHasSym(sym)
10021003
tree.setDefTree
10031004
}
10041005

Diff for: compiler/src/dotty/tools/dotc/typer/Typer.scala

+6-3
Original file line numberDiff line numberDiff line change
@@ -2949,19 +2949,22 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
29492949
val ddef2 = assignType(cpy.DefDef(ddef)(name, paramss1, tpt1, rhs1), sym)
29502950

29512951
postProcessInfo(ddef2, sym)
2952-
ddef2.setDefTree
2953-
//todo: make sure dependent method types do not depend on implicits or by-name params
2952+
//todo: make sure dependent method types do not depend on implicits or by-name params
29542953
}
29552954

29562955
/** (1) Check that the signature of the class member does not return a repeated parameter type
29572956
* (2) If info is an erased class, set erased flag of member
29582957
* (3) Check that erased classes are not parameters of polymorphic functions.
2958+
* (4) Make sure the definition's symbol is `sym`.
2959+
* (5) Set the `defTree` of `sym` to be `mdef`.
29592960
*/
2960-
private def postProcessInfo(mdef: MemberDef, sym: Symbol)(using Context): Unit =
2961+
private def postProcessInfo(mdef: MemberDef, sym: Symbol)(using Context): MemberDef =
29612962
if (!sym.isOneOf(Synthetic | InlineProxy | Param) && sym.info.finalResultType.isRepeatedParam)
29622963
report.error(em"Cannot return repeated parameter type ${sym.info.finalResultType}", sym.srcPos)
29632964
if !sym.is(Module) && !sym.isConstructor && sym.info.finalResultType.isErasedClass then
29642965
sym.setFlag(Erased)
2966+
mdef.ensureHasSym(sym)
2967+
mdef.setDefTree
29652968

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

Diff for: tests/pos/i21755.scala

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
trait GraphTraversal {
2+
type NodeT
3+
4+
protected trait Properties {
5+
def root: NodeT
6+
}
7+
8+
abstract protected class TraverserMethods[A, +CC <: TraverserMethods[A, CC]] { this: CC with Properties =>
9+
def root: NodeT
10+
}
11+
}

0 commit comments

Comments
 (0)