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 casting on numeric type error #47247

Merged
merged 6 commits into from
Jan 22, 2018
Merged

Conversation

estebank
Copy link
Contributor

@estebank estebank commented Jan 7, 2018

Re #47168.

@rust-highfive
Copy link
Collaborator

r? @petrochenkov

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

@GuillaumeGomez
Copy link
Member

Shouldn't we suggest to use from instead of casting?

@GuillaumeGomez
Copy link
Member

More globally, I'm not sure talking about size fit/shortage is a good idea. Just talking about from should be enough for most cases, don't you think?

&format!("{}, producing the closest possible value",
msg),
suggestion);
err.warn("casting here will cause Undefined Behavior if the value is \
Copy link
Member

Choose a reason for hiding this comment

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

Should "undefined behaviour" be capitalised like this? It doesn't seem to be typical in error messages.

@estebank
Copy link
Contributor Author

estebank commented Jan 7, 2018

More globally, I'm not sure talking about size fit/shortage is a good idea.

I find the possibility of using the compiler errors to teach the language appealing. Presenting some of the possible trade offs inline like this seems like a great opportunity, even though completely I agree with the problems presented by as.

Just talking about from should be enough for most cases, don't you think?

Part of what gave me pause is that From is not implemented for all conversions, only for the ones that cannot fail, and TryFrom is confined to nightly behind a feature flag. Also, the suggestion becomes much more verbose in that case (and only applies to nightly):

fn foo<T>(x: T) {}
fn main() {
    foo::<u32>(3_i32);
}

after:

#![feature(try_from)]
use std::convert::TryFrom;

fn foo<T>(x: T) {}
fn main() {
    foo::<u32>(u32::try_from(3_i32).unwrap());
}

That being said, the way I wrote the code was to make it possible to only show a subset of these suggestions depending on the case. I could suggest into() when it is supported (growing an type, u16 to u32), and remain silent in the other cases.

@estebank
Copy link
Contributor Author

estebank commented Jan 7, 2018

Updated the PR to only suggest .into() conversions. The code for suggesting casts is still there, just never triggered (it is gated on the type of expression, right now not enabled for any).

@estebank estebank added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jan 7, 2018
@GuillaumeGomez
Copy link
Member

That's problematic that TryFrom is still nightly only... And where is From implementation missing?

@estebank
Copy link
Contributor Author

estebank commented Jan 8, 2018

@GuillaumeGomez in https://github.com/rust-lang/rust/pull/47247/files#diff-1743dc5c92f33d15fb1e903d7ad3ce58 (which is admittedly very verbose, as it has every single possible numeric type mismatch) you can see that the only suggestions provided are for the types that have a From implementation:

  • within the same numeric type, being signed or unsigned, there's a From implementation from the type with a lesser bit width to the wider type (u16 -> u32, i32 -> i64),
  • from f32 to f64,
  • from 32 bit integers and lower to f64
  • from 16 bit integers and lower to f32.

let can_cast = false;

let needs_paren = match expr.node {
hir::ExprBinary(..) => true,
Copy link
Contributor

Choose a reason for hiding this comment

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

I think you can reuse syntax::util::parser::expr_precedence here and get more precise result.
See fn print_expr_method_call in pprust.rs for an example.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated.

cast_suggestion);
err.warn("casting here will cause undefined behavior if the value is \
finite but larger or smaller than the largest or smallest \
finite value representable by `f32` (this is a bug and will be \
Copy link
Contributor

Choose a reason for hiding this comment

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

float <-> float conversions are buggy?
I don't think this is true. There's -Z saturating-float-casts for correcting float -> int casts, but everything else is already correct, if I remember correctly.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh, indeed, #15536 is still open.
Ping @rkruppe just in case.

Copy link
Contributor

Choose a reason for hiding this comment

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

The default behavior is indeed still UB, saturating casts are still opt-in.

if exp.bit_width() > found.bit_width().unwrap_or(256) {
err.span_suggestion(expr.span,
&format!("{}, producing the floating point \
representation of the integer, rounded if \
Copy link
Contributor

Choose a reason for hiding this comment

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

If into is available, then the conversion will be lossless and no rounding will happen.
Also into is not available for i/usize and floats.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated message.

The suggestion is not given for isize/usize (that's what the unwrap(256) is doing). Added comment to that effect.

if exp.bit_width() > found.bit_width().unwrap_or(256) {
err.span_suggestion(expr.span,
&format!("{}, producing the floating point \
representation of the integer, rounded if \
Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

@petrochenkov
Copy link
Contributor

Looks pretty useful.
I'm also okay with dead code from can_cast = false because the implementation doesn't look "complete" without it, something can be done with it later.
I left some comments inline.

@petrochenkov petrochenkov added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jan 10, 2018
@estebank estebank added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jan 10, 2018
@estebank estebank added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jan 10, 2018
// For now, don't suggest casting with `as`.
let can_cast = false;

let needs_paren = expr_precedence(expr) < (AssocOp::As.precedence() as i8);
Copy link
Contributor

Choose a reason for hiding this comment

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

Argh, this expr_precedence works on AST.
There's another one in rustc::hir::print.
Also, AssocOp::As.precedence() -> PREC_POSTFIX.

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'm gonna add a commit to merge both into one place (new enum that only holds the type to precedence mapping, and an into impl for {hir, ast}::Expr so that there's only one source of truth for this. Started that yesterday but went to bed before I could complete it.

@bors
Copy link
Contributor

bors commented Jan 13, 2018

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

 - Use `syntax::util::parser::expr_precedence` to determine wether
   parenthesis are needed around the casting target.
 - Update message to not incorrectly mention rounding on `.into()`
   suggestions, as those types that do have that implemented will never
   round.
Introduce a new unified type that holds the expression precedence for
both AST and HIR nodes.
@estebank
Copy link
Contributor Author

Fixed.

@estebank estebank added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jan 15, 2018
@@ -903,6 +917,129 @@ pub struct Expr {
pub attrs: ThinVec<Attribute>
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ExprPrecedence {
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you move all this stuff from ast.rs somewhere, e.g. into util/parser.rs where it was previously.
This is not a part of AST or HIR, really, it's a parsing-specific detail.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done. Waiting for the tests to run to make sure nothing broke.

@petrochenkov petrochenkov added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jan 15, 2018
@petrochenkov
Copy link
Contributor

@bors r+

@bors
Copy link
Contributor

bors commented Jan 16, 2018

📌 Commit 71c0873 has been approved by petrochenkov

@petrochenkov petrochenkov added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jan 16, 2018
GuillaumeGomez added a commit to GuillaumeGomez/rust that referenced this pull request Jan 21, 2018
bors added a commit that referenced this pull request Jan 21, 2018
Rollup of 9 pull requests

- Successful merges: #47247, #47334, #47512, #47582, #47595, #47625, #47632, #47633, #47637
- Failed merges:
@bors bors merged commit 71c0873 into rust-lang:master Jan 22, 2018
@estebank estebank deleted the suggest-cast branch November 9, 2023 05:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants