From 06a72d2ba60c0e179a7724dcb470d2af70c84850 Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Fri, 8 Mar 2024 19:37:16 +0100 Subject: [PATCH 1/7] clean up fulfillment error reporting --- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 19 ++- .../error_reporting/type_err_ctxt_ext.rs | 117 +++++++++--------- 2 files changed, 70 insertions(+), 66 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index dd44fdd889328..488a505531da2 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -589,11 +589,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, mutate_fulfillment_errors: impl Fn(&mut Vec>), ) { - let mut result = self.fulfillment_cx.borrow_mut().select_where_possible(self); - if !result.is_empty() { - mutate_fulfillment_errors(&mut result); - self.adjust_fulfillment_errors_for_expr_obligation(&mut result); - self.err_ctxt().report_fulfillment_errors(result); + let mut errors = self.fulfillment_cx.borrow_mut().select_where_possible(self); + if !errors.is_empty() { + mutate_fulfillment_errors(&mut errors); + if errors.is_empty() { + // We sometimes skip reporting fulfillment errors while constructing + // a different error. + self.dcx().span_delayed_bug( + self.tcx.def_span(self.body_id), + "skipped reporting fulfillment errors", + ); + return; + } + self.adjust_fulfillment_errors_for_expr_obligation(&mut errors); + self.err_ctxt().report_fulfillment_errors(errors); } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 4bc3ff92a6751..5eff413b886aa 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -80,14 +80,28 @@ pub fn suggest_new_overflow_limit<'tcx, G: EmissionGuarantee>( #[extension(pub trait TypeErrCtxtExt<'tcx>)] impl<'tcx> TypeErrCtxt<'_, 'tcx> { + #[instrument(skip(self), level = "debug")] fn report_fulfillment_errors( &self, mut errors: Vec>, ) -> ErrorGuaranteed { + if errors.is_empty() { + bug!("attempted to report fulfillment errors, but there we no errors"); + } + self.sub_relations .borrow_mut() .add_constraints(self, errors.iter().map(|e| e.obligation.predicate)); + let mut reported = None; + + // We want to ignore desugarings when filtering errors: spans are equivalent even + // if one is the result of a desugaring and the other is not. + let strip_desugaring = |span: Span| { + let expn_data = span.ctxt().outer_expn_data(); + if let ExpnKind::Desugaring(_) = expn_data.kind { expn_data.call_site } else { span } + }; + #[derive(Debug)] struct ErrorDescriptor<'tcx> { predicate: ty::Predicate<'tcx>, @@ -98,40 +112,32 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { .reported_trait_errors .borrow() .iter() - .map(|(&span, predicates)| { - ( - span, - predicates - .0 - .iter() - .map(|&predicate| ErrorDescriptor { predicate, index: None }) - .collect(), - ) + .map(|(&span, &(ref predicates, guar))| { + reported = Some(guar); + let span = strip_desugaring(span); + let reported_errors = predicates + .iter() + .map(|&predicate| ErrorDescriptor { predicate, index: None }) + .collect(); + (span, reported_errors) }) .collect(); // Ensure `T: Sized` and `T: WF` obligations come last. This lets us display diagnostics - // with more relevant type information and hide redundant E0282 errors. + // with more relevant type information and hide redundant E0282 ("type annotations needed") errors. errors.sort_by_key(|e| match e.obligation.predicate.kind().skip_binder() { ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) if Some(pred.def_id()) == self.tcx.lang_items().sized_trait() => { 1 } - ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => 3, ty::PredicateKind::Coerce(_) => 2, + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => 3, _ => 0, }); for (index, error) in errors.iter().enumerate() { - // We want to ignore desugarings here: spans are equivalent even - // if one is the result of a desugaring and the other is not. - let mut span = error.obligation.cause.span; - let expn_data = span.ctxt().outer_expn_data(); - if let ExpnKind::Desugaring(_) = expn_data.kind { - span = expn_data.call_site; - } - + let span = strip_desugaring(error.obligation.cause.span); error_map.entry(span).or_default().push(ErrorDescriptor { predicate: error.obligation.predicate, index: Some(index), @@ -144,59 +150,48 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { for (_, error_set) in error_map.iter() { // We want to suppress "duplicate" errors with the same span. for error in error_set { - if let Some(index) = error.index { - // Suppress errors that are either: - // 1) strictly implied by another error. - // 2) implied by an error with a smaller index. - for error2 in error_set { - if error2.index.is_some_and(|index2| is_suppressed[index2]) { - // Avoid errors being suppressed by already-suppressed - // errors, to prevent all errors from being suppressed - // at once. - continue; - } + let Some(index) = error.index else { + continue; + }; - if self.error_implies(error2.predicate, error.predicate) - && !(error2.index >= error.index - && self.error_implies(error.predicate, error2.predicate)) - { - info!("skipping {:?} (implied by {:?})", error, error2); - is_suppressed[index] = true; - break; - } + // Suppress errors that are either: + // 1) strictly implied by another error. + // 2) implied by an error with a smaller index. + for error2 in error_set { + if self.error_implies(error2.predicate, error.predicate) + && (!error2.index.is_some_and(|index2| index2 >= index) + || !self.error_implies(error.predicate, error2.predicate)) + { + info!("skipping `{}` (implied by `{}`)", error.predicate, error2.predicate); + is_suppressed[index] = true; + break; } } } } - let mut reported = None; - for from_expansion in [false, true] { - for (error, suppressed) in iter::zip(&errors, &is_suppressed) { - if !suppressed && error.obligation.cause.span.from_expansion() == from_expansion { - let guar = self.report_fulfillment_error(error); - reported = Some(guar); - // We want to ignore desugarings here: spans are equivalent even - // if one is the result of a desugaring and the other is not. - let mut span = error.obligation.cause.span; - let expn_data = span.ctxt().outer_expn_data(); - if let ExpnKind::Desugaring(_) = expn_data.kind { - span = expn_data.call_site; - } - self.reported_trait_errors - .borrow_mut() - .entry(span) - .or_insert_with(|| (vec![], guar)) - .0 - .push(error.obligation.predicate); + for (error, &suppressed) in iter::zip(&errors, &is_suppressed) { + let span = error.obligation.cause.span; + if suppressed || span.from_expansion() != from_expansion { + continue; } + + let guar = self.report_fulfillment_error(error); + reported = Some(guar); + + self.reported_trait_errors + .borrow_mut() + .entry(span) + .or_insert_with(|| (vec![], guar)) + .0 + .push(error.obligation.predicate); } } - // It could be that we don't report an error because we have seen an `ErrorReported` from - // another source. We should probably be able to fix most of these, but some are delayed - // bugs that get a proper error after this function. - reported.unwrap_or_else(|| self.dcx().delayed_bug("failed to report fulfillment errors")) + // If all errors are suppressed, then we must have reported at least one error + // from a previous call to this function. + reported.unwrap_or_else(|| bug!("failed to report fulfillment errors")) } /// Reports that an overflow has occurred and halts compilation. We From dbdc03cc908b16e595f6f9e3575bfa6e235e14b6 Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Mon, 11 Mar 2024 20:21:17 +0100 Subject: [PATCH 2/7] add tests for mismatched super projections with nested obligations --- tests/ui/trait-bounds/super-assoc-mismatch.rs | 36 ++- .../trait-bounds/super-assoc-mismatch.stderr | 262 +++++++++++++++--- 2 files changed, 259 insertions(+), 39 deletions(-) diff --git a/tests/ui/trait-bounds/super-assoc-mismatch.rs b/tests/ui/trait-bounds/super-assoc-mismatch.rs index 97dfec80e3167..17e5260eb0bb5 100644 --- a/tests/ui/trait-bounds/super-assoc-mismatch.rs +++ b/tests/ui/trait-bounds/super-assoc-mismatch.rs @@ -6,6 +6,8 @@ impl Super for () { } trait Sub: Super {} +// direct impls (no nested obligations): + trait BoundOnSelf: Sub {} impl BoundOnSelf for () {} //~^ ERROR the trait bound `(): Sub` is not satisfied @@ -25,7 +27,7 @@ impl BoundOnAssoc for () { trait BoundOnGat where Self::Assoc: Sub { type Assoc; } -impl BoundOnGat for u8 { +impl BoundOnGat for () { type Assoc = (); //~^ ERROR the trait bound `(): Sub` is not satisfied } @@ -33,6 +35,38 @@ impl BoundOnGat for u8 { fn trivial_bound() where (): Sub {} //~^ ERROR the trait bound `(): Sub` is not satisfied +// blanket impls with nested obligations: + +struct Wrapper(T); +impl Super for Wrapper { + type Assoc = T::Assoc; +} +impl Sub for Wrapper {} + +impl BoundOnSelf for Wrapper<()> {} +//~^ ERROR the trait bound `(): Sub` is not satisfied +//~| ERROR type mismatch resolving ` as Super>::Assoc == u16 + +impl BoundOnParam> for Wrapper<()> {} +//~^ ERROR the trait bound `(): Sub` is not satisfied +//~| ERROR type mismatch resolving ` as Super>::Assoc == u16 + +impl BoundOnAssoc for Wrapper<()> { + type Assoc = Wrapper<()>; + //~^ ERROR the trait bound `(): Sub` is not satisfied + //~| ERROR type mismatch resolving ` as Super>::Assoc == u16 +} + +impl BoundOnGat for Wrapper<()> { + type Assoc = Wrapper<()>; + //~^ ERROR the trait bound `(): Sub` is not satisfied + //~| ERROR type mismatch resolving ` as Super>::Assoc == u16 +} + +fn trivial_bound_wrapper() where Wrapper<()>: Sub {} +//~^ ERROR the trait bound `(): Sub` is not satisfied +//~| ERROR type mismatch resolving ` as Super>::Assoc == u16 + // The following is an edge case where the unsatisfied projection predicate // `<::Assoc1<()> as SuperGeneric>::Assoc == ::Assoc2` // contains both associated types of `MultiAssoc`. To suppress the error about the unsatisfied diff --git a/tests/ui/trait-bounds/super-assoc-mismatch.stderr b/tests/ui/trait-bounds/super-assoc-mismatch.stderr index f2c5eb47e5981..6b781d8b895a9 100644 --- a/tests/ui/trait-bounds/super-assoc-mismatch.stderr +++ b/tests/ui/trait-bounds/super-assoc-mismatch.stderr @@ -1,82 +1,267 @@ error[E0277]: the trait bound `(): Sub` is not satisfied - --> $DIR/super-assoc-mismatch.rs:10:22 + --> $DIR/super-assoc-mismatch.rs:12:22 | LL | impl BoundOnSelf for () {} | ^^ the trait `Sub` is not implemented for `()` | -help: this trait has no implementations, consider adding one - --> $DIR/super-assoc-mismatch.rs:7:1 - | -LL | trait Sub: Super {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: the trait `Sub` is implemented for `Wrapper` note: required by a bound in `BoundOnSelf` - --> $DIR/super-assoc-mismatch.rs:9:20 + --> $DIR/super-assoc-mismatch.rs:11:20 | LL | trait BoundOnSelf: Sub {} | ^^^ required by this bound in `BoundOnSelf` error[E0277]: the trait bound `(): Sub` is not satisfied - --> $DIR/super-assoc-mismatch.rs:14:27 + --> $DIR/super-assoc-mismatch.rs:16:27 | LL | impl BoundOnParam<()> for () {} | ^^ the trait `Sub` is not implemented for `()` | -help: this trait has no implementations, consider adding one - --> $DIR/super-assoc-mismatch.rs:7:1 - | -LL | trait Sub: Super {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: the trait `Sub` is implemented for `Wrapper` note: required by a bound in `BoundOnParam` - --> $DIR/super-assoc-mismatch.rs:13:23 + --> $DIR/super-assoc-mismatch.rs:15:23 | LL | trait BoundOnParam {} | ^^^ required by this bound in `BoundOnParam` error[E0277]: the trait bound `(): Sub` is not satisfied - --> $DIR/super-assoc-mismatch.rs:21:18 + --> $DIR/super-assoc-mismatch.rs:23:18 | LL | type Assoc = (); | ^^ the trait `Sub` is not implemented for `()` | -help: this trait has no implementations, consider adding one - --> $DIR/super-assoc-mismatch.rs:7:1 - | -LL | trait Sub: Super {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: the trait `Sub` is implemented for `Wrapper` note: required by a bound in `BoundOnAssoc::Assoc` - --> $DIR/super-assoc-mismatch.rs:18:17 + --> $DIR/super-assoc-mismatch.rs:20:17 | LL | type Assoc: Sub; | ^^^ required by this bound in `BoundOnAssoc::Assoc` error[E0277]: the trait bound `(): Sub` is not satisfied - --> $DIR/super-assoc-mismatch.rs:29:21 + --> $DIR/super-assoc-mismatch.rs:31:21 | LL | type Assoc = (); - | ^^ the trait `Sub` is not implemented for `()`, which is required by `::Assoc: Sub` - | -help: this trait has no implementations, consider adding one - --> $DIR/super-assoc-mismatch.rs:7:1 + | ^^ the trait `Sub` is not implemented for `()`, which is required by `<() as BoundOnGat>::Assoc: Sub` | -LL | trait Sub: Super {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: the trait `Sub` is implemented for `Wrapper` note: required by a bound in `BoundOnGat` - --> $DIR/super-assoc-mismatch.rs:25:41 + --> $DIR/super-assoc-mismatch.rs:27:41 | LL | trait BoundOnGat where Self::Assoc: Sub { | ^^^ required by this bound in `BoundOnGat` error[E0277]: the trait bound `(): Sub` is not satisfied - --> $DIR/super-assoc-mismatch.rs:33:26 + --> $DIR/super-assoc-mismatch.rs:35:26 | LL | fn trivial_bound() where (): Sub {} | ^^^^^^^ the trait `Sub` is not implemented for `()` | -help: this trait has no implementations, consider adding one - --> $DIR/super-assoc-mismatch.rs:7:1 + = help: the trait `Sub` is implemented for `Wrapper` + = help: see issue #48214 +help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + | +LL + #![feature(trivial_bounds)] + | + +error[E0271]: type mismatch resolving ` as Super>::Assoc == u16` + --> $DIR/super-assoc-mismatch.rs:46:22 + | +LL | impl BoundOnSelf for Wrapper<()> {} + | ^^^^^^^^^^^ type mismatch resolving ` as Super>::Assoc == u16` + | +note: expected this to be `u16` + --> $DIR/super-assoc-mismatch.rs:42:18 + | +LL | type Assoc = T::Assoc; + | ^^^^^^^^ +note: required for `Wrapper<()>` to implement `Sub` + --> $DIR/super-assoc-mismatch.rs:7:7 + | +LL | trait Sub: Super {} + | ^^^ +note: required by a bound in `BoundOnSelf` + --> $DIR/super-assoc-mismatch.rs:11:20 + | +LL | trait BoundOnSelf: Sub {} + | ^^^ required by this bound in `BoundOnSelf` + +error[E0277]: the trait bound `(): Sub` is not satisfied + --> $DIR/super-assoc-mismatch.rs:46:22 + | +LL | impl BoundOnSelf for Wrapper<()> {} + | ^^^^^^^^^^^ the trait `Sub` is not implemented for `()`, which is required by `Wrapper<()>: Sub` + | + = help: the trait `Sub` is implemented for `Wrapper` +note: required for `Wrapper<()>` to implement `Sub` + --> $DIR/super-assoc-mismatch.rs:44:14 + | +LL | impl Sub for Wrapper {} + | --- ^^^ ^^^^^^^^^^ + | | + | unsatisfied trait bound introduced here +note: required by a bound in `BoundOnSelf` + --> $DIR/super-assoc-mismatch.rs:11:20 + | +LL | trait BoundOnSelf: Sub {} + | ^^^ required by this bound in `BoundOnSelf` + +error[E0271]: type mismatch resolving ` as Super>::Assoc == u16` + --> $DIR/super-assoc-mismatch.rs:50:36 + | +LL | impl BoundOnParam> for Wrapper<()> {} + | ^^^^^^^^^^^ type mismatch resolving ` as Super>::Assoc == u16` + | +note: expected this to be `u16` + --> $DIR/super-assoc-mismatch.rs:42:18 + | +LL | type Assoc = T::Assoc; + | ^^^^^^^^ +note: required for `Wrapper<()>` to implement `Sub` + --> $DIR/super-assoc-mismatch.rs:7:7 + | +LL | trait Sub: Super {} + | ^^^ +note: required by a bound in `BoundOnParam` + --> $DIR/super-assoc-mismatch.rs:15:23 + | +LL | trait BoundOnParam {} + | ^^^ required by this bound in `BoundOnParam` + +error[E0277]: the trait bound `(): Sub` is not satisfied + --> $DIR/super-assoc-mismatch.rs:50:36 + | +LL | impl BoundOnParam> for Wrapper<()> {} + | ^^^^^^^^^^^ the trait `Sub` is not implemented for `()`, which is required by `Wrapper<()>: Sub` + | + = help: the trait `Sub` is implemented for `Wrapper` +note: required for `Wrapper<()>` to implement `Sub` + --> $DIR/super-assoc-mismatch.rs:44:14 + | +LL | impl Sub for Wrapper {} + | --- ^^^ ^^^^^^^^^^ + | | + | unsatisfied trait bound introduced here +note: required by a bound in `BoundOnParam` + --> $DIR/super-assoc-mismatch.rs:15:23 + | +LL | trait BoundOnParam {} + | ^^^ required by this bound in `BoundOnParam` + +error[E0271]: type mismatch resolving ` as Super>::Assoc == u16` + --> $DIR/super-assoc-mismatch.rs:55:18 + | +LL | type Assoc = Wrapper<()>; + | ^^^^^^^^^^^ type mismatch resolving ` as Super>::Assoc == u16` + | +note: expected this to be `u16` + --> $DIR/super-assoc-mismatch.rs:42:18 + | +LL | type Assoc = T::Assoc; + | ^^^^^^^^ +note: required for ` as BoundOnAssoc>::Assoc` to implement `Sub` + --> $DIR/super-assoc-mismatch.rs:7:7 | LL | trait Sub: Super {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^ +note: required by a bound in `BoundOnAssoc::Assoc` + --> $DIR/super-assoc-mismatch.rs:20:17 + | +LL | type Assoc: Sub; + | ^^^ required by this bound in `BoundOnAssoc::Assoc` + +error[E0277]: the trait bound `(): Sub` is not satisfied + --> $DIR/super-assoc-mismatch.rs:55:18 + | +LL | type Assoc = Wrapper<()>; + | ^^^^^^^^^^^ the trait `Sub` is not implemented for `()`, which is required by `Wrapper<()>: Sub` + | + = help: the trait `Sub` is implemented for `Wrapper` +note: required for `Wrapper<()>` to implement `Sub` + --> $DIR/super-assoc-mismatch.rs:44:14 + | +LL | impl Sub for Wrapper {} + | --- ^^^ ^^^^^^^^^^ + | | + | unsatisfied trait bound introduced here +note: required by a bound in `BoundOnAssoc::Assoc` + --> $DIR/super-assoc-mismatch.rs:20:17 + | +LL | type Assoc: Sub; + | ^^^ required by this bound in `BoundOnAssoc::Assoc` + +error[E0271]: type mismatch resolving ` as Super>::Assoc == u16` + --> $DIR/super-assoc-mismatch.rs:61:21 + | +LL | type Assoc = Wrapper<()>; + | ^^^^^^^^^^^ type mismatch resolving ` as Super>::Assoc == u16` + | +note: expected this to be `u16` + --> $DIR/super-assoc-mismatch.rs:42:18 + | +LL | type Assoc = T::Assoc; + | ^^^^^^^^ +note: required for ` as BoundOnGat>::Assoc` to implement `Sub` + --> $DIR/super-assoc-mismatch.rs:7:7 + | +LL | trait Sub: Super {} + | ^^^ +note: required by a bound in `BoundOnGat` + --> $DIR/super-assoc-mismatch.rs:27:41 + | +LL | trait BoundOnGat where Self::Assoc: Sub { + | ^^^ required by this bound in `BoundOnGat` + +error[E0277]: the trait bound `(): Sub` is not satisfied + --> $DIR/super-assoc-mismatch.rs:61:21 + | +LL | type Assoc = Wrapper<()>; + | ^^^^^^^^^^^ the trait `Sub` is not implemented for `()`, which is required by ` as BoundOnGat>::Assoc: Sub` + | + = help: the trait `Sub` is implemented for `Wrapper` +note: required for `Wrapper<()>` to implement `Sub` + --> $DIR/super-assoc-mismatch.rs:44:14 + | +LL | impl Sub for Wrapper {} + | --- ^^^ ^^^^^^^^^^ + | | + | unsatisfied trait bound introduced here +note: required by a bound in `BoundOnGat` + --> $DIR/super-assoc-mismatch.rs:27:41 + | +LL | trait BoundOnGat where Self::Assoc: Sub { + | ^^^ required by this bound in `BoundOnGat` + +error[E0271]: type mismatch resolving ` as Super>::Assoc == u16` + --> $DIR/super-assoc-mismatch.rs:66:34 + | +LL | fn trivial_bound_wrapper() where Wrapper<()>: Sub {} + | ^^^^^^^^^^^^^^^^ type mismatch resolving ` as Super>::Assoc == u16` + | +note: expected this to be `u8` + --> $DIR/super-assoc-mismatch.rs:42:18 + | +LL | type Assoc = T::Assoc; + | ^^^^^^^^ + = help: see issue #48214 +help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + | +LL + #![feature(trivial_bounds)] + | + +error[E0277]: the trait bound `(): Sub` is not satisfied + --> $DIR/super-assoc-mismatch.rs:66:34 + | +LL | fn trivial_bound_wrapper() where Wrapper<()>: Sub {} + | ^^^^^^^^^^^^^^^^ the trait `Sub` is not implemented for `()`, which is required by `Wrapper<()>: Sub` + | + = help: the trait `Sub` is implemented for `Wrapper` +note: required for `Wrapper<()>` to implement `Sub` + --> $DIR/super-assoc-mismatch.rs:44:14 + | +LL | impl Sub for Wrapper {} + | --- ^^^ ^^^^^^^^^^ + | | + | unsatisfied trait bound introduced here = help: see issue #48214 help: add `#![feature(trivial_bounds)]` to the crate attributes to enable | @@ -84,18 +269,18 @@ LL + #![feature(trivial_bounds)] | error[E0277]: the trait bound `(): SubGeneric` is not satisfied - --> $DIR/super-assoc-mismatch.rs:55:22 + --> $DIR/super-assoc-mismatch.rs:89:22 | LL | type Assoc1 = (); | ^^ the trait `SubGeneric` is not implemented for `()`, which is required by `::Assoc1<()>: SubGeneric<::Assoc2>` | help: this trait has no implementations, consider adding one - --> $DIR/super-assoc-mismatch.rs:43:1 + --> $DIR/super-assoc-mismatch.rs:77:1 | LL | trait SubGeneric: SuperGeneric {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `MultiAssoc` - --> $DIR/super-assoc-mismatch.rs:46:23 + --> $DIR/super-assoc-mismatch.rs:80:23 | LL | trait MultiAssoc | ---------- required by a bound in this trait @@ -103,6 +288,7 @@ LL | where LL | Self::Assoc1<()>: SubGeneric | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `MultiAssoc` -error: aborting due to 6 previous errors +error: aborting due to 16 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0271, E0277. +For more information about an error, try `rustc --explain E0271`. From 504da112550b675b7d78a2e9e7eb70c9931218de Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Tue, 6 Feb 2024 19:45:41 +0100 Subject: [PATCH 3/7] make `Thin` a supertrait of `Sized` --- .../src/solve/normalizes_to/mod.rs | 20 +--- .../error_reporting/type_err_ctxt_ext.rs | 22 ++++- .../src/traits/project.rs | 81 +++++++--------- library/core/src/marker.rs | 13 +++ .../feature-gate-trivial_bounds.rs | 1 + .../feature-gate-trivial_bounds.stderr | 19 +++- ...gat-bound-during-assoc-ty-selection.stderr | 5 + tests/ui/layout/layout-cycle.rs | 1 + .../recursive-type-coercion-from-never.rs | 4 +- tests/ui/sized/recursive-type-pass.rs | 2 +- tests/ui/sized/recursive-type-tail.rs | 11 +++ tests/ui/sized/recursive-type-tail.stderr | 21 ++++ tests/ui/trait-bounds/unsized-bound.rs | 3 + tests/ui/trait-bounds/unsized-bound.stderr | 95 +++++++++++++++---- tests/ui/traits/bad-sized.stderr | 12 +-- tests/ui/traits/issue-32963.rs | 4 +- tests/ui/traits/issue-32963.stderr | 6 +- tests/ui/traits/pointee-normalize-equate.rs | 20 +++- 18 files changed, 235 insertions(+), 105 deletions(-) create mode 100644 tests/ui/sized/recursive-type-tail.rs create mode 100644 tests/ui/sized/recursive-type-tail.stderr diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs index d24bec5a766b9..d0d0e904380ed 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -541,22 +541,6 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { .instantiate(tcx, &[ty::GenericArg::from(goal.predicate.self_ty())]) } - ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => { - // This is the "fallback impl" for type parameters, unnormalizable projections - // and opaque types: If the `self_ty` is `Sized`, then the metadata is `()`. - // FIXME(ptr_metadata): This impl overlaps with the other impls and shouldn't - // exist. Instead, `Pointee` should be a supertrait of `Sized`. - let sized_predicate = ty::TraitRef::from_lang_item( - tcx, - LangItem::Sized, - DUMMY_SP, - [ty::GenericArg::from(goal.predicate.self_ty())], - ); - // FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`? - ecx.add_goal(GoalSource::Misc, goal.with(tcx, sized_predicate)); - tcx.types.unit - } - ty::Adt(def, args) if def.is_struct() => match def.non_enum_variant().tail_opt() { None => tcx.types.unit, Some(tail_def) => { @@ -571,6 +555,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { Some(&tail_ty) => Ty::new_projection(tcx, metadata_def_id, [tail_ty]), }, + // The metadata of these types can only be known from param env or alias bound + // candidates. + ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => return Err(NoSolution), + ty::Infer( ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_), ) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 5eff413b886aa..eadd3daa88e2a 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -123,17 +123,31 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }) .collect(); + #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] + enum ErrorOrd { + Default, + Sized, + Metadata, + Coerce, + WellFormed, + } + // Ensure `T: Sized` and `T: WF` obligations come last. This lets us display diagnostics // with more relevant type information and hide redundant E0282 ("type annotations needed") errors. errors.sort_by_key(|e| match e.obligation.predicate.kind().skip_binder() { ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) if Some(pred.def_id()) == self.tcx.lang_items().sized_trait() => { - 1 + ErrorOrd::Sized + } + ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) + if Some(pred.def_id()) == self.tcx.lang_items().metadata_type() => + { + ErrorOrd::Metadata } - ty::PredicateKind::Coerce(_) => 2, - ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => 3, - _ => 0, + ty::PredicateKind::Coerce(_) => ErrorOrd::Coerce, + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => ErrorOrd::WellFormed, + _ => ErrorOrd::Default, }); for (index, error) in errors.iter().enumerate() { diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 6756b5dec2318..7ee0edf9947a0 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -23,7 +23,6 @@ use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::{BoundRegionConversionTime, InferOk}; use crate::traits::normalize::normalize_with_depth; use crate::traits::normalize::normalize_with_depth_to; -use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use crate::traits::select::ProjectionMatchesProjection; use rustc_data_structures::sso::SsoHashSet; use rustc_data_structures::stack::ensure_sufficient_stack; @@ -975,9 +974,12 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // // NOTE: This should be kept in sync with the similar code in // `rustc_ty_utils::instance::resolve_associated_item()`. - let node_item = - specialization_graph::assoc_def(selcx.tcx(), impl_data.impl_def_id, obligation.predicate.def_id) - .map_err(|ErrorGuaranteed { .. }| ())?; + let node_item = specialization_graph::assoc_def( + selcx.tcx(), + impl_data.impl_def_id, + obligation.predicate.def_id, + ) + .map_err(|ErrorGuaranteed { .. }| ())?; if node_item.is_final() { // Non-specializable items are always projectable. @@ -1020,7 +1022,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( lang_items.async_fn_trait(), lang_items.async_fn_mut_trait(), lang_items.async_fn_once_trait(), - ].contains(&Some(trait_ref.def_id)) + ] + .contains(&Some(trait_ref.def_id)) { true } else if lang_items.async_fn_kind_helper() == Some(trait_ref.def_id) { @@ -1033,7 +1036,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( true } else { obligation.predicate.args.type_at(0).to_opt_closure_kind().is_some() - && obligation.predicate.args.type_at(1).to_opt_closure_kind().is_some() + && obligation.predicate.args.type_at(1).to_opt_closure_kind().is_some() } } else if lang_items.discriminant_kind_trait() == Some(trait_ref.def_id) { match self_ty.kind() { @@ -1116,34 +1119,28 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // If returned by `struct_tail_without_normalization` this is the empty tuple. | ty::Tuple(..) // Integers and floats are always Sized, and so have unit type metadata. - | ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) => true, + | ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) + // `{type error}` is sized, so its metadata must be the unit type. + | ty::Error(_) => true, - // We normalize from `Wrapper::Metadata` to `Tail::Metadata` if able. - // Otherwise, type parameters, opaques, and unnormalized projections have - // unit metadata if they're known (e.g. by the param_env) to be sized. - ty::Param(_) | ty::Alias(..) - if self_ty != tail || selcx.infcx.predicate_must_hold_modulo_regions( - &obligation.with( - selcx.tcx(), - ty::TraitRef::from_lang_item(selcx.tcx(), LangItem::Sized, obligation.cause.span(),[self_ty]), - ), - ) => - { - true - } + // We normalize from `Wrapper::Metadata` to `Tail::Metadata`. + ty::Param(_) | ty::Alias(..) => self_ty != tail, - // FIXME(compiler-errors): are Bound and Placeholder types ever known sized? - ty::Param(_) - | ty::Alias(..) - | ty::Bound(..) - | ty::Placeholder(..) - | ty::Infer(..) - | ty::Error(_) => { - if tail.has_infer_types() { - candidate_set.mark_ambiguous(); - } + // FIXME: These should probably project to the tail as well. + ty::Bound(..) | ty::Placeholder(..) => false, + + ty::Infer(ty::TyVar(_)) => { + candidate_set.mark_ambiguous(); false } + + ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + span_bug!( + obligation.cause.span, + "unexpected self ty `{self_ty:?}` when normalizing \ + `::Metadata`", + ) + } } } else { bug!("unexpected builtin trait with associated type: {trait_ref:?}") @@ -1190,7 +1187,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( obligation.cause.span, format!("Cannot project an associated type from `{impl_source:?}`"), ); - return Err(()) + return Err(()); } }; @@ -1510,23 +1507,15 @@ fn confirm_builtin_candidate<'cx, 'tcx>( }; let metadata_ty = self_ty.ptr_metadata_ty_or_tail(tcx, normalize).unwrap_or_else(|tail| { if tail == self_ty { - // This is the "fallback impl" for type parameters, unnormalizable projections - // and opaque types: If the `self_ty` is `Sized`, then the metadata is `()`. - // FIXME(ptr_metadata): This impl overlaps with the other impls and shouldn't - // exist. Instead, `Pointee` should be a supertrait of `Sized`. - let sized_predicate = ty::TraitRef::from_lang_item( - tcx, - LangItem::Sized, - obligation.cause.span(), - [self_ty], + span_bug!( + obligation.cause.span, + "`<{self_ty:?} as Pointee>::Metadata` projection candidate assembled, \ + but we cannot project further", ); - obligations.push(obligation.with(tcx, sized_predicate)); - tcx.types.unit - } else { - // We know that `self_ty` has the same metadata as `tail`. This allows us - // to prove predicates like `Wrapper::Metadata == Tail::Metadata`. - Ty::new_projection(tcx, metadata_def_id, [tail]) } + // We know that `self_ty` has the same metadata as `tail`. This allows us + // to prove predicates like `Wrapper::Metadata == Tail::Metadata`. + Ty::new_projection(tcx, metadata_def_id, [tail]) }); (metadata_ty.into(), obligations) } else { diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index a56a2578c2241..5fd0e0195bf1a 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -142,6 +142,19 @@ unsafe impl Send for &T {} #[rustc_specialization_trait] #[rustc_deny_explicit_impl(implement_via_object = false)] #[rustc_coinductive] +#[cfg(not(bootstrap))] +pub trait Sized: crate::ptr::Thin { + // Empty. +} + +#[stable(feature = "rust1", since = "1.0.0")] +#[lang = "sized"] +#[fundamental] +#[rustc_specialization_trait] +#[rustc_deny_explicit_impl(implement_via_object = false)] +#[rustc_coinductive] +#[cfg(bootstrap)] +#[allow(missing_docs)] pub trait Sized { // Empty. } diff --git a/tests/ui/feature-gates/feature-gate-trivial_bounds.rs b/tests/ui/feature-gates/feature-gate-trivial_bounds.rs index 3dbaf5dea250e..eb550a37f1e9b 100644 --- a/tests/ui/feature-gates/feature-gate-trivial_bounds.rs +++ b/tests/ui/feature-gates/feature-gate-trivial_bounds.rs @@ -53,6 +53,7 @@ struct TwoStrs(str, str) where str: Sized; //~ ERROR fn unsized_local() where Dst: Sized { //~ ERROR +//~^ ERROR type mismatch resolving ` as Pointee>::Metadata == ()` let x: Dst = *(Box::new(Dst { x: 1 }) as Box>); } diff --git a/tests/ui/feature-gates/feature-gate-trivial_bounds.stderr b/tests/ui/feature-gates/feature-gate-trivial_bounds.stderr index 0ee2d93fb26a2..cccb0b0b8f03c 100644 --- a/tests/ui/feature-gates/feature-gate-trivial_bounds.stderr +++ b/tests/ui/feature-gates/feature-gate-trivial_bounds.stderr @@ -132,8 +132,20 @@ help: add `#![feature(trivial_bounds)]` to the crate attributes to enable LL + #![feature(trivial_bounds)] | +error[E0271]: type mismatch resolving ` as Pointee>::Metadata == ()` + --> $DIR/feature-gate-trivial_bounds.rs:55:26 + | +LL | fn unsized_local() where Dst: Sized { + | ^^^^^^^^^^^^^^^^^ expected `DynMetadata<(dyn A + 'static)>`, found `()` + | + = help: see issue #48214 +help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + | +LL + #![feature(trivial_bounds)] + | + error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/feature-gate-trivial_bounds.rs:59:30 + --> $DIR/feature-gate-trivial_bounds.rs:60:30 | LL | fn return_str() -> str where str: Sized { | ^^^^^^^^^^ doesn't have a size known at compile-time @@ -145,6 +157,7 @@ help: add `#![feature(trivial_bounds)]` to the crate attributes to enable LL + #![feature(trivial_bounds)] | -error: aborting due to 11 previous errors +error: aborting due to 12 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0271, E0277. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.stderr b/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.stderr index b31689dbf7365..00c91c3e4f072 100644 --- a/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.stderr +++ b/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.stderr @@ -32,6 +32,11 @@ LL | impl Node LL | where LL | P::Pointer>: Sized, | ^^^^^ unsatisfied trait bound introduced here + = note: the following trait bounds were not satisfied: + `(dyn Deref> + 'static): Thin` + which is required by `(dyn Deref> + 'static): Sized` + `<(dyn Deref> + 'static) as Pointee>::Metadata = ()` + which is required by `(dyn Deref> + 'static): Sized` error: aborting due to 2 previous errors diff --git a/tests/ui/layout/layout-cycle.rs b/tests/ui/layout/layout-cycle.rs index 3c930def43b2b..ccd01c00a9c1c 100644 --- a/tests/ui/layout/layout-cycle.rs +++ b/tests/ui/layout/layout-cycle.rs @@ -8,6 +8,7 @@ use std::mem; pub struct S { pub f: ::I, + _tail: (), // without this, we get "reached the recursion limit finding the struct tail" instead } pub trait Tr { diff --git a/tests/ui/sized/recursive-type-coercion-from-never.rs b/tests/ui/sized/recursive-type-coercion-from-never.rs index 7bd87ae06c5e4..5f5a501990968 100644 --- a/tests/ui/sized/recursive-type-coercion-from-never.rs +++ b/tests/ui/sized/recursive-type-coercion-from-never.rs @@ -9,8 +9,8 @@ impl A for () { type Assoc = Foo<()>; } -struct Foo(T::Assoc); +struct Foo(T::Assoc, ()); fn main() { - Foo::<()>(todo!()); + Foo::<()>(todo!(), ()); } diff --git a/tests/ui/sized/recursive-type-pass.rs b/tests/ui/sized/recursive-type-pass.rs index bffca39ffcbbf..1831b7363f82c 100644 --- a/tests/ui/sized/recursive-type-pass.rs +++ b/tests/ui/sized/recursive-type-pass.rs @@ -5,6 +5,6 @@ impl A for () { // FIXME: it would be nice for this to at least cause a warning. type Assoc = Foo<()>; } -struct Foo(T::Assoc); +struct Foo(T::Assoc, ()); fn main() {} diff --git a/tests/ui/sized/recursive-type-tail.rs b/tests/ui/sized/recursive-type-tail.rs new file mode 100644 index 0000000000000..4c5f3c6dc7944 --- /dev/null +++ b/tests/ui/sized/recursive-type-tail.rs @@ -0,0 +1,11 @@ +//@ check-fail +//@ error-pattern: reached the recursion limit finding the struct tail + +trait A { type Assoc; } + +impl A for () { + type Assoc = Foo<()>; +} +struct Foo(T::Assoc); + +fn main() {} diff --git a/tests/ui/sized/recursive-type-tail.stderr b/tests/ui/sized/recursive-type-tail.stderr new file mode 100644 index 0000000000000..98f80a58f9812 --- /dev/null +++ b/tests/ui/sized/recursive-type-tail.stderr @@ -0,0 +1,21 @@ +error: reached the recursion limit finding the struct tail for `<() as A>::Assoc` + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` + +error: reached the recursion limit finding the struct tail for `<() as A>::Assoc` + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: reached the recursion limit finding the struct tail for `<() as A>::Assoc` + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: reached the recursion limit finding the struct tail for `<() as A>::Assoc` + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 4 previous errors + diff --git a/tests/ui/trait-bounds/unsized-bound.rs b/tests/ui/trait-bounds/unsized-bound.rs index 035b8ef1bdebc..6b433078d026c 100644 --- a/tests/ui/trait-bounds/unsized-bound.rs +++ b/tests/ui/trait-bounds/unsized-bound.rs @@ -2,14 +2,17 @@ trait Trait {} impl Trait<(A, B)> for (A, B) where A: ?Sized, B: ?Sized, {} //~^ ERROR E0277 //~| ERROR E0277 +//~| ERROR type mismatch resolving `<(A, B) as Pointee>::Metadata == ()` [E0271] impl Trait<(A, B, C)> for (A, B, C) where A: ?Sized, {} //~^ ERROR E0277 //~| ERROR E0277 //~| ERROR E0277 +//~| ERROR type mismatch resolving `<(A, B, C) as Pointee>::Metadata == ()` [E0271] trait Trait2 {} impl Trait2<(A, B)> for (A, B) {} //~^ ERROR E0277 //~| ERROR E0277 +//~| ERROR type mismatch resolving `<(A, B) as Pointee>::Metadata == ()` [E0271] trait Trait3 {} impl Trait3 for A where A: ?Sized {} //~^ ERROR E0277 diff --git a/tests/ui/trait-bounds/unsized-bound.stderr b/tests/ui/trait-bounds/unsized-bound.stderr index c8049ebee1173..8e4cb35fbe772 100644 --- a/tests/ui/trait-bounds/unsized-bound.stderr +++ b/tests/ui/trait-bounds/unsized-bound.stderr @@ -37,8 +37,26 @@ LL - impl Trait<(A, B)> for (A, B) where A: ?Sized, B: ?Sized, {} LL + impl Trait<(A, B)> for (A, B) where B: ?Sized, {} | +error[E0271]: type mismatch resolving `<(A, B) as Pointee>::Metadata == ()` + --> $DIR/unsized-bound.rs:2:30 + | +LL | impl Trait<(A, B)> for (A, B) where A: ?Sized, B: ?Sized, {} + | ^^^^^^ expected `()`, found associated type + | + = note: expected unit type `()` + found associated type `::Metadata` + = help: consider constraining the associated type `::Metadata` to `()` + = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html + = note: required for `(A, B)` to implement `Thin` + = note: required for `(A, B)` to implement `Sized` +note: required by an implicit `Sized` bound in `Trait` + --> $DIR/unsized-bound.rs:1:13 + | +LL | trait Trait {} + | ^ required by the implicit `Sized` requirement on this type parameter in `Trait` + error[E0277]: the size for values of type `C` cannot be known at compilation time - --> $DIR/unsized-bound.rs:5:52 + --> $DIR/unsized-bound.rs:6:52 | LL | impl Trait<(A, B, C)> for (A, B, C) where A: ?Sized, {} | - ^^^^^^^^^ doesn't have a size known at compile-time @@ -62,7 +80,7 @@ LL | trait Trait {} | ++++++++ error[E0277]: the size for values of type `A` cannot be known at compilation time - --> $DIR/unsized-bound.rs:5:52 + --> $DIR/unsized-bound.rs:6:52 | LL | impl Trait<(A, B, C)> for (A, B, C) where A: ?Sized, {} | - this type parameter needs to be `Sized` ^^^^^^^^^ doesn't have a size known at compile-time @@ -75,7 +93,7 @@ LL + impl Trait<(A, B, C)> for (A, B, C) {} | error[E0277]: the size for values of type `B` cannot be known at compilation time - --> $DIR/unsized-bound.rs:5:52 + --> $DIR/unsized-bound.rs:6:52 | LL | impl Trait<(A, B, C)> for (A, B, C) where A: ?Sized, {} | - this type parameter needs to be `Sized` ^^^^^^^^^ doesn't have a size known at compile-time @@ -87,8 +105,26 @@ LL - impl Trait<(A, B, C)> for (A, B, C) where A: ?Size LL + impl Trait<(A, B, C)> for (A, B, C) where A: ?Sized, {} | +error[E0271]: type mismatch resolving `<(A, B, C) as Pointee>::Metadata == ()` + --> $DIR/unsized-bound.rs:6:52 + | +LL | impl Trait<(A, B, C)> for (A, B, C) where A: ?Sized, {} + | ^^^^^^^^^ expected `()`, found associated type + | + = note: expected unit type `()` + found associated type `::Metadata` + = help: consider constraining the associated type `::Metadata` to `()` + = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html + = note: required for `(A, B, C)` to implement `Thin` + = note: required for `(A, B, C)` to implement `Sized` +note: required by an implicit `Sized` bound in `Trait` + --> $DIR/unsized-bound.rs:1:13 + | +LL | trait Trait {} + | ^ required by the implicit `Sized` requirement on this type parameter in `Trait` + error[E0277]: the size for values of type `B` cannot be known at compilation time - --> $DIR/unsized-bound.rs:10:47 + --> $DIR/unsized-bound.rs:12:47 | LL | impl Trait2<(A, B)> for (A, B) {} | - ^^^^^^ doesn't have a size known at compile-time @@ -97,7 +133,7 @@ LL | impl Trait2<(A, B)> for (A, B) {} | = note: required because it appears within the type `(A, B)` note: required by an implicit `Sized` bound in `Trait2` - --> $DIR/unsized-bound.rs:9:14 + --> $DIR/unsized-bound.rs:11:14 | LL | trait Trait2 {} | ^ required by the implicit `Sized` requirement on this type parameter in `Trait2` @@ -112,7 +148,7 @@ LL | trait Trait2 {} | ++++++++ error[E0277]: the size for values of type `A` cannot be known at compilation time - --> $DIR/unsized-bound.rs:10:47 + --> $DIR/unsized-bound.rs:12:47 | LL | impl Trait2<(A, B)> for (A, B) {} | - ^^^^^^ doesn't have a size known at compile-time @@ -126,8 +162,26 @@ LL - impl Trait2<(A, B)> for (A, B) {} LL + impl Trait2<(A, B)> for (A, B) {} | +error[E0271]: type mismatch resolving `<(A, B) as Pointee>::Metadata == ()` + --> $DIR/unsized-bound.rs:12:47 + | +LL | impl Trait2<(A, B)> for (A, B) {} + | ^^^^^^ expected `()`, found associated type + | + = note: expected unit type `()` + found associated type `::Metadata` + = help: consider constraining the associated type `::Metadata` to `()` + = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html + = note: required for `(A, B)` to implement `Thin` + = note: required for `(A, B)` to implement `Sized` +note: required by an implicit `Sized` bound in `Trait2` + --> $DIR/unsized-bound.rs:11:14 + | +LL | trait Trait2 {} + | ^ required by the implicit `Sized` requirement on this type parameter in `Trait2` + error[E0277]: the size for values of type `A` cannot be known at compilation time - --> $DIR/unsized-bound.rs:14:23 + --> $DIR/unsized-bound.rs:17:23 | LL | impl Trait3 for A where A: ?Sized {} | - ^ doesn't have a size known at compile-time @@ -135,7 +189,7 @@ LL | impl Trait3 for A where A: ?Sized {} | this type parameter needs to be `Sized` | note: required by an implicit `Sized` bound in `Trait3` - --> $DIR/unsized-bound.rs:13:14 + --> $DIR/unsized-bound.rs:16:14 | LL | trait Trait3 {} | ^ required by the implicit `Sized` requirement on this type parameter in `Trait3` @@ -150,7 +204,7 @@ LL | trait Trait3 {} | ++++++++ error[E0277]: the size for values of type `A` cannot be known at compilation time - --> $DIR/unsized-bound.rs:17:31 + --> $DIR/unsized-bound.rs:20:31 | LL | impl Trait4 for A {} | - ^ doesn't have a size known at compile-time @@ -158,7 +212,7 @@ LL | impl Trait4 for A {} | this type parameter needs to be `Sized` | note: required by an implicit `Sized` bound in `Trait4` - --> $DIR/unsized-bound.rs:16:14 + --> $DIR/unsized-bound.rs:19:14 | LL | trait Trait4 {} | ^ required by the implicit `Sized` requirement on this type parameter in `Trait4` @@ -173,7 +227,7 @@ LL | trait Trait4 {} | ++++++++ error[E0277]: the size for values of type `X` cannot be known at compilation time - --> $DIR/unsized-bound.rs:20:29 + --> $DIR/unsized-bound.rs:23:29 | LL | impl Trait5 for X where X: ?Sized {} | - ^ doesn't have a size known at compile-time @@ -181,7 +235,7 @@ LL | impl Trait5 for X where X: ?Sized {} | this type parameter needs to be `Sized` | note: required by an implicit `Sized` bound in `Trait5` - --> $DIR/unsized-bound.rs:19:14 + --> $DIR/unsized-bound.rs:22:14 | LL | trait Trait5 {} | ^ required by the implicit `Sized` requirement on this type parameter in `Trait5` @@ -196,7 +250,7 @@ LL | trait Trait5 {} | ++++++++ error[E0277]: the size for values of type `X` cannot be known at compilation time - --> $DIR/unsized-bound.rs:23:37 + --> $DIR/unsized-bound.rs:26:37 | LL | impl Trait6 for X {} | - ^ doesn't have a size known at compile-time @@ -204,7 +258,7 @@ LL | impl Trait6 for X {} | this type parameter needs to be `Sized` | note: required by an implicit `Sized` bound in `Trait6` - --> $DIR/unsized-bound.rs:22:14 + --> $DIR/unsized-bound.rs:25:14 | LL | trait Trait6 {} | ^ required by the implicit `Sized` requirement on this type parameter in `Trait6` @@ -219,7 +273,7 @@ LL | trait Trait6 {} | ++++++++ error[E0277]: the size for values of type `Y` cannot be known at compilation time - --> $DIR/unsized-bound.rs:26:12 + --> $DIR/unsized-bound.rs:29:12 | LL | impl Trait7 for X where Y: ?Sized {} | - ^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -227,7 +281,7 @@ LL | impl Trait7 for X where Y: ?Sized {} | this type parameter needs to be `Sized` | note: required by an implicit `Sized` bound in `Trait7` - --> $DIR/unsized-bound.rs:25:17 + --> $DIR/unsized-bound.rs:28:17 | LL | trait Trait7 {} | ^ required by the implicit `Sized` requirement on this type parameter in `Trait7` @@ -242,7 +296,7 @@ LL | trait Trait7 {} | ++++++++ error[E0277]: the size for values of type `Y` cannot be known at compilation time - --> $DIR/unsized-bound.rs:29:20 + --> $DIR/unsized-bound.rs:32:20 | LL | impl Trait8 for X {} | - ^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -250,7 +304,7 @@ LL | impl Trait8 for X {} | this type parameter needs to be `Sized` | note: required by an implicit `Sized` bound in `Trait8` - --> $DIR/unsized-bound.rs:28:17 + --> $DIR/unsized-bound.rs:31:17 | LL | trait Trait8 {} | ^ required by the implicit `Sized` requirement on this type parameter in `Trait8` @@ -264,6 +318,7 @@ help: consider relaxing the implicit `Sized` restriction LL | trait Trait8 {} | ++++++++ -error: aborting due to 13 previous errors +error: aborting due to 16 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0271, E0277. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/traits/bad-sized.stderr b/tests/ui/traits/bad-sized.stderr index 4c1835dfed085..0d05dfa872830 100644 --- a/tests/ui/traits/bad-sized.stderr +++ b/tests/ui/traits/bad-sized.stderr @@ -9,33 +9,33 @@ LL | let x: Vec = Vec::new(); = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Trait + Sized {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit -error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time +error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time --> $DIR/bad-sized.rs:4:12 | LL | let x: Vec = Vec::new(); | ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `Sized` is not implemented for `dyn Trait` + = help: the trait `Sized` is not implemented for `dyn Trait` note: required by an implicit `Sized` bound in `Vec` --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL -error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time +error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time --> $DIR/bad-sized.rs:4:37 | LL | let x: Vec = Vec::new(); | ^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `Sized` is not implemented for `dyn Trait` + = help: the trait `Sized` is not implemented for `dyn Trait` note: required by a bound in `Vec::::new` --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL -error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time +error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time --> $DIR/bad-sized.rs:4:37 | LL | let x: Vec = Vec::new(); | ^^^ doesn't have a size known at compile-time | - = help: the trait `Sized` is not implemented for `dyn Trait` + = help: the trait `Sized` is not implemented for `dyn Trait` note: required by an implicit `Sized` bound in `Vec` --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL diff --git a/tests/ui/traits/issue-32963.rs b/tests/ui/traits/issue-32963.rs index 56a68f3a2312c..9c0bb6833adb2 100644 --- a/tests/ui/traits/issue-32963.rs +++ b/tests/ui/traits/issue-32963.rs @@ -2,10 +2,10 @@ use std::mem; trait Misc {} -fn size_of_copy() -> usize { mem::size_of::() } +fn size_of_copy() -> usize { mem::size_of::() } fn main() { size_of_copy::(); //~^ ERROR only auto traits can be used as additional traits in a trait object - //~| ERROR the trait bound `dyn Misc: Copy` is not satisfied + //~| ERROR the trait bound `dyn Misc: Copy` is not satisfied } diff --git a/tests/ui/traits/issue-32963.stderr b/tests/ui/traits/issue-32963.stderr index bad45e54d6428..057420c78748a 100644 --- a/tests/ui/traits/issue-32963.stderr +++ b/tests/ui/traits/issue-32963.stderr @@ -9,16 +9,16 @@ LL | size_of_copy::(); = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Misc + Copy {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit -error[E0277]: the trait bound `dyn Misc: Copy` is not satisfied +error[E0277]: the trait bound `dyn Misc: Copy` is not satisfied --> $DIR/issue-32963.rs:8:20 | LL | size_of_copy::(); - | ^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `dyn Misc` + | ^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `dyn Misc` | note: required by a bound in `size_of_copy` --> $DIR/issue-32963.rs:5:20 | -LL | fn size_of_copy() -> usize { mem::size_of::() } +LL | fn size_of_copy() -> usize { mem::size_of::() } | ^^^^ required by this bound in `size_of_copy` error: aborting due to 2 previous errors diff --git a/tests/ui/traits/pointee-normalize-equate.rs b/tests/ui/traits/pointee-normalize-equate.rs index 3edb010a827b8..5b7a1901c6731 100644 --- a/tests/ui/traits/pointee-normalize-equate.rs +++ b/tests/ui/traits/pointee-normalize-equate.rs @@ -26,6 +26,14 @@ fn wrapper_to_unit(ptr: *const ()) -> *const Wrapper { cast_same_meta(ptr) } +// normalize `Wrapper::Metadata` -> `()` +fn wrapper_to_unit2(ptr: *const ()) -> *const Wrapper +where + Wrapper: Sized, +{ + cast_same_meta(ptr) +} + trait Project { type Assoc: ?Sized; } @@ -45,8 +53,16 @@ where cast_same_meta(ptr) } -// normalize `<[T] as Pointee>::Metadata` -> `usize`, even if `[T]: Sized` -fn sized_slice(ptr: *const [T]) -> *const str +// normalize `WrapperProject::Metadata` -> `T::Assoc::Metadata` -> `()` +fn wrapper_project_unit2(ptr: *const ()) -> *const WrapperProject +where + WrapperProject: Sized, +{ + cast_same_meta(ptr) +} + +// if `[T]: Sized`, then normalize `<[T] as Pointee>::Metadata` -> `()` +fn sized_slice(ptr: *const ()) -> *const [T] where [T]: Sized, { From a7f12dc57f7673140f2f2cdb2756b690d895a849 Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Wed, 13 Mar 2024 16:13:10 +0100 Subject: [PATCH 4/7] always use shallow tail for metadata projections --- .../src/traits/project.rs | 125 +++++++++++------- tests/ui/layout/layout-cycle.rs | 2 +- tests/ui/sized/recursive-type-tail.rs | 2 +- tests/ui/sized/recursive-type-tail.stderr | 30 ++--- tests/ui/traits/pointee-normalize-shallow.rs | 20 +++ 5 files changed, 111 insertions(+), 68 deletions(-) create mode 100644 tests/ui/traits/pointee-normalize-shallow.rs diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 7ee0edf9947a0..ab5855ebc325a 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1075,24 +1075,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( | ty::Error(_) => false, } } else if lang_items.pointee_trait() == Some(trait_ref.def_id) { - let tail = selcx.tcx().struct_tail_with_normalize( - self_ty, - |ty| { - // We throw away any obligations we get from this, since we normalize - // and confirm these obligations once again during confirmation - normalize_with_depth( - selcx, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - ty, - ) - .value - }, - || {}, - ); - - match tail.kind() { + match self_ty.kind() { ty::Bool | ty::Char | ty::Int(_) @@ -1113,21 +1096,17 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( | ty::Never // Extern types have unit metadata, according to RFC 2850 | ty::Foreign(_) - // If returned by `struct_tail_without_normalization` this is a unit struct - // without any fields, or not a struct, and therefore is Sized. + // The metadata of an ADT or tuple is the metadata of its tail, + // or unit if it has no tail. | ty::Adt(..) - // If returned by `struct_tail_without_normalization` this is the empty tuple. | ty::Tuple(..) - // Integers and floats are always Sized, and so have unit type metadata. + // Integers and floats are always sized, and so have unit type metadata. | ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) - // `{type error}` is sized, so its metadata must be the unit type. + // The metadata of `{type error}` is `{type error}`. | ty::Error(_) => true, - // We normalize from `Wrapper::Metadata` to `Tail::Metadata`. - ty::Param(_) | ty::Alias(..) => self_ty != tail, - - // FIXME: These should probably project to the tail as well. - ty::Bound(..) | ty::Placeholder(..) => false, + // The metadata of these types can only be known from param env candidates. + ty::Param(_) | ty::Alias(..) | ty::Bound(..) | ty::Placeholder(..) => false, ty::Infer(ty::TyVar(_)) => { candidate_set.mark_ambiguous(); @@ -1485,39 +1464,79 @@ fn confirm_builtin_candidate<'cx, 'tcx>( let lang_items = tcx.lang_items(); let item_def_id = obligation.predicate.def_id; let trait_def_id = tcx.trait_of_item(item_def_id).unwrap(); - let (term, obligations) = if lang_items.discriminant_kind_trait() == Some(trait_def_id) { + let mut potentially_unnormalized = false; + let term = if lang_items.discriminant_kind_trait() == Some(trait_def_id) { let discriminant_def_id = tcx.require_lang_item(LangItem::Discriminant, None); assert_eq!(discriminant_def_id, item_def_id); - (self_ty.discriminant_ty(tcx).into(), Vec::new()) + self_ty.discriminant_ty(tcx).into() } else if lang_items.pointee_trait() == Some(trait_def_id) { let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None); assert_eq!(metadata_def_id, item_def_id); - let mut obligations = Vec::new(); - let normalize = |ty| { - normalize_with_depth_to( - selcx, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - ty, - &mut obligations, - ) - }; - let metadata_ty = self_ty.ptr_metadata_ty_or_tail(tcx, normalize).unwrap_or_else(|tail| { - if tail == self_ty { + let metadata_ty = match self_ty.kind() { + ty::Bool + | ty::Char + | ty::Int(..) + | ty::Uint(..) + | ty::Float(..) + | ty::Array(..) + | ty::RawPtr(..) + | ty::Ref(..) + | ty::FnDef(..) + | ty::FnPtr(..) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Infer(ty::IntVar(..) | ty::FloatVar(..)) + | ty::Coroutine(..) + | ty::CoroutineWitness(..) + | ty::Never + | ty::Foreign(..) + | ty::Dynamic(_, _, ty::DynStar) => tcx.types.unit, + + ty::Error(e) => Ty::new_error(tcx, *e), + + ty::Str | ty::Slice(_) => tcx.types.usize, + + ty::Dynamic(_, _, ty::Dyn) => { + let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None); + tcx.type_of(dyn_metadata).instantiate(tcx, &[self_ty.into()]) + } + + ty::Adt(def, args) if def.is_struct() => match def.non_enum_variant().tail_opt() { + None => tcx.types.unit, + Some(tail_def) => { + // We know that `self_ty` has the same metadata as its tail. This allows us + // to prove predicates like `Wrapper::Metadata == Tail::Metadata`. + let tail_ty = tail_def.ty(tcx, args); + potentially_unnormalized = true; + Ty::new_projection(tcx, metadata_def_id, [tail_ty]) + } + }, + ty::Adt(_, _) => tcx.types.unit, + + ty::Tuple(elements) => match elements.last() { + None => tcx.types.unit, + Some(&tail_ty) => { + potentially_unnormalized = true; + Ty::new_projection(tcx, metadata_def_id, [tail_ty]) + } + }, + + ty::Param(_) + | ty::Alias(..) + | ty::Bound(..) + | ty::Placeholder(..) + | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { span_bug!( obligation.cause.span, "`<{self_ty:?} as Pointee>::Metadata` projection candidate assembled, \ but we cannot project further", ); } - // We know that `self_ty` has the same metadata as `tail`. This allows us - // to prove predicates like `Wrapper::Metadata == Tail::Metadata`. - Ty::new_projection(tcx, metadata_def_id, [tail]) - }); - (metadata_ty.into(), obligations) + }; + + metadata_ty.into() } else { bug!("unexpected builtin trait with associated type: {:?}", obligation.predicate); }; @@ -1525,9 +1544,13 @@ fn confirm_builtin_candidate<'cx, 'tcx>( let predicate = ty::ProjectionPredicate { projection_ty: ty::AliasTy::new(tcx, item_def_id, args), term }; - confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false) - .with_addl_obligations(obligations) - .with_addl_obligations(data) + confirm_param_env_candidate( + selcx, + obligation, + ty::Binder::dummy(predicate), + potentially_unnormalized, + ) + .with_addl_obligations(data) } fn confirm_fn_pointer_candidate<'cx, 'tcx>( diff --git a/tests/ui/layout/layout-cycle.rs b/tests/ui/layout/layout-cycle.rs index ccd01c00a9c1c..406dbcd5a45cd 100644 --- a/tests/ui/layout/layout-cycle.rs +++ b/tests/ui/layout/layout-cycle.rs @@ -8,7 +8,7 @@ use std::mem; pub struct S { pub f: ::I, - _tail: (), // without this, we get "reached the recursion limit finding the struct tail" instead + _tail: (), // without this, we get an overflow error instead } pub trait Tr { diff --git a/tests/ui/sized/recursive-type-tail.rs b/tests/ui/sized/recursive-type-tail.rs index 4c5f3c6dc7944..6efa2f56f21e2 100644 --- a/tests/ui/sized/recursive-type-tail.rs +++ b/tests/ui/sized/recursive-type-tail.rs @@ -1,10 +1,10 @@ //@ check-fail -//@ error-pattern: reached the recursion limit finding the struct tail trait A { type Assoc; } impl A for () { type Assoc = Foo<()>; + //~^ ERROR overflow evaluating the requirement ` as Pointee>::Metadata == ()` } struct Foo(T::Assoc); diff --git a/tests/ui/sized/recursive-type-tail.stderr b/tests/ui/sized/recursive-type-tail.stderr index 98f80a58f9812..7ce0dec89afb7 100644 --- a/tests/ui/sized/recursive-type-tail.stderr +++ b/tests/ui/sized/recursive-type-tail.stderr @@ -1,21 +1,21 @@ -error: reached the recursion limit finding the struct tail for `<() as A>::Assoc` +error[E0275]: overflow evaluating the requirement ` as Pointee>::Metadata == ()` + --> $DIR/recursive-type-tail.rs:6:18 | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` - -error: reached the recursion limit finding the struct tail for `<() as A>::Assoc` +LL | type Assoc = Foo<()>; + | ^^^^^^^ | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: reached the recursion limit finding the struct tail for `<() as A>::Assoc` + = note: required for `<() as A>::Assoc` to implement `Thin` + = note: required for `<() as A>::Assoc` to implement `Sized` +note: required by a bound in `A::Assoc` + --> $DIR/recursive-type-tail.rs:3:11 | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: reached the recursion limit finding the struct tail for `<() as A>::Assoc` +LL | trait A { type Assoc; } + | ^^^^^^^^^^^ required by this bound in `A::Assoc` +help: consider relaxing the implicit `Sized` restriction | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +LL | trait A { type Assoc: ?Sized; } + | ++++++++ -error: aborting due to 4 previous errors +error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/pointee-normalize-shallow.rs b/tests/ui/traits/pointee-normalize-shallow.rs new file mode 100644 index 0000000000000..032a0dc738efc --- /dev/null +++ b/tests/ui/traits/pointee-normalize-shallow.rs @@ -0,0 +1,20 @@ +//@ check-pass + +#![feature(ptr_metadata)] + +use std::ptr::Thin; + +struct Wrapper(T); + +fn check_thin() {} + +// Test that normalization of ` as Pointee>::Metadata` respects the +// `<[T] as Pointee>::Metadata == ()` bound from the param env. +fn foo() +where + [T]: Thin, +{ + check_thin::>(); +} + +fn main() {} From c02b3c769a350d67e5af4937ed17538b829cd764 Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Fri, 15 Mar 2024 15:10:27 +0100 Subject: [PATCH 5/7] suppress errors about `T: !Thin` caused by `T: !Sized` --- .../error_reporting/type_err_ctxt_ext.rs | 66 ++++++++-- .../feature-gate-trivial_bounds.rs | 1 - .../feature-gate-trivial_bounds.stderr | 19 +-- tests/ui/trait-bounds/super-assoc-mismatch.rs | 5 - .../trait-bounds/super-assoc-mismatch.stderr | 124 ++---------------- tests/ui/trait-bounds/unsized-bound.rs | 3 - tests/ui/trait-bounds/unsized-bound.stderr | 95 +++----------- 7 files changed, 84 insertions(+), 229 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index eadd3daa88e2a..4f4675e97bdd8 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -103,9 +103,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }; #[derive(Debug)] - struct ErrorDescriptor<'tcx> { + struct ErrorDescriptor<'tcx, 'err> { predicate: ty::Predicate<'tcx>, - index: Option, // None if this is an old error + source: Option<(usize, &'err FulfillmentError<'tcx>)>, // None if this is an old error } let mut error_map: FxIndexMap<_, Vec<_>> = self @@ -117,7 +117,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let span = strip_desugaring(span); let reported_errors = predicates .iter() - .map(|&predicate| ErrorDescriptor { predicate, index: None }) + .map(|&predicate| ErrorDescriptor { predicate, source: None }) .collect(); (span, reported_errors) }) @@ -154,7 +154,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let span = strip_desugaring(error.obligation.cause.span); error_map.entry(span).or_default().push(ErrorDescriptor { predicate: error.obligation.predicate, - index: Some(index), + source: Some((index, error)), }); } @@ -164,22 +164,37 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { for (_, error_set) in error_map.iter() { // We want to suppress "duplicate" errors with the same span. for error in error_set { - let Some(index) = error.index else { + let Some((index, error_source)) = error.source else { continue; }; - // Suppress errors that are either: - // 1) strictly implied by another error. - // 2) implied by an error with a smaller index. for error2 in error_set { - if self.error_implies(error2.predicate, error.predicate) - && (!error2.index.is_some_and(|index2| index2 >= index) - || !self.error_implies(error.predicate, error2.predicate)) + // Suppress errors that are either: + // 1) strictly implied by another error. + // 2) implied by an error with a smaller index. + if self.error_implied_by(error.predicate, error2.predicate) + && (!error2.source.is_some_and(|(index2, _)| index2 >= index) + || !self.error_implied_by(error2.predicate, error.predicate)) { info!("skipping `{}` (implied by `{}`)", error.predicate, error2.predicate); is_suppressed[index] = true; break; } + + // Also suppress the error if we are absolutely certain that a different + // error is the one that the user should fix. This will suppress errors + // about `::Metadata == ()` that can be fixed by `T: Sized`. + if error.predicate.to_opt_poly_projection_pred().is_some() + && error2.predicate.to_opt_poly_trait_pred().is_some() + && self.error_fixed_by( + error_source.obligation.clone(), + error2.predicate.expect_clause(), + ) + { + info!("skipping `{}` (fixed by `{}`)", error.predicate, error2.predicate); + is_suppressed[index] = true; + break; + } } } } @@ -1474,10 +1489,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { && self.can_eq(param_env, goal.term, assumption.term) } - // returns if `cond` not occurring implies that `error` does not occur - i.e., that - // `error` occurring implies that `cond` occurs. + /// Returns whether `cond` not occurring implies that `error` does not occur - i.e., that + /// `error` occurring implies that `cond` occurs. #[instrument(level = "debug", skip(self), ret)] - fn error_implies(&self, cond: ty::Predicate<'tcx>, error: ty::Predicate<'tcx>) -> bool { + fn error_implied_by(&self, error: ty::Predicate<'tcx>, cond: ty::Predicate<'tcx>) -> bool { if cond == error { return true; } @@ -1499,6 +1514,29 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } + /// Returns whether fixing `cond` will also fix `error`. + #[instrument(level = "debug", skip(self), ret)] + fn error_fixed_by(&self, mut error: PredicateObligation<'tcx>, cond: ty::Clause<'tcx>) -> bool { + self.probe(|_| { + let ocx = ObligationCtxt::new(self); + + let clauses = elaborate(self.tcx, std::iter::once(cond)).collect::>(); + let clauses = ocx.normalize(&error.cause, error.param_env, clauses); + let mut clauses = self.resolve_vars_if_possible(clauses); + + if clauses.has_infer() { + return false; + } + + clauses.extend(error.param_env.caller_bounds()); + let clauses = self.tcx.mk_clauses(&clauses); + error.param_env = ty::ParamEnv::new(clauses, error.param_env.reveal()); + + ocx.register_obligation(error); + ocx.select_all_or_error().is_empty() + }) + } + #[instrument(skip(self), level = "debug")] fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) -> ErrorGuaranteed { if self.tcx.sess.opts.unstable_opts.next_solver.map(|c| c.dump_tree).unwrap_or_default() diff --git a/tests/ui/feature-gates/feature-gate-trivial_bounds.rs b/tests/ui/feature-gates/feature-gate-trivial_bounds.rs index eb550a37f1e9b..3dbaf5dea250e 100644 --- a/tests/ui/feature-gates/feature-gate-trivial_bounds.rs +++ b/tests/ui/feature-gates/feature-gate-trivial_bounds.rs @@ -53,7 +53,6 @@ struct TwoStrs(str, str) where str: Sized; //~ ERROR fn unsized_local() where Dst: Sized { //~ ERROR -//~^ ERROR type mismatch resolving ` as Pointee>::Metadata == ()` let x: Dst = *(Box::new(Dst { x: 1 }) as Box>); } diff --git a/tests/ui/feature-gates/feature-gate-trivial_bounds.stderr b/tests/ui/feature-gates/feature-gate-trivial_bounds.stderr index cccb0b0b8f03c..0ee2d93fb26a2 100644 --- a/tests/ui/feature-gates/feature-gate-trivial_bounds.stderr +++ b/tests/ui/feature-gates/feature-gate-trivial_bounds.stderr @@ -132,20 +132,8 @@ help: add `#![feature(trivial_bounds)]` to the crate attributes to enable LL + #![feature(trivial_bounds)] | -error[E0271]: type mismatch resolving ` as Pointee>::Metadata == ()` - --> $DIR/feature-gate-trivial_bounds.rs:55:26 - | -LL | fn unsized_local() where Dst: Sized { - | ^^^^^^^^^^^^^^^^^ expected `DynMetadata<(dyn A + 'static)>`, found `()` - | - = help: see issue #48214 -help: add `#![feature(trivial_bounds)]` to the crate attributes to enable - | -LL + #![feature(trivial_bounds)] - | - error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/feature-gate-trivial_bounds.rs:60:30 + --> $DIR/feature-gate-trivial_bounds.rs:59:30 | LL | fn return_str() -> str where str: Sized { | ^^^^^^^^^^ doesn't have a size known at compile-time @@ -157,7 +145,6 @@ help: add `#![feature(trivial_bounds)]` to the crate attributes to enable LL + #![feature(trivial_bounds)] | -error: aborting due to 12 previous errors +error: aborting due to 11 previous errors -Some errors have detailed explanations: E0271, E0277. -For more information about an error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/trait-bounds/super-assoc-mismatch.rs b/tests/ui/trait-bounds/super-assoc-mismatch.rs index 17e5260eb0bb5..c2fc484f1c97c 100644 --- a/tests/ui/trait-bounds/super-assoc-mismatch.rs +++ b/tests/ui/trait-bounds/super-assoc-mismatch.rs @@ -45,27 +45,22 @@ impl Sub for Wrapper {} impl BoundOnSelf for Wrapper<()> {} //~^ ERROR the trait bound `(): Sub` is not satisfied -//~| ERROR type mismatch resolving ` as Super>::Assoc == u16 impl BoundOnParam> for Wrapper<()> {} //~^ ERROR the trait bound `(): Sub` is not satisfied -//~| ERROR type mismatch resolving ` as Super>::Assoc == u16 impl BoundOnAssoc for Wrapper<()> { type Assoc = Wrapper<()>; //~^ ERROR the trait bound `(): Sub` is not satisfied - //~| ERROR type mismatch resolving ` as Super>::Assoc == u16 } impl BoundOnGat for Wrapper<()> { type Assoc = Wrapper<()>; //~^ ERROR the trait bound `(): Sub` is not satisfied - //~| ERROR type mismatch resolving ` as Super>::Assoc == u16 } fn trivial_bound_wrapper() where Wrapper<()>: Sub {} //~^ ERROR the trait bound `(): Sub` is not satisfied -//~| ERROR type mismatch resolving ` as Super>::Assoc == u16 // The following is an edge case where the unsatisfied projection predicate // `<::Assoc1<()> as SuperGeneric>::Assoc == ::Assoc2` diff --git a/tests/ui/trait-bounds/super-assoc-mismatch.stderr b/tests/ui/trait-bounds/super-assoc-mismatch.stderr index 6b781d8b895a9..0fdc9b7eb0dcb 100644 --- a/tests/ui/trait-bounds/super-assoc-mismatch.stderr +++ b/tests/ui/trait-bounds/super-assoc-mismatch.stderr @@ -63,28 +63,6 @@ help: add `#![feature(trivial_bounds)]` to the crate attributes to enable LL + #![feature(trivial_bounds)] | -error[E0271]: type mismatch resolving ` as Super>::Assoc == u16` - --> $DIR/super-assoc-mismatch.rs:46:22 - | -LL | impl BoundOnSelf for Wrapper<()> {} - | ^^^^^^^^^^^ type mismatch resolving ` as Super>::Assoc == u16` - | -note: expected this to be `u16` - --> $DIR/super-assoc-mismatch.rs:42:18 - | -LL | type Assoc = T::Assoc; - | ^^^^^^^^ -note: required for `Wrapper<()>` to implement `Sub` - --> $DIR/super-assoc-mismatch.rs:7:7 - | -LL | trait Sub: Super {} - | ^^^ -note: required by a bound in `BoundOnSelf` - --> $DIR/super-assoc-mismatch.rs:11:20 - | -LL | trait BoundOnSelf: Sub {} - | ^^^ required by this bound in `BoundOnSelf` - error[E0277]: the trait bound `(): Sub` is not satisfied --> $DIR/super-assoc-mismatch.rs:46:22 | @@ -105,30 +83,8 @@ note: required by a bound in `BoundOnSelf` LL | trait BoundOnSelf: Sub {} | ^^^ required by this bound in `BoundOnSelf` -error[E0271]: type mismatch resolving ` as Super>::Assoc == u16` - --> $DIR/super-assoc-mismatch.rs:50:36 - | -LL | impl BoundOnParam> for Wrapper<()> {} - | ^^^^^^^^^^^ type mismatch resolving ` as Super>::Assoc == u16` - | -note: expected this to be `u16` - --> $DIR/super-assoc-mismatch.rs:42:18 - | -LL | type Assoc = T::Assoc; - | ^^^^^^^^ -note: required for `Wrapper<()>` to implement `Sub` - --> $DIR/super-assoc-mismatch.rs:7:7 - | -LL | trait Sub: Super {} - | ^^^ -note: required by a bound in `BoundOnParam` - --> $DIR/super-assoc-mismatch.rs:15:23 - | -LL | trait BoundOnParam {} - | ^^^ required by this bound in `BoundOnParam` - error[E0277]: the trait bound `(): Sub` is not satisfied - --> $DIR/super-assoc-mismatch.rs:50:36 + --> $DIR/super-assoc-mismatch.rs:49:36 | LL | impl BoundOnParam> for Wrapper<()> {} | ^^^^^^^^^^^ the trait `Sub` is not implemented for `()`, which is required by `Wrapper<()>: Sub` @@ -147,30 +103,8 @@ note: required by a bound in `BoundOnParam` LL | trait BoundOnParam {} | ^^^ required by this bound in `BoundOnParam` -error[E0271]: type mismatch resolving ` as Super>::Assoc == u16` - --> $DIR/super-assoc-mismatch.rs:55:18 - | -LL | type Assoc = Wrapper<()>; - | ^^^^^^^^^^^ type mismatch resolving ` as Super>::Assoc == u16` - | -note: expected this to be `u16` - --> $DIR/super-assoc-mismatch.rs:42:18 - | -LL | type Assoc = T::Assoc; - | ^^^^^^^^ -note: required for ` as BoundOnAssoc>::Assoc` to implement `Sub` - --> $DIR/super-assoc-mismatch.rs:7:7 - | -LL | trait Sub: Super {} - | ^^^ -note: required by a bound in `BoundOnAssoc::Assoc` - --> $DIR/super-assoc-mismatch.rs:20:17 - | -LL | type Assoc: Sub; - | ^^^ required by this bound in `BoundOnAssoc::Assoc` - error[E0277]: the trait bound `(): Sub` is not satisfied - --> $DIR/super-assoc-mismatch.rs:55:18 + --> $DIR/super-assoc-mismatch.rs:53:18 | LL | type Assoc = Wrapper<()>; | ^^^^^^^^^^^ the trait `Sub` is not implemented for `()`, which is required by `Wrapper<()>: Sub` @@ -189,30 +123,8 @@ note: required by a bound in `BoundOnAssoc::Assoc` LL | type Assoc: Sub; | ^^^ required by this bound in `BoundOnAssoc::Assoc` -error[E0271]: type mismatch resolving ` as Super>::Assoc == u16` - --> $DIR/super-assoc-mismatch.rs:61:21 - | -LL | type Assoc = Wrapper<()>; - | ^^^^^^^^^^^ type mismatch resolving ` as Super>::Assoc == u16` - | -note: expected this to be `u16` - --> $DIR/super-assoc-mismatch.rs:42:18 - | -LL | type Assoc = T::Assoc; - | ^^^^^^^^ -note: required for ` as BoundOnGat>::Assoc` to implement `Sub` - --> $DIR/super-assoc-mismatch.rs:7:7 - | -LL | trait Sub: Super {} - | ^^^ -note: required by a bound in `BoundOnGat` - --> $DIR/super-assoc-mismatch.rs:27:41 - | -LL | trait BoundOnGat where Self::Assoc: Sub { - | ^^^ required by this bound in `BoundOnGat` - error[E0277]: the trait bound `(): Sub` is not satisfied - --> $DIR/super-assoc-mismatch.rs:61:21 + --> $DIR/super-assoc-mismatch.rs:58:21 | LL | type Assoc = Wrapper<()>; | ^^^^^^^^^^^ the trait `Sub` is not implemented for `()`, which is required by ` as BoundOnGat>::Assoc: Sub` @@ -231,25 +143,8 @@ note: required by a bound in `BoundOnGat` LL | trait BoundOnGat where Self::Assoc: Sub { | ^^^ required by this bound in `BoundOnGat` -error[E0271]: type mismatch resolving ` as Super>::Assoc == u16` - --> $DIR/super-assoc-mismatch.rs:66:34 - | -LL | fn trivial_bound_wrapper() where Wrapper<()>: Sub {} - | ^^^^^^^^^^^^^^^^ type mismatch resolving ` as Super>::Assoc == u16` - | -note: expected this to be `u8` - --> $DIR/super-assoc-mismatch.rs:42:18 - | -LL | type Assoc = T::Assoc; - | ^^^^^^^^ - = help: see issue #48214 -help: add `#![feature(trivial_bounds)]` to the crate attributes to enable - | -LL + #![feature(trivial_bounds)] - | - error[E0277]: the trait bound `(): Sub` is not satisfied - --> $DIR/super-assoc-mismatch.rs:66:34 + --> $DIR/super-assoc-mismatch.rs:62:34 | LL | fn trivial_bound_wrapper() where Wrapper<()>: Sub {} | ^^^^^^^^^^^^^^^^ the trait `Sub` is not implemented for `()`, which is required by `Wrapper<()>: Sub` @@ -269,18 +164,18 @@ LL + #![feature(trivial_bounds)] | error[E0277]: the trait bound `(): SubGeneric` is not satisfied - --> $DIR/super-assoc-mismatch.rs:89:22 + --> $DIR/super-assoc-mismatch.rs:84:22 | LL | type Assoc1 = (); | ^^ the trait `SubGeneric` is not implemented for `()`, which is required by `::Assoc1<()>: SubGeneric<::Assoc2>` | help: this trait has no implementations, consider adding one - --> $DIR/super-assoc-mismatch.rs:77:1 + --> $DIR/super-assoc-mismatch.rs:72:1 | LL | trait SubGeneric: SuperGeneric {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `MultiAssoc` - --> $DIR/super-assoc-mismatch.rs:80:23 + --> $DIR/super-assoc-mismatch.rs:75:23 | LL | trait MultiAssoc | ---------- required by a bound in this trait @@ -288,7 +183,6 @@ LL | where LL | Self::Assoc1<()>: SubGeneric | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `MultiAssoc` -error: aborting due to 16 previous errors +error: aborting due to 11 previous errors -Some errors have detailed explanations: E0271, E0277. -For more information about an error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/trait-bounds/unsized-bound.rs b/tests/ui/trait-bounds/unsized-bound.rs index 6b433078d026c..035b8ef1bdebc 100644 --- a/tests/ui/trait-bounds/unsized-bound.rs +++ b/tests/ui/trait-bounds/unsized-bound.rs @@ -2,17 +2,14 @@ trait Trait {} impl Trait<(A, B)> for (A, B) where A: ?Sized, B: ?Sized, {} //~^ ERROR E0277 //~| ERROR E0277 -//~| ERROR type mismatch resolving `<(A, B) as Pointee>::Metadata == ()` [E0271] impl Trait<(A, B, C)> for (A, B, C) where A: ?Sized, {} //~^ ERROR E0277 //~| ERROR E0277 //~| ERROR E0277 -//~| ERROR type mismatch resolving `<(A, B, C) as Pointee>::Metadata == ()` [E0271] trait Trait2 {} impl Trait2<(A, B)> for (A, B) {} //~^ ERROR E0277 //~| ERROR E0277 -//~| ERROR type mismatch resolving `<(A, B) as Pointee>::Metadata == ()` [E0271] trait Trait3 {} impl Trait3 for A where A: ?Sized {} //~^ ERROR E0277 diff --git a/tests/ui/trait-bounds/unsized-bound.stderr b/tests/ui/trait-bounds/unsized-bound.stderr index 8e4cb35fbe772..c8049ebee1173 100644 --- a/tests/ui/trait-bounds/unsized-bound.stderr +++ b/tests/ui/trait-bounds/unsized-bound.stderr @@ -37,26 +37,8 @@ LL - impl Trait<(A, B)> for (A, B) where A: ?Sized, B: ?Sized, {} LL + impl Trait<(A, B)> for (A, B) where B: ?Sized, {} | -error[E0271]: type mismatch resolving `<(A, B) as Pointee>::Metadata == ()` - --> $DIR/unsized-bound.rs:2:30 - | -LL | impl Trait<(A, B)> for (A, B) where A: ?Sized, B: ?Sized, {} - | ^^^^^^ expected `()`, found associated type - | - = note: expected unit type `()` - found associated type `::Metadata` - = help: consider constraining the associated type `::Metadata` to `()` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html - = note: required for `(A, B)` to implement `Thin` - = note: required for `(A, B)` to implement `Sized` -note: required by an implicit `Sized` bound in `Trait` - --> $DIR/unsized-bound.rs:1:13 - | -LL | trait Trait {} - | ^ required by the implicit `Sized` requirement on this type parameter in `Trait` - error[E0277]: the size for values of type `C` cannot be known at compilation time - --> $DIR/unsized-bound.rs:6:52 + --> $DIR/unsized-bound.rs:5:52 | LL | impl Trait<(A, B, C)> for (A, B, C) where A: ?Sized, {} | - ^^^^^^^^^ doesn't have a size known at compile-time @@ -80,7 +62,7 @@ LL | trait Trait {} | ++++++++ error[E0277]: the size for values of type `A` cannot be known at compilation time - --> $DIR/unsized-bound.rs:6:52 + --> $DIR/unsized-bound.rs:5:52 | LL | impl Trait<(A, B, C)> for (A, B, C) where A: ?Sized, {} | - this type parameter needs to be `Sized` ^^^^^^^^^ doesn't have a size known at compile-time @@ -93,7 +75,7 @@ LL + impl Trait<(A, B, C)> for (A, B, C) {} | error[E0277]: the size for values of type `B` cannot be known at compilation time - --> $DIR/unsized-bound.rs:6:52 + --> $DIR/unsized-bound.rs:5:52 | LL | impl Trait<(A, B, C)> for (A, B, C) where A: ?Sized, {} | - this type parameter needs to be `Sized` ^^^^^^^^^ doesn't have a size known at compile-time @@ -105,26 +87,8 @@ LL - impl Trait<(A, B, C)> for (A, B, C) where A: ?Size LL + impl Trait<(A, B, C)> for (A, B, C) where A: ?Sized, {} | -error[E0271]: type mismatch resolving `<(A, B, C) as Pointee>::Metadata == ()` - --> $DIR/unsized-bound.rs:6:52 - | -LL | impl Trait<(A, B, C)> for (A, B, C) where A: ?Sized, {} - | ^^^^^^^^^ expected `()`, found associated type - | - = note: expected unit type `()` - found associated type `::Metadata` - = help: consider constraining the associated type `::Metadata` to `()` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html - = note: required for `(A, B, C)` to implement `Thin` - = note: required for `(A, B, C)` to implement `Sized` -note: required by an implicit `Sized` bound in `Trait` - --> $DIR/unsized-bound.rs:1:13 - | -LL | trait Trait {} - | ^ required by the implicit `Sized` requirement on this type parameter in `Trait` - error[E0277]: the size for values of type `B` cannot be known at compilation time - --> $DIR/unsized-bound.rs:12:47 + --> $DIR/unsized-bound.rs:10:47 | LL | impl Trait2<(A, B)> for (A, B) {} | - ^^^^^^ doesn't have a size known at compile-time @@ -133,7 +97,7 @@ LL | impl Trait2<(A, B)> for (A, B) {} | = note: required because it appears within the type `(A, B)` note: required by an implicit `Sized` bound in `Trait2` - --> $DIR/unsized-bound.rs:11:14 + --> $DIR/unsized-bound.rs:9:14 | LL | trait Trait2 {} | ^ required by the implicit `Sized` requirement on this type parameter in `Trait2` @@ -148,7 +112,7 @@ LL | trait Trait2 {} | ++++++++ error[E0277]: the size for values of type `A` cannot be known at compilation time - --> $DIR/unsized-bound.rs:12:47 + --> $DIR/unsized-bound.rs:10:47 | LL | impl Trait2<(A, B)> for (A, B) {} | - ^^^^^^ doesn't have a size known at compile-time @@ -162,26 +126,8 @@ LL - impl Trait2<(A, B)> for (A, B) {} LL + impl Trait2<(A, B)> for (A, B) {} | -error[E0271]: type mismatch resolving `<(A, B) as Pointee>::Metadata == ()` - --> $DIR/unsized-bound.rs:12:47 - | -LL | impl Trait2<(A, B)> for (A, B) {} - | ^^^^^^ expected `()`, found associated type - | - = note: expected unit type `()` - found associated type `::Metadata` - = help: consider constraining the associated type `::Metadata` to `()` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html - = note: required for `(A, B)` to implement `Thin` - = note: required for `(A, B)` to implement `Sized` -note: required by an implicit `Sized` bound in `Trait2` - --> $DIR/unsized-bound.rs:11:14 - | -LL | trait Trait2 {} - | ^ required by the implicit `Sized` requirement on this type parameter in `Trait2` - error[E0277]: the size for values of type `A` cannot be known at compilation time - --> $DIR/unsized-bound.rs:17:23 + --> $DIR/unsized-bound.rs:14:23 | LL | impl Trait3 for A where A: ?Sized {} | - ^ doesn't have a size known at compile-time @@ -189,7 +135,7 @@ LL | impl Trait3 for A where A: ?Sized {} | this type parameter needs to be `Sized` | note: required by an implicit `Sized` bound in `Trait3` - --> $DIR/unsized-bound.rs:16:14 + --> $DIR/unsized-bound.rs:13:14 | LL | trait Trait3 {} | ^ required by the implicit `Sized` requirement on this type parameter in `Trait3` @@ -204,7 +150,7 @@ LL | trait Trait3 {} | ++++++++ error[E0277]: the size for values of type `A` cannot be known at compilation time - --> $DIR/unsized-bound.rs:20:31 + --> $DIR/unsized-bound.rs:17:31 | LL | impl Trait4 for A {} | - ^ doesn't have a size known at compile-time @@ -212,7 +158,7 @@ LL | impl Trait4 for A {} | this type parameter needs to be `Sized` | note: required by an implicit `Sized` bound in `Trait4` - --> $DIR/unsized-bound.rs:19:14 + --> $DIR/unsized-bound.rs:16:14 | LL | trait Trait4 {} | ^ required by the implicit `Sized` requirement on this type parameter in `Trait4` @@ -227,7 +173,7 @@ LL | trait Trait4 {} | ++++++++ error[E0277]: the size for values of type `X` cannot be known at compilation time - --> $DIR/unsized-bound.rs:23:29 + --> $DIR/unsized-bound.rs:20:29 | LL | impl Trait5 for X where X: ?Sized {} | - ^ doesn't have a size known at compile-time @@ -235,7 +181,7 @@ LL | impl Trait5 for X where X: ?Sized {} | this type parameter needs to be `Sized` | note: required by an implicit `Sized` bound in `Trait5` - --> $DIR/unsized-bound.rs:22:14 + --> $DIR/unsized-bound.rs:19:14 | LL | trait Trait5 {} | ^ required by the implicit `Sized` requirement on this type parameter in `Trait5` @@ -250,7 +196,7 @@ LL | trait Trait5 {} | ++++++++ error[E0277]: the size for values of type `X` cannot be known at compilation time - --> $DIR/unsized-bound.rs:26:37 + --> $DIR/unsized-bound.rs:23:37 | LL | impl Trait6 for X {} | - ^ doesn't have a size known at compile-time @@ -258,7 +204,7 @@ LL | impl Trait6 for X {} | this type parameter needs to be `Sized` | note: required by an implicit `Sized` bound in `Trait6` - --> $DIR/unsized-bound.rs:25:14 + --> $DIR/unsized-bound.rs:22:14 | LL | trait Trait6 {} | ^ required by the implicit `Sized` requirement on this type parameter in `Trait6` @@ -273,7 +219,7 @@ LL | trait Trait6 {} | ++++++++ error[E0277]: the size for values of type `Y` cannot be known at compilation time - --> $DIR/unsized-bound.rs:29:12 + --> $DIR/unsized-bound.rs:26:12 | LL | impl Trait7 for X where Y: ?Sized {} | - ^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -281,7 +227,7 @@ LL | impl Trait7 for X where Y: ?Sized {} | this type parameter needs to be `Sized` | note: required by an implicit `Sized` bound in `Trait7` - --> $DIR/unsized-bound.rs:28:17 + --> $DIR/unsized-bound.rs:25:17 | LL | trait Trait7 {} | ^ required by the implicit `Sized` requirement on this type parameter in `Trait7` @@ -296,7 +242,7 @@ LL | trait Trait7 {} | ++++++++ error[E0277]: the size for values of type `Y` cannot be known at compilation time - --> $DIR/unsized-bound.rs:32:20 + --> $DIR/unsized-bound.rs:29:20 | LL | impl Trait8 for X {} | - ^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -304,7 +250,7 @@ LL | impl Trait8 for X {} | this type parameter needs to be `Sized` | note: required by an implicit `Sized` bound in `Trait8` - --> $DIR/unsized-bound.rs:31:17 + --> $DIR/unsized-bound.rs:28:17 | LL | trait Trait8 {} | ^ required by the implicit `Sized` requirement on this type parameter in `Trait8` @@ -318,7 +264,6 @@ help: consider relaxing the implicit `Sized` restriction LL | trait Trait8 {} | ++++++++ -error: aborting due to 16 previous errors +error: aborting due to 13 previous errors -Some errors have detailed explanations: E0271, E0277. -For more information about an error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0277`. From e39997013ac6454d4518b7a253993c311808096f Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Fri, 15 Mar 2024 18:00:30 +0100 Subject: [PATCH 6/7] clippy: handle supertraits of Sized --- .../clippy_lints/src/methods/unnecessary_to_owned.rs | 5 +++-- .../clippy_lints/src/needless_borrows_for_generic_args.rs | 8 ++++++-- .../clippy/clippy_lints/src/needless_pass_by_value.rs | 3 ++- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs index c234e4f9b110c..d8d078d1a3a42 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -23,7 +23,7 @@ use rustc_middle::ty::{ }; use rustc_span::{sym, Symbol}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; -use rustc_trait_selection::traits::{Obligation, ObligationCause}; +use rustc_trait_selection::traits::{self, Obligation, ObligationCause}; use super::UNNECESSARY_TO_OWNED; @@ -323,9 +323,10 @@ fn check_other_call_arg<'tcx>( && let (input, n_refs) = peel_mid_ty_refs(*input) && let (trait_predicates, _) = get_input_traits_and_projections(cx, callee_def_id, input) && let Some(sized_def_id) = cx.tcx.lang_items().sized_trait() + && let sized_super_def_ids = traits::supertrait_def_ids(cx.tcx, sized_def_id).collect::>() && let [trait_predicate] = trait_predicates .iter() - .filter(|trait_predicate| trait_predicate.def_id() != sized_def_id) + .filter(|trait_predicate| !sized_super_def_ids.contains(&trait_predicate.def_id())) .collect::>()[..] && let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref) && let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef) diff --git a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs index a32bca3d03816..d50b172e21b40 100644 --- a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -18,7 +18,7 @@ use rustc_middle::ty::{ use rustc_session::impl_lint_pass; use rustc_span::symbol::sym; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; -use rustc_trait_selection::traits::{Obligation, ObligationCause}; +use rustc_trait_selection::traits::{self, Obligation, ObligationCause}; use std::collections::VecDeque; declare_clippy_lint! { @@ -171,6 +171,10 @@ fn needless_borrow_count<'tcx>( let sized_trait_def_id = cx.tcx.lang_items().sized_trait(); let drop_trait_def_id = cx.tcx.lang_items().drop_trait(); + let sized_super_def_ids = sized_trait_def_id.map_or_else(Vec::new, |sized_def_id| { + traits::supertrait_def_ids(cx.tcx, sized_def_id).collect() + }); + let fn_sig = cx.tcx.fn_sig(fn_id).instantiate_identity().skip_binder(); let predicates = cx.tcx.param_env(fn_id).caller_bounds(); let projection_predicates = predicates @@ -203,7 +207,7 @@ fn needless_borrow_count<'tcx>( }) .all(|trait_def_id| { Some(trait_def_id) == destruct_trait_def_id - || Some(trait_def_id) == sized_trait_def_id + || sized_super_def_ids.contains(&trait_def_id) || cx.tcx.is_diagnostic_item(sym::Any, trait_def_id) }) { diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index f33e2e0ed71aa..0bad6ac52dc08 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -118,13 +118,14 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { ]; let sized_trait = need!(cx.tcx.lang_items().sized_trait()); + let sized_super_traits = traits::supertrait_def_ids(cx.tcx, sized_trait).collect::>(); let preds = traits::elaborate(cx.tcx, cx.param_env.caller_bounds().iter()) .filter(|p| !p.is_global()) .filter_map(|pred| { // Note that we do not want to deal with qualified predicates here. match pred.kind().no_bound_vars() { - Some(ty::ClauseKind::Trait(pred)) if pred.def_id() != sized_trait => Some(pred), + Some(ty::ClauseKind::Trait(pred)) if !sized_super_traits.contains(&pred.def_id()) => Some(pred), _ => None, } }) From 81a8fae10d0f88f977e41535544243ca57b2d798 Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Fri, 15 Mar 2024 19:01:19 +0100 Subject: [PATCH 7/7] miri: adjust layout cycle test to avoid overflow error --- src/tools/miri/tests/fail/layout_cycle.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/miri/tests/fail/layout_cycle.rs b/src/tools/miri/tests/fail/layout_cycle.rs index 3e0dd881db84e..2ea96ef7649da 100644 --- a/src/tools/miri/tests/fail/layout_cycle.rs +++ b/src/tools/miri/tests/fail/layout_cycle.rs @@ -5,6 +5,7 @@ use std::mem; pub struct S { pub f: ::I, + _tail: (), // without this, we get an overflow error instead } pub trait Tr {