Skip to content

Commit

Permalink
Basic mut enforcement, remove .clone() function
Browse files Browse the repository at this point in the history
  • Loading branch information
sbillig committed Oct 7, 2022
1 parent c3a1d99 commit 3b547e7
Show file tree
Hide file tree
Showing 429 changed files with 5,993 additions and 3,860 deletions.
1 change: 0 additions & 1 deletion crates/analyzer/src/builtins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use strum::{AsRefStr, EnumIter, EnumString};
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, EnumString, AsRefStr)]
#[strum(serialize_all = "snake_case")]
pub enum ValueMethod {
Clone,
ToMem,
AbiEncode,
}
Expand Down
12 changes: 9 additions & 3 deletions crates/analyzer/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ pub trait AnalyzerContext {
/// Panics if a context is not in a function. Use [`Self::is_in_function`]
/// to determine whether a context is in a function.
fn add_call(&self, node: &Node<ast::Expr>, call_type: CallType);
fn get_call(&self, node: &Node<ast::Expr>) -> Option<CallType>;

/// Returns `true` if the context is in function scope.
fn is_in_function(&self) -> bool;
Expand Down Expand Up @@ -362,6 +363,10 @@ impl AnalyzerContext for TempContext {
panic!("TempContext can't add call");
}

fn get_call(&self, _node: &Node<ast::Expr>) -> Option<CallType> {
panic!("TempContext can't have calls");
}

fn is_in_function(&self) -> bool {
false
}
Expand Down Expand Up @@ -419,8 +424,9 @@ pub struct Adjustment {

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum AdjustmentKind {
FromStorage,
// DeMut,
Copy,
/// Load from storage ptr
Load,
IntSizeIncrease,
StringSizeIncrease,
}
Expand All @@ -447,7 +453,7 @@ impl crate::display::DisplayWithDb for ExpressionAttributes {
write!(f, " = {:?}", val)?;
}
for adj in type_adjustments {
write!(f, " -> {}", adj.into.display(db))?;
write!(f, " -{:?}-> {}", adj.kind, adj.into.display(db))?;
}
Ok(())
}
Expand Down
19 changes: 13 additions & 6 deletions crates/analyzer/src/db/queries/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,15 @@ pub fn function_signature(
.iter()
.enumerate()
.filter_map(|(index, arg)| match &arg.kind {
ast::FunctionArg::Self_ { .. }=> {
ast::FunctionArg::Self_ { mut_ }=> {
if matches!(fn_parent, Item::Module(_)) {
scope.error(
"`self` can only be used in contract, struct, trait or impl functions",
arg.span,
"not allowed in functions defined directly in a module",
);
} else {
self_decl = Some(SelfDecl::Mutable);
self_decl = Some(SelfDecl { span: arg.span, mut_: *mut_ });
if index != 0 {
scope.error(
"`self` is not the first parameter",
Expand All @@ -104,9 +104,15 @@ pub fn function_signature(
}
None
}
ast::FunctionArg::Regular { mut_: _, label, name, typ: typedesc } => {
let typ = resolve_function_param_type(db, function, &mut scope, &typedesc).and_then(|typ| match typ {
typ if typ.has_fixed_size(db) => Ok(typ),
ast::FunctionArg::Regular { mut_, label, name, typ: typedesc } => {
let typ = resolve_function_param_type(db, function, &mut scope, typedesc).and_then(|typ| match typ {
typ if typ.has_fixed_size(db) => {
if mut_.is_some() {
Ok(Type::Mut(typ).id(db))
} else {
Ok(typ)
}
}
_ => Err(TypeError::new(scope.error(
"function parameter types must have fixed size",
typedesc.span,
Expand Down Expand Up @@ -177,6 +183,7 @@ pub fn function_signature(
None
} else {
names.insert(&name.kind, index);

Some(types::FunctionParam::new(
label.as_ref().map(|s| s.kind.as_str()),
&name.kind,
Expand Down Expand Up @@ -229,7 +236,7 @@ pub fn function_signature(
}
}

pub fn resolve_function_param_type(
fn resolve_function_param_type(
db: &dyn AnalyzerDb,
function: FunctionSigId,
context: &mut dyn AnalyzerContext,
Expand Down
11 changes: 10 additions & 1 deletion crates/analyzer/src/namespace/scopes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ impl<'a> AnalyzerContext for ItemScope<'a> {
fn add_call(&self, _node: &Node<ast::Expr>, _call_type: CallType) {
unreachable!("Can't call function outside of function")
}
fn get_call(&self, _node: &Node<ast::Expr>) -> Option<CallType> {
unreachable!("Can't call function outside of function")
}

fn is_in_function(&self) -> bool {
false
Expand Down Expand Up @@ -285,14 +288,16 @@ impl<'a> AnalyzerContext for FunctionScope<'a> {

fn add_call(&self, node: &Node<ast::Expr>, call_type: CallType) {
// TODO: should probably take the Expr::Call node, rather than the function node

self.add_node(node);
self.body
.borrow_mut()
.calls
.insert(node.id, call_type)
.expect_none("call attributes already exist");
}
fn get_call(&self, node: &Node<ast::Expr>) -> Option<CallType> {
self.body.borrow().calls.get(&node.id).cloned()
}

fn is_in_function(&self) -> bool {
true
Expand Down Expand Up @@ -509,6 +514,10 @@ impl AnalyzerContext for BlockScope<'_, '_> {
self.root.add_call(node, call_type)
}

fn get_call(&self, node: &Node<ast::Expr>) -> Option<CallType> {
self.root.get_call(node)
}

fn is_in_function(&self) -> bool {
true
}
Expand Down
37 changes: 32 additions & 5 deletions crates/analyzer/src/namespace/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ impl TypeId {
pub fn deref(self, db: &dyn AnalyzerDb) -> TypeId {
match self.typ(db) {
Type::SPtr(inner) => inner,
Type::Mut(inner) => inner.deref(db),
_ => self,
}
}
Expand All @@ -96,6 +97,11 @@ impl TypeId {
pub fn has_fixed_size(&self, db: &dyn AnalyzerDb) -> bool {
self.typ(db).has_fixed_size(db)
}

/// `true` if Type::Base or Type::Contract (which is just an Address)
pub fn is_primitive(&self, db: &dyn AnalyzerDb) -> bool {
matches!(self.typ(db), Type::Base(_) | Type::Contract(_))
}
pub fn is_base(&self, db: &dyn AnalyzerDb) -> bool {
matches!(self.typ(db), Type::Base(_))
}
Expand Down Expand Up @@ -125,7 +131,18 @@ impl TypeId {
matches!(self.typ(db), Type::Struct(_))
}
pub fn is_sptr(&self, db: &dyn AnalyzerDb) -> bool {
matches!(self.typ(db), Type::SPtr(_))
match self.typ(db) {
Type::SPtr(_) => true,
Type::Mut(inner) => inner.is_sptr(db),
_ => false,
}
}
pub fn is_generic(&self, db: &dyn AnalyzerDb) -> bool {
matches!(self.deref(db).typ(db), Type::Generic(_))
}

pub fn is_mut(&self, db: &dyn AnalyzerDb) -> bool {
matches!(self.typ(db), Type::Mut(_))
}

pub fn name(&self, db: &dyn AnalyzerDb) -> SmolStr {
Expand Down Expand Up @@ -305,9 +322,15 @@ pub struct FunctionSignature {
pub return_type: Result<TypeId, TypeError>,
}

#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)]
pub enum SelfDecl {
Mutable,
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct SelfDecl {
pub span: Span,
pub mut_: Option<Span>,
}
impl SelfDecl {
pub fn is_mut(&self) -> bool {
self.mut_.is_some()
}
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
Expand Down Expand Up @@ -718,9 +741,13 @@ impl DisplayWithDb for FunctionSignature {
return_type,
} = self;

write!(f, "self: {:?}, ", self_decl)?;
write!(f, "params: [")?;
let mut delim = "";
if let Some(s) = self_decl {
write!(f, "{}self", if s.mut_.is_some() { "mut " } else { "" },)?;
delim = ", ";
}

for p in params {
write!(
f,
Expand Down
8 changes: 5 additions & 3 deletions crates/analyzer/src/operations.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::context::AnalyzerContext;
use crate::errors::{BinaryOperationError, IndexingError};
use crate::namespace::types::{Array, Integer, Map, Type, TypeDowncast, TypeId};

use crate::traversal::types::{deref_type, try_coerce_type};
use fe_parser::{ast as fe, node::Node};

Expand Down Expand Up @@ -56,7 +57,7 @@ fn index_array(
index_expr: &Node<fe::Expr>,
) -> Result<TypeId, IndexingError> {
let u256 = Type::u256().id(context.db());
if try_coerce_type(context, Some(index_expr), index, u256).is_err() {
if try_coerce_type(context, Some(index_expr), index, u256, false).is_err() {
return Err(IndexingError::WrongIndexType);
}

Expand All @@ -70,7 +71,8 @@ fn index_map(
index_expr: &Node<fe::Expr>,
) -> Result<TypeId, IndexingError> {
let Map { key, value } = map;
if try_coerce_type(context, Some(index_expr), index, *key).is_err() {

if try_coerce_type(context, Some(index_expr), index, *key, false).is_err() {
return Err(IndexingError::WrongIndexType);
}
Ok(*value)
Expand Down Expand Up @@ -120,7 +122,7 @@ fn bin_arithmetic(
) -> Result<TypeId, BinaryOperationError> {
// For now, we require that the types be numeric, have the same signedness,
// and that left.size() >= right.size(). (The rules imposed by try_coerce_type)
if try_coerce_type(context, Some(right_expr), right, left).is_ok() {
if try_coerce_type(context, Some(right_expr), right, left, false).is_ok() {
// TODO: loosen up arightmetic type rules.
// The rules should be:
// - Any combination of numeric types can be operated on.
Expand Down
Loading

0 comments on commit 3b547e7

Please sign in to comment.