]>
Commit | Line | Data |
---|---|---|
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 | ||
c620b35d FG |
10 | use std::assert_matches::assert_matches; |
11 | ||
c0240ec0 | 12 | use itertools::Itertools; |
c620b35d | 13 | use rustc_hir as hir; |
e8be2606 | 14 | use rustc_infer::infer::type_variable::TypeVariableOrigin; |
c620b35d | 15 | use rustc_infer::infer::{BoundRegionConversionTime, RegionVariableOrigin}; |
ba9703b0 | 16 | use rustc_middle::mir::*; |
9c376795 | 17 | use rustc_middle::ty::{self, Ty}; |
dfeec247 | 18 | use rustc_span::Span; |
ff7c6d11 | 19 | |
c620b35d FG |
20 | use crate::renumber::RegionCtxt; |
21 | use crate::universal_regions::{DefiningTy, UniversalRegions}; | |
60c5eb7d | 22 | |
83c7162d | 23 | use super::{Locations, TypeChecker}; |
ff7c6d11 | 24 | |
dc9dc135 | 25 | impl<'a, 'tcx> TypeChecker<'a, 'tcx> { |
9c376795 | 26 | /// Check explicit closure signature annotation, |
353b0b11 | 27 | /// e.g., `|x: FxIndexMap<_, &'static u32>| ...`. |
9c376795 FG |
28 | #[instrument(skip(self, body), level = "debug")] |
29 | pub(super) fn check_signature_annotation(&mut self, body: &Body<'tcx>) { | |
30 | let mir_def_id = body.source.def_id().expect_local(); | |
c620b35d FG |
31 | |
32 | if !self.tcx().is_closure_like(mir_def_id.to_def_id()) { | |
9c376795 FG |
33 | return; |
34 | } | |
c620b35d | 35 | |
9ffffee4 | 36 | let user_provided_poly_sig = self.tcx().closure_user_provided_sig(mir_def_id); |
9c376795 FG |
37 | |
38 | // Instantiate the canonicalized variables from user-provided signature | |
39 | // (e.g., the `_` in the code above) with fresh variables. | |
40 | // Then replace the bound items in the fn sig with fresh variables, | |
41 | // so that they represent the view from "inside" the closure. | |
e8be2606 | 42 | let user_provided_sig = self.instantiate_canonical(body.span, &user_provided_poly_sig); |
c620b35d | 43 | let mut user_provided_sig = self.infcx.instantiate_binder_with_fresh_vars( |
9c376795 | 44 | body.span, |
4b012472 | 45 | BoundRegionConversionTime::FnCall, |
9c376795 FG |
46 | user_provided_sig, |
47 | ); | |
48 | ||
c620b35d FG |
49 | // FIXME(async_closures): It's kind of wacky that we must apply this |
50 | // transformation here, since we do the same thing in HIR typeck. | |
51 | // Maybe we could just fix up the canonicalized signature during HIR typeck? | |
52 | if let DefiningTy::CoroutineClosure(_, args) = | |
53 | self.borrowck_context.universal_regions.defining_ty | |
54 | { | |
55 | assert_matches!( | |
56 | self.tcx().coroutine_kind(self.tcx().coroutine_for_closure(mir_def_id)), | |
57 | Some(hir::CoroutineKind::Desugared( | |
58 | hir::CoroutineDesugaring::Async, | |
59 | hir::CoroutineSource::Closure | |
60 | )), | |
61 | "this needs to be modified if we're lowering non-async closures" | |
62 | ); | |
63 | // Make sure to use the args from `DefiningTy` so the right NLL region vids are prepopulated | |
64 | // into the type. | |
65 | let args = args.as_coroutine_closure(); | |
66 | let tupled_upvars_ty = ty::CoroutineClosureSignature::tupled_upvars_by_closure_kind( | |
67 | self.tcx(), | |
68 | args.kind(), | |
69 | Ty::new_tup(self.tcx(), user_provided_sig.inputs()), | |
70 | args.tupled_upvars_ty(), | |
71 | args.coroutine_captures_by_ref_ty(), | |
72 | self.infcx.next_region_var(RegionVariableOrigin::MiscVariable(body.span), || { | |
73 | RegionCtxt::Unknown | |
74 | }), | |
75 | ); | |
76 | ||
77 | let next_ty_var = || { | |
e8be2606 | 78 | self.infcx.next_ty_var(TypeVariableOrigin { span: body.span, param_def_id: None }) |
c620b35d FG |
79 | }; |
80 | let output_ty = Ty::new_coroutine( | |
81 | self.tcx(), | |
82 | self.tcx().coroutine_for_closure(mir_def_id), | |
83 | ty::CoroutineArgs::new( | |
84 | self.tcx(), | |
85 | ty::CoroutineArgsParts { | |
86 | parent_args: args.parent_args(), | |
e8be2606 | 87 | kind_ty: Ty::from_coroutine_closure_kind(self.tcx(), args.kind()), |
c620b35d FG |
88 | return_ty: user_provided_sig.output(), |
89 | tupled_upvars_ty, | |
90 | // For async closures, none of these can be annotated, so just fill | |
91 | // them with fresh ty vars. | |
92 | resume_ty: next_ty_var(), | |
93 | yield_ty: next_ty_var(), | |
94 | witness: next_ty_var(), | |
95 | }, | |
96 | ) | |
97 | .args, | |
98 | ); | |
99 | ||
100 | user_provided_sig = self.tcx().mk_fn_sig( | |
101 | user_provided_sig.inputs().iter().copied(), | |
102 | output_ty, | |
103 | user_provided_sig.c_variadic, | |
104 | user_provided_sig.unsafety, | |
105 | user_provided_sig.abi, | |
106 | ); | |
107 | } | |
108 | ||
c0240ec0 FG |
109 | let is_coroutine_with_implicit_resume_ty = self.tcx().is_coroutine(mir_def_id.to_def_id()) |
110 | && user_provided_sig.inputs().is_empty(); | |
111 | ||
112 | for (&user_ty, arg_decl) in user_provided_sig.inputs().iter().zip_eq( | |
113 | // In MIR, closure args begin with an implicit `self`. | |
114 | // Also, coroutines have a resume type which may be implicitly `()`. | |
115 | body.args_iter() | |
116 | .skip(1 + if is_coroutine_with_implicit_resume_ty { 1 } else { 0 }) | |
117 | .map(|local| &body.local_decls[local]), | |
9c376795 FG |
118 | ) { |
119 | self.ascribe_user_type_skip_wf( | |
120 | arg_decl.ty, | |
121 | ty::UserType::Ty(user_ty), | |
122 | arg_decl.source_info.span, | |
123 | ); | |
124 | } | |
125 | ||
126 | // If the user explicitly annotated the output type, enforce it. | |
127 | let output_decl = &body.local_decls[RETURN_PLACE]; | |
128 | self.ascribe_user_type_skip_wf( | |
129 | output_decl.ty, | |
130 | ty::UserType::Ty(user_provided_sig.output()), | |
131 | output_decl.source_info.span, | |
132 | ); | |
133 | } | |
134 | ||
c295e0f8 | 135 | #[instrument(skip(self, body, universal_regions), level = "debug")] |
ff7c6d11 XL |
136 | pub(super) fn equate_inputs_and_outputs( |
137 | &mut self, | |
dc9dc135 | 138 | body: &Body<'tcx>, |
ff7c6d11 | 139 | universal_regions: &UniversalRegions<'tcx>, |
8faf50e0 | 140 | normalized_inputs_and_output: &[Ty<'tcx>], |
ff7c6d11 | 141 | ) { |
8faf50e0 XL |
142 | let (&normalized_output_ty, normalized_input_tys) = |
143 | normalized_inputs_and_output.split_last().unwrap(); | |
0bf4aa26 | 144 | |
3c0e092e XL |
145 | debug!(?normalized_output_ty); |
146 | debug!(?normalized_input_tys); | |
147 | ||
ff7c6d11 | 148 | // Equate expected input tys with those in the MIR. |
29967ef6 | 149 | for (argument_index, &normalized_input_ty) in normalized_input_tys.iter().enumerate() { |
cdc7bbd5 XL |
150 | if argument_index + 1 >= body.local_decls.len() { |
151 | self.tcx() | |
c0240ec0 | 152 | .dcx() |
c620b35d | 153 | .span_bug(body.span, "found more normalized_input_ty than local_decls"); |
cdc7bbd5 | 154 | } |
3c0e092e | 155 | |
0bf4aa26 | 156 | // In MIR, argument N is stored in local N+1. |
49aad941 | 157 | let local = Local::from_usize(argument_index + 1); |
0bf4aa26 | 158 | |
dc9dc135 | 159 | let mir_input_ty = body.local_decls[local].ty; |
3c0e092e | 160 | |
dc9dc135 | 161 | let mir_input_span = body.local_decls[local].source_info.span; |
0bf4aa26 XL |
162 | self.equate_normalized_input_or_output( |
163 | normalized_input_ty, | |
164 | mir_input_ty, | |
165 | mir_input_span, | |
166 | ); | |
167 | } | |
168 | ||
c0240ec0 FG |
169 | if let Some(mir_yield_ty) = body.yield_ty() { |
170 | let yield_span = body.local_decls[RETURN_PLACE].source_info.span; | |
171 | self.equate_normalized_input_or_output( | |
172 | universal_regions.yield_ty.unwrap(), | |
173 | mir_yield_ty, | |
174 | yield_span, | |
a2a8927a XL |
175 | ); |
176 | } | |
177 | ||
c0240ec0 | 178 | if let Some(mir_resume_ty) = body.resume_ty() { |
dc9dc135 | 179 | let yield_span = body.local_decls[RETURN_PLACE].source_info.span; |
c0240ec0 FG |
180 | self.equate_normalized_input_or_output( |
181 | universal_regions.resume_ty.unwrap(), | |
182 | mir_resume_ty, | |
183 | yield_span, | |
184 | ); | |
2c00a5a8 XL |
185 | } |
186 | ||
416331ca | 187 | // Return types are a bit more complex. They may contain opaque `impl Trait` types. |
dc9dc135 XL |
188 | let mir_output_ty = body.local_decls[RETURN_PLACE].ty; |
189 | let output_span = body.local_decls[RETURN_PLACE].source_info.span; | |
fe692bf9 | 190 | self.equate_normalized_input_or_output(normalized_output_ty, mir_output_ty, output_span); |
ff7c6d11 XL |
191 | } |
192 | ||
2b03887a | 193 | #[instrument(skip(self), level = "debug")] |
0bf4aa26 | 194 | fn equate_normalized_input_or_output(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, span: Span) { |
94222f64 | 195 | if let Err(_) = |
dfeec247 XL |
196 | self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation) |
197 | { | |
94222f64 XL |
198 | // FIXME(jackh726): This is a hack. It's somewhat like |
199 | // `rustc_traits::normalize_after_erasing_regions`. Ideally, we'd | |
200 | // like to normalize *before* inserting into `local_decls`, but | |
201 | // doing so ends up causing some other trouble. | |
2b03887a | 202 | let b = self.normalize(b, Locations::All(span)); |
3c0e092e | 203 | |
c295e0f8 XL |
204 | // Note: if we have to introduce new placeholders during normalization above, then we won't have |
205 | // added those universes to the universe info, which we would want in `relate_tys`. | |
94222f64 XL |
206 | if let Err(terr) = |
207 | self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation) | |
208 | { | |
209 | span_mirbug!( | |
210 | self, | |
211 | Location::START, | |
212 | "equate_normalized_input_or_output: `{:?}=={:?}` failed with `{:?}`", | |
213 | a, | |
214 | b, | |
215 | terr | |
216 | ); | |
217 | } | |
ff7c6d11 XL |
218 | } |
219 | } | |
220 | } |