Skip to content

Fix #1688: don't allow override of synthetic or primitive classes #1689

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

Closed

Conversation

felixmulder
Copy link
Contributor

review by: @DarkDimius

/** Checks if the user is trying to illegally override synthetic classes,
* primitives or their boxed equivalent
*/
class CheckIllegalOverrides extends MiniPhaseTransform {
Copy link
Contributor

Choose a reason for hiding this comment

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

I wouldn't call this an override, it's more of a re-definition. But I'm also fine with the current name.

class CheckIllegalOverrides extends MiniPhaseTransform {
import ast.tpd._

override def phaseName = "checkPhantom"
Copy link
Contributor

Choose a reason for hiding this comment

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

It would be nice to have phaseName and class name in sync.


override def phaseName = "checkPhantom"

override def transformTypeDef(tree: TypeDef)(implicit ctx: Context, info: TransformerInfo) = {
Copy link
Contributor

@DarkDimius DarkDimius Nov 9, 2016

Choose a reason for hiding this comment

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

I'd propose to slightly change the way such checks are done.
The problem with this approach is that the other mini-phases in the same block couldn't rely on the facts that you've checking, as they run interleaved with this phase.

As you see, your implementation only needs the symbol and this means that you can make it into an SymTransformer which checks the invariants. Checking in a SymTransformer enforces that even phases in the same mini-phase block that are after you may rely on invariants that you introduce.

Some("boxed primitive")
else
None

Copy link
Contributor

Choose a reason for hiding this comment

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

It would be also nice to check that no-one tries to introduce a companion to those classes.
Eg, there actually is a class Nothing$ that isn't source defined but backend relies on it existing.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Since we're comparing the full paths of the symbols we get this for free, but I added a neg test i1688c.scala just to make sure.

@felixmulder
Copy link
Contributor Author

@DarkDimius - addressed your feedback :)

Copy link
Contributor

@odersky odersky left a comment

Choose a reason for hiding this comment

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

IMO, making CheckRedefs a SymTransformer is not the right way to go about it.

  • It imposes a tax on every symbol in the whole compilation run. The more SymTransformers are in the pipeline, the slower all transformations get.
  • The Symtransformer itself is really slow because it compares fully qualified names.
  • It feels like the "one check per phase" system is not workable. The compiler contains on the order of 10^3 checks. Do we really want 10^3 phases?

@odersky
Copy link
Contributor

odersky commented Nov 10, 2016

Also, we can't forbid defining primitive value classes here because we do define them when we bootstrap!

@smarter
Copy link
Member

smarter commented Nov 10, 2016

I think the correct way to fix #1688 is to change the backend to issue an error and gracefully exit instead of asserting when trying to define scala.Null or scala.Nothing

@odersky
Copy link
Contributor

odersky commented Nov 10, 2016

@smarter Or change the frontend to disallow definitions of such classes. Which might prevent other possible crashes.

@felixmulder
Copy link
Contributor Author

felixmulder commented Nov 10, 2016

(Already said this in part on a commit, the emailed link sent me there - reiterating:)

@smarter - IIRC when I was looking at this, changing the backend required changing the shared backend that we're depending on from artefact.

As @odersky suggested, I could change the enterSymbol function to take this into account by not allowing to enter symbols of the same primitives / boxed primitives. WDYT?

Also, we can't forbid defining primitive value classes here because we do define them when we bootstrap!

I thought FrontEnd threw these out in discardAfterTyper? Or are we defining them somewhere else?

@odersky
Copy link
Contributor

odersky commented Nov 10, 2016

I thought FrontEnd threw these out in discardAfterTyper? Or are we defining them somewhere else?

Ah, yes, I had not thought of that. But that means a test later on is redundant, right? I.e. if it fires it would be a (weird) internal compiler error.

@odersky
Copy link
Contributor

odersky commented Nov 10, 2016

enterSymbol is a possibility but I think it's even better to do it in Desugar. Let me close this and do a new PR with the idea.

@felixmulder
Copy link
Contributor Author

IIUC if it fires, it just means that the class that got through with the fully qualified name scala.Char was not a value class :)

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.

4 participants