Search more efficiently for int/float impls

This commit is contained in:
Florian Diebold 2020-07-11 19:12:10 +02:00
parent 00bda1cafb
commit 7e9c4d58f1
3 changed files with 119 additions and 19 deletions

View file

@ -6,8 +6,10 @@ use std::{iter, sync::Arc};
use arrayvec::ArrayVec;
use hir_def::{
lang_item::LangItemTarget, type_ref::Mutability, AssocContainerId, AssocItemId, FunctionId,
HasModule, ImplId, Lookup, TraitId,
builtin_type::{IntBitness, Signedness},
lang_item::LangItemTarget,
type_ref::Mutability,
AssocContainerId, AssocItemId, FunctionId, HasModule, ImplId, Lookup, TraitId,
};
use hir_expand::name::Name;
use ra_db::CrateId;
@ -16,9 +18,12 @@ use rustc_hash::{FxHashMap, FxHashSet};
use super::Substs;
use crate::{
autoderef, db::HirDatabase, primitive::FloatBitness, utils::all_super_traits, ApplicationTy,
Canonical, DebruijnIndex, InEnvironment, TraitEnvironment, TraitRef, Ty, TyKind, TypeCtor,
TypeWalk,
autoderef,
db::HirDatabase,
primitive::{FloatBitness, FloatTy, IntTy},
utils::all_super_traits,
ApplicationTy, Canonical, DebruijnIndex, InEnvironment, TraitEnvironment, TraitRef, Ty, TyKind,
TypeCtor, TypeWalk,
};
/// This is used as a key for indexing impls.
@ -39,6 +44,62 @@ impl TyFingerprint {
}
}
pub(crate) const ALL_INT_FPS: [TyFingerprint; 12] = [
TyFingerprint::Apply(TypeCtor::Int(IntTy {
signedness: Signedness::Unsigned,
bitness: IntBitness::X8,
})),
TyFingerprint::Apply(TypeCtor::Int(IntTy {
signedness: Signedness::Unsigned,
bitness: IntBitness::X16,
})),
TyFingerprint::Apply(TypeCtor::Int(IntTy {
signedness: Signedness::Unsigned,
bitness: IntBitness::X32,
})),
TyFingerprint::Apply(TypeCtor::Int(IntTy {
signedness: Signedness::Unsigned,
bitness: IntBitness::X64,
})),
TyFingerprint::Apply(TypeCtor::Int(IntTy {
signedness: Signedness::Unsigned,
bitness: IntBitness::X128,
})),
TyFingerprint::Apply(TypeCtor::Int(IntTy {
signedness: Signedness::Unsigned,
bitness: IntBitness::Xsize,
})),
TyFingerprint::Apply(TypeCtor::Int(IntTy {
signedness: Signedness::Signed,
bitness: IntBitness::X8,
})),
TyFingerprint::Apply(TypeCtor::Int(IntTy {
signedness: Signedness::Signed,
bitness: IntBitness::X16,
})),
TyFingerprint::Apply(TypeCtor::Int(IntTy {
signedness: Signedness::Signed,
bitness: IntBitness::X32,
})),
TyFingerprint::Apply(TypeCtor::Int(IntTy {
signedness: Signedness::Signed,
bitness: IntBitness::X64,
})),
TyFingerprint::Apply(TypeCtor::Int(IntTy {
signedness: Signedness::Signed,
bitness: IntBitness::X128,
})),
TyFingerprint::Apply(TypeCtor::Int(IntTy {
signedness: Signedness::Signed,
bitness: IntBitness::Xsize,
})),
];
pub(crate) const ALL_FLOAT_FPS: [TyFingerprint; 2] = [
TyFingerprint::Apply(TypeCtor::Float(FloatTy { bitness: FloatBitness::X32 })),
TyFingerprint::Apply(TypeCtor::Float(FloatTy { bitness: FloatBitness::X64 })),
];
/// Trait impls defined or available in some crate.
#[derive(Debug, Eq, PartialEq)]
pub struct TraitImpls {

View file

@ -3042,7 +3042,7 @@ fn foo() {
}
#[test]
fn variable_kinds() {
fn variable_kinds_1() {
check_types(
r#"
trait Trait<T> { fn get(self, t: T) -> T; }
@ -3058,3 +3058,20 @@ fn test() {
"#,
);
}
#[test]
fn variable_kinds_2() {
check_types(
r#"
trait Trait { fn get(self) -> Self; }
impl Trait for u128 {}
impl Trait for f32 {}
fn test() {
1.get();
//^^^^^^^ u128
(1.).get();
//^^^^^^^^^^ f32
}
"#,
);
}

View file

@ -14,7 +14,10 @@ use ra_db::{salsa::InternKey, CrateId};
use super::{builtin, AssocTyValue, ChalkContext, Impl};
use crate::{
db::HirDatabase, display::HirDisplay, method_resolution::TyFingerprint, utils::generics,
db::HirDatabase,
display::HirDisplay,
method_resolution::{TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS},
utils::generics,
CallableDef, DebruijnIndex, GenericPredicate, Substs, Ty, TypeCtor,
};
use mapping::{convert_where_clauses, generic_predicate_to_inline_bound, make_binders};
@ -66,16 +69,31 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
&self,
trait_id: TraitId,
parameters: &[GenericArg<Interner>],
_binders: &CanonicalVarKinds<Interner>,
binders: &CanonicalVarKinds<Interner>,
) -> Vec<ImplId> {
debug!("impls_for_trait {:?}", trait_id);
let trait_: hir_def::TraitId = from_chalk(self.db, trait_id);
// FIXME use binders to look for int/float impls when necessary
let ty: Ty = from_chalk(self.db, parameters[0].assert_ty_ref(&Interner).clone());
fn binder_kind(ty: &Ty, binders: &CanonicalVarKinds<Interner>) -> Option<chalk_ir::TyKind> {
if let Ty::Bound(bv) = ty {
let binders = binders.as_slice(&Interner);
if bv.debruijn == DebruijnIndex::INNERMOST {
if let chalk_ir::VariableKind::Ty(tk) = binders[bv.index].kind {
return Some(tk);
}
}
}
None
}
let self_ty_fp = TyFingerprint::for_impl(&ty);
let fps: &[TyFingerprint] = match binder_kind(&ty, binders) {
Some(chalk_ir::TyKind::Integer) => &ALL_INT_FPS,
Some(chalk_ir::TyKind::Float) => &ALL_FLOAT_FPS,
_ => self_ty_fp.as_ref().map(std::slice::from_ref).unwrap_or(&[]),
};
// Note: Since we're using impls_for_trait, only impls where the trait
// can be resolved should ever reach Chalk. `impl_datum` relies on that
@ -86,17 +104,21 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
let id_to_chalk = |id: hir_def::ImplId| Impl::ImplDef(id).to_chalk(self.db);
let mut result: Vec<_> = match self_ty_fp {
Some(fp) => impl_maps
.iter()
.flat_map(|crate_impl_defs| {
crate_impl_defs.for_trait_and_self_ty(trait_, fp).map(id_to_chalk)
})
.collect(),
None => impl_maps
let mut result: Vec<_> = if fps.is_empty() {
debug!("Unrestricted search for {:?} impls...", trait_);
impl_maps
.iter()
.flat_map(|crate_impl_defs| crate_impl_defs.for_trait(trait_).map(id_to_chalk))
.collect(),
.collect()
} else {
impl_maps
.iter()
.flat_map(|crate_impl_defs| {
fps.iter().flat_map(move |fp| {
crate_impl_defs.for_trait_and_self_ty(trait_, *fp).map(id_to_chalk)
})
})
.collect()
};
let arg: Option<Ty> =