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