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