1 mod _impl; 2 mod checks; 3 mod suggestions; 4 5 pub use _impl::*; 6 pub use checks::*; 7 pub use suggestions::*; 8 9 use crate::astconv::AstConv; 10 use crate::check::coercion::DynamicCoerceMany; 11 use crate::check::{Diverges, EnclosingBreakables, Inherited, UnsafetyState}; 12 13 use rustc_hir as hir; 14 use rustc_hir::def_id::DefId; 15 use rustc_infer::infer; 16 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; 17 use rustc_infer::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; 18 use rustc_middle::ty::fold::TypeFoldable; 19 use rustc_middle::ty::subst::GenericArgKind; 20 use rustc_middle::ty::{self, Const, Ty, TyCtxt}; 21 use rustc_session::Session; 22 use rustc_span::symbol::Ident; 23 use rustc_span::{self, Span}; 24 use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode}; 25 26 use std::cell::{Cell, RefCell}; 27 use std::ops::Deref; 28 29 pub struct FnCtxt<'a, 'tcx> { 30 pub(super) body_id: hir::HirId, 31 32 /// The parameter environment used for proving trait obligations 33 /// in this function. This can change when we descend into 34 /// closures (as they bring new things into scope), hence it is 35 /// not part of `Inherited` (as of the time of this writing, 36 /// closures do not yet change the environment, but they will 37 /// eventually). 38 pub(super) param_env: ty::ParamEnv<'tcx>, 39 40 /// Number of errors that had been reported when we started 41 /// checking this function. On exit, if we find that *more* errors 42 /// have been reported, we will skip regionck and other work that 43 /// expects the types within the function to be consistent. 44 // FIXME(matthewjasper) This should not exist, and it's not correct 45 // if type checking is run in parallel. 46 err_count_on_creation: usize, 47 48 /// If `Some`, this stores coercion information for returned 49 /// expressions. If `None`, this is in a context where return is 50 /// inappropriate, such as a const expression. 51 /// 52 /// This is a `RefCell<DynamicCoerceMany>`, which means that we 53 /// can track all the return expressions and then use them to 54 /// compute a useful coercion from the set, similar to a match 55 /// expression or other branching context. You can use methods 56 /// like `expected_ty` to access the declared return type (if 57 /// any). 58 pub(super) ret_coercion: Option<RefCell<DynamicCoerceMany<'tcx>>>, 59 60 pub(super) ret_coercion_impl_trait: Option<Ty<'tcx>>, 61 62 pub(super) ret_type_span: Option<Span>, 63 64 /// Used exclusively to reduce cost of advanced evaluation used for 65 /// more helpful diagnostics. 66 pub(super) in_tail_expr: bool, 67 68 /// First span of a return site that we find. Used in error messages. 69 pub(super) ret_coercion_span: Cell<Option<Span>>, 70 71 pub(super) resume_yield_tys: Option<(Ty<'tcx>, Ty<'tcx>)>, 72 73 pub(super) ps: Cell<UnsafetyState>, 74 75 /// Whether the last checked node generates a divergence (e.g., 76 /// `return` will set this to `Always`). In general, when entering 77 /// an expression or other node in the tree, the initial value 78 /// indicates whether prior parts of the containing expression may 79 /// have diverged. It is then typically set to `Maybe` (and the 80 /// old value remembered) for processing the subparts of the 81 /// current expression. As each subpart is processed, they may set 82 /// the flag to `Always`, etc. Finally, at the end, we take the 83 /// result and "union" it with the original value, so that when we 84 /// return the flag indicates if any subpart of the parent 85 /// expression (up to and including this part) has diverged. So, 86 /// if you read it after evaluating a subexpression `X`, the value 87 /// you get indicates whether any subexpression that was 88 /// evaluating up to and including `X` diverged. 89 /// 90 /// We currently use this flag only for diagnostic purposes: 91 /// 92 /// - To warn about unreachable code: if, after processing a 93 /// sub-expression but before we have applied the effects of the 94 /// current node, we see that the flag is set to `Always`, we 95 /// can issue a warning. This corresponds to something like 96 /// `foo(return)`; we warn on the `foo()` expression. (We then 97 /// update the flag to `WarnedAlways` to suppress duplicate 98 /// reports.) Similarly, if we traverse to a fresh statement (or 99 /// tail expression) from an `Always` setting, we will issue a 100 /// warning. This corresponds to something like `{return; 101 /// foo();}` or `{return; 22}`, where we would warn on the 102 /// `foo()` or `22`. 103 /// 104 /// An expression represents dead code if, after checking it, 105 /// the diverges flag is set to something other than `Maybe`. 106 pub(super) diverges: Cell<Diverges>, 107 108 /// Whether any child nodes have any type errors. 109 pub(super) has_errors: Cell<bool>, 110 111 pub(super) enclosing_breakables: RefCell<EnclosingBreakables<'tcx>>, 112 113 pub(super) inh: &'a Inherited<'a, 'tcx>, 114 115 /// True if the function or closure's return type is known before 116 /// entering the function/closure, i.e. if the return type is 117 /// either given explicitly or inferred from, say, an `Fn*` trait 118 /// bound. Used for diagnostic purposes only. 119 pub(super) return_type_pre_known: bool, 120 } 121 122 impl<'a, 'tcx> FnCtxt<'a, 'tcx> { new( inh: &'a Inherited<'a, 'tcx>, param_env: ty::ParamEnv<'tcx>, body_id: hir::HirId, ) -> FnCtxt<'a, 'tcx>123 pub fn new( 124 inh: &'a Inherited<'a, 'tcx>, 125 param_env: ty::ParamEnv<'tcx>, 126 body_id: hir::HirId, 127 ) -> FnCtxt<'a, 'tcx> { 128 FnCtxt { 129 body_id, 130 param_env, 131 err_count_on_creation: inh.tcx.sess.err_count(), 132 ret_coercion: None, 133 ret_coercion_impl_trait: None, 134 ret_type_span: None, 135 in_tail_expr: false, 136 ret_coercion_span: Cell::new(None), 137 resume_yield_tys: None, 138 ps: Cell::new(UnsafetyState::function(hir::Unsafety::Normal, hir::CRATE_HIR_ID)), 139 diverges: Cell::new(Diverges::Maybe), 140 has_errors: Cell::new(false), 141 enclosing_breakables: RefCell::new(EnclosingBreakables { 142 stack: Vec::new(), 143 by_id: Default::default(), 144 }), 145 inh, 146 return_type_pre_known: true, 147 } 148 } 149 cause(&self, span: Span, code: ObligationCauseCode<'tcx>) -> ObligationCause<'tcx>150 pub fn cause(&self, span: Span, code: ObligationCauseCode<'tcx>) -> ObligationCause<'tcx> { 151 ObligationCause::new(span, self.body_id, code) 152 } 153 misc(&self, span: Span) -> ObligationCause<'tcx>154 pub fn misc(&self, span: Span) -> ObligationCause<'tcx> { 155 self.cause(span, ObligationCauseCode::MiscObligation) 156 } 157 sess(&self) -> &Session158 pub fn sess(&self) -> &Session { 159 &self.tcx.sess 160 } 161 errors_reported_since_creation(&self) -> bool162 pub fn errors_reported_since_creation(&self) -> bool { 163 self.tcx.sess.err_count() > self.err_count_on_creation 164 } 165 } 166 167 impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> { 168 type Target = Inherited<'a, 'tcx>; deref(&self) -> &Self::Target169 fn deref(&self) -> &Self::Target { 170 &self.inh 171 } 172 } 173 174 impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { tcx<'b>(&'b self) -> TyCtxt<'tcx>175 fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { 176 self.tcx 177 } 178 item_def_id(&self) -> Option<DefId>179 fn item_def_id(&self) -> Option<DefId> { 180 None 181 } 182 get_type_parameter_bounds( &self, _: Span, def_id: DefId, _: Ident, ) -> ty::GenericPredicates<'tcx>183 fn get_type_parameter_bounds( 184 &self, 185 _: Span, 186 def_id: DefId, 187 _: Ident, 188 ) -> ty::GenericPredicates<'tcx> { 189 let tcx = self.tcx; 190 let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); 191 let item_id = tcx.hir().ty_param_owner(hir_id); 192 let item_def_id = tcx.hir().local_def_id(item_id); 193 let generics = tcx.generics_of(item_def_id); 194 let index = generics.param_def_id_to_index[&def_id]; 195 ty::GenericPredicates { 196 parent: None, 197 predicates: tcx.arena.alloc_from_iter( 198 self.param_env.caller_bounds().iter().filter_map(|predicate| { 199 match predicate.kind().skip_binder() { 200 ty::PredicateKind::Trait(data) if data.self_ty().is_param(index) => { 201 // HACK(eddyb) should get the original `Span`. 202 let span = tcx.def_span(def_id); 203 Some((predicate, span)) 204 } 205 _ => None, 206 } 207 }), 208 ), 209 } 210 } 211 re_infer(&self, def: Option<&ty::GenericParamDef>, span: Span) -> Option<ty::Region<'tcx>>212 fn re_infer(&self, def: Option<&ty::GenericParamDef>, span: Span) -> Option<ty::Region<'tcx>> { 213 let v = match def { 214 Some(def) => infer::EarlyBoundRegion(span, def.name), 215 None => infer::MiscVariable(span), 216 }; 217 Some(self.next_region_var(v)) 218 } 219 allow_ty_infer(&self) -> bool220 fn allow_ty_infer(&self) -> bool { 221 true 222 } 223 ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx>224 fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> { 225 if let Some(param) = param { 226 if let GenericArgKind::Type(ty) = self.var_for_def(span, param).unpack() { 227 return ty; 228 } 229 unreachable!() 230 } else { 231 self.next_ty_var(TypeVariableOrigin { 232 kind: TypeVariableOriginKind::TypeInference, 233 span, 234 }) 235 } 236 } 237 ct_infer( &self, ty: Ty<'tcx>, param: Option<&ty::GenericParamDef>, span: Span, ) -> &'tcx Const<'tcx>238 fn ct_infer( 239 &self, 240 ty: Ty<'tcx>, 241 param: Option<&ty::GenericParamDef>, 242 span: Span, 243 ) -> &'tcx Const<'tcx> { 244 if let Some(param) = param { 245 if let GenericArgKind::Const(ct) = self.var_for_def(span, param).unpack() { 246 return ct; 247 } 248 unreachable!() 249 } else { 250 self.next_const_var( 251 ty, 252 ConstVariableOrigin { kind: ConstVariableOriginKind::ConstInference, span }, 253 ) 254 } 255 } 256 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>257 fn projected_ty_from_poly_trait_ref( 258 &self, 259 span: Span, 260 item_def_id: DefId, 261 item_segment: &hir::PathSegment<'_>, 262 poly_trait_ref: ty::PolyTraitRef<'tcx>, 263 ) -> Ty<'tcx> { 264 let (trait_ref, _) = self.replace_bound_vars_with_fresh_vars( 265 span, 266 infer::LateBoundRegionConversionTime::AssocTypeProjection(item_def_id), 267 poly_trait_ref, 268 ); 269 270 let item_substs = <dyn AstConv<'tcx>>::create_substs_for_associated_item( 271 self, 272 self.tcx, 273 span, 274 item_def_id, 275 item_segment, 276 trait_ref.substs, 277 ); 278 279 self.tcx().mk_projection(item_def_id, item_substs) 280 } 281 normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx>282 fn normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx> { 283 if ty.has_escaping_bound_vars() { 284 ty // FIXME: normalization and escaping regions 285 } else { 286 self.normalize_associated_types_in(span, &ty) 287 } 288 } 289 set_tainted_by_errors(&self)290 fn set_tainted_by_errors(&self) { 291 self.infcx.set_tainted_by_errors() 292 } 293 record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, _span: Span)294 fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, _span: Span) { 295 self.write_ty(hir_id, ty) 296 } 297 } 298