Skip to content

Commit

Permalink
fix state member access in functions
Browse files Browse the repository at this point in the history
  • Loading branch information
SkymanOne committed Mar 24, 2024
1 parent 2ae0733 commit e9298e4
Show file tree
Hide file tree
Showing 8 changed files with 141 additions and 135 deletions.
2 changes: 1 addition & 1 deletion crates/semantics/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ pub struct Param {
pub struct ViewState {
pub loc: Span,
/// State type identifier.
pub ty: usize,
pub ty: SymbolInfo,
/// Variable name identifier.
pub name: Identifier,
}
Expand Down
61 changes: 10 additions & 51 deletions crates/semantics/src/bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ use folidity_parser::ast as parsed_ast;
use crate::{
ast::{
Expression,
FuncReturnType,
StateBody,
StateParam,
TypeVariant,
},
contract::ContractDefinition,
Expand Down Expand Up @@ -39,7 +37,7 @@ pub fn resolve_bounds(contract: &mut ContractDefinition, delay: &DelayedDeclarat
loc: model_delay.decl.loc.clone(),
i: model_delay.i,
}),
ScopeContext::Bounds,
ScopeContext::DeclarationBounds,
);
let mut fields = Vec::new();
let parent_sym = contract.models[model_delay.i].parent.clone();
Expand Down Expand Up @@ -76,7 +74,7 @@ pub fn resolve_bounds(contract: &mut ContractDefinition, delay: &DelayedDeclarat
loc: state_delay.decl.loc.clone(),
i: state_delay.i,
}),
ScopeContext::Bounds,
ScopeContext::DeclarationBounds,
);

let state = contract.states[state_delay.i].clone();
Expand All @@ -86,7 +84,7 @@ pub fn resolve_bounds(contract: &mut ContractDefinition, delay: &DelayedDeclarat
ident,
TypeVariant::State(parent.clone()),
None,
VariableKind::State,
VariableKind::FromState,
false,
scope.current,
contract,
Expand Down Expand Up @@ -120,58 +118,19 @@ pub fn resolve_bounds(contract: &mut ContractDefinition, delay: &DelayedDeclarat
}

for func_delay in &delay.functions {
let Some(st) = &func_delay.decl.st_block else {
continue;
};
let mut scope = Scope::default();
std::mem::swap(&mut contract.functions[func_delay.i].scope, &mut scope);

scope.push(ScopeContext::Bounds);

let func_state = contract.functions[func_delay.i].state_bound.clone();
let func_return = contract.functions[func_delay.i].return_ty.clone();

let mut add_state_param = |param: &StateParam| {
if let Some(ident) = &param.name {
scope.add(
ident,
TypeVariant::State(param.ty.clone()),
None,
VariableKind::State,
false,
scope.current,
contract,
);
}
};

if let Some(b) = &func_state {
if let Some(from) = &b.from {
add_state_param(from);
}
for state_param in &b.to {
add_state_param(state_param);
}
}

if let FuncReturnType::ParamType(param) = &func_return {
scope.add(
&param.name,
param.ty.ty.clone(),
None,
VariableKind::Return,
false,
scope.current,
contract,
);
if let Some(st) = &func_delay.decl.st_block {
let bounds = if let Ok(exprs) = resolve_bound_exprs(&st.expr, &mut scope, contract) {
exprs
} else {
vec![]
};
contract.functions[func_delay.i].bounds = bounds;
}

let Ok(bounds) = resolve_bound_exprs(&st.expr, &mut scope, contract) else {
continue;
};

std::mem::swap(&mut scope, &mut contract.functions[func_delay.i].scope);
contract.functions[func_delay.i].bounds = bounds;
}
}

Expand Down
23 changes: 8 additions & 15 deletions crates/semantics/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,14 @@ use folidity_parser::{
};
use indexmap::IndexMap;

use crate::{
ast::{
EnumDeclaration,
Function,
ModelDeclaration,
Param,
StateBody,
StateDeclaration,
StructDeclaration,
},
functions::resolve_func_body,
use crate::ast::{
EnumDeclaration,
Function,
ModelDeclaration,
Param,
StateBody,
StateDeclaration,
StructDeclaration,
};

use crate::{
Expand Down Expand Up @@ -116,10 +113,6 @@ impl ContractDefinition {
});
}
}

for f in &delayed_decls.functions {
let _ = resolve_func_body(&f.decl, f.i, self);
}
}

/// Resolves fields during the second pass.
Expand Down
5 changes: 4 additions & 1 deletion crates/semantics/src/expression/complex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -834,7 +834,10 @@ fn find_var(
let Some((v_i, _)) = scope.find_var_index(&ident.name) else {
contract.diagnostics.push(Report::semantic_error(
ident.loc.clone(),
format!("`{}`: Variable is not declared.", ident.name),
format!(
"`{}`: Variable is not declared or inaccessible.",
ident.name
),
));
return Err(());
};
Expand Down
99 changes: 64 additions & 35 deletions crates/semantics/src/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ pub fn function_decl(
let mut func_vis = FunctionVisibility::Priv;
if let parsed_ast::FunctionVisibility::View(v) = &func.vis {
let mut view_error = false;
let mut id = 0;
let mut id = SymbolInfo::default();
let mut ident = Identifier::default();
if func.access_attributes.is_empty() {
contract.diagnostics.push(Report::semantic_warning(
Expand All @@ -105,7 +105,7 @@ pub fn function_decl(

if let Some(sym) = GlobalSymbol::lookup(contract, &v.param.ty) {
if let GlobalSymbol::State(s) = sym {
id = s.i;
id = s.clone();
} else {
contract.diagnostics.push(Report::semantic_error(
ident.loc.clone(),
Expand Down Expand Up @@ -172,33 +172,31 @@ pub fn function_decl(
i: function_no,
});

let mut scope = Scope::new(&sym, ScopeContext::AccessAttributes);
let mut scope = Scope::new(&sym, ScopeContext::DeclarationBounds);

scope.add(
&Identifier {
loc: func.loc.clone(),
name: "any".to_string(),
},
TypeVariant::Address,
None,
VariableKind::State,
VariableKind::Local,
false,
scope.current,
contract,
);
if let Some(bounds) = &s_bound {
if let Some(from) = &bounds.from {
if let Some(var) = &from.name {
scope.add(
var,
TypeVariant::State(from.ty.clone()),
None,
VariableKind::State,
false,
scope.current,
contract,
);
}
}

if let FunctionVisibility::View(v) = &func_vis {
scope.add(
&v.name,
TypeVariant::State(v.ty.clone()),
None,
VariableKind::Local,
false,
scope.current,
contract,
);
}

let access_attributes: Vec<Expression> = func
Expand Down Expand Up @@ -243,6 +241,54 @@ pub fn function_decl(
return Err(());
}

// add params to the scope.
for param in params.values() {
scope.add(
&param.name,
param.ty.ty.clone(),
None,
VariableKind::Param,
param.is_mut,
scope.current,
contract,
);
}

let mut add_state_param = |param: &StateParam, kind: VariableKind| {
if let Some(ident) = &param.name {
scope.add(
ident,
TypeVariant::State(param.ty.clone()),
None,
kind,
false,
0,
contract,
);
}
};

if let Some(b) = &s_bound {
if let Some(from) = &b.from {
add_state_param(from, VariableKind::FromState);
}
for state_param in &b.to {
add_state_param(state_param, VariableKind::ToState);
}
}

if let FuncReturnType::ParamType(param) = &return_ty {
scope.add(
&param.name,
param.ty.ty.clone(),
None,
VariableKind::Return,
false,
0,
contract,
);
}

let mut decl = Function::new(
func.loc.clone(),
func.is_init,
Expand Down Expand Up @@ -278,26 +324,9 @@ pub fn resolve_func_body(
) -> Result<(), ()> {
let mut scope = Scope::default();
std::mem::swap(&mut scope, &mut contract.functions[func_i].scope);
scope.push(ScopeContext::FunctionParams);

let mut resolved_stmts = Vec::new();

// add params to the scope.
for param in &func_decl.params {
let ty = map_type(contract, &param.ty)?;
scope.add(
&param.name,
ty.ty,
None,
VariableKind::Param,
param.is_mut,
scope.current,
contract,
);
}

scope.push(ScopeContext::FunctionBody);

// if the return type is not `()` then we expect the function body to contain `return`
// statement. i.e. it should be unreachable after the last statement,
let return_required = !matches!(func_decl.return_ty.ty(), parsed_ast::TypeVariant::Unit);
Expand Down
5 changes: 5 additions & 0 deletions crates/semantics/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use bounds::resolve_bounds;
use contract::ContractDefinition;
use folidity_parser::ast::Source;
use functions::resolve_func_body;
use types::check_inheritance;

mod ast;
Expand Down Expand Up @@ -36,5 +37,9 @@ pub fn resolve_semantics(source: &Source) -> ContractDefinition {
// now we can resolve model bounds on all declarations.
resolve_bounds(&mut definition, &delay);

for f in &delay.functions {
let _ = resolve_func_body(&f.decl, f.i, &mut definition);
}

definition
}
Loading

0 comments on commit e9298e4

Please sign in to comment.