11//! The implementation of `RustIrDatabase` for Chalk, which provides information
22//! about the code that Chalk needs.
33use core:: ops;
4- use std:: { iter, sync:: Arc } ;
4+ use std:: { iter, ops :: ControlFlow , sync:: Arc } ;
55
66use tracing:: debug;
77
@@ -10,9 +10,10 @@ use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait};
1010
1111use base_db:: CrateId ;
1212use hir_def:: {
13+ data:: adt:: StructFlags ,
1314 hir:: Movability ,
1415 lang_item:: { LangItem , LangItemTarget } ,
15- AssocItemId , BlockId , GenericDefId , HasModule , ItemContainerId , Lookup , TypeAliasId ,
16+ AssocItemId , BlockId , GenericDefId , HasModule , ItemContainerId , Lookup , TypeAliasId , VariantId ,
1617} ;
1718use hir_expand:: name:: name;
1819
@@ -33,7 +34,7 @@ use crate::{
3334
3435pub ( crate ) type AssociatedTyDatum = chalk_solve:: rust_ir:: AssociatedTyDatum < Interner > ;
3536pub ( 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 > ;
3738pub ( crate ) type ImplDatum = chalk_solve:: rust_ir:: ImplDatum < Interner > ;
3839pub ( crate ) type OpaqueTyDatum = chalk_solve:: rust_ir:: OpaqueTyDatum < Interner > ;
3940
@@ -53,8 +54,8 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
5354 fn trait_datum ( & self , trait_id : TraitId ) -> Arc < TraitDatum > {
5455 self . db . trait_datum ( self . krate , trait_id)
5556 }
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)
5859 }
5960 fn adt_repr ( & self , _struct_id : AdtId ) -> Arc < rust_ir:: AdtRepr < Interner > > {
6061 // FIXME: keep track of these
@@ -136,81 +137,92 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
136137 _ => self_ty_fp. as_ref ( ) . map ( std:: slice:: from_ref) . unwrap_or ( & [ ] ) ,
137138 } ;
138139
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-
172140 let id_to_chalk = |id : hir_def:: ImplId | id. to_chalk ( self . db ) ;
141+
173142 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+ } ;
206159
207160 debug ! ( "impls_for_trait returned {} impls" , result. len( ) ) ;
208161 result
209162 }
163+
210164 fn impl_provided_for ( & self , auto_trait_id : TraitId , kind : & chalk_ir:: TyKind < Interner > ) -> bool {
211165 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 ( )
213224 }
225+
214226 fn associated_ty_value ( & self , id : AssociatedTyValueId ) -> Arc < AssociatedTyValue > {
215227 self . db . associated_ty_value ( self . krate , id)
216228 }
@@ -489,6 +501,59 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
489501 }
490502}
491503
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+
492557impl chalk_ir:: UnificationDatabase < Interner > for & dyn HirDatabase {
493558 fn fn_def_variance (
494559 & self ,
@@ -590,7 +655,7 @@ pub(crate) fn trait_datum_query(
590655 coinductive : false , // only relevant for Chalk testing
591656 // FIXME: set these flags correctly
592657 marker : false ,
593- fundamental : false ,
658+ fundamental : trait_data . fundamental ,
594659 } ;
595660 let where_clauses = convert_where_clauses ( db, trait_. into ( ) , & bound_vars) ;
596661 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 {
649714 }
650715}
651716
652- pub ( crate ) fn struct_datum_query (
717+ pub ( crate ) fn adt_datum_query (
653718 db : & dyn HirDatabase ,
654719 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) ;
659723 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 ) ,
665738 } ;
666739 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 }
671761 } ;
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+ }
675780 } ;
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 ) ,
681786 binders : make_binders ( db, & generic_params, struct_datum_bound) ,
682787 flags,
683788 } ;
0 commit comments