1 use std::fmt; 2 3 use rustc_errors::ErrorGuaranteed; 4 use rustc_infer::infer::canonical::Canonical; 5 use rustc_middle::mir::ConstraintCategory; 6 use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable}; 7 use rustc_span::def_id::DefId; 8 use rustc_span::Span; 9 use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput}; 10 use rustc_trait_selection::traits::ObligationCause; 11 12 use crate::diagnostics::{ToUniverseInfo, UniverseInfo}; 13 14 use super::{Locations, NormalizeLocation, TypeChecker}; 15 16 impl<'a, 'tcx> TypeChecker<'a, 'tcx> { 17 /// Given some operation `op` that manipulates types, proves 18 /// predicates, or otherwise uses the inference context, executes 19 /// `op` and then executes all the further obligations that `op` 20 /// returns. This will yield a set of outlives constraints amongst 21 /// regions which are extracted and stored as having occurred at 22 /// `locations`. 23 /// 24 /// **Any `rustc_infer::infer` operations that might generate region 25 /// constraints should occur within this method so that those 26 /// constraints can be properly localized!** 27 #[instrument(skip(self, op), level = "trace")] fully_perform_op<R: fmt::Debug, Op>( &mut self, locations: Locations, category: ConstraintCategory<'tcx>, op: Op, ) -> Result<R, ErrorGuaranteed> where Op: type_op::TypeOp<'tcx, Output = R>, Op::ErrorInfo: ToUniverseInfo<'tcx>,28 pub(super) fn fully_perform_op<R: fmt::Debug, Op>( 29 &mut self, 30 locations: Locations, 31 category: ConstraintCategory<'tcx>, 32 op: Op, 33 ) -> Result<R, ErrorGuaranteed> 34 where 35 Op: type_op::TypeOp<'tcx, Output = R>, 36 Op::ErrorInfo: ToUniverseInfo<'tcx>, 37 { 38 let old_universe = self.infcx.universe(); 39 40 let TypeOpOutput { output, constraints, error_info } = 41 op.fully_perform(self.infcx, locations.span(self.body))?; 42 43 debug!(?output, ?constraints); 44 45 if let Some(data) = constraints { 46 self.push_region_constraints(locations, category, data); 47 } 48 49 let universe = self.infcx.universe(); 50 51 if old_universe != universe { 52 let universe_info = match error_info { 53 Some(error_info) => error_info.to_universe_info(old_universe), 54 None => UniverseInfo::other(), 55 }; 56 for u in (old_universe + 1)..=universe { 57 self.borrowck_context.constraints.universe_causes.insert(u, universe_info.clone()); 58 } 59 } 60 61 Ok(output) 62 } 63 instantiate_canonical_with_fresh_inference_vars<T>( &mut self, span: Span, canonical: &Canonical<'tcx, T>, ) -> T where T: TypeFoldable<TyCtxt<'tcx>>,64 pub(super) fn instantiate_canonical_with_fresh_inference_vars<T>( 65 &mut self, 66 span: Span, 67 canonical: &Canonical<'tcx, T>, 68 ) -> T 69 where 70 T: TypeFoldable<TyCtxt<'tcx>>, 71 { 72 let old_universe = self.infcx.universe(); 73 74 let (instantiated, _) = 75 self.infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical); 76 77 for u in (old_universe + 1)..=self.infcx.universe() { 78 self.borrowck_context.constraints.universe_causes.insert(u, UniverseInfo::other()); 79 } 80 81 instantiated 82 } 83 84 #[instrument(skip(self), level = "debug")] prove_trait_ref( &mut self, trait_ref: ty::TraitRef<'tcx>, locations: Locations, category: ConstraintCategory<'tcx>, )85 pub(super) fn prove_trait_ref( 86 &mut self, 87 trait_ref: ty::TraitRef<'tcx>, 88 locations: Locations, 89 category: ConstraintCategory<'tcx>, 90 ) { 91 self.prove_predicate( 92 ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::Trait( 93 ty::TraitPredicate { 94 trait_ref, 95 constness: ty::BoundConstness::NotConst, 96 polarity: ty::ImplPolarity::Positive, 97 }, 98 ))), 99 locations, 100 category, 101 ); 102 } 103 104 #[instrument(level = "debug", skip(self))] normalize_and_prove_instantiated_predicates( &mut self, _def_id: DefId, instantiated_predicates: ty::InstantiatedPredicates<'tcx>, locations: Locations, )105 pub(super) fn normalize_and_prove_instantiated_predicates( 106 &mut self, 107 // Keep this parameter for now, in case we start using 108 // it in `ConstraintCategory` at some point. 109 _def_id: DefId, 110 instantiated_predicates: ty::InstantiatedPredicates<'tcx>, 111 locations: Locations, 112 ) { 113 for (predicate, span) in instantiated_predicates { 114 debug!(?predicate); 115 let category = ConstraintCategory::Predicate(span); 116 let predicate = self.normalize_with_category(predicate, locations, category); 117 self.prove_predicate(predicate, locations, category); 118 } 119 } 120 prove_predicates( &mut self, predicates: impl IntoIterator<Item: ToPredicate<'tcx> + std::fmt::Debug>, locations: Locations, category: ConstraintCategory<'tcx>, )121 pub(super) fn prove_predicates( 122 &mut self, 123 predicates: impl IntoIterator<Item: ToPredicate<'tcx> + std::fmt::Debug>, 124 locations: Locations, 125 category: ConstraintCategory<'tcx>, 126 ) { 127 for predicate in predicates { 128 self.prove_predicate(predicate, locations, category); 129 } 130 } 131 132 #[instrument(skip(self), level = "debug")] prove_predicate( &mut self, predicate: impl ToPredicate<'tcx> + std::fmt::Debug, locations: Locations, category: ConstraintCategory<'tcx>, )133 pub(super) fn prove_predicate( 134 &mut self, 135 predicate: impl ToPredicate<'tcx> + std::fmt::Debug, 136 locations: Locations, 137 category: ConstraintCategory<'tcx>, 138 ) { 139 let param_env = self.param_env; 140 let predicate = predicate.to_predicate(self.tcx()); 141 let _: Result<_, ErrorGuaranteed> = self.fully_perform_op( 142 locations, 143 category, 144 param_env.and(type_op::prove_predicate::ProvePredicate::new(predicate)), 145 ); 146 } 147 normalize<T>(&mut self, value: T, location: impl NormalizeLocation) -> T where T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,148 pub(super) fn normalize<T>(&mut self, value: T, location: impl NormalizeLocation) -> T 149 where 150 T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx, 151 { 152 self.normalize_with_category(value, location, ConstraintCategory::Boring) 153 } 154 155 #[instrument(skip(self), level = "debug")] normalize_with_category<T>( &mut self, value: T, location: impl NormalizeLocation, category: ConstraintCategory<'tcx>, ) -> T where T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,156 pub(super) fn normalize_with_category<T>( 157 &mut self, 158 value: T, 159 location: impl NormalizeLocation, 160 category: ConstraintCategory<'tcx>, 161 ) -> T 162 where 163 T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx, 164 { 165 let param_env = self.param_env; 166 let result: Result<_, ErrorGuaranteed> = self.fully_perform_op( 167 location.to_locations(), 168 category, 169 param_env.and(type_op::normalize::Normalize::new(value)), 170 ); 171 result.unwrap_or(value) 172 } 173 174 #[instrument(skip(self), level = "debug")] ascribe_user_type( &mut self, mir_ty: Ty<'tcx>, user_ty: ty::UserType<'tcx>, span: Span, )175 pub(super) fn ascribe_user_type( 176 &mut self, 177 mir_ty: Ty<'tcx>, 178 user_ty: ty::UserType<'tcx>, 179 span: Span, 180 ) { 181 let _: Result<_, ErrorGuaranteed> = self.fully_perform_op( 182 Locations::All(span), 183 ConstraintCategory::Boring, 184 self.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(mir_ty, user_ty)), 185 ); 186 } 187 188 /// *Incorrectly* skips the WF checks we normally do in `ascribe_user_type`. 189 /// 190 /// FIXME(#104478, #104477): This is a hack for backward-compatibility. 191 #[instrument(skip(self), level = "debug")] ascribe_user_type_skip_wf( &mut self, mir_ty: Ty<'tcx>, user_ty: ty::UserType<'tcx>, span: Span, )192 pub(super) fn ascribe_user_type_skip_wf( 193 &mut self, 194 mir_ty: Ty<'tcx>, 195 user_ty: ty::UserType<'tcx>, 196 span: Span, 197 ) { 198 let ty::UserType::Ty(user_ty) = user_ty else { bug!() }; 199 200 // A fast path for a common case with closure input/output types. 201 if let ty::Infer(_) = user_ty.kind() { 202 self.eq_types(user_ty, mir_ty, Locations::All(span), ConstraintCategory::Boring) 203 .unwrap(); 204 return; 205 } 206 207 // FIXME: Ideally MIR types are normalized, but this is not always true. 208 let mir_ty = self.normalize(mir_ty, Locations::All(span)); 209 210 let cause = ObligationCause::dummy_with_span(span); 211 let param_env = self.param_env; 212 let _: Result<_, ErrorGuaranteed> = self.fully_perform_op( 213 Locations::All(span), 214 ConstraintCategory::Boring, 215 type_op::custom::CustomTypeOp::new( 216 |ocx| { 217 let user_ty = ocx.normalize(&cause, param_env, user_ty); 218 ocx.eq(&cause, param_env, user_ty, mir_ty)?; 219 Ok(()) 220 }, 221 "ascribe_user_type_skip_wf", 222 ), 223 ); 224 } 225 } 226