@@ -9,17 +9,18 @@ use rustc_hir as hir;
99use rustc_hir:: lang_items:: LangItem ;
1010use rustc_hir_analysis:: hir_ty_lowering:: HirTyLowerer ;
1111use rustc_infer:: infer:: { BoundRegionConversionTime , DefineOpaqueTypes , InferOk , InferResult } ;
12- use rustc_infer:: traits:: { ObligationCauseCode , PredicateObligations } ;
12+ use rustc_infer:: traits:: { ObligationCause , ObligationCauseCode , PredicateObligations } ;
1313use rustc_macros:: { TypeFoldable , TypeVisitable } ;
1414use rustc_middle:: span_bug;
15+ use rustc_middle:: ty:: error:: TypeError ;
1516use rustc_middle:: ty:: {
16- self , ClosureKind , GenericArgs , Ty , TyCtxt , TypeSuperVisitable , TypeVisitable ,
17- TypeVisitableExt , TypeVisitor ,
17+ self , ClosureKind , GenericArgs , Ty , TyCtxt , TypeFoldable , TypeFolder , TypeSuperFoldable ,
18+ TypeSuperVisitable , TypeVisitable , TypeVisitableExt , TypeVisitor ,
1819} ;
1920use rustc_span:: def_id:: LocalDefId ;
2021use rustc_span:: { DUMMY_SP , Span } ;
2122use rustc_trait_selection:: error_reporting:: traits:: ArgKind ;
22- use rustc_trait_selection:: traits;
23+ use rustc_trait_selection:: traits:: { self , ObligationCtxt } ;
2324use tracing:: { debug, instrument, trace} ;
2425
2526use super :: { CoroutineTypes , Expectation , FnCtxt , check_fn} ;
@@ -384,56 +385,83 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
384385 // Make sure that we didn't infer a signature that mentions itself.
385386 // This can happen when we elaborate certain supertrait bounds that
386387 // mention projections containing the `Self` type. See #105401.
387- struct MentionsTy < ' tcx > {
388- expected_ty : Ty < ' tcx > ,
389- }
390- impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for MentionsTy < ' tcx > {
391- type Result = ControlFlow < ( ) > ;
392-
393- fn visit_ty ( & mut self , t : Ty < ' tcx > ) -> Self :: Result {
394- if t == self . expected_ty {
395- ControlFlow :: Break ( ( ) )
396- } else {
397- t. super_visit_with ( self )
398- }
399- }
400- }
401-
402- // Don't infer a closure signature from a goal that names the closure type as this will
403- // (almost always) lead to occurs check errors later in type checking.
388+ //
389+ // Doing so will (almost always) lead to occurs check errors later in
390+ // type checking.
404391 if self . next_trait_solver ( )
405392 && let Some ( inferred_sig) = inferred_sig
406393 {
407- // In the new solver it is difficult to explicitly normalize the inferred signature as we
408- // would have to manually handle universes and rewriting bound vars and placeholders back
409- // and forth.
410- //
411- // Instead we take advantage of the fact that we relating an inference variable with an alias
412- // will only instantiate the variable if the alias is rigid(*not quite). Concretely we:
413- // - Create some new variable `?sig`
414- // - Equate `?sig` with the unnormalized signature, e.g. `fn(<Foo<?x> as Trait>::Assoc)`
415- // - Depending on whether `<Foo<?x> as Trait>::Assoc` is rigid, ambiguous or normalizeable,
416- // we will either wind up with `?sig=<Foo<?x> as Trait>::Assoc/?y/ConcreteTy` respectively.
417- //
418- // *: In cases where there are ambiguous aliases in the signature that make use of bound vars
419- // they will wind up present in `?sig` even though they are non-rigid.
394+ // If we've got `F: FnOnce(<u32 as Id<F>>::This)` we want to
395+ // use this to infer the signature `FnOnce(u32)` for the closure.
420396 //
421- // This is a bit weird and means we may wind up discarding the goal due to it naming `expected_ty`
422- // even though the normalized form may not name `expected_ty`. However, this matches the existing
423- // behaviour of the old solver and would be technically a breaking change to fix.
397+ // We handle self-referential aliases here by relying on generalization
398+ // which replaces such aliases with inference variables. This is currently
399+ // a bit too weak, see trait-system-refactor-initiative#191.
400+ struct ReplaceTy < ' tcx > {
401+ tcx : TyCtxt < ' tcx > ,
402+ expected_ty : Ty < ' tcx > ,
403+ with_ty : Ty < ' tcx > ,
404+ }
405+ impl < ' tcx > TypeFolder < TyCtxt < ' tcx > > for ReplaceTy < ' tcx > {
406+ fn cx ( & self ) -> TyCtxt < ' tcx > {
407+ self . tcx
408+ }
409+
410+ fn fold_ty ( & mut self , t : Ty < ' tcx > ) -> Ty < ' tcx > {
411+ if t == self . expected_ty {
412+ self . with_ty
413+ } else {
414+ t. super_fold_with ( self )
415+ }
416+ }
417+ }
424418 let generalized_fnptr_sig = self . next_ty_var ( span) ;
425419 let inferred_fnptr_sig = Ty :: new_fn_ptr ( self . tcx , inferred_sig. sig ) ;
426- self . demand_eqtype ( span, inferred_fnptr_sig, generalized_fnptr_sig) ;
427-
428- let resolved_sig = self . resolve_vars_if_possible ( generalized_fnptr_sig) ;
429-
430- if resolved_sig. visit_with ( & mut MentionsTy { expected_ty } ) . is_continue ( ) {
431- expected_sig = Some ( ExpectedSig {
432- cause_span : inferred_sig. cause_span ,
433- sig : resolved_sig. fn_sig ( self . tcx ) ,
434- } ) ;
420+ let inferred_fnptr_sig = inferred_fnptr_sig. fold_with ( & mut ReplaceTy {
421+ tcx : self . tcx ,
422+ expected_ty,
423+ with_ty : generalized_fnptr_sig,
424+ } ) ;
425+ let resolved_sig = self . commit_if_ok ( |snapshot| {
426+ let outer_universe = self . universe ( ) ;
427+ let ocx = ObligationCtxt :: new ( self ) ;
428+ ocx. eq (
429+ & ObligationCause :: dummy ( ) ,
430+ self . param_env ,
431+ generalized_fnptr_sig,
432+ inferred_fnptr_sig,
433+ ) ?;
434+ if ocx. select_where_possible ( ) . is_empty ( ) {
435+ self . leak_check ( outer_universe, Some ( snapshot) ) ?;
436+ Ok ( self . resolve_vars_if_possible ( generalized_fnptr_sig) )
437+ } else {
438+ Err ( TypeError :: Mismatch )
439+ }
440+ } ) ;
441+ match resolved_sig {
442+ Ok ( resolved_sig) => {
443+ expected_sig = Some ( ExpectedSig {
444+ cause_span : inferred_sig. cause_span ,
445+ sig : resolved_sig. fn_sig ( self . tcx ) ,
446+ } )
447+ }
448+ Err ( _) => { }
435449 }
436450 } else {
451+ struct MentionsTy < ' tcx > {
452+ expected_ty : Ty < ' tcx > ,
453+ }
454+ impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for MentionsTy < ' tcx > {
455+ type Result = ControlFlow < ( ) > ;
456+
457+ fn visit_ty ( & mut self , t : Ty < ' tcx > ) -> Self :: Result {
458+ if t == self . expected_ty {
459+ ControlFlow :: Break ( ( ) )
460+ } else {
461+ t. super_visit_with ( self )
462+ }
463+ }
464+ }
437465 if inferred_sig. visit_with ( & mut MentionsTy { expected_ty } ) . is_continue ( ) {
438466 expected_sig = inferred_sig;
439467 }
0 commit comments