Skip to content
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

Import selector respects backquotes [ci: last-only] #6218

Merged
merged 1 commit into from
Nov 27, 2018

Conversation

som-snytt
Copy link
Contributor

@som-snytt som-snytt commented Dec 7, 2017

An import selector from WILDCARD to WILDCARD is taken as importing member underscore, and WILDCARD to anything else not null as renaming it. Renaming unquoted wildcard is not allowed.

was:
To disambiguate backquoted underscore, the convention
for ImportSelector is tweaked by using EMPTY instead of
WILDCARD as the special value. So EMPTY => EMPTY is
wildcard import, nonempty => EMPTY is hidden.

This encoding also avoids a null value for the rename field.

A rename is detected more simply by name != rename.

This change would require communication with anyone who builds ImportSelector manually. It would be nice to use ImportSelector.wild instead of relying on the encoding. See the test that does that.

Fixes scala/bug#6426
Fixes scala/bug#10641
Fixes scala/bug#7691

@som-snytt
Copy link
Contributor Author

som-snytt commented Dec 8, 2017

A couple of fixes for reflection. I was inclined to add API for ImportSelector such as isWildcard and isHidden. The conventional construction is distributed far and wide, for testing and making wildcards etc. Note that underscore remains _ in WildcardSelectorRepr and friends, because pq"_".

@som-snytt som-snytt force-pushed the issue/underscore branch 2 times, most recently from faae4c8 to 0ea6c72 Compare December 9, 2017 01:09
@dwijnand
Copy link
Member

Btw, you need to say "fixes xx/yy#zz" for each xx/yy#zz, otherwise it'll just close the first one.

@som-snytt
Copy link
Contributor Author

Also fix ImportInto.isExplicitImport by adding that API to ImportSelector.

@retronym retronym self-requested a review January 12, 2018 04:41
@retronym retronym self-assigned this Jan 12, 2018
@retronym
Copy link
Member

I'd be most worried about compatibility with Scala IDE and Scala refactoring.

⚡ git grep WILDCARD | grep -i import
src/main/scala/scala/tools/refactoring/analysis/ImportAnalysis.scala:      imp.expr.toString() + "." + nme.WILDCARD.decoded
src/main/scala/scala/tools/refactoring/analysis/ImportAnalysis.scala:      val symImpStr = (nme.WILDCARD.decoded :: parts).reverse.mkString(".")
src/main/scala/scala/tools/refactoring/analysis/ImportAnalysis.scala:      if (sel.name == nme.WILDCARD)
src/main/scala/scala/tools/refactoring/analysis/ImportsToolbox.scala:        if (sel.name == nme.WILDCARD) List(mkName(thatQual))
src/main/scala/scala/tools/refactoring/implementations/ImportsHelper.scala:                          selector.name == nme.WILDCARD || {
src/main/scala/scala/tools/refactoring/implementations/UnusedImportsFinder.scala:  def wildcardImport(i: ImportSelector) = i.name == nme.WILDCARD
src/main/scala/scala/tools/refactoring/implementations/UnusedImportsFinder.scala:    if (s.rename == nme.WILDCARD) return true
src/main/scala/scala/tools/refactoring/implementations/oimports/ImportParticipants.scala:        importSelector.rename == nme.WILDCARD
src/main/scala/scala/tools/refactoring/implementations/oimports/ImportParticipants.scala:      importSelector.name == nme.WILDCARD || (allTypeNamesFromSelect(select) & allTypeNamesFromImportSelector(importSelector)).nonEmpty
src/main/scala/scala/tools/refactoring/implementations/oimports/ImportParticipants.scala:      val wild = imp.selectors.find(_.name == nme.WILDCARD)
src/main/scala/scala/tools/refactoring/implementations/oimports/ImportParticipants.scala:        val (wild, rest) = imports.partition(_.selectors.exists(_.name == nme.WILDCARD))
src/main/scala/scala/tools/refactoring/implementations/oimports/ImportParticipants.scala:            Some(imp.copy(qual, List(ImportSelector(nme.WILDCARD, -1, nme.WILDCARD, -1))).copyAttrs(imp))
src/main/scala/scala/tools/refactoring/implementations/oimports/RegionTransformations.scala:        importName.endsWith(selector.name.decoded) && selector.rename == nme.WILDCARD
src/main/scala/scala/tools/refactoring/implementations/oimports/RegionTransformations.scala:          selector.name == nme.WILDCARD || importsNames.exists { importName =>
src/main/scala/scala/tools/refactoring/implementations/oimports/RegionTransformations.scala:              case imp @ RegionImport(expr, sels) if sels.exists { _.name == nme.WILDCARD } =>
src/main/scala/scala/tools/refactoring/implementations/oimports/TreeToolbox.scala:              rsels.exists { _.name == global.nme.WILDCARD } && (treeComparables.isSameWithSymbols(true)(expr.symbol, rexpr.symbol) || treeComparables.isSameExprByName(true)(expr, rexpr)) ||

I wonder if we can find a way to leave the encoding as is, but sneak an extra boolean onto ImportSelector to identify the problematic (and esoteric) case of import foo.{_ => bar}. (Are there more problematic cases than that?)

@som-snytt
Copy link
Contributor Author

Yes, for sure, I meant tooling needs communication, but that it would nicer if there were an API to make the change easier and more uniform, too. I could experiment on refactoring.

I think my first thought was a tree attachment.

@adriaanm

This comment has been minimized.

@adriaanm adriaanm modified the milestones: 2.13.0-M3, 2.13.0-M4 Jan 12, 2018
@SethTisue

This comment has been minimized.

@SethTisue

This comment has been minimized.

@som-snytt

This comment has been minimized.

@adriaanm adriaanm modified the milestones: 2.13.0-M4, 2.13.0-M5 Apr 30, 2018
@dwijnand
Copy link
Member

dwijnand commented Jun 6, 2018

Refactoring requested and new commits pushed. Re-review by @retronym, perhaps?

@adriaanm
Copy link
Contributor

adriaanm commented Aug 3, 2018

I like using EMPTY for the target of a rename that intends to hide a name (a => _), but don't understand why we can't represent a final _ import internally as (_ => _). It seems that would yield a smaller delta in the internal representation.

The caution about breaking tooling remains, but I'm fine moving forward as long as scalafix etc is not affected. (Which seems unlikely since they reimplemented all this ;-))

*
* Would be represented as:
*
* Import(qual, List(("x", "x"), ("y", "z"), (WILDCARD, null)))
* Import(qual, List(("w", EMPTY), ("x", "x"), ("y", "z"), (EMPTY, EMPTY)))
Copy link
Contributor

Choose a reason for hiding this comment

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

As mentioned in the discussion, could we use (WILDCARD, WILDCARD) for the last element?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Now (WILD, WILD) means import backticked underscore, possibly with rename. Otherwise, the encoding is unchanged.

@SethTisue SethTisue modified the milestones: 2.13.0-M5, 2.13.0-RC1 Aug 7, 2018
@adriaanm adriaanm modified the milestones: 2.13.0-RC1, 2.13.x Aug 7, 2018
@SethTisue
Copy link
Member

@som-snytt do you plan to resume work on this?

@SethTisue SethTisue added the WIP label Nov 6, 2018
@som-snytt
Copy link
Contributor Author

@adriaanm This is totally incrementable and useful and unoffensive and could be moved up to 2.13.0 cycle. I was looking at imports today thinking I thought I'd changed that code.

@adriaanm adriaanm modified the milestones: 2.13.1, 2.13.0-RC1 Nov 27, 2018
Copy link
Contributor

@adriaanm adriaanm left a comment

Choose a reason for hiding this comment

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

💯 the code is much, much nicer! encapsulation FTW
🏅 for moxie
🃏 because wild card

@adriaanm adriaanm merged commit 1bf19cd into scala:2.13.x Nov 27, 2018
@som-snytt som-snytt deleted the issue/underscore branch November 27, 2018 12:11
rtyley added a commit to guardian/twitter4s that referenced this pull request Oct 20, 2019
This project now compiles with Scala 2.13 by default, while still
cross-compiling to Scala 2.12.

Issues addressed with this upgrade:

### Underscore (`_`) is no longer a valid identifer for vals

Using underscore like this is no longer allowed...

```
implicit val _ = ...
```

...we have to give the `val` a valid name:


```
implicit val v = ...
```

See also:

* scala/bug#10384
* scala/bug#7691
* scala/scala#6218

### `Map.mapValues()` now returns a `MapView` rather than a `Map`

We usually want a `Map`, so we can just add in a `.toMap` to the end of
the expression - it's harmless in Scala 2.12, and allows the code to
compile in Scala 2.13. `Map.mapValues()` itself is deprecated in Scala
2.13, but using the new recommended alternative doesn't work in Scala 2.12.

https://docs.scala-lang.org/overviews/core/collections-migration-213.html#what-are-the-breaking-changes

See also:

* scala/bug#10919
* scala/scala#7014
rtyley added a commit to guardian/twitter4s that referenced this pull request Oct 20, 2019
This project now compiles with Scala 2.13 by default, while still
cross-compiling to Scala 2.12.

Issues addressed with this upgrade:

### Underscore (`_`) is no longer a valid identifer for `val`s

Using underscore like this is no longer allowed...

```
implicit val _ = ...
```

...we have to give the `val` a valid name (even if it's just `v`):


```
implicit val v = ...
```

See also:

* scala/bug#10384
* scala/bug#7691
* scala/scala#6218

### `Map.mapValues()` now returns a `MapView` rather than a `Map`

We usually want a `Map`, so we can just add in a `.toMap` to the end of
the expression - it's harmless in Scala 2.12, and allows the code to
compile in Scala 2.13. `Map.mapValues()` itself is deprecated in Scala
2.13, but using the new recommended alternative doesn't work in Scala 2.12.

https://docs.scala-lang.org/overviews/core/collections-migration-213.html#what-are-the-breaking-changes

See also:

* scala/bug#10919
* scala/scala#7014

### `.to` can no longer infer what resulting collection type you want

This is all part of `CanBuildFrom` going away in Scala 2.13:

https://www.scala-lang.org/blog/2018/06/13/scala-213-collections.html#life-without-canbuildfrom
rtyley added a commit to guardian/twitter4s that referenced this pull request Oct 20, 2019
This project now compiles with Scala 2.13 by default, while still
cross-compiling to Scala 2.12 & 2.11.

Issues addressed with this upgrade:

### Underscore (`_`) is no longer a valid identifer for `val`s

Using underscore like this is no longer allowed...

```
implicit val _ = ...
```

...we have to give the `val` a valid name (even if it's just `v`):


```
implicit val v = ...
```

See also:

* scala/bug#10384
* scala/bug#7691
* scala/scala#6218

### `Map.mapValues()` now returns a `MapView` rather than a `Map`

We usually want a `Map`, so we can just add in a `.toMap` to the end of
the expression - it's harmless in Scala 2.12, and allows the code to
compile in Scala 2.13. `Map.mapValues()` itself is deprecated in Scala
2.13, but using the new recommended alternative doesn't work in Scala 2.12.

https://docs.scala-lang.org/overviews/core/collections-migration-213.html#what-are-the-breaking-changes

See also:

* scala/bug#10919
* scala/scala#7014

### `.to` can no longer infer what resulting collection type you want

This is all part of `CanBuildFrom` going away in Scala 2.13:

https://www.scala-lang.org/blog/2018/06/13/scala-213-collections.html#life-without-canbuildfrom
rtyley added a commit to guardian/twitter4s that referenced this pull request Oct 20, 2019
This project now compiles with Scala 2.13 by default, while still
cross-compiling to Scala 2.12 & 2.11.

Issues addressed with this upgrade:

### Underscore (`_`) is no longer a valid identifer for `val`s

Using underscore like this is no longer allowed...

```
implicit val _ = ...
```

...we have to give the `val` a valid name (even if it's just `v`):


```
implicit val v = ...
```

See also:

* scala/bug#10384
* scala/bug#7691
* scala/scala#6218

### `Map.mapValues()` now returns a `MapView` rather than a `Map`

We usually want a `Map`, so we can just add in a `.toMap` to the end of
the expression - it's harmless in Scala 2.12, and allows the code to
compile in Scala 2.13. `Map.mapValues()` itself is deprecated in Scala
2.13, but using the new recommended alternative doesn't work in Scala 2.12.

https://docs.scala-lang.org/overviews/core/collections-migration-213.html#what-are-the-breaking-changes

See also:

* scala/bug#10919
* scala/scala#7014

### `.to` can no longer infer what resulting collection type you want

This is all part of `CanBuildFrom` going away in Scala 2.13:

https://www.scala-lang.org/blog/2018/06/13/scala-213-collections.html#life-without-canbuildfrom
rtyley added a commit to guardian/twitter4s that referenced this pull request Oct 21, 2019
This project now compiles with Scala 2.13 by default, while still
cross-compiling to Scala 2.12 & 2.11.

Issues addressed with this upgrade:

### Underscore (`_`) is no longer a valid identifer for `val`s

Using underscore like this is no longer allowed...

```
implicit val _ = ...
```

...we have to give the `val` a valid name (even if it's just `v`):


```
implicit val v = ...
```

See also:

* scala/bug#10384
* scala/bug#7691
* scala/scala#6218

### `Map.mapValues()` now returns a `MapView` rather than a `Map`

We usually want a `Map`, so we can just add in a `.toMap` to the end of
the expression - it's harmless in Scala 2.12, and allows the code to
compile in Scala 2.13. `Map.mapValues()` itself is deprecated in Scala
2.13, but using the new recommended alternative doesn't work in Scala 2.12.

https://docs.scala-lang.org/overviews/core/collections-migration-213.html#what-are-the-breaking-changes

See also:

* scala/bug#10919
* scala/scala#7014

### `.to` can no longer infer what resulting collection type you want

This is all part of `CanBuildFrom` going away in Scala 2.13:

https://www.scala-lang.org/blog/2018/06/13/scala-213-collections.html#life-without-canbuildfrom
rtyley added a commit to guardian/twitter4s that referenced this pull request Oct 21, 2019
This project now compiles with Scala 2.13 by default, while still
cross-compiling to Scala 2.12 & 2.11.

Although Scala 2.13.1 has been released, this change sticks with 2.13.0,
as `scoverage` has not yet released an update compatible with 2.13.1:

scoverage/sbt-scoverage#295
scoverage/scalac-scoverage-plugin#283
scoverage/sbt-scoverage#299


Migration issues addressed with the update to Scala 2.13:

### Underscore (`_`) is no longer a valid identifer for `val`s

Using underscore like this is no longer allowed...

```
implicit val _ = ...
```

...we have to give the `val` a valid name (even if it's just `v`):


```
implicit val v = ...
```

See also:

* scala/bug#10384
* scala/bug#7691
* scala/scala#6218

### `Map.mapValues()` now returns a `MapView` rather than a `Map`

We usually want a `Map`, so we can just add in a `.toMap` to the end of
the expression - it's harmless in Scala 2.12, and allows the code to
compile in Scala 2.13. `Map.mapValues()` itself is deprecated in Scala
2.13, but using the new recommended alternative doesn't work in Scala 2.12.

https://docs.scala-lang.org/overviews/core/collections-migration-213.html#what-are-the-breaking-changes

See also:

* scala/bug#10919
* scala/scala#7014

### `.to` can no longer infer what resulting collection type you want

This is all part of `CanBuildFrom` going away in Scala 2.13:

https://www.scala-lang.org/blog/2018/06/13/scala-213-collections.html#life-without-canbuildfrom
rtyley added a commit to guardian/twitter4s that referenced this pull request Oct 21, 2019
This project now compiles with Scala 2.13 by default, while still
cross-compiling to Scala 2.12 & 2.11.

Although Scala 2.13.1 has been released, this change sticks with 2.13.0,
as `scoverage` has not yet released an update compatible with 2.13.1:

scoverage/sbt-scoverage#295
scoverage/scalac-scoverage-plugin#283
scoverage/sbt-scoverage#299


Migration issues addressed with the update to Scala 2.13:

### Underscore (`_`) is no longer a valid identifer for `val`s

Using underscore like this is no longer allowed...

```
implicit val _ = ...
```

...we have to give the `val` a valid name (even if it's just `v`):


```
implicit val v = ...
```

See also:

* scala/bug#10384
* scala/bug#7691
* scala/scala#6218

### `Map.mapValues()` now returns a `MapView` rather than a `Map`

We usually want a `Map`, so we can just add in a `.toMap` to the end of
the expression - it's harmless in Scala 2.12, and allows the code to
compile in Scala 2.13. `Map.mapValues()` itself is deprecated in Scala
2.13, but using the new recommended alternative doesn't work in Scala 2.12.

https://docs.scala-lang.org/overviews/core/collections-migration-213.html#what-are-the-breaking-changes

See also:

* scala/bug#10919
* scala/scala#7014

### `.to` can no longer infer what resulting collection type you want

This is all part of `CanBuildFrom` going away in Scala 2.13:

https://www.scala-lang.org/blog/2018/06/13/scala-213-collections.html#life-without-canbuildfrom
@SethTisue
Copy link
Member

SethTisue commented Feb 6, 2020

implicit val _ = ... used to work and now doesn't. that's as intended, but it would be nice if the compiler issued a warning

@eed3si9n
Copy link
Member

Thanks for fixing this. Maybe we could mention in https://github.com/scala/scala/releases/tag/v2.13.0 that this allows multiple dummy binding.

What do you think about the following edit?

  * Underscore is no longer a legal identifier unless backquoted ([bug\#10384](https://github.com/scala/bug/issues/10384))
+   * Multiple dummy bindings can now be used within a scope: `{ val _ = 3; val _ = 5; 7 }`
    * `val _ =` is now a pattern match
    * `implicit val _ =` is also now a pattern match which does not introduce an identifier and therefore does not add anything to implicit scope

@SethTisue
Copy link
Member

@eed3si9n hmm... not against adding some wording, but I think we should make it very clear to the reader why we're telling them this. (which the existing text isn't necessarily doing an ideal job of, either)

what is the recommended way to value-discard, warning-free? is it (...: Unit), or val _ = ...? I'm not sure which I like better, style-wise.

@eed3si9n
Copy link
Member

Between the two, val _ = .... I think is less surprising to the person reading the code:

val _ = compile.value
val _ = copyResources.value

(...: Unit) has similar vibe to final val in a sense that all the tokens make sense, but the intent is opaque unless you're in the close circle of people who's been watching the development of 2.13 closely.

@som-snytt
Copy link
Contributor Author

what is the recommended way to value-discard, warning-free?

@nowarn or -Wconf

"Warn-free, as free as the wind blows..." 🎶

@SethTisue
Copy link
Member

SethTisue commented Aug 13, 2020

okay, I changed that section of the notes to:

  • Underscore is no longer a legal identifier unless backquoted (bug#10384)
    • val _ = is now a pattern match (and discards the value without incurring a warning)
    • implicit val _ = is also now a pattern match (and is useless, because it no longer adds to implicit scope)

(The fact that as an additional consequence it is now allowed to val _ = ... multiple times seems like unnecessary extra detail to me.)

@som-snytt
Copy link
Contributor Author

Also, from now on, we should call them the release 🎶 or is that already the name of Seth's band?

@dwijnand
Copy link
Member

what is the recommended way to value-discard, warning-free? is it (...: Unit), or val _ = ...? I'm not sure which I like better, style-wise.

#7563 makes (...: Unit) the official way to avoid warnings.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
7 participants