@@ -126,6 +126,31 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
126126 ) ;
127127 }
128128
129+ // FIXME(BoxyUwU): This should probably be part of a larger borrowck dev-guide chapter
130+ //
131+ /// Enforce that the types of the locals corresponding to the inputs and output of
132+ /// the body are equal to those of the (normalized) signature.
133+ ///
134+ /// This is necessary for two reasons:
135+ /// - Locals in the MIR all start out with `'erased` regions and then are replaced
136+ /// with unconstrained nll vars. If we have a function returning `&'a u32` then
137+ /// the local `_0: &'?10 u32` needs to have its region var equated with the nll
138+ /// var representing `'a`. i.e. borrow check must uphold that `'?10 = 'a`.
139+ /// - When computing the normalized signature we may introduce new unconstrained nll
140+ /// vars due to higher ranked where clauses ([#136547]). We then wind up with implied
141+ /// bounds involving these vars.
142+ ///
143+ /// For this reason it is important that we equate with the *normalized* signature
144+ /// which was produced when computing implied bounds. If we do not do so then we will
145+ /// wind up with implied bounds on nll vars which cannot actually be used as the nll
146+ /// var never gets related to anything.
147+ ///
148+ /// For 'closure-like' bodies this function effectively relates the *inferred* signature
149+ /// of the closure against the locals corresponding to the closure's inputs/output. It *does
150+ /// not* relate the user provided types for the signature to the locals, this is handled
151+ /// separately by: [`TypeChecker::check_signature_annotation`].
152+ ///
153+ /// [#136547]: <https://www.github.com/rust-lang/rust/issues/136547>
129154 #[ instrument( skip( self ) , level = "debug" ) ]
130155 pub ( super ) fn equate_inputs_and_outputs ( & mut self , normalized_inputs_and_output : & [ Ty < ' tcx > ] ) {
131156 let ( & normalized_output_ty, normalized_input_tys) =
@@ -173,38 +198,43 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
173198 ) ;
174199 }
175200
176- // Return types are a bit more complex. They may contain opaque `impl Trait` types.
177- let mir_output_ty = self . body . local_decls [ RETURN_PLACE ] . ty ;
201+ // Equate expected output ty with the type of the RETURN_PLACE in MIR
202+ let mir_output_ty = self . body . return_ty ( ) ;
178203 let output_span = self . body . local_decls [ RETURN_PLACE ] . source_info . span ;
179204 self . equate_normalized_input_or_output ( normalized_output_ty, mir_output_ty, output_span) ;
180205 }
181206
182207 #[ instrument( skip( self ) , level = "debug" ) ]
183208 fn equate_normalized_input_or_output ( & mut self , a : Ty < ' tcx > , b : Ty < ' tcx > , span : Span ) {
209+ if self . infcx . next_trait_solver ( ) {
210+ self . eq_types ( a, b, Locations :: All ( span) , ConstraintCategory :: BoringNoLocation )
211+ . unwrap_or_else ( |terr| {
212+ span_mirbug ! (
213+ self ,
214+ Location :: START ,
215+ "equate_normalized_input_or_output: `{a:?}=={b:?}` failed with `{terr:?}`" ,
216+ ) ;
217+ } ) ;
218+ }
219+
220+ // This is a hack. `body.local_decls` are not necessarily normalized in the old
221+ // solver due to not deeply normalizing in writeback. So we must re-normalize here.
222+ //
223+ // However, in most cases normalizing is unnecessary so we only do so if it may be
224+ // necessary for type equality to hold. This leads to some (very minor) performance
225+ // wins.
184226 if let Err ( _) =
185227 self . eq_types ( a, b, Locations :: All ( span) , ConstraintCategory :: BoringNoLocation )
186228 {
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.
191229 let b = self . normalize ( b, Locations :: All ( span) ) ;
192-
193- // Note: if we have to introduce new placeholders during normalization above, then we
194- // won't have added those universes to the universe info, which we would want in
195- // `relate_tys`.
196- if let Err ( terr) =
197- self . eq_types ( a, b, Locations :: All ( span) , ConstraintCategory :: BoringNoLocation )
198- {
199- span_mirbug ! (
200- self ,
201- Location :: START ,
202- "equate_normalized_input_or_output: `{:?}=={:?}` failed with `{:?}`" ,
203- a,
204- b,
205- terr
206- ) ;
207- }
208- }
230+ self . eq_types ( a, b, Locations :: All ( span) , ConstraintCategory :: BoringNoLocation )
231+ . unwrap_or_else ( |terr| {
232+ span_mirbug ! (
233+ self ,
234+ Location :: START ,
235+ "equate_normalized_input_or_output: `{a:?}=={b:?}` failed with `{terr:?}`" ,
236+ ) ;
237+ } ) ;
238+ } ;
209239 }
210240}
0 commit comments