-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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 clearer error message using &str + &str
#39116
Conversation
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @nrc (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. Please see the contribution instructions for more information. |
Mostly looks okay? Would like to see if @jonathandturner has thoughts on this. Feel free to try and add handling for the other forms. I've been considering having lang-item-like annotations for types in the stdlib, which let diagnostics check for their existence. We do path matching extensively in clippy, and it would be useful to do something less hacky in rustc. |
}; | ||
err.span_suggestion(expr.span, | ||
&format!("Your first argument should be a `String`, not `&str`. \ | ||
Try using `to_string()`"), |
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.
.to_string()
//~^ ERROR 12:18: 12:26: binary operation `+` cannot be applied to type `&'static str` [E0369] | ||
//~| NOTE You can't use `+` between a `&str` and `&str` | ||
//~| HELP Your first argument should be a `String`, not `&str`. Try using `to_string()` | ||
//~| NOTE an implementation of `std::ops::Add` might be missing for `&'static str` |
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.
Have a thingy for the suggestion too
span_note!(&mut err, lhs_expr.span, | ||
"an implementation of `{}` might be missing for `{}`", | ||
"an implementation of `{}` might be missing for `{}`", |
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.
Please remove this extra space.
I've updated the code with the above suggestions. @Manishearth how would I go about searching for a |
This is what we do in clippy to match structs. I think we should just land as-is since that's a bit hacky. I'm filing an issue for the diagnostic-lang-item stuff. |
Filed #39131 about the diagnostic item |
In the meantime I think it might be good to get the diagnostic of things like |
Actually, you can make this work without the full framework of diagnostics items; just add a |
@Manishearth using the code from clippy or just putting it in the code now as is? |
No, we don't want to use the clippy code, it's hacky. Use an attribute as shown above. |
Maybe |
I used ripgrep and git grep to search the code and neither of those attributes exist in the code base so I have no basis of comparison to do it the way you've mentioned. |
I'm saying you invent a new attribute :) Annotate String with You will probably have to add it to libsyntax/feature_gate.rs as well, as a Gated attribute. |
Anyway we can land as-is if you'd prefer too. |
I like the idea. Can you use a src/test/ui test instead of a compile_fail test? Just so that we can see what the final output looks like a bit better in the PR. |
@Manishearth ohhhhhh okay I think I see what you're talking about now. I can try when I'm off work. @jonathandturner I'll switch it over to ui test when I'm off work! |
if let TyRef(_, r_ty) = rhs_ty.sty { | ||
if l_ty.ty.sty == TyStr && r_ty.ty.sty == TyStr { | ||
span_note!(&mut err, lhs_expr.span, | ||
"You can't use `+` between a `&str` and `&str`"); |
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.
We usually use the passive voice for error messages, i.e., something like "+
can't be used to concatenate two &str
strings" and similarly later on.
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.
Consistency is good. This one is a quick fix.
_ => format!("<expression>") | ||
}; | ||
err.span_suggestion(expr.span, | ||
&format!("Your first argument should be a `String`, not `&str`. \ |
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.
It would be nice to explain why a String is needed, otherwise this seems a little like boilerplate.
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.
Yeah I can see why it's boilerplate like. I'll put a more descriptive message.
}; | ||
err.span_suggestion(expr.span, | ||
&format!("Your first argument should be a `String`, not `&str`. \ | ||
Try using to_string()"), |
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.
I would prefer phrasing like "to_string
can be used to create an owned string from a string reference", I actually prefer using to_owned
rather than to_string
because it better describes what is going on
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.
to_owned
or to_string
is always a hot button topic. Now they're semantically equivalent at least. I can put to_owned
. It's all the same to me and with the rest of the sentence you put it communicates the intent of the function call.
//~| NOTE You can't use `+` between a `&str` and `&str` | ||
//~| HELP Your first argument should be a `String`, not `&str`. Try using to_string() | ||
//~| SUGGESTION let string = "Hello ".to_string() + "World" + "!" | ||
//~| NOTE an implementation of `std::ops::Add` might be missing for `&'static str` |
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.
Would be nice if we could skip the NOTE in this case.
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.
@nrc - I think he's going to move to a UI test, so we won't need them (and we'll be able to see what the actual error will look like)
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.
I meant remove it from the error message, not from the test
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.
Shouldn't be too hard. I have an idea of how to bypass this output.
@nrc I've updated the wording, though I'm wondering if it could use some improvement. I didn't want to make it too verbose, but I wanted to get the point across as well. I've also added a way to bypass the NOTE you didn't want output here through some conditional logic short circuiting. It feels a little hackish and I was wondering if you had a better idea here as to what could be improved. Also not since the test hasn't been updated yet this should fail testing. |
// and it was an addition with &str then skip the | ||
// span note below it. Otherwise just emit the span | ||
// note | ||
if missing_trait == "std::ops::Add" && |
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 will also skip the note when the trait is not Add instead of only when Add + &str
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.
You're right. I got the logic wrong here. I tested it just to make sure so this will need to get changed
err.span_suggestion(expr.span, | ||
&format!("to_owned() can be used to create an owned `String` \ | ||
from a string reference. This allows concatenation \ | ||
since the `String` is owned."), suggestion); |
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.
The second sentence doesn't quite explain why that is necessary. How about, "String concatenation appends the string on the right to the string on the left. That modifies the string on the left and may require reallocation, this requires ownership of the string on the left." It's a bit wordy, but tries to explain why you can't use a reference.
@nrc and @jonathandturner these commits should cover both the ui test and message output that was brought up earlier. |
Looking at the raw log one failed on my test due to the output being different but it passed for all the other ones. I'm not sure why this would happen though |
r = me with the test fixed. I'm not sure why that is failing, but it looks legit to me. |
@nrc looking at the logs further this seems to be the problem
I think I added in this file by accident. I think removing it should fix the build issue. If not I'm building the compiler again from scratch and reupdating the references |
@nrc I fixed the build! |
@mgattozzi nice! Could you squash the commits please? Then r+ |
@nrc squash and force push? |
yes |
@nrc got it. Wasn't sure policy regarding force pushing. Alright it's all rebased and good to go! |
@bors: r+ Thanks for sticking with it @mgattozzi , nice PR! |
📌 Commit 4da2994 has been approved by |
@nrc I'm glad to have been able to contribute to the compiler itself finally! It was a joy and I'm hoping to tackle some more issues. Thanks for reviewing it! |
⌛ Testing commit 4da2994 with merge 27a80f7... |
💔 Test failed - status-travis |
@nrc looks like curl messed up trying to download the rustc binary to do compilation. |
@bors: retry |
☔ The latest upstream changes (presumably #39353) made this pull request unmergeable. Please resolve the merge conflicts. |
Looks like this unintentionally added files under |
@kevinmehall thanks I'll remove it |
This is the first part of #39018. One of the common things for new users coming from more dynamic languages like JavaScript, Python or Ruby is to use `+` to concatenate strings. However, this doesn't work that way in Rust unless the first type is a `String`. This commit adds a check for this use case and outputs a new error as well as a suggestion to guide the user towards the desired behavior. It also adds a new test case to test the output of the error.
@nrc it needs to get approved again so it can go through |
@bors: r+ |
📌 Commit b54f593 has been approved by |
Add clearer error message using `&str + &str` This is the first part of #39018. One of the common things for new users coming from more dynamic languages like JavaScript, Python or Ruby is to use `+` to concatenate strings. However, this doesn't work that way in Rust unless the first type is a `String`. This commit adds a check for this use case and outputs a new error as well as a suggestion to guide the user towards the desired behavior. It also adds a new test case to test the output of the error.
☀️ Test successful - status-appveyor, status-travis |
Finally! |
@Manishearth and @nrc thanks a lot! This great that it's finally merged! |
This is the first part of #39018. One of the common things for new users
coming from more dynamic languages like JavaScript, Python or Ruby is to
use
+
to concatenate strings. However, this doesn't work that way inRust unless the first type is a
String
. This commit adds a check forthis use case and outputs a new error as well as a suggestion to guide
the user towards the desired behavior. It also adds a new test case to
test the output of the error.