about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_middle/src/query/mod.rs2
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs18
-rw-r--r--compiler/rustc_trait_selection/src/traits/codegen.rs91
-rw-r--r--compiler/rustc_ty_utils/src/instance.rs18
4 files changed, 52 insertions, 77 deletions
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 629a550b775..0ef694a3c85 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1145,7 +1145,7 @@ rustc_queries! {
 
     query codegen_fulfill_obligation(
         key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)
-    ) -> Result<&'tcx ImplSource<'tcx, ()>, ErrorGuaranteed> {
+    ) -> Result<&'tcx ImplSource<'tcx, ()>, traits::CodegenObligationError> {
         cache_on_disk_if { true }
         desc { |tcx|
             "checking if `{}` fulfills its obligations",
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index ffde1294ec6..8c660e38a7f 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -963,3 +963,21 @@ pub enum MethodViolationCode {
     /// the method's receiver (`self` argument) can't be dispatched on
     UndispatchableReceiver,
 }
+
+/// These are the error cases for `codegen_fulfill_obligation`.
+#[derive(Copy, Clone, Debug, Hash, HashStable, Encodable, Decodable)]
+pub enum CodegenObligationError {
+    /// Ambiguity can happen when monomorphizing during trans
+    /// expands to some humongous type that never occurred
+    /// statically -- this humongous type can then overflow,
+    /// leading to an ambiguous result. So report this as an
+    /// overflow bug, since I believe this is the only case
+    /// where ambiguity can result.
+    Ambiguity,
+    /// This can trigger when we probe for the source of a `'static` lifetime requirement
+    /// on a trait object: `impl Foo for dyn Trait {}` has an implicit `'static` bound.
+    /// This can also trigger when we have a global bound that is not actually satisfied,
+    /// but was included during typeck due to the trivial_bounds feature.
+    Unimplemented,
+    FulfillmentError,
+}
diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs
index c76a6542ca1..6ca630b74cc 100644
--- a/compiler/rustc_trait_selection/src/traits/codegen.rs
+++ b/compiler/rustc_trait_selection/src/traits/codegen.rs
@@ -3,13 +3,12 @@
 // seems likely that they should eventually be merged into more
 // general routines.
 
-use crate::infer::{InferCtxt, TyCtxtInferExt};
+use crate::infer::TyCtxtInferExt;
 use crate::traits::{
     FulfillmentContext, ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine,
     Unimplemented,
 };
-use rustc_errors::ErrorGuaranteed;
-use rustc_middle::ty::fold::TypeFoldable;
+use rustc_middle::traits::CodegenObligationError;
 use rustc_middle::ty::{self, TyCtxt};
 
 /// Attempts to resolve an obligation to an `ImplSource`. The result is
@@ -23,7 +22,7 @@ use rustc_middle::ty::{self, TyCtxt};
 pub fn codegen_fulfill_obligation<'tcx>(
     tcx: TyCtxt<'tcx>,
     (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>),
-) -> Result<&'tcx ImplSource<'tcx, ()>, ErrorGuaranteed> {
+) -> Result<&'tcx ImplSource<'tcx, ()>, CodegenObligationError> {
     // Remove any references to regions; this helps improve caching.
     let trait_ref = tcx.erase_regions(trait_ref);
     // We expect the input to be fully normalized.
@@ -40,37 +39,8 @@ pub fn codegen_fulfill_obligation<'tcx>(
 
         let selection = match selcx.select(&obligation) {
             Ok(Some(selection)) => selection,
-            Ok(None) => {
-                // Ambiguity can happen when monomorphizing during trans
-                // expands to some humongous type that never occurred
-                // statically -- this humongous type can then overflow,
-                // leading to an ambiguous result. So report this as an
-                // overflow bug, since I believe this is the only case
-                // where ambiguity can result.
-                let reported = infcx.tcx.sess.delay_span_bug(
-                    rustc_span::DUMMY_SP,
-                    &format!(
-                        "encountered ambiguity selecting `{:?}` during codegen, presuming due to \
-                         overflow or prior type error",
-                        trait_ref
-                    ),
-                );
-                return Err(reported);
-            }
-            Err(Unimplemented) => {
-                // This can trigger when we probe for the source of a `'static` lifetime requirement
-                // on a trait object: `impl Foo for dyn Trait {}` has an implicit `'static` bound.
-                // This can also trigger when we have a global bound that is not actually satisfied,
-                // but was included during typeck due to the trivial_bounds feature.
-                let guar = infcx.tcx.sess.delay_span_bug(
-                    rustc_span::DUMMY_SP,
-                    &format!(
-                        "Encountered error `Unimplemented` selecting `{:?}` during codegen",
-                        trait_ref
-                    ),
-                );
-                return Err(guar);
-            }
+            Ok(None) => return Err(CodegenObligationError::Ambiguity),
+            Err(Unimplemented) => return Err(CodegenObligationError::Unimplemented),
             Err(e) => {
                 bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref)
             }
@@ -85,7 +55,17 @@ pub fn codegen_fulfill_obligation<'tcx>(
         let impl_source = selection.map(|predicate| {
             fulfill_cx.register_predicate_obligation(&infcx, predicate);
         });
-        let impl_source = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, impl_source);
+
+        // In principle, we only need to do this so long as `impl_source`
+        // contains unbound type parameters. It could be a slight
+        // optimization to stop iterating early.
+        let errors = fulfill_cx.select_all_or_error(&infcx);
+        if !errors.is_empty() {
+            return Err(CodegenObligationError::FulfillmentError);
+        }
+
+        let impl_source = infcx.resolve_vars_if_possible(impl_source);
+        let impl_source = infcx.tcx.erase_regions(impl_source);
 
         // Opaque types may have gotten their hidden types constrained, but we can ignore them safely
         // as they will get constrained elsewhere, too.
@@ -95,42 +75,3 @@ pub fn codegen_fulfill_obligation<'tcx>(
         Ok(&*tcx.arena.alloc(impl_source))
     })
 }
-
-// # Global Cache
-
-/// Finishes processes any obligations that remain in the
-/// fulfillment context, and then returns the result with all type
-/// variables removed and regions erased. Because this is intended
-/// for use outside of type inference, if any errors occur,
-/// it will panic. It is used during normalization and other cases
-/// where processing the obligations in `fulfill_cx` may cause
-/// type inference variables that appear in `result` to be
-/// unified, and hence we need to process those obligations to get
-/// the complete picture of the type.
-fn drain_fulfillment_cx_or_panic<'tcx, T>(
-    infcx: &InferCtxt<'_, 'tcx>,
-    fulfill_cx: &mut FulfillmentContext<'tcx>,
-    result: T,
-) -> T
-where
-    T: TypeFoldable<'tcx>,
-{
-    debug!("drain_fulfillment_cx_or_panic()");
-
-    // In principle, we only need to do this so long as `result`
-    // contains unbound type parameters. It could be a slight
-    // optimization to stop iterating early.
-    let errors = fulfill_cx.select_all_or_error(infcx);
-    if !errors.is_empty() {
-        infcx.tcx.sess.delay_span_bug(
-            rustc_span::DUMMY_SP,
-            &format!(
-                "Encountered errors `{:?}` resolving bounds outside of type inference",
-                errors
-            ),
-        );
-    }
-
-    let result = infcx.resolve_vars_if_possible(result);
-    infcx.tcx.erase_regions(result)
-}
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index 802a59abe5f..143081d61fb 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -1,6 +1,7 @@
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_infer::infer::TyCtxtInferExt;
+use rustc_middle::traits::CodegenObligationError;
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{self, Binder, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitor};
 use rustc_span::{sym, DUMMY_SP};
@@ -212,7 +213,22 @@ fn resolve_associated_item<'tcx>(
     let mut bound_vars_collector = BoundVarsCollector::new();
     trait_ref.visit_with(&mut bound_vars_collector);
     let trait_binder = ty::Binder::bind_with_vars(trait_ref, bound_vars_collector.into_vars(tcx));
-    let vtbl = tcx.codegen_fulfill_obligation((param_env, trait_binder))?;
+    let vtbl = match tcx.codegen_fulfill_obligation((param_env, trait_binder)) {
+        Ok(vtbl) => vtbl,
+        Err(CodegenObligationError::Ambiguity) => {
+            let reported = tcx.sess.delay_span_bug(
+                tcx.def_span(trait_item_id),
+                &format!(
+                    "encountered ambiguity selecting `{:?}` during codegen, presuming due to \
+                     overflow or prior type error",
+                    trait_binder
+                ),
+            );
+            return Err(reported);
+        }
+        Err(CodegenObligationError::Unimplemented) => return Ok(None),
+        Err(CodegenObligationError::FulfillmentError) => return Ok(None),
+    };
 
     // Now that we know which impl is being used, we can dispatch to
     // the actual function: