Skip to content

Commit

Permalink
Fix DCA for generic functions.
Browse files Browse the repository at this point in the history
Closes #3671.
  • Loading branch information
tritao committed Feb 6, 2023
1 parent 25245c3 commit d0b6de5
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 23 deletions.
6 changes: 2 additions & 4 deletions sway-core/src/control_flow_analysis/analyze_return_paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ impl<'cfg> ControlFlowGraph<'cfg> {
pub(crate) fn analyze_return_paths(&self, engines: Engines<'_>) -> Vec<CompileError> {
let mut errors = vec![];
for (
name,
(name, _sig),
FunctionNamespaceEntry {
entry_point,
exit_point,
Expand Down Expand Up @@ -305,9 +305,7 @@ fn connect_typed_fn_decl<'eng: 'cfg, 'cfg>(
.to_typeinfo(fn_decl.return_type, &fn_decl.return_type_span)
.unwrap_or_else(|_| TypeInfo::Tuple(Vec::new())),
};
graph
.namespace
.insert_function(fn_decl.name.clone(), namespace_entry);
graph.namespace.insert_function(fn_decl, namespace_entry);
Ok(())
}

Expand Down
54 changes: 42 additions & 12 deletions sway-core/src/control_flow_analysis/dead_code_analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,7 @@ impl<'cfg> ControlFlowGraph<'cfg> {
&leaves,
exit_node,
tree_type,
NodeConnectionOptions {
force_struct_fields_connection: false,
},
NodeConnectionOptions::default(),
)?;

leaves = l_leaves;
Expand Down Expand Up @@ -188,7 +186,7 @@ fn collect_entry_points(

/// This struct is used to pass node connection further down the tree as
/// we are processing AST nodes.
#[derive(Clone, Copy)]
#[derive(Clone, Copy, Default)]
struct NodeConnectionOptions {
/// When this is enabled, connect struct fields to the struct itself,
/// thus making all struct fields considered as being used in the graph.
Expand Down Expand Up @@ -689,9 +687,7 @@ fn connect_typed_fn_decl<'eng: 'cfg, 'cfg>(
return_type: ty,
};

graph
.namespace
.insert_function(fn_decl.name.clone(), namespace_entry);
graph.namespace.insert_function(fn_decl, namespace_entry);

connect_fn_params_struct_enums(engines, fn_decl, graph, entry_node)?;
Ok(())
Expand Down Expand Up @@ -827,11 +823,45 @@ fn connect_expression<'eng: 'cfg, 'cfg>(
} => {
let fn_decl = decl_engine.get_function(function_decl_id.clone(), &expression_span)?;
let mut is_external = false;

// in the case of monomorphized functions, first check if we already have a node for
// it in the namespace. if not then we need to check to see if the namespace contains
// the decl id parents (the original generic non monomorphized decl id).
let mut exists = false;
let parents = decl_engine.find_all_parents(engines, function_decl_id.clone());
for parent in parents {
if let Ok(parent) = decl_engine.get_function(parent.clone(), &expression_span) {
exists |= graph.namespace.get_function(&parent).is_some();
}
}

// find the function in the namespace
let (fn_entrypoint, fn_exit_point) = graph
.namespace
.get_function(&fn_decl.name)
.cloned()
let fn_namespace_entry = graph.namespace.get_function(&fn_decl).cloned();

let mut leaves = leaves.to_vec();

// if the parent node exists in this module, then add the monomorphized version
// to the graph.
if fn_namespace_entry.is_none() && exists {
let (l_leaves, _new_exit_node) = connect_node(
engines,
&ty::TyAstNode {
content: ty::TyAstNodeContent::Declaration(
ty::TyDeclaration::FunctionDeclaration(function_decl_id.clone()),
),
span: expression_span.clone(),
},
graph,
&leaves,
exit_node,
tree_type,
NodeConnectionOptions::default(),
)?;

leaves = l_leaves;
}

let (fn_entrypoint, fn_exit_point) = fn_namespace_entry
.map(
|FunctionNamespaceEntry {
entry_point,
Expand Down Expand Up @@ -863,7 +893,7 @@ fn connect_expression<'eng: 'cfg, 'cfg>(
}

for leaf in leaves {
graph.add_edge(*leaf, fn_entrypoint, label.into());
graph.add_edge(leaf, fn_entrypoint, label.into());
}

// save the existing options value to restore after handling the arguments
Expand Down
27 changes: 20 additions & 7 deletions sway-core/src/control_flow_analysis/flow_graph/namespace.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use super::{EntryPoint, ExitPoint};
use crate::{
language::{ty, CallPath},
language::{
ty::{self, TyFunctionDeclaration, TyFunctionSig},
CallPath,
},
type_system::TypeInfo,
Ident,
};
Expand Down Expand Up @@ -32,7 +35,7 @@ pub(crate) struct StructNamespaceEntry {
/// of scope at this point, as that would have been caught earlier and aborted the compilation
/// process.
pub struct ControlFlowNamespace {
pub(crate) function_namespace: HashMap<IdentUnique, FunctionNamespaceEntry>,
pub(crate) function_namespace: HashMap<(IdentUnique, TyFunctionSig), FunctionNamespaceEntry>,
pub(crate) enum_namespace: HashMap<IdentUnique, (NodeIndex, HashMap<Ident, NodeIndex>)>,
pub(crate) trait_namespace: HashMap<CallPath, NodeIndex>,
/// This is a mapping from trait name to method names and their node indexes
Expand All @@ -45,13 +48,23 @@ pub struct ControlFlowNamespace {
}

impl ControlFlowNamespace {
pub(crate) fn get_function(&self, ident: &Ident) -> Option<&FunctionNamespaceEntry> {
let ident: IdentUnique = ident.into();
self.function_namespace.get(&ident)
pub(crate) fn get_function(
&self,
fn_decl: &TyFunctionDeclaration,
) -> Option<&FunctionNamespaceEntry> {
let ident: IdentUnique = fn_decl.name.clone().into();
self.function_namespace
.get(&(ident, TyFunctionSig::from_fn_decl(fn_decl)))
}
pub(crate) fn insert_function(&mut self, ident: Ident, entry: FunctionNamespaceEntry) {
pub(crate) fn insert_function(
&mut self,
fn_decl: &ty::TyFunctionDeclaration,
entry: FunctionNamespaceEntry,
) {
let ident = &fn_decl.name;
let ident: IdentUnique = ident.into();
self.function_namespace.insert(ident, entry);
self.function_namespace
.insert((ident, TyFunctionSig::from_fn_decl(fn_decl)), entry);
}
pub(crate) fn get_constant(&self, ident: &Ident) -> Option<&NodeIndex> {
self.const_namespace.get(ident)
Expand Down
19 changes: 19 additions & 0 deletions sway-core/src/language/ty/declaration/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -372,3 +372,22 @@ impl TyFunctionParameter {
self.name.as_str() == "self"
}
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct TyFunctionSig {
pub return_type: TypeId,
pub parameters: Vec<TypeId>,
}

impl TyFunctionSig {
pub fn from_fn_decl(fn_decl: &TyFunctionDeclaration) -> Self {
Self {
return_type: fn_decl.return_type,
parameters: fn_decl
.parameters
.iter()
.map(|p| p.type_id)
.collect::<Vec<_>>(),
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[[package]]
name = 'impl_trait_single'
source = 'member'
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[project]
authors = ["Fuel Labs <contact@fuel.sh>"]
entry = "main.sw"
license = "Apache-2.0"
name = "impl_trait_single"
implicit-std = false
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
script;

pub trait MyEq {
fn my_eq(self, other: Self);
}

impl MyEq for u64 {
fn my_eq(self, other: Self) {
}
}

fn test_my_eq<T>(x: T, y: T) where T: MyEq {
x.my_eq(y)
}

fn main() {
test_my_eq(42, 42);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
category = "compile"

# not: $()This declaration is never used

# not: $()This trait is never implemented

0 comments on commit d0b6de5

Please sign in to comment.