Skip to content

Commit

Permalink
Refactor, get rid of Class
Browse files Browse the repository at this point in the history
  • Loading branch information
cburgdorf committed Jul 8, 2022
1 parent 3ffe8d3 commit 0bad376
Show file tree
Hide file tree
Showing 5 changed files with 321 additions and 339 deletions.
6 changes: 3 additions & 3 deletions crates/analyzer/src/context.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::display::Displayable;

use crate::namespace::items::{
Class, ContractId, DiagnosticSink, EventId, FunctionId, FunctionSigId, Item, TraitId,
ContractId, DiagnosticSink, EventId, FunctionId, FunctionSigId, Item, TraitId,
};
use crate::namespace::types::{Generic, SelfDecl, Type, TypeId};
use crate::AnalyzerDb;
Expand Down Expand Up @@ -451,12 +451,12 @@ pub enum CallType {

// MyStruct.foo() (soon MyStruct::foo())
AssociatedFunction {
class: Class,
typ: TypeId,
function: FunctionId,
},
// some_struct_or_contract.foo()
ValueMethod {
class: Class,
typ: TypeId,
method: FunctionId,
},
// some_trait.foo()
Expand Down
6 changes: 1 addition & 5 deletions crates/analyzer/src/db/queries/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,11 +381,7 @@ pub fn function_dependency_graph(db: &dyn AnalyzerDb, function: FunctionId) -> D
CallType::Pure(function) | CallType::AssociatedFunction { function, .. } => {
directs.push((root, Item::Function(*function), DepLocality::Local));
}
CallType::ValueMethod { class, method, .. } => {
// Including the "class" type here is probably redundant; the type will
// also be part of the fn sig, or some type decl, or some create/create2 call,
// or...
directs.push((root, class.as_item(db), DepLocality::Local));
CallType::ValueMethod { method, .. } => {
directs.push((root, Item::Function(*method), DepLocality::Local));
}
CallType::TraitValueMethod { trait_id, .. } => {
Expand Down
90 changes: 16 additions & 74 deletions crates/analyzer/src/namespace/items.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::context::{self, Analysis, Constant};
use crate::display::Displayable;
use crate::errors::{self, IncompleteItem, TypeError};
use crate::namespace::types::{self, GenericType, Type, TypeDowncast, TypeId};
use crate::namespace::types::{self, GenericType, Type, TypeId};
use crate::traversal::pragma::check_pragma_version;
use crate::AnalyzerDb;
use crate::{builtins, errors::ConstEvalError};
Expand Down Expand Up @@ -232,12 +232,12 @@ impl Item {
}
}

pub fn as_class(&self) -> Option<Class> {
pub fn function_sig(&self, db: &dyn AnalyzerDb, name: &str) -> Option<FunctionSigId> {
match self {
Item::Type(TypeDef::Contract(id)) => Some(Class::Contract(*id)),
Item::Type(TypeDef::Struct(id)) => Some(Class::Struct(*id)),
Item::Trait(id) => Some(Class::Trait(*id)),
Item::Impl(id) => Some(Class::Impl(*id)),
Item::Type(TypeDef::Contract(id)) => id.function(db, name).map(|fun| fun.sig(db)),
Item::Type(TypeDef::Struct(id)) => id.function(db, name).map(|fun| fun.sig(db)),
Item::Impl(id) => id.function(db, name).map(|fun| fun.sig(db)),
Item::Trait(id) => id.function(db, name),
_ => None,
}
}
Expand Down Expand Up @@ -1158,6 +1158,16 @@ impl FunctionSigId {
.unwrap_or_else(|| Item::Module(self.module(db)))
}

/// Looks up the `FunctionId` based on the parent of the function signature
pub fn function(&self, db: &dyn AnalyzerDb) -> Option<FunctionId> {
match self.parent(db) {
Item::Type(TypeDef::Struct(id)) => id.function(db, &self.name(db)),
Item::Impl(id) => id.function(db, &self.name(db)),
Item::Type(TypeDef::Contract(id)) => id.function(db, &self.name(db)),
_ => None,
}
}

pub fn is_trait_fn(&self, db: &dyn AnalyzerDb) -> bool {
matches!(self.parent(db), Item::Trait(_))
}
Expand Down Expand Up @@ -1295,70 +1305,6 @@ impl FunctionId {
}
}

/// A `Class` is an item that can have member functions.
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub enum Class {
Contract(ContractId),
Struct(StructId),
Trait(TraitId),
Impl(ImplId),
}
impl Class {
pub fn function(&self, db: &dyn AnalyzerDb, name: &str) -> Option<FunctionId> {
match self {
Class::Contract(id) => id.function(db, name),
Class::Struct(id) => id.function(db, name),
Class::Impl(id) => id.function(db, name),
// This would possibly change when in the future trait methods can provide a default implementation
Class::Trait(_) => None,
}
}
pub fn function_sig(&self, db: &dyn AnalyzerDb, name: &str) -> Option<FunctionSigId> {
match self {
Class::Contract(id) => id.function(db, name).map(|fun| fun.sig(db)),
Class::Struct(id) => id.function(db, name).map(|fun| fun.sig(db)),
Class::Impl(id) => id.function(db, name).map(|fun| fun.sig(db)),
Class::Trait(id) => id.function(db, name),
}
}
pub fn self_function(&self, db: &dyn AnalyzerDb, name: &str) -> Option<FunctionSigId> {
let fun = self.function_sig(db, name)?;
fun.takes_self(db).then(|| fun)
}

pub fn name(&self, db: &dyn AnalyzerDb) -> SmolStr {
match self {
Class::Contract(inner) => inner.name(db),
Class::Struct(inner) => inner.name(db),
Class::Trait(inner) => inner.name(db),
Class::Impl(inner) => inner.name(db),
}
}
pub fn kind(&self) -> &str {
match self {
Class::Contract(_) => "contract",
Class::Struct(_) => "struct",
Class::Trait(_) => "trait",
Class::Impl(_) => "impl",
}
}
pub fn as_item(&self, db: &dyn AnalyzerDb) -> Item {
match self {
Class::Contract(id) => Item::Type(TypeDef::Contract(*id)),
Class::Struct(id) => Item::Type(TypeDef::Struct(*id)),
Class::Trait(id) => Item::Trait(*id),
// Coercing into an Item of the basis of the receiver doesn't seem ideal but can hopefully
// be addressed when we get rid of `Class`.
Class::Impl(id) => id
.receiver(db)
.typ(db)
.as_struct()
.map(|id| Item::Type(TypeDef::Struct(id)))
.expect("missing receiver"),
}
}
}

#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub struct Struct {
pub ast: Node<ast::Struct>,
Expand Down Expand Up @@ -1746,10 +1692,6 @@ impl TraitId {
self.functions(db).get(name).copied()
}

pub fn as_class(&self) -> Class {
Class::Trait(*self)
}

pub fn sink_diagnostics(&self, db: &dyn AnalyzerDb, sink: &mut impl DiagnosticSink) {
db.trait_all_functions(*self).iter().for_each(|id| {
if !id.takes_self(db) {
Expand Down
77 changes: 59 additions & 18 deletions crates/analyzer/src/namespace/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::context::AnalyzerContext;
use crate::display::DisplayWithDb;
use crate::display::Displayable;
use crate::errors::TypeError;
use crate::namespace::items::{Class, ContractId, StructId, TraitId};
use crate::namespace::items::{ContractId, StructId, TraitId};
use crate::AnalyzerDb;

use fe_common::impl_intern_key;
Expand All @@ -15,7 +15,9 @@ use std::rc::Rc;
use std::str::FromStr;
use strum::{AsRefStr, EnumIter, EnumString};

use super::items::FunctionSigId;
use super::items::ImplId;
use super::items::ModuleId;

pub fn u256_min() -> BigInt {
BigInt::from(0)
Expand Down Expand Up @@ -86,6 +88,9 @@ impl TypeId {
pub fn is_bool(&self, db: &dyn AnalyzerDb) -> bool {
matches!(self.typ(db), Type::Base(Base::Bool))
}
pub fn is_contract(&self, db: &dyn AnalyzerDb) -> bool {
matches!(self.typ(db), Type::Contract(_) | Type::SelfContract(_))
}
pub fn is_integer(&self, db: &dyn AnalyzerDb) -> bool {
self.typ(db).is_integer()
}
Expand All @@ -95,15 +100,66 @@ impl TypeId {
pub fn as_struct(&self, db: &dyn AnalyzerDb) -> Option<StructId> {
self.typ(db).as_struct()
}
pub fn as_class(&self, db: &dyn AnalyzerDb) -> Option<Class> {
self.typ(db).as_class()

pub fn name(&self, db: &dyn AnalyzerDb) -> SmolStr {
self.typ(db).name(db)
}

pub fn kind_display_name(&self, db: &dyn AnalyzerDb) -> &str {
match self.typ(db) {
Type::Contract(_) | Type::SelfContract(_) => "contract",
Type::Struct(_) => "struct",
_ => "type",
}
}

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(),
}
}

/// Returns all `impls` for the type
pub fn get_all_impls(&self, db: &dyn AnalyzerDb, module_id: ModuleId) -> Vec<ImplId> {
// TODO: Probably, this isn't looking for all `impl` at all relevant places.
// An `impl` could be in the module of the type but it could also be in the module
// of the trait (which we don't know yet since we just want to get all `impl` regardless of the trait).
// Most likely, what we actually need is a mapping from type to impls and then we can just pick all
// `impl` for some type via that mapping.
module_id
.impls(db)
.iter()
.filter_map(
|((_, ty), impl_)| {
if ty == self {
Some(*impl_)
} else {
None
}
},
)
.collect()
}

pub fn function_sig(&self, db: &dyn AnalyzerDb, name: &str) -> Option<FunctionSigId> {
match self.typ(db) {
Type::Contract(id) => id.function(db, name).map(|fun| fun.sig(db)),
Type::SelfContract(id) => id.function(db, name).map(|fun| fun.sig(db)),
Type::Struct(id) => id.function(db, name).map(|fun| fun.sig(db)),
// FIXME: multiple bounds
Type::Generic(inner) => inner
.bounds
.first()
.and_then(|bound| bound.function(db, name)),
_ => None,
}
}

pub fn self_function(&self, db: &dyn AnalyzerDb, name: &str) -> Option<FunctionSigId> {
let fun = self.function_sig(db, name)?;
fun.takes_self(db).then(|| fun)
}
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
Expand Down Expand Up @@ -503,7 +559,6 @@ pub trait TypeDowncast {
fn as_map(&self) -> Option<&Map>;
fn as_int(&self) -> Option<Integer>;
fn as_primitive(&self) -> Option<Base>;
fn as_class(&self) -> Option<Class>;
fn as_generic(&self) -> Option<&Generic>;
fn as_struct(&self) -> Option<StructId>;
}
Expand Down Expand Up @@ -545,17 +600,6 @@ impl TypeDowncast for Type {
_ => None,
}
}
fn as_class(&self) -> Option<Class> {
match self {
Type::Struct(id) => Some(Class::Struct(*id)),
Type::Contract(id) | Type::SelfContract(id) => Some(Class::Contract(*id)),
Type::Generic(inner) if !inner.bounds.is_empty() => {
// FIXME: This won't hold when we support multiple bounds
inner.bounds.first().map(TraitId::as_class)
}
_ => None,
}
}
fn as_struct(&self) -> Option<StructId> {
match self {
Type::Struct(id) => Some(*id),
Expand Down Expand Up @@ -589,9 +633,6 @@ impl TypeDowncast for Option<&Type> {
fn as_primitive(&self) -> Option<Base> {
self.and_then(TypeDowncast::as_primitive)
}
fn as_class(&self) -> Option<Class> {
self.and_then(TypeDowncast::as_class)
}
fn as_struct(&self) -> Option<StructId> {
self.and_then(TypeDowncast::as_struct)
}
Expand Down
Loading

0 comments on commit 0bad376

Please sign in to comment.