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