Skip to content

Commit

Permalink
Treat trait exclusively as Item not Type (#744)
Browse files Browse the repository at this point in the history
  • Loading branch information
cburgdorf authored Jun 17, 2022
1 parent 35579de commit 9a4a2fe
Show file tree
Hide file tree
Showing 14 changed files with 151 additions and 74 deletions.
8 changes: 0 additions & 8 deletions crates/analyzer/src/db/queries/contracts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,14 +330,6 @@ pub fn contract_field_type(

let node = &field.data(db).ast;

if let Ok(Type::Trait(ref val)) = typ {
scope.error(
"traits can not be used as contract fields",
node.span,
&format!("trait `{}` can not appear here", val.name),
);
}

if node.kind.is_pub {
scope.not_yet_implemented("contract `pub` fields", node.span);
}
Expand Down
22 changes: 5 additions & 17 deletions crates/analyzer/src/db/queries/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::namespace::items::{
use crate::namespace::scopes::{BlockScope, BlockScopeType, FunctionScope, ItemScope};
use crate::namespace::types::{self, Contract, CtxDecl, Generic, SelfDecl, Struct, Type};
use crate::traversal::functions::traverse_statements;
use crate::traversal::types::type_desc;
use crate::traversal::types::{type_desc, type_desc_to_trait};
use fe_common::diagnostics::Label;
use fe_parser::ast::{self, GenericParameter};
use fe_parser::node::Node;
Expand Down Expand Up @@ -255,17 +255,9 @@ pub fn resolve_function_param_type(
if let Some(val) = function.generic_param(db, base) {
let bounds = match val {
ast::GenericParameter::Unbounded(_) => vec![],
ast::GenericParameter::Bounded { bound, .. } => match type_desc(context, &bound)? {
Type::Trait(trait_ty) => vec![trait_ty.id],
other => {
context.error(
&format!("expected trait, found type `{}`", other),
bound.span,
"not a trait",
);
vec![]
}
},
ast::GenericParameter::Bounded { bound, .. } => {
vec![type_desc_to_trait(context, &bound)?]
}
};

return Ok(Type::Generic(Generic {
Expand Down Expand Up @@ -401,11 +393,7 @@ pub fn function_dependency_graph(db: &dyn AnalyzerDb, function: FunctionId) -> D
directs.push((root, Item::Function(*method), DepLocality::Local));
}
CallType::TraitValueMethod { trait_id, .. } => {
directs.push((
root,
Item::Type(TypeDef::Trait(*trait_id)),
DepLocality::Local,
));
directs.push((root, Item::Trait(*trait_id), DepLocality::Local));
}
CallType::External { contract, function } => {
directs.push((root, Item::Function(*function), DepLocality::External));
Expand Down
12 changes: 5 additions & 7 deletions crates/analyzer/src/db/queries/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,10 @@ pub fn module_all_items(db: &dyn AnalyzerDb, module: ModuleId) -> Rc<[Item]> {
ast::ModuleStmt::Function(node) => Some(Item::Function(
db.intern_function(Rc::new(Function::new(db, node, None, module))),
)),
ast::ModuleStmt::Trait(node) => Some(Item::Type(TypeDef::Trait(db.intern_trait(
Rc::new(Trait {
ast: node.clone(),
module,
}),
)))),
ast::ModuleStmt::Trait(node) => Some(Item::Trait(db.intern_trait(Rc::new(Trait {
ast: node.clone(),
module,
})))),
ast::ModuleStmt::Pragma(_) | ast::ModuleStmt::Use(_) | ast::ModuleStmt::Impl(_) => None,
ast::ModuleStmt::Event(node) => Some(Item::Event(db.intern_event(Rc::new(Event {
ast: node.clone(),
Expand All @@ -119,7 +117,7 @@ pub fn module_all_impls(db: &dyn AnalyzerDb, module: ModuleId) -> Rc<[ImplId]> {
let mut scope = ItemScope::new(db, module);
let receiver_type = type_desc(&mut scope, &impl_node.kind.receiver).unwrap();

if let Some(Item::Type(TypeDef::Trait(val))) = treit {
if let Some(Item::Trait(val)) = treit {
Some(db.intern_impl(Rc::new(Impl {
trait_id: val,
receiver: receiver_type,
Expand Down
24 changes: 11 additions & 13 deletions crates/analyzer/src/namespace/items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ pub enum Item {
// Events aren't normal types; they *could* be moved into
// TypeDef, but it would have consequences.
Event(EventId),
Trait(TraitId),
Function(FunctionId),
Constant(ModuleConstantId),
// Needed until we can represent keccak256 as a FunctionId.
Expand All @@ -48,6 +49,7 @@ impl Item {
pub fn name(&self, db: &dyn AnalyzerDb) -> SmolStr {
match self {
Item::Type(id) => id.name(db),
Item::Trait(id) => id.name(db),
Item::GenericType(id) => id.name(),
Item::Event(id) => id.name(db),
Item::Function(id) => id.name(db),
Expand All @@ -62,6 +64,7 @@ impl Item {
pub fn name_span(&self, db: &dyn AnalyzerDb) -> Option<Span> {
match self {
Item::Type(id) => id.name_span(db),
Item::Trait(id) => Some(id.name_span(db)),
Item::GenericType(_) => None,
Item::Event(id) => Some(id.name_span(db)),
Item::Function(id) => Some(id.name_span(db)),
Expand All @@ -81,6 +84,7 @@ impl Item {
| Self::Intrinsic(_)
| Self::GenericType(_) => true,
Self::Type(id) => id.is_public(db),
Self::Trait(id) => id.is_public(db),
Self::Event(id) => id.is_public(db),
Self::Function(id) => id.is_public(db),
Self::Constant(id) => id.is_public(db),
Expand All @@ -94,6 +98,7 @@ impl Item {
| Item::BuiltinFunction(_)
| Item::Intrinsic(_) => true,
Item::Type(_)
| Item::Trait(_)
| Item::Event(_)
| Item::Function(_)
| Item::Constant(_)
Expand All @@ -113,6 +118,7 @@ impl Item {
pub fn item_kind_display_name(&self) -> &'static str {
match self {
Item::Type(_) | Item::GenericType(_) => "type",
Item::Trait(_) => "trait",
Item::Event(_) => "event",
Item::Function(_) | Item::BuiltinFunction(_) => "function",
Item::Intrinsic(_) => "intrinsic function",
Expand All @@ -129,6 +135,7 @@ impl Item {
Item::Type(val) => val.items(db),
Item::GenericType(_)
| Item::Event(_)
| Item::Trait(_)
| Item::Function(_)
| Item::Constant(_)
| Item::BuiltinFunction(_)
Expand All @@ -139,6 +146,7 @@ impl Item {
pub fn parent(&self, db: &dyn AnalyzerDb) -> Option<Item> {
match self {
Item::Type(id) => id.parent(db),
Item::Trait(id) => Some(id.parent(db)),
Item::GenericType(_) => None,
Item::Event(id) => Some(id.parent(db)),
Item::Function(id) => Some(id.parent(db)),
Expand Down Expand Up @@ -222,6 +230,7 @@ impl Item {
pub fn sink_diagnostics(&self, db: &dyn AnalyzerDb, sink: &mut impl DiagnosticSink) {
match self {
Item::Type(id) => id.sink_diagnostics(db, sink),
Item::Trait(id) => id.sink_diagnostics(db, sink),
Item::Event(id) => id.sink_diagnostics(db, sink),
Item::Function(id) => id.sink_diagnostics(db, sink),
Item::GenericType(_) | Item::BuiltinFunction(_) | Item::Intrinsic(_) => {}
Expand Down Expand Up @@ -772,7 +781,6 @@ impl ModuleConstantId {
pub enum TypeDef {
Alias(TypeAliasId),
Struct(StructId),
Trait(TraitId),
Contract(ContractId),
Primitive(types::Base),
}
Expand Down Expand Up @@ -804,7 +812,6 @@ impl TypeDef {
match self {
TypeDef::Alias(id) => id.name(db),
TypeDef::Struct(id) => id.name(db),
TypeDef::Trait(id) => id.name(db),
TypeDef::Contract(id) => id.name(db),
TypeDef::Primitive(typ) => typ.name(),
}
Expand All @@ -814,7 +821,6 @@ impl TypeDef {
match self {
TypeDef::Alias(id) => Some(id.name_span(db)),
TypeDef::Struct(id) => Some(id.name_span(db)),
TypeDef::Trait(id) => Some(id.name_span(db)),
TypeDef::Contract(id) => Some(id.name_span(db)),
TypeDef::Primitive(_) => None,
}
Expand All @@ -828,10 +834,6 @@ impl TypeDef {
name: id.name(db),
field_count: id.fields(db).len(), // for the EvmSized trait
})),
TypeDef::Trait(id) => Ok(types::Type::Trait(types::Trait {
id: *id,
name: id.name(db),
})),
TypeDef::Contract(id) => Ok(types::Type::Contract(types::Contract {
id: *id,
name: id.name(db),
Expand All @@ -844,7 +846,6 @@ impl TypeDef {
match self {
Self::Alias(id) => id.is_public(db),
Self::Struct(id) => id.is_public(db),
Self::Trait(id) => id.is_public(db),
Self::Contract(id) => id.is_public(db),
Self::Primitive(_) => true,
}
Expand All @@ -854,7 +855,6 @@ impl TypeDef {
match self {
TypeDef::Alias(id) => Some(id.parent(db)),
TypeDef::Struct(id) => Some(id.parent(db)),
TypeDef::Trait(id) => Some(id.parent(db)),
TypeDef::Contract(id) => Some(id.parent(db)),
TypeDef::Primitive(_) => None,
}
Expand All @@ -864,7 +864,6 @@ impl TypeDef {
match self {
TypeDef::Alias(id) => id.sink_diagnostics(db, sink),
TypeDef::Struct(id) => id.sink_diagnostics(db, sink),
TypeDef::Trait(id) => id.sink_diagnostics(db, sink),
TypeDef::Contract(id) => id.sink_diagnostics(db, sink),
TypeDef::Primitive(_) => {}
}
Expand Down Expand Up @@ -1158,7 +1157,7 @@ impl FunctionSigId {
}

pub fn is_trait_fn(&self, db: &dyn AnalyzerDb) -> bool {
matches!(self.parent(db), Item::Type(TypeDef::Trait(_)))
matches!(self.parent(db), Item::Trait(_))
}

pub fn is_impl_fn(&self, db: &dyn AnalyzerDb) -> bool {
Expand Down Expand Up @@ -1344,7 +1343,7 @@ impl Class {
match self {
Class::Contract(id) => Item::Type(TypeDef::Contract(*id)),
Class::Struct(id) => Item::Type(TypeDef::Struct(*id)),
Class::Trait(id) => Item::Type(TypeDef::Trait(*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
Expand Down Expand Up @@ -1595,7 +1594,6 @@ impl ImplId {
Type::Contract(_)
| Type::Map(_)
| Type::SelfContract(_)
| Type::Trait(_)
| Type::Generic(_)
// TODO: We should find a way to support these types. We only support implementing traits for structs
// so far because it simplifies things regarding the assign location of the underlying type.
Expand Down
5 changes: 1 addition & 4 deletions crates/analyzer/src/namespace/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ pub enum Type {
/// of `self` within a contract function.
SelfContract(Contract),
Struct(Struct),
Trait(Trait),
Generic(Generic),
}

Expand Down Expand Up @@ -410,7 +409,6 @@ impl Type {
Type::Tuple(inner) => inner.to_string().into(),
Type::String(inner) => inner.to_string().into(),
Type::Struct(inner) => inner.name.clone(),
Type::Trait(inner) => inner.name.clone(),
Type::Generic(inner) => inner.name.clone(),
Type::Contract(inner) | Type::SelfContract(inner) => inner.name.clone(),
}
Expand Down Expand Up @@ -482,7 +480,7 @@ impl Type {
| Type::Struct(_)
| Type::Generic(_)
| Type::Contract(_) => true,
Type::Map(_) | Type::SelfContract(_) | Type::Trait(_) => false,
Type::Map(_) | Type::SelfContract(_) => false,
}
}
}
Expand Down Expand Up @@ -686,7 +684,6 @@ impl fmt::Display for Type {
Type::Contract(inner) => inner.fmt(f),
Type::SelfContract(inner) => inner.fmt(f),
Type::Struct(inner) => inner.fmt(f),
Type::Trait(inner) => inner.fmt(f),
Type::Generic(inner) => inner.fmt(f),
}
}
Expand Down
1 change: 0 additions & 1 deletion crates/analyzer/src/operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ pub fn index(value: Type, index: Type) -> Result<Type, IndexingError> {
| Type::String(_)
| Type::Contract(_)
| Type::SelfContract(_)
| Type::Trait(_)
| Type::Generic(_)
| Type::Struct(_) => Err(IndexingError::NotSubscriptable),
}
Expand Down
40 changes: 28 additions & 12 deletions crates/analyzer/src/traversal/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use crate::context::{AnalyzerContext, CallType, ExpressionAttributes, Location,
use crate::errors::{FatalError, IndexingError};
use crate::namespace::items::{Class, FunctionId, Item, TypeDef};
use crate::namespace::scopes::BlockScopeType;
use crate::namespace::types::Trait;
use crate::namespace::types::{
Array, Base, Contract, FeString, Integer, Struct, Tuple, Type, TypeDowncast, U256,
};
Expand Down Expand Up @@ -179,7 +178,7 @@ pub fn assignable_expr(
attributes.move_location = Some(Location::Value);
}
}
Array(_) | Tuple(_) | String(_) | Struct(_) | Trait(_) | Generic(_) => {
Array(_) | Tuple(_) | String(_) | Struct(_) | Generic(_) => {
if attributes.final_location() != Location::Memory {
context.fancy_error(
"value must be copied to memory",
Expand Down Expand Up @@ -318,10 +317,24 @@ fn expr_named_thing(
id.receiver(context.db()),
Location::Memory,
)),
Class::Trait(id) => Ok(ExpressionAttributes::new(
Type::Trait(Trait::from_id(id, context.db())),
Location::Memory,
)),
// This can only happen when trait methods can implement a default body
Class::Trait(id) => Err(FatalError::new(context.fancy_error(
&format!(
"`{}` is a trait, and can't be used as an expression",
exp.kind
),
vec![
Label::primary(
id.name_span(context.db()),
&format!("`{}` is defined here as a trait", exp.kind),
),
Label::primary(
exp.span,
&format!("`{}` is used here as a value", exp.kind),
),
],
vec![],
))),
Class::Contract(id) => Ok(ExpressionAttributes::new(
Type::SelfContract(Contract::from_id(id, context.db())),
Location::Value,
Expand Down Expand Up @@ -974,6 +987,14 @@ fn expr_call_named_thing<T: std::fmt::Display>(
func.kind
)],
))),
NamedThing::Item(Item::Trait(_)) => Err(FatalError::new(context.error(
&format!("`{}` is not callable", func.kind),
func.span,
&format!(
"`{}` is a trait, and can't be used as a function",
func.kind
),
))),
NamedThing::Item(Item::Ingot(_)) => Err(FatalError::new(context.error(
&format!("`{}` is not callable", func.kind),
func.span,
Expand Down Expand Up @@ -1129,11 +1150,7 @@ fn expr_call_type_constructor(
Type::Struct(struct_type) => {
return expr_call_struct_constructor(context, name_span, struct_type, args)
}
Type::Base(Base::Bool)
| Type::Array(_)
| Type::Map(_)
| Type::Generic(_)
| Type::Trait(_) => {
Type::Base(Base::Bool) | Type::Array(_) | Type::Map(_) | Type::Generic(_) => {
return Err(FatalError::new(context.error(
&format!("`{}` type is not callable", typ.name()),
name_span,
Expand Down Expand Up @@ -1220,7 +1237,6 @@ fn expr_call_type_constructor(
Type::Struct(_) => unreachable!(), // handled above
Type::Map(_) => unreachable!(), // handled above
Type::Array(_) => unreachable!(), // handled above
Type::Trait(_) => unreachable!(), // handled above
Type::Generic(_) => unreachable!(), // handled above
Type::SelfContract(_) => unreachable!(), /* unnameable; contract names all become
* Type::Contract */
Expand Down
Loading

0 comments on commit 9a4a2fe

Please sign in to comment.