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

Suggest solutions for fn foo(&foo: Foo) #38605

Merged
merged 5 commits into from
Jan 12, 2017
Merged

Conversation

estebank
Copy link
Contributor

@estebank estebank commented Dec 25, 2016

For a given file:

struct Foo {}

fn foo(&foo: Foo) {}

suggest:

error[E0308]: mismatched types
 --> file.rs:3:8
  |
3 | fn foo(&foo: Foo) {}
  |        ^^^^ expected struct `Foo`, found reference
  |
  = note: expected type `Foo`
  = note:    found type `&_`
  = help: did you mean `foo: &Foo`?

Fix #38371.

@rust-highfive
Copy link
Collaborator

r? @nikomatsakis

(rust_highfive has picked a reviewer for you, use r? to override)

@bors
Copy link
Contributor

bors commented Dec 28, 2016

☔ The latest upstream changes (presumably #38449) made this pull request unmergeable. Please resolve the merge conflicts.

@nikomatsakis
Copy link
Contributor

@estebank I definitely think we need suggestions here, but somehow I'm not sure this output will address the core problem, which tends to be that people don't know where to put the &. I wonder if we want something more targeted. I am imagining something like:

error[E0308]: inappropriate pattern for type
 --> file.rs:3:8
  |
3 | fn foo(&foo: Foo) {}
  |        ^^^^ `&` pattern cannot be used to match a value of type `Foo`
  |
  = help: use `foo: &Foo` to declare an argument `foo` of type `&Foo`

I realize this is a deeper change, but my goals here are:

  • convey to user that in fact this is a "pattern" and use the word "match" to show that is related to match
  • give a suggestion for what I suspect they actually wanted

I am not crazy about the precise wording of my final suggestion there. (I wonder if @wycats has any suggestions here?)

@pnkfelix
Copy link
Member

pnkfelix commented Jan 3, 2017

Perhaps the most important point of @nikomatsakis 's comment:

in practice, someone who writes: fn f(&foo: Foo) wants

  • neither foo: Foo (pass by value, but clearly the developer wanted a reference somewhere),
  • nor &foo: &Foo (because pattern-binding of &foo will attempt to copy the dereferenced value into foo, which is probably not what was wanted either).

So I imagine a shallower change to your PR would be to make it emit:

help: did you mean `foo: &Foo`?

@nikomatsakis
Copy link
Contributor

help: did you mean foo: &Foo?

Yeah, this is probably best

@estebank
Copy link
Contributor Author

estebank commented Jan 4, 2017

Changed to @pnkfelix's version. Next time I have some time to look at this, I will look at adding a new error code for this specific case so that --explain has a complete explanation of the differences for the three valid cases (f: F, f: &F, &f: &F), as well as the more specific wording in @nikomatsakis' suggestion.

Copy link
Contributor

@nikomatsakis nikomatsakis left a comment

Choose a reason for hiding this comment

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

Can you add the wacky test cases too?

if let Ok(snippet) = self.sess().codemap()
.span_to_snippet(pat.span)
{
err.help(&format!("did you mean `{}: &{}`?",
Copy link
Contributor

Choose a reason for hiding this comment

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

One concern -- what happens in more extreme cases? I think we should check that the inner pattern (represented by inner, here) is a binding pattern, so as not to trigger for something like fn foo(&&bar: &u32) or fn foo(&[bar]: &u32). Suggesting &bar: &&u32 and [bar]: &&u32 respectively doesn't seem all that helpful (that is what we will do, right?)

Copy link
Contributor Author

@estebank estebank Jan 6, 2017

Choose a reason for hiding this comment

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

I tried adding these cases to the test and the results where:

fn ugh(&[bar]: &u32) {
}

error: slice pattern syntax is experimental (see issue #23121)
  --> ../../src/test/ui/mismatched_types/issue-38371.rs:26:9
   |
26 | fn ugh(&[bar]: &u32) {
   |         ^^^^^
fn agh(&&bar: &u32) {
}

error[E0308]: mismatched types
  --> ../../src/test/ui/mismatched_types/issue-38371.rs:29:9
   |
29 | fn agh(&&bar: &u32) {
   |         ^^^^ expected u32, found reference
   |
   = note: expected type `u32`
   = note:    found type `&_`

without changes to the code.

Copy link
Contributor

Choose a reason for hiding this comment

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

So, the first one is a case of needing a feature-gate, but I'm surprised by the second one. What does &&bar: &Foo do? I can't tell why the help doesn't trigger here...?

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 can't tell why the help doesn't trigger here...?

Neither can I. I've never even thought about trying to use something like (&&bar: &u32).

the first one is a case of needing a feature-gate

I figured as much. Last time I looked at this I couldn't find the appropriate feature gate, but just googled again and found it. I added the test back.

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe I'll pull your branch and build it locally and try to figure out what is going on then. I mean the tests look pretty good but I'd rather not enable misleading output if we can help it. Might take a day or two though.

| ^^^^ expected struct `Foo`, found reference
|
= note: expected type `Foo`
= note: found type `&_`
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think we have to fix this here necessarily, but I feel like these note: messages are kind of distracting from the help, which is more likely to be of use. But I'm not sure how to fix without doing potentially more harm than good, so let's leave as is.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For a while I've been thinking wether it would make sense to make the expected/found notes a first class comment, so that these errors would look closer to

error[E0308]: mismatched types
  --> ../../src/test/ui/mismatched_types/issue-38371.rs:14:8
   |
14 | fn foo(&foo: Foo) {
   |        ^^^^ expected struct `Foo`, found reference
   |
   = expected type `Foo`
   =    found type `&_`
   = help: did you mean `foo: &Foo`?

error[E0308]: mismatched types
  --> ../../src/test/ui/mismatched_types/issue-38371.rs:26:9
   |
26 | fn agh(&&bar: &u32) {
   |         ^^^^ expected u32, found reference
   |
   = expected type `u32`
   =    found type `&_`

If you feel there'd be value on that, I could create an issue and start a PR for it.

Copy link
Contributor

Choose a reason for hiding this comment

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

I agree that looks better

Copy link
Contributor Author

@estebank estebank Jan 7, 2017

Choose a reason for hiding this comment

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

Opened issue #38901 and PR #38902 for this.

@nikomatsakis
Copy link
Contributor

OK, I investigated. The reason that my examples were not producing bad suggestions was because the is_arg flag is only true on the outermost pattern. This was not obvious to me and probably merits a comment. In any case, you can produce bad output with an example like this one:

fn agh(&&&bar: u32) {
}

fn main() { }

which emits:

error[E0308]: mismatched types
 --> /home/nmatsakis/tmp/foo.rs:1:8
  |
1 | fn agh(&&bar: u32) {
  |        ^^^^^ expected u32, found reference
  |
  = note: expected type `u32`
  = note:    found type `&_`
  = help: did you mean `&bar: &u32`?

error: aborting due to previous error

I pushed a commit addressing this issue and adding a comment -- but without a test case yet.

@nikomatsakis
Copy link
Contributor

@bors r+

@bors
Copy link
Contributor

bors commented Jan 11, 2017

📌 Commit d723e02 has been approved by nikomatsakis

@bors
Copy link
Contributor

bors commented Jan 11, 2017

⌛ Testing commit d723e02 with merge 2a0b975...

@bors
Copy link
Contributor

bors commented Jan 11, 2017

💔 Test failed - status-travis

@alexcrichton
Copy link
Member

alexcrichton commented Jan 11, 2017 via email

@bors
Copy link
Contributor

bors commented Jan 12, 2017

⌛ Testing commit d723e02 with merge 1ca100d...

bors added a commit that referenced this pull request Jan 12, 2017
Suggest solutions for `fn foo(&foo: Foo)`

For a given file:

```rust
struct Foo {}

fn foo(&foo: Foo) {}
```

suggest:

```
error[E0308]: mismatched types
 --> file.rs:3:8
  |
3 | fn foo(&foo: Foo) {}
  |        ^^^^ expected struct `Foo`, found reference
  |
  = note: expected type `Foo`
  = note:    found type `&_`
  = help: did you mean `foo: &Foo`?
```

Fix #38371.
@bors
Copy link
Contributor

bors commented Jan 12, 2017

☀️ Test successful - status-appveyor, status-travis
Approved by: nikomatsakis
Pushing 1ca100d to master...

@bors bors merged commit d723e02 into rust-lang:master Jan 12, 2017
@estebank estebank deleted the fix-38371 branch November 9, 2023 05:27
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.

6 participants