@@ -296,7 +296,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
296
296
297
297
/// Given the expected type, figures out what it can about this closure we
298
298
/// are about to type check:
299
- #[ instrument( skip( self ) , level = "debug" ) ]
299
+ #[ instrument( skip( self ) , level = "debug" , ret ) ]
300
300
fn deduce_closure_signature (
301
301
& self ,
302
302
expected_ty : Ty < ' tcx > ,
@@ -378,6 +378,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
378
378
bound_predicate. rebind ( proj_predicate) ,
379
379
) ,
380
380
) ;
381
+
381
382
// Make sure that we didn't infer a signature that mentions itself.
382
383
// This can happen when we elaborate certain supertrait bounds that
383
384
// mention projections containing the `Self` type. See #105401.
@@ -395,8 +396,45 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
395
396
}
396
397
}
397
398
}
398
- if inferred_sig. visit_with ( & mut MentionsTy { expected_ty } ) . is_continue ( ) {
399
- expected_sig = inferred_sig;
399
+
400
+ // Don't infer a closure signature from a goal that names the closure type as this will
401
+ // (almost always) lead to occurs check errors later in type checking.
402
+ if self . next_trait_solver ( )
403
+ && let Some ( inferred_sig) = inferred_sig
404
+ {
405
+ // In the new solver it is difficult to explicitly normalize the inferred signature as we
406
+ // would have to manually handle universes and rewriting bound vars and placeholders back
407
+ // and forth.
408
+ //
409
+ // Instead we take advantage of the fact that we relating an inference variable with an alias
410
+ // will only instantiate the variable if the alias is rigid(*not quite). Concretely we:
411
+ // - Create some new variable `?sig`
412
+ // - Equate `?sig` with the unnormalized signature, e.g. `fn(<Foo<?x> as Trait>::Assoc)`
413
+ // - Depending on whether `<Foo<?x> as Trait>::Assoc` is rigid, ambiguous or normalizeable,
414
+ // we will either wind up with `?sig=<Foo<?x> as Trait>::Assoc/?y/ConcreteTy` respectively.
415
+ //
416
+ // *: In cases where there are ambiguous aliases in the signature that make use of bound vars
417
+ // they will wind up present in `?sig` even though they are non-rigid.
418
+ //
419
+ // This is a bit weird and means we may wind up discarding the goal due to it naming `expected_ty`
420
+ // even though the normalized form may not name `expected_ty`. However, this matches the existing
421
+ // behaviour of the old solver and would be technically a breaking change to fix.
422
+ let generalized_fnptr_sig = self . next_ty_var ( span) ;
423
+ let inferred_fnptr_sig = Ty :: new_fn_ptr ( self . tcx , inferred_sig. sig ) ;
424
+ self . demand_eqtype ( span, inferred_fnptr_sig, generalized_fnptr_sig) ;
425
+
426
+ let resolved_sig = self . resolve_vars_if_possible ( generalized_fnptr_sig) ;
427
+
428
+ if resolved_sig. visit_with ( & mut MentionsTy { expected_ty } ) . is_continue ( ) {
429
+ expected_sig = Some ( ExpectedSig {
430
+ cause_span : inferred_sig. cause_span ,
431
+ sig : resolved_sig. fn_sig ( self . tcx ) ,
432
+ } ) ;
433
+ }
434
+ } else {
435
+ if inferred_sig. visit_with ( & mut MentionsTy { expected_ty } ) . is_continue ( ) {
436
+ expected_sig = inferred_sig;
437
+ }
400
438
}
401
439
}
402
440
0 commit comments