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