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
Add flags -Ysysdef and -Ypredef to configure root imports [ci: last-only] #5350
Conversation
It looks like it would be reasonable to implement support for importing individual symbols. For example, |
I would love to see this feature, with fine-grained support as described above. |
That was my thinking as well. There might be considerations about symbol init which makes it not work as simply as an import? The idiom would be Does the refactor of that part work the same? I remember the import has to be at the top of the unit, because otherwise the semantics looks like unimporting. The REPL supports it at the top. The other part is don't import our own package. There are postSetHooks for settings which you can use to wire -Ypredef to -Yno-imports and -Yno-predef. I guess -Yno-imports resets to empty, -Yno-predef strips Predef. (As you have it in the code.) |
@@ -33,7 +33,7 @@ trait AbsScalaSettings { | |||
def ChoiceSetting(name: String, helpArg: String, descr: String, choices: List[String], default: String): ChoiceSetting | |||
def ChoiceSettingForcedDefault(name: String, helpArg: String, descr: String, choices: List[String], default: String): ChoiceSetting | |||
def IntSetting(name: String, descr: String, default: Int, range: Option[(Int, Int)], parser: String => Option[Int]): IntSetting | |||
def MultiStringSetting(name: String, helpArg: String, descr: String): MultiStringSetting | |||
def MultiStringSetting(name: String, helpArg: String, descr: String, default: List[String] = Nil): MultiStringSetting |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't look right to me. Compare MultiChoiceSetting
where default arg is on MutableSettings.
I'm very much in favour of this. However if deprecation warnings are added for existing compiler flags I'd like to see some mechanism to disable them. Maybe flag deprecation warnings could also be covered by |
If that's for cross-building sbt reasons, you can make compiler flags conditional to the scala version. I had to do that with, for example, 2.12 renaming |
@dwijnand no, not really. If a warning really shouldn't be ignored it should be an error. If it is permissible to ignore it, at least temporarily, then it should be possible to note the warning, disable it and return a build uncluttered with noise. People don't ignore warnings for fun ... typically there's some constraint that prevents them from fixing them immediately ... that being so we should avoid imposing additional burdens on them. |
TIL
I think there's a proposal for warnings to be typed, so it's easier to filter them (in a reporter). Then maybe they'll do warning suppression of a sort. |
if (peer.isSetByUser) | ||
errorFn(s"Flag ${s.name} can not be used in conjunction with flag ${peer.name}") | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a bit odd. Is there a word for currying in this way? I think this is the same:
def exclusively(peer: Setting)(setting: Setting): Unit = if (peer.isSet) fail(setting)
I made an attempt at handling import selectors-- some help needed for this one, so I've added a few comments to my own code. |
/rebuild |
Getting the For this test to pass, hard coded logic for // Belongs in TreeInfo but then I can't reach it from Printers.
def isReferenceToScalaMember(t: Tree, Id: Name) = t match {
case Ident(Id) => true
case Select(Ident(nme.scala_), Id) => true
case Select(Select(Ident(nme.ROOTPKG), nme.scala_), Id) => true
case _ => false
} To make this easier, I may put a constraint that all predef imports would automatically be attached to |
@andyscott While you are on it, can you add something to treat named imports as wildcard imports? |
@soc I'm not familiar with what you mean by start trees. Can you explain? |
@andyscott Sorry, I was still editing => wildcard imports. |
One issue I am still having: Many of the tests, such as
I noticed a few existing tests extending |
I guess you're talking about your local test output, not the jenkins failure
That log output is when I haven't followed the last changes, so I don't understand the semicolon separator change. |
I made the delimiter configurable for multi string settings, since commas might be present in the import selector syntax. I believe I fixed that particular error in one of the last commits. It had to do with calling |
Ah. I wonder if it isn't better just to make the option parser aware of brackets. Needless to add, if we're imitating import syntax, Or, it's not a multistring at all, but a string. When you receive it, prepend "import" and parse it and typecheck it. |
I'm okay with any of those approaches. The custom delimiter seems to work fine, but if you'd prefer that I go a different route let me know and I can switch it over. |
Just noticed |
closing for inactivity. can always be reopened |
@andyscott if you'd still like to work on this — and/or if someone else wants to take it up — we'd be happy to reopen |
(P.S. if having some help might help this move towards the finish line, you might post about it on https://contributors.scala-lang.org and see if you can generate some interest/assistance that way) |
to summarise my feedback from above:
other than that, I can live with all the other glitches because I'd really like system imports to behave as if I wrote them explicitly at the top of the file. |
I'm interested in helping, because I think fixing name binding in another PR will make more folks (common folk) consider controlling the implicit imports in projects, even if they are a handy default for beginners and casual REPLing. I'll also look at whether they warn. How can they warn if they are not in code? |
If we can come up with a reasonable path forward I'd be very happy to allocate some time to wrap this up (or something similar in functionality). Is this PR the best place to continue the discussion? |
Yes please! I spinned of a scala-dev ticket to continue the discussion: scala/scala-dev#474. |
I left a note on scala-dev that I've proposed a simplified version of this feature, as part of a PR that has been hanging around about as long as this one. |
Heads up: if this is going to make it into 2.13, it will need to be ready to merge by M5 (due Aug 10). |
My simpler |
private[this] def collectLeadingImports(body: Tree): List[Import] = { | ||
@tailrec def loop(rem: List[Tree], acc: List[Import]): List[Import] = rem match { | ||
case tree :: tail => tree match { | ||
case PackageDef(_, stats) => loop(stats ::: tail, acc) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This drills down through package statements, different from current check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I retract that! It does in fact enter nested packages looking for the exclusionary import.
Looking this over again for ideas and LOC for my Thinking about this during unbearably long Bay Area commutes, I wanted to minimize scans of unit trees, and also minimize context lookups, in part to avoid forcing infos. I was also thinking that you only need to look at previous imports (including renames). But the approach taken here doesn't work for this case where a definition aliases a name in the full name of the predef object
In a normal context lookup, the definition shadows the import. The problem is partly that the existing implementation doesn't just look at "leading" imports. But switching the order of the object and the import from it shouldn't change semantics. The revised words at this puzzler are still not right, but the gist is that the import can be at the bottom of the file, like vi modelines. Possibly we should just disallow that, for the sake of efficiency. Here is the working example, where
Edit: there are couple of heuristics or limitations that we could apply, such as taking only leading imports, up to a def, and only at top-level or top-level package; and either requiring fully-qualified import (with the exception of By fully-qualified, I wasn't even thinking "absolute", Proposed warning, torn from the headlines of The Onion:
Or is there a fifth level of name binding that ignores definitions in imports? |
This work was brought forward in a slightly different form in #6764 which supersedes this PR. The merged PR is one flag, and distinguishes "sysdef" as packages and "predef" as objects that are not packages. You get wildcard imports from either sort, and the order is respected, where later shadows earlier, as though nested. The way predefs are excluded is similar but arguably more workable. "Fine-grained" control is not supported. Root contexts work more like nested packages than like imports. I commented that a true |
This adds a
-Ysysdef
and-Ypredef
flag to give you full control over global imports for Scala compilation units.Background information:
By default, scalac imports
java.lang._
,scala._
, andscala.Predef._
into the namespace of Scala compilation units.As it stands, we have two existing flags that adjust the behavior of predefined imports.
-Yno-imports
disables all of these.-Yno-predef
disablesscala.Predef._
.There are a few other nuances to the behavior of imports. The most important behavior is that
scala.Predef._
is unimported/evicted if there are any direct leading imports for anything withinscala.Predef
. For example, an import toscala.Predef.DummyImplicit
will cause everything else normally imported by predef to be unimported.Changes
scala.Predef
).-Ysysdef
which controls the global sysdef imports for all Scala compilation units. The default value is set tojava.lang._; scala._
.-Ypredef
which controls the predef imports for Scala compilation units. The default value is set toscala.Predef._
.I'd be great to get any feedback. I would also to back port this to 2.11.