]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_borrowck/src/type_check/input_output.rs
Replacing bound vars is actually instantiating a binder
[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 rustc_index::vec::Idx;
11 use rustc_infer::infer::LateBoundRegionConversionTime;
12 use rustc_middle::mir::*;
13 use rustc_middle::ty::{self, 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     /// Check explicit closure signature annotation,
22     /// e.g., `|x: FxHashMap<_, &'static u32>| ...`.
23     #[instrument(skip(self, body), level = "debug")]
24     pub(super) fn check_signature_annotation(&mut self, body: &Body<'tcx>) {
25         let mir_def_id = body.source.def_id().expect_local();
26         if !self.tcx().is_closure(mir_def_id.to_def_id()) {
27             return;
28         }
29         let Some(user_provided_poly_sig) =
30             self.tcx().typeck(mir_def_id).user_provided_sigs.get(&mir_def_id)
31         else {
32             return;
33         };
34
35         // Instantiate the canonicalized variables from user-provided signature
36         // (e.g., the `_` in the code above) with fresh variables.
37         // Then replace the bound items in the fn sig with fresh variables,
38         // so that they represent the view from "inside" the closure.
39         let user_provided_sig = self
40             .instantiate_canonical_with_fresh_inference_vars(body.span, &user_provided_poly_sig);
41         let user_provided_sig = self.infcx.instantiate_binder_with_fresh_vars(
42             body.span,
43             LateBoundRegionConversionTime::FnCall,
44             user_provided_sig,
45         );
46
47         for (&user_ty, arg_decl) in user_provided_sig.inputs().iter().zip(
48             // In MIR, closure args begin with an implicit `self`. Skip it!
49             body.args_iter().skip(1).map(|local| &body.local_decls[local]),
50         ) {
51             self.ascribe_user_type_skip_wf(
52                 arg_decl.ty,
53                 ty::UserType::Ty(user_ty),
54                 arg_decl.source_info.span,
55             );
56         }
57
58         // If the user explicitly annotated the output type, enforce it.
59         let output_decl = &body.local_decls[RETURN_PLACE];
60         self.ascribe_user_type_skip_wf(
61             output_decl.ty,
62             ty::UserType::Ty(user_provided_sig.output()),
63             output_decl.source_info.span,
64         );
65     }
66
67     #[instrument(skip(self, body, universal_regions), level = "debug")]
68     pub(super) fn equate_inputs_and_outputs(
69         &mut self,
70         body: &Body<'tcx>,
71         universal_regions: &UniversalRegions<'tcx>,
72         normalized_inputs_and_output: &[Ty<'tcx>],
73     ) {
74         let (&normalized_output_ty, normalized_input_tys) =
75             normalized_inputs_and_output.split_last().unwrap();
76
77         debug!(?normalized_output_ty);
78         debug!(?normalized_input_tys);
79
80         // Equate expected input tys with those in the MIR.
81         for (argument_index, &normalized_input_ty) in normalized_input_tys.iter().enumerate() {
82             if argument_index + 1 >= body.local_decls.len() {
83                 self.tcx()
84                     .sess
85                     .delay_span_bug(body.span, "found more normalized_input_ty than local_decls");
86                 break;
87             }
88
89             // In MIR, argument N is stored in local N+1.
90             let local = Local::new(argument_index + 1);
91
92             let mir_input_ty = body.local_decls[local].ty;
93
94             let mir_input_span = body.local_decls[local].source_info.span;
95             self.equate_normalized_input_or_output(
96                 normalized_input_ty,
97                 mir_input_ty,
98                 mir_input_span,
99             );
100         }
101
102         debug!(
103             "equate_inputs_and_outputs: body.yield_ty {:?}, universal_regions.yield_ty {:?}",
104             body.yield_ty(),
105             universal_regions.yield_ty
106         );
107
108         // We will not have a universal_regions.yield_ty if we yield (by accident)
109         // outside of a generator and return an `impl Trait`, so emit a delay_span_bug
110         // because we don't want to panic in an assert here if we've already got errors.
111         if body.yield_ty().is_some() != universal_regions.yield_ty.is_some() {
112             self.tcx().sess.delay_span_bug(
113                 body.span,
114                 &format!(
115                     "Expected body to have yield_ty ({:?}) iff we have a UR yield_ty ({:?})",
116                     body.yield_ty(),
117                     universal_regions.yield_ty,
118                 ),
119             );
120         }
121
122         if let (Some(mir_yield_ty), Some(ur_yield_ty)) =
123             (body.yield_ty(), universal_regions.yield_ty)
124         {
125             let yield_span = body.local_decls[RETURN_PLACE].source_info.span;
126             self.equate_normalized_input_or_output(ur_yield_ty, mir_yield_ty, yield_span);
127         }
128
129         // Return types are a bit more complex. They may contain opaque `impl Trait` types.
130         let mir_output_ty = body.local_decls[RETURN_PLACE].ty;
131         let output_span = body.local_decls[RETURN_PLACE].source_info.span;
132         if let Err(terr) = self.eq_types(
133             normalized_output_ty,
134             mir_output_ty,
135             Locations::All(output_span),
136             ConstraintCategory::BoringNoLocation,
137         ) {
138             span_mirbug!(
139                 self,
140                 Location::START,
141                 "equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`",
142                 normalized_output_ty,
143                 mir_output_ty,
144                 terr
145             );
146         };
147     }
148
149     #[instrument(skip(self), level = "debug")]
150     fn equate_normalized_input_or_output(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, span: Span) {
151         if let Err(_) =
152             self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation)
153         {
154             // FIXME(jackh726): This is a hack. It's somewhat like
155             // `rustc_traits::normalize_after_erasing_regions`. Ideally, we'd
156             // like to normalize *before* inserting into `local_decls`, but
157             // doing so ends up causing some other trouble.
158             let b = self.normalize(b, Locations::All(span));
159
160             // Note: if we have to introduce new placeholders during normalization above, then we won't have
161             // added those universes to the universe info, which we would want in `relate_tys`.
162             if let Err(terr) =
163                 self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation)
164             {
165                 span_mirbug!(
166                     self,
167                     Location::START,
168                     "equate_normalized_input_or_output: `{:?}=={:?}` failed with `{:?}`",
169                     a,
170                     b,
171                     terr
172                 );
173             }
174         }
175     }
176 }