From 0ccdd1bac5df836fdf5dd8fbcf9a61490f8378f4 Mon Sep 17 00:00:00 2001 From: Christoph Burgdorf Date: Thu, 7 Jul 2022 11:16:54 +0200 Subject: [PATCH] Make handling of impls more generic and query based --- crates/analyzer/src/db.rs | 4 ++ crates/analyzer/src/db/queries/types.rs | 42 +++++++++++++++----- crates/analyzer/src/namespace/items.rs | 23 ----------- crates/analyzer/src/namespace/types.rs | 23 +++-------- crates/analyzer/src/traversal/expressions.rs | 1 + 5 files changed, 42 insertions(+), 51 deletions(-) diff --git a/crates/analyzer/src/db.rs b/crates/analyzer/src/db.rs index 0403e3503a..a0ece832c7 100644 --- a/crates/analyzer/src/db.rs +++ b/crates/analyzer/src/db.rs @@ -186,6 +186,10 @@ pub trait AnalyzerDb: SourceDb + Upcast + UpcastMut // Type #[salsa::invoke(queries::types::all_impls)] fn all_impls(&self, ty: TypeId) -> Rc<[ImplId]>; + #[salsa::invoke(queries::types::impl_for)] + fn impl_for(&self, ty: TypeId, treit: TraitId) -> Option; + #[salsa::invoke(queries::types::function_sigs)] + fn function_sigs(&self, ty: TypeId, name: SmolStr) -> Rc<[FunctionSigId]>; // Type alias #[salsa::invoke(queries::types::type_alias_type)] diff --git a/crates/analyzer/src/db/queries/types.rs b/crates/analyzer/src/db/queries/types.rs index 2e2756b5a7..91bfb35619 100644 --- a/crates/analyzer/src/db/queries/types.rs +++ b/crates/analyzer/src/db/queries/types.rs @@ -1,25 +1,47 @@ use std::rc::Rc; +use smol_str::SmolStr; + use crate::context::{AnalyzerContext, TempContext}; use crate::db::Analysis; use crate::errors::TypeError; -use crate::namespace::items::{ImplId, TypeAliasId}; +use crate::namespace::items::{FunctionSigId, ImplId, TraitId, TypeAliasId}; use crate::namespace::scopes::ItemScope; use crate::namespace::types::{self, TypeId}; use crate::traversal::types::type_desc; use crate::AnalyzerDb; +/// Returns all `impl` for the given type from the current ingot as well as dependency ingots pub fn all_impls(db: &dyn AnalyzerDb, ty: TypeId) -> Rc<[ImplId]> { - db.root_ingot() - .all_existing_impls(db) + let ingot_modules = db + .root_ingot() + .all_modules(db) + .iter() + .flat_map(|module_id| module_id.all_impls(db).to_vec()) + .collect::>(); + + db.ingot_external_ingots(db.root_ingot()) + .values() + .flat_map(|ingot| ingot.all_modules(db).to_vec()) + .flat_map(|module_id| module_id.all_impls(db).to_vec()) + .chain(ingot_modules) + .filter(|val| val.receiver(db) == ty) + .collect() +} + +pub fn impl_for(db: &dyn AnalyzerDb, ty: TypeId, treit: TraitId) -> Option { + db.all_impls(ty) + .iter() + .find(|impl_| impl_.trait_id(db) == treit) + .cloned() +} + +pub fn function_sigs(db: &dyn AnalyzerDb, ty: TypeId, name: SmolStr) -> Rc<[FunctionSigId]> { + ty.get_all_impls(db) .iter() - .filter_map(|val| { - if val.receiver(db) == ty { - Some(*val) - } else { - None - } - }) + .filter_map(|impl_| impl_.function(db, &name)) + .map(|fun| fun.sig(db)) + .chain(ty.function_sig(db, &name).map_or(vec![], |fun| vec![fun])) .collect() } diff --git a/crates/analyzer/src/namespace/items.rs b/crates/analyzer/src/namespace/items.rs index 26ea666024..2877303966 100644 --- a/crates/analyzer/src/namespace/items.rs +++ b/crates/analyzer/src/namespace/items.rs @@ -393,22 +393,6 @@ impl IngotId { self.root_module(db).expect("missing root module").items(db) } - /// Returns all `impl` from the current ingot as well as dependency ingots - pub fn all_existing_impls(&self, db: &dyn AnalyzerDb) -> Vec { - let ingot_modules = self - .all_modules(db) - .iter() - .flat_map(|module_id| module_id.all_impls(db).to_vec()) - .collect::>(); - - self.external_ingots(db) - .values() - .flat_map(|ingot| ingot.all_modules(db).to_vec()) - .flat_map(|module_id| module_id.all_impls(db).to_vec()) - .chain(ingot_modules) - .collect() - } - pub fn diagnostics(&self, db: &dyn AnalyzerDb) -> Vec { let mut diagnostics = vec![]; self.sink_diagnostics(db, &mut diagnostics); @@ -1374,13 +1358,6 @@ impl StructId { db.intern_type(Type::Struct(*self)) } - pub fn get_impl_for(&self, db: &dyn AnalyzerDb, trait_: TraitId) -> Option { - self.module(db) - .impls(db) - .get(&(trait_, db.intern_type(Type::Struct(*self)))) - .cloned() - } - pub fn has_private_field(&self, db: &dyn AnalyzerDb) -> bool { self.fields(db).values().any(|field| !field.is_public(db)) } diff --git a/crates/analyzer/src/namespace/types.rs b/crates/analyzer/src/namespace/types.rs index 9b9f32ce0f..36f75d37a4 100644 --- a/crates/analyzer/src/namespace/types.rs +++ b/crates/analyzer/src/namespace/types.rs @@ -114,11 +114,10 @@ impl TypeId { } } + /// Return the `impl` for the given trait. There can only ever be a single implementation + /// per concrete type and trait. pub fn get_impl_for(&self, db: &dyn AnalyzerDb, trait_: TraitId) -> Option { - match self.typ(db) { - Type::Struct(id) => id.get_impl_for(db, trait_), - _ => trait_.module(db).impls(db).get(&(trait_, *self)).cloned(), - } + db.impl_for(*self, trait_) } // Returns all `impl` for the type even from foreign ingots @@ -142,20 +141,8 @@ impl TypeId { /// Like `function_sig` but returns a `Vec` which not only considers functions natively /// implemented on the type but also those that are provided by implemented traits on the type. - pub fn function_sigs(&self, db: &dyn AnalyzerDb, name: &str) -> Vec { - let native = self.function_sig(db, name); - - let mut fns: Vec = self - .get_all_impls(db) - .iter() - .filter_map(|impl_| impl_.function(db, name)) - .map(|fun| fun.sig(db)) - .collect(); - - if let Some(fun) = native { - fns.push(fun) - } - fns + pub fn function_sigs(&self, db: &dyn AnalyzerDb, name: &str) -> Rc<[FunctionSigId]> { + db.function_sigs(*self, name.into()) } pub fn self_function(&self, db: &dyn AnalyzerDb, name: &str) -> Option { diff --git a/crates/analyzer/src/traversal/expressions.rs b/crates/analyzer/src/traversal/expressions.rs index 191be5a15b..5e56406302 100644 --- a/crates/analyzer/src/traversal/expressions.rs +++ b/crates/analyzer/src/traversal/expressions.rs @@ -1437,6 +1437,7 @@ fn expr_call_method( match target_type .function_sigs(context.db(), &field.kind) + .to_vec() .as_slice() { [] => Err(FatalError::new(context.fancy_error(