Skip to content

Fix #10178: Put the wildcard demon back in the bottle #10195

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 1 commit into from
Nov 6, 2020

Conversation

odersky
Copy link
Contributor

@odersky odersky commented Nov 5, 2020

This was a very interesting bug. Why did any2stringadd appear out of the blue?
The first observation was that it was resolved by an import of an identifier with
_ as its name. Why? Because we have a standard predefined import

import Predef.{any2stringadd => _, _}

This is represented as a "rename" from anyToStringAdd to _, assuming that
no real identifier could be _. But that assumption turned out to be wrong.

How did we end up with an identifier _ that needed to be resolved? This was a
second bug in Desugar, method makeIdPat. Here we needed to create binds for parts
of a pattern. If the pattern was already a Bind, we used that one instead. But the
Bind in question was anonymous, using _ as the pattern variable. So we did not
replace that by a fresh identifier, but used _ as the identifier instead. However,
_ is treated specially as a binder; it does not generate a symbol in the enclosing
scope. So resolving the _ identifier did not see the enclosing bind and searched
further out instead, until it found the "renamed" import. Beautiful! It shows that
treating wildcards as some sort of identifiers is fraught with surprises.

@som-snytt
Copy link
Contributor

Reminiscent of scala/scala#6218 which in 2017 used the encoding with empty tree, but that was deemed too big a change, so in 2018 it just got some encapsulation at ImportSelectorApi and ImportSelector.

I mention it only because of the psychological scarring.

This was a very interesting bug. Why did `any2stringadd` appear out of the blue?
The first observation was that it was resolved by an import of an identifier with
`_` as its name. Why? Because we have a standard predefined import
```scala
import Predef.{any2stringadd => _, _}
```
This is represented as a "rename" from `anyToStringAdd` to `_`, assuming that
no real identifier could be `_`. But that assumption turned out to be wrong.

How did we end up with an identifier `_` that needed to be resolved? This was a
second bug in Desugar, method `makeIdPat`. Here we needed to create binds for parts
of a pattern. If the pattern was already a Bind, we used that one instead. But the
`Bind` in question was anonymous, using `_` as the pattern variable. So we did not
replace that by a fresh identifier, but used `_` as the identifier instead. However,
`_` is treated specially as a binder; it does not generate a symbol in the enclosing
scope. So resolving the `_` identifier did not see the enclosing bind and searched
further out instead, until it found the "renamed" import. Beautiful! It shows that
treating wildcards as some sort of identifiers is fraught with surprises.
@odersky
Copy link
Contributor Author

odersky commented Nov 6, 2020

A more robust representation could be to avoid using Ident for wildcards. We could use a special Tree node class for them.

Copy link
Member

@bishabosha bishabosha left a comment

Choose a reason for hiding this comment

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

LGTM

@bishabosha bishabosha merged commit fc8b512 into scala:master Nov 6, 2020
@bishabosha bishabosha deleted the fix-#10178 branch November 6, 2020 11:26
@Kordyjan Kordyjan added this to the 3.0.0 milestone Aug 2, 2023
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