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