1 use super::callee::DeferredCallResolution; 2 3 use rustc_data_structures::fx::{FxHashMap, FxHashSet}; 4 use rustc_hir as hir; 5 use rustc_hir::def_id::LocalDefId; 6 use rustc_hir::HirIdMap; 7 use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt}; 8 use rustc_middle::traits::DefiningAnchor; 9 use rustc_middle::ty::visit::TypeVisitableExt; 10 use rustc_middle::ty::{self, Ty, TyCtxt}; 11 use rustc_span::def_id::LocalDefIdMap; 12 use rustc_span::{self, Span}; 13 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; 14 use rustc_trait_selection::traits::{self, PredicateObligation, TraitEngine, TraitEngineExt as _}; 15 16 use std::cell::RefCell; 17 use std::ops::Deref; 18 19 /// Closures defined within the function. For example: 20 /// ```ignore (illustrative) 21 /// fn foo() { 22 /// bar(move|| { ... }) 23 /// } 24 /// ``` 25 /// Here, the function `foo()` and the closure passed to 26 /// `bar()` will each have their own `FnCtxt`, but they will 27 /// share the inherited fields. 28 pub struct Inherited<'tcx> { 29 pub(super) infcx: InferCtxt<'tcx>, 30 31 pub(super) typeck_results: RefCell<ty::TypeckResults<'tcx>>, 32 33 pub(super) locals: RefCell<HirIdMap<Ty<'tcx>>>, 34 35 pub(super) fulfillment_cx: RefCell<Box<dyn TraitEngine<'tcx>>>, 36 37 /// Some additional `Sized` obligations badly affect type inference. 38 /// These obligations are added in a later stage of typeck. 39 /// Removing these may also cause additional complications, see #101066. 40 pub(super) deferred_sized_obligations: 41 RefCell<Vec<(Ty<'tcx>, Span, traits::ObligationCauseCode<'tcx>)>>, 42 43 /// When we process a call like `c()` where `c` is a closure type, 44 /// we may not have decided yet whether `c` is a `Fn`, `FnMut`, or 45 /// `FnOnce` closure. In that case, we defer full resolution of the 46 /// call until upvar inference can kick in and make the 47 /// decision. We keep these deferred resolutions grouped by the 48 /// def-id of the closure, so that once we decide, we can easily go 49 /// back and process them. 50 pub(super) deferred_call_resolutions: RefCell<LocalDefIdMap<Vec<DeferredCallResolution<'tcx>>>>, 51 52 pub(super) deferred_cast_checks: RefCell<Vec<super::cast::CastCheck<'tcx>>>, 53 54 pub(super) deferred_transmute_checks: RefCell<Vec<(Ty<'tcx>, Ty<'tcx>, hir::HirId)>>, 55 56 pub(super) deferred_asm_checks: RefCell<Vec<(&'tcx hir::InlineAsm<'tcx>, hir::HirId)>>, 57 58 pub(super) deferred_generator_interiors: 59 RefCell<Vec<(LocalDefId, hir::BodyId, Ty<'tcx>, hir::GeneratorKind)>>, 60 61 /// Whenever we introduce an adjustment from `!` into a type variable, 62 /// we record that type variable here. This is later used to inform 63 /// fallback. See the `fallback` module for details. 64 pub(super) diverging_type_vars: RefCell<FxHashSet<Ty<'tcx>>>, 65 66 pub(super) infer_var_info: RefCell<FxHashMap<ty::TyVid, ty::InferVarInfo>>, 67 } 68 69 impl<'tcx> Deref for Inherited<'tcx> { 70 type Target = InferCtxt<'tcx>; deref(&self) -> &Self::Target71 fn deref(&self) -> &Self::Target { 72 &self.infcx 73 } 74 } 75 76 impl<'tcx> Inherited<'tcx> { new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self77 pub fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self { 78 let hir_owner = tcx.hir().local_def_id_to_hir_id(def_id).owner; 79 80 let infcx = tcx 81 .infer_ctxt() 82 .ignoring_regions() 83 .with_opaque_type_inference(DefiningAnchor::Bind(def_id)) 84 .build(); 85 let typeck_results = RefCell::new(ty::TypeckResults::new(hir_owner)); 86 87 Inherited { 88 typeck_results, 89 fulfillment_cx: RefCell::new(<dyn TraitEngine<'_>>::new(&infcx)), 90 infcx, 91 locals: RefCell::new(Default::default()), 92 deferred_sized_obligations: RefCell::new(Vec::new()), 93 deferred_call_resolutions: RefCell::new(Default::default()), 94 deferred_cast_checks: RefCell::new(Vec::new()), 95 deferred_transmute_checks: RefCell::new(Vec::new()), 96 deferred_asm_checks: RefCell::new(Vec::new()), 97 deferred_generator_interiors: RefCell::new(Vec::new()), 98 diverging_type_vars: RefCell::new(Default::default()), 99 infer_var_info: RefCell::new(Default::default()), 100 } 101 } 102 103 #[instrument(level = "debug", skip(self))] register_predicate(&self, obligation: traits::PredicateObligation<'tcx>)104 pub(super) fn register_predicate(&self, obligation: traits::PredicateObligation<'tcx>) { 105 if obligation.has_escaping_bound_vars() { 106 span_bug!(obligation.cause.span, "escaping bound vars in predicate {:?}", obligation); 107 } 108 109 self.update_infer_var_info(&obligation); 110 111 self.fulfillment_cx.borrow_mut().register_predicate_obligation(self, obligation); 112 } 113 register_predicates<I>(&self, obligations: I) where I: IntoIterator<Item = traits::PredicateObligation<'tcx>>,114 pub(super) fn register_predicates<I>(&self, obligations: I) 115 where 116 I: IntoIterator<Item = traits::PredicateObligation<'tcx>>, 117 { 118 for obligation in obligations { 119 self.register_predicate(obligation); 120 } 121 } 122 register_infer_ok_obligations<T>(&self, infer_ok: InferOk<'tcx, T>) -> T123 pub(super) fn register_infer_ok_obligations<T>(&self, infer_ok: InferOk<'tcx, T>) -> T { 124 self.register_predicates(infer_ok.obligations); 125 infer_ok.value 126 } 127 update_infer_var_info(&self, obligation: &PredicateObligation<'tcx>)128 pub fn update_infer_var_info(&self, obligation: &PredicateObligation<'tcx>) { 129 let infer_var_info = &mut self.infer_var_info.borrow_mut(); 130 131 // (*) binder skipped 132 if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(tpred)) = obligation.predicate.kind().skip_binder() 133 && let Some(ty) = self.shallow_resolve(tpred.self_ty()).ty_vid().map(|t| self.root_var(t)) 134 && self.tcx.lang_items().sized_trait().is_some_and(|st| st != tpred.trait_ref.def_id) 135 { 136 let new_self_ty = self.tcx.types.unit; 137 138 // Then construct a new obligation with Self = () added 139 // to the ParamEnv, and see if it holds. 140 let o = obligation.with(self.tcx, 141 obligation 142 .predicate 143 .kind() 144 .rebind( 145 // (*) binder moved here 146 ty::PredicateKind::Clause(ty::ClauseKind::Trait(tpred.with_self_ty(self.tcx, new_self_ty))) 147 ), 148 ); 149 // Don't report overflow errors. Otherwise equivalent to may_hold. 150 if let Ok(result) = self.probe(|_| self.evaluate_obligation(&o)) && result.may_apply() { 151 infer_var_info.entry(ty).or_default().self_in_trait = true; 152 } 153 } 154 155 if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(predicate)) = 156 obligation.predicate.kind().skip_binder() 157 { 158 // If the projection predicate (Foo::Bar == X) has X as a non-TyVid, 159 // we need to make it into one. 160 if let Some(vid) = predicate.term.ty().and_then(|ty| ty.ty_vid()) { 161 debug!("infer_var_info: {:?}.output = true", vid); 162 infer_var_info.entry(vid).or_default().output = true; 163 } 164 } 165 } 166 } 167