about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock1
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs17
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs7
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs22
-rw-r--r--compiler/rustc_middle/src/query/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/engine.rs30
-rw-r--r--compiler/rustc_ty_utils/Cargo.toml1
-rw-r--r--compiler/rustc_ty_utils/src/implied_bounds.rs76
10 files changed, 112 insertions, 52 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 5bc2dc5eefa..53a880e5b9f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4136,6 +4136,7 @@ dependencies = [
 name = "rustc_ty_utils"
 version = "0.0.0"
 dependencies = [
+ "itertools",
  "rustc_data_structures",
  "rustc_errors",
  "rustc_fluent_macro",
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 346e153a69d..d232747b647 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -224,7 +224,8 @@ fn check_opaque(tcx: TyCtxt<'_>, id: hir::ItemId) {
     if check_opaque_for_cycles(tcx, item.owner_id.def_id, substs, span, &origin).is_err() {
         return;
     }
-    check_opaque_meets_bounds(tcx, item.owner_id.def_id, span, &origin);
+
+    let _ = check_opaque_meets_bounds(tcx, item.owner_id.def_id, span, &origin);
 }
 
 /// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result
@@ -395,7 +396,7 @@ fn check_opaque_meets_bounds<'tcx>(
     def_id: LocalDefId,
     span: Span,
     origin: &hir::OpaqueTyOrigin,
-) {
+) -> Result<(), ErrorGuaranteed> {
     let defining_use_anchor = match *origin {
         hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did,
         hir::OpaqueTyOrigin::TyAlias { .. } => tcx.impl_trait_parent(def_id),
@@ -429,10 +430,10 @@ fn check_opaque_meets_bounds<'tcx>(
         Ok(()) => {}
         Err(ty_err) => {
             let ty_err = ty_err.to_string(tcx);
-            tcx.sess.delay_span_bug(
+            return Err(tcx.sess.delay_span_bug(
                 span,
                 format!("could not unify `{hidden_ty}` with revealed type:\n{ty_err}"),
-            );
+            ));
         }
     }
 
@@ -447,7 +448,8 @@ fn check_opaque_meets_bounds<'tcx>(
     // version.
     let errors = ocx.select_all_or_error();
     if !errors.is_empty() {
-        infcx.err_ctxt().report_fulfillment_errors(&errors);
+        let guar = infcx.err_ctxt().report_fulfillment_errors(&errors);
+        return Err(guar);
     }
     match origin {
         // Checked when type checking the function containing them.
@@ -461,14 +463,15 @@ fn check_opaque_meets_bounds<'tcx>(
             if tcx.def_kind(tcx.parent(def_id.to_def_id())) == DefKind::OpaqueTy => {}
         // Can have different predicates to their defining use
         hir::OpaqueTyOrigin::TyAlias { .. } => {
-            let wf_tys = ocx.assumed_wf_types(param_env, span, def_id);
+            let wf_tys = ocx.assumed_wf_types_and_report_errors(param_env, def_id)?;
             let implied_bounds = infcx.implied_bounds_tys(param_env, def_id, wf_tys);
             let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
-            let _ = ocx.resolve_regions_and_report_errors(defining_use_anchor, &outlives_env);
+            ocx.resolve_regions_and_report_errors(defining_use_anchor, &outlives_env)?;
         }
     }
     // Clean up after ourselves
     let _ = infcx.take_opaque_types();
+    Ok(())
 }
 
 fn is_enum_of_nonnullable_ptr<'tcx>(
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index 76edeccaf29..3f5164e093d 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -2121,7 +2121,7 @@ pub(super) fn check_type_bounds<'tcx>(
             _ => bug!(),
         }
     };
-    let assumed_wf_types = ocx.assumed_wf_types(param_env, impl_ty_span, impl_ty_def_id);
+    let assumed_wf_types = ocx.assumed_wf_types_and_report_errors(param_env, impl_ty_def_id)?;
 
     let normalize_cause = ObligationCause::new(
         impl_ty_span,
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index d34d6f644a7..506fdccd6c2 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -105,7 +105,12 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>(
     }
     f(&mut wfcx);
 
-    let assumed_wf_types = wfcx.ocx.assumed_wf_types(param_env, span, body_def_id);
+    let assumed_wf_types = match wfcx.ocx.assumed_wf_types_and_report_errors(param_env, body_def_id)
+    {
+        Ok(wf_types) => wf_types,
+        Err(_guar) => return,
+    };
+
     let implied_bounds = infcx.implied_bounds_tys(param_env, body_def_id, assumed_wf_types);
 
     let errors = wfcx.select_all_or_error();
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
index 383144ce139..67800dbd2a2 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
@@ -77,7 +77,7 @@ use rustc_infer::traits::specialization_graph::Node;
 use rustc_middle::ty::subst::{GenericArg, InternalSubsts, SubstsRef};
 use rustc_middle::ty::trait_def::TraitSpecializationKind;
 use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
-use rustc_span::Span;
+use rustc_span::{ErrorGuaranteed, Span};
 use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
 use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
 use rustc_trait_selection::traits::{self, translate_substs_with_cause, wf, ObligationCtxt};
@@ -113,7 +113,7 @@ fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node
     let span = tcx.def_span(impl1_def_id);
     check_has_items(tcx, impl1_def_id, impl2_node, span);
 
-    if let Some((impl1_substs, impl2_substs)) = get_impl_substs(tcx, impl1_def_id, impl2_node) {
+    if let Ok((impl1_substs, impl2_substs)) = get_impl_substs(tcx, impl1_def_id, impl2_node) {
         let impl2_def_id = impl2_node.def_id();
         debug!(?impl2_def_id, ?impl2_substs);
 
@@ -171,16 +171,14 @@ fn get_impl_substs(
     tcx: TyCtxt<'_>,
     impl1_def_id: LocalDefId,
     impl2_node: Node,
-) -> Option<(SubstsRef<'_>, SubstsRef<'_>)> {
+) -> Result<(SubstsRef<'_>, SubstsRef<'_>), ErrorGuaranteed> {
     let infcx = &tcx.infer_ctxt().build();
     let ocx = ObligationCtxt::new(infcx);
     let param_env = tcx.param_env(impl1_def_id);
-
-    let assumed_wf_types =
-        ocx.assumed_wf_types(param_env, tcx.def_span(impl1_def_id), impl1_def_id);
+    let impl1_span = tcx.def_span(impl1_def_id);
+    let assumed_wf_types = ocx.assumed_wf_types_and_report_errors(param_env, impl1_def_id)?;
 
     let impl1_substs = InternalSubsts::identity_for_item(tcx, impl1_def_id);
-    let impl1_span = tcx.def_span(impl1_def_id);
     let impl2_substs = translate_substs_with_cause(
         infcx,
         param_env,
@@ -198,8 +196,8 @@ fn get_impl_substs(
 
     let errors = ocx.select_all_or_error();
     if !errors.is_empty() {
-        ocx.infcx.err_ctxt().report_fulfillment_errors(&errors);
-        return None;
+        let guar = ocx.infcx.err_ctxt().report_fulfillment_errors(&errors);
+        return Err(guar);
     }
 
     let implied_bounds = infcx.implied_bounds_tys(param_env, impl1_def_id, assumed_wf_types);
@@ -207,10 +205,10 @@ fn get_impl_substs(
     let _ = ocx.resolve_regions_and_report_errors(impl1_def_id, &outlives_env);
     let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else {
         let span = tcx.def_span(impl1_def_id);
-        tcx.sess.emit_err(SubstsOnOverriddenImpl { span });
-        return None;
+        let guar = tcx.sess.emit_err(SubstsOnOverriddenImpl { span });
+        return Err(guar);
     };
-    Some((impl1_substs, impl2_substs))
+    Ok((impl1_substs, impl2_substs))
 }
 
 /// Returns a list of all of the unconstrained subst of the given impl.
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index c12587845e5..a8cdf8286fe 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -881,7 +881,7 @@ rustc_queries! {
     ///
     /// Note that we've liberated the late bound regions of function signatures, so
     /// this can not be used to check whether these types are well formed.
-    query assumed_wf_types(key: DefId) -> &'tcx ty::List<Ty<'tcx>> {
+    query assumed_wf_types(key: LocalDefId) -> &'tcx [(Ty<'tcx>, Span)] {
         desc { |tcx| "computing the implied bounds of `{}`", tcx.def_path_str(key) }
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 9e1332c1c81..4cfe2bfcb12 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -427,7 +427,11 @@ fn prove_negated_obligation<'tcx>(
     let body_def_id = body_def_id.as_local().unwrap_or(CRATE_DEF_ID);
 
     let ocx = ObligationCtxt::new(&infcx);
-    let wf_tys = ocx.assumed_wf_types(param_env, DUMMY_SP, body_def_id);
+    let Ok(wf_tys) = ocx.assumed_wf_types(param_env, body_def_id)
+    else {
+        return false;
+    };
+
     let outlives_env = OutlivesEnvironment::with_bounds(
         param_env,
         infcx.implied_bounds_tys(param_env, body_def_id, wf_tys),
diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs
index faa675054b7..2fa69b995ff 100644
--- a/compiler/rustc_trait_selection/src/traits/engine.rs
+++ b/compiler/rustc_trait_selection/src/traits/engine.rs
@@ -4,6 +4,7 @@ use std::fmt::Debug;
 use super::TraitEngine;
 use super::{ChalkFulfillmentContext, FulfillmentContext};
 use crate::solve::FulfillmentCtxt as NextFulfillmentCtxt;
+use crate::traits::error_reporting::TypeErrCtxtExt;
 use crate::traits::NormalizeExt;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::ErrorGuaranteed;
@@ -24,7 +25,6 @@ use rustc_middle::ty::ToPredicate;
 use rustc_middle::ty::TypeFoldable;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::config::TraitSolver;
-use rustc_span::Span;
 
 pub trait TraitEngineExt<'tcx> {
     fn new(infcx: &InferCtxt<'tcx>) -> Box<Self>;
@@ -198,17 +198,24 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
         }
     }
 
+    pub fn assumed_wf_types_and_report_errors(
+        &self,
+        param_env: ty::ParamEnv<'tcx>,
+        def_id: LocalDefId,
+    ) -> Result<FxIndexSet<Ty<'tcx>>, ErrorGuaranteed> {
+        self.assumed_wf_types(param_env, def_id)
+            .map_err(|errors| self.infcx.err_ctxt().report_fulfillment_errors(&errors))
+    }
+
     pub fn assumed_wf_types(
         &self,
         param_env: ty::ParamEnv<'tcx>,
-        span: Span,
         def_id: LocalDefId,
-    ) -> FxIndexSet<Ty<'tcx>> {
+    ) -> Result<FxIndexSet<Ty<'tcx>>, Vec<FulfillmentError<'tcx>>> {
         let tcx = self.infcx.tcx;
-        let assumed_wf_types = tcx.assumed_wf_types(def_id);
         let mut implied_bounds = FxIndexSet::default();
-        let cause = ObligationCause::misc(span, def_id);
-        for ty in assumed_wf_types {
+        let mut errors = Vec::new();
+        for &(ty, span) in tcx.assumed_wf_types(def_id) {
             // FIXME(@lcnr): rustc currently does not check wf for types
             // pre-normalization, meaning that implied bounds are sometimes
             // incorrect. See #100910 for more details.
@@ -221,10 +228,15 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
             // sound and then uncomment this line again.
 
             // implied_bounds.insert(ty);
-            let normalized = self.normalize(&cause, param_env, ty);
-            implied_bounds.insert(normalized);
+            let cause = ObligationCause::misc(span, def_id);
+            match self.infcx.at(&cause, param_env).deeply_normalize(ty) {
+                // Insert well-formed types, ignoring duplicates.
+                Ok(normalized) => drop(implied_bounds.insert(normalized)),
+                Err(normalization_errors) => errors.extend(normalization_errors),
+            };
         }
-        implied_bounds
+
+        if errors.is_empty() { Ok(implied_bounds) } else { Err(errors) }
     }
 
     pub fn make_canonicalized_query_response<T>(
diff --git a/compiler/rustc_ty_utils/Cargo.toml b/compiler/rustc_ty_utils/Cargo.toml
index 51885c9b47e..50dac3a37a4 100644
--- a/compiler/rustc_ty_utils/Cargo.toml
+++ b/compiler/rustc_ty_utils/Cargo.toml
@@ -5,6 +5,7 @@ edition = "2021"
 
 [dependencies]
 tracing = "0.1"
+itertools = "0.10.1"
 rustc_middle = { path = "../rustc_middle" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs
index 081be065864..10dec9a7a32 100644
--- a/compiler/rustc_ty_utils/src/implied_bounds.rs
+++ b/compiler/rustc_ty_utils/src/implied_bounds.rs
@@ -1,45 +1,56 @@
-use rustc_hir::{def::DefKind, def_id::DefId};
+use rustc_hir as hir;
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::LocalDefId;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_span::Span;
+use std::iter;
 
 pub fn provide(providers: &mut Providers) {
     *providers = Providers { assumed_wf_types, ..*providers };
 }
 
-fn assumed_wf_types(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::List<Ty<'_>> {
+fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<'tcx>, Span)] {
     match tcx.def_kind(def_id) {
         DefKind::Fn => {
             let sig = tcx.fn_sig(def_id).subst_identity();
-            let liberated_sig = tcx.liberate_late_bound_regions(def_id, sig);
-            liberated_sig.inputs_and_output
+            let liberated_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), sig);
+            tcx.arena.alloc_from_iter(itertools::zip_eq(
+                liberated_sig.inputs_and_output,
+                fn_sig_spans(tcx, def_id),
+            ))
         }
         DefKind::AssocFn => {
             let sig = tcx.fn_sig(def_id).subst_identity();
-            let liberated_sig = tcx.liberate_late_bound_regions(def_id, sig);
+            let liberated_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), sig);
             let mut assumed_wf_types: Vec<_> =
-                tcx.assumed_wf_types(tcx.parent(def_id)).as_slice().into();
-            assumed_wf_types.extend(liberated_sig.inputs_and_output);
-            tcx.mk_type_list(&assumed_wf_types)
+                tcx.assumed_wf_types(tcx.local_parent(def_id)).into();
+            assumed_wf_types.extend(itertools::zip_eq(
+                liberated_sig.inputs_and_output,
+                fn_sig_spans(tcx, def_id),
+            ));
+            tcx.arena.alloc_slice(&assumed_wf_types)
         }
         DefKind::Impl { .. } => {
-            match tcx.impl_trait_ref(def_id) {
-                Some(trait_ref) => {
-                    let types: Vec<_> = trait_ref.skip_binder().substs.types().collect();
-                    tcx.mk_type_list(&types)
-                }
-                // Only the impl self type
-                None => tcx.mk_type_list(&[tcx.type_of(def_id).subst_identity()]),
-            }
+            // Trait arguments and the self type for trait impls or only the self type for
+            // inherent impls.
+            let tys = match tcx.impl_trait_ref(def_id) {
+                Some(trait_ref) => trait_ref.skip_binder().substs.types().collect(),
+                None => vec![tcx.type_of(def_id).subst_identity()],
+            };
+
+            let mut impl_spans = impl_spans(tcx, def_id);
+            tcx.arena.alloc_from_iter(tys.into_iter().map(|ty| (ty, impl_spans.next().unwrap())))
         }
-        DefKind::AssocConst | DefKind::AssocTy => tcx.assumed_wf_types(tcx.parent(def_id)),
-        DefKind::OpaqueTy => match tcx.def_kind(tcx.parent(def_id)) {
+        DefKind::AssocConst | DefKind::AssocTy => tcx.assumed_wf_types(tcx.local_parent(def_id)),
+        DefKind::OpaqueTy => match tcx.def_kind(tcx.local_parent(def_id)) {
             DefKind::TyAlias => ty::List::empty(),
-            DefKind::AssocTy => tcx.assumed_wf_types(tcx.parent(def_id)),
+            DefKind::AssocTy => tcx.assumed_wf_types(tcx.local_parent(def_id)),
             // Nested opaque types only occur in associated types:
             // ` type Opaque<T> = impl Trait<&'static T, AssocTy = impl Nested>; `
             // assumed_wf_types should include those of `Opaque<T>`, `Opaque<T>` itself
             // and `&'static T`.
-            DefKind::OpaqueTy => bug!("unimplemented implied bounds for neseted opaque types"),
+            DefKind::OpaqueTy => bug!("unimplemented implied bounds for nested opaque types"),
             def_kind @ _ => {
                 bug!("unimplemented implied bounds for opaque types with parent {def_kind:?}")
             }
@@ -72,3 +83,28 @@ fn assumed_wf_types(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::List<Ty<'_>> {
         | DefKind::Generator => ty::List::empty(),
     }
 }
+
+fn fn_sig_spans(tcx: TyCtxt<'_>, def_id: LocalDefId) -> impl Iterator<Item = Span> + '_ {
+    let node = tcx.hir().get(tcx.local_def_id_to_hir_id(def_id));
+    if let Some(decl) = node.fn_decl() {
+        decl.inputs.iter().map(|ty| ty.span).chain(iter::once(decl.output.span()))
+    } else {
+        bug!("unexpected item for fn {def_id:?}: {node:?}")
+    }
+}
+
+fn impl_spans(tcx: TyCtxt<'_>, def_id: LocalDefId) -> impl Iterator<Item = Span> + '_ {
+    let item = tcx.hir().expect_item(def_id);
+    if let hir::ItemKind::Impl(impl_) = item.kind {
+        let trait_args = impl_
+            .of_trait
+            .into_iter()
+            .flat_map(|trait_ref| trait_ref.path.segments.last().unwrap().args().args)
+            .map(|arg| arg.span());
+        let dummy_spans_for_default_args =
+            impl_.of_trait.into_iter().flat_map(|trait_ref| iter::repeat(trait_ref.path.span));
+        iter::once(impl_.self_ty.span).chain(trait_args).chain(dummy_spans_for_default_args)
+    } else {
+        bug!("unexpected item for impl {def_id:?}: {item:?}")
+    }
+}