about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2024-11-08 04:27:20 +0000
committerMichael Goulet <michael@errs.io>2024-11-08 04:56:08 +0000
commit97dfe8b87115c44d480b6282aae7754e7c4ab4fe (patch)
treece666ae95451e00c8b95d4223e6d362e22832801
parente4c1a0016c0bd1b6579123c785e38e63b4ccf143 (diff)
downloadrust-97dfe8b87115c44d480b6282aae7754e7c4ab4fe.tar.gz
rust-97dfe8b87115c44d480b6282aae7754e7c4ab4fe.zip
Manually register some bounds for a better span
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs45
-rw-r--r--compiler/rustc_infer/src/infer/outlives/obligations.rs1
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs5
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs16
-rw-r--r--tests/ui/async-await/issue-70935-complex-spans.stderr5
-rw-r--r--tests/ui/type-alias-impl-trait/bounds-are-checked-2.stderr10
-rw-r--r--tests/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr10
-rw-r--r--tests/ui/type-alias-impl-trait/generic_duplicate_param_use4.stderr10
-rw-r--r--tests/ui/type-alias-impl-trait/hidden_type_mismatch.stderr14
-rw-r--r--tests/ui/type-alias-impl-trait/implied_lifetime_wf_check4_static.stderr7
-rw-r--r--tests/ui/type-alias-impl-trait/issue-52843.stderr10
-rw-r--r--tests/ui/type-alias-impl-trait/issue-90400-2.stderr20
-rw-r--r--tests/ui/type-alias-impl-trait/underconstrained_generic.stderr10
-rw-r--r--tests/ui/type-alias-impl-trait/wf-in-associated-type.fail.stderr7
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_errors::codes::*;
 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<LocalDefId>,
 ) -> 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<LocalDefId>,
-) -> Option<Span> {
+) -> 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<Span> {
+        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 span_of_opaque<'tcx>(
             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 span_of_opaque<'tcx>(
     }
     impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'tcx> {
         type NestedFilter = nested_filter::All;
-        type Result = ControlFlow<Span>;
+        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 @@ impl<'tcx> InferCtxt<'tcx> {
             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<LocalDefId>),
+
     /// 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 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 // 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<T> = 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: Clone>(t: T) -> X<T> {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: consider restricting type parameter `T`
    |
 LL |     pub type X<T: std::clone::Clone> = 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<T, U> = 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: Debug, U>(t: T, _: U) -> Two<T, U> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: consider restricting type parameter `T`
    |
 LL | type Two<T: std::fmt::Debug, U> = 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<T, U> = 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: Debug>(_: T, u: U) -> Two<T, U> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: consider restricting type parameter `U`
    |
 LL | type Two<T, U: std::fmt::Debug> = 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<T: Proj<Assoc = i32> + Copy> Copy for Bar<T> {}
    |                  -----------          ^^^^     ^^^^^^
    |                  |
    |                  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<Bar<()>> + Into<Bar<()>>;
+   |                          ^^^^
+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<Assoc = i32>,
+   | |______________________________^
 
 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<A> = impl Sized + 'static;
+   |                                   ^^^^^^^
 help: consider adding an explicit lifetime bound
    |
 LL |     pub type Ty<A: 'static> = 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<T> = impl Default;
+   |                    ^^^^^^^
+note: this definition site has more where clauses than the opaque type
+  --> $DIR/issue-52843.rs:6:1
+   |
+LL | fn foo<T: Default>(t: T) -> Foo<T> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: consider restricting type parameter `T`
    |
 LL | type Foo<T: std::default::Default> = 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<B>` to implement `Baz`
+  --> $DIR/issue-90400-2.rs:30:14
    |
-LL | struct MyBaz<B: Bar>(B);
-   |                 ^^^ required by this bound in `MyBaz`
+LL | impl<B: Bar> Baz for MyBaz<B> {
+   |         ---  ^^^     ^^^^^^^^
+   |         |
+   |         unsatisfied trait bound introduced here
+note: required by a bound in an opaque type
+  --> $DIR/issue-90400-2.rs:22:26
+   |
+LL |     type FooFn<B> = impl Baz;
+   |                          ^^^
+note: this definition site has more where clauses than the opaque type
+  --> $DIR/issue-90400-2.rs:24:5
+   |
+LL |     fn foo<B: Bar>(&self, bar: B) -> Self::FooFn<B> {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: consider restricting type parameter `B`
    |
 LL |     type FooFn<B: Bar> = 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<X: Trait> ProofForConversion<X> for () {
    |         -----  ^^^^^^^^^^^^^^^^^^^^^     ^^
    |         |
    |         unsatisfied trait bound introduced here
+note: required by a bound in an opaque type
+  --> $DIR/underconstrained_generic.rs:19:26
+   |
+LL | type Converter<T> = impl ProofForConversion<T>;
+   |                          ^^^^^^^^^^^^^^^^^^^^^
+note: this definition site has more where clauses than the opaque type
+  --> $DIR/underconstrained_generic.rs:21:1
+   |
+LL | fn _defining_use<T: Trait>() -> Converter<T> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: consider restricting type parameter `T`
    |
 LL | type Converter<T: Trait> = impl ProofForConversion<T>;
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 () {