diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_middle/src/query/mod.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/traits/mod.rs | 18 | ||||
| -rw-r--r-- | compiler/rustc_trait_selection/src/traits/codegen.rs | 91 | ||||
| -rw-r--r-- | compiler/rustc_ty_utils/src/instance.rs | 18 |
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: |
