]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
Rollup merge of #81891 - CraftSpider:fn-header, r=jyn514
[rust.git] / compiler / rustc_typeck / src / check / fn_ctxt / mod.rs
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::hir::map::blocks::FnLikeNode;
19 use rustc_middle::ty::fold::TypeFoldable;
20 use rustc_middle::ty::subst::GenericArgKind;
21 use rustc_middle::ty::{self, Const, Ty, TyCtxt};
22 use rustc_session::Session;
23 use rustc_span::symbol::Ident;
24 use rustc_span::{self, Span};
25 use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode};
26
27 use std::cell::{Cell, RefCell};
28 use std::ops::Deref;
29
30 pub struct FnCtxt<'a, 'tcx> {
31     pub(super) body_id: hir::HirId,
32
33     /// The parameter environment used for proving trait obligations
34     /// in this function. This can change when we descend into
35     /// closures (as they bring new things into scope), hence it is
36     /// not part of `Inherited` (as of the time of this writing,
37     /// closures do not yet change the environment, but they will
38     /// eventually).
39     pub(super) param_env: ty::ParamEnv<'tcx>,
40
41     /// Number of errors that had been reported when we started
42     /// checking this function. On exit, if we find that *more* errors
43     /// have been reported, we will skip regionck and other work that
44     /// expects the types within the function to be consistent.
45     // FIXME(matthewjasper) This should not exist, and it's not correct
46     // if type checking is run in parallel.
47     err_count_on_creation: usize,
48
49     /// If `Some`, this stores coercion information for returned
50     /// expressions. If `None`, this is in a context where return is
51     /// inappropriate, such as a const expression.
52     ///
53     /// This is a `RefCell<DynamicCoerceMany>`, which means that we
54     /// can track all the return expressions and then use them to
55     /// compute a useful coercion from the set, similar to a match
56     /// expression or other branching context. You can use methods
57     /// like `expected_ty` to access the declared return type (if
58     /// any).
59     pub(super) ret_coercion: Option<RefCell<DynamicCoerceMany<'tcx>>>,
60
61     pub(super) ret_coercion_impl_trait: Option<Ty<'tcx>>,
62
63     pub(super) ret_type_span: Option<Span>,
64
65     /// Used exclusively to reduce cost of advanced evaluation used for
66     /// more helpful diagnostics.
67     pub(super) in_tail_expr: bool,
68
69     /// First span of a return site that we find. Used in error messages.
70     pub(super) ret_coercion_span: Cell<Option<Span>>,
71
72     pub(super) resume_yield_tys: Option<(Ty<'tcx>, Ty<'tcx>)>,
73
74     pub(super) ps: Cell<UnsafetyState>,
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 a `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     /// Whether any child nodes have any type errors.
110     pub(super) has_errors: Cell<bool>,
111
112     pub(super) enclosing_breakables: RefCell<EnclosingBreakables<'tcx>>,
113
114     pub(super) inh: &'a Inherited<'a, 'tcx>,
115 }
116
117 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
118     pub fn new(
119         inh: &'a Inherited<'a, 'tcx>,
120         param_env: ty::ParamEnv<'tcx>,
121         body_id: hir::HirId,
122     ) -> FnCtxt<'a, 'tcx> {
123         FnCtxt {
124             body_id,
125             param_env,
126             err_count_on_creation: inh.tcx.sess.err_count(),
127             ret_coercion: None,
128             ret_coercion_impl_trait: None,
129             ret_type_span: None,
130             in_tail_expr: false,
131             ret_coercion_span: Cell::new(None),
132             resume_yield_tys: None,
133             ps: Cell::new(UnsafetyState::function(hir::Unsafety::Normal, hir::CRATE_HIR_ID)),
134             diverges: Cell::new(Diverges::Maybe),
135             has_errors: Cell::new(false),
136             enclosing_breakables: RefCell::new(EnclosingBreakables {
137                 stack: Vec::new(),
138                 by_id: Default::default(),
139             }),
140             inh,
141         }
142     }
143
144     pub fn cause(&self, span: Span, code: ObligationCauseCode<'tcx>) -> ObligationCause<'tcx> {
145         ObligationCause::new(span, self.body_id, code)
146     }
147
148     pub fn misc(&self, span: Span) -> ObligationCause<'tcx> {
149         self.cause(span, ObligationCauseCode::MiscObligation)
150     }
151
152     pub fn sess(&self) -> &Session {
153         &self.tcx.sess
154     }
155
156     pub fn errors_reported_since_creation(&self) -> bool {
157         self.tcx.sess.err_count() > self.err_count_on_creation
158     }
159 }
160
161 impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> {
162     type Target = Inherited<'a, 'tcx>;
163     fn deref(&self) -> &Self::Target {
164         &self.inh
165     }
166 }
167
168 impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
169     fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
170         self.tcx
171     }
172
173     fn item_def_id(&self) -> Option<DefId> {
174         None
175     }
176
177     fn default_constness_for_trait_bounds(&self) -> hir::Constness {
178         // FIXME: refactor this into a method
179         let node = self.tcx.hir().get(self.body_id);
180         if let Some(fn_like) = FnLikeNode::from_node(node) {
181             fn_like.constness()
182         } else {
183             hir::Constness::NotConst
184         }
185     }
186
187     fn get_type_parameter_bounds(
188         &self,
189         _: Span,
190         def_id: DefId,
191         _: Ident,
192     ) -> ty::GenericPredicates<'tcx> {
193         let tcx = self.tcx;
194         let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
195         let item_id = tcx.hir().ty_param_owner(hir_id);
196         let item_def_id = tcx.hir().local_def_id(item_id);
197         let generics = tcx.generics_of(item_def_id);
198         let index = generics.param_def_id_to_index[&def_id];
199         ty::GenericPredicates {
200             parent: None,
201             predicates: tcx.arena.alloc_from_iter(
202                 self.param_env.caller_bounds().iter().filter_map(|predicate| {
203                     match predicate.kind().skip_binder() {
204                         ty::PredicateKind::Trait(data, _) if data.self_ty().is_param(index) => {
205                             // HACK(eddyb) should get the original `Span`.
206                             let span = tcx.def_span(def_id);
207                             Some((predicate, span))
208                         }
209                         _ => None,
210                     }
211                 }),
212             ),
213         }
214     }
215
216     fn re_infer(&self, def: Option<&ty::GenericParamDef>, span: Span) -> Option<ty::Region<'tcx>> {
217         let v = match def {
218             Some(def) => infer::EarlyBoundRegion(span, def.name),
219             None => infer::MiscVariable(span),
220         };
221         Some(self.next_region_var(v))
222     }
223
224     fn allow_ty_infer(&self) -> bool {
225         true
226     }
227
228     fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
229         if let Some(param) = param {
230             if let GenericArgKind::Type(ty) = self.var_for_def(span, param).unpack() {
231                 return ty;
232             }
233             unreachable!()
234         } else {
235             self.next_ty_var(TypeVariableOrigin {
236                 kind: TypeVariableOriginKind::TypeInference,
237                 span,
238             })
239         }
240     }
241
242     fn ct_infer(
243         &self,
244         ty: Ty<'tcx>,
245         param: Option<&ty::GenericParamDef>,
246         span: Span,
247     ) -> &'tcx Const<'tcx> {
248         if let Some(param) = param {
249             if let GenericArgKind::Const(ct) = self.var_for_def(span, param).unpack() {
250                 return ct;
251             }
252             unreachable!()
253         } else {
254             self.next_const_var(
255                 ty,
256                 ConstVariableOrigin { kind: ConstVariableOriginKind::ConstInference, span },
257             )
258         }
259     }
260
261     fn projected_ty_from_poly_trait_ref(
262         &self,
263         span: Span,
264         item_def_id: DefId,
265         item_segment: &hir::PathSegment<'_>,
266         poly_trait_ref: ty::PolyTraitRef<'tcx>,
267     ) -> Ty<'tcx> {
268         let (trait_ref, _) = self.replace_bound_vars_with_fresh_vars(
269             span,
270             infer::LateBoundRegionConversionTime::AssocTypeProjection(item_def_id),
271             poly_trait_ref,
272         );
273
274         let item_substs = <dyn AstConv<'tcx>>::create_substs_for_associated_item(
275             self,
276             self.tcx,
277             span,
278             item_def_id,
279             item_segment,
280             trait_ref.substs,
281         );
282
283         self.tcx().mk_projection(item_def_id, item_substs)
284     }
285
286     fn normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
287         if ty.has_escaping_bound_vars() {
288             ty // FIXME: normalization and escaping regions
289         } else {
290             self.normalize_associated_types_in(span, &ty)
291         }
292     }
293
294     fn set_tainted_by_errors(&self) {
295         self.infcx.set_tainted_by_errors()
296     }
297
298     fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, _span: Span) {
299         self.write_ty(hir_id, ty)
300     }
301 }