1 mod _impl; 2 mod adjust_fulfillment_errors; 3 mod arg_matrix; 4 mod checks; 5 mod suggestions; 6 7 pub use _impl::*; 8 use rustc_errors::ErrorGuaranteed; 9 pub use suggestions::*; 10 11 use crate::coercion::DynamicCoerceMany; 12 use crate::{Diverges, EnclosingBreakables, Inherited}; 13 use rustc_hir as hir; 14 use rustc_hir::def_id::{DefId, LocalDefId}; 15 use rustc_hir_analysis::astconv::AstConv; 16 use rustc_infer::infer; 17 use rustc_infer::infer::error_reporting::TypeErrCtxt; 18 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; 19 use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; 20 use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt}; 21 use rustc_session::Session; 22 use rustc_span::symbol::Ident; 23 use rustc_span::{self, Span, DUMMY_SP}; 24 use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode, ObligationCtxt}; 25 26 use std::cell::{Cell, RefCell}; 27 use std::ops::Deref; 28 29 /// The `FnCtxt` stores type-checking context needed to type-check bodies of 30 /// functions, closures, and `const`s, including performing type inference 31 /// with [`InferCtxt`]. 32 /// 33 /// This is in contrast to [`ItemCtxt`], which is used to type-check item *signatures* 34 /// and thus does not perform type inference. 35 /// 36 /// See [`ItemCtxt`]'s docs for more. 37 /// 38 /// [`ItemCtxt`]: rustc_hir_analysis::collect::ItemCtxt 39 /// [`InferCtxt`]: infer::InferCtxt 40 pub struct FnCtxt<'a, 'tcx> { 41 pub(super) body_id: LocalDefId, 42 43 /// The parameter environment used for proving trait obligations 44 /// in this function. This can change when we descend into 45 /// closures (as they bring new things into scope), hence it is 46 /// not part of `Inherited` (as of the time of this writing, 47 /// closures do not yet change the environment, but they will 48 /// eventually). 49 pub(super) param_env: ty::ParamEnv<'tcx>, 50 51 /// Number of errors that had been reported when we started 52 /// checking this function. On exit, if we find that *more* errors 53 /// have been reported, we will skip regionck and other work that 54 /// expects the types within the function to be consistent. 55 // FIXME(matthewjasper) This should not exist, and it's not correct 56 // if type checking is run in parallel. 57 err_count_on_creation: usize, 58 59 /// If `Some`, this stores coercion information for returned 60 /// expressions. If `None`, this is in a context where return is 61 /// inappropriate, such as a const expression. 62 /// 63 /// This is a `RefCell<DynamicCoerceMany>`, which means that we 64 /// can track all the return expressions and then use them to 65 /// compute a useful coercion from the set, similar to a match 66 /// expression or other branching context. You can use methods 67 /// like `expected_ty` to access the declared return type (if 68 /// any). 69 pub(super) ret_coercion: Option<RefCell<DynamicCoerceMany<'tcx>>>, 70 71 /// First span of a return site that we find. Used in error messages. 72 pub(super) ret_coercion_span: Cell<Option<Span>>, 73 74 pub(super) resume_yield_tys: Option<(Ty<'tcx>, Ty<'tcx>)>, 75 76 /// Whether the last checked node generates a divergence (e.g., 77 /// `return` will set this to `Always`). In general, when entering 78 /// an expression or other node in the tree, the initial value 79 /// indicates whether prior parts of the containing expression may 80 /// have diverged. It is then typically set to `Maybe` (and the 81 /// old value remembered) for processing the subparts of the 82 /// current expression. As each subpart is processed, they may set 83 /// the flag to `Always`, etc. Finally, at the end, we take the 84 /// result and "union" it with the original value, so that when we 85 /// return the flag indicates if any subpart of the parent 86 /// expression (up to and including this part) has diverged. So, 87 /// if you read it after evaluating a subexpression `X`, the value 88 /// you get indicates whether any subexpression that was 89 /// evaluating up to and including `X` diverged. 90 /// 91 /// We currently use this flag only for diagnostic purposes: 92 /// 93 /// - To warn about unreachable code: if, after processing a 94 /// sub-expression but before we have applied the effects of the 95 /// current node, we see that the flag is set to `Always`, we 96 /// can issue a warning. This corresponds to something like 97 /// `foo(return)`; we warn on the `foo()` expression. (We then 98 /// update the flag to `WarnedAlways` to suppress duplicate 99 /// reports.) Similarly, if we traverse to a fresh statement (or 100 /// tail expression) from an `Always` setting, we will issue a 101 /// warning. This corresponds to something like `{return; 102 /// foo();}` or `{return; 22}`, where we would warn on the 103 /// `foo()` or `22`. 104 /// 105 /// An expression represents dead code if, after checking it, 106 /// the diverges flag is set to something other than `Maybe`. 107 pub(super) diverges: Cell<Diverges>, 108 109 pub(super) enclosing_breakables: RefCell<EnclosingBreakables<'tcx>>, 110 111 pub(super) inh: &'a Inherited<'tcx>, 112 113 pub(super) fallback_has_occurred: Cell<bool>, 114 } 115 116 impl<'a, 'tcx> FnCtxt<'a, 'tcx> { new( inh: &'a Inherited<'tcx>, param_env: ty::ParamEnv<'tcx>, body_id: LocalDefId, ) -> FnCtxt<'a, 'tcx>117 pub fn new( 118 inh: &'a Inherited<'tcx>, 119 param_env: ty::ParamEnv<'tcx>, 120 body_id: LocalDefId, 121 ) -> FnCtxt<'a, 'tcx> { 122 FnCtxt { 123 body_id, 124 param_env, 125 err_count_on_creation: inh.tcx.sess.err_count(), 126 ret_coercion: None, 127 ret_coercion_span: Cell::new(None), 128 resume_yield_tys: None, 129 diverges: Cell::new(Diverges::Maybe), 130 enclosing_breakables: RefCell::new(EnclosingBreakables { 131 stack: Vec::new(), 132 by_id: Default::default(), 133 }), 134 inh, 135 fallback_has_occurred: Cell::new(false), 136 } 137 } 138 cause(&self, span: Span, code: ObligationCauseCode<'tcx>) -> ObligationCause<'tcx>139 pub fn cause(&self, span: Span, code: ObligationCauseCode<'tcx>) -> ObligationCause<'tcx> { 140 ObligationCause::new(span, self.body_id, code) 141 } 142 misc(&self, span: Span) -> ObligationCause<'tcx>143 pub fn misc(&self, span: Span) -> ObligationCause<'tcx> { 144 self.cause(span, ObligationCauseCode::MiscObligation) 145 } 146 sess(&self) -> &Session147 pub fn sess(&self) -> &Session { 148 &self.tcx.sess 149 } 150 151 /// Creates an `TypeErrCtxt` with a reference to the in-progress 152 /// `TypeckResults` which is used for diagnostics. 153 /// Use [`InferCtxt::err_ctxt`] to start one without a `TypeckResults`. 154 /// 155 /// [`InferCtxt::err_ctxt`]: infer::InferCtxt::err_ctxt err_ctxt(&'a self) -> TypeErrCtxt<'a, 'tcx>156 pub fn err_ctxt(&'a self) -> TypeErrCtxt<'a, 'tcx> { 157 TypeErrCtxt { 158 infcx: &self.infcx, 159 typeck_results: Some(self.typeck_results.borrow()), 160 fallback_has_occurred: self.fallback_has_occurred.get(), 161 normalize_fn_sig: Box::new(|fn_sig| { 162 if fn_sig.has_escaping_bound_vars() { 163 return fn_sig; 164 } 165 self.probe(|_| { 166 let ocx = ObligationCtxt::new(self); 167 let normalized_fn_sig = 168 ocx.normalize(&ObligationCause::dummy(), self.param_env, fn_sig); 169 if ocx.select_all_or_error().is_empty() { 170 let normalized_fn_sig = self.resolve_vars_if_possible(normalized_fn_sig); 171 if !normalized_fn_sig.has_infer() { 172 return normalized_fn_sig; 173 } 174 } 175 fn_sig 176 }) 177 }), 178 autoderef_steps: Box::new(|ty| { 179 let mut autoderef = self.autoderef(DUMMY_SP, ty).silence_errors(); 180 let mut steps = vec![]; 181 while let Some((ty, _)) = autoderef.next() { 182 steps.push((ty, autoderef.current_obligations())); 183 } 184 steps 185 }), 186 } 187 } 188 errors_reported_since_creation(&self) -> bool189 pub fn errors_reported_since_creation(&self) -> bool { 190 self.tcx.sess.err_count() > self.err_count_on_creation 191 } 192 next_root_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx>193 pub fn next_root_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> { 194 Ty::new_var(self.tcx, self.next_ty_var_id_in_universe(origin, ty::UniverseIndex::ROOT)) 195 } 196 } 197 198 impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> { 199 type Target = Inherited<'tcx>; deref(&self) -> &Self::Target200 fn deref(&self) -> &Self::Target { 201 &self.inh 202 } 203 } 204 205 impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { tcx<'b>(&'b self) -> TyCtxt<'tcx>206 fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { 207 self.tcx 208 } 209 item_def_id(&self) -> DefId210 fn item_def_id(&self) -> DefId { 211 self.body_id.to_def_id() 212 } 213 get_type_parameter_bounds( &self, _: Span, def_id: LocalDefId, _: Ident, ) -> ty::GenericPredicates<'tcx>214 fn get_type_parameter_bounds( 215 &self, 216 _: Span, 217 def_id: LocalDefId, 218 _: Ident, 219 ) -> ty::GenericPredicates<'tcx> { 220 let tcx = self.tcx; 221 let item_def_id = tcx.hir().ty_param_owner(def_id); 222 let generics = tcx.generics_of(item_def_id); 223 let index = generics.param_def_id_to_index[&def_id.to_def_id()]; 224 ty::GenericPredicates { 225 parent: None, 226 predicates: tcx.arena.alloc_from_iter( 227 self.param_env.caller_bounds().iter().filter_map(|predicate| { 228 match predicate.kind().skip_binder() { 229 ty::ClauseKind::Trait(data) if data.self_ty().is_param(index) => { 230 // HACK(eddyb) should get the original `Span`. 231 let span = tcx.def_span(def_id); 232 Some((predicate, span)) 233 } 234 _ => None, 235 } 236 }), 237 ), 238 } 239 } 240 re_infer(&self, def: Option<&ty::GenericParamDef>, span: Span) -> Option<ty::Region<'tcx>>241 fn re_infer(&self, def: Option<&ty::GenericParamDef>, span: Span) -> Option<ty::Region<'tcx>> { 242 let v = match def { 243 Some(def) => infer::EarlyBoundRegion(span, def.name), 244 None => infer::MiscVariable(span), 245 }; 246 Some(self.next_region_var(v)) 247 } 248 allow_ty_infer(&self) -> bool249 fn allow_ty_infer(&self) -> bool { 250 true 251 } 252 ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx>253 fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> { 254 match param { 255 Some(param) => self.var_for_def(span, param).as_type().unwrap(), 256 None => self.next_ty_var(TypeVariableOrigin { 257 kind: TypeVariableOriginKind::TypeInference, 258 span, 259 }), 260 } 261 } 262 ct_infer( &self, ty: Ty<'tcx>, param: Option<&ty::GenericParamDef>, span: Span, ) -> Const<'tcx>263 fn ct_infer( 264 &self, 265 ty: Ty<'tcx>, 266 param: Option<&ty::GenericParamDef>, 267 span: Span, 268 ) -> Const<'tcx> { 269 match param { 270 Some(param) => self.var_for_def(span, param).as_const().unwrap(), 271 None => self.next_const_var( 272 ty, 273 ConstVariableOrigin { kind: ConstVariableOriginKind::ConstInference, span }, 274 ), 275 } 276 } 277 projected_ty_from_poly_trait_ref( &self, span: Span, item_def_id: DefId, item_segment: &hir::PathSegment<'_>, poly_trait_ref: ty::PolyTraitRef<'tcx>, ) -> Ty<'tcx>278 fn projected_ty_from_poly_trait_ref( 279 &self, 280 span: Span, 281 item_def_id: DefId, 282 item_segment: &hir::PathSegment<'_>, 283 poly_trait_ref: ty::PolyTraitRef<'tcx>, 284 ) -> Ty<'tcx> { 285 let trait_ref = self.instantiate_binder_with_fresh_vars( 286 span, 287 infer::LateBoundRegionConversionTime::AssocTypeProjection(item_def_id), 288 poly_trait_ref, 289 ); 290 291 let item_substs = self.astconv().create_substs_for_associated_item( 292 span, 293 item_def_id, 294 item_segment, 295 trait_ref.substs, 296 ); 297 298 Ty::new_projection(self.tcx(), item_def_id, item_substs) 299 } 300 probe_adt(&self, span: Span, ty: Ty<'tcx>) -> Option<ty::AdtDef<'tcx>>301 fn probe_adt(&self, span: Span, ty: Ty<'tcx>) -> Option<ty::AdtDef<'tcx>> { 302 match ty.kind() { 303 ty::Adt(adt_def, _) => Some(*adt_def), 304 // FIXME(#104767): Should we handle bound regions here? 305 ty::Alias(ty::Projection | ty::Inherent, _) if !ty.has_escaping_bound_vars() => { 306 self.normalize(span, ty).ty_adt_def() 307 } 308 _ => None, 309 } 310 } 311 set_tainted_by_errors(&self, e: ErrorGuaranteed)312 fn set_tainted_by_errors(&self, e: ErrorGuaranteed) { 313 self.infcx.set_tainted_by_errors(e) 314 } 315 record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span)316 fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span) { 317 // FIXME: normalization and escaping regions 318 let ty = if !ty.has_escaping_bound_vars() { self.normalize(span, ty) } else { ty }; 319 self.write_ty(hir_id, ty) 320 } 321 infcx(&self) -> Option<&infer::InferCtxt<'tcx>>322 fn infcx(&self) -> Option<&infer::InferCtxt<'tcx>> { 323 Some(&self.infcx) 324 } 325 } 326 327 /// Represents a user-provided type in the raw form (never normalized). 328 /// 329 /// This is a bridge between the interface of `AstConv`, which outputs a raw `Ty`, 330 /// and the API in this module, which expect `Ty` to be fully normalized. 331 #[derive(Clone, Copy, Debug)] 332 pub struct RawTy<'tcx> { 333 pub raw: Ty<'tcx>, 334 335 /// The normalized form of `raw`, stored here for efficiency. 336 pub normalized: Ty<'tcx>, 337 } 338