about summary refs log tree commit diff
path: root/compiler
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 /compiler
parente4c1a0016c0bd1b6579123c785e38e63b4ccf143 (diff)
downloadrust-97dfe8b87115c44d480b6282aae7754e7c4ab4fe.tar.gz
rust-97dfe8b87115c44d480b6282aae7754e7c4ab4fe.zip
Manually register some bounds for a better span
Diffstat (limited to 'compiler')
-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
4 files changed, 59 insertions, 8 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);