Skip to content

Fix #518 - compute denotations #534

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
May 5, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
54 changes: 33 additions & 21 deletions src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 =>
Expand Down Expand Up @@ -1216,27 +1229,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) {
Expand All @@ -1245,14 +1248,25 @@ 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
}
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
Expand All @@ -1271,11 +1285,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

Expand Down
3 changes: 1 addition & 2 deletions src/dotty/tools/dotc/transform/ExtensionMethods.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -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),
Expand Down
6 changes: 6 additions & 0 deletions tests/pos/i518.scala
Original file line number Diff line number Diff line change
@@ -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)
}