1 use std::cell::RefCell; 2 use std::fmt::Debug; 3 4 use super::FulfillmentContext; 5 use super::TraitEngine; 6 use crate::solve::FulfillmentCtxt as NextFulfillmentCtxt; 7 use crate::traits::error_reporting::TypeErrCtxtExt; 8 use crate::traits::NormalizeExt; 9 use rustc_data_structures::fx::FxIndexSet; 10 use rustc_errors::ErrorGuaranteed; 11 use rustc_hir::def_id::{DefId, LocalDefId}; 12 use rustc_infer::infer::at::ToTrace; 13 use rustc_infer::infer::canonical::{ 14 Canonical, CanonicalQueryResponse, CanonicalVarValues, QueryResponse, 15 }; 16 use rustc_infer::infer::outlives::env::OutlivesEnvironment; 17 use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk}; 18 use rustc_infer::traits::{ 19 FulfillmentError, Obligation, ObligationCause, PredicateObligation, TraitEngineExt as _, 20 }; 21 use rustc_middle::arena::ArenaAllocatable; 22 use rustc_middle::traits::query::NoSolution; 23 use rustc_middle::ty::error::TypeError; 24 use rustc_middle::ty::ToPredicate; 25 use rustc_middle::ty::TypeFoldable; 26 use rustc_middle::ty::{self, Ty, TyCtxt}; 27 use rustc_session::config::TraitSolver; 28 29 pub trait TraitEngineExt<'tcx> { new(infcx: &InferCtxt<'tcx>) -> Box<Self>30 fn new(infcx: &InferCtxt<'tcx>) -> Box<Self>; 31 } 32 33 impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> { new(infcx: &InferCtxt<'tcx>) -> Box<Self>34 fn new(infcx: &InferCtxt<'tcx>) -> Box<Self> { 35 match (infcx.tcx.sess.opts.unstable_opts.trait_solver, infcx.next_trait_solver()) { 36 (TraitSolver::Classic, false) | (TraitSolver::NextCoherence, false) => { 37 Box::new(FulfillmentContext::new(infcx)) 38 } 39 (TraitSolver::Next | TraitSolver::NextCoherence, true) => { 40 Box::new(NextFulfillmentCtxt::new(infcx)) 41 } 42 _ => bug!( 43 "incompatible combination of -Ztrait-solver flag ({:?}) and InferCtxt::next_trait_solver ({:?})", 44 infcx.tcx.sess.opts.unstable_opts.trait_solver, 45 infcx.next_trait_solver() 46 ), 47 } 48 } 49 } 50 51 /// Used if you want to have pleasant experience when dealing 52 /// with obligations outside of hir or mir typeck. 53 pub struct ObligationCtxt<'a, 'tcx> { 54 pub infcx: &'a InferCtxt<'tcx>, 55 engine: RefCell<Box<dyn TraitEngine<'tcx>>>, 56 } 57 58 impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { new(infcx: &'a InferCtxt<'tcx>) -> Self59 pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self { 60 Self { infcx, engine: RefCell::new(<dyn TraitEngine<'_>>::new(infcx)) } 61 } 62 register_obligation(&self, obligation: PredicateObligation<'tcx>)63 pub fn register_obligation(&self, obligation: PredicateObligation<'tcx>) { 64 self.engine.borrow_mut().register_predicate_obligation(self.infcx, obligation); 65 } 66 register_obligations( &self, obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>, )67 pub fn register_obligations( 68 &self, 69 obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>, 70 ) { 71 // Can't use `register_predicate_obligations` because the iterator 72 // may also use this `ObligationCtxt`. 73 for obligation in obligations { 74 self.engine.borrow_mut().register_predicate_obligation(self.infcx, obligation) 75 } 76 } 77 register_infer_ok_obligations<T>(&self, infer_ok: InferOk<'tcx, T>) -> T78 pub fn register_infer_ok_obligations<T>(&self, infer_ok: InferOk<'tcx, T>) -> T { 79 let InferOk { value, obligations } = infer_ok; 80 self.engine.borrow_mut().register_predicate_obligations(self.infcx, obligations); 81 value 82 } 83 84 /// Requires that `ty` must implement the trait with `def_id` in 85 /// the given environment. This trait must not have any type 86 /// parameters (except for `Self`). register_bound( &self, cause: ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>, def_id: DefId, )87 pub fn register_bound( 88 &self, 89 cause: ObligationCause<'tcx>, 90 param_env: ty::ParamEnv<'tcx>, 91 ty: Ty<'tcx>, 92 def_id: DefId, 93 ) { 94 let tcx = self.infcx.tcx; 95 let trait_ref = ty::TraitRef::new(tcx, def_id, [ty]); 96 self.register_obligation(Obligation { 97 cause, 98 recursion_depth: 0, 99 param_env, 100 predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx), 101 }); 102 } 103 normalize<T: TypeFoldable<TyCtxt<'tcx>>>( &self, cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, value: T, ) -> T104 pub fn normalize<T: TypeFoldable<TyCtxt<'tcx>>>( 105 &self, 106 cause: &ObligationCause<'tcx>, 107 param_env: ty::ParamEnv<'tcx>, 108 value: T, 109 ) -> T { 110 let infer_ok = self.infcx.at(&cause, param_env).normalize(value); 111 self.register_infer_ok_obligations(infer_ok) 112 } 113 114 /// Makes `expected <: actual`. eq_exp<T>( &self, cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, a_is_expected: bool, a: T, b: T, ) -> Result<(), TypeError<'tcx>> where T: ToTrace<'tcx>,115 pub fn eq_exp<T>( 116 &self, 117 cause: &ObligationCause<'tcx>, 118 param_env: ty::ParamEnv<'tcx>, 119 a_is_expected: bool, 120 a: T, 121 b: T, 122 ) -> Result<(), TypeError<'tcx>> 123 where 124 T: ToTrace<'tcx>, 125 { 126 self.infcx 127 .at(cause, param_env) 128 .eq_exp(DefineOpaqueTypes::Yes, a_is_expected, a, b) 129 .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) 130 } 131 eq<T: ToTrace<'tcx>>( &self, cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, expected: T, actual: T, ) -> Result<(), TypeError<'tcx>>132 pub fn eq<T: ToTrace<'tcx>>( 133 &self, 134 cause: &ObligationCause<'tcx>, 135 param_env: ty::ParamEnv<'tcx>, 136 expected: T, 137 actual: T, 138 ) -> Result<(), TypeError<'tcx>> { 139 self.infcx 140 .at(cause, param_env) 141 .eq(DefineOpaqueTypes::Yes, expected, actual) 142 .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) 143 } 144 145 /// Checks whether `expected` is a subtype of `actual`: `expected <: actual`. sub<T: ToTrace<'tcx>>( &self, cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, expected: T, actual: T, ) -> Result<(), TypeError<'tcx>>146 pub fn sub<T: ToTrace<'tcx>>( 147 &self, 148 cause: &ObligationCause<'tcx>, 149 param_env: ty::ParamEnv<'tcx>, 150 expected: T, 151 actual: T, 152 ) -> Result<(), TypeError<'tcx>> { 153 self.infcx 154 .at(cause, param_env) 155 .sub(DefineOpaqueTypes::Yes, expected, actual) 156 .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) 157 } 158 159 /// Checks whether `expected` is a supertype of `actual`: `expected :> actual`. sup<T: ToTrace<'tcx>>( &self, cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, expected: T, actual: T, ) -> Result<(), TypeError<'tcx>>160 pub fn sup<T: ToTrace<'tcx>>( 161 &self, 162 cause: &ObligationCause<'tcx>, 163 param_env: ty::ParamEnv<'tcx>, 164 expected: T, 165 actual: T, 166 ) -> Result<(), TypeError<'tcx>> { 167 self.infcx 168 .at(cause, param_env) 169 .sup(DefineOpaqueTypes::Yes, expected, actual) 170 .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) 171 } 172 173 #[must_use] select_where_possible(&self) -> Vec<FulfillmentError<'tcx>>174 pub fn select_where_possible(&self) -> Vec<FulfillmentError<'tcx>> { 175 self.engine.borrow_mut().select_where_possible(self.infcx) 176 } 177 178 #[must_use] select_all_or_error(&self) -> Vec<FulfillmentError<'tcx>>179 pub fn select_all_or_error(&self) -> Vec<FulfillmentError<'tcx>> { 180 self.engine.borrow_mut().select_all_or_error(self.infcx) 181 } 182 183 /// Resolves regions and reports errors. 184 /// 185 /// Takes ownership of the context as doing trait solving afterwards 186 /// will result in region constraints getting ignored. resolve_regions_and_report_errors( self, generic_param_scope: LocalDefId, outlives_env: &OutlivesEnvironment<'tcx>, ) -> Result<(), ErrorGuaranteed>187 pub fn resolve_regions_and_report_errors( 188 self, 189 generic_param_scope: LocalDefId, 190 outlives_env: &OutlivesEnvironment<'tcx>, 191 ) -> Result<(), ErrorGuaranteed> { 192 let errors = self.infcx.resolve_regions(&outlives_env); 193 if errors.is_empty() { 194 Ok(()) 195 } else { 196 Err(self.infcx.err_ctxt().report_region_errors(generic_param_scope, &errors)) 197 } 198 } 199 assumed_wf_types_and_report_errors( &self, param_env: ty::ParamEnv<'tcx>, def_id: LocalDefId, ) -> Result<FxIndexSet<Ty<'tcx>>, ErrorGuaranteed>200 pub fn assumed_wf_types_and_report_errors( 201 &self, 202 param_env: ty::ParamEnv<'tcx>, 203 def_id: LocalDefId, 204 ) -> Result<FxIndexSet<Ty<'tcx>>, ErrorGuaranteed> { 205 self.assumed_wf_types(param_env, def_id) 206 .map_err(|errors| self.infcx.err_ctxt().report_fulfillment_errors(&errors)) 207 } 208 assumed_wf_types( &self, param_env: ty::ParamEnv<'tcx>, def_id: LocalDefId, ) -> Result<FxIndexSet<Ty<'tcx>>, Vec<FulfillmentError<'tcx>>>209 pub fn assumed_wf_types( 210 &self, 211 param_env: ty::ParamEnv<'tcx>, 212 def_id: LocalDefId, 213 ) -> Result<FxIndexSet<Ty<'tcx>>, Vec<FulfillmentError<'tcx>>> { 214 let tcx = self.infcx.tcx; 215 let mut implied_bounds = FxIndexSet::default(); 216 let mut errors = Vec::new(); 217 for &(ty, span) in tcx.assumed_wf_types(def_id) { 218 // FIXME(@lcnr): rustc currently does not check wf for types 219 // pre-normalization, meaning that implied bounds are sometimes 220 // incorrect. See #100910 for more details. 221 // 222 // Not adding the unnormalized types here mostly fixes that, except 223 // that there are projections which are still ambiguous in the item definition 224 // but do normalize successfully when using the item, see #98543. 225 // 226 // Anyways, I will hopefully soon change implied bounds to make all of this 227 // sound and then uncomment this line again. 228 229 // implied_bounds.insert(ty); 230 let cause = ObligationCause::misc(span, def_id); 231 match self 232 .infcx 233 .at(&cause, param_env) 234 .deeply_normalize(ty, &mut **self.engine.borrow_mut()) 235 { 236 // Insert well-formed types, ignoring duplicates. 237 Ok(normalized) => drop(implied_bounds.insert(normalized)), 238 Err(normalization_errors) => errors.extend(normalization_errors), 239 }; 240 } 241 242 if errors.is_empty() { Ok(implied_bounds) } else { Err(errors) } 243 } 244 make_canonicalized_query_response<T>( &self, inference_vars: CanonicalVarValues<'tcx>, answer: T, ) -> Result<CanonicalQueryResponse<'tcx, T>, NoSolution> where T: Debug + TypeFoldable<TyCtxt<'tcx>>, Canonical<'tcx, QueryResponse<'tcx, T>>: ArenaAllocatable<'tcx>,245 pub fn make_canonicalized_query_response<T>( 246 &self, 247 inference_vars: CanonicalVarValues<'tcx>, 248 answer: T, 249 ) -> Result<CanonicalQueryResponse<'tcx, T>, NoSolution> 250 where 251 T: Debug + TypeFoldable<TyCtxt<'tcx>>, 252 Canonical<'tcx, QueryResponse<'tcx, T>>: ArenaAllocatable<'tcx>, 253 { 254 self.infcx.make_canonicalized_query_response( 255 inference_vars, 256 answer, 257 &mut **self.engine.borrow_mut(), 258 ) 259 } 260 } 261