suggest const_in_array_repeat_expression
flag
This commit adds a suggestion to add the `#![feature(const_in_array_repeat_expression)]` attribute to the crate when a promotable expression is used in a repeat expression. Signed-off-by: David Wood <david@davidtw.co>
This commit is contained in:
parent
03a50ae9b8
commit
92b151287f
8 changed files with 83 additions and 14 deletions
|
@ -2112,9 +2112,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
err.note(&format!("required by cast to type `{}`",
|
||||
self.ty_to_string(target)));
|
||||
}
|
||||
ObligationCauseCode::RepeatVec => {
|
||||
ObligationCauseCode::RepeatVec(suggest_const_in_array_repeat_expression) => {
|
||||
err.note("the `Copy` trait is required because the \
|
||||
repeated element will be copied");
|
||||
if suggest_const_in_array_repeat_expression {
|
||||
err.note("this array initializer can be evaluated at compile-time, for more \
|
||||
information, see issue \
|
||||
https://github.com/rust-lang/rust/issues/49147");
|
||||
if tcx.sess.opts.unstable_features.is_nightly_build() {
|
||||
err.help("add `#![feature(const_in_array_repeat_expression)]` to the \
|
||||
crate attributes to enable");
|
||||
}
|
||||
}
|
||||
}
|
||||
ObligationCauseCode::VariableType(_) => {
|
||||
err.note("all local variables must have a statically known size");
|
||||
|
|
|
@ -206,8 +206,9 @@ pub enum ObligationCauseCode<'tcx> {
|
|||
SizedReturnType,
|
||||
/// Yield type must be Sized
|
||||
SizedYieldType,
|
||||
/// [T,..n] --> T must be Copy
|
||||
RepeatVec,
|
||||
/// [T,..n] --> T must be Copy. If `true`, suggest `const_in_array_repeat_expression` feature
|
||||
/// flag.
|
||||
RepeatVec(bool),
|
||||
|
||||
/// Types of fields (other than the last, except for packed structs) in a struct must be sized.
|
||||
FieldSized { adt_kind: AdtKind, last: bool },
|
||||
|
|
|
@ -494,7 +494,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
|
|||
super::SizedArgumentType => Some(super::SizedArgumentType),
|
||||
super::SizedReturnType => Some(super::SizedReturnType),
|
||||
super::SizedYieldType => Some(super::SizedYieldType),
|
||||
super::RepeatVec => Some(super::RepeatVec),
|
||||
super::RepeatVec(suggest_flag) => Some(super::RepeatVec(suggest_flag)),
|
||||
super::FieldSized { adt_kind, last } => Some(super::FieldSized { adt_kind, last }),
|
||||
super::ConstSized => Some(super::ConstSized),
|
||||
super::ConstPatternStructural => Some(super::ConstPatternStructural),
|
||||
|
|
|
@ -16,6 +16,7 @@ use crate::borrow_check::nll::type_check::free_region_relations::{
|
|||
};
|
||||
use crate::borrow_check::nll::universal_regions::{DefiningTy, UniversalRegions};
|
||||
use crate::borrow_check::nll::ToRegionVid;
|
||||
use crate::transform::promote_consts::should_suggest_const_in_array_repeat_expressions_attribute;
|
||||
use crate::dataflow::move_paths::MoveData;
|
||||
use crate::dataflow::FlowAtLocation;
|
||||
use crate::dataflow::MaybeInitializedPlaces;
|
||||
|
@ -1983,12 +1984,19 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
let span = body.source_info(location).span;
|
||||
let ty = operand.ty(body, tcx);
|
||||
if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span) {
|
||||
// To determine if `const_in_array_repeat_expression` feature gate should
|
||||
// be mentioned, need to check if the rvalue is promotable.
|
||||
let should_suggest =
|
||||
should_suggest_const_in_array_repeat_expressions_attribute(
|
||||
tcx, self.mir_def_id, body, operand);
|
||||
debug!("check_rvalue: should_suggest={:?}", should_suggest);
|
||||
|
||||
self.infcx.report_selection_error(
|
||||
&traits::Obligation::new(
|
||||
ObligationCause::new(
|
||||
span,
|
||||
self.tcx().hir().def_index_to_hir_id(self.mir_def_id.index),
|
||||
traits::ObligationCauseCode::RepeatVec,
|
||||
traits::ObligationCauseCode::RepeatVec(should_suggest),
|
||||
),
|
||||
self.param_env,
|
||||
ty::Predicate::Trait(ty::Binder::bind(ty::TraitPredicate {
|
||||
|
|
|
@ -1110,3 +1110,28 @@ pub fn promote_candidates<'tcx>(
|
|||
|
||||
promotions
|
||||
}
|
||||
|
||||
/// This function returns `true` if the `const_in_array_repeat_expression` feature attribute should
|
||||
/// be suggested. This function is probably quite expensive, it shouldn't be run in the happy path.
|
||||
/// Feature attribute should be suggested if `operand` can be promoted and the feature is not
|
||||
/// enabled.
|
||||
crate fn should_suggest_const_in_array_repeat_expressions_attribute<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
mir_def_id: DefId,
|
||||
body: &Body<'tcx>,
|
||||
operand: &Operand<'tcx>,
|
||||
) -> bool {
|
||||
let mut rpo = traversal::reverse_postorder(body);
|
||||
let (temps, _) = collect_temps_and_candidates(tcx, body, &mut rpo);
|
||||
let validator = Validator {
|
||||
item: Item::new(tcx, mir_def_id, body),
|
||||
temps: &temps,
|
||||
explicit: false,
|
||||
};
|
||||
|
||||
let should_promote = validator.validate_operand(operand).is_ok();
|
||||
let feature_flag = tcx.features().const_in_array_repeat_expressions;
|
||||
debug!("should_suggest_const_in_array_repeat_expressions_flag: mir_def_id={:?} \
|
||||
should_promote={:?} feature_flag={:?}", mir_def_id, should_promote, feature_flag);
|
||||
should_promote && !feature_flag
|
||||
}
|
||||
|
|
|
@ -878,13 +878,11 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
|
|||
}
|
||||
},
|
||||
ValueSource::Rvalue(&Rvalue::Repeat(ref operand, _)) => {
|
||||
let candidate = Candidate::Repeat(location);
|
||||
let not_promotable = IsNotImplicitlyPromotable::in_operand(self, operand) ||
|
||||
IsNotPromotable::in_operand(self, operand);
|
||||
debug!("assign: self.def_id={:?} operand={:?}", self.def_id, operand);
|
||||
if !not_promotable && self.tcx.features().const_in_array_repeat_expressions {
|
||||
debug!("assign: candidate={:?}", candidate);
|
||||
self.promotion_candidates.push(candidate);
|
||||
debug!("assign: self.cx.mode={:?} self.def_id={:?} location={:?} operand={:?}",
|
||||
self.cx.mode, self.def_id, location, operand);
|
||||
if self.should_promote_repeat_expression(operand) &&
|
||||
self.tcx.features().const_in_array_repeat_expressions {
|
||||
self.promotion_candidates.push(Candidate::Repeat(location));
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
|
@ -1149,6 +1147,15 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
|
|||
|
||||
candidates
|
||||
}
|
||||
|
||||
/// Returns `true` if the operand of a repeat expression is promotable.
|
||||
fn should_promote_repeat_expression(&self, operand: &Operand<'tcx>) -> bool {
|
||||
let not_promotable = IsNotImplicitlyPromotable::in_operand(self, operand) ||
|
||||
IsNotPromotable::in_operand(self, operand);
|
||||
debug!("should_promote_repeat_expression: operand={:?} not_promotable={:?}",
|
||||
operand, not_promotable);
|
||||
!not_promotable
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
|
||||
|
|
|
@ -3,9 +3,16 @@
|
|||
|
||||
struct Bar;
|
||||
|
||||
// This function would compile with the feature gate, and tests that it is suggested.
|
||||
fn foo() {
|
||||
let arr: [Option<String>; 2] = [None::<String>; 2];
|
||||
//~^ ERROR the trait bound `std::option::Option<std::string::String>: std::marker::Copy` is not satisfied [E0277]
|
||||
}
|
||||
|
||||
// This function would not compile with the feature gate, and tests that it is not suggested.
|
||||
fn bar() {
|
||||
let arr: [Option<String>; 2] = [Some("foo".to_string()); 2];
|
||||
//~^ ERROR the trait bound `std::option::Option<std::string::String>: std::marker::Copy` is not satisfied [E0277]
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error[E0277]: the trait bound `std::option::Option<std::string::String>: std::marker::Copy` is not satisfied
|
||||
--> $DIR/feature-gate-const_in_array_repeat_expressions.rs:7:36
|
||||
--> $DIR/feature-gate-const_in_array_repeat_expressions.rs:8:36
|
||||
|
|
||||
LL | let arr: [Option<String>; 2] = [None::<String>; 2];
|
||||
| ^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option<std::string::String>`
|
||||
|
@ -7,7 +7,19 @@ LL | let arr: [Option<String>; 2] = [None::<String>; 2];
|
|||
= help: the following implementations were found:
|
||||
<std::option::Option<T> as std::marker::Copy>
|
||||
= note: the `Copy` trait is required because the repeated element will be copied
|
||||
= note: this array initializer can be evaluated at compile-time, for more information, see issue https://github.com/rust-lang/rust/issues/49147
|
||||
= help: add `#![feature(const_in_array_repeat_expression)]` to the crate attributes to enable
|
||||
|
||||
error: aborting due to previous error
|
||||
error[E0277]: the trait bound `std::option::Option<std::string::String>: std::marker::Copy` is not satisfied
|
||||
--> $DIR/feature-gate-const_in_array_repeat_expressions.rs:14:36
|
||||
|
|
||||
LL | let arr: [Option<String>; 2] = [Some("foo".to_string()); 2];
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option<std::string::String>`
|
||||
|
|
||||
= help: the following implementations were found:
|
||||
<std::option::Option<T> as std::marker::Copy>
|
||||
= note: the `Copy` trait is required because the repeated element will be copied
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
|
|
Loading…
Reference in a new issue