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

On E0277 be clearer about implicit Sized bounds on type params and assoc types #120323

Merged
merged 4 commits into from
Feb 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
14 changes: 11 additions & 3 deletions compiler/rustc_hir_analysis/src/astconv/bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
let tcx = self.tcx();
let sized_def_id = tcx.lang_items().sized_trait();
let mut seen_negative_sized_bound = false;
let mut seen_positive_sized_bound = false;

// Try to find an unbound in bounds.
let mut unbounds: SmallVec<[_; 1]> = SmallVec::new();
Expand All @@ -45,6 +46,13 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
seen_negative_sized_bound = true;
}
}
hir::TraitBoundModifier::None => {
if let Some(sized_def_id) = sized_def_id
&& ptr.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id)
{
seen_positive_sized_bound = true;
}
}
_ => {}
}
}
Expand Down Expand Up @@ -82,11 +90,11 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
);
}

if seen_sized_unbound || seen_negative_sized_bound {
// There was in fact a `?Sized` or `!Sized` bound;
if seen_sized_unbound || seen_negative_sized_bound || seen_positive_sized_bound {
// There was in fact a `?Sized`, `!Sized` or explicit `Sized` bound;
// we don't need to do anything.
} else if sized_def_id.is_some() {
// There was no `?Sized` or `!Sized` bound;
// There was no `?Sized`, `!Sized` or explicit `Sized` bound;
// add `Sized` if it's available.
bounds.push_sized(tcx, self_ty, span);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3009,35 +3009,44 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
);
}
}
let descr = format!("required by a bound in `{item_name}`");
if span.is_visible(sm) {
let msg = format!("required by this bound in `{short_item_name}`");
multispan.push_span_label(span, msg);
err.span_note(multispan, descr);
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 Some(def_id) == tcx.lang_items().sized_trait()
&& let Some(hir::Node::TraitItem(hir::TraitItem {
ident,
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 mut a = "a";
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 Some(def_id) == tcx.lang_items().sized_trait() {
// Check if this is an implicit bound, even in foreign crates.
if tcx
.generics_of(item_def_id)
.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 {
ident,
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(), " +")
Expand All @@ -3051,52 +3060,64 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
Applicability::MachineApplicable,
);
}
if let DefKind::Trait = tcx.def_kind(item_def_id)
&& !visible_item
{
err.note(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())
}
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<_>>();
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()
};
err.help(format!(
"the following type{} implement{} the trait:\n{}{post}",
pluralize!(len),
if len == 1 { "s" } else { "" },
types.join("\n"),
));
}
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"),
));
}
}
};
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}`");
multispan.push_span_label(span, msg);
err.span_note(multispan, descr);
} else {
err.span_note(tcx.def_span(item_def_id), descr);
}
if let Some(note) = note {
err.note(note);
}
if let Some(help) = help {
err.help(help);
}
}
ObligationCauseCode::Coercion { source, target } => {
let mut file = None;
Expand Down
4 changes: 2 additions & 2 deletions tests/incremental/hashes/trait_defs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -559,10 +559,10 @@ trait TraitAddBuiltinBoundToMethodTypeParameter {
#[cfg(not(any(cfail1,cfail4)))]
#[rustc_clean(cfg="cfail2")]
#[rustc_clean(cfg="cfail3")]
#[rustc_clean(cfg="cfail5")]
#[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail5")]
#[rustc_clean(cfg="cfail6")]
trait TraitAddBuiltinBoundToMethodTypeParameter {
#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail2")]
#[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail2")]
#[rustc_clean(cfg="cfail3")]
#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")]
#[rustc_clean(cfg="cfail6")]
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/associated-types/defaults-wf.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ LL | type Ty = Vec<[u8]>;
| ^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `[u8]`
note: required by a bound in `Vec`
note: required by an implicit `Sized` bound in `Vec`
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL

error: aborting due to 1 previous error
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/associated-types/issue-20005.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ error[E0277]: the size for values of type `Self` cannot be known at compilation
LL | ) -> <Dst as From<Self>>::Result where Dst: From<Self> {
| ^^^^^^^^^^ doesn't have a size known at compile-time
|
note: required by a bound in `From`
note: required by an implicit `Sized` bound in `From`
--> $DIR/issue-20005.rs:1:12
|
LL | trait From<Src> {
| ^^^ required by this bound in `From`
| ^^^ required by the implicit `Sized` requirement on this type parameter in `From`
help: consider further restricting `Self`
|
LL | ) -> <Dst as From<Self>>::Result where Dst: From<Self>, Self: Sized {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `Self` cannot be known at compilation
LL | trait ArithmeticOps: Add<Output=Self> + Sub<Output=Self> + Mul<Output=Self> + Div<Output=Self> {}
| ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
note: required by a bound in `Add`
note: required by an implicit `Sized` bound in `Add`
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
help: consider further restricting `Self`
|
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/closures/issue-111932.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ LL | println!("{:?}", foo);
| required by a bound introduced by this call
|
= help: the trait `Sized` is not implemented for `dyn Foo`
note: required by a bound in `core::fmt::rt::Argument::<'a>::new_debug`
note: required by an implicit `Sized` bound in `core::fmt::rt::Argument::<'a>::new_debug`
--> $SRC_DIR/core/src/fmt/rt.rs:LL:COL
= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)

Expand Down
2 changes: 1 addition & 1 deletion tests/ui/coroutine/sized-yield.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ LL | Pin::new(&mut gen).resume(());
| ^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `str`
note: required by a bound in `CoroutineState`
note: required by an implicit `Sized` bound in `CoroutineState`
--> $SRC_DIR/core/src/ops/coroutine.rs:LL:COL

error: aborting due to 2 previous errors
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/dst/dst-sized-trait-param.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ LL | impl Foo<[isize]> for usize { }
| ^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `[isize]`
note: required by a bound in `Foo`
note: required by an implicit `Sized` bound in `Foo`
--> $DIR/dst-sized-trait-param.rs:5:11
|
LL | trait Foo<T> : Sized { fn take(self, x: &T) { } } // Note: T is sized
| ^ required by this bound in `Foo`
| ^ required by the implicit `Sized` requirement on this type parameter in `Foo`
help: consider relaxing the implicit `Sized` restriction
|
LL | trait Foo<T: ?Sized> : Sized { fn take(self, x: &T) { } } // Note: T is sized
Expand Down
16 changes: 8 additions & 8 deletions tests/ui/extern/extern-types-unsized.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ LL | assert_sized::<A>();
| ^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `A`
note: required by a bound in `assert_sized`
note: required by an implicit `Sized` bound in `assert_sized`
--> $DIR/extern-types-unsized.rs:19:17
|
LL | fn assert_sized<T>() {}
| ^ required by this bound in `assert_sized`
| ^ required by the implicit `Sized` requirement on this type parameter in `assert_sized`
help: consider relaxing the implicit `Sized` restriction
|
LL | fn assert_sized<T: ?Sized>() {}
Expand All @@ -27,11 +27,11 @@ note: required because it appears within the type `Foo`
|
LL | struct Foo {
| ^^^
note: required by a bound in `assert_sized`
note: required by an implicit `Sized` bound in `assert_sized`
--> $DIR/extern-types-unsized.rs:19:17
|
LL | fn assert_sized<T>() {}
| ^ required by this bound in `assert_sized`
| ^ required by the implicit `Sized` requirement on this type parameter in `assert_sized`
help: consider relaxing the implicit `Sized` restriction
|
LL | fn assert_sized<T: ?Sized>() {}
Expand All @@ -49,11 +49,11 @@ note: required because it appears within the type `Bar<A>`
|
LL | struct Bar<T: ?Sized> {
| ^^^
note: required by a bound in `assert_sized`
note: required by an implicit `Sized` bound in `assert_sized`
--> $DIR/extern-types-unsized.rs:19:17
|
LL | fn assert_sized<T>() {}
| ^ required by this bound in `assert_sized`
| ^ required by the implicit `Sized` requirement on this type parameter in `assert_sized`
help: consider relaxing the implicit `Sized` restriction
|
LL | fn assert_sized<T: ?Sized>() {}
Expand All @@ -71,11 +71,11 @@ note: required because it appears within the type `Bar<A>`
|
LL | struct Bar<T: ?Sized> {
| ^^^
note: required by a bound in `assert_sized`
note: required by an implicit `Sized` bound in `assert_sized`
--> $DIR/extern-types-unsized.rs:19:17
|
LL | fn assert_sized<T>() {}
| ^ required by this bound in `assert_sized`
| ^ required by the implicit `Sized` requirement on this type parameter in `assert_sized`
help: consider relaxing the implicit `Sized` restriction
|
LL | fn assert_sized<T: ?Sized>() {}
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/generic-associated-types/issue-88287.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ LL | type SearchFutureTy<'f, A, B: 'f>
LL | async move { todo!() }
| ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
note: required by a bound in `<T as SearchableResourceExt<Criteria>>`
note: required by an implicit `Sized` bound in `<T as SearchableResourceExt<Criteria>>`
--> $DIR/issue-88287.rs:24:6
|
LL | impl<T, Criteria> SearchableResourceExt<Criteria> for T
| ^ required by this bound in `<T as SearchableResourceExt<Criteria>>`
| ^ required by the implicit `Sized` requirement on this type parameter in `<T as SearchableResourceExt<Criteria>>`
help: consider removing the `?Sized` bound to make the type parameter `Sized`
|
LL - A: SearchableResource<B> + ?Sized + 'f,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ LL | impl Tsized for () {}
|
= help: the trait `Sized` is not implemented for `[()]`
note: required by a bound in `Tsized`
--> $DIR/issue-61631-default-type-param-can-reference-self-in-trait.rs:17:14
--> $DIR/issue-61631-default-type-param-can-reference-self-in-trait.rs:17:17
|
LL | trait Tsized<P: Sized = [Self]> {}
| ^^^^^^^^^^^^^^^^^ required by this bound in `Tsized`
| ^^^^^ required by this bound in `Tsized`

error: aborting due to 1 previous error

Expand Down
Loading
Loading