aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dotty/tools/dotc/core/Definitions.scala1
-rw-r--r--src/dotty/tools/dotc/core/Types.scala54
-rw-r--r--src/dotty/tools/dotc/transform/ExtensionMethods.scala3
-rw-r--r--tests/pos/i518.scala6
4 files changed, 40 insertions, 24 deletions
diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala
index 784773fd3..c21620048 100644
--- a/src/dotty/tools/dotc/core/Definitions.scala
+++ b/src/dotty/tools/dotc/core/Definitions.scala
@@ -451,7 +451,6 @@ class Definitions {
lazy val RootImports = List[Symbol](JavaLangPackageVal, ScalaPackageVal, ScalaPredefModule, DottyPredefModule)
- lazy val overriddenBySynthetic = Set[Symbol](Any_equals, Any_hashCode, Any_toString, Product_canEqual)
def isTupleType(tp: Type)(implicit ctx: Context) = {
val arity = tp.dealias.argInfos.length
arity <= MaxTupleArity && (tp isRef TupleClass(arity))
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index 80cceed38..512ddc41a 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -126,6 +126,19 @@ object Types {
false
}
+ /** Does this type refer exactly to class symbol `sym`, instead of to a subclass of `sym`?
+ * Implemented like `isRef`, but follows more types: all type proxies as well as and- and or-types
+ */
+ private[Types] def isTightPrefix(sym: Symbol)(implicit ctx: Context): Boolean = stripTypeVar match {
+ case tp: NamedType => tp.info.isTightPrefix(sym)
+ case tp: ClassInfo => tp.cls eq sym
+ case tp: Types.ThisType => tp.cls eq sym
+ case tp: TypeProxy => tp.underlying.isTightPrefix(sym)
+ case tp: AndType => tp.tp1.isTightPrefix(sym) && tp.tp2.isTightPrefix(sym)
+ case tp: OrType => tp.tp1.isTightPrefix(sym) || tp.tp2.isTightPrefix(sym)
+ case _ => false
+ }
+
/** Is this type an instance of a non-bottom subclass of the given class `cls`? */
final def derivesFrom(cls: Symbol)(implicit ctx: Context): Boolean = this match {
case tp: TypeRef =>
@@ -1221,27 +1234,17 @@ object Types {
val sym = lastSymbol
if (sym == null) loadDenot else denotOfSym(sym)
case d: SymDenotation =>
- if ( d.validFor.runId == ctx.runId
- || ctx.stillValid(d)
- || this.isInstanceOf[WithFixedSym]) d.current
+ if (this.isInstanceOf[WithFixedSym]) d.current
+ else if (d.validFor.runId == ctx.runId || ctx.stillValid(d))
+ if (prefix.isTightPrefix(d.owner) || d.isConstructor) d.current
+ else recomputeMember(d) // symbol could have been overridden, recompute membership
else {
val newd = loadDenot
if (newd.exists) newd else d.staleSymbolError
}
case d =>
- if (d.validFor.runId != ctx.period.runId)
- loadDenot
- // The following branch was used to avoid an assertErased error.
- // It's idea was to void keeping non-sym denotations after erasure
- // since they violate the assertErased contract. But the problem is
- // that when seen again in an earlier phase the denotation is
- // still seen as a SymDenotation, whereas it should be a SingleDenotation.
- // That's why the branch is disabled.
- //
- // else if (ctx.erasedTypes && lastSymbol != null)
- // denotOfSym(lastSymbol)
- else
- d.current
+ if (d.validFor.runId != ctx.period.runId) loadDenot
+ else d.current
}
if (ctx.typerState.ephemeral) record("ephemeral cache miss: loadDenot")
else if (d.exists) {
@@ -1250,7 +1253,10 @@ object Types {
// phase but a defined denotation earlier (e.g. a TypeRef to an abstract type
// is undefined after erasure.) We need to be able to do time travel back and
// forth also in these cases.
- setDenot(d)
+
+ // Don't use setDenot here; double binding checks can give spurious failures after erasure
+ lastDenotation = d
+ lastSymbol = d.symbol
checkedPeriod = ctx.period
}
d
@@ -1258,6 +1264,14 @@ object Types {
finally ctx.typerState.ephemeral |= savedEphemeral
}
+ /** A member of `prefix` (disambiguated by `d.signature`) or, if none was found, `d.current`. */
+ private def recomputeMember(d: SymDenotation)(implicit ctx: Context): Denotation =
+ asMemberOf(prefix) match {
+ case NoDenotation => d.current
+ case newd: SingleDenotation => newd
+ case newd => newd.atSignature(d.signature).orElse(d.current)
+ }
+
private def denotOfSym(sym: Symbol)(implicit ctx: Context): Denotation = {
val d = sym.denot
val owner = d.owner
@@ -1276,11 +1290,9 @@ object Types {
(lastDefRunId == NoRunId)
} ||
(lastSymbol.infoOrCompleter == ErrorType ||
- defn.overriddenBySynthetic.contains(lastSymbol)
- // for overriddenBySynthetic symbols a TermRef such as SomeCaseClass.this.hashCode
- // might be rewritten from Object#hashCode to the hashCode generated at SyntheticMethods
+ sym.owner.derivesFrom(lastSymbol.owner) && sym.owner != lastSymbol.owner
),
- s"data race? overwriting symbol of ${this.show} / $this / ${this.getClass} / ${lastSymbol.id} / ${sym.id}")
+ s"data race? overwriting symbol of ${this.show} / $this / ${this.getClass} / ${lastSymbol.id} / ${sym.id} / ${sym.owner} / ${lastSymbol.owner} / ${ctx.phase}")
protected def sig: Signature = Signature.NotAMethod
diff --git a/src/dotty/tools/dotc/transform/ExtensionMethods.scala b/src/dotty/tools/dotc/transform/ExtensionMethods.scala
index b2f402bc5..009257dc0 100644
--- a/src/dotty/tools/dotc/transform/ExtensionMethods.scala
+++ b/src/dotty/tools/dotc/transform/ExtensionMethods.scala
@@ -54,7 +54,7 @@ class ExtensionMethods extends MiniPhaseTransform with DenotTransformer with Ful
ctx.atPhase(thisTransformer.next) { implicit ctx =>
// In Scala 2, extension methods are added before pickling so we should
// not generate them again.
- if (!(origClass is Scala2x)) {
+ if (!(origClass is Scala2x)) ctx.atPhase(thisTransformer) { implicit ctx =>
for (decl <- origClass.classInfo.decls) {
if (isMethodWithExtension(decl))
decls1.enter(createExtensionMethod(decl, ref.symbol))
@@ -91,7 +91,6 @@ class ExtensionMethods extends MiniPhaseTransform with DenotTransformer with Ful
else NoSymbol
private def createExtensionMethod(imeth: Symbol, staticClass: Symbol)(implicit ctx: Context): TermSymbol = {
- assert(ctx.phase == thisTransformer.next)
val extensionName = extensionNames(imeth).head.toTermName
val extensionMeth = ctx.newSymbol(staticClass, extensionName,
imeth.flags | Final &~ (Override | Protected | AbsOverride),
diff --git a/tests/pos/i518.scala b/tests/pos/i518.scala
new file mode 100644
index 000000000..390437dae
--- /dev/null
+++ b/tests/pos/i518.scala
@@ -0,0 +1,6 @@
+class Meter(val underlying: Int) extends AnyVal
+
+class Test {
+ val x: Int = new Meter(3).hashCode()
+ // After phase VCInline the rhs should be expanded to Meter.hashCode$extension(3)
+}