Skip to content

Conversation

@adriaanm
Copy link
Contributor

@adriaanm adriaanm commented Mar 8, 2017

Based on @allisonhb's excellent analysis in milessabin/shapeless#679 (original fix in #5656), here's my proposed fix.

The bug report analysis correctly identified an unexpected cyclic error, which was triggered by implicit search. Implicit search is not expected while type checking the qualifier of a type selection node. Fixing this also removes the cyclic error.

Thus, align typedSelect to be more consistent in dealing with Select and SelectFromTypeTree nodes. The spec is clear on the equivalence between p.T (Select(p, T)) and p.type#T (SelectFromTypeTree(SingletonTypeTree(p), T)).

This bug gets even more intriguing, in that it shows that you can sneak a macro call into a path using selectDynamic. (See the test in next commit.)

Eventually, we should disable applyDynamic in paths. It wasn't explicitly disallowed, since we assumed the stability check would rule out method calls. However, a macro application will dissolve into its rhs before stability is checked...

Fixes scala/bug#10159

@scala-jenkins scala-jenkins added this to the 2.12.2 milestone Mar 8, 2017
@adriaanm adriaanm requested a review from retronym March 8, 2017 00:38
@ghost
Copy link

ghost commented Mar 8, 2017

Cool! I think this is way more sensible than my fix; the equivalence with SelectFromTypeTree(SingletonType(...), ...) makes a lot of sense. ApplyDynamic ever producing a stable path is very suspicious but seems to have worked for a lot of "tricks" in shapeless and elsewhere... potentially you will be making @milessabin sad.

Looks a lot nicer though; thanks! I'll close mine out for now.

if ((qualTp eq null) || qualTp.isError) setError(tree)
else if (name.isTypeName && qualTp.isVolatile) // TODO: use same error message for volatileType#T and volatilePath.T?
if (tree.isInstanceOf[SelectFromTypeTree]) TypeSelectionFromVolatileTypeError(tree, qual)
else UnstableTreeError(qual)
Copy link
Contributor

Choose a reason for hiding this comment

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

Nested braceless style made me instinctively reach out for something to hold onto.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I really hated my braces as a teenager. I guess it still shows.

@milessabin
Copy link
Contributor

To clarify, is this fix going to break shapeless's current use of this mechanism?

@ghost
Copy link

ghost commented Mar 8, 2017

As I understand it, no... @adriaanm mentioned considering that we could stop considering SelectDynamic to ever be part of a stable path, even during macro expansion. Obviously that wouldn't come around until 2.13.x... plenty of time to think of a workaround :P

@adriaanm
Copy link
Contributor Author

adriaanm commented Mar 8, 2017

Indeed. At the earliest we would consider this change for 2.13. I can see its utility, though -- not saying we definitely will plug the hole. (From a soundness/IDE perspective, I think we should, but tbd.)

@adriaanm
Copy link
Contributor Author

Rebased.

@adriaanm
Copy link
Contributor Author

Re-rebased.

@adriaanm
Copy link
Contributor Author

adriaanm commented Jun 29, 2017

no idea why cla check is failing, others are green

// note: on error, we discard the work we did in type checking tree.qualifier into qual
// (tree is either Select or SelectFromTypeTree, and qual may be different from tree.qualifier because it has been type checked)
val qualTp = qual.tpe
if ((qualTp eq null) || qualTp.isError) setError(tree)
Copy link
Member

Choose a reason for hiding this comment

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

Checking qual.tpe.isError for selections from term trees appears to be new. I haven't figured out how that case was handled before. The new formulation (checking early and bailing out) appears sane, but I need to connect a few more dots to feel comfortable.

I haven't found any example where the compiler before/after this change differs in behaviour, so I'm probably just being paranoid. I focussed on error cases.

@retronym
Copy link
Member

/synch

@retronym
Copy link
Member

Comparative benchmark results coming soon here

@retronym retronym modified the milestones: 2.12.4, 2.12.3 Jul 7, 2017
@retronym
Copy link
Member

retronym commented Jul 7, 2017

Reassigning to 2.12.4. While I think the change looks good, the bug is pretty esoteric, and this touches core part of the typechecker, so I'd rather we merge it after the impending 2.12.3 release.

@adriaanm
Copy link
Contributor Author

Rebased. Ping @retronym. Let's decide this week whether we feel this is ok for 2.12.4

@retronym
Copy link
Member

merge error in the rebase, it would seem:

[error] /home/jenkins/workspace/scala-2.12.x-validate-publish-core/src/compiler/scala/tools/nsc/typechecker/Typers.scala:4884: ';' expected but 'if' found.
[error]         val sym = tree.symbol orElse member(qual, name) orElse inCompanionForJavaStatic(qual.tpe.prefix, qual.symbol, name) if ((sym eq NoSymbol) && name != nme.CONSTRUCTOR && mode.inAny(EXPRmode | PATTERNmode)) {
[error]                                                                                                                             ^
[warn] one warning found
[error] one error found

@adriaanm
Copy link
Contributor Author

ugh, i've gotten too lazy with IJ's magic "resolve all"

adriaanm and others added 2 commits September 18, 2017 17:52
The bug report analysis correctly identified an unexpected
cyclic error, which was triggered by implicit search.
Implicit search is not expected while type checking
the qualifier of a type selection node. Fixing this
also removes the cyclic error.

Thus, align `typedSelect` to be more consistent in dealing with
`Select` and `SelectFromTypeTree` nodes. The spec is clear on
the equivalence between `p.T` (`Select(p, T)`) and
`p.type#T` (`SelectFromTypeTree(SingletonTypeTree(p), T)`).

This bug gets even more intriguing, in that it shows that
you can sneak a macro call into a path using `selectDynamic`.
(See the test in next commit.)

Eventually, we should disable applyDynamic in paths.
It wasn't explicitly disallowed, since we assumed the stability check
would rule out method calls. However, a macro application will
dissolve into its rhs before stability is checked...
NOTE: the fix in the parent was inspired by allisonhb's analysis.
This commit was amended to reuse the test case.

Original commit message:

Previously, while the implicit would rightly be discarded,
`typedInternal` would catch the CyclicReference error
and call `reportTypeError` before rethrowing, which would cause
compilation to fail.
@retronym
Copy link
Member

retronym commented Sep 19, 2017

Benchmark scheduled.

@milessabin
Copy link
Contributor

Let me know if there's anything I can do to help with this ...

@adriaanm
Copy link
Contributor Author

As far as I can tell, benchmarks look unaffected -- right, @retronym?

@retronym retronym merged commit 0d81083 into scala:2.12.x Sep 19, 2017
@retronym retronym changed the title SI-10159 spurious cyclic error in type selection spurious cyclic error in type selection Sep 19, 2017
adriaanm added a commit to adriaanm/scala that referenced this pull request Sep 27, 2017
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.

5 participants