From 97dfe8b87115c44d480b6282aae7754e7c4ab4fe Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 8 Nov 2024 04:27:20 +0000 Subject: [PATCH] Manually register some bounds for a better span --- .../rustc_hir_analysis/src/check/check.rs | 45 +++++++++++++++---- .../src/infer/outlives/obligations.rs | 1 + compiler/rustc_middle/src/traits/mod.rs | 5 +++ .../src/error_reporting/traits/suggestions.rs | 16 +++++++ .../issue-70935-complex-spans.stderr | 5 +++ .../bounds-are-checked-2.stderr | 10 +++++ .../generic_duplicate_param_use2.stderr | 10 +++++ .../generic_duplicate_param_use4.stderr | 10 +++++ .../hidden_type_mismatch.stderr | 14 ++++++ .../implied_lifetime_wf_check4_static.stderr | 7 ++- .../type-alias-impl-trait/issue-52843.stderr | 10 +++++ .../issue-90400-2.stderr | 20 +++++++-- .../underconstrained_generic.stderr | 10 +++++ .../wf-in-associated-type.fail.stderr | 7 ++- 14 files changed, 156 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 12b842e70b7..3080d8b3510 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -8,7 +8,7 @@ use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::{Node, intravisit}; use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt}; -use rustc_infer::traits::Obligation; +use rustc_infer::traits::{Obligation, ObligationCauseCode}; use rustc_lint_defs::builtin::{ REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS, }; @@ -267,7 +267,12 @@ fn check_opaque_meets_bounds<'tcx>( def_id: LocalDefId, origin: hir::OpaqueTyOrigin, ) -> Result<(), ErrorGuaranteed> { - let span = span_of_opaque(tcx, def_id, origin).unwrap_or_else(|| tcx.def_span(def_id)); + let (span, definition_def_id) = + if let Some((span, def_id)) = best_definition_site_of_opaque(tcx, def_id, origin) { + (span, Some(def_id)) + } else { + (tcx.def_span(def_id), None) + }; let defining_use_anchor = match origin { hir::OpaqueTyOrigin::FnReturn { parent, .. } @@ -305,8 +310,32 @@ fn check_opaque_meets_bounds<'tcx>( _ => re, }); - let misc_cause = traits::ObligationCause::misc(span, def_id); + // HACK: We eagerly instantiate some bounds to report better errors for them... + // This isn't necessary for correctness, since we register these bounds when + // equating the opaque below, but we should clean this up in the new solver. + for (predicate, pred_span) in + tcx.explicit_item_bounds(def_id).iter_instantiated_copied(tcx, args) + { + let predicate = predicate.fold_with(&mut BottomUpFolder { + tcx, + ty_op: |ty| if ty == opaque_ty { hidden_ty } else { ty }, + lt_op: |lt| lt, + ct_op: |ct| ct, + }); + ocx.register_obligation(Obligation::new( + tcx, + ObligationCause::new( + span, + def_id, + ObligationCauseCode::OpaqueTypeBound(pred_span, definition_def_id), + ), + param_env, + predicate, + )); + } + + let misc_cause = ObligationCause::misc(span, def_id); // FIXME: We should just register the item bounds here, rather than equating. match ocx.eq(&misc_cause, param_env, opaque_ty, hidden_ty) { Ok(()) => {} @@ -364,17 +393,17 @@ fn check_opaque_meets_bounds<'tcx>( } } -fn span_of_opaque<'tcx>( +fn best_definition_site_of_opaque<'tcx>( tcx: TyCtxt<'tcx>, opaque_def_id: LocalDefId, origin: hir::OpaqueTyOrigin, -) -> Option { +) -> Option<(Span, LocalDefId)> { struct TaitConstraintLocator<'tcx> { opaque_def_id: LocalDefId, tcx: TyCtxt<'tcx>, } impl<'tcx> TaitConstraintLocator<'tcx> { - fn check(&self, item_def_id: LocalDefId) -> ControlFlow { + fn check(&self, item_def_id: LocalDefId) -> ControlFlow<(Span, LocalDefId)> { if !self.tcx.has_typeck_results(item_def_id) { return ControlFlow::Continue(()); } @@ -382,7 +411,7 @@ fn check(&self, item_def_id: LocalDefId) -> ControlFlow { if let Some(hidden_ty) = self.tcx.mir_borrowck(item_def_id).concrete_opaque_types.get(&self.opaque_def_id) { - ControlFlow::Break(hidden_ty.span) + ControlFlow::Break((hidden_ty.span, item_def_id)) } else { ControlFlow::Continue(()) } @@ -390,7 +419,7 @@ fn check(&self, item_def_id: LocalDefId) -> ControlFlow { } impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'tcx> { type NestedFilter = nested_filter::All; - type Result = ControlFlow; + type Result = ControlFlow<(Span, LocalDefId)>; fn nested_visit_map(&mut self) -> Self::Map { self.tcx.hir() } diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index e0e03a29220..b1d5d688295 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -104,6 +104,7 @@ pub fn register_region_obligation_with_cause( infer::RelateParamBound(cause.span, sup_type, match cause.code().peel_derives() { ObligationCauseCode::WhereClause(_, span) | ObligationCauseCode::WhereClauseInExpr(_, span, ..) + | ObligationCauseCode::OpaqueTypeBound(span, _) if !span.is_dummy() => { Some(*span) diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 40e5ec45959..09731d565b6 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -193,6 +193,11 @@ pub enum ObligationCauseCode<'tcx> { /// The span corresponds to the clause. WhereClause(DefId, Span), + /// Represents a bound for an opaque we are checking the well-formedness of. + /// The def-id corresponds to a specific definition site that we found the + /// hidden type from, if any. + OpaqueTypeBound(Span, Option), + /// Like `WhereClause`, but also identifies the expression /// which requires the `where` clause to be proven, and also /// identifies the index of the predicate in the `predicates_of` diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 86fd4c230f6..a5e364d49f7 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -2953,6 +2953,22 @@ pub(super) fn note_obligation_cause_code( // We hold the `DefId` of the item introducing the obligation, but displaying it // doesn't add user usable information. It always point at an associated item. } + ObligationCauseCode::OpaqueTypeBound(span, definition_def_id) => { + err.span_note(span, "required by a bound in an opaque type"); + if let Some(definition_def_id) = definition_def_id + // If there are any stalled coroutine obligations, then this + // error may be due to that, and not because the body has more + // where-clauses. + && self.tcx.typeck(definition_def_id).coroutine_stalled_predicates.is_empty() + { + // FIXME(compiler-errors): We could probably point to something + // specific here if we tried hard enough... + err.span_note( + tcx.def_span(definition_def_id), + "this definition site has more where clauses than the opaque type", + ); + } + } ObligationCauseCode::Coercion { source, target } => { let source = tcx.short_ty_string(self.resolve_vars_if_possible(source), long_ty_file); diff --git a/tests/ui/async-await/issue-70935-complex-spans.stderr b/tests/ui/async-await/issue-70935-complex-spans.stderr index 777eefe897b..31d15c45921 100644 --- a/tests/ui/async-await/issue-70935-complex-spans.stderr +++ b/tests/ui/async-await/issue-70935-complex-spans.stderr @@ -35,6 +35,11 @@ note: required because it's used within this `async` block | LL | async move { | ^^^^^^^^^^ +note: required by a bound in an opaque type + --> $DIR/issue-70935-complex-spans.rs:15:37 + | +LL | fn foo(x: NotSync) -> impl Future + Send { + | ^^^^ error[E0277]: `*mut ()` cannot be shared between threads safely --> $DIR/issue-70935-complex-spans.rs:15:23 diff --git a/tests/ui/type-alias-impl-trait/bounds-are-checked-2.stderr b/tests/ui/type-alias-impl-trait/bounds-are-checked-2.stderr index 0c937f92253..8f887a6ac68 100644 --- a/tests/ui/type-alias-impl-trait/bounds-are-checked-2.stderr +++ b/tests/ui/type-alias-impl-trait/bounds-are-checked-2.stderr @@ -4,6 +4,16 @@ error[E0277]: the trait bound `T: Clone` is not satisfied LL | t | ^ the trait `Clone` is not implemented for `T` | +note: required by a bound in an opaque type + --> $DIR/bounds-are-checked-2.rs:7:26 + | +LL | pub type X = impl Clone; + | ^^^^^ +note: this definition site has more where clauses than the opaque type + --> $DIR/bounds-are-checked-2.rs:9:5 + | +LL | fn f(t: T) -> X { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider restricting type parameter `T` | LL | pub type X = impl Clone; diff --git a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr index d2d6380b65a..af6e6e1e66e 100644 --- a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr +++ b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr @@ -4,6 +4,16 @@ error[E0277]: `T` doesn't implement `Debug` LL | t | ^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug` | +note: required by a bound in an opaque type + --> $DIR/generic_duplicate_param_use2.rs:8:23 + | +LL | type Two = impl Debug; + | ^^^^^ +note: this definition site has more where clauses than the opaque type + --> $DIR/generic_duplicate_param_use2.rs:10:1 + | +LL | fn two(t: T, _: U) -> Two { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider restricting type parameter `T` | LL | type Two = impl Debug; diff --git a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use4.stderr b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use4.stderr index 2338dbd522b..a847bed93da 100644 --- a/tests/ui/type-alias-impl-trait/generic_duplicate_param_use4.stderr +++ b/tests/ui/type-alias-impl-trait/generic_duplicate_param_use4.stderr @@ -4,6 +4,16 @@ error[E0277]: `U` doesn't implement `Debug` LL | u | ^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug` | +note: required by a bound in an opaque type + --> $DIR/generic_duplicate_param_use4.rs:8:23 + | +LL | type Two = impl Debug; + | ^^^^^ +note: this definition site has more where clauses than the opaque type + --> $DIR/generic_duplicate_param_use4.rs:10:1 + | +LL | fn three(_: T, u: U) -> Two { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider restricting type parameter `U` | LL | type Two = impl Debug; diff --git a/tests/ui/type-alias-impl-trait/hidden_type_mismatch.stderr b/tests/ui/type-alias-impl-trait/hidden_type_mismatch.stderr index b05121a489e..be68bac5575 100644 --- a/tests/ui/type-alias-impl-trait/hidden_type_mismatch.stderr +++ b/tests/ui/type-alias-impl-trait/hidden_type_mismatch.stderr @@ -21,6 +21,20 @@ LL | impl + Copy> Copy for Bar {} | ----------- ^^^^ ^^^^^^ | | | unsatisfied trait bound introduced here +note: required by a bound in an opaque type + --> $DIR/hidden_type_mismatch.rs:36:26 + | +LL | pub type Tait = impl Copy + From> + Into>; + | ^^^^ +note: this definition site has more where clauses than the opaque type + --> $DIR/hidden_type_mismatch.rs:37:5 + | +LL | / pub fn define_tait() -> Tait +LL | | where +LL | | // this proves `Bar<()>: Copy`, but `define_tait` is +LL | | // now uncallable +LL | | (): Proj, + | |______________________________^ error: aborting due to 1 previous error diff --git a/tests/ui/type-alias-impl-trait/implied_lifetime_wf_check4_static.stderr b/tests/ui/type-alias-impl-trait/implied_lifetime_wf_check4_static.stderr index e5919be0532..f23b978d0b6 100644 --- a/tests/ui/type-alias-impl-trait/implied_lifetime_wf_check4_static.stderr +++ b/tests/ui/type-alias-impl-trait/implied_lifetime_wf_check4_static.stderr @@ -5,8 +5,13 @@ LL | s | ^ | | | the parameter type `A` must be valid for the static lifetime... - | ...so that the type `A` will meet its required lifetime bounds + | ...so that the type `A` will meet its required lifetime bounds... | +note: ...that is required by this bound + --> $DIR/implied_lifetime_wf_check4_static.rs:4:35 + | +LL | pub type Ty = impl Sized + 'static; + | ^^^^^^^ help: consider adding an explicit lifetime bound | LL | pub type Ty = impl Sized + 'static; diff --git a/tests/ui/type-alias-impl-trait/issue-52843.stderr b/tests/ui/type-alias-impl-trait/issue-52843.stderr index ea4c5297ad5..a6bdddbc98c 100644 --- a/tests/ui/type-alias-impl-trait/issue-52843.stderr +++ b/tests/ui/type-alias-impl-trait/issue-52843.stderr @@ -4,6 +4,16 @@ error[E0277]: the trait bound `T: Default` is not satisfied LL | t | ^ the trait `Default` is not implemented for `T` | +note: required by a bound in an opaque type + --> $DIR/issue-52843.rs:3:20 + | +LL | type Foo = impl Default; + | ^^^^^^^ +note: this definition site has more where clauses than the opaque type + --> $DIR/issue-52843.rs:6:1 + | +LL | fn foo(t: T) -> Foo { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider restricting type parameter `T` | LL | type Foo = impl Default; diff --git a/tests/ui/type-alias-impl-trait/issue-90400-2.stderr b/tests/ui/type-alias-impl-trait/issue-90400-2.stderr index b4b78f8175f..4a6a62bdf96 100644 --- a/tests/ui/type-alias-impl-trait/issue-90400-2.stderr +++ b/tests/ui/type-alias-impl-trait/issue-90400-2.stderr @@ -4,11 +4,23 @@ error[E0277]: the trait bound `B: Bar` is not satisfied LL | MyBaz(bar) | ^^^^^^^^^^ the trait `Bar` is not implemented for `B` | -note: required by a bound in `MyBaz` - --> $DIR/issue-90400-2.rs:29:17 +note: required for `MyBaz` to implement `Baz` + --> $DIR/issue-90400-2.rs:30:14 | -LL | struct MyBaz(B); - | ^^^ required by this bound in `MyBaz` +LL | impl Baz for MyBaz { + | --- ^^^ ^^^^^^^^ + | | + | unsatisfied trait bound introduced here +note: required by a bound in an opaque type + --> $DIR/issue-90400-2.rs:22:26 + | +LL | type FooFn = impl Baz; + | ^^^ +note: this definition site has more where clauses than the opaque type + --> $DIR/issue-90400-2.rs:24:5 + | +LL | fn foo(&self, bar: B) -> Self::FooFn { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider restricting type parameter `B` | LL | type FooFn = impl Baz; diff --git a/tests/ui/type-alias-impl-trait/underconstrained_generic.stderr b/tests/ui/type-alias-impl-trait/underconstrained_generic.stderr index e4de9245951..48cef847fbb 100644 --- a/tests/ui/type-alias-impl-trait/underconstrained_generic.stderr +++ b/tests/ui/type-alias-impl-trait/underconstrained_generic.stderr @@ -11,6 +11,16 @@ LL | impl ProofForConversion for () { | ----- ^^^^^^^^^^^^^^^^^^^^^ ^^ | | | unsatisfied trait bound introduced here +note: required by a bound in an opaque type + --> $DIR/underconstrained_generic.rs:19:26 + | +LL | type Converter = impl ProofForConversion; + | ^^^^^^^^^^^^^^^^^^^^^ +note: this definition site has more where clauses than the opaque type + --> $DIR/underconstrained_generic.rs:21:1 + | +LL | fn _defining_use() -> Converter { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider restricting type parameter `T` | LL | type Converter = impl ProofForConversion; diff --git a/tests/ui/type-alias-impl-trait/wf-in-associated-type.fail.stderr b/tests/ui/type-alias-impl-trait/wf-in-associated-type.fail.stderr index 03ff2e3444b..34648a420ac 100644 --- a/tests/ui/type-alias-impl-trait/wf-in-associated-type.fail.stderr +++ b/tests/ui/type-alias-impl-trait/wf-in-associated-type.fail.stderr @@ -5,8 +5,13 @@ LL | impl<'a, T> Trait<'a, T> for () { | -- the parameter type `T` must be valid for the lifetime `'a` as defined here... ... LL | req - | ^^^ ...so that the type `&'a T` will meet its required lifetime bounds + | ^^^ ...so that the type `&'a T` will meet its required lifetime bounds... | +note: ...that is required by this bound + --> $DIR/wf-in-associated-type.rs:38:36 + | +LL | type Opaque = impl Sized + 'a; + | ^^ help: consider adding an explicit lifetime bound | LL | impl<'a, T: 'a> Trait<'a, T> for () {