Rollup merge of #72380 - lcnr:const_context, r=estebank
Fix `is_const_context`, update `check_for_cast` A better version of #71477 Adds `fn enclosing_body_owner` and uses it in `is_const_context`. `is_const_context` now uses the same mechanism as `mir_const_qualif` as it was previously incorrect. Renames `is_const_context` to `is_inside_const_context`. I also updated `check_for_cast` in the second commit, so r? @estebank (I removed one lvl of indentation, so it might be easier to review by hiding whitespace changes)
This commit is contained in:
commit
298467ee9a
9 changed files with 236 additions and 253 deletions
|
@ -335,6 +335,16 @@ impl<'hir> Map<'hir> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn enclosing_body_owner(&self, hir_id: HirId) -> HirId {
|
||||||
|
for (parent, _) in self.parent_iter(hir_id) {
|
||||||
|
if let Some(body) = self.maybe_body_owned_by(parent) {
|
||||||
|
return self.body_owner(body);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bug!("no `enclosing_body_owner` for hir_id `{}`", hir_id);
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the `HirId` that corresponds to the definition of
|
/// Returns the `HirId` that corresponds to the definition of
|
||||||
/// which this is the body of, i.e., a `fn`, `const` or `static`
|
/// which this is the body of, i.e., a `fn`, `const` or `static`
|
||||||
/// item (possibly associated), a closure, or a `hir::AnonConst`.
|
/// item (possibly associated), a closure, or a `hir::AnonConst`.
|
||||||
|
@ -537,18 +547,8 @@ impl<'hir> Map<'hir> {
|
||||||
|
|
||||||
/// Whether the expression pointed at by `hir_id` belongs to a `const` evaluation context.
|
/// Whether the expression pointed at by `hir_id` belongs to a `const` evaluation context.
|
||||||
/// Used exclusively for diagnostics, to avoid suggestion function calls.
|
/// Used exclusively for diagnostics, to avoid suggestion function calls.
|
||||||
pub fn is_const_context(&self, hir_id: HirId) -> bool {
|
pub fn is_inside_const_context(&self, hir_id: HirId) -> bool {
|
||||||
let parent_id = self.get_parent_item(hir_id);
|
self.body_const_context(self.local_def_id(self.enclosing_body_owner(hir_id))).is_some()
|
||||||
match self.get(parent_id) {
|
|
||||||
Node::Item(&Item { kind: ItemKind::Const(..) | ItemKind::Static(..), .. })
|
|
||||||
| Node::TraitItem(&TraitItem { kind: TraitItemKind::Const(..), .. })
|
|
||||||
| Node::ImplItem(&ImplItem { kind: ImplItemKind::Const(..), .. })
|
|
||||||
| Node::AnonConst(_) => true,
|
|
||||||
Node::Item(&Item { kind: ItemKind::Fn(ref sig, ..), .. }) => {
|
|
||||||
sig.header.constness == Constness::Const
|
|
||||||
}
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether `hir_id` corresponds to a `mod` or a crate.
|
/// Whether `hir_id` corresponds to a `mod` or a crate.
|
||||||
|
|
|
@ -495,7 +495,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||||
let closure_id = hir.as_local_hir_id(self.mir_def_id);
|
let closure_id = hir.as_local_hir_id(self.mir_def_id);
|
||||||
let fn_call_id = hir.get_parent_node(closure_id);
|
let fn_call_id = hir.get_parent_node(closure_id);
|
||||||
let node = hir.get(fn_call_id);
|
let node = hir.get(fn_call_id);
|
||||||
let item_id = hir.get_parent_item(fn_call_id);
|
let item_id = hir.enclosing_body_owner(fn_call_id);
|
||||||
let mut look_at_return = true;
|
let mut look_at_return = true;
|
||||||
// If we can detect the expression to be an `fn` call where the closure was an argument,
|
// If we can detect the expression to be an `fn` call where the closure was an argument,
|
||||||
// we point at the `fn` definition argument...
|
// we point at the `fn` definition argument...
|
||||||
|
|
|
@ -15,6 +15,8 @@ use rustc_span::Span;
|
||||||
|
|
||||||
use super::method::probe;
|
use super::method::probe;
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
pub fn emit_coerce_suggestions(
|
pub fn emit_coerce_suggestions(
|
||||||
&self,
|
&self,
|
||||||
|
@ -670,16 +672,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
checked_ty: Ty<'tcx>,
|
checked_ty: Ty<'tcx>,
|
||||||
expected_ty: Ty<'tcx>,
|
expected_ty: Ty<'tcx>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if self.tcx.hir().is_const_context(expr.hir_id) {
|
|
||||||
// Shouldn't suggest `.into()` on `const`s.
|
|
||||||
// FIXME(estebank): modify once we decide to suggest `as` casts
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if self.tcx.sess.source_map().is_imported(expr.span) {
|
if self.tcx.sess.source_map().is_imported(expr.span) {
|
||||||
// Ignore if span is from within a macro.
|
// Ignore if span is from within a macro.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let src = if let Ok(src) = self.tcx.sess.source_map().span_to_snippet(expr.span) {
|
||||||
|
src
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
// If casting this expression to a given numeric type would be appropriate in case of a type
|
// If casting this expression to a given numeric type would be appropriate in case of a type
|
||||||
// mismatch.
|
// mismatch.
|
||||||
//
|
//
|
||||||
|
@ -708,6 +711,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
} else {
|
} else {
|
||||||
String::new()
|
String::new()
|
||||||
};
|
};
|
||||||
|
|
||||||
if let hir::ExprKind::Call(path, args) = &expr.kind {
|
if let hir::ExprKind::Call(path, args) = &expr.kind {
|
||||||
if let (hir::ExprKind::Path(hir::QPath::TypeRelative(base_ty, path_segment)), 1) =
|
if let (hir::ExprKind::Path(hir::QPath::TypeRelative(base_ty, path_segment)), 1) =
|
||||||
(&path.kind, args.len())
|
(&path.kind, args.len())
|
||||||
|
@ -749,37 +753,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
checked_ty, expected_ty,
|
checked_ty, expected_ty,
|
||||||
);
|
);
|
||||||
|
|
||||||
let needs_paren = expr.precedence().order() < (PREC_POSTFIX as i8);
|
let with_opt_paren: fn(&dyn fmt::Display) -> String =
|
||||||
|
if expr.precedence().order() < PREC_POSTFIX {
|
||||||
|
|s| format!("({})", s)
|
||||||
|
} else {
|
||||||
|
|s| s.to_string()
|
||||||
|
};
|
||||||
|
|
||||||
if let Ok(src) = self.tcx.sess.source_map().span_to_snippet(expr.span) {
|
let cast_suggestion = format!("{}{} as {}", prefix, with_opt_paren(&src), expected_ty);
|
||||||
let cast_suggestion = format!(
|
let try_into_suggestion = format!("{}{}.try_into().unwrap()", prefix, with_opt_paren(&src));
|
||||||
"{}{}{}{} as {}",
|
let into_suggestion = format!("{}{}.into()", prefix, with_opt_paren(&src));
|
||||||
prefix,
|
let suffix_suggestion = with_opt_paren(&format_args!(
|
||||||
if needs_paren { "(" } else { "" },
|
"{}{}",
|
||||||
src,
|
if matches!(
|
||||||
if needs_paren { ")" } else { "" },
|
(&expected_ty.kind, &checked_ty.kind),
|
||||||
expected_ty,
|
(ty::Int(_) | ty::Uint(_), ty::Float(_))
|
||||||
);
|
) {
|
||||||
let try_into_suggestion = format!(
|
|
||||||
"{}{}{}{}.try_into().unwrap()",
|
|
||||||
prefix,
|
|
||||||
if needs_paren { "(" } else { "" },
|
|
||||||
src,
|
|
||||||
if needs_paren { ")" } else { "" },
|
|
||||||
);
|
|
||||||
let into_suggestion = format!(
|
|
||||||
"{}{}{}{}.into()",
|
|
||||||
prefix,
|
|
||||||
if needs_paren { "(" } else { "" },
|
|
||||||
src,
|
|
||||||
if needs_paren { ")" } else { "" },
|
|
||||||
);
|
|
||||||
let suffix_suggestion = format!(
|
|
||||||
"{}{}{}{}",
|
|
||||||
if needs_paren { "(" } else { "" },
|
|
||||||
if let (ty::Int(_) | ty::Uint(_), ty::Float(_)) =
|
|
||||||
(&expected_ty.kind, &checked_ty.kind,)
|
|
||||||
{
|
|
||||||
// Remove fractional part from literal, for example `42.0f32` into `42`
|
// Remove fractional part from literal, for example `42.0f32` into `42`
|
||||||
let src = src.trim_end_matches(&checked_ty.to_string());
|
let src = src.trim_end_matches(&checked_ty.to_string());
|
||||||
src.split('.').next().unwrap()
|
src.split('.').next().unwrap()
|
||||||
|
@ -787,36 +776,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
src.trim_end_matches(&checked_ty.to_string())
|
src.trim_end_matches(&checked_ty.to_string())
|
||||||
},
|
},
|
||||||
expected_ty,
|
expected_ty,
|
||||||
if needs_paren { ")" } else { "" },
|
));
|
||||||
);
|
|
||||||
let literal_is_ty_suffixed = |expr: &hir::Expr<'_>| {
|
let literal_is_ty_suffixed = |expr: &hir::Expr<'_>| {
|
||||||
if let hir::ExprKind::Lit(lit) = &expr.kind {
|
if let hir::ExprKind::Lit(lit) = &expr.kind { lit.node.is_suffixed() } else { false }
|
||||||
lit.node.is_suffixed()
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let in_const_context = self.tcx.hir().is_inside_const_context(expr.hir_id);
|
||||||
let suggest_to_change_suffix_or_into =
|
let suggest_to_change_suffix_or_into =
|
||||||
|err: &mut DiagnosticBuilder<'_>, is_fallible: bool| {
|
|err: &mut DiagnosticBuilder<'_>, is_fallible: bool| {
|
||||||
err.span_suggestion(
|
let msg = if literal_is_ty_suffixed(expr) {
|
||||||
expr.span,
|
|
||||||
if literal_is_ty_suffixed(expr) {
|
|
||||||
&lit_msg
|
&lit_msg
|
||||||
|
} else if in_const_context {
|
||||||
|
// Do not recommend `into` or `try_into` in const contexts.
|
||||||
|
return;
|
||||||
} else if is_fallible {
|
} else if is_fallible {
|
||||||
&try_msg
|
&try_msg
|
||||||
} else {
|
} else {
|
||||||
&msg
|
&msg
|
||||||
},
|
};
|
||||||
if literal_is_ty_suffixed(expr) {
|
let suggestion = if literal_is_ty_suffixed(expr) {
|
||||||
suffix_suggestion.clone()
|
suffix_suggestion.clone()
|
||||||
} else if is_fallible {
|
} else if is_fallible {
|
||||||
try_into_suggestion
|
try_into_suggestion
|
||||||
} else {
|
} else {
|
||||||
into_suggestion.clone()
|
into_suggestion.clone()
|
||||||
},
|
};
|
||||||
Applicability::MachineApplicable,
|
err.span_suggestion(expr.span, msg, suggestion, Applicability::MachineApplicable);
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
match (&expected_ty.kind, &checked_ty.kind) {
|
match (&expected_ty.kind, &checked_ty.kind) {
|
||||||
|
@ -963,8 +948,5 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5091,7 +5091,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
expected: Ty<'tcx>,
|
expected: Ty<'tcx>,
|
||||||
found: Ty<'tcx>,
|
found: Ty<'tcx>,
|
||||||
) {
|
) {
|
||||||
if self.tcx.hir().is_const_context(expr.hir_id) {
|
if self.tcx.hir().is_inside_const_context(expr.hir_id) {
|
||||||
// Do not suggest `Box::new` in const context.
|
// Do not suggest `Box::new` in const context.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -5128,7 +5128,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// Handle #68197.
|
// Handle #68197.
|
||||||
|
|
||||||
if self.tcx.hir().is_const_context(expr.hir_id) {
|
if self.tcx.hir().is_inside_const_context(expr.hir_id) {
|
||||||
// Do not suggest `Box::new` in const context.
|
// Do not suggest `Box::new` in const context.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,10 +11,6 @@ LL | | }
|
||||||
| |_- in this macro invocation
|
| |_- in this macro invocation
|
||||||
|
|
|
|
||||||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
help: you can convert an `i32` to `isize` and panic if the converted value wouldn't fit
|
|
||||||
|
|
|
||||||
LL | $( $v = $s::V.try_into().unwrap(), )*
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/enum-discr-type-err.rs:18:21
|
--> $DIR/enum-discr-type-err.rs:18:21
|
||||||
|
@ -29,10 +25,6 @@ LL | | }
|
||||||
| |_- in this macro invocation
|
| |_- in this macro invocation
|
||||||
|
|
|
|
||||||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
help: you can convert an `i32` to `isize` and panic if the converted value wouldn't fit
|
|
||||||
|
|
|
||||||
LL | $( $v = $s::V.try_into().unwrap(), )*
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
|
|
@ -3,11 +3,6 @@ error[E0308]: mismatched types
|
||||||
|
|
|
|
||||||
LL | X = Trait::Number,
|
LL | X = Trait::Number,
|
||||||
| ^^^^^^^^^^^^^ expected `isize`, found `i32`
|
| ^^^^^^^^^^^^^ expected `isize`, found `i32`
|
||||||
|
|
|
||||||
help: you can convert an `i32` to `isize` and panic if the converted value wouldn't fit
|
|
||||||
|
|
|
||||||
LL | X = Trait::Number.try_into().unwrap(),
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,11 @@ error[E0308]: mismatched types
|
||||||
|
|
|
|
||||||
LL | const C: i32 = 1i8;
|
LL | const C: i32 = 1i8;
|
||||||
| ^^^ expected `i32`, found `i8`
|
| ^^^ expected `i32`, found `i8`
|
||||||
|
|
|
||||||
|
help: change the type of the numeric literal from `i8` to `i32`
|
||||||
|
|
|
||||||
|
LL | const C: i32 = 1i32;
|
||||||
|
| ^^^^
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/const-scope.rs:2:15
|
--> $DIR/const-scope.rs:2:15
|
||||||
|
@ -17,6 +22,11 @@ LL | let c: i32 = 1i8;
|
||||||
| --- ^^^ expected `i32`, found `i8`
|
| --- ^^^ expected `i32`, found `i8`
|
||||||
| |
|
| |
|
||||||
| expected due to this
|
| expected due to this
|
||||||
|
|
|
||||||
|
help: change the type of the numeric literal from `i8` to `i32`
|
||||||
|
|
|
||||||
|
LL | let c: i32 = 1i32;
|
||||||
|
| ^^^^
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/const-scope.rs:6:17
|
--> $DIR/const-scope.rs:6:17
|
||||||
|
|
|
@ -22,6 +22,9 @@ fn main() {
|
||||||
let f = [0_usize; -1_isize];
|
let f = [0_usize; -1_isize];
|
||||||
//~^ ERROR mismatched types
|
//~^ ERROR mismatched types
|
||||||
//~| expected `usize`, found `isize`
|
//~| expected `usize`, found `isize`
|
||||||
|
let f = [0; 4u8];
|
||||||
|
//~^ ERROR mismatched types
|
||||||
|
//~| expected `usize`, found `u8`
|
||||||
struct G {
|
struct G {
|
||||||
g: (),
|
g: (),
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ LL | let e = [0; "foo"];
|
||||||
| ^^^^^ expected `usize`, found `&str`
|
| ^^^^^ expected `usize`, found `&str`
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/repeat_count.rs:28:17
|
--> $DIR/repeat_count.rs:31:17
|
||||||
|
|
|
|
||||||
LL | let g = [0; G { g: () }];
|
LL | let g = [0; G { g: () }];
|
||||||
| ^^^^^^^^^^^ expected `usize`, found struct `main::G`
|
| ^^^^^^^^^^^ expected `usize`, found struct `main::G`
|
||||||
|
@ -39,24 +39,25 @@ error[E0308]: mismatched types
|
||||||
|
|
|
|
||||||
LL | let f = [0; -4_isize];
|
LL | let f = [0; -4_isize];
|
||||||
| ^^^^^^^^ expected `usize`, found `isize`
|
| ^^^^^^^^ expected `usize`, found `isize`
|
||||||
|
|
|
||||||
help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit
|
|
||||||
|
|
|
||||||
LL | let f = [0; (-4_isize).try_into().unwrap()];
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/repeat_count.rs:22:23
|
--> $DIR/repeat_count.rs:22:23
|
||||||
|
|
|
|
||||||
LL | let f = [0_usize; -1_isize];
|
LL | let f = [0_usize; -1_isize];
|
||||||
| ^^^^^^^^ expected `usize`, found `isize`
|
| ^^^^^^^^ expected `usize`, found `isize`
|
||||||
|
|
|
||||||
help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit
|
|
||||||
|
|
|
||||||
LL | let f = [0_usize; (-1_isize).try_into().unwrap()];
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: aborting due to 8 previous errors
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/repeat_count.rs:25:17
|
||||||
|
|
|
||||||
|
LL | let f = [0; 4u8];
|
||||||
|
| ^^^ expected `usize`, found `u8`
|
||||||
|
|
|
||||||
|
help: change the type of the numeric literal from `u8` to `usize`
|
||||||
|
|
|
||||||
|
LL | let f = [0; 4usize];
|
||||||
|
| ^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 9 previous errors
|
||||||
|
|
||||||
Some errors have detailed explanations: E0308, E0435.
|
Some errors have detailed explanations: E0308, E0435.
|
||||||
For more information about an error, try `rustc --explain E0308`.
|
For more information about an error, try `rustc --explain E0308`.
|
||||||
|
|
Loading…
Add table
Reference in a new issue