]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_borrowck/src/type_check/input_output.rs
Rollup merge of #102766 - thomcc:remove-resolv, r=Mark-Simulacrum
[rust.git] / compiler / rustc_borrowck / src / 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 opaque
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 rustc_index::vec::Idx;
11 use rustc_infer::infer::LateBoundRegionConversionTime;
12 use rustc_middle::mir::*;
13 use rustc_middle::ty::Ty;
14 use rustc_span::Span;
15
16 use crate::universal_regions::UniversalRegions;
17
18 use super::{Locations, TypeChecker};
19
20 impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
21     #[instrument(skip(self, body, universal_regions), level = "debug")]
22     pub(super) fn equate_inputs_and_outputs(
23         &mut self,
24         body: &Body<'tcx>,
25         universal_regions: &UniversalRegions<'tcx>,
26         normalized_inputs_and_output: &[Ty<'tcx>],
27     ) {
28         let (&normalized_output_ty, normalized_input_tys) =
29             normalized_inputs_and_output.split_last().unwrap();
30
31         debug!(?normalized_output_ty);
32         debug!(?normalized_input_tys);
33
34         let mir_def_id = body.source.def_id().expect_local();
35
36         // If the user explicitly annotated the input types, extract
37         // those.
38         //
39         // e.g., `|x: FxHashMap<_, &'static u32>| ...`
40         let user_provided_sig;
41         if !self.tcx().is_closure(mir_def_id.to_def_id()) {
42             user_provided_sig = None;
43         } else {
44             let typeck_results = self.tcx().typeck(mir_def_id);
45             user_provided_sig = typeck_results.user_provided_sigs.get(&mir_def_id.to_def_id()).map(
46                 |user_provided_poly_sig| {
47                     // Instantiate the canonicalized variables from
48                     // user-provided signature (e.g., the `_` in the code
49                     // above) with fresh variables.
50                     let poly_sig = self.instantiate_canonical_with_fresh_inference_vars(
51                         body.span,
52                         &user_provided_poly_sig,
53                     );
54
55                     // Replace the bound items in the fn sig with fresh
56                     // variables, so that they represent the view from
57                     // "inside" the closure.
58                     self.infcx.replace_bound_vars_with_fresh_vars(
59                         body.span,
60                         LateBoundRegionConversionTime::FnCall,
61                         poly_sig,
62                     )
63                 },
64             );
65         }
66
67         debug!(?normalized_input_tys, ?body.local_decls);
68
69         // Equate expected input tys with those in the MIR.
70         for (argument_index, &normalized_input_ty) in normalized_input_tys.iter().enumerate() {
71             if argument_index + 1 >= body.local_decls.len() {
72                 self.tcx()
73                     .sess
74                     .delay_span_bug(body.span, "found more normalized_input_ty than local_decls");
75                 break;
76             }
77
78             // In MIR, argument N is stored in local N+1.
79             let local = Local::new(argument_index + 1);
80
81             let mir_input_ty = body.local_decls[local].ty;
82
83             let mir_input_span = body.local_decls[local].source_info.span;
84             self.equate_normalized_input_or_output(
85                 normalized_input_ty,
86                 mir_input_ty,
87                 mir_input_span,
88             );
89         }
90
91         if let Some(user_provided_sig) = user_provided_sig {
92             for (argument_index, &user_provided_input_ty) in
93                 user_provided_sig.inputs().iter().enumerate()
94             {
95                 // In MIR, closures begin an implicit `self`, so
96                 // argument N is stored in local N+2.
97                 let local = Local::new(argument_index + 2);
98                 let mir_input_ty = body.local_decls[local].ty;
99                 let mir_input_span = body.local_decls[local].source_info.span;
100
101                 // If the user explicitly annotated the input types, enforce those.
102                 let user_provided_input_ty =
103                     self.normalize(user_provided_input_ty, Locations::All(mir_input_span));
104
105                 self.equate_normalized_input_or_output(
106                     user_provided_input_ty,
107                     mir_input_ty,
108                     mir_input_span,
109                 );
110             }
111         }
112
113         debug!(
114             "equate_inputs_and_outputs: body.yield_ty {:?}, universal_regions.yield_ty {:?}",
115             body.yield_ty(),
116             universal_regions.yield_ty
117         );
118
119         // We will not have a universal_regions.yield_ty if we yield (by accident)
120         // outside of a generator and return an `impl Trait`, so emit a delay_span_bug
121         // because we don't want to panic in an assert here if we've already got errors.
122         if body.yield_ty().is_some() != universal_regions.yield_ty.is_some() {
123             self.tcx().sess.delay_span_bug(
124                 body.span,
125                 &format!(
126                     "Expected body to have yield_ty ({:?}) iff we have a UR yield_ty ({:?})",
127                     body.yield_ty(),
128                     universal_regions.yield_ty,
129                 ),
130             );
131         }
132
133         if let (Some(mir_yield_ty), Some(ur_yield_ty)) =
134             (body.yield_ty(), universal_regions.yield_ty)
135         {
136             let yield_span = body.local_decls[RETURN_PLACE].source_info.span;
137             self.equate_normalized_input_or_output(ur_yield_ty, mir_yield_ty, yield_span);
138         }
139
140         // Return types are a bit more complex. They may contain opaque `impl Trait` types.
141         let mir_output_ty = body.local_decls[RETURN_PLACE].ty;
142         let output_span = body.local_decls[RETURN_PLACE].source_info.span;
143         if let Err(terr) = self.eq_types(
144             normalized_output_ty,
145             mir_output_ty,
146             Locations::All(output_span),
147             ConstraintCategory::BoringNoLocation,
148         ) {
149             span_mirbug!(
150                 self,
151                 Location::START,
152                 "equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`",
153                 normalized_output_ty,
154                 mir_output_ty,
155                 terr
156             );
157         };
158
159         // If the user explicitly annotated the output types, enforce those.
160         // Note that this only happens for closures.
161         if let Some(user_provided_sig) = user_provided_sig {
162             let user_provided_output_ty = user_provided_sig.output();
163             let user_provided_output_ty =
164                 self.normalize(user_provided_output_ty, Locations::All(output_span));
165             if let Err(err) = self.eq_types(
166                 user_provided_output_ty,
167                 mir_output_ty,
168                 Locations::All(output_span),
169                 ConstraintCategory::BoringNoLocation,
170             ) {
171                 span_mirbug!(
172                     self,
173                     Location::START,
174                     "equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`",
175                     mir_output_ty,
176                     user_provided_output_ty,
177                     err
178                 );
179             }
180         }
181     }
182
183     #[instrument(skip(self), level = "debug")]
184     fn equate_normalized_input_or_output(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, span: Span) {
185         if let Err(_) =
186             self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation)
187         {
188             // FIXME(jackh726): This is a hack. It's somewhat like
189             // `rustc_traits::normalize_after_erasing_regions`. Ideally, we'd
190             // like to normalize *before* inserting into `local_decls`, but
191             // doing so ends up causing some other trouble.
192             let b = self.normalize(b, Locations::All(span));
193
194             // Note: if we have to introduce new placeholders during normalization above, then we won't have
195             // added those universes to the universe info, which we would want in `relate_tys`.
196             if let Err(terr) =
197                 self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation)
198             {
199                 span_mirbug!(
200                     self,
201                     Location::START,
202                     "equate_normalized_input_or_output: `{:?}=={:?}` failed with `{:?}`",
203                     a,
204                     b,
205                     terr
206                 );
207             }
208         }
209     }
210 }