Skip to content

Commit 7129cbe

Browse files
committed
Merge pull request #534 from dotty-staging/fix/computeDenot
Fix #518 - compute denotations
2 parents c4dba24 + 3edf285 commit 7129cbe

File tree

4 files changed

+40
-24
lines changed

4 files changed

+40
-24
lines changed

src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,6 @@ class Definitions {
451451

452452
lazy val RootImports = List[Symbol](JavaLangPackageVal, ScalaPackageVal, ScalaPredefModule, DottyPredefModule)
453453

454-
lazy val overriddenBySynthetic = Set[Symbol](Any_equals, Any_hashCode, Any_toString, Product_canEqual)
455454
def isTupleType(tp: Type)(implicit ctx: Context) = {
456455
val arity = tp.dealias.argInfos.length
457456
arity <= MaxTupleArity && (tp isRef TupleClass(arity))

src/dotty/tools/dotc/core/Types.scala

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,19 @@ object Types {
126126
false
127127
}
128128

129+
/** Does this type refer exactly to class symbol `sym`, instead of to a subclass of `sym`?
130+
* Implemented like `isRef`, but follows more types: all type proxies as well as and- and or-types
131+
*/
132+
private[Types] def isTightPrefix(sym: Symbol)(implicit ctx: Context): Boolean = stripTypeVar match {
133+
case tp: NamedType => tp.info.isTightPrefix(sym)
134+
case tp: ClassInfo => tp.cls eq sym
135+
case tp: Types.ThisType => tp.cls eq sym
136+
case tp: TypeProxy => tp.underlying.isTightPrefix(sym)
137+
case tp: AndType => tp.tp1.isTightPrefix(sym) && tp.tp2.isTightPrefix(sym)
138+
case tp: OrType => tp.tp1.isTightPrefix(sym) || tp.tp2.isTightPrefix(sym)
139+
case _ => false
140+
}
141+
129142
/** Is this type an instance of a non-bottom subclass of the given class `cls`? */
130143
final def derivesFrom(cls: Symbol)(implicit ctx: Context): Boolean = this match {
131144
case tp: TypeRef =>
@@ -1221,27 +1234,17 @@ object Types {
12211234
val sym = lastSymbol
12221235
if (sym == null) loadDenot else denotOfSym(sym)
12231236
case d: SymDenotation =>
1224-
if ( d.validFor.runId == ctx.runId
1225-
|| ctx.stillValid(d)
1226-
|| this.isInstanceOf[WithFixedSym]) d.current
1237+
if (this.isInstanceOf[WithFixedSym]) d.current
1238+
else if (d.validFor.runId == ctx.runId || ctx.stillValid(d))
1239+
if (prefix.isTightPrefix(d.owner) || d.isConstructor) d.current
1240+
else recomputeMember(d) // symbol could have been overridden, recompute membership
12271241
else {
12281242
val newd = loadDenot
12291243
if (newd.exists) newd else d.staleSymbolError
12301244
}
12311245
case d =>
1232-
if (d.validFor.runId != ctx.period.runId)
1233-
loadDenot
1234-
// The following branch was used to avoid an assertErased error.
1235-
// It's idea was to void keeping non-sym denotations after erasure
1236-
// since they violate the assertErased contract. But the problem is
1237-
// that when seen again in an earlier phase the denotation is
1238-
// still seen as a SymDenotation, whereas it should be a SingleDenotation.
1239-
// That's why the branch is disabled.
1240-
//
1241-
// else if (ctx.erasedTypes && lastSymbol != null)
1242-
// denotOfSym(lastSymbol)
1243-
else
1244-
d.current
1246+
if (d.validFor.runId != ctx.period.runId) loadDenot
1247+
else d.current
12451248
}
12461249
if (ctx.typerState.ephemeral) record("ephemeral cache miss: loadDenot")
12471250
else if (d.exists) {
@@ -1250,14 +1253,25 @@ object Types {
12501253
// phase but a defined denotation earlier (e.g. a TypeRef to an abstract type
12511254
// is undefined after erasure.) We need to be able to do time travel back and
12521255
// forth also in these cases.
1253-
setDenot(d)
1256+
1257+
// Don't use setDenot here; double binding checks can give spurious failures after erasure
1258+
lastDenotation = d
1259+
lastSymbol = d.symbol
12541260
checkedPeriod = ctx.period
12551261
}
12561262
d
12571263
}
12581264
finally ctx.typerState.ephemeral |= savedEphemeral
12591265
}
12601266

1267+
/** A member of `prefix` (disambiguated by `d.signature`) or, if none was found, `d.current`. */
1268+
private def recomputeMember(d: SymDenotation)(implicit ctx: Context): Denotation =
1269+
asMemberOf(prefix) match {
1270+
case NoDenotation => d.current
1271+
case newd: SingleDenotation => newd
1272+
case newd => newd.atSignature(d.signature).orElse(d.current)
1273+
}
1274+
12611275
private def denotOfSym(sym: Symbol)(implicit ctx: Context): Denotation = {
12621276
val d = sym.denot
12631277
val owner = d.owner
@@ -1276,11 +1290,9 @@ object Types {
12761290
(lastDefRunId == NoRunId)
12771291
} ||
12781292
(lastSymbol.infoOrCompleter == ErrorType ||
1279-
defn.overriddenBySynthetic.contains(lastSymbol)
1280-
// for overriddenBySynthetic symbols a TermRef such as SomeCaseClass.this.hashCode
1281-
// might be rewritten from Object#hashCode to the hashCode generated at SyntheticMethods
1293+
sym.owner.derivesFrom(lastSymbol.owner) && sym.owner != lastSymbol.owner
12821294
),
1283-
s"data race? overwriting symbol of ${this.show} / $this / ${this.getClass} / ${lastSymbol.id} / ${sym.id}")
1295+
s"data race? overwriting symbol of ${this.show} / $this / ${this.getClass} / ${lastSymbol.id} / ${sym.id} / ${sym.owner} / ${lastSymbol.owner} / ${ctx.phase}")
12841296

12851297
protected def sig: Signature = Signature.NotAMethod
12861298

src/dotty/tools/dotc/transform/ExtensionMethods.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ class ExtensionMethods extends MiniPhaseTransform with DenotTransformer with Ful
5454
ctx.atPhase(thisTransformer.next) { implicit ctx =>
5555
// In Scala 2, extension methods are added before pickling so we should
5656
// not generate them again.
57-
if (!(origClass is Scala2x)) {
57+
if (!(origClass is Scala2x)) ctx.atPhase(thisTransformer) { implicit ctx =>
5858
for (decl <- origClass.classInfo.decls) {
5959
if (isMethodWithExtension(decl))
6060
decls1.enter(createExtensionMethod(decl, ref.symbol))
@@ -91,7 +91,6 @@ class ExtensionMethods extends MiniPhaseTransform with DenotTransformer with Ful
9191
else NoSymbol
9292

9393
private def createExtensionMethod(imeth: Symbol, staticClass: Symbol)(implicit ctx: Context): TermSymbol = {
94-
assert(ctx.phase == thisTransformer.next)
9594
val extensionName = extensionNames(imeth).head.toTermName
9695
val extensionMeth = ctx.newSymbol(staticClass, extensionName,
9796
imeth.flags | Final &~ (Override | Protected | AbsOverride),

tests/pos/i518.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
class Meter(val underlying: Int) extends AnyVal
2+
3+
class Test {
4+
val x: Int = new Meter(3).hashCode()
5+
// After phase VCInline the rhs should be expanded to Meter.hashCode$extension(3)
6+
}

0 commit comments

Comments
 (0)