Skip to content

Commit 2223b4f

Browse files
committed
Auto merge of #13112 - lowr:patch/auto-trait-bounds, r=Veykril
Setup infra for handling auto trait bounds disabled due to perf problems This patch updates some of the partially-implemented functions of `ChalkContext as RustIrDatabase`, namely `adt_datum()` and `impl_provided_for()`. With those, we can now correctly work with auto trait bounds and distinguish methods based on them. Resolves#7856 (the second code; the first one is resolved by #13074) **IMPORTANT**: I don't think we want to merge this until #7637 is resolved. Currently this patch introduces A LOT of unknown types and type mismtaches as shown below. This is because we cannot resolve items like `hashbrown::HashMap` in `std` modules, leading to auto trait bounds on them and their dependents unprovable. |crate (from `rustc-perf@c52ee6` except for r-a)|e3dc5a588f07d6f1d3a0f33051d4af26190abe9e|HEAD of this branch| |---|---|---| |rust-analyzer @ e3dc5a5 |exprs: 417528, ??ty: 907 (0%), ?ty: 114 (0%), !ty: 1|exprs: 417528, ??ty: 1704 (0%), ?ty: 403 (0%), !ty: 20| |ripgrep|exprs: 62120, ??ty: 2 (0%), ?ty: 0 (0%), !ty: 0|exprs: 62120, ??ty: 132 (0%), ?ty: 58 (0%), !ty: 11| |webrender/webrender|exprs: 94355, ??ty: 49 (0%), ?ty: 16 (0%), !ty: 2|exprs: 94355, ??ty: 429 (0%), ?ty: 130 (0%), !ty: 7| |diesel|exprs: 132591, ??ty: 401 (0%), ?ty: 5129 (3%), !ty: 31|exprs: 132591, ??ty: 401 (0%), ?ty: 5129 (3%), !ty: 31|
2 parents bbb781e + d2b27d0 commit 2223b4f

7 files changed

Lines changed: 262 additions & 102 deletions

File tree

‎crates/hir-def/src/data/adt.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ pub struct StructData {
4040
}
4141

4242
bitflags!{
43-
#[derive(Debug,Clone,PartialEq,Eq)]
43+
#[derive(Debug,Copy,Clone,PartialEq,Eq)]
4444
pubstructStructFlags:u8{
4545
constNO_FLAGS = 0;
4646
/// Indicates whether the struct is `PhantomData`.

‎crates/hir-ty/src/chalk_db.rs‎

Lines changed: 199 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! The implementation of `RustIrDatabase` for Chalk, which provides information
22
//! about the code that Chalk needs.
33
use core::ops;
4-
use std::{iter, sync::Arc};
4+
use std::{iter,ops::ControlFlow,sync::Arc};
55

66
use tracing::debug;
77

@@ -10,9 +10,10 @@ use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait};
1010

1111
use base_db::CrateId;
1212
use 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
};
1718
use hir_expand::name::name;
1819

@@ -33,7 +34,7 @@ use crate::{
3334

3435
pub(crate)typeAssociatedTyDatum = chalk_solve::rust_ir::AssociatedTyDatum<Interner>;
3536
pub(crate)typeTraitDatum = chalk_solve::rust_ir::TraitDatum<Interner>;
36-
pub(crate)typeStructDatum = chalk_solve::rust_ir::AdtDatum<Interner>;
37+
pub(crate)typeAdtDatum = chalk_solve::rust_ir::AdtDatum<Interner>;
3738
pub(crate)typeImplDatum = chalk_solve::rust_ir::ImplDatum<Interner>;
3839
pub(crate)typeOpaqueTyDatum = chalk_solve::rust_ir::OpaqueTyDatum<Interner>;
3940

@@ -53,8 +54,8 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
5354
fntrait_datum(&self,trait_id:TraitId) -> Arc<TraitDatum>{
5455
self.db.trait_datum(self.krate, trait_id)
5556
}
56-
fnadt_datum(&self,struct_id:AdtId) -> Arc<StructDatum>{
57-
self.db.struct_datum(self.krate, struct_id)
57+
fnadt_datum(&self,struct_id:AdtId) -> Arc<AdtDatum>{
58+
self.db.adt_datum(self.krate, struct_id)
5859
}
5960
fnadt_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-
letmut 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
letmut result = vec![];
174-
match fps {
175-
[] => {
176-
debug!("Unrestricted search for {:?} impls...", trait_);
177-
letmut 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-
letmut 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
fnimpl_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+
ifletSome(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
fnassociated_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+
fnfor_trait_impls(
506+
&self,
507+
trait_id: hir_def::TraitId,
508+
self_ty_fp:Option<TyFingerprint>,
509+
mutf:implFnMut(&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+
letmut 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+
492557
impl chalk_ir::UnificationDatabase<Interner>for&dynHirDatabase{
493558
fnfn_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)fnstruct_datum_query(
717+
pub(crate)fnadt_datum_query(
653718
db:&dynHirDatabase,
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-
letstruct_datum = StructDatum{
678-
// FIXME set ADT kind
679-
kind: rust_ir::AdtKind::Struct,
680-
id:struct_id,
781+
782+
letstruct_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
};

‎crates/hir-ty/src/db.rs‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -220,12 +220,12 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
220220
trait_id: chalk_db::TraitId,
221221
) -> sync::Arc<chalk_db::TraitDatum>;
222222

223-
#[salsa::invoke(chalk_db::struct_datum_query)]
224-
fnstruct_datum(
223+
#[salsa::invoke(chalk_db::adt_datum_query)]
224+
fnadt_datum(
225225
&self,
226226
krate:CrateId,
227227
struct_id: chalk_db::AdtId,
228-
) -> sync::Arc<chalk_db::StructDatum>;
228+
) -> sync::Arc<chalk_db::AdtDatum>;
229229

230230
#[salsa::invoke(chalk_db::impl_datum_query)]
231231
fnimpl_datum(

0 commit comments

Comments
 (0)