Browse Source

Permit function list in using syntax

This is new syntax introduced with solc 0.8.13.

	function foo(int) {};
	function foo2(int) {};

	contract c {
		using {foo,foo2} for int;

		function test(int c) public {
			c.foo();
			c.foo2();
		}
	}

Signed-off-by: Sean Young <sean@mess.org>
Sean Young 3 years ago
parent
commit
2c138a10c5

+ 8 - 1
solang-parser/src/pt.rs

@@ -211,11 +211,18 @@ pub enum ContractPart {
     DocComment(DocComment),
 }
 
+#[derive(Debug, PartialEq, Clone)]
+pub enum UsingList {
+    Library(Expression),
+    Functions(Vec<Expression>),
+}
+
 #[derive(Debug, PartialEq, Clone)]
 pub struct Using {
     pub loc: Loc,
-    pub library: Expression,
+    pub list: UsingList,
     pub ty: Option<Expression>,
+    pub global: Option<Identifier>,
 }
 
 #[derive(Debug, PartialEq, Clone)]

+ 11 - 4
solang-parser/src/solidity.lalrpop

@@ -686,18 +686,25 @@ FunctionDefinition: Box<FunctionDefinition> = {
 }
 
 Using: Box<Using> = {
-    <l:@L> "using" <library:SolIdentifierNamespace> "for" <ty:Precedence0> <r:@R> ";" => Box::new(Using {
+    <l:@L> "using" <list:UsingList> "for" <ty:Precedence0> <global:SolIdentifier?> <r:@R> ";" => Box::new(Using {
         loc: Loc::File(file_no, l, r),
-        library,
+        list,
         ty: Some(ty),
+        global,
     }),
-    <l:@L> "using" <library:SolIdentifierNamespace> "for" "*" <r:@R> ";" => Box::new(Using {
+    <l:@L> "using" <list:UsingList> "for" "*" <global:SolIdentifier?> <r:@R> ";" => Box::new(Using {
         loc: Loc::File(file_no, l, r),
-        library,
+        list,
         ty: None,
+        global,
     }),
 }
 
+UsingList: UsingList = {
+    SolIdentifierNamespace => UsingList::Library(<>),
+    "{" <Comma<SolIdentifierNamespace>> "}" => UsingList::Functions(<>),
+}
+
 BlockStatement: Statement = {
     <l:@L> "{" <statements:Statement*> "}" <r:@R> => {
         Statement::Block { loc: Loc::File(file_no, l, r), unchecked: false, statements }

+ 6 - 1
src/sema/ast.rs

@@ -489,13 +489,18 @@ pub struct Base {
     pub constructor: Option<(usize, Vec<Expression>)>,
 }
 
+pub enum Using {
+    Library(usize),
+    Functions(Vec<usize>),
+}
+
 pub struct Contract {
     pub tags: Vec<Tag>,
     pub loc: pt::Loc,
     pub ty: pt::ContractTy,
     pub name: String,
     pub bases: Vec<Base>,
-    pub using: Vec<(usize, Option<Type>)>,
+    pub using: Vec<(Using, Option<Type>)>,
     pub layout: Vec<Layout>,
     pub fixed_layout_size: BigInt,
     pub functions: Vec<usize>,

+ 116 - 37
src/sema/contracts.rs

@@ -834,55 +834,134 @@ fn resolve_using(
     for (contract_no, def) in contracts {
         for part in &def.parts {
             if let pt::ContractPart::Using(using) = part {
-                if let Ok(library_no) =
-                    ns.resolve_contract_with_namespace(file_no, &using.library, &mut diagnostics)
-                {
-                    if !ns.contracts[library_no].is_library() {
-                        ns.diagnostics.push(ast::Diagnostic::error(
-                            using.library.loc(),
-                            format!(
-                                "library expected but {} '{}' found",
-                                ns.contracts[library_no].ty, using.library
-                            ),
-                        ));
-
-                        continue;
+                let ty = if let Some(expr) = &using.ty {
+                    let mut diagnostics = Vec::new();
+
+                    match ns.resolve_type(
+                        file_no,
+                        Some(*contract_no),
+                        false,
+                        expr,
+                        &mut diagnostics,
+                    ) {
+                        Ok(ast::Type::Contract(contract_no))
+                            if ns.contracts[contract_no].is_library() =>
+                        {
+                            ns.diagnostics.push(ast::Diagnostic::error(
+                                expr.loc(),
+                                format!("using for library '{}' type not permitted", expr),
+                            ));
+                            continue;
+                        }
+                        Ok(ty) => Some(ty),
+                        Err(_) => {
+                            ns.diagnostics.extend(diagnostics);
+                            continue;
+                        }
                     }
+                } else {
+                    None
+                };
 
-                    let ty = if let Some(expr) = &using.ty {
-                        let mut diagnostics = Vec::new();
-
-                        match ns.resolve_type(
-                            file_no,
-                            Some(*contract_no),
-                            false,
-                            expr,
-                            &mut diagnostics,
-                        ) {
-                            Ok(ast::Type::Contract(contract_no))
-                                if ns.contracts[contract_no].is_library() =>
-                            {
+                let list = match &using.list {
+                    pt::UsingList::Library(library) => {
+                        if let Ok(library_no) =
+                            ns.resolve_contract_with_namespace(file_no, library, &mut diagnostics)
+                        {
+                            if ns.contracts[library_no].is_library() {
+                                ast::Using::Library(library_no)
+                            } else {
                                 ns.diagnostics.push(ast::Diagnostic::error(
-                                    using.library.loc(),
+                                    library.loc(),
                                     format!(
-                                        "using library '{}' to extend library not possible",
-                                        using.library,
+                                        "library expected but {} '{}' found",
+                                        ns.contracts[library_no].ty, library
                                     ),
                                 ));
                                 continue;
                             }
-                            Ok(ty) => Some(ty),
-                            Err(_) => {
-                                ns.diagnostics.extend(diagnostics);
-                                continue;
+                        } else {
+                            continue;
+                        }
+                    }
+                    pt::UsingList::Functions(functions) => {
+                        let mut res = Vec::new();
+
+                        for function_name in functions {
+                            if let Ok(list) = ns.resolve_free_function_with_namespace(
+                                file_no,
+                                function_name,
+                                &mut diagnostics,
+                            ) {
+                                if list.len() > 1 {
+                                    let notes = list
+                                        .iter()
+                                        .map(|(loc, _)| ast::Note {
+                                            pos: *loc,
+                                            message: format!("definition of '{}'", function_name),
+                                        })
+                                        .collect();
+
+                                    diagnostics.push(ast::Diagnostic::error_with_notes(
+                                        function_name.loc(),
+                                        format!("'{}' is an overloaded function", function_name),
+                                        notes,
+                                    ));
+                                    continue;
+                                }
+
+                                let (loc, func_no) = list[0];
+
+                                let func = &ns.functions[func_no];
+
+                                if func.params.is_empty() {
+                                    diagnostics.push(ast::Diagnostic::error_with_note(
+                                        function_name.loc(),
+                                        format!(
+                                            "'{}' has no arguments, at least one argument required",
+                                            function_name
+                                        ),
+                                        loc,
+                                        format!("definition of '{}'", function_name),
+                                    ));
+                                    continue;
+                                }
+
+                                if let Some(ty) = &ty {
+                                    if *ty != func.params[0].ty {
+                                        diagnostics.push(ast::Diagnostic::error_with_note(
+                                            function_name.loc(),
+                                            format!("function cannot be used since first argument is '{}' rather than the required '{}'", func.params[0].ty.to_string(ns), ty.to_string(ns)),
+                                            loc,
+                                            format!("definition of '{}'", function_name),
+                                        ));
+                                        continue;
+                                    }
+                                }
+
+                                res.push(func_no);
                             }
                         }
-                    } else {
-                        None
-                    };
 
-                    ns.contracts[*contract_no].using.push((library_no, ty));
+                        ast::Using::Functions(res)
+                    }
+                };
+
+                if let Some(global) = &using.global {
+                    if global.name == "global" {
+                        ns.diagnostics.push(ast::Diagnostic::error(
+                            global.loc,
+                            format!("'{}' on using within contract not permitted", global.name),
+                        ));
+                    } else {
+                        ns.diagnostics.push(ast::Diagnostic::error(
+                            global.loc,
+                            format!("'{}' not expected", global.name),
+                        ));
+                    }
                 }
+
+                ns.contracts[*contract_no].using.push((list, ty));
             }
         }
     }

+ 24 - 22
src/sema/dotgraphviz.rs

@@ -2229,30 +2229,32 @@ impl Namespace {
                 dot.add_tags(&var.tags, node);
             }
 
-            for (library, ty) in &c.using {
+            for (libraries, ty) in &c.using {
+                let mut labels = match libraries {
+                    Using::Functions(functions) => functions
+                        .iter()
+                        .map(|func_no| {
+                            let func = &self.functions[*func_no];
+
+                            format!("function {} {}", func.name, self.loc_to_string(&func.loc))
+                        })
+                        .collect(),
+                    Using::Library(library_no) => {
+                        let library = &self.contracts[*library_no];
+
+                        vec![format!("library {}", library.name)]
+                    }
+                };
+
                 if let Some(ty) = ty {
-                    dot.add_node(
-                        Node::new(
-                            "using",
-                            vec![format!(
-                                "using {} for {}",
-                                self.contracts[*library].name,
-                                ty.to_string(self)
-                            )],
-                        ),
-                        Some(contract),
-                        Some(String::from("base")),
-                    );
-                } else {
-                    dot.add_node(
-                        Node::new(
-                            "using",
-                            vec![format!("using {}", self.contracts[*library].name)],
-                        ),
-                        Some(contract),
-                        Some(String::from("base")),
-                    );
+                    labels.insert(0, format!("using for {}", ty.to_string(self)));
                 }
+
+                dot.add_node(
+                    Node::new("using", labels),
+                    Some(contract),
+                    Some(String::from("base")),
+                );
             }
 
             for func in &c.functions {

+ 99 - 87
src/sema/expression.rs

@@ -15,7 +15,7 @@ use std::ops::{Add, Shl, Sub};
 use super::address::to_hexstr_eip55;
 use super::ast::{
     Builtin, BuiltinStruct, CallArgs, CallTy, Diagnostic, Expression, Function, Mutability,
-    Namespace, StringLocation, Symbol, Type,
+    Namespace, StringLocation, Symbol, Type, Using,
 };
 use super::builtin;
 use super::contracts::{is_base, visit_bases};
@@ -6326,118 +6326,130 @@ fn resolve_using(
     ns: &mut Namespace,
     resolve_to: ResolveTo,
 ) -> Result<Option<Expression>, ()> {
-    // first collect all possible libraries that match the using directive type
+    // first collect all possible functions that could be used for using
     // Use HashSet for deduplication.
     // If the using directive specifies a type, the type must match the type of
     // the method call object exactly.
-    let libraries: HashSet<usize> = ns.contracts[context.contract_no.unwrap()]
+    let possible_functions: HashSet<usize> = ns.contracts[context.contract_no.unwrap()]
         .using
         .iter()
-        .filter_map(|(library_no, ty)| match ty {
-            None => Some(*library_no),
-            Some(ty) if ty == self_ty => Some(*library_no),
-            _ => None,
+        .filter(|(_, ty)| {
+            if let Some(ty) = ty {
+                self_ty == ty
+            } else {
+                true
+            }
+        })
+        .flat_map(|(using, _)| {
+            match using {
+                Using::Library(library_no) => ns.contracts[*library_no].functions.iter(),
+                Using::Functions(functions) => functions.iter(),
+            }
+            .filter(|func_no| {
+                let libfunc = &ns.functions[**func_no];
+
+                libfunc.name == func.name && libfunc.ty == pt::FunctionTy::Function
+            })
+            .cloned()
         })
         .collect();
 
     let mut name_matches = 0;
     let mut errors = Vec::new();
 
-    for library_no in libraries {
-        for function_no in ns.contracts[library_no].functions.clone() {
-            let libfunc = &ns.functions[function_no];
-            if libfunc.name != func.name || libfunc.ty != pt::FunctionTy::Function {
-                continue;
-            }
+    for function_no in possible_functions {
+        let libfunc = &ns.functions[function_no];
+        if libfunc.name != func.name || libfunc.ty != pt::FunctionTy::Function {
+            continue;
+        }
 
-            name_matches += 1;
+        name_matches += 1;
 
-            let params_len = libfunc.params.len();
+        let params_len = libfunc.params.len();
 
-            if params_len != args.len() + 1 {
-                errors.push(Diagnostic::error(
-                    *loc,
-                    format!(
-                        "library function expects {} arguments, {} provided (including self)",
-                        params_len,
-                        args.len() + 1
-                    ),
-                ));
-                continue;
-            }
-            let mut matches = true;
-            let mut cast_args = Vec::new();
+        if params_len != args.len() + 1 {
+            errors.push(Diagnostic::error(
+                *loc,
+                format!(
+                    "using function expects {} arguments, {} provided (including self)",
+                    params_len,
+                    args.len() + 1
+                ),
+            ));
+            continue;
+        }
+        let mut matches = true;
+        let mut cast_args = Vec::new();
 
-            match self_expr.cast(
-                &self_expr.loc(),
-                &libfunc.params[0].ty,
-                true,
+        match self_expr.cast(
+            &self_expr.loc(),
+            &libfunc.params[0].ty,
+            true,
+            ns,
+            &mut errors,
+        ) {
+            Ok(e) => cast_args.push(e),
+            Err(()) => continue,
+        }
+
+        // check if arguments can be implicitly casted
+        for (i, arg) in args.iter().enumerate() {
+            let ty = ns.functions[function_no].params[i + 1].ty.clone();
+
+            let arg = match expression(
+                arg,
+                context,
                 ns,
+                symtable,
                 &mut errors,
+                ResolveTo::Type(&ty),
             ) {
-                Ok(e) => cast_args.push(e),
-                Err(()) => continue,
-            }
-
-            // check if arguments can be implicitly casted
-            for (i, arg) in args.iter().enumerate() {
-                let ty = ns.functions[function_no].params[i + 1].ty.clone();
-
-                let arg = match expression(
-                    arg,
-                    context,
-                    ns,
-                    symtable,
-                    &mut errors,
-                    ResolveTo::Type(&ty),
-                ) {
-                    Ok(e) => e,
-                    Err(()) => {
-                        matches = false;
-                        continue;
-                    }
-                };
+                Ok(e) => e,
+                Err(()) => {
+                    matches = false;
+                    continue;
+                }
+            };
 
-                match arg.cast(&arg.loc(), &ty, true, ns, &mut errors) {
-                    Ok(expr) => cast_args.push(expr),
-                    Err(_) => {
-                        matches = false;
-                        break;
-                    }
+            match arg.cast(&arg.loc(), &ty, true, ns, &mut errors) {
+                Ok(expr) => cast_args.push(expr),
+                Err(_) => {
+                    matches = false;
+                    break;
                 }
             }
-            if !matches {
-                continue;
-            }
+        }
+        if !matches {
+            continue;
+        }
 
-            let libfunc = &ns.functions[function_no];
+        let libfunc = &ns.functions[function_no];
 
-            if libfunc.is_private() {
-                errors.push(Diagnostic::error_with_note(
-                    *loc,
-                    "cannot call private library function".to_string(),
-                    libfunc.loc,
-                    format!("declaration of function '{}'", libfunc.name),
-                ));
+        if libfunc.is_private() {
+            errors.push(Diagnostic::error_with_note(
+                *loc,
+                "cannot call private library function".to_string(),
+                libfunc.loc,
+                format!("declaration of function '{}'", libfunc.name),
+            ));
 
-                continue;
-            }
+            continue;
+        }
 
-            let returns = function_returns(libfunc, resolve_to);
-            let ty = function_type(libfunc, false, resolve_to);
+        let returns = function_returns(libfunc, resolve_to);
+        let ty = function_type(libfunc, false, resolve_to);
 
-            return Ok(Some(Expression::InternalFunctionCall {
+        return Ok(Some(Expression::InternalFunctionCall {
+            loc: *loc,
+            returns,
+            function: Box::new(Expression::InternalFunction {
                 loc: *loc,
-                returns,
-                function: Box::new(Expression::InternalFunction {
-                    loc: *loc,
-                    ty,
-                    function_no,
-                    signature: None,
-                }),
-                args: cast_args,
-            }));
-        }
+                ty,
+                function_no,
+                signature: None,
+            }),
+            args: cast_args,
+        }));
     }
 
     match name_matches {
@@ -6450,7 +6462,7 @@ fn resolve_using(
         _ => {
             diagnostics.push(Diagnostic::error(
                 *loc,
-                "cannot find overloaded library function which matches signature".to_string(),
+                "cannot find overloaded function which matches signature".to_string(),
             ));
             Err(())
         }

+ 41 - 0
src/sema/namespace.rs

@@ -345,6 +345,47 @@ impl Namespace {
         }
     }
 
+    /// Resolve a free function name with namespace
+    pub fn resolve_free_function_with_namespace(
+        &mut self,
+        file_no: usize,
+        expr: &pt::Expression,
+        diagnostics: &mut Vec<Diagnostic>,
+    ) -> Result<Vec<(pt::Loc, usize)>, ()> {
+        let (namespace, id, dimensions) = self.expr_to_type(file_no, None, expr, diagnostics)?;
+
+        if !dimensions.is_empty() {
+            diagnostics.push(Diagnostic::decl_error(
+                expr.loc(),
+                "array type found where function expected".to_string(),
+            ));
+            return Err(());
+        }
+
+        let id = match id {
+            pt::Expression::Variable(id) => id,
+            _ => {
+                diagnostics.push(Diagnostic::decl_error(
+                    expr.loc(),
+                    "expression found where function expected".to_string(),
+                ));
+                return Err(());
+            }
+        };
+
+        let s = self.resolve_namespace(namespace, file_no, None, &id, diagnostics)?;
+
+        if let Some(Symbol::Function(list)) = s {
+            Ok(list.clone())
+        } else {
+            let error = Namespace::wrong_symbol(s, &id);
+
+            diagnostics.push(error);
+
+            Err(())
+        }
+    }
+
     /// Resolve an event. We should only be resolving events for emit statements
     pub fn resolve_event(
         &mut self,

+ 2 - 2
tests/contract_testcases/ewasm/comment_tests.dot

@@ -384,8 +384,8 @@ strict digraph "tests/contract_testcases/ewasm/comment_tests.sol" {
 	var_384 [label="variable _symbol\nvisibility private\ntests/contract_testcases/ewasm/comment_tests.sol:412:5-27"]
 	var_385 [label="variable _name\nvisibility private\ntests/contract_testcases/ewasm/comment_tests.sol:413:5-25"]
 	var_386 [label="variable damada\nvisibility private\ntests/contract_testcases/ewasm/comment_tests.sol:522:5-27"]
-	using [label="using SafeMath for uint256"]
-	using_388 [label="using Address for address"]
+	using [label="using for uint256\nlibrary SafeMath"]
+	using_388 [label="using for address\nlibrary Address"]
 	node_389 [label="constructor \ncontract: TigerBNB\ntests/contract_testcases/ewasm/comment_tests.sol:415:9-417:11\nsignature ()\nvisibility public\nmutability nonpayable"]
 	expr_390 [label="expression\ntests/contract_testcases/ewasm/comment_tests.sol:419:14-47"]
 	assign_391 [label="assign\naddress storage\ntests/contract_testcases/ewasm/comment_tests.sol:419:14-20"]

+ 1 - 1
tests/contract_testcases/solana/doccomments_everywhere.dot

@@ -126,7 +126,7 @@ strict digraph "tests/contract_testcases/solana/doccomments_everywhere.sol" {
 	sellShares [label="function sellShares\ncontract: Property\ntests/contract_testcases/solana/doccomments_everywhere.sol:77:3-59\nsignature sellShares(uint256,uint256)\nvisibility public\nmutability nonpayable"]
 	parameters_128 [label="parameters\nuint256 shares_\nuint256 _id"]
 	diagnostic [label="pragma 'solidity' is ignored\nlevel Debug\ntests/contract_testcases/solana/doccomments_everywhere.sol:1:1-24"]
-	diagnostic_131 [label="'Counters' not found\nlevel Error\ntests/contract_testcases/solana/doccomments_everywhere.sol:6:9-17"]
+	diagnostic_131 [label="'Counters' not found\nlevel Error\ntests/contract_testcases/solana/doccomments_everywhere.sol:6:22-30"]
 	diagnostic_132 [label="found contract 'Property'\nlevel Debug\ntests/contract_testcases/solana/doccomments_everywhere.sol:4:107-5:19"]
 	diagnostic_133 [label="'Counters' not found\nlevel Error\ntests/contract_testcases/solana/doccomments_everywhere.sol:7:3-11"]
 	diagnostic_134 [label="'ERC1155' not found\nlevel Error\ntests/contract_testcases/solana/doccomments_everywhere.sol:17:17-24"]

+ 1 - 1
tests/contract_testcases/solana/import_contracts_via_object.dot

@@ -1,7 +1,7 @@
 strict digraph "tests/contract_testcases/solana/import_contracts_via_object.sol" {
 	contract [label="contract C\ntests/contract_testcases/solana/import_contracts_via_object.sol:2:1-3:20"]
 	base [label="base A\ntests/contract_testcases/solana/import_contracts_via_object.sol:3:15-20"]
-	using [label="using L"]
+	using [label="library L"]
 	node_5 [label="constructor \ncontract: C\ntests/contract_testcases/solana/import_contracts_via_object.sol:5:2-23\nsignature ()\nvisibility public\nmutability nonpayable"]
 	contract_6 [label="contract A\ntests/contract_testcases/solana/simple.sol:1:1-12"]
 	contract_7 [label="contract L\ntests/contract_testcases/solana/simple.sol:1:14-2:11"]

+ 36 - 0
tests/contract_testcases/solana/using_list.dot

@@ -0,0 +1,36 @@
+strict digraph "tests/contract_testcases/solana/using_list.sol" {
+	contract [label="contract C\ntests/contract_testcases/solana/using_list.sol:8:1-9:12"]
+	using [label="using for uint256\nfunction id tests/contract_testcases/solana/using_list.sol:1:1-40\nfunction zero tests/contract_testcases/solana/using_list.sol:4:1-5:40"]
+	f [label="function f\ncontract: C\ntests/contract_testcases/solana/using_list.sol:10:5-51\nsignature f(uint256)\nvisibility external\nmutability pure"]
+	parameters [label="parameters\nuint256 z"]
+	returns [label="returns\nuint256 "]
+	return [label="return\ntests/contract_testcases/solana/using_list.sol:11:9-22"]
+	call_internal_function [label="call internal function\ntests/contract_testcases/solana/using_list.sol:11:16-22"]
+	internal_function [label="function(uint256) internal pure returns (uint256)\nfree function id\ntests/contract_testcases/solana/using_list.sol:11:16-22"]
+	variable [label="variable: z\nuint256\ntests/contract_testcases/solana/using_list.sol:11:16-17"]
+	g [label="function g\ncontract: C\ntests/contract_testcases/solana/using_list.sol:14:5-52\nsignature g(uint256)\nvisibility external\nmutability pure"]
+	parameters_12 [label="parameters\nuint256 z"]
+	returns_13 [label="returns\nuint256 "]
+	return_14 [label="return\ntests/contract_testcases/solana/using_list.sol:15:9-24"]
+	call_internal_function_15 [label="call internal function\ntests/contract_testcases/solana/using_list.sol:15:16-24"]
+	internal_function_16 [label="function(uint256) internal pure returns (uint256)\nfree function zero\ntests/contract_testcases/solana/using_list.sol:15:16-24"]
+	variable_17 [label="variable: z\nuint256\ntests/contract_testcases/solana/using_list.sol:15:16-17"]
+	diagnostic [label="found contract 'C'\nlevel Debug\ntests/contract_testcases/solana/using_list.sol:8:1-9:12"]
+	contracts -> contract
+	contract -> using [label="base"]
+	contract -> f [label="function"]
+	f -> parameters [label="parameters"]
+	f -> returns [label="returns"]
+	f -> return [label="body"]
+	return -> call_internal_function [label="expr"]
+	call_internal_function -> internal_function [label="function"]
+	call_internal_function -> variable [label="arg #0"]
+	contract -> g [label="function"]
+	g -> parameters_12 [label="parameters"]
+	g -> returns_13 [label="returns"]
+	g -> return_14 [label="body"]
+	return_14 -> call_internal_function_15 [label="expr"]
+	call_internal_function_15 -> internal_function_16 [label="function"]
+	call_internal_function_15 -> variable_17 [label="arg #0"]
+	diagnostics -> diagnostic [label="Debug"]
+}

+ 20 - 0
tests/contract_testcases/solana/using_list.sol

@@ -0,0 +1,20 @@
+function id(uint x) pure returns (uint) {
+    return x;
+}
+
+function zero(uint) pure returns (uint) {
+    return 0;
+}
+
+contract C {
+    function f(uint z) pure external returns(uint) {
+        return z.id();
+    }
+
+    function g(uint z) pure external returns (uint) {
+        return z.zero();
+    }
+
+    using {id, zero} for uint;
+}
+

+ 1 - 1
tests/contract_testcases/substrate/libraries/using.dot

@@ -1,6 +1,6 @@
 strict digraph "tests/contract_testcases/substrate/libraries/using.sol" {
 	contract [label="contract c\ntests/contract_testcases/substrate/libraries/using.sol:2:9-20"]
-	diagnostic [label="'x' not found\nlevel Error\ntests/contract_testcases/substrate/libraries/using.sol:3:19-20"]
+	diagnostic [label="type 'x' not found\nlevel Error\ntests/contract_testcases/substrate/libraries/using.sol:3:25-26"]
 	diagnostic_5 [label="found contract 'c'\nlevel Debug\ntests/contract_testcases/substrate/libraries/using.sol:2:9-20"]
 	contracts -> contract
 	diagnostics -> diagnostic [label="Error"]

+ 1 - 1
tests/contract_testcases/substrate/libraries/using_03.dot

@@ -11,7 +11,7 @@ strict digraph "tests/contract_testcases/substrate/libraries/using_03.sol" {
 	variable_10 [label="variable: a\nuint64\ntests/contract_testcases/substrate/libraries/using_03.sol:4:32-33"]
 	variable_11 [label="variable: b\nuint64\ntests/contract_testcases/substrate/libraries/using_03.sol:4:36-37"]
 	contract_12 [label="contract c\ntests/contract_testcases/substrate/libraries/using_03.sol:8:9-20"]
-	diagnostic [label="using library 'x' to extend library not possible\nlevel Error\ntests/contract_testcases/substrate/libraries/using_03.sol:9:19-20"]
+	diagnostic [label="using for library 'x' type not permitted\nlevel Error\ntests/contract_testcases/substrate/libraries/using_03.sol:9:25-26"]
 	diagnostic_15 [label="found library 'x'\nlevel Debug\ntests/contract_testcases/substrate/libraries/using_03.sol:2:9-19"]
 	diagnostic_16 [label="found contract 'c'\nlevel Debug\ntests/contract_testcases/substrate/libraries/using_03.sol:8:9-20"]
 	contracts -> contract

+ 1 - 1
tests/contract_testcases/substrate/libraries/using_04.dot

@@ -1,6 +1,6 @@
 strict digraph "tests/contract_testcases/substrate/libraries/using_04.sol" {
 	contract [label="contract test\ntests/contract_testcases/substrate/libraries/using_04.sol:2:9-23"]
-	using [label="using ints for uint64"]
+	using [label="using for uint64\nlibrary ints"]
 	foo [label="function foo\ncontract: test\ntests/contract_testcases/substrate/libraries/using_04.sol:4:13-64\nsignature foo(uint32)\nvisibility public\nmutability pure"]
 	parameters [label="parameters\nuint32 x"]
 	returns [label="returns\nuint64 "]

+ 2 - 2
tests/contract_testcases/substrate/libraries/using_05.dot

@@ -1,6 +1,6 @@
 strict digraph "tests/contract_testcases/substrate/libraries/using_05.sol" {
 	contract [label="contract test\ntests/contract_testcases/substrate/libraries/using_05.sol:2:9-23"]
-	using [label="using ints for uint32"]
+	using [label="using for uint32\nlibrary ints"]
 	foo [label="function foo\ncontract: test\ntests/contract_testcases/substrate/libraries/using_05.sol:4:13-64\nsignature foo(uint32)\nvisibility public\nmutability pure"]
 	parameters [label="parameters\nuint32 x"]
 	returns [label="returns\nuint64 "]
@@ -17,7 +17,7 @@ strict digraph "tests/contract_testcases/substrate/libraries/using_05.sol" {
 	variable_16 [label="variable: b\nuint64\ntests/contract_testcases/substrate/libraries/using_05.sol:12:36-37"]
 	diagnostic [label="found contract 'test'\nlevel Debug\ntests/contract_testcases/substrate/libraries/using_05.sol:2:9-23"]
 	diagnostic_19 [label="found library 'ints'\nlevel Debug\ntests/contract_testcases/substrate/libraries/using_05.sol:10:9-22"]
-	diagnostic_20 [label="library function expects 2 arguments, 3 provided (including self)\nlevel Error\ntests/contract_testcases/substrate/libraries/using_05.sol:6:24-39"]
+	diagnostic_20 [label="using function expects 2 arguments, 3 provided (including self)\nlevel Error\ntests/contract_testcases/substrate/libraries/using_05.sol:6:24-39"]
 	contracts -> contract
 	contract -> using [label="base"]
 	contract -> foo [label="function"]

+ 2 - 2
tests/contract_testcases/substrate/libraries/using_06.dot

@@ -1,6 +1,6 @@
 strict digraph "tests/contract_testcases/substrate/libraries/using_06.sol" {
 	contract [label="contract test\ntests/contract_testcases/substrate/libraries/using_06.sol:2:9-23"]
-	using [label="using ints for uint32"]
+	using [label="using for uint32\nlibrary ints"]
 	foo [label="function foo\ncontract: test\ntests/contract_testcases/substrate/libraries/using_06.sol:4:13-64\nsignature foo(uint32)\nvisibility public\nmutability pure"]
 	parameters [label="parameters\nuint32 x"]
 	returns [label="returns\nuint64 "]
@@ -24,7 +24,7 @@ strict digraph "tests/contract_testcases/substrate/libraries/using_06.sol" {
 	variable_23 [label="variable: a\nuint64\ntests/contract_testcases/substrate/libraries/using_06.sol:17:24-25"]
 	diagnostic [label="found contract 'test'\nlevel Debug\ntests/contract_testcases/substrate/libraries/using_06.sol:2:9-23"]
 	diagnostic_26 [label="found library 'ints'\nlevel Debug\ntests/contract_testcases/substrate/libraries/using_06.sol:10:9-22"]
-	diagnostic_27 [label="cannot find overloaded library function which matches signature\nlevel Error\ntests/contract_testcases/substrate/libraries/using_06.sol:6:24-39"]
+	diagnostic_27 [label="cannot find overloaded function which matches signature\nlevel Error\ntests/contract_testcases/substrate/libraries/using_06.sol:6:24-39"]
 	contracts -> contract
 	contract -> using [label="base"]
 	contract -> foo [label="function"]

+ 53 - 0
tests/contract_testcases/substrate/libraries/using_07.dot

@@ -0,0 +1,53 @@
+strict digraph "tests/contract_testcases/substrate/libraries/using_07.sol" {
+	contract [label="contract C\ntests/contract_testcases/substrate/libraries/using_07.sol:10:1-11:12"]
+	using [label="using for int256"]
+	using_4 [label="using for uint256"]
+	using_5 [label="using for int256\nfunction foo3 tests/contract_testcases/substrate/libraries/using_07.sol:3:23-4:35\nfunction foo4 tests/contract_testcases/substrate/libraries/using_07.sol:6:2-7:42"]
+	test [label="function test\ncontract: C\ntests/contract_testcases/substrate/libraries/using_07.sol:17:2-29\nsignature test(int256)\nvisibility public\nmutability nonpayable"]
+	parameters [label="parameters\nint256 c"]
+	var_decl [label="variable decl int256 a\ntests/contract_testcases/substrate/libraries/using_07.sol:18:3-19"]
+	call_internal_function [label="call internal function\ntests/contract_testcases/substrate/libraries/using_07.sol:18:11-19"]
+	internal_function [label="function(int256) internal returns (int256)\nfree function foo3\ntests/contract_testcases/substrate/libraries/using_07.sol:18:11-19"]
+	variable [label="variable: c\nint256\ntests/contract_testcases/substrate/libraries/using_07.sol:18:11-12"]
+	expr [label="expression\ntests/contract_testcases/substrate/libraries/using_07.sol:20:3-12"]
+	call_internal_function_13 [label="call internal function\ntests/contract_testcases/substrate/libraries/using_07.sol:20:3-12"]
+	internal_function_14 [label="function(int256,int256) internal returns (void)\nfree function foo4\ntests/contract_testcases/substrate/libraries/using_07.sol:20:3-12"]
+	variable_15 [label="variable: a\nint256\ntests/contract_testcases/substrate/libraries/using_07.sol:20:3-4"]
+	number_literal [label="int256 literal: 1\ntests/contract_testcases/substrate/libraries/using_07.sol:20:10-11"]
+	diagnostic [label="'global' on using within contract not permitted\nlevel Error\ntests/contract_testcases/substrate/libraries/using_07.sol:12:23-29"]
+	diagnostic_19 [label="'feh' not expected\nlevel Error\ntests/contract_testcases/substrate/libraries/using_07.sol:13:21-24"]
+	diagnostic_20 [label="'foo1' has no arguments, at least one argument required\nlevel Error\ntests/contract_testcases/substrate/libraries/using_07.sol:12:9-13"]
+	note [label="definition of 'foo1'\ntests/contract_testcases/substrate/libraries/using_07.sol:1:10-14"]
+	diagnostic_22 [label="'foo2' is an overloaded function\nlevel Error\ntests/contract_testcases/substrate/libraries/using_07.sol:13:9-13"]
+	note_23 [label="definition of 'foo2'\ntests/contract_testcases/substrate/libraries/using_07.sol:2:10-14"]
+	note_24 [label="definition of 'foo2'\ntests/contract_testcases/substrate/libraries/using_07.sol:2:22-3:21"]
+	diagnostic_25 [label="function cannot be used since first argument is 'int256' rather than the required 'uint256'\nlevel Error\ntests/contract_testcases/substrate/libraries/using_07.sol:14:9-13"]
+	note_26 [label="definition of 'foo3'\ntests/contract_testcases/substrate/libraries/using_07.sol:4:10-14"]
+	diagnostic_27 [label="found contract 'C'\nlevel Debug\ntests/contract_testcases/substrate/libraries/using_07.sol:10:1-11:12"]
+	contracts -> contract
+	contract -> using [label="base"]
+	contract -> using_3 [label="base"]
+	contract -> using_4 [label="base"]
+	contract -> using_5 [label="base"]
+	contract -> test [label="function"]
+	test -> parameters [label="parameters"]
+	test -> var_decl [label="body"]
+	var_decl -> call_internal_function [label="init"]
+	call_internal_function -> internal_function [label="function"]
+	call_internal_function -> variable [label="arg #0"]
+	var_decl -> expr [label="next"]
+	expr -> call_internal_function_13 [label="expr"]
+	call_internal_function_13 -> internal_function_14 [label="function"]
+	call_internal_function_13 -> variable_15 [label="arg #0"]
+	call_internal_function_13 -> number_literal [label="arg #1"]
+	diagnostics -> diagnostic [label="Error"]
+	diagnostics -> diagnostic_19 [label="Error"]
+	diagnostics -> diagnostic_20 [label="Error"]
+	diagnostic_20 -> note [label="note"]
+	diagnostics -> diagnostic_22 [label="Error"]
+	diagnostic_22 -> note_23 [label="note"]
+	diagnostic_22 -> note_24 [label="note"]
+	diagnostics -> diagnostic_25 [label="Error"]
+	diagnostic_25 -> note_26 [label="note"]
+	diagnostics -> diagnostic_27 [label="Debug"]
+}

+ 22 - 0
tests/contract_testcases/substrate/libraries/using_07.sol

@@ -0,0 +1,22 @@
+function foo1() {}
+function foo2(int) {}
+function foo2(uint) {}
+function foo3(int v) returns (int) {
+	return v * 3;
+}
+function foo4(int v, int b) returns (int) {
+	return v * 3 + b;
+}
+
+contract C {
+	using {foo1} for int global;
+	using {foo2} for * feh;
+	using {foo3} for uint;
+	using {foo3, foo4} for int;
+
+	function test(int c) public {
+		int a = c.foo3();
+
+		a.foo4(1);
+	}
+}