1
1
//! The implementation of `RustIrDatabase` for Chalk, which provides information
2
2
//! about the code that Chalk needs.
3
3
use core:: ops;
4
- use std:: { iter, sync:: Arc } ;
4
+ use std:: { iter, ops :: ControlFlow , sync:: Arc } ;
5
5
6
6
use tracing:: debug;
7
7
@@ -10,9 +10,10 @@ use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait};
10
10
11
11
use base_db:: CrateId ;
12
12
use hir_def:: {
13
+ data:: adt:: StructFlags ,
13
14
hir:: Movability ,
14
15
lang_item:: { LangItem , LangItemTarget } ,
15
- AssocItemId , BlockId , GenericDefId , HasModule , ItemContainerId , Lookup , TypeAliasId ,
16
+ AssocItemId , BlockId , GenericDefId , HasModule , ItemContainerId , Lookup , TypeAliasId , VariantId ,
16
17
} ;
17
18
use hir_expand:: name:: name;
18
19
@@ -33,7 +34,7 @@ use crate::{
33
34
34
35
pub ( crate ) type AssociatedTyDatum = chalk_solve:: rust_ir:: AssociatedTyDatum < Interner > ;
35
36
pub ( crate ) type TraitDatum = chalk_solve:: rust_ir:: TraitDatum < Interner > ;
36
- pub ( crate ) type StructDatum = chalk_solve:: rust_ir:: AdtDatum < Interner > ;
37
+ pub ( crate ) type AdtDatum = chalk_solve:: rust_ir:: AdtDatum < Interner > ;
37
38
pub ( crate ) type ImplDatum = chalk_solve:: rust_ir:: ImplDatum < Interner > ;
38
39
pub ( crate ) type OpaqueTyDatum = chalk_solve:: rust_ir:: OpaqueTyDatum < Interner > ;
39
40
@@ -53,8 +54,8 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
53
54
fn trait_datum ( & self , trait_id : TraitId ) -> Arc < TraitDatum > {
54
55
self . db . trait_datum ( self . krate , trait_id)
55
56
}
56
- fn adt_datum ( & self , struct_id : AdtId ) -> Arc < StructDatum > {
57
- self . db . struct_datum ( self . krate , struct_id)
57
+ fn adt_datum ( & self , struct_id : AdtId ) -> Arc < AdtDatum > {
58
+ self . db . adt_datum ( self . krate , struct_id)
58
59
}
59
60
fn adt_repr ( & self , _struct_id : AdtId ) -> Arc < rust_ir:: AdtRepr < Interner > > {
60
61
// FIXME: keep track of these
@@ -136,81 +137,92 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
136
137
_ => self_ty_fp. as_ref ( ) . map ( std:: slice:: from_ref) . unwrap_or ( & [ ] ) ,
137
138
} ;
138
139
139
- let trait_module = trait_. module ( self . db . upcast ( ) ) ;
140
- let type_module = match self_ty_fp {
141
- Some ( TyFingerprint :: Adt ( adt_id) ) => Some ( adt_id. module ( self . db . upcast ( ) ) ) ,
142
- Some ( TyFingerprint :: ForeignType ( type_id) ) => {
143
- Some ( from_foreign_def_id ( type_id) . module ( self . db . upcast ( ) ) )
144
- }
145
- Some ( TyFingerprint :: Dyn ( trait_id) ) => Some ( trait_id. module ( self . db . upcast ( ) ) ) ,
146
- _ => None ,
147
- } ;
148
-
149
- let mut def_blocks =
150
- [ trait_module. containing_block ( ) , type_module. and_then ( |it| it. containing_block ( ) ) ] ;
151
-
152
- // Note: Since we're using impls_for_trait, only impls where the trait
153
- // can be resolved should ever reach Chalk. impl_datum relies on that
154
- // and will panic if the trait can't be resolved.
155
- let in_deps = self . db . trait_impls_in_deps ( self . krate ) ;
156
- let in_self = self . db . trait_impls_in_crate ( self . krate ) ;
157
-
158
- let block_impls = iter:: successors ( self . block , |& block_id| {
159
- cov_mark:: hit!( block_local_impls) ;
160
- self . db . block_def_map ( block_id) . parent ( ) . and_then ( |module| module. containing_block ( ) )
161
- } )
162
- . inspect ( |& block_id| {
163
- // make sure we don't search the same block twice
164
- def_blocks. iter_mut ( ) . for_each ( |block| {
165
- if * block == Some ( block_id) {
166
- * block = None ;
167
- }
168
- } ) ;
169
- } )
170
- . filter_map ( |block_id| self . db . trait_impls_in_block ( block_id) ) ;
171
-
172
140
let id_to_chalk = |id : hir_def:: ImplId | id. to_chalk ( self . db ) ;
141
+
173
142
let mut result = vec ! [ ] ;
174
- match fps {
175
- [ ] => {
176
- debug ! ( "Unrestricted search for {:?} impls..." , trait_) ;
177
- let mut f = |impls : & TraitImpls | {
178
- result. extend ( impls. for_trait ( trait_) . map ( id_to_chalk) ) ;
179
- } ;
180
- f ( & in_self) ;
181
- in_deps. iter ( ) . map ( ops:: Deref :: deref) . for_each ( & mut f) ;
182
- block_impls. for_each ( |it| f ( & it) ) ;
183
- def_blocks
184
- . into_iter ( )
185
- . flatten ( )
186
- . filter_map ( |it| self . db . trait_impls_in_block ( it) )
187
- . for_each ( |it| f ( & it) ) ;
188
- }
189
- fps => {
190
- let mut f =
191
- |impls : & TraitImpls | {
192
- result. extend ( fps. iter ( ) . flat_map ( |fp| {
193
- impls. for_trait_and_self_ty ( trait_, * fp) . map ( id_to_chalk)
194
- } ) ) ;
195
- } ;
196
- f ( & in_self) ;
197
- in_deps. iter ( ) . map ( ops:: Deref :: deref) . for_each ( & mut f) ;
198
- block_impls. for_each ( |it| f ( & it) ) ;
199
- def_blocks
200
- . into_iter ( )
201
- . flatten ( )
202
- . filter_map ( |it| self . db . trait_impls_in_block ( it) )
203
- . for_each ( |it| f ( & it) ) ;
204
- }
205
- }
143
+ if fps. is_empty ( ) {
144
+ debug ! ( "Unrestricted search for {:?} impls..." , trait_) ;
145
+ self . for_trait_impls ( trait_, self_ty_fp, |impls| {
146
+ result. extend ( impls. for_trait ( trait_) . map ( id_to_chalk) ) ;
147
+ ControlFlow :: Continue ( ( ) )
148
+ } )
149
+ } else {
150
+ self . for_trait_impls ( trait_, self_ty_fp, |impls| {
151
+ result. extend (
152
+ fps. iter ( ) . flat_map ( move |fp| {
153
+ impls. for_trait_and_self_ty ( trait_, * fp) . map ( id_to_chalk)
154
+ } ) ,
155
+ ) ;
156
+ ControlFlow :: Continue ( ( ) )
157
+ } )
158
+ } ;
206
159
207
160
debug ! ( "impls_for_trait returned {} impls" , result. len( ) ) ;
208
161
result
209
162
}
163
+
210
164
fn impl_provided_for ( & self , auto_trait_id : TraitId , kind : & chalk_ir:: TyKind < Interner > ) -> bool {
211
165
debug ! ( "impl_provided_for {:?}, {:?}" , auto_trait_id, kind) ;
212
- false // FIXME
166
+
167
+ let trait_id = from_chalk_trait_id ( auto_trait_id) ;
168
+ let self_ty = kind. clone ( ) . intern ( Interner ) ;
169
+ // We cannot filter impls by `TyFingerprint` for the following types:
170
+ let self_ty_fp = match kind {
171
+ // because we need to find any impl whose Self type is a ref with the same mutability
172
+ // (we don't care about the inner type).
173
+ TyKind :: Ref ( ..) => None ,
174
+ // because we need to find any impl whose Self type is a tuple with the same arity.
175
+ TyKind :: Tuple ( ..) => None ,
176
+ _ => TyFingerprint :: for_trait_impl ( & self_ty) ,
177
+ } ;
178
+
179
+ let check_kind = |impl_id| {
180
+ let impl_self_ty = self . db . impl_self_ty ( impl_id) ;
181
+ // NOTE(skip_binders): it's safe to skip binders here as we don't check substitutions.
182
+ let impl_self_kind = impl_self_ty. skip_binders ( ) . kind ( Interner ) ;
183
+
184
+ match ( kind, impl_self_kind) {
185
+ ( TyKind :: Adt ( id_a, _) , TyKind :: Adt ( id_b, _) ) => id_a == id_b,
186
+ ( TyKind :: AssociatedType ( id_a, _) , TyKind :: AssociatedType ( id_b, _) ) => id_a == id_b,
187
+ ( TyKind :: Scalar ( scalar_a) , TyKind :: Scalar ( scalar_b) ) => scalar_a == scalar_b,
188
+ ( TyKind :: Error , TyKind :: Error )
189
+ | ( TyKind :: Str , TyKind :: Str )
190
+ | ( TyKind :: Slice ( _) , TyKind :: Slice ( _) )
191
+ | ( TyKind :: Never , TyKind :: Never )
192
+ | ( TyKind :: Array ( _, _) , TyKind :: Array ( _, _) ) => true ,
193
+ ( TyKind :: Tuple ( arity_a, _) , TyKind :: Tuple ( arity_b, _) ) => arity_a == arity_b,
194
+ ( TyKind :: OpaqueType ( id_a, _) , TyKind :: OpaqueType ( id_b, _) ) => id_a == id_b,
195
+ ( TyKind :: FnDef ( id_a, _) , TyKind :: FnDef ( id_b, _) ) => id_a == id_b,
196
+ ( TyKind :: Ref ( id_a, _, _) , TyKind :: Ref ( id_b, _, _) )
197
+ | ( TyKind :: Raw ( id_a, _) , TyKind :: Raw ( id_b, _) ) => id_a == id_b,
198
+ ( TyKind :: Closure ( id_a, _) , TyKind :: Closure ( id_b, _) ) => id_a == id_b,
199
+ ( TyKind :: Coroutine ( id_a, _) , TyKind :: Coroutine ( id_b, _) )
200
+ | ( TyKind :: CoroutineWitness ( id_a, _) , TyKind :: CoroutineWitness ( id_b, _) ) => {
201
+ id_a == id_b
202
+ }
203
+ ( TyKind :: Foreign ( id_a) , TyKind :: Foreign ( id_b) ) => id_a == id_b,
204
+ ( _, _) => false ,
205
+ }
206
+ } ;
207
+
208
+ if let Some ( fp) = self_ty_fp {
209
+ self . for_trait_impls ( trait_id, self_ty_fp, |impls| {
210
+ match impls. for_trait_and_self_ty ( trait_id, fp) . any ( check_kind) {
211
+ true => ControlFlow :: Break ( ( ) ) ,
212
+ false => ControlFlow :: Continue ( ( ) ) ,
213
+ }
214
+ } )
215
+ } else {
216
+ self . for_trait_impls ( trait_id, self_ty_fp, |impls| {
217
+ match impls. for_trait ( trait_id) . any ( check_kind) {
218
+ true => ControlFlow :: Break ( ( ) ) ,
219
+ false => ControlFlow :: Continue ( ( ) ) ,
220
+ }
221
+ } )
222
+ }
223
+ . is_break ( )
213
224
}
225
+
214
226
fn associated_ty_value ( & self , id : AssociatedTyValueId ) -> Arc < AssociatedTyValue > {
215
227
self . db . associated_ty_value ( self . krate , id)
216
228
}
@@ -489,6 +501,59 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
489
501
}
490
502
}
491
503
504
+ impl < ' a > ChalkContext < ' a > {
505
+ fn for_trait_impls (
506
+ & self ,
507
+ trait_id : hir_def:: TraitId ,
508
+ self_ty_fp : Option < TyFingerprint > ,
509
+ mut f : impl FnMut ( & TraitImpls ) -> ControlFlow < ( ) > ,
510
+ ) -> ControlFlow < ( ) > {
511
+ // Note: Since we're using `impls_for_trait` and `impl_provided_for`,
512
+ // only impls where the trait can be resolved should ever reach Chalk.
513
+ // `impl_datum` relies on that and will panic if the trait can't be resolved.
514
+ let in_deps = self . db . trait_impls_in_deps ( self . krate ) ;
515
+ let in_self = self . db . trait_impls_in_crate ( self . krate ) ;
516
+ let trait_module = trait_id. module ( self . db . upcast ( ) ) ;
517
+ let type_module = match self_ty_fp {
518
+ Some ( TyFingerprint :: Adt ( adt_id) ) => Some ( adt_id. module ( self . db . upcast ( ) ) ) ,
519
+ Some ( TyFingerprint :: ForeignType ( type_id) ) => {
520
+ Some ( from_foreign_def_id ( type_id) . module ( self . db . upcast ( ) ) )
521
+ }
522
+ Some ( TyFingerprint :: Dyn ( trait_id) ) => Some ( trait_id. module ( self . db . upcast ( ) ) ) ,
523
+ _ => None ,
524
+ } ;
525
+
526
+ let mut def_blocks =
527
+ [ trait_module. containing_block ( ) , type_module. and_then ( |it| it. containing_block ( ) ) ] ;
528
+
529
+ let block_impls = iter:: successors ( self . block , |& block_id| {
530
+ cov_mark:: hit!( block_local_impls) ;
531
+ self . db . block_def_map ( block_id) . parent ( ) . and_then ( |module| module. containing_block ( ) )
532
+ } )
533
+ . inspect ( |& block_id| {
534
+ // make sure we don't search the same block twice
535
+ def_blocks. iter_mut ( ) . for_each ( |block| {
536
+ if * block == Some ( block_id) {
537
+ * block = None ;
538
+ }
539
+ } ) ;
540
+ } )
541
+ . filter_map ( |block_id| self . db . trait_impls_in_block ( block_id) ) ;
542
+ f ( & in_self) ?;
543
+ for it in in_deps. iter ( ) . map ( ops:: Deref :: deref) {
544
+ f ( it) ?;
545
+ }
546
+ for it in block_impls {
547
+ f ( & it) ?;
548
+ }
549
+ for it in def_blocks. into_iter ( ) . flatten ( ) . filter_map ( |it| self . db . trait_impls_in_block ( it) )
550
+ {
551
+ f ( & it) ?;
552
+ }
553
+ ControlFlow :: Continue ( ( ) )
554
+ }
555
+ }
556
+
492
557
impl chalk_ir:: UnificationDatabase < Interner > for & dyn HirDatabase {
493
558
fn fn_def_variance (
494
559
& self ,
@@ -590,7 +655,7 @@ pub(crate) fn trait_datum_query(
590
655
coinductive : false , // only relevant for Chalk testing
591
656
// FIXME: set these flags correctly
592
657
marker : false ,
593
- fundamental : false ,
658
+ fundamental : trait_data . fundamental ,
594
659
} ;
595
660
let where_clauses = convert_where_clauses ( db, trait_. into ( ) , & bound_vars) ;
596
661
let associated_ty_ids = trait_data. associated_types ( ) . map ( to_assoc_type_id) . collect ( ) ;
@@ -649,35 +714,75 @@ fn lang_item_from_well_known_trait(trait_: WellKnownTrait) -> LangItem {
649
714
}
650
715
}
651
716
652
- pub ( crate ) fn struct_datum_query (
717
+ pub ( crate ) fn adt_datum_query (
653
718
db : & dyn HirDatabase ,
654
719
krate : CrateId ,
655
- struct_id : AdtId ,
656
- ) -> Arc < StructDatum > {
657
- debug ! ( "struct_datum {:?}" , struct_id) ;
658
- let chalk_ir:: AdtId ( adt_id) = struct_id;
720
+ chalk_ir:: AdtId ( adt_id) : AdtId ,
721
+ ) -> Arc < AdtDatum > {
722
+ debug ! ( "adt_datum {:?}" , adt_id) ;
659
723
let generic_params = generics ( db. upcast ( ) , adt_id. into ( ) ) ;
660
- let upstream = adt_id. module ( db. upcast ( ) ) . krate ( ) != krate;
661
- let where_clauses = {
662
- let generic_params = generics ( db. upcast ( ) , adt_id. into ( ) ) ;
663
- let bound_vars = generic_params. bound_vars_subst ( db, DebruijnIndex :: INNERMOST ) ;
664
- convert_where_clauses ( db, adt_id. into ( ) , & bound_vars)
724
+ let bound_vars_subst = generic_params. bound_vars_subst ( db, DebruijnIndex :: INNERMOST ) ;
725
+ let where_clauses = convert_where_clauses ( db, adt_id. into ( ) , & bound_vars_subst) ;
726
+
727
+ let ( fundamental, phantom_data) = match adt_id {
728
+ hir_def:: AdtId :: StructId ( s) => {
729
+ let flags = db. struct_data ( s) . flags ;
730
+ (
731
+ flags. contains ( StructFlags :: IS_FUNDAMENTAL ) ,
732
+ flags. contains ( StructFlags :: IS_PHANTOM_DATA ) ,
733
+ )
734
+ }
735
+ // FIXME set fundamental flags correctly
736
+ hir_def:: AdtId :: UnionId ( _) => ( false , false ) ,
737
+ hir_def:: AdtId :: EnumId ( _) => ( false , false ) ,
665
738
} ;
666
739
let flags = rust_ir:: AdtFlags {
667
- upstream,
668
- // FIXME set fundamental and phantom_data flags correctly
669
- fundamental : false ,
670
- phantom_data : false ,
740
+ upstream : adt_id. module ( db. upcast ( ) ) . krate ( ) != krate,
741
+ fundamental,
742
+ phantom_data,
743
+ } ;
744
+
745
+ #[ cfg( FALSE ) ]
746
+ // this slows down rust-analyzer by quite a bit unfortunately, so enabling this is currently not worth it
747
+ let variant_id_to_fields = |id : VariantId | {
748
+ let variant_data = & id. variant_data ( db. upcast ( ) ) ;
749
+ let fields = if variant_data. fields ( ) . is_empty ( ) {
750
+ vec ! [ ]
751
+ } else {
752
+ let field_types = db. field_types ( id) ;
753
+ variant_data
754
+ . fields ( )
755
+ . iter ( )
756
+ . map ( |( idx, _) | field_types[ idx] . clone ( ) . substitute ( Interner , & bound_vars_subst) )
757
+ . filter ( |it| !it. contains_unknown ( ) )
758
+ . collect ( )
759
+ } ;
760
+ rust_ir:: AdtVariantDatum { fields }
671
761
} ;
672
- // FIXME provide enum variants properly (for auto traits)
673
- let variant = rust_ir:: AdtVariantDatum {
674
- fields : Vec :: new ( ) , // FIXME add fields (only relevant for auto traits),
762
+ let variant_id_to_fields = |_: VariantId | rust_ir:: AdtVariantDatum { fields : vec ! [ ] } ;
763
+
764
+ let ( kind, variants) = match adt_id {
765
+ hir_def:: AdtId :: StructId ( id) => {
766
+ ( rust_ir:: AdtKind :: Struct , vec ! [ variant_id_to_fields( id. into( ) ) ] )
767
+ }
768
+ hir_def:: AdtId :: EnumId ( id) => {
769
+ let variants = db
770
+ . enum_data ( id)
771
+ . variants
772
+ . iter ( )
773
+ . map ( |& ( variant_id, _) | variant_id_to_fields ( variant_id. into ( ) ) )
774
+ . collect ( ) ;
775
+ ( rust_ir:: AdtKind :: Enum , variants)
776
+ }
777
+ hir_def:: AdtId :: UnionId ( id) => {
778
+ ( rust_ir:: AdtKind :: Union , vec ! [ variant_id_to_fields( id. into( ) ) ] )
779
+ }
675
780
} ;
676
- let struct_datum_bound = rust_ir :: AdtDatumBound { variants : vec ! [ variant ] , where_clauses } ;
677
- let struct_datum = StructDatum {
678
- // FIXME set ADT kind
679
- kind : rust_ir :: AdtKind :: Struct ,
680
- id : struct_id ,
781
+
782
+ let struct_datum_bound = rust_ir :: AdtDatumBound { variants , where_clauses } ;
783
+ let struct_datum = AdtDatum {
784
+ kind,
785
+ id : chalk_ir :: AdtId ( adt_id ) ,
681
786
binders : make_binders ( db, & generic_params, struct_datum_bound) ,
682
787
flags,
683
788
} ;
0 commit comments