Skip to content

Commit

Permalink
Allow using {func} for type to use library functions
Browse files Browse the repository at this point in the history
Fixes hyperledger-solang#1525

Signed-off-by: Sean Young <sean@mess.org>
  • Loading branch information
seanyoung committed Sep 21, 2023
1 parent c2d0fd8 commit 06a55dc
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 7 deletions.
5 changes: 3 additions & 2 deletions src/sema/contracts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,6 @@ impl ast::Contract {

/// Resolve the following contract
pub fn resolve(contracts: &[ContractDefinition], file_no: usize, ns: &mut ast::Namespace) {
resolve_using(contracts, file_no, ns);

// we need to resolve declarations first, so we call functions/constructors of
// contracts before they are declared
let mut delayed: ResolveLater = Default::default();
Expand All @@ -73,6 +71,9 @@ pub fn resolve(contracts: &[ContractDefinition], file_no: usize, ns: &mut ast::N
resolve_declarations(def, file_no, ns, &mut delayed);
}

// using may use functions declared in contracts
resolve_using(contracts, file_no, ns);

// Resolve base contract constructor arguments on contract definition (not constructor definitions)
resolve_base_args(contracts, file_no, ns);

Expand Down
6 changes: 4 additions & 2 deletions src/sema/expression/function_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1352,8 +1352,9 @@ pub(super) fn method_call_pos_args(
if let Some(mut path) = ns.expr_to_identifier_path(var) {
path.identifiers.push(func.clone());

if let Ok(list) = ns.resolve_free_function_with_namespace(
if let Ok(list) = ns.resolve_function_with_namespace(
context.file_no,
None,
&path,
&mut Diagnostics::default(),
) {
Expand Down Expand Up @@ -1640,8 +1641,9 @@ pub(super) fn method_call_named_args(
if let Some(mut path) = ns.expr_to_identifier_path(var) {
path.identifiers.push(func_name.clone());

if let Ok(list) = ns.resolve_free_function_with_namespace(
if let Ok(list) = ns.resolve_function_with_namespace(
context.file_no,
None,
&path,
&mut Diagnostics::default(),
) {
Expand Down
10 changes: 8 additions & 2 deletions src/sema/namespace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -364,9 +364,10 @@ impl Namespace {
}

/// Resolve a free function name with namespace
pub(super) fn resolve_free_function_with_namespace(
pub(super) fn resolve_function_with_namespace(
&mut self,
file_no: usize,
contract_no: Option<usize>,
name: &pt::IdentifierPath,
diagnostics: &mut Diagnostics,
) -> Result<Vec<(pt::Loc, usize)>, ()> {
Expand All @@ -376,7 +377,7 @@ impl Namespace {
.map(|(id, namespace)| (id, namespace.iter().collect()))
.unwrap();

let s = self.resolve_namespace(namespace, file_no, None, id, diagnostics)?;
let s = self.resolve_namespace(namespace, file_no, contract_no, id, diagnostics)?;

if let Some(Symbol::Function(list)) = s {
Ok(list.clone())
Expand Down Expand Up @@ -1335,6 +1336,7 @@ impl Namespace {
));
return Err(());
};
namespace.clear();
Some(*n)
}
Some(Symbol::Function(_)) => {
Expand Down Expand Up @@ -1390,6 +1392,10 @@ impl Namespace {
};
}

if !namespace.is_empty() {
return Ok(None);
}

let mut s = self
.variable_symbols
.get(&(import_file_no, contract_no, id.name.to_owned()))
Expand Down
15 changes: 14 additions & 1 deletion src/sema/using.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,9 @@ pub(crate) fn using_decl(

for using_function in functions {
let function_name = &using_function.path;
if let Ok(list) = ns.resolve_free_function_with_namespace(
if let Ok(list) = ns.resolve_function_with_namespace(
file_no,
contract_no,
&using_function.path,
&mut diagnostics,
) {
Expand All @@ -120,6 +121,18 @@ pub(crate) fn using_decl(

let func = &ns.functions[func_no];

if let Some(contract_no) = func.contract_no {
if !ns.contracts[contract_no].is_library() {
diagnostics.push(Diagnostic::error_with_note(
function_name.loc,
format!("'{function_name}' is not a library function"),
func.loc,
format!("definition of {}", using_function.path),
));
continue;
}
}

if func.params.is_empty() {
diagnostics.push(Diagnostic::error_with_note(
function_name.loc,
Expand Down
31 changes: 31 additions & 0 deletions tests/contract_testcases/solana/using_functions.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
contract C {
function foo(int256 a) internal pure returns (int256) {
return a;
}
}

library L {
function bar(int256 a) internal pure returns (int256) {
return a;
}
}

library Lib {
function baz(int256 a, bool b) internal pure returns (int256) {
if (b) {
return 1;
} else {
return a;
}
}
using {L.bar, baz} for int256;
}

library Lib2 {
using {L.foo.bar, C.foo} for int256;
}

// ---- Expect: diagnostics ----
// error: 25:15-18: 'foo' not found
// error: 25:20-25: 'C.foo' is not a library function
// note 2:2-55: definition of C.foo

0 comments on commit 06a55dc

Please sign in to comment.