Skip to content

Commit

Permalink
Make handling of impls more generic and query based
Browse files Browse the repository at this point in the history
  • Loading branch information
cburgdorf committed Jul 8, 2022
1 parent 92931cd commit 0ccdd1b
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 51 deletions.
4 changes: 4 additions & 0 deletions crates/analyzer/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,10 @@ pub trait AnalyzerDb: SourceDb + Upcast<dyn SourceDb> + UpcastMut<dyn SourceDb>
// 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<ImplId>;
#[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)]
Expand Down
42 changes: 32 additions & 10 deletions crates/analyzer/src/db/queries/types.rs
Original file line number Diff line number Diff line change
@@ -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::<Vec<_>>();

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<ImplId> {
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()
}

Expand Down
23 changes: 0 additions & 23 deletions crates/analyzer/src/namespace/items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<ImplId> {
let ingot_modules = self
.all_modules(db)
.iter()
.flat_map(|module_id| module_id.all_impls(db).to_vec())
.collect::<Vec<_>>();

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<Diagnostic> {
let mut diagnostics = vec![];
self.sink_diagnostics(db, &mut diagnostics);
Expand Down Expand Up @@ -1374,13 +1358,6 @@ impl StructId {
db.intern_type(Type::Struct(*self))
}

pub fn get_impl_for(&self, db: &dyn AnalyzerDb, trait_: TraitId) -> Option<ImplId> {
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))
}
Expand Down
23 changes: 5 additions & 18 deletions crates/analyzer/src/namespace/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<ImplId> {
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
Expand All @@ -142,20 +141,8 @@ impl TypeId {

/// Like `function_sig` but returns a `Vec<FunctionSigId>` 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<FunctionSigId> {
let native = self.function_sig(db, name);

let mut fns: Vec<FunctionSigId> = 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<FunctionSigId> {
Expand Down
1 change: 1 addition & 0 deletions crates/analyzer/src/traversal/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down

0 comments on commit 0ccdd1b

Please sign in to comment.