]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/borrow_check/nll/type_check/input_output.rs
Changes the type `mir::Mir` into `mir::Body`
[rust.git] / src / librustc_mir / borrow_check / nll / type_check / input_output.rs
1 //! This module contains code to equate the input/output types appearing
2 //! in the MIR with the expected input/output types from the function
3 //! signature. This requires a bit of processing, as the expected types
4 //! are supplied to us before normalization and may contain existential
5 //! `impl Trait` instances. In contrast, the input/output types found in
6 //! the MIR (specifically, in the special local variables for the
7 //! `RETURN_PLACE` the MIR arguments) are always fully normalized (and
8 //! contain revealed `impl Trait` values).
9
10 use crate::borrow_check::nll::universal_regions::UniversalRegions;
11 use rustc::infer::LateBoundRegionConversionTime;
12 use rustc::mir::*;
13 use rustc::ty::Ty;
14
15 use rustc_data_structures::indexed_vec::Idx;
16 use syntax_pos::Span;
17
18 use super::{Locations, TypeChecker};
19
20 impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
21     pub(super) fn equate_inputs_and_outputs(
22         &mut self,
23         mir: &Body<'tcx>,
24         universal_regions: &UniversalRegions<'tcx>,
25         normalized_inputs_and_output: &[Ty<'tcx>],
26     ) {
27         let (&normalized_output_ty, normalized_input_tys) =
28             normalized_inputs_and_output.split_last().unwrap();
29
30         // If the user explicitly annotated the input types, extract
31         // those.
32         //
33         // e.g., `|x: FxHashMap<_, &'static u32>| ...`
34         let user_provided_sig;
35         if !self.tcx().is_closure(self.mir_def_id) {
36             user_provided_sig = None;
37         } else {
38             let typeck_tables = self.tcx().typeck_tables_of(self.mir_def_id);
39             user_provided_sig = match typeck_tables.user_provided_sigs.get(&self.mir_def_id) {
40                 None => None,
41                 Some(user_provided_poly_sig) => {
42                     // Instantiate the canonicalized variables from
43                     // user-provided signature (e.g., the `_` in the code
44                     // above) with fresh variables.
45                     let (poly_sig, _) = self.infcx.instantiate_canonical_with_fresh_inference_vars(
46                         mir.span,
47                         &user_provided_poly_sig,
48                     );
49
50                     // Replace the bound items in the fn sig with fresh
51                     // variables, so that they represent the view from
52                     // "inside" the closure.
53                     Some(
54                         self.infcx
55                             .replace_bound_vars_with_fresh_vars(
56                                 mir.span,
57                                 LateBoundRegionConversionTime::FnCall,
58                                 &poly_sig,
59                             )
60                             .0,
61                     )
62                 }
63             }
64         };
65
66         // Equate expected input tys with those in the MIR.
67         for (&normalized_input_ty, argument_index) in normalized_input_tys.iter().zip(0..) {
68             // In MIR, argument N is stored in local N+1.
69             let local = Local::new(argument_index + 1);
70
71             debug!(
72                 "equate_inputs_and_outputs: normalized_input_ty = {:?}",
73                 normalized_input_ty
74             );
75
76             let mir_input_ty = mir.local_decls[local].ty;
77             let mir_input_span = mir.local_decls[local].source_info.span;
78             self.equate_normalized_input_or_output(
79                 normalized_input_ty,
80                 mir_input_ty,
81                 mir_input_span,
82             );
83         }
84
85         if let Some(user_provided_sig) = user_provided_sig {
86             for (&user_provided_input_ty, argument_index) in
87                 user_provided_sig.inputs().iter().zip(0..)
88             {
89                 // In MIR, closures begin an implicit `self`, so
90                 // argument N is stored in local N+2.
91                 let local = Local::new(argument_index + 2);
92                 let mir_input_ty = mir.local_decls[local].ty;
93                 let mir_input_span = mir.local_decls[local].source_info.span;
94
95                 // If the user explicitly annotated the input types, enforce those.
96                 let user_provided_input_ty =
97                     self.normalize(user_provided_input_ty, Locations::All(mir_input_span));
98                 self.equate_normalized_input_or_output(
99                     user_provided_input_ty,
100                     mir_input_ty,
101                     mir_input_span,
102                 );
103             }
104         }
105
106         assert!(
107             mir.yield_ty.is_some() && universal_regions.yield_ty.is_some()
108                 || mir.yield_ty.is_none() && universal_regions.yield_ty.is_none()
109         );
110         if let Some(mir_yield_ty) = mir.yield_ty {
111             let ur_yield_ty = universal_regions.yield_ty.unwrap();
112             let yield_span = mir.local_decls[RETURN_PLACE].source_info.span;
113             self.equate_normalized_input_or_output(ur_yield_ty, mir_yield_ty, yield_span);
114         }
115
116         // Return types are a bit more complex. They may contain existential `impl Trait`
117         // types.
118         let mir_output_ty = mir.local_decls[RETURN_PLACE].ty;
119         let output_span = mir.local_decls[RETURN_PLACE].source_info.span;
120         if let Err(terr) = self.eq_opaque_type_and_type(
121             mir_output_ty,
122             normalized_output_ty,
123             self.mir_def_id,
124             Locations::All(output_span),
125             ConstraintCategory::BoringNoLocation,
126         ) {
127             span_mirbug!(
128                 self,
129                 Location::START,
130                 "equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`",
131                 normalized_output_ty,
132                 mir_output_ty,
133                 terr
134             );
135         };
136
137         // If the user explicitly annotated the output types, enforce those.
138         if let Some(user_provided_sig) = user_provided_sig {
139             let user_provided_output_ty = user_provided_sig.output();
140             let user_provided_output_ty =
141                 self.normalize(user_provided_output_ty, Locations::All(output_span));
142             self.equate_normalized_input_or_output(
143                 user_provided_output_ty,
144                 mir_output_ty,
145                 output_span,
146             );
147         }
148     }
149
150     fn equate_normalized_input_or_output(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, span: Span) {
151         debug!("equate_normalized_input_or_output(a={:?}, b={:?})", a, b);
152
153         if let Err(terr) = self.eq_types(
154             a,
155             b,
156             Locations::All(span),
157             ConstraintCategory::BoringNoLocation,
158         ) {
159             span_mirbug!(
160                 self,
161                 Location::START,
162                 "equate_normalized_input_or_output: `{:?}=={:?}` failed with `{:?}`",
163                 a,
164                 b,
165                 terr
166             );
167         }
168     }
169 }