]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_borrowck/src/type_check/input_output.rs
New upstream version 1.59.0+dfsg1
[rustc.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
64 .replace_bound_vars_with_fresh_vars(
65 body.span,
66 LateBoundRegionConversionTime::FnCall,
67 poly_sig,
68 )
69 .0
70 },
71 );
72 }
73
74 debug!(?normalized_input_tys, ?body.local_decls);
75
76 // Equate expected input tys with those in the MIR.
77 for (argument_index, &normalized_input_ty) in normalized_input_tys.iter().enumerate() {
78 if argument_index + 1 >= body.local_decls.len() {
79 self.tcx()
80 .sess
81 .delay_span_bug(body.span, "found more normalized_input_ty than local_decls");
82 break;
83 }
84
85 // In MIR, argument N is stored in local N+1.
86 let local = Local::new(argument_index + 1);
87
88 let mir_input_ty = body.local_decls[local].ty;
89
90 let mir_input_span = body.local_decls[local].source_info.span;
91 self.equate_normalized_input_or_output(
92 normalized_input_ty,
93 mir_input_ty,
94 mir_input_span,
95 );
96 }
97
98 if let Some(user_provided_sig) = user_provided_sig {
99 for (argument_index, &user_provided_input_ty) in
100 user_provided_sig.inputs().iter().enumerate()
101 {
102 // In MIR, closures begin an implicit `self`, so
103 // argument N is stored in local N+2.
104 let local = Local::new(argument_index + 2);
105 let mir_input_ty = body.local_decls[local].ty;
106 let mir_input_span = body.local_decls[local].source_info.span;
107
108 // If the user explicitly annotated the input types, enforce those.
109 let user_provided_input_ty =
110 self.normalize(user_provided_input_ty, Locations::All(mir_input_span));
111
112 self.equate_normalized_input_or_output(
113 user_provided_input_ty,
114 mir_input_ty,
115 mir_input_span,
116 );
117 }
118 }
119
120 debug!(
121 "equate_inputs_and_outputs: body.yield_ty {:?}, universal_regions.yield_ty {:?}",
122 body.yield_ty(),
123 universal_regions.yield_ty
124 );
125
126 // We will not have a universal_regions.yield_ty if we yield (by accident)
127 // outside of a generator and return an `impl Trait`, so emit a delay_span_bug
128 // because we don't want to panic in an assert here if we've already got errors.
129 if body.yield_ty().is_some() != universal_regions.yield_ty.is_some() {
130 self.tcx().sess.delay_span_bug(
131 body.span,
132 &format!(
133 "Expected body to have yield_ty ({:?}) iff we have a UR yield_ty ({:?})",
134 body.yield_ty(),
135 universal_regions.yield_ty,
136 ),
137 );
138 }
139
140 if let (Some(mir_yield_ty), Some(ur_yield_ty)) =
141 (body.yield_ty(), universal_regions.yield_ty)
142 {
143 let yield_span = body.local_decls[RETURN_PLACE].source_info.span;
144 self.equate_normalized_input_or_output(ur_yield_ty, mir_yield_ty, yield_span);
145 }
146
147 // Return types are a bit more complex. They may contain opaque `impl Trait` types.
148 let mir_output_ty = body.local_decls[RETURN_PLACE].ty;
149 let output_span = body.local_decls[RETURN_PLACE].source_info.span;
150 if let Err(terr) = self.eq_opaque_type_and_type(
151 mir_output_ty,
152 normalized_output_ty,
153 Locations::All(output_span),
154 ConstraintCategory::BoringNoLocation,
155 ) {
156 span_mirbug!(
157 self,
158 Location::START,
159 "equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`",
160 normalized_output_ty,
161 mir_output_ty,
162 terr
163 );
164 };
165
166 // If the user explicitly annotated the output types, enforce those.
167 // Note that this only happens for closures.
168 if let Some(user_provided_sig) = user_provided_sig {
169 let user_provided_output_ty = user_provided_sig.output();
170 let user_provided_output_ty =
171 self.normalize(user_provided_output_ty, Locations::All(output_span));
172 if let Err(err) = self.eq_opaque_type_and_type(
173 mir_output_ty,
174 user_provided_output_ty,
175 Locations::All(output_span),
176 ConstraintCategory::BoringNoLocation,
177 ) {
178 span_mirbug!(
179 self,
180 Location::START,
181 "equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`",
182 mir_output_ty,
183 user_provided_output_ty,
184 err
185 );
186 }
187 }
188 }
189
190 #[instrument(skip(self, span), level = "debug")]
191 fn equate_normalized_input_or_output(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, span: Span) {
192 if let Err(_) =
193 self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation)
194 {
195 // FIXME(jackh726): This is a hack. It's somewhat like
196 // `rustc_traits::normalize_after_erasing_regions`. Ideally, we'd
197 // like to normalize *before* inserting into `local_decls`, but
198 // doing so ends up causing some other trouble.
199 let b = match self.normalize_and_add_constraints(b) {
200 Ok(n) => n,
201 Err(_) => {
202 debug!("equate_inputs_and_outputs: NoSolution");
203 b
204 }
205 };
206
207 // Note: if we have to introduce new placeholders during normalization above, then we won't have
208 // added those universes to the universe info, which we would want in `relate_tys`.
209 if let Err(terr) =
210 self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation)
211 {
212 span_mirbug!(
213 self,
214 Location::START,
215 "equate_normalized_input_or_output: `{:?}=={:?}` failed with `{:?}`",
216 a,
217 b,
218 terr
219 );
220 }
221 }
222 }
223
224 pub(crate) fn normalize_and_add_constraints(&mut self, t: Ty<'tcx>) -> Fallible<Ty<'tcx>> {
225 let TypeOpOutput { output: norm_ty, constraints, .. } =
226 self.param_env.and(type_op::normalize::Normalize::new(t)).fully_perform(self.infcx)?;
227
228 debug!("{:?} normalized to {:?}", t, norm_ty);
229
230 for data in constraints.into_iter().collect::<Vec<_>>() {
231 ConstraintConversion::new(
232 self.infcx,
233 &self.borrowck_context.universal_regions,
234 &self.region_bound_pairs,
235 Some(self.implicit_region_bound),
236 self.param_env,
237 Locations::All(DUMMY_SP),
238 ConstraintCategory::Internal,
239 &mut self.borrowck_context.constraints,
240 )
241 .convert_all(&*data);
242 }
243
244 Ok(norm_ty)
245 }
246 }