From 7e9c4d58f189d4ac3c390a6ea345f2578dd5f661 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 11 Jul 2020 19:12:10 +0200 Subject: Search more efficiently for int/float impls --- crates/ra_hir_ty/src/method_resolution.rs | 71 ++++++++++++++++++++++++++++--- crates/ra_hir_ty/src/tests/traits.rs | 19 ++++++++- crates/ra_hir_ty/src/traits/chalk.rs | 46 ++++++++++++++------ 3 files changed, 118 insertions(+), 18 deletions(-) diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs index a45febbf7..fb4b30a13 100644 --- a/crates/ra_hir_ty/src/method_resolution.rs +++ b/crates/ra_hir_ty/src/method_resolution.rs @@ -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 { diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index 85bcd0050..511ed8fe3 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs @@ -3042,7 +3042,7 @@ fn foo() { } #[test] -fn variable_kinds() { +fn variable_kinds_1() { check_types( r#" trait Trait { 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 +} + "#, + ); +} diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs index e944c1976..c448aea65 100644 --- a/crates/ra_hir_ty/src/traits/chalk.rs +++ b/crates/ra_hir_ty/src/traits/chalk.rs @@ -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 for ChalkContext<'a> { &self, trait_id: TraitId, parameters: &[GenericArg], - _binders: &CanonicalVarKinds, + binders: &CanonicalVarKinds, ) -> Vec { 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) -> Option { + 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 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 + 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() + } else { + impl_maps .iter() .flat_map(|crate_impl_defs| { - crate_impl_defs.for_trait_and_self_ty(trait_, fp).map(id_to_chalk) + fps.iter().flat_map(move |fp| { + crate_impl_defs.for_trait_and_self_ty(trait_, *fp).map(id_to_chalk) + }) }) - .collect(), - None => impl_maps - .iter() - .flat_map(|crate_impl_defs| crate_impl_defs.for_trait(trait_).map(id_to_chalk)) - .collect(), + .collect() }; let arg: Option = -- cgit v1.2.3