@@ -10,25 +10,26 @@ use chalk_ir::{
10
10
} ;
11
11
use chalk_solve:: rust_ir:: AssociatedTyValueBound ;
12
12
use hir_def:: {
13
- AssocItemId , FunctionId , GenericDefId , GenericParamId , ImplId , TraitId ,
13
+ AssocItemId , ConstParamId , FunctionId , GenericDefId , GenericParamId , ImplId , ItemContainerId ,
14
+ TraitId ,
14
15
hir:: generics:: { GenericParams , TypeOrConstParamData } ,
15
16
resolver:: HasResolver ,
16
17
} ;
17
18
use rustc_hash:: FxHashMap ;
18
19
use thin_vec:: ThinVec ;
19
20
20
21
use crate :: {
21
- AliasTy , AnyTraitAssocType , Binders , Const , ConstData , ConstValue , DomainGoal , Goal , GoalData ,
22
- ImplTraitLoweringMode , InferenceTable , Interner , Lifetime , LifetimeData , LifetimeElisionKind ,
23
- ParamLoweringMode , PlaceholderIndex , ProjectionTy , Substitution , TraitRef , Ty , TyKind ,
24
- TyLoweringContext , VariableKinds ,
22
+ AliasEq , AliasTy , AnyTraitAssocType , Binders , Const , ConstData , ConstValue , DomainGoal , Goal ,
23
+ GoalData , ImplTraitLoweringMode , InferenceTable , Interner , Lifetime , LifetimeData ,
24
+ LifetimeElisionKind , ParamLoweringMode , PlaceholderIndex , ProgramClause , ProjectionTy ,
25
+ Substitution , TraitRef , Ty , TyKind , TyLoweringContext , VariableKinds , WhereClause ,
25
26
chalk_db:: { AssociatedTyValue , inline_bound_to_generic_predicate} ,
26
27
db:: HirDatabase ,
27
- from_assoc_type_id, from_placeholder_idx,
28
+ error_lifetime , from_assoc_type_id, from_chalk_trait_id , from_placeholder_idx,
28
29
generics:: { Generics , generics} ,
29
30
lt_from_placeholder_idx,
30
31
mapping:: { ToChalk , to_assoc_type_id_rpitit} ,
31
- variable_kinds_from_generics,
32
+ to_placeholder_idx , variable_kinds_from_generics,
32
33
} ;
33
34
34
35
/// An associated type synthesized from a Return Position Impl Trait In Trait
@@ -72,7 +73,7 @@ pub(crate) fn impl_method_rpitit_values(
72
73
db : & dyn HirDatabase ,
73
74
impl_id : ImplId ,
74
75
trait_method_id : FunctionId ,
75
- ) -> Box < [ Arc < AssociatedTyValue > ] > {
76
+ ) -> ThinVec < Arc < AssociatedTyValue > > {
76
77
let impl_items = db. impl_items ( impl_id) ;
77
78
let trait_method_generics = generics ( db, trait_method_id. into ( ) ) ;
78
79
let trait_method = db. function_signature ( trait_method_id) ;
@@ -108,7 +109,7 @@ pub(crate) fn impl_method_rpitit_values(
108
109
trait_method_generics. self_params ( ) ,
109
110
impl_method_generics. self_params ( ) ,
110
111
) {
111
- return Box :: default ( ) ;
112
+ return ThinVec :: new ( ) ;
112
113
}
113
114
114
115
// The inference algorithm works as follows: in the trait method, we replace each RPITIT with an infer var,
@@ -180,10 +181,12 @@ pub(crate) fn impl_method_rpitit_values(
180
181
// generics in the binder.
181
182
let impl_rpitit_binders = VariableKinds :: from_iter (
182
183
Interner ,
183
- trait_assoc. bounds . binders . as_slice ( Interner ) [ ..trait_method_generics. len ( ) ]
184
- . iter ( )
185
- . cloned ( )
186
- . chain ( variable_kinds_from_generics ( db, impl_method_generics. iter_parent_id ( ) ) ) ,
184
+ variable_kinds_from_generics ( db, impl_method_generics. iter_parent_id ( ) ) . chain (
185
+ trait_assoc. bounds . binders . as_slice ( Interner )
186
+ [ trait_method_generics. len_parent ( ) ..]
187
+ . iter ( )
188
+ . cloned ( ) ,
189
+ ) ,
187
190
) ;
188
191
let impl_rpitit =
189
192
Binders :: new ( impl_rpitit_binders, AssociatedTyValueBound { ty : impl_rpitit } ) ;
@@ -202,7 +205,7 @@ fn defaulted_impl_method_rpitit_values(
202
205
trait_method_id : FunctionId ,
203
206
impl_trait_ref : Binders < TraitRef > ,
204
207
trait_method_generics : & Generics ,
205
- ) -> Box < [ Arc < AssociatedTyValue > ] > {
208
+ ) -> ThinVec < Arc < AssociatedTyValue > > {
206
209
let defaulted_rpitit_values = defaulted_trait_method_rpitit_values ( db, trait_method_id) ;
207
210
let impl_generics = generics ( db, impl_id. into ( ) ) ;
208
211
// The associated type generics as the same as the trait method's, but we take the impl as
@@ -461,12 +464,14 @@ impl TypeFolder<Interner> for PlaceholderToBoundVarFolder<'_> {
461
464
)
462
465
. to_ty ( Interner )
463
466
} else if placeholder. parent == self . parent {
464
- BoundVar :: new (
465
- DebruijnIndex :: INNERMOST ,
466
- placeholder. local_id . into_raw ( ) . into_u32 ( ) as usize
467
- + self . parent_generics . len_lifetimes ( ) ,
468
- )
469
- . to_ty ( Interner )
467
+ let local_id = placeholder. local_id . into_raw ( ) . into_u32 ( ) ;
468
+ let index = if matches ! ( self . parent, GenericDefId :: TraitId ( _) ) && local_id == 0 {
469
+ // `Self` parameter.
470
+ 0
471
+ } else {
472
+ local_id as usize + self . parent_generics . len_lifetimes ( )
473
+ } ;
474
+ BoundVar :: new ( DebruijnIndex :: INNERMOST , index) . to_ty ( Interner )
470
475
} else {
471
476
TyKind :: Placeholder ( universe) . intern ( Interner )
472
477
}
@@ -512,13 +517,126 @@ impl TypeFolder<Interner> for PlaceholderToBoundVarFolder<'_> {
512
517
)
513
518
. to_lifetime ( Interner )
514
519
} else if placeholder. parent == self . parent {
515
- BoundVar :: new (
516
- DebruijnIndex :: INNERMOST ,
517
- placeholder. local_id . into_raw ( ) . into_u32 ( ) as usize ,
518
- )
519
- . to_lifetime ( Interner )
520
+ let local_id = placeholder. local_id . into_raw ( ) . into_u32 ( ) as usize ;
521
+ let index = if matches ! ( self . parent, GenericDefId :: TraitId ( _) ) {
522
+ // Account for `Self` parameter that comes before lifetimes.
523
+ local_id + 1
524
+ } else {
525
+ local_id
526
+ } ;
527
+ BoundVar :: new ( DebruijnIndex :: INNERMOST , index) . to_lifetime ( Interner )
520
528
} else {
521
529
Lifetime :: new ( Interner , LifetimeData :: Placeholder ( universe) )
522
530
}
523
531
}
524
532
}
533
+
534
+ /// When inferring a method body of a trait or impl, and that method has RPITITs, we need to add
535
+ /// `RpititGeneratedAssoc = Type` clauses.
536
+ pub ( crate ) fn add_method_body_rpitit_clauses (
537
+ db : & dyn HirDatabase ,
538
+ impl_method_generics : & Generics ,
539
+ clauses : & mut Vec < ProgramClause > ,
540
+ impl_method : FunctionId ,
541
+ ) {
542
+ match impl_method. loc ( db) . container {
543
+ ItemContainerId :: ImplId ( impl_id) => {
544
+ ( || {
545
+ let method_data = db. function_signature ( impl_method) ;
546
+ let trait_ref = db. impl_trait ( impl_id) ?;
547
+ let trait_items =
548
+ db. trait_items ( from_chalk_trait_id ( trait_ref. skip_binders ( ) . trait_id ) ) ;
549
+ let trait_method = trait_items. method_by_name ( & method_data. name ) ?;
550
+
551
+ let rpitits = impl_method_rpitit_values ( db, impl_id, trait_method) ;
552
+ let mut substitution = None ;
553
+ clauses. extend ( rpitits. iter ( ) . map ( |rpitit| {
554
+ let ( impl_subst, trait_subst) = substitution. get_or_insert_with ( || {
555
+ let impl_method_subst = impl_method_generics. placeholder_subst ( db) ;
556
+ let trait_method_generics =
557
+ crate :: generics:: generics ( db, trait_method. into ( ) ) ;
558
+ let trait_method_subst = trait_method_generics. placeholder_subst ( db) ;
559
+ let impl_subst = Substitution :: from_iter (
560
+ Interner ,
561
+ impl_method_subst. as_slice ( Interner )
562
+ [ ..impl_method_generics. len_parent ( ) ]
563
+ . iter ( )
564
+ . chain (
565
+ & trait_method_subst. as_slice ( Interner )
566
+ [ trait_method_generics. len_parent ( ) ..] ,
567
+ ) ,
568
+ ) ;
569
+
570
+ let trait_ref_subst =
571
+ trait_ref. clone ( ) . substitute ( Interner , & impl_method_subst) ;
572
+ // Lifetime parameters may change between trait and impl, and we don't check from that in `impl_method_rpitit_values()`
573
+ // (because it's valid). So fill them with errors.
574
+ // FIXME: This isn't really correct, we should still fill the lifetimes. rustc does some kind of mapping, I think there
575
+ // are also restrictions on what exactly lifetimes can change between trait and impl.
576
+ let trait_method_subst = std:: iter:: repeat_n (
577
+ error_lifetime ( ) . cast ( Interner ) ,
578
+ trait_method_generics. len_lifetimes_self ( ) ,
579
+ )
580
+ . chain (
581
+ impl_method_generics. iter_self_type_or_consts_id ( ) . map (
582
+ |( param_id, param_data) | {
583
+ let placeholder = to_placeholder_idx ( db, param_id) ;
584
+ match param_data {
585
+ TypeOrConstParamData :: TypeParamData ( _) => {
586
+ placeholder. to_ty ( Interner ) . cast ( Interner )
587
+ }
588
+ TypeOrConstParamData :: ConstParamData ( _) => placeholder
589
+ . to_const (
590
+ Interner ,
591
+ db. const_param_ty ( ConstParamId :: from_unchecked (
592
+ param_id,
593
+ ) ) ,
594
+ )
595
+ . cast ( Interner ) ,
596
+ }
597
+ } ,
598
+ ) ,
599
+ ) ;
600
+ let trait_subst = Substitution :: from_iter (
601
+ Interner ,
602
+ trait_ref_subst
603
+ . substitution
604
+ . iter ( Interner )
605
+ . cloned ( )
606
+ . chain ( trait_method_subst) ,
607
+ ) ;
608
+
609
+ ( impl_subst, trait_subst)
610
+ } ) ;
611
+ WhereClause :: AliasEq ( AliasEq {
612
+ alias : AliasTy :: Projection ( ProjectionTy {
613
+ associated_ty_id : rpitit. associated_ty_id ,
614
+ substitution : trait_subst. clone ( ) ,
615
+ } ) ,
616
+ ty : rpitit. value . clone ( ) . substitute ( Interner , & * impl_subst) . ty ,
617
+ } )
618
+ . cast ( Interner )
619
+ } ) ) ;
620
+
621
+ Some ( ( ) )
622
+ } ) ( ) ;
623
+ }
624
+ ItemContainerId :: TraitId ( _) => {
625
+ let rpitits = defaulted_trait_method_rpitit_values ( db, impl_method) ;
626
+ let mut substitution = None ;
627
+ clauses. extend ( rpitits. iter ( ) . map ( |( trait_rpitit, rpitit_value) | {
628
+ let substitution =
629
+ substitution. get_or_insert_with ( || impl_method_generics. placeholder_subst ( db) ) ;
630
+ WhereClause :: AliasEq ( AliasEq {
631
+ alias : AliasTy :: Projection ( ProjectionTy {
632
+ associated_ty_id : to_assoc_type_id_rpitit ( * trait_rpitit) ,
633
+ substitution : substitution. clone ( ) ,
634
+ } ) ,
635
+ ty : rpitit_value. clone ( ) . substitute ( Interner , & * substitution) ,
636
+ } )
637
+ . cast ( Interner )
638
+ } ) ) ;
639
+ }
640
+ _ => { }
641
+ }
642
+ }
0 commit comments