Skip to content

Commit

Permalink
Add function declarations to the DeclarationEngine (FuelLabs#2722)
Browse files Browse the repository at this point in the history
Add function declarations to the declaration engine.

Closes FuelLabs#2635.
  • Loading branch information
tritao authored Sep 12, 2022
1 parent 95cd150 commit 9aeb723
Show file tree
Hide file tree
Showing 11 changed files with 219 additions and 119 deletions.
15 changes: 10 additions & 5 deletions sway-core/src/control_flow_analysis/analyze_return_paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@
//! execution.
use crate::{
control_flow_analysis::*, declaration_engine::declaration_engine::de_get_impl_trait, error::*,
parse_tree::*, semantic_analysis::*, type_system::*,
control_flow_analysis::*,
declaration_engine::declaration_engine::{de_get_function, de_get_impl_trait},
error::*,
parse_tree::*,
semantic_analysis::*,
type_system::*,
};
use petgraph::prelude::NodeIndex;
use sway_types::{ident::Ident, span::Span};
use sway_types::{ident::Ident, span::Span, Spanned};

impl ControlFlowGraph {
pub(crate) fn construct_return_path_graph(
Expand Down Expand Up @@ -210,12 +214,13 @@ fn connect_declaration(
}
Ok(vec![entry_node])
}
FunctionDeclaration(fn_decl) => {
FunctionDeclaration(decl_id) => {
let fn_decl = de_get_function(decl_id.clone(), &decl.span())?;
let entry_node = graph.add_node(node.into());
for leaf in leaves {
graph.add_edge(*leaf, entry_node, "".into());
}
connect_typed_fn_decl(fn_decl, graph, entry_node, span)?;
connect_typed_fn_decl(&fn_decl, graph, entry_node, span)?;
Ok(leaves.to_vec())
}
ImplTrait(decl_id) => {
Expand Down
61 changes: 31 additions & 30 deletions sway-core/src/control_flow_analysis/dead_code_analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,25 +123,28 @@ impl ControlFlowGraph {
graph.entry_points = match tree_type {
TreeType::Predicate | TreeType::Script => {
// a predicate or script have a main function as the only entry point
vec![
graph
.graph
.node_indices()
.find(|i| match graph.graph[*i] {
ControlFlowGraphNode::OrganizationalDominator(_) => false,
ControlFlowGraphNode::ProgramNode(TypedAstNode {
content:
TypedAstNodeContent::Declaration(
TypedDeclaration::FunctionDeclaration(
TypedFunctionDeclaration { ref name, .. },
),
),
..
}) => name.as_str() == "main",
_ => false,
})
.unwrap(),
]
let mut ret = vec![];
for i in graph.graph.node_indices() {
let count_it = match &graph.graph[i] {
ControlFlowGraphNode::OrganizationalDominator(_) => false,
ControlFlowGraphNode::ProgramNode(TypedAstNode {
span,
content:
TypedAstNodeContent::Declaration(TypedDeclaration::FunctionDeclaration(
decl_id,
)),
..
}) => {
let decl = de_get_function(decl_id.clone(), span)?;
decl.name.as_str() == "main"
}
_ => false,
};
if count_it {
ret.push(i);
}
}
ret
}
TreeType::Contract | TreeType::Library { .. } => {
let mut ret = vec![];
Expand All @@ -151,13 +154,13 @@ impl ControlFlowGraph {
ControlFlowGraphNode::ProgramNode(TypedAstNode {
content:
TypedAstNodeContent::Declaration(TypedDeclaration::FunctionDeclaration(
TypedFunctionDeclaration {
visibility: Visibility::Public,
..
},
decl_id,
)),
..
}) => true,
}) => {
let function_decl = de_get_function(decl_id.clone(), &decl_id.span())?;
function_decl.visibility == Visibility::Public
}
ControlFlowGraphNode::ProgramNode(TypedAstNode {
content:
TypedAstNodeContent::Declaration(TypedDeclaration::TraitDeclaration(
Expand Down Expand Up @@ -354,8 +357,9 @@ fn connect_declaration(
value.span.clone(),
)
}
FunctionDeclaration(fn_decl) => {
connect_typed_fn_decl(fn_decl, graph, entry_node, span, exit_node, tree_type)?;
FunctionDeclaration(decl_id) => {
let fn_decl = de_get_function(decl_id.clone(), &decl.span())?;
connect_typed_fn_decl(&fn_decl, graph, entry_node, span, exit_node, tree_type)?;
Ok(leaves.to_vec())
}
TraitDeclaration(decl_id) => {
Expand Down Expand Up @@ -1251,10 +1255,7 @@ fn construct_dead_code_warning_from_node(node: &TypedAstNode) -> Option<CompileW
// if this is a function, struct, or trait declaration that is never called, then it is dead
// code.
TypedAstNode {
content:
TypedAstNodeContent::Declaration(TypedDeclaration::FunctionDeclaration(
TypedFunctionDeclaration { .. },
)),
content: TypedAstNodeContent::Declaration(TypedDeclaration::FunctionDeclaration(_)),
span,
..
} => CompileWarning {
Expand Down
2 changes: 1 addition & 1 deletion sway-core/src/declaration_engine/declaration_engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ pub(crate) fn de_insert_function(function: TypedFunctionDeclaration) -> Declarat
DECLARATION_ENGINE.insert_function(function)
}

pub(crate) fn de_get_function(
pub fn de_get_function(
index: DeclarationId,
span: &Span,
) -> Result<TypedFunctionDeclaration, CompileError> {
Expand Down
101 changes: 64 additions & 37 deletions sway-core/src/semantic_analysis/ast_node/declaration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use sway_types::{Ident, Span, Spanned};
pub enum TypedDeclaration {
VariableDeclaration(Box<TypedVariableDeclaration>),
ConstantDeclaration(DeclarationId),
FunctionDeclaration(TypedFunctionDeclaration),
FunctionDeclaration(DeclarationId),
TraitDeclaration(DeclarationId),
StructDeclaration(DeclarationId),
EnumDeclaration(DeclarationId),
Expand Down Expand Up @@ -72,7 +72,7 @@ impl Spanned for TypedDeclaration {
match self {
VariableDeclaration(decl) => decl.name.span(),
ConstantDeclaration(decl_id) => decl_id.span(),
FunctionDeclaration(TypedFunctionDeclaration { span, .. }) => span.clone(),
FunctionDeclaration(decl_id) => decl_id.span(),
TraitDeclaration(decl_id) => decl_id.span(),
StructDeclaration(decl_id) => decl_id.span(),
EnumDeclaration(decl_id) => decl_id.span(),
Expand Down Expand Up @@ -117,10 +117,11 @@ impl fmt::Display for TypedDeclaration {
builder.push_str(&body.to_string());
builder
}
TypedDeclaration::FunctionDeclaration(TypedFunctionDeclaration {
name, ..
}) => {
name.as_str().into()
TypedDeclaration::FunctionDeclaration(decl_id) => {
match de_get_function(decl_id.clone(), &decl_id.span()) {
Ok(TypedFunctionDeclaration { name, .. }) => name.as_str().into(),
Err(_) => "unknown function".into(),
}
}
TypedDeclaration::TraitDeclaration(decl_id) => {
match de_get_trait(decl_id.clone(), &decl_id.span()) {
Expand Down Expand Up @@ -168,40 +169,47 @@ impl CollectTypesMetadata for TypedDeclaration {
));
body
}
FunctionDeclaration(decl) => {
let mut body = vec![];
for content in decl.body.contents.iter() {
FunctionDeclaration(decl_id) => match de_get_function(decl_id.clone(), &decl_id.span())
{
Ok(decl) => {
let mut body = vec![];
for content in decl.body.contents.iter() {
body.append(&mut check!(
content.collect_types_metadata(),
return err(warnings, errors),
warnings,
errors
));
}
body.append(&mut check!(
content.collect_types_metadata(),
decl.return_type.collect_types_metadata(),
return err(warnings, errors),
warnings,
errors
));
for type_param in decl.type_parameters.iter() {
body.append(&mut check!(
type_param.type_id.collect_types_metadata(),
return err(warnings, errors),
warnings,
errors
));
}
for param in decl.parameters.iter() {
body.append(&mut check!(
param.type_id.collect_types_metadata(),
return err(warnings, errors),
warnings,
errors
));
}
body
}
body.append(&mut check!(
decl.return_type.collect_types_metadata(),
return err(warnings, errors),
warnings,
errors
));
for type_param in decl.type_parameters.iter() {
body.append(&mut check!(
type_param.type_id.collect_types_metadata(),
return err(warnings, errors),
warnings,
errors
));
Err(e) => {
errors.push(e);
return err(warnings, errors);
}
for param in decl.parameters.iter() {
body.append(&mut check!(
param.type_id.collect_types_metadata(),
return err(warnings, errors),
warnings,
errors
));
}
body
}
},
ConstantDeclaration(decl_id) => {
match de_get_constant(decl_id.clone(), &decl_id.span()) {
Ok(TypedConstantDeclaration { value, .. }) => {
Expand Down Expand Up @@ -286,11 +294,22 @@ impl TypedDeclaration {
/// Retrieves the declaration as a function declaration.
///
/// Returns an error if `self` is not a `TypedFunctionDeclaration`.
pub(crate) fn expect_function(&self) -> CompileResult<&TypedFunctionDeclaration> {
let warnings = vec![];
pub(crate) fn expect_function(
&self,
access_span: &Span,
) -> CompileResult<TypedFunctionDeclaration> {
let mut warnings = vec![];
let mut errors = vec![];
match self {
TypedDeclaration::FunctionDeclaration(decl) => ok(decl, warnings, errors),
TypedDeclaration::FunctionDeclaration(decl_id) => {
let decl = check!(
CompileResult::from(de_get_function(decl_id.clone(), access_span)),
return err(warnings, errors),
warnings,
errors,
);
ok(decl, warnings, errors)
}
decl => {
errors.push(CompileError::DeclIsNotAFunction {
actually: decl.friendly_name().to_string(),
Expand Down Expand Up @@ -452,13 +471,21 @@ impl TypedDeclaration {
);
visibility
}
FunctionDeclaration(decl_id) => {
let TypedFunctionDeclaration { visibility, .. } = check!(
CompileResult::from(de_get_function(decl_id.clone(), &decl_id.span())),
return err(warnings, errors),
warnings,
errors
);
visibility
}
GenericTypeForFunctionScope { .. }
| ImplTrait { .. }
| StorageDeclaration { .. }
| AbiDeclaration(..)
| ErrorRecovery => Visibility::Public,
VariableDeclaration(decl) => decl.mutability.visibility(),
FunctionDeclaration(TypedFunctionDeclaration { visibility, .. }) => *visibility,
};
ok(visibility, warnings, errors)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
mod function_parameter;
pub use function_parameter::*;

use crate::{error::*, parse_tree::*, semantic_analysis::*, style::*, type_system::*};
use crate::{
declaration_engine::declaration_engine::de_insert_function, error::*, parse_tree::*,
semantic_analysis::*, style::*, type_system::*,
};
use sha2::{Digest, Sha256};
use sway_types::{Ident, JsonABIFunction, JsonTypeApplication, JsonTypeDeclaration, Span, Spanned};

Expand All @@ -28,7 +31,7 @@ impl From<&TypedFunctionDeclaration> for TypedAstNode {
let span = o.span.clone();
TypedAstNode {
content: TypedAstNodeContent::Declaration(TypedDeclaration::FunctionDeclaration(
o.clone(),
de_insert_function(o.clone()),
)),
span,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -914,7 +914,7 @@ impl TypedExpression {
ctx: TypeCheckContext,
mut call_path_binding: TypeBinding<CallPath>,
arguments: Vec<Expression>,
_span: Span,
span: Span,
) -> CompileResult<TypedExpression> {
let mut warnings = vec![];
let mut errors = vec![];
Expand All @@ -929,7 +929,7 @@ impl TypedExpression {

// check that the decl is a function decl
let function_decl = check!(
unknown_decl.expect_function().cloned(),
unknown_decl.expect_function(&span),
return err(warnings, errors),
warnings,
errors
Expand Down Expand Up @@ -1487,7 +1487,7 @@ impl TypedExpression {
let maybe_function = {
let mut call_path_binding = call_path_binding.clone();
TypeBinding::type_check_with_ident(&mut call_path_binding, &ctx)
.flat_map(|unknown_decl| unknown_decl.expect_function().cloned())
.flat_map(|unknown_decl| unknown_decl.expect_function(&span))
.ok(&mut function_probe_warnings, &mut function_probe_errors)
};

Expand Down
26 changes: 18 additions & 8 deletions sway-core/src/semantic_analysis/ast_node/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,18 +134,27 @@ impl TypedAstNode {

/// Naive check to see if this node is a function declaration of a function called `main` if
/// the [TreeType] is Script or Predicate.
pub(crate) fn is_main_function(&self, tree_type: TreeType) -> bool {
pub(crate) fn is_main_function(&self, tree_type: TreeType) -> CompileResult<bool> {
let mut warnings = vec![];
let mut errors = vec![];
match &self {
TypedAstNode {
span,
content:
TypedAstNodeContent::Declaration(TypedDeclaration::FunctionDeclaration(
TypedFunctionDeclaration { name, .. },
)),
TypedAstNodeContent::Declaration(TypedDeclaration::FunctionDeclaration(decl_id)),
..
} if name.as_str() == crate::constants::DEFAULT_ENTRY_POINT_FN_NAME => {
matches!(tree_type, TreeType::Script | TreeType::Predicate)
} => {
let TypedFunctionDeclaration { name, .. } = check!(
CompileResult::from(de_get_function(decl_id.clone(), span)),
return err(warnings, errors),
warnings,
errors
);
let is_main = name.as_str() == crate::constants::DEFAULT_ENTRY_POINT_FN_NAME
&& matches!(tree_type, TreeType::Script | TreeType::Predicate);
ok(is_main, warnings, errors)
}
_ => false,
_ => ok(false, warnings, errors),
}
}

Expand Down Expand Up @@ -314,7 +323,8 @@ impl TypedAstNode {
);

let name = fn_decl.name.clone();
let decl = TypedDeclaration::FunctionDeclaration(fn_decl);
let decl =
TypedDeclaration::FunctionDeclaration(de_insert_function(fn_decl));
ctx.namespace.insert_symbol(name, decl.clone());
decl
}
Expand Down
Loading

0 comments on commit 9aeb723

Please sign in to comment.