Rollup merge of #91443 - compiler-errors:bad_collect_into_slice, r=wesleywiser
Better suggestions when user tries to collect into an unsized `[_]` 1. Extend the predicate on `rustc_on_unimplemented` to support substitutions like note, label, etc (i.e. treat it as a `OnUnimplementedFormatString`) so we can have slightly more general `rustc_on_unimplemented` special-cases. 2. Add a `rustc_on_unimplemented` if we fail on `FromIterator<A> for [A]` which happens when we don't explicitly collect into a `vec<A>`, but then pass the return from a `.collect` call into something that takes a slice. Fixes #91423
This commit is contained in:
commit
9634559599
5 changed files with 106 additions and 12 deletions
|
@ -668,6 +668,7 @@ symbols! {
|
||||||
fill,
|
fill,
|
||||||
finish,
|
finish,
|
||||||
flags,
|
flags,
|
||||||
|
float,
|
||||||
float_to_int_unchecked,
|
float_to_int_unchecked,
|
||||||
floorf32,
|
floorf32,
|
||||||
floorf64,
|
floorf64,
|
||||||
|
@ -771,6 +772,8 @@ symbols! {
|
||||||
inline_const_pat,
|
inline_const_pat,
|
||||||
inout,
|
inout,
|
||||||
instruction_set,
|
instruction_set,
|
||||||
|
integer_: "integer",
|
||||||
|
integral,
|
||||||
intel,
|
intel,
|
||||||
into_future,
|
into_future,
|
||||||
into_iter,
|
into_iter,
|
||||||
|
|
|
@ -62,6 +62,10 @@ impl<'tcx> OnUnimplementedDirective {
|
||||||
let mut errored = false;
|
let mut errored = false;
|
||||||
let mut item_iter = items.iter();
|
let mut item_iter = items.iter();
|
||||||
|
|
||||||
|
let parse_value = |value_str| {
|
||||||
|
OnUnimplementedFormatString::try_parse(tcx, trait_def_id, value_str, span).map(Some)
|
||||||
|
};
|
||||||
|
|
||||||
let condition = if is_root {
|
let condition = if is_root {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
|
@ -86,7 +90,14 @@ impl<'tcx> OnUnimplementedDirective {
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
attr::eval_condition(cond, &tcx.sess.parse_sess, Some(tcx.features()), &mut |_| true);
|
attr::eval_condition(cond, &tcx.sess.parse_sess, Some(tcx.features()), &mut |item| {
|
||||||
|
if let Some(symbol) = item.value_str() {
|
||||||
|
if parse_value(symbol).is_err() {
|
||||||
|
errored = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
});
|
||||||
Some(cond.clone())
|
Some(cond.clone())
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -97,10 +108,6 @@ impl<'tcx> OnUnimplementedDirective {
|
||||||
let mut subcommands = vec![];
|
let mut subcommands = vec![];
|
||||||
let mut append_const_msg = None;
|
let mut append_const_msg = None;
|
||||||
|
|
||||||
let parse_value = |value_str| {
|
|
||||||
OnUnimplementedFormatString::try_parse(tcx, trait_def_id, value_str, span).map(Some)
|
|
||||||
};
|
|
||||||
|
|
||||||
for item in item_iter {
|
for item in item_iter {
|
||||||
if item.has_name(sym::message) && message.is_none() {
|
if item.has_name(sym::message) && message.is_none() {
|
||||||
if let Some(message_) = item.value_str() {
|
if let Some(message_) = item.value_str() {
|
||||||
|
@ -221,6 +228,9 @@ impl<'tcx> OnUnimplementedDirective {
|
||||||
let mut append_const_msg = None;
|
let mut append_const_msg = None;
|
||||||
info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options);
|
info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options);
|
||||||
|
|
||||||
|
let options_map: FxHashMap<Symbol, String> =
|
||||||
|
options.iter().filter_map(|(k, v)| v.as_ref().map(|v| (*k, v.to_owned()))).collect();
|
||||||
|
|
||||||
for command in self.subcommands.iter().chain(Some(self)).rev() {
|
for command in self.subcommands.iter().chain(Some(self)).rev() {
|
||||||
if let Some(ref condition) = command.condition {
|
if let Some(ref condition) = command.condition {
|
||||||
if !attr::eval_condition(
|
if !attr::eval_condition(
|
||||||
|
@ -229,7 +239,11 @@ impl<'tcx> OnUnimplementedDirective {
|
||||||
Some(tcx.features()),
|
Some(tcx.features()),
|
||||||
&mut |c| {
|
&mut |c| {
|
||||||
c.ident().map_or(false, |ident| {
|
c.ident().map_or(false, |ident| {
|
||||||
options.contains(&(ident.name, c.value_str().map(|s| s.to_string())))
|
let value = c.value_str().map(|s| {
|
||||||
|
OnUnimplementedFormatString(s).format(tcx, trait_ref, &options_map)
|
||||||
|
});
|
||||||
|
|
||||||
|
options.contains(&(ident.name, value))
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
|
@ -257,13 +271,11 @@ impl<'tcx> OnUnimplementedDirective {
|
||||||
append_const_msg = command.append_const_msg.clone();
|
append_const_msg = command.append_const_msg.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
let options: FxHashMap<Symbol, String> =
|
|
||||||
options.iter().filter_map(|(k, v)| v.as_ref().map(|v| (*k, v.to_owned()))).collect();
|
|
||||||
OnUnimplementedNote {
|
OnUnimplementedNote {
|
||||||
label: label.map(|l| l.format(tcx, trait_ref, &options)),
|
label: label.map(|l| l.format(tcx, trait_ref, &options_map)),
|
||||||
message: message.map(|m| m.format(tcx, trait_ref, &options)),
|
message: message.map(|m| m.format(tcx, trait_ref, &options_map)),
|
||||||
note: note.map(|n| n.format(tcx, trait_ref, &options)),
|
note: note.map(|n| n.format(tcx, trait_ref, &options_map)),
|
||||||
enclosing_scope: enclosing_scope.map(|e_s| e_s.format(tcx, trait_ref, &options)),
|
enclosing_scope: enclosing_scope.map(|e_s| e_s.format(tcx, trait_ref, &options_map)),
|
||||||
append_const_msg,
|
append_const_msg,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -306,6 +318,12 @@ impl<'tcx> OnUnimplementedFormatString {
|
||||||
Position::ArgumentNamed(s) if s == sym::from_desugaring => (),
|
Position::ArgumentNamed(s) if s == sym::from_desugaring => (),
|
||||||
// `{ItemContext}` is allowed
|
// `{ItemContext}` is allowed
|
||||||
Position::ArgumentNamed(s) if s == sym::ItemContext => (),
|
Position::ArgumentNamed(s) if s == sym::ItemContext => (),
|
||||||
|
// `{integral}` and `{integer}` and `{float}` are allowed
|
||||||
|
Position::ArgumentNamed(s)
|
||||||
|
if s == sym::integral || s == sym::integer_ || s == sym::float =>
|
||||||
|
{
|
||||||
|
()
|
||||||
|
}
|
||||||
// So is `{A}` if A is a type parameter
|
// So is `{A}` if A is a type parameter
|
||||||
Position::ArgumentNamed(s) => {
|
Position::ArgumentNamed(s) => {
|
||||||
match generics.params.iter().find(|param| param.name == s) {
|
match generics.params.iter().find(|param| param.name == s) {
|
||||||
|
@ -385,6 +403,12 @@ impl<'tcx> OnUnimplementedFormatString {
|
||||||
&empty_string
|
&empty_string
|
||||||
} else if s == sym::ItemContext {
|
} else if s == sym::ItemContext {
|
||||||
&item_context
|
&item_context
|
||||||
|
} else if s == sym::integral {
|
||||||
|
"{integral}"
|
||||||
|
} else if s == sym::integer_ {
|
||||||
|
"{integer}"
|
||||||
|
} else if s == sym::float {
|
||||||
|
"{float}"
|
||||||
} else {
|
} else {
|
||||||
bug!(
|
bug!(
|
||||||
"broken on_unimplemented {:?} for {:?}: \
|
"broken on_unimplemented {:?} for {:?}: \
|
||||||
|
|
|
@ -81,6 +81,32 @@
|
||||||
/// ```
|
/// ```
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[rustc_on_unimplemented(
|
#[rustc_on_unimplemented(
|
||||||
|
on(
|
||||||
|
_Self = "[{A}]",
|
||||||
|
message = "a value of type `{Self}` cannot be built since `{Self}` has no definite size",
|
||||||
|
label = "try explicitly collecting into a `Vec<{A}>`",
|
||||||
|
),
|
||||||
|
on(
|
||||||
|
all(
|
||||||
|
A = "{integer}",
|
||||||
|
any(
|
||||||
|
_Self = "[i8]",
|
||||||
|
_Self = "[i16]",
|
||||||
|
_Self = "[i32]",
|
||||||
|
_Self = "[i64]",
|
||||||
|
_Self = "[i128]",
|
||||||
|
_Self = "[isize]",
|
||||||
|
_Self = "[u8]",
|
||||||
|
_Self = "[u16]",
|
||||||
|
_Self = "[u32]",
|
||||||
|
_Self = "[u64]",
|
||||||
|
_Self = "[u128]",
|
||||||
|
_Self = "[usize]"
|
||||||
|
)
|
||||||
|
),
|
||||||
|
message = "a value of type `{Self}` cannot be built since `{Self}` has no definite size",
|
||||||
|
label = "try explicitly collecting into a `Vec<{A}>`",
|
||||||
|
),
|
||||||
message = "a value of type `{Self}` cannot be built from an iterator \
|
message = "a value of type `{Self}` cannot be built from an iterator \
|
||||||
over elements of type `{A}`",
|
over elements of type `{A}`",
|
||||||
label = "value of type `{Self}` cannot be built from `std::iter::Iterator<Item={A}>`"
|
label = "value of type `{Self}` cannot be built from `std::iter::Iterator<Item={A}>`"
|
||||||
|
|
15
src/test/ui/iterators/collect-into-slice.rs
Normal file
15
src/test/ui/iterators/collect-into-slice.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
fn process_slice(data: &[i32]) {
|
||||||
|
//~^ NOTE required by a bound in this
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let some_generated_vec = (0..10).collect();
|
||||||
|
//~^ ERROR the size for values of type `[i32]` cannot be known at compilation time
|
||||||
|
//~| ERROR a value of type `[i32]` cannot be built since `[i32]` has no definite size
|
||||||
|
//~| NOTE try explicitly collecting into a `Vec<{integer}>`
|
||||||
|
//~| NOTE required by a bound in `collect`
|
||||||
|
//~| NOTE all local variables must have a statically known size
|
||||||
|
//~| NOTE doesn't have a size known at compile-time
|
||||||
|
process_slice(&some_generated_vec);
|
||||||
|
}
|
26
src/test/ui/iterators/collect-into-slice.stderr
Normal file
26
src/test/ui/iterators/collect-into-slice.stderr
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
error[E0277]: the size for values of type `[i32]` cannot be known at compilation time
|
||||||
|
--> $DIR/collect-into-slice.rs:7:9
|
||||||
|
|
|
||||||
|
LL | let some_generated_vec = (0..10).collect();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||||
|
|
|
||||||
|
= help: the trait `Sized` is not implemented for `[i32]`
|
||||||
|
= note: all local variables must have a statically known size
|
||||||
|
= help: unsized locals are gated as an unstable feature
|
||||||
|
|
||||||
|
error[E0277]: a value of type `[i32]` cannot be built since `[i32]` has no definite size
|
||||||
|
--> $DIR/collect-into-slice.rs:7:38
|
||||||
|
|
|
||||||
|
LL | let some_generated_vec = (0..10).collect();
|
||||||
|
| ^^^^^^^ try explicitly collecting into a `Vec<{integer}>`
|
||||||
|
|
|
||||||
|
= help: the trait `FromIterator<{integer}>` is not implemented for `[i32]`
|
||||||
|
note: required by a bound in `collect`
|
||||||
|
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
|
||||||
|
|
|
||||||
|
LL | fn collect<B: FromIterator<Self::Item>>(self) -> B
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `collect`
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0277`.
|
Loading…
Add table
Add a link
Reference in a new issue