Skip to content

Rework NamedTypes #3494

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 58 commits into from
Dec 6, 2017
Merged

Rework NamedTypes #3494

merged 58 commits into from
Dec 6, 2017

Conversation

odersky
Copy link
Contributor

@odersky odersky commented Nov 17, 2017

When analyzing #3488, the root cause seems to be that constructing TermRefs with signatures is fragile. Signatures might not be fully known at the point a TermRef is constructed, which leads to complicated compensation actions.

In this PR I try to make NamedTypes by default symbolic (i.e. all designators should ideally be symbols, not names). We need to compensate for cross compilation unit references in Tasty trees.
These need names and signatures as before. But hopefully we can be symbol-only in the internal types.

Postscript: Some NamedTypes are still created with a name only, in order not to force too much. But the scheme should now be much more robust than before.

@odersky odersky force-pushed the fix-#3488 branch 3 times, most recently from 07d38c2 to 070b889 Compare November 19, 2017 20:39
@odersky
Copy link
Contributor Author

odersky commented Nov 26, 2017

Something is not right with the CI. It seems to pick up an outdated version of SymDenotations.scala. The line that leads to the compile error (420) has been deleted and now contains something unrelated to the error message.

@odersky
Copy link
Contributor Author

odersky commented Nov 27, 2017

It turned out to be a rebase problem.

@odersky
Copy link
Contributor Author

odersky commented Nov 27, 2017

test performance please

@dottybot
Copy link
Member

performance test scheduled: 1 job(s) in queue, 0 running.

@dottybot
Copy link
Member

Performance test finished successfully:

Visit http://dotty-bench.epfl.ch/3494/ to see the changes.

Benchmarks is based on merging with master (8558b4d)

Make them update themselves across runs
All symbols sharing the same toplevel class are now considered
localy defined.

Previously, this was order-dependent.
Will be needed to represent overloaded TermRefs
Test types arguments for equality with =:= rather than ==.

Also, better diagnostics for requiredSymbol
For now it's controlled under a config option.
They wold transform the pre-existing type of the denotation instead of the
symbol's type. This is clearly the wrong behavior for erasure. It was not
detected before because we changed all types from name-based to symbolic
during erasure, which meant we computed the denotation after erasure by a
loadDenot. So we never exercised the `d.current` code on a derived denotation.
It caused errors even in the old scheme, because we now had another
symbol that "existed" yet did not have an owner.

Also, change creation methods for NamedTypes to accommodate
NoSymbol as a symbol of an overloaded denotation.
Simplifying an overloaded reference risks changing the prefix, which will
lead into trouble using the new overloading scheme (because the only info
is in the denotation, which will be thrown away when the prefix is changed).

Also, both interpolating undetermined variables and simplifying are likely to be
inefficient on overloaded types because they tend to be large. Delaying these operations
means we only have to perform them on alternatives that might plausibly match the
expected type.
Make PreDenotation a superclass of Denotation. The immediate need
for this is that we would like to add an `asSeenFrom` to Denotations,
but if we do that it clashes with the `asSeenFrom` in Predenotations.
JoinRefDenotations before erasure become UniqueRefDenotations after.
The former are no longer legal after erasure.
 - need to adapt denotation if prefix changes in `withPrefix`
 - need to recover name of reference from the denotation.
 - don't suppress them when retying after a contextual search
 - give a more helpful error message
Gave sometimes nonsensical messages like

   x is not a member of Object { ... }
It's called in a lot of maps and forcing presents a risk of stale symbol
errors. So we should force the minimum possible.
TypeArgRefs with equal prefix, classes and indices should compare as equal.
Previously this probably was not detected because equal prefixes happened to
be identical and then the `eq` case in isSubType would kick in. The problematic
case happened when comparing `ParMapLike[<lots of arguments>]#<typearg Sequential>` with
itself except that one side had a Lazy(CC) where the other had a CC. It was in compileStdLib,
in case you were wondering.
Update stale references only if -Yupdate-state is set, fail with a StaleSymbol
error otherwise.

This required some fixes to the way ScalaShadowing was treated. If we compile a
ScalaShadowing (as is done in tasty-bootstrap) we need to also overwrite the
mirrored symbol in the scala package. Otherwise we would get a stale reference
when looking up the latter.
 - don't compute members when unpickling termrefs, it caused
   cyclic reference errors on tasty-bootstrap.

 - to make this robust, have currentSignature in TermRef return
   a NotAMethof if not symbol or denotation is known.
 - make private where possible
 - make public where the operation is immutable and has a simple
   to understand meaning.
There was a scenario in the IDE where this was not the case: If the owner of
a denotation was deleted in the new run, the old symbol gets an updated validity.
Then, a call to bringForward of a member of that invalid owner will lookup
the symbol in its owner, yielding itself. But the validity still was the previous period.
Also: reinstantiate an accidentally deleted test
In interactive mode, allow uncompleted symbols with completers from
previous runs. This is possible due to the way we bring forwward stale
symbols. Liek in manual cleanup in InteractiveDriver, we set the info
of such symbols to UnspecifiedError.
@@ -106,6 +106,7 @@ class ScalaSettings extends Settings.SettingGroup {
val YkeepComments = BooleanSetting("-Ykeep-comments", "Keep comments when scanning source files.")
val YforceSbtPhases = BooleanSetting("-Yforce-sbt-phases", "Run the phases used by sbt for incremental compilation (ExtractDependencies and ExtractAPI) even if the compiler is ran outside of sbt, for debugging.")
val YdumpSbtInc = BooleanSetting("-Ydump-sbt-inc", "For every compiled foo.scala, output the API representation and dependencies used for sbt incremental compilation in foo.inc, implies -Yforce-sbt-phases.")
val YupdateStale = BooleanSetting("-Yupdate-stale", "Automically update stale top-level classes and objects to latest version")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we still need this? It's currently never enabled.

final override def isTerm(implicit ctx: Context): Boolean =
(lastDenot.validFor.runId == ctx.runId || ctx.stillValid(lastDenot)) &&
(lastDenot.symbol eq this)
// the last condition is needed because under option -Yupdate-stale overwritten
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add ctx.settings.YupdateStale.value && to that last condition?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No that would not work. The condition is redundant unless stale symbols are accepted.

d
}

def fromDesignator = designator match {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The finish call could be moved here to wrap the entire expression

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True. I left it like this for better debuggability. If checkDenot (called from setDenot) fails with an AssertionError, we know exactly how we got there.


private def memberDenot(name: Name, allowPrivate: Boolean)(implicit ctx: Context): Denotation = {
var d = memberDenot(prefix, name, allowPrivate)
if (!d.exists && ctx.mode.is(Mode.Interactive))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add && !allowPrivate, also maybe add a comment explaining why this may arise in the IDE.

if (d.exists) d
else throw new Error(s"failure to reload $this of class $getClass")
}
/** Is this a reference to a class or object member? */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment does not seem to match the implementation: infoDependsOnPrefix calls membersNeedAsSeenFrom(prefix) which will return false if prefix is a statically accessible object.

val adapted = withSym(denot.symbol)
if (adapted ne this) adapted.withDenot(denot).asInstanceOf[ThisType]
else {
setDenot(denot)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the name of this method and its documentation, it's surprising that it can mutate this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I'll update the docs.

}

abstract case class TermRef(override val prefix: Type, designator: TermDesignator) extends NamedType with SingletonType {
abstract case class TermRef(override val prefix: Type, var designator: Designator)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see var designator here, doesn't that make the setter of TermRef#designator public?

Major changes

 - Drop -Yupdate-stale and simplify bringForward accordingly
 - Make designator a private field of TypeRef and TermRef
@odersky odersky merged commit 7848ef6 into scala:master Dec 6, 2017
@allanrenucci allanrenucci deleted the fix-#3488 branch December 6, 2017 20:31
@odersky odersky mentioned this pull request Jan 2, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants