]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_mir/src/borrow_check/type_check/input_output.rs
New upstream version 1.56.0~beta.4+dfsg1
[rustc.git] / compiler / rustc_mir / src / borrow_check / type_check / input_output.rs
CommitLineData
ff7c6d11
XL
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
416331ca 4//! are supplied to us before normalization and may contain opaque
ff7c6d11
XL
5//! `impl Trait` instances. In contrast, the input/output types found in
6//! the MIR (specifically, in the special local variables for the
0bf4aa26 7//! `RETURN_PLACE` the MIR arguments) are always fully normalized (and
ff7c6d11
XL
8//! contain revealed `impl Trait` values).
9
74b04a01 10use rustc_infer::infer::LateBoundRegionConversionTime;
ba9703b0 11use rustc_middle::mir::*;
94222f64
XL
12use rustc_middle::traits::ObligationCause;
13use rustc_middle::ty::{self, Ty};
14use rustc_trait_selection::traits::query::normalize::AtExt;
ff7c6d11 15
e74abb32 16use rustc_index::vec::Idx;
dfeec247 17use rustc_span::Span;
ff7c6d11 18
60c5eb7d
XL
19use crate::borrow_check::universal_regions::UniversalRegions;
20
83c7162d 21use super::{Locations, TypeChecker};
ff7c6d11 22
dc9dc135 23impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
ff7c6d11
XL
24 pub(super) fn equate_inputs_and_outputs(
25 &mut self,
dc9dc135 26 body: &Body<'tcx>,
ff7c6d11 27 universal_regions: &UniversalRegions<'tcx>,
8faf50e0 28 normalized_inputs_and_output: &[Ty<'tcx>],
ff7c6d11 29 ) {
8faf50e0
XL
30 let (&normalized_output_ty, normalized_input_tys) =
31 normalized_inputs_and_output.split_last().unwrap();
0bf4aa26 32
29967ef6
XL
33 let mir_def_id = body.source.def_id().expect_local();
34
0bf4aa26
XL
35 // If the user explicitly annotated the input types, extract
36 // those.
37 //
0731742a 38 // e.g., `|x: FxHashMap<_, &'static u32>| ...`
0bf4aa26 39 let user_provided_sig;
29967ef6 40 if !self.tcx().is_closure(mir_def_id.to_def_id()) {
0bf4aa26
XL
41 user_provided_sig = None;
42 } else {
29967ef6 43 let typeck_results = self.tcx().typeck(mir_def_id);
5869c6ff
XL
44 user_provided_sig = typeck_results.user_provided_sigs.get(&mir_def_id.to_def_id()).map(
45 |user_provided_poly_sig| {
29967ef6
XL
46 // Instantiate the canonicalized variables from
47 // user-provided signature (e.g., the `_` in the code
48 // above) with fresh variables.
94222f64 49 let poly_sig = self.instantiate_canonical_with_fresh_inference_vars(
29967ef6
XL
50 body.span,
51 &user_provided_poly_sig,
52 );
53
54 // Replace the bound items in the fn sig with fresh
55 // variables, so that they represent the view from
56 // "inside" the closure.
5869c6ff
XL
57 self.infcx
58 .replace_bound_vars_with_fresh_vars(
59 body.span,
60 LateBoundRegionConversionTime::FnCall,
61 poly_sig,
62 )
63 .0
64 },
65 );
66 }
ff7c6d11 67
ba9703b0
XL
68 debug!(
69 "equate_inputs_and_outputs: normalized_input_tys = {:?}, local_decls = {:?}",
70 normalized_input_tys, body.local_decls
71 );
72
ff7c6d11 73 // Equate expected input tys with those in the MIR.
29967ef6 74 for (argument_index, &normalized_input_ty) in normalized_input_tys.iter().enumerate() {
cdc7bbd5
XL
75 if argument_index + 1 >= body.local_decls.len() {
76 self.tcx()
77 .sess
78 .delay_span_bug(body.span, "found more normalized_input_ty than local_decls");
79 break;
80 }
0bf4aa26
XL
81 // In MIR, argument N is stored in local N+1.
82 let local = Local::new(argument_index + 1);
83
dc9dc135
XL
84 let mir_input_ty = body.local_decls[local].ty;
85 let mir_input_span = body.local_decls[local].source_info.span;
0bf4aa26
XL
86 self.equate_normalized_input_or_output(
87 normalized_input_ty,
88 mir_input_ty,
89 mir_input_span,
90 );
91 }
92
93 if let Some(user_provided_sig) = user_provided_sig {
29967ef6
XL
94 for (argument_index, &user_provided_input_ty) in
95 user_provided_sig.inputs().iter().enumerate()
0bf4aa26
XL
96 {
97 // In MIR, closures begin an implicit `self`, so
98 // argument N is stored in local N+2.
99 let local = Local::new(argument_index + 2);
dc9dc135
XL
100 let mir_input_ty = body.local_decls[local].ty;
101 let mir_input_span = body.local_decls[local].source_info.span;
0bf4aa26
XL
102
103 // If the user explicitly annotated the input types, enforce those.
104 let user_provided_input_ty =
105 self.normalize(user_provided_input_ty, Locations::All(mir_input_span));
106 self.equate_normalized_input_or_output(
107 user_provided_input_ty,
108 mir_input_ty,
109 mir_input_span,
110 );
111 }
ff7c6d11
XL
112 }
113
6a06907d
XL
114 assert!(body.yield_ty().is_some() == universal_regions.yield_ty.is_some());
115 if let Some(mir_yield_ty) = body.yield_ty() {
2c00a5a8 116 let ur_yield_ty = universal_regions.yield_ty.unwrap();
dc9dc135 117 let yield_span = body.local_decls[RETURN_PLACE].source_info.span;
0bf4aa26 118 self.equate_normalized_input_or_output(ur_yield_ty, mir_yield_ty, yield_span);
2c00a5a8
XL
119 }
120
416331ca 121 // Return types are a bit more complex. They may contain opaque `impl Trait` types.
dc9dc135
XL
122 let mir_output_ty = body.local_decls[RETURN_PLACE].ty;
123 let output_span = body.local_decls[RETURN_PLACE].source_info.span;
0bf4aa26
XL
124 if let Err(terr) = self.eq_opaque_type_and_type(
125 mir_output_ty,
126 normalized_output_ty,
0bf4aa26
XL
127 Locations::All(output_span),
128 ConstraintCategory::BoringNoLocation,
129 ) {
130 span_mirbug!(
131 self,
132 Location::START,
133 "equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`",
134 normalized_output_ty,
135 mir_output_ty,
136 terr
137 );
138 };
139
140 // If the user explicitly annotated the output types, enforce those.
60c5eb7d 141 // Note that this only happens for closures.
0bf4aa26
XL
142 if let Some(user_provided_sig) = user_provided_sig {
143 let user_provided_output_ty = user_provided_sig.output();
144 let user_provided_output_ty =
145 self.normalize(user_provided_output_ty, Locations::All(output_span));
60c5eb7d 146 if let Err(err) = self.eq_opaque_type_and_type(
0bf4aa26 147 mir_output_ty,
60c5eb7d 148 user_provided_output_ty,
60c5eb7d 149 Locations::All(output_span),
dfeec247 150 ConstraintCategory::BoringNoLocation,
60c5eb7d
XL
151 ) {
152 span_mirbug!(
153 self,
154 Location::START,
155 "equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`",
156 mir_output_ty,
157 user_provided_output_ty,
158 err
159 );
160 }
ff7c6d11
XL
161 }
162 }
163
0bf4aa26 164 fn equate_normalized_input_or_output(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, span: Span) {
ff7c6d11
XL
165 debug!("equate_normalized_input_or_output(a={:?}, b={:?})", a, b);
166
94222f64 167 if let Err(_) =
dfeec247
XL
168 self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation)
169 {
94222f64
XL
170 // FIXME(jackh726): This is a hack. It's somewhat like
171 // `rustc_traits::normalize_after_erasing_regions`. Ideally, we'd
172 // like to normalize *before* inserting into `local_decls`, but
173 // doing so ends up causing some other trouble.
174 let b = match self
175 .infcx
176 .at(&ObligationCause::dummy(), ty::ParamEnv::empty())
177 .normalize(b)
178 {
179 Ok(n) => {
180 debug!("equate_inputs_and_outputs: {:?}", n);
181 if n.obligations.iter().all(|o| {
182 matches!(
183 o.predicate.kind().skip_binder(),
184 ty::PredicateKind::RegionOutlives(_)
185 | ty::PredicateKind::TypeOutlives(_)
186 )
187 }) {
188 n.value
189 } else {
190 b
191 }
192 }
193 Err(_) => {
194 debug!("equate_inputs_and_outputs: NoSolution");
195 b
196 }
197 };
198 if let Err(terr) =
199 self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation)
200 {
201 span_mirbug!(
202 self,
203 Location::START,
204 "equate_normalized_input_or_output: `{:?}=={:?}` failed with `{:?}`",
205 a,
206 b,
207 terr
208 );
209 }
ff7c6d11
XL
210 }
211 }
212}