Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Const generic parameters aren't bounds, even if we end up erroring be…
…cause of the bound that binds the parameter's type
  • Loading branch information
oli-obk committed Jun 19, 2024
commit e4c9a8cf9b2e2a17c589dadcaffae0b9e6b62cbc
188 changes: 103 additions & 85 deletions compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2776,97 +2776,115 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
let mut this = "this bound";
let mut note = None;
let mut help = None;
if let ty::PredicateKind::Clause(clause) = predicate.kind().skip_binder()
&& let ty::ClauseKind::Trait(trait_pred) = clause
{
let def_id = trait_pred.def_id();
let visible_item = if let Some(local) = def_id.as_local() {
// Check for local traits being reachable.
let vis = &tcx.resolutions(()).effective_visibilities;
// Account for non-`pub` traits in the root of the local crate.
let is_locally_reachable = tcx.parent(def_id).is_crate_root();
vis.is_reachable(local) || is_locally_reachable
} else {
// Check for foreign traits being reachable.
tcx.visible_parent_map(()).get(&def_id).is_some()
};
if tcx.is_lang_item(def_id, LangItem::Sized) {
// Check if this is an implicit bound, even in foreign crates.
if tcx
.generics_of(item_def_id)
.own_params
.iter()
.any(|param| tcx.def_span(param.def_id) == span)
{
a = "an implicit `Sized`";
this = "the implicit `Sized` requirement on this type parameter";
}
if let Some(hir::Node::TraitItem(hir::TraitItem {
generics,
kind: hir::TraitItemKind::Type(bounds, None),
..
})) = tcx.hir().get_if_local(item_def_id)
// Do not suggest relaxing if there is an explicit `Sized` obligation.
&& !bounds.iter()
.filter_map(|bound| bound.trait_ref())
.any(|tr| tr.trait_def_id() == tcx.lang_items().sized_trait())
{
let (span, separator) = if let [.., last] = bounds {
(last.span().shrink_to_hi(), " +")
if let ty::PredicateKind::Clause(clause) = predicate.kind().skip_binder() {
match clause {
ty::ClauseKind::Trait(trait_pred) => {
let def_id = trait_pred.def_id();
let visible_item = if let Some(local) = def_id.as_local() {
// Check for local traits being reachable.
let vis = &tcx.resolutions(()).effective_visibilities;
// Account for non-`pub` traits in the root of the local crate.
let is_locally_reachable = tcx.parent(def_id).is_crate_root();
vis.is_reachable(local) || is_locally_reachable
} else {
(generics.span.shrink_to_hi(), ":")
// Check for foreign traits being reachable.
tcx.visible_parent_map(()).get(&def_id).is_some()
};
err.span_suggestion_verbose(
span,
"consider relaxing the implicit `Sized` restriction",
format!("{separator} ?Sized"),
Applicability::MachineApplicable,
);
if tcx.is_lang_item(def_id, LangItem::Sized) {
// Check if this is an implicit bound, even in foreign crates.
if tcx
.generics_of(item_def_id)
.own_params
.iter()
.any(|param| tcx.def_span(param.def_id) == span)
{
a = "an implicit `Sized`";
this =
"the implicit `Sized` requirement on this type parameter";
}
if let Some(hir::Node::TraitItem(hir::TraitItem {
generics,
kind: hir::TraitItemKind::Type(bounds, None),
..
})) = tcx.hir().get_if_local(item_def_id)
// Do not suggest relaxing if there is an explicit `Sized` obligation.
&& !bounds.iter()
.filter_map(|bound| bound.trait_ref())
.any(|tr| tr.trait_def_id() == tcx.lang_items().sized_trait())
{
let (span, separator) = if let [.., last] = bounds {
(last.span().shrink_to_hi(), " +")
} else {
(generics.span.shrink_to_hi(), ":")
};
err.span_suggestion_verbose(
span,
"consider relaxing the implicit `Sized` restriction",
format!("{separator} ?Sized"),
Applicability::MachineApplicable,
);
}
}
if let DefKind::Trait = tcx.def_kind(item_def_id)
&& !visible_item
{
note = Some(format!(
"`{short_item_name}` is a \"sealed trait\", because to implement it \
you also need to implement `{}`, which is not accessible; this is \
usually done to force you to use one of the provided types that \
already implement it",
with_no_trimmed_paths!(tcx.def_path_str(def_id)),
));
let impls_of = tcx.trait_impls_of(def_id);
let impls = impls_of
.non_blanket_impls()
.values()
.flatten()
.chain(impls_of.blanket_impls().iter())
.collect::<Vec<_>>();
if !impls.is_empty() {
let len = impls.len();
let mut types = impls
.iter()
.map(|t| {
with_no_trimmed_paths!(format!(
" {}",
tcx.type_of(*t).instantiate_identity(),
))
})
.collect::<Vec<_>>();
let post = if types.len() > 9 {
types.truncate(8);
format!("\nand {} others", len - 8)
} else {
String::new()
};
help = Some(format!(
"the following type{} implement{} the trait:\n{}{post}",
pluralize!(len),
if len == 1 { "s" } else { "" },
types.join("\n"),
));
}
}
}
}
if let DefKind::Trait = tcx.def_kind(item_def_id)
&& !visible_item
{
note = Some(format!(
"`{short_item_name}` is a \"sealed trait\", because to implement it \
you also need to implement `{}`, which is not accessible; this is \
usually done to force you to use one of the provided types that \
already implement it",
with_no_trimmed_paths!(tcx.def_path_str(def_id)),
));
let impls_of = tcx.trait_impls_of(def_id);
let impls = impls_of
.non_blanket_impls()
.values()
.flatten()
.chain(impls_of.blanket_impls().iter())
.collect::<Vec<_>>();
if !impls.is_empty() {
let len = impls.len();
let mut types = impls
.iter()
.map(|t| {
with_no_trimmed_paths!(format!(
" {}",
tcx.type_of(*t).instantiate_identity(),
))
})
.collect::<Vec<_>>();
let post = if types.len() > 9 {
types.truncate(8);
format!("\nand {} others", len - 8)
ty::ClauseKind::ConstArgHasType(..) => {
let descr =
format!("required by a const generic parameter in `{item_name}`");
if span.is_visible(sm) {
let msg = format!(
"required by this const generic parameter in `{short_item_name}`"
);
multispan.push_span_label(span, msg);
err.span_note(multispan, descr);
} else {
String::new()
};
help = Some(format!(
"the following type{} implement{} the trait:\n{}{post}",
pluralize!(len),
if len == 1 { "s" } else { "" },
types.join("\n"),
));
err.span_note(tcx.def_span(item_def_id), descr);
}
return;
}
_ => (),
}
};
}
let descr = format!("required by {a} bound in `{item_name}`");
if span.is_visible(sm) {
let msg = format!("required by {this} in `{short_item_name}`");
Expand Down
8 changes: 4 additions & 4 deletions tests/ui/const-generics/defaults/doesnt_infer.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ error[E0284]: type annotations needed for `Foo<_>`
LL | let foo = Foo::foo();
| ^^^ ---------- type must be known at this point
|
note: required by a bound in `Foo::<N>::foo`
note: required by a const generic parameter in `Foo::<N>::foo`
--> $DIR/doesnt_infer.rs:5:6
|
LL | impl<const N: u32> Foo<N> {
| ^^^^^^^^^^^^ required by this bound in `Foo::<N>::foo`
| ^^^^^^^^^^^^ required by this const generic parameter in `Foo::<N>::foo`
LL | fn foo() -> Self {
| --- required by a bound in this associated function
help: consider giving `foo` an explicit type, where the value of const parameter `N` is specified
Expand All @@ -22,11 +22,11 @@ error[E0284]: type annotations needed for `Foo<_>`
LL | let foo = Foo::foo();
| ^^^ --- type must be known at this point
|
note: required by a bound in `Foo`
note: required by a const generic parameter in `Foo`
--> $DIR/doesnt_infer.rs:3:12
|
LL | struct Foo<const N: u32 = 2>;
| ^^^^^^^^^^^^^^^^ required by this bound in `Foo`
| ^^^^^^^^^^^^^^^^ required by this const generic parameter in `Foo`
help: consider giving `foo` an explicit type, where the value of const parameter `N` is specified
|
LL | let foo: Foo<N> = Foo::foo();
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/const-generics/defaults/rp_impl_trait_fail.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@ error[E0284]: type annotations needed
LL | uwu();
| ^^^ cannot infer the value of the const parameter `N` declared on the function `uwu`
|
note: required by a bound in `uwu`
note: required by a const generic parameter in `uwu`
--> $DIR/rp_impl_trait_fail.rs:16:8
|
LL | fn uwu<const N: u8>() -> impl Traitor<N> {
| ^^^^^^^^^^^ required by this bound in `uwu`
| ^^^^^^^^^^^ required by this const generic parameter in `uwu`
help: consider specifying the generic argument
|
LL | uwu::<N>();
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/const-generics/generic_arg_infer/issue-91614.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ error[E0284]: type annotations needed for `Mask<_, _>`
LL | let y = Mask::<_, _>::splat(false);
| ^ -------------------------- type must be known at this point
|
note: required by a bound in `Mask::<T, N>::splat`
note: required by a const generic parameter in `Mask::<T, N>::splat`
--> $SRC_DIR/core/src/../../portable-simd/crates/core_simd/src/masks.rs:LL:COL
help: consider giving `y` an explicit type, where the value of const parameter `N` is specified
|
Expand All @@ -17,7 +17,7 @@ error[E0284]: type annotations needed for `Mask<_, _>`
LL | let y = Mask::<_, _>::splat(false);
| ^ ------------ type must be known at this point
|
note: required by a bound in `Mask`
note: required by a const generic parameter in `Mask`
--> $SRC_DIR/core/src/../../portable-simd/crates/core_simd/src/masks.rs:LL:COL
help: consider giving `y` an explicit type, where the value of const parameter `N` is specified
|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ error[E0284]: type annotations needed for `ArrayHolder<_>`
LL | let mut array = ArrayHolder::new();
| ^^^^^^^^^ ------------------ type must be known at this point
|
note: required by a bound in `ArrayHolder::<X>::new`
note: required by a const generic parameter in `ArrayHolder::<X>::new`
--> $DIR/issue-62504.rs:16:6
|
LL | impl<const X: usize> ArrayHolder<X> {
| ^^^^^^^^^^^^^^ required by this bound in `ArrayHolder::<X>::new`
| ^^^^^^^^^^^^^^ required by this const generic parameter in `ArrayHolder::<X>::new`
LL | pub const fn new() -> Self {
| --- required by a bound in this associated function
help: consider giving `array` an explicit type, where the value of const parameter `X` is specified
Expand All @@ -42,11 +42,11 @@ error[E0284]: type annotations needed for `ArrayHolder<_>`
LL | let mut array = ArrayHolder::new();
| ^^^^^^^^^ ----------- type must be known at this point
|
note: required by a bound in `ArrayHolder`
note: required by a const generic parameter in `ArrayHolder`
--> $DIR/issue-62504.rs:14:20
|
LL | struct ArrayHolder<const X: usize>([u32; X]);
| ^^^^^^^^^^^^^^ required by this bound in `ArrayHolder`
| ^^^^^^^^^^^^^^ required by this const generic parameter in `ArrayHolder`
help: consider giving `array` an explicit type, where the value of const parameter `X` is specified
|
LL | let mut array: ArrayHolder<X> = ArrayHolder::new();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ error[E0284]: type annotations needed for `ArrayHolder<_>`
LL | let mut array = ArrayHolder::new();
| ^^^^^^^^^ ------------------ type must be known at this point
|
note: required by a bound in `ArrayHolder::<X>::new`
note: required by a const generic parameter in `ArrayHolder::<X>::new`
--> $DIR/issue-62504.rs:16:6
|
LL | impl<const X: usize> ArrayHolder<X> {
| ^^^^^^^^^^^^^^ required by this bound in `ArrayHolder::<X>::new`
| ^^^^^^^^^^^^^^ required by this const generic parameter in `ArrayHolder::<X>::new`
LL | pub const fn new() -> Self {
| --- required by a bound in this associated function
help: consider giving `array` an explicit type, where the value of const parameter `X` is specified
Expand All @@ -46,11 +46,11 @@ error[E0284]: type annotations needed for `ArrayHolder<_>`
LL | let mut array = ArrayHolder::new();
| ^^^^^^^^^ ----------- type must be known at this point
|
note: required by a bound in `ArrayHolder`
note: required by a const generic parameter in `ArrayHolder`
--> $DIR/issue-62504.rs:14:20
|
LL | struct ArrayHolder<const X: usize>([u32; X]);
| ^^^^^^^^^^^^^^ required by this bound in `ArrayHolder`
| ^^^^^^^^^^^^^^ required by this const generic parameter in `ArrayHolder`
help: consider giving `array` an explicit type, where the value of const parameter `X` is specified
|
LL | let mut array: ArrayHolder<X> = ArrayHolder::new();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ error[E0284]: type annotations needed
LL | use_dyn(&());
| ^^^^^^^ cannot infer the value of the const parameter `N` declared on the function `use_dyn`
|
note: required by a bound in `use_dyn`
note: required by a const generic parameter in `use_dyn`
--> $DIR/object-safety-ok-infer-err.rs:14:12
|
LL | fn use_dyn<const N: usize>(v: &dyn Foo<N>) where [u8; N + 1]: Sized {
| ^^^^^^^^^^^^^^ required by this bound in `use_dyn`
| ^^^^^^^^^^^^^^ required by this const generic parameter in `use_dyn`
help: consider specifying the generic argument
|
LL | use_dyn::<N>(&());
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/const-generics/infer/cannot-infer-const-args.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ error[E0284]: type annotations needed
LL | foo();
| ^^^ cannot infer the value of the const parameter `X` declared on the function `foo`
|
note: required by a bound in `foo`
note: required by a const generic parameter in `foo`
--> $DIR/cannot-infer-const-args.rs:1:8
|
LL | fn foo<const X: usize>() -> usize {
| ^^^^^^^^^^^^^^ required by this bound in `foo`
| ^^^^^^^^^^^^^^ required by this const generic parameter in `foo`
help: consider specifying the generic argument
|
LL | foo::<X>();
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/const-generics/infer/issue-77092.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ error[E0284]: type annotations needed
LL | println!("{:?}", take_array_from_mut(&mut arr, i));
| ^^^^^^^^^^^^^^^^^^^ cannot infer the value of the const parameter `N` declared on the function `take_array_from_mut`
|
note: required by a bound in `take_array_from_mut`
note: required by a const generic parameter in `take_array_from_mut`
--> $DIR/issue-77092.rs:3:27
|
LL | fn take_array_from_mut<T, const N: usize>(data: &mut [T], start: usize) -> &mut [T; N] {
| ^^^^^^^^^^^^^^ required by this bound in `take_array_from_mut`
| ^^^^^^^^^^^^^^ required by this const generic parameter in `take_array_from_mut`
help: consider specifying the generic arguments
|
LL | println!("{:?}", take_array_from_mut::<i32, N>(&mut arr, i));
Expand Down
Loading