Skip to content

Commit 2ee1db1

Browse files
oderskytgodzik
authored andcommitted
Make sure definition tree has the defined symbol
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 scala#21755 because we now have two different definitions in two different classes that have the same symbol. Fixes scala#21755
1 parent 1d5e3c5 commit 2ee1db1

File tree

4 files changed

+36
-4
lines changed

4 files changed

+36
-4
lines changed

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

@@ -1155,6 +1156,21 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
11551156
tree
11561157
}
11571158

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

compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

+1
Original file line numberDiff line numberDiff line change
@@ -960,6 +960,7 @@ class TreeUnpickler(reader: TastyReader,
960960
}
961961
}
962962

963+
tree.ensureHasSym(sym)
963964
tree.setDefTree
964965
}
965966

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

+8-4
Original file line numberDiff line numberDiff line change
@@ -2610,19 +2610,23 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
26102610

26112611
val ddef2 = assignType(cpy.DefDef(ddef)(name, paramss1, tpt1, rhs1), sym)
26122612

2613-
postProcessInfo(sym)
2614-
ddef2.setDefTree
2615-
//todo: make sure dependent method types do not depend on implicits or by-name params
2613+
postProcessInfo(ddef2, sym)
2614+
//todo: make sure dependent method types do not depend on implicits or by-name params
26162615
}
26172616

26182617
/** (1) Check that the signature of the class member does not return a repeated parameter type
26192618
* (2) If info is an erased class, set erased flag of member
2619+
* (3) Check that erased classes are not parameters of polymorphic functions.
2620+
* (4) Make sure the definition's symbol is `sym`.
2621+
* (5) Set the `defTree` of `sym` to be `mdef`.
26202622
*/
2621-
private def postProcessInfo(sym: Symbol)(using Context): Unit =
2623+
private def postProcessInfo(mdef: MemberDef, sym: Symbol)(using Context): MemberDef =
26222624
if (!sym.isOneOf(Synthetic | InlineProxy | Param) && sym.info.finalResultType.isRepeatedParam)
26232625
report.error(em"Cannot return repeated parameter type ${sym.info.finalResultType}", sym.srcPos)
26242626
if !sym.is(Module) && !sym.isConstructor && sym.info.finalResultType.isErasedClass then
26252627
sym.setFlag(Erased)
2628+
mdef.ensureHasSym(sym)
2629+
mdef.setDefTree
26262630

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

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)