11use crate :: clauses:: ClauseBuilder ;
22use crate :: infer:: instantiate:: IntoBindersAndValue ;
3+ use crate :: rust_ir:: WellKnownTrait ;
34use crate :: { Interner , RustIrDatabase , TraitRef } ;
4- use chalk_ir:: { ApplicationTy , Binders , Substitution , Ty , TyData , TypeName , VariableKinds } ;
5+ use chalk_ir:: {
6+ AliasTy , ApplicationTy , Binders , Normalize , ProjectionTy , Substitution , TraitId , Ty , TyData ,
7+ TypeName , VariableKinds ,
8+ } ;
59
6- // Handles clauses for FnOnce/FnMut/Fn
10+ /// Handles clauses for FnOnce/FnMut/Fn.
11+ /// If `assoc_output` is `true`, we push a clause of the form
12+ /// `Normalize(<fn(A) -> B as FnOnce<(A,)>>::Output -> B) :- Implemented(fn(A) -> B as FnOnce<(A,)>`
13+ ///
14+ /// If `assoc_output` is `false`, we push a clause of the form
15+ /// `Implemented(fn(A) -> B as FnOnce<(A,)>)`
716pub fn add_fn_trait_program_clauses < I : Interner > (
817 db : & dyn RustIrDatabase < I > ,
918 builder : & mut ClauseBuilder < ' _ , I > ,
10- trait_ref : & TraitRef < I > ,
19+ trait_id : TraitId < I > ,
1120 ty : & TyData < I > ,
21+ assoc_output : bool ,
1222) {
1323 match ty {
1424 TyData :: Function ( fn_val) => {
1525 let interner = db. interner ( ) ;
16- let ( binders, sub) = fn_val. into_binders_and_value ( interner) ;
26+ let ( binders, orig_sub) = fn_val. into_binders_and_value ( interner) ;
27+ // Take all of the arguments except for the last one, which
28+ // represents the return type
29+ let arg_sub = Substitution :: from (
30+ interner,
31+ orig_sub. iter ( interner) . take ( orig_sub. len ( interner) - 1 ) ,
32+ ) ;
33+ let fn_output_ty = orig_sub
34+ . at ( interner, orig_sub. len ( interner) - 1 )
35+ . assert_ty_ref ( interner) ;
1736
1837 // We are constructing a reference to `FnOnce<Args>`, where
1938 // `Args` is a tuple of the function's argument types
2039 let tupled = Ty :: new (
2140 interner,
2241 TyData :: Apply ( ApplicationTy {
23- name : TypeName :: Tuple ( sub . len ( interner) ) ,
24- substitution : sub . clone ( ) ,
42+ name : TypeName :: Tuple ( arg_sub . len ( interner) ) ,
43+ substitution : arg_sub . clone ( ) ,
2544 } ) ,
2645 ) ;
2746
@@ -31,16 +50,42 @@ pub fn add_fn_trait_program_clauses<I: Interner>(
3150 // Given a function type `fn(A1, A2, ..., AN)`, construct a `TraitRef`
3251 // of the form `fn(A1, A2, ..., AN): FnOnce<(A1, A2, ..., AN)>`
3352 let new_trait_ref = TraitRef {
34- trait_id : trait_ref . trait_id ,
35- substitution : tupled_sub,
53+ trait_id,
54+ substitution : tupled_sub. clone ( ) ,
3655 } ;
3756
3857 // Functions types come with a binder, which we push so
3958 // that the `TraitRef` properly references any bound lifetimes
4059 // (e.g. `for<'a> fn(&'a u8): FnOnce<(&'b u8)>`)
4160 let bound_ref = Binders :: new ( VariableKinds :: from ( interner, binders) , new_trait_ref) ;
4261 builder. push_binders ( & bound_ref, |this, inner_trait| {
43- this. push_fact ( inner_trait) ;
62+ if assoc_output {
63+ //The `Output` type is defined on the `FnOnceTrait`
64+ let fn_once = db. trait_datum ( trait_id) ;
65+ assert_eq ! ( fn_once. well_known, Some ( WellKnownTrait :: FnOnceTrait ) ) ;
66+ let assoc_types = & fn_once. associated_ty_ids ;
67+ if assoc_types. len ( ) != 1 {
68+ panic ! (
69+ "FnOnce trait should have exactly one associated type, found {:?}" ,
70+ assoc_types
71+ ) ;
72+ }
73+
74+ // Construct `Normalize(<fn(A) -> B as FnOnce<(A,)>>::Output -> B)`
75+ let assoc_output_ty = assoc_types[ 0 ] ;
76+ let proj_ty = ProjectionTy {
77+ associated_ty_id : assoc_output_ty,
78+ substitution : tupled_sub,
79+ } ;
80+ let normalize = Normalize {
81+ alias : AliasTy :: Projection ( proj_ty) ,
82+ ty : fn_output_ty. clone ( ) ,
83+ } ;
84+
85+ this. push_clause ( normalize, std:: iter:: once ( inner_trait) ) ;
86+ } else {
87+ this. push_fact ( inner_trait) ;
88+ }
4489 } )
4590 }
4691 _ => { }
0 commit comments