about summary refs log tree commit diff
path: root/compiler/rustc_trait_selection/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_trait_selection/src')
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs16
-rw-r--r--compiler/rustc_trait_selection/src/opaque_types.rs54
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs9
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs16
5 files changed, 68 insertions, 31 deletions
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 e31ff8b8729..aa153d3607b 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -820,16 +820,20 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         if matches!(obligation.cause.code(), ObligationCauseCode::FunctionArg { .. })
             && obligation.cause.span.can_be_used_for_suggestions()
         {
+            let (span, sugg) = if let Some(snippet) =
+                self.tcx.sess.source_map().span_to_snippet(obligation.cause.span).ok()
+                && snippet.starts_with("|")
+            {
+                (obligation.cause.span, format!("({snippet})({args})"))
+            } else {
+                (obligation.cause.span.shrink_to_hi(), format!("({args})"))
+            };
+
             // When the obligation error has been ensured to have been caused by
             // an argument, the `obligation.cause.span` points at the expression
             // of the argument, so we can provide a suggestion. Otherwise, we give
             // a more general note.
-            err.span_suggestion_verbose(
-                obligation.cause.span.shrink_to_hi(),
-                msg,
-                format!("({args})"),
-                Applicability::HasPlaceholders,
-            );
+            err.span_suggestion_verbose(span, msg, sugg, Applicability::HasPlaceholders);
         } else if let DefIdOrName::DefId(def_id) = def_id_or_name {
             let name = match self.tcx.hir_get_if_local(def_id) {
                 Some(hir::Node::Expr(hir::Expr {
diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs
index 70a08f34f33..bc7bdd372ba 100644
--- a/compiler/rustc_trait_selection/src/opaque_types.rs
+++ b/compiler/rustc_trait_selection/src/opaque_types.rs
@@ -4,8 +4,8 @@ use rustc_hir::def_id::LocalDefId;
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_middle::ty::{
-    self, DefiningScopeKind, GenericArgKind, GenericArgs, OpaqueTypeKey, TyCtxt, TypeVisitableExt,
-    TypingMode, fold_regions,
+    self, DefiningScopeKind, GenericArgKind, GenericArgs, OpaqueTypeKey, Ty, TyCtxt,
+    TypeVisitableExt, TypingMode, fold_regions,
 };
 use rustc_span::{ErrorGuaranteed, Span};
 
@@ -14,22 +14,22 @@ use crate::regions::OutlivesEnvironmentBuildExt;
 use crate::traits::ObligationCtxt;
 
 #[derive(Debug)]
-pub enum InvalidOpaqueTypeArgs<'tcx> {
-    AlreadyReported(ErrorGuaranteed),
+pub enum NonDefiningUseReason<'tcx> {
+    Tainted(ErrorGuaranteed),
     NotAParam { opaque_type_key: OpaqueTypeKey<'tcx>, param_index: usize, span: Span },
     DuplicateParam { opaque_type_key: OpaqueTypeKey<'tcx>, param_indices: Vec<usize>, span: Span },
 }
-impl From<ErrorGuaranteed> for InvalidOpaqueTypeArgs<'_> {
+impl From<ErrorGuaranteed> for NonDefiningUseReason<'_> {
     fn from(guar: ErrorGuaranteed) -> Self {
-        InvalidOpaqueTypeArgs::AlreadyReported(guar)
+        NonDefiningUseReason::Tainted(guar)
     }
 }
-impl<'tcx> InvalidOpaqueTypeArgs<'tcx> {
+impl<'tcx> NonDefiningUseReason<'tcx> {
     pub fn report(self, infcx: &InferCtxt<'tcx>) -> ErrorGuaranteed {
         let tcx = infcx.tcx;
         match self {
-            InvalidOpaqueTypeArgs::AlreadyReported(guar) => guar,
-            InvalidOpaqueTypeArgs::NotAParam { opaque_type_key, param_index, span } => {
+            NonDefiningUseReason::Tainted(guar) => guar,
+            NonDefiningUseReason::NotAParam { opaque_type_key, param_index, span } => {
                 let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
                 let opaque_param = opaque_generics.param_at(param_index, tcx);
                 let kind = opaque_param.kind.descr();
@@ -40,7 +40,7 @@ impl<'tcx> InvalidOpaqueTypeArgs<'tcx> {
                     param_span: tcx.def_span(opaque_param.def_id),
                 })
             }
-            InvalidOpaqueTypeArgs::DuplicateParam { opaque_type_key, param_indices, span } => {
+            NonDefiningUseReason::DuplicateParam { opaque_type_key, param_indices, span } => {
                 let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
                 let descr = opaque_generics.param_at(param_indices[0], tcx).kind.descr();
                 let spans: Vec<_> = param_indices
@@ -58,15 +58,17 @@ impl<'tcx> InvalidOpaqueTypeArgs<'tcx> {
 }
 
 /// Opaque type parameter validity check as documented in the [rustc-dev-guide chapter].
+/// With the new solver, uses which fail this check are simply treated as non-defining
+/// and we only emit an error if no defining use exists.
 ///
 /// [rustc-dev-guide chapter]:
 /// https://rustc-dev-guide.rust-lang.org/opaque-types-region-infer-restrictions.html
-pub fn check_opaque_type_parameter_valid<'tcx>(
+pub fn opaque_type_has_defining_use_args<'tcx>(
     infcx: &InferCtxt<'tcx>,
     opaque_type_key: OpaqueTypeKey<'tcx>,
     span: Span,
     defining_scope_kind: DefiningScopeKind,
-) -> Result<(), InvalidOpaqueTypeArgs<'tcx>> {
+) -> Result<(), NonDefiningUseReason<'tcx>> {
     let tcx = infcx.tcx;
     let opaque_env = LazyOpaqueTyEnv::new(tcx, opaque_type_key.def_id);
     let mut seen_params: FxIndexMap<_, Vec<_>> = FxIndexMap::default();
@@ -105,13 +107,13 @@ pub fn check_opaque_type_parameter_valid<'tcx>(
         } else {
             // Prevent `fn foo() -> Foo<u32>` from being defining.
             opaque_env.param_is_error(i)?;
-            return Err(InvalidOpaqueTypeArgs::NotAParam { opaque_type_key, param_index: i, span });
+            return Err(NonDefiningUseReason::NotAParam { opaque_type_key, param_index: i, span });
         }
     }
 
     for (_, param_indices) in seen_params {
         if param_indices.len() > 1 {
-            return Err(InvalidOpaqueTypeArgs::DuplicateParam {
+            return Err(NonDefiningUseReason::DuplicateParam {
                 opaque_type_key,
                 param_indices,
                 span,
@@ -206,3 +208,27 @@ impl<'tcx> LazyOpaqueTyEnv<'tcx> {
         canonical_args
     }
 }
+
+pub fn report_item_does_not_constrain_error<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    item_def_id: LocalDefId,
+    def_id: LocalDefId,
+    non_defining_use: Option<(OpaqueTypeKey<'tcx>, Span)>,
+) -> ErrorGuaranteed {
+    let span = tcx.def_ident_span(item_def_id).unwrap_or_else(|| tcx.def_span(item_def_id));
+    let opaque_type_span = tcx.def_span(def_id);
+    let opaque_type_name = tcx.def_path_str(def_id);
+
+    let mut err =
+        tcx.dcx().struct_span_err(span, format!("item does not constrain `{opaque_type_name}`"));
+    err.note("consider removing `#[define_opaque]` or adding an empty `#[define_opaque()]`");
+    err.span_note(opaque_type_span, "this opaque type is supposed to be constrained");
+    if let Some((key, span)) = non_defining_use {
+        let opaque_ty = Ty::new_opaque(tcx, key.def_id.into(), key.args);
+        err.span_note(
+            span,
+            format!("this use of `{opaque_ty}` does not have unique universal generic arguments"),
+        );
+    }
+    err.emit()
+}
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs
index 3f628d80662..575e0472e0e 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs
@@ -252,7 +252,9 @@ where
                         // inside of an opaque type, e.g. if there's `Opaque = (?x, ?x)` in the
                         // storage, we can also rely on structural identity of `?x` even if we
                         // later uniquify it in MIR borrowck.
-                        if infcx.in_hir_typeck && obligation.has_non_region_infer() {
+                        if infcx.in_hir_typeck
+                            && (obligation.has_non_region_infer() || obligation.has_free_regions())
+                        {
                             infcx.push_hir_typeck_potentially_region_dependent_goal(obligation);
                         }
                     }
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
index 0ca2d216228..6ce68507d65 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
@@ -1,6 +1,7 @@
 use std::fmt;
 
 use rustc_errors::ErrorGuaranteed;
+use rustc_hir::def_id::LocalDefId;
 use rustc_infer::infer::region_constraints::RegionConstraintData;
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::ty::{TyCtxt, TypeFoldable};
@@ -42,13 +43,14 @@ where
     fn fully_perform(
         self,
         infcx: &InferCtxt<'tcx>,
+        root_def_id: LocalDefId,
         span: Span,
     ) -> Result<TypeOpOutput<'tcx, Self>, ErrorGuaranteed> {
         if cfg!(debug_assertions) {
             info!("fully_perform({:?})", self);
         }
 
-        Ok(scrape_region_constraints(infcx, self.closure, self.description, span)?.0)
+        Ok(scrape_region_constraints(infcx, root_def_id, self.description, span, self.closure)?.0)
     }
 }
 
@@ -62,9 +64,10 @@ impl<F> fmt::Debug for CustomTypeOp<F> {
 /// constraints that result, creating query-region-constraints.
 pub fn scrape_region_constraints<'tcx, Op, R>(
     infcx: &InferCtxt<'tcx>,
-    op: impl FnOnce(&ObligationCtxt<'_, 'tcx>) -> Result<R, NoSolution>,
+    root_def_id: LocalDefId,
     name: &'static str,
     span: Span,
+    op: impl FnOnce(&ObligationCtxt<'_, 'tcx>) -> Result<R, NoSolution>,
 ) -> Result<(TypeOpOutput<'tcx, Op>, RegionConstraintData<'tcx>), ErrorGuaranteed>
 where
     R: TypeFoldable<TyCtxt<'tcx>>,
@@ -94,6 +97,8 @@ where
         let errors = ocx.select_all_or_error();
         if errors.is_empty() {
             Ok(value)
+        } else if let Err(guar) = infcx.tcx.check_potentially_region_dependent_goals(root_def_id) {
+            Err(guar)
         } else {
             Err(infcx
                 .dcx()
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
index 018e9748cf0..4b8bf868123 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
@@ -1,6 +1,7 @@
 use std::fmt;
 
 use rustc_errors::ErrorGuaranteed;
+use rustc_hir::def_id::LocalDefId;
 use rustc_infer::traits::PredicateObligations;
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::ty::{ParamEnvAnd, TyCtxt, TypeFoldable};
@@ -37,6 +38,7 @@ pub trait TypeOp<'tcx>: Sized + fmt::Debug {
     fn fully_perform(
         self,
         infcx: &InferCtxt<'tcx>,
+        root_def_id: LocalDefId,
         span: Span,
     ) -> Result<TypeOpOutput<'tcx, Self>, ErrorGuaranteed>;
 }
@@ -140,6 +142,7 @@ where
     fn fully_perform(
         self,
         infcx: &InferCtxt<'tcx>,
+        root_def_id: LocalDefId,
         span: Span,
     ) -> Result<TypeOpOutput<'tcx, Self>, ErrorGuaranteed> {
         // In the new trait solver, query type ops are performed locally. This
@@ -152,9 +155,10 @@ where
         if infcx.next_trait_solver() {
             return Ok(scrape_region_constraints(
                 infcx,
-                |ocx| QueryTypeOp::perform_locally_with_next_solver(ocx, self, span),
+                root_def_id,
                 "query type op",
                 span,
+                |ocx| QueryTypeOp::perform_locally_with_next_solver(ocx, self, span),
             )?
             .0);
         }
@@ -166,19 +170,15 @@ where
         // we sometimes end up with `Opaque<'a> = Opaque<'b>` instead of an actual hidden type. In that case we don't register a
         // hidden type but just equate the lifetimes. Thus we need to scrape the region constraints even though we're also manually
         // collecting region constraints via `region_constraints`.
-        let (mut output, _) = scrape_region_constraints(
-            infcx,
-            |ocx| {
+        let (mut output, _) =
+            scrape_region_constraints(infcx, root_def_id, "fully_perform", span, |ocx| {
                 let (output, ei, obligations, _) =
                     Q::fully_perform_into(self, infcx, &mut region_constraints, span)?;
                 error_info = ei;
 
                 ocx.register_obligations(obligations);
                 Ok(output)
-            },
-            "fully_perform",
-            span,
-        )?;
+            })?;
         output.error_info = error_info;
         if let Some(QueryRegionConstraints { outlives, assumptions }) = output.constraints {
             region_constraints.outlives.extend(outlives.iter().cloned());