From 348e1a4297656e969a44a3cfc0632da8aa9726a3 Mon Sep 17 00:00:00 2001 From: German Nikolishin Date: Sat, 24 Feb 2024 14:58:49 +0000 Subject: [PATCH] resolve fields --- crates/semantics/src/ast.rs | 14 ----------- crates/semantics/src/contract.rs | 10 +++++--- crates/semantics/src/lib.rs | 1 + crates/semantics/src/types.rs | 42 +++++++++++++++++++++++++++++--- 4 files changed, 46 insertions(+), 21 deletions(-) diff --git a/crates/semantics/src/ast.rs b/crates/semantics/src/ast.rs index 862e01c..d4b220e 100644 --- a/crates/semantics/src/ast.rs +++ b/crates/semantics/src/ast.rs @@ -47,20 +47,6 @@ impl Type { set } TypeVariant::Struct(s) => HashSet::from([s.i]), - TypeVariant::Model(s) => { - contract.diagnostics.push(Report::semantic_error( - s.loc.clone(), - String::from("Cannot use model as a type here,"), - )); - HashSet::new() - } - TypeVariant::State(s) => { - contract.diagnostics.push(Report::semantic_error( - s.loc.clone(), - String::from("Cannot use state as a type here,"), - )); - HashSet::new() - } _ => HashSet::new(), } } diff --git a/crates/semantics/src/contract.rs b/crates/semantics/src/contract.rs index 34480b5..97ed390 100644 --- a/crates/semantics/src/contract.rs +++ b/crates/semantics/src/contract.rs @@ -11,7 +11,7 @@ use crate::ast::{ }; use crate::decls::DelayedDeclaration; use crate::global_symbol::SymbolInfo; -use crate::types::map_type; +use crate::types::{find_user_type_recursion, map_type, validate_fields}; use crate::{decls::DelayedDeclarations, global_symbol::GlobalSymbol}; /// Arbitrary limit of a max number of topic. @@ -73,6 +73,9 @@ impl ContractDefinition { } /// Resolves fields during the second pass. + /// - Discover fields for structs, models, and states. + /// - Detect any cycles and report them. + /// - Ensure that no fields have types of any state or model. pub fn resolve_fields(&mut self, delay: &DelayedDeclarations) { // Update fields of the models and structs together. for (s, m) in delay.structs.iter().zip(delay.models.iter()) { @@ -115,8 +118,9 @@ impl ContractDefinition { self.states[state.i].body = body; } - // todo: check for cycles. - // todo: check for valid types. + + find_user_type_recursion(self); + validate_fields(self); } /// Resolve fields of declarations. diff --git a/crates/semantics/src/lib.rs b/crates/semantics/src/lib.rs index a472313..bf90ecd 100644 --- a/crates/semantics/src/lib.rs +++ b/crates/semantics/src/lib.rs @@ -18,6 +18,7 @@ mod tests; pub fn resolve_semantics(source: &Source) -> ContractDefinition { let mut definition = ContractDefinition::default(); let delay = definition.resolve_declarations(source); + definition.resolve_fields(&delay); definition } diff --git a/crates/semantics/src/types.rs b/crates/semantics/src/types.rs index 41b7d47..2691a75 100644 --- a/crates/semantics/src/types.rs +++ b/crates/semantics/src/types.rs @@ -1,6 +1,6 @@ use std::collections::HashSet; -use crate::ast::{List, Mapping, Param, Set, Type, TypeVariant}; +use crate::ast::{List, Mapping, Param, Set, StateBody, Type, TypeVariant}; use crate::contract::ContractDefinition; use crate::global_symbol::{GlobalSymbol, SymbolInfo}; use folidity_diagnostics::Report; @@ -81,7 +81,7 @@ pub fn map_type(contract: &mut ContractDefinition, ty: &parsed_ast::Type) -> Res /// Licensed as Apache 2.0 //todo: rewrite. //TODO: support finite size recursive types. -pub fn find_user_type_recursion(contract: &mut ContractDefinition) -> Result<(), Span> { +pub fn find_user_type_recursion(contract: &mut ContractDefinition) { let mut edges = HashSet::new(); for n in 0..contract.structs.len() { collect_edges( @@ -111,8 +111,6 @@ pub fn find_user_type_recursion(contract: &mut ContractDefinition) -> Result<(), )); } } - - Ok(()) } /// Collect field dependencies into the graph edges. @@ -145,3 +143,39 @@ fn check_for_recursive_types(node: usize, graph: &FieldGraph, contract: &mut Con } } } + +pub fn validate_fields(contract: &mut ContractDefinition) { + let mut validate = |fields: &[Param]| { + for field in fields.iter() { + match &field.ty.ty { + TypeVariant::Function(_) => contract.diagnostics.push(Report::semantic_error( + field.loc.clone(), + String::from("Function cannot be used as a field type."), + )), + TypeVariant::Model(_) => contract.diagnostics.push(Report::semantic_error( + field.loc.clone(), + String::from("Model cannot be used as a field type."), + )), + TypeVariant::State(_) => contract.diagnostics.push(Report::semantic_error( + field.loc.clone(), + String::from("State cannot be used as a field type."), + )), + _ => {} + } + } + }; + + for s in &contract.structs { + validate(&s.fields); + } + + for s in &contract.states { + if let Some(StateBody::Raw(fields)) = &s.body { + validate(fields); + } + } + + for m in &contract.models { + validate(&m.fields); + } +}