mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Contract level checker: Disallow free function redefinition and alias
shadowing another free function Co-authored-by: chriseth <chris@ethereum.org>
This commit is contained in:
parent
1cc0d642e8
commit
e2a2276272
@ -1,5 +1,8 @@
|
||||
### 0.7.2 (unreleased)
|
||||
|
||||
Important Bugfixes:
|
||||
* Type Checker: Disallow two or more free functions with identical name (potentially imported and aliased) and parameter types.
|
||||
|
||||
Language Features:
|
||||
|
||||
|
||||
|
@ -1,4 +1,12 @@
|
||||
[
|
||||
{
|
||||
"name": "FreeFunctionRedefinition",
|
||||
"summary": "The compiler does not flag an error when two or more free functions with the same name and parameter types are defined in a source unit or when an imported free function alias shadows another free function with a different name but identical parameter types.",
|
||||
"description": "In contrast to functions defined inside contracts, free functions with identical names and parameter types did not create an error. Both definition of free functions with identical name and parameter types and an imported free function with an alias that shadows another function with a different name but identical parameter types were permitted due to which a call to either the multiply defined free function or the imported free function alias within a contract led to the execution of that free function which was defined first within the source unit. Subsequently defined identical free function definitions were silently ignored and their code generation was skipped.",
|
||||
"introduced": "0.7.1",
|
||||
"fixed": "0.7.2",
|
||||
"severity": "low"
|
||||
},
|
||||
{
|
||||
"name": "UsingForCalldata",
|
||||
"summary": "Function calls to internal library functions with calldata parameters called via ``using for`` can result in invalid data being read.",
|
||||
|
@ -1187,7 +1187,9 @@
|
||||
"released": "2020-07-28"
|
||||
},
|
||||
"0.7.1": {
|
||||
"bugs": [],
|
||||
"bugs": [
|
||||
"FreeFunctionRedefinition"
|
||||
],
|
||||
"released": "2020-09-02"
|
||||
}
|
||||
}
|
@ -38,15 +38,45 @@ namespace
|
||||
{
|
||||
|
||||
template <class T, class B>
|
||||
bool hasEqualNameAndParameters(T const& _a, B const& _b)
|
||||
bool hasEqualParameters(T const& _a, B const& _b)
|
||||
{
|
||||
return
|
||||
_a.name() == _b.name() &&
|
||||
FunctionType(_a).asExternallyCallableFunction(false)->hasEqualParameterTypes(
|
||||
*FunctionType(_b).asExternallyCallableFunction(false)
|
||||
);
|
||||
return FunctionType(_a).asExternallyCallableFunction(false)->hasEqualParameterTypes(
|
||||
*FunctionType(_b).asExternallyCallableFunction(false)
|
||||
);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
map<ASTString, vector<T const*>> filterDeclarations(
|
||||
map<ASTString, vector<Declaration const*>> const& _declarations)
|
||||
{
|
||||
map<ASTString, vector<T const*>> filteredDeclarations;
|
||||
for (auto const& [name, overloads]: _declarations)
|
||||
for (auto const* declaration: overloads)
|
||||
if (auto typedDeclaration = dynamic_cast<T const*>(declaration))
|
||||
filteredDeclarations[name].push_back(typedDeclaration);
|
||||
return filteredDeclarations;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool ContractLevelChecker::check(SourceUnit const& _sourceUnit)
|
||||
{
|
||||
bool noErrors = true;
|
||||
findDuplicateDefinitions(
|
||||
filterDeclarations<FunctionDefinition>(*_sourceUnit.annotation().exportedSymbols)
|
||||
);
|
||||
// This check flags duplicate free events when free events become
|
||||
// a Solidity feature
|
||||
findDuplicateDefinitions(
|
||||
filterDeclarations<EventDefinition>(*_sourceUnit.annotation().exportedSymbols)
|
||||
);
|
||||
if (!Error::containsOnlyWarnings(m_errorReporter.errors()))
|
||||
noErrors = false;
|
||||
for (ASTPointer<ASTNode> const& node: _sourceUnit.nodes())
|
||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||
if (!check(*contract))
|
||||
noErrors = false;
|
||||
return noErrors;
|
||||
}
|
||||
|
||||
bool ContractLevelChecker::check(ContractDefinition const& _contract)
|
||||
@ -143,8 +173,21 @@ void ContractLevelChecker::findDuplicateDefinitions(map<string, vector<T>> const
|
||||
SecondarySourceLocation ssl;
|
||||
|
||||
for (size_t j = i + 1; j < overloads.size(); ++j)
|
||||
if (hasEqualNameAndParameters(*overloads[i], *overloads[j]))
|
||||
if (hasEqualParameters(*overloads[i], *overloads[j]))
|
||||
{
|
||||
solAssert(
|
||||
(
|
||||
dynamic_cast<ContractDefinition const*>(overloads[i]->scope()) &&
|
||||
dynamic_cast<ContractDefinition const*>(overloads[j]->scope()) &&
|
||||
overloads[i]->name() == overloads[j]->name()
|
||||
) ||
|
||||
(
|
||||
dynamic_cast<SourceUnit const*>(overloads[i]->scope()) &&
|
||||
dynamic_cast<SourceUnit const*>(overloads[j]->scope())
|
||||
),
|
||||
"Override is neither a namesake function/event in contract scope nor "
|
||||
"a free function/event (alias)."
|
||||
);
|
||||
ssl.append("Other declaration is here:", overloads[j]->location());
|
||||
reported.insert(j);
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ namespace solidity::frontend
|
||||
|
||||
/**
|
||||
* Component that verifies overloads, abstract contracts, function clashes and others
|
||||
* checks at contract or function level.
|
||||
* checks at file, contract, or function level.
|
||||
*/
|
||||
class ContractLevelChecker
|
||||
{
|
||||
@ -51,11 +51,14 @@ public:
|
||||
m_errorReporter(_errorReporter)
|
||||
{}
|
||||
|
||||
/// Performs checks on the given source ast.
|
||||
/// @returns true iff all checks passed. Note even if all checks passed, errors() can still contain warnings
|
||||
bool check(SourceUnit const& _sourceUnit);
|
||||
|
||||
private:
|
||||
/// Performs checks on the given contract.
|
||||
/// @returns true iff all checks passed. Note even if all checks passed, errors() can still contain warnings
|
||||
bool check(ContractDefinition const& _contract);
|
||||
|
||||
private:
|
||||
/// Checks that two functions defined in this contract with the same name have different
|
||||
/// arguments and that there is at most one constructor.
|
||||
void checkDuplicateFunctions(ContractDefinition const& _contract);
|
||||
|
@ -121,6 +121,7 @@ bool NameAndTypeResolver::performImports(SourceUnit& _sourceUnit, map<string, So
|
||||
))
|
||||
error = true;
|
||||
}
|
||||
_sourceUnit.annotation().exportedSymbols = m_scopes[&_sourceUnit]->declarations();
|
||||
return !error;
|
||||
}
|
||||
|
||||
@ -533,7 +534,6 @@ bool DeclarationRegistrationHelper::visit(SourceUnit& _sourceUnit)
|
||||
|
||||
void DeclarationRegistrationHelper::endVisit(SourceUnit& _sourceUnit)
|
||||
{
|
||||
_sourceUnit.annotation().exportedSymbols = m_scopes[&_sourceUnit]->declarations();
|
||||
ASTVisitor::endVisit(_sourceUnit);
|
||||
}
|
||||
|
||||
|
@ -366,12 +366,10 @@ bool CompilerStack::analyze()
|
||||
// This also calculates whether a contract is abstract, which is needed by the
|
||||
// type checker.
|
||||
ContractLevelChecker contractLevelChecker(m_errorReporter);
|
||||
|
||||
for (Source const* source: m_sourceOrder)
|
||||
if (source->ast)
|
||||
for (ASTPointer<ASTNode> const& node: source->ast->nodes())
|
||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||
if (!contractLevelChecker.check(*contract))
|
||||
noErrors = false;
|
||||
if (auto sourceAst = source->ast)
|
||||
noErrors = contractLevelChecker.check(*sourceAst);
|
||||
|
||||
// Requires ContractLevelChecker
|
||||
DocStringAnalyser docStringAnalyser(m_errorReporter);
|
||||
|
@ -0,0 +1,10 @@
|
||||
function f() pure returns (uint) { return 1337; }
|
||||
contract C {
|
||||
function f() public pure returns (uint) {
|
||||
return f();
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> FAILURE
|
@ -0,0 +1,15 @@
|
||||
==== Source: s1.sol ====
|
||||
import {f as g} from "s2.sol";
|
||||
function f() pure returns (uint) { return 1; }
|
||||
==== Source: s2.sol ====
|
||||
import {f as g} from "s1.sol";
|
||||
function f() pure returns (uint) { return 2; }
|
||||
contract C {
|
||||
function foo() public pure returns (uint) {
|
||||
return f() - g();
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// foo() -> 1
|
@ -0,0 +1,14 @@
|
||||
==== Source: s1.sol ====
|
||||
import {f as g, g as h} from "s2.sol";
|
||||
function f() pure returns (uint) { return h() - g(); }
|
||||
==== Source: s2.sol ====
|
||||
import {f as h} from "s1.sol";
|
||||
function f() pure returns (uint) { return 2; }
|
||||
function g() pure returns (uint) { return 4; }
|
||||
contract C {
|
||||
function foo() public pure returns (uint) {
|
||||
return h() - f() - g();
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// foo() -> -4
|
@ -0,0 +1,16 @@
|
||||
==== Source: s1.sol ====
|
||||
import {f as g, g as h} from "s2.sol";
|
||||
function f() pure returns (uint) { return h() - g(); }
|
||||
==== Source: s2.sol ====
|
||||
import {f as h} from "s1.sol";
|
||||
function f() pure returns (uint) { return 2; }
|
||||
function g() pure returns (uint) { return 4; }
|
||||
==== Source: s3.sol ====
|
||||
import "s1.sol";
|
||||
contract C {
|
||||
function foo() public pure returns (uint) {
|
||||
return f() - g() - h();
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// foo() -> -4
|
@ -0,0 +1,16 @@
|
||||
==== Source: s1.sol ====
|
||||
import {f as g, g as h} from "s2.sol";
|
||||
function f() pure returns (uint) { return h() - g(); }
|
||||
==== Source: s2.sol ====
|
||||
import {f as h} from "s1.sol";
|
||||
function f() pure returns (uint) { return 2; }
|
||||
function g() pure returns (uint) { return 4; }
|
||||
==== Source: s3.sol ====
|
||||
import "s2.sol";
|
||||
contract C {
|
||||
function foo() public pure returns (uint) {
|
||||
return f() - g() - h();
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// foo() -> -4
|
@ -0,0 +1,14 @@
|
||||
==== Source: s1.sol ====
|
||||
function f(uint24) pure returns (uint) { return 24; }
|
||||
function g(bool) pure returns (bool) { return true; }
|
||||
==== Source: s2.sol ====
|
||||
import {f as g, g as g} from "s1.sol";
|
||||
contract C {
|
||||
function foo() public pure returns (uint, bool) {
|
||||
return (g(2), g(false));
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// foo() -> 24, true
|
@ -0,0 +1,18 @@
|
||||
==== Source: s1.sol ====
|
||||
function f() pure returns (uint) { return 1337; }
|
||||
contract C {
|
||||
function g() public pure returns (uint) {
|
||||
return f();
|
||||
}
|
||||
}
|
||||
==== Source: s2.sol ====
|
||||
import "s1.sol";
|
||||
contract D is C {
|
||||
function h() public pure returns (uint) {
|
||||
return g();
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// h() -> 1337
|
@ -0,0 +1,18 @@
|
||||
==== Source: s1.sol ====
|
||||
function f() pure returns (uint) { return 1337; }
|
||||
contract C {
|
||||
function g() public pure virtual returns (uint) {
|
||||
return f() + 1;
|
||||
}
|
||||
}
|
||||
==== Source: s2.sol ====
|
||||
import "s1.sol";
|
||||
contract D is C {
|
||||
function g() public pure override returns (uint) {
|
||||
return f();
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// g() -> 1337
|
@ -0,0 +1,18 @@
|
||||
==== Source: s1.sol ====
|
||||
function f() pure returns (uint) { return 1337; }
|
||||
contract C {
|
||||
function g() public pure virtual returns (uint) {
|
||||
return f();
|
||||
}
|
||||
}
|
||||
==== Source: s2.sol ====
|
||||
import "s1.sol";
|
||||
contract D is C {
|
||||
function g() public pure override returns (uint) {
|
||||
return super.g();
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// g() -> 1337
|
@ -0,0 +1,25 @@
|
||||
==== Source: s1.sol ====
|
||||
function f() pure returns (uint) { return 1337; }
|
||||
contract C {
|
||||
function g() public pure virtual returns (uint) {
|
||||
return f();
|
||||
}
|
||||
}
|
||||
==== Source: s2.sol ====
|
||||
import "s1.sol";
|
||||
contract D is C {
|
||||
function g() public pure virtual override returns (uint) {
|
||||
return super.g() + 1;
|
||||
}
|
||||
}
|
||||
==== Source: s3.sol ====
|
||||
import "s2.sol";
|
||||
contract E is D {
|
||||
function g() public pure override returns (uint) {
|
||||
return super.g() + 1;
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// g() -> 1339
|
@ -0,0 +1,27 @@
|
||||
==== Source: s1.sol ====
|
||||
function f() pure returns (uint) { return 1337; }
|
||||
contract C {
|
||||
function g() public pure returns (uint) {
|
||||
return f();
|
||||
}
|
||||
}
|
||||
==== Source: s2.sol ====
|
||||
import "s1.sol";
|
||||
contract D is C {
|
||||
function h() public pure returns (uint) {
|
||||
return g();
|
||||
}
|
||||
}
|
||||
==== Source: s3.sol ====
|
||||
import "s2.sol";
|
||||
import {f as f} from "s2.sol";
|
||||
contract E is D {
|
||||
function i() public pure returns (uint) {
|
||||
return f();
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// i() -> 1337
|
@ -0,0 +1,19 @@
|
||||
==== Source: s1.sol ====
|
||||
function f() pure returns (uint) { return 1337; }
|
||||
contract C {
|
||||
function g() public pure virtual returns (uint) {
|
||||
return f();
|
||||
}
|
||||
}
|
||||
==== Source: s2.sol ====
|
||||
import "s1.sol" as M;
|
||||
function f() pure returns (uint) { return 6; }
|
||||
contract D is M.C {
|
||||
function g() public pure override returns (uint) {
|
||||
return super.g() + f() * 10000;
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// g() -> 61337
|
@ -0,0 +1,14 @@
|
||||
==== Source: s1.sol ====
|
||||
function f() pure returns (uint) { return 1337; }
|
||||
==== Source: s2.sol ====
|
||||
import {f as g} from "s1.sol";
|
||||
function f() pure returns (uint) { return 6; }
|
||||
contract D {
|
||||
function h() public pure returns (uint) {
|
||||
return g() + f() * 10000;
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// h() -> 61337
|
@ -0,0 +1,15 @@
|
||||
==== Source: s1.sol ====
|
||||
function f() pure returns (uint) { return 1337; }
|
||||
==== Source: s2.sol ====
|
||||
import {f as g} from "s1.sol";
|
||||
==== Source: s3.sol ====
|
||||
import {g as h} from "s2.sol";
|
||||
contract C {
|
||||
function foo() public pure returns (uint) {
|
||||
return h();
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// foo() -> 1337
|
@ -0,0 +1,4 @@
|
||||
function f(uint24) {}
|
||||
function f(uint16) {}
|
||||
function f(int24) {}
|
||||
function f(bool) {}
|
@ -0,0 +1,11 @@
|
||||
function g() pure returns (uint) { return 1; }
|
||||
function g() pure returns (string memory) { return "1"; }
|
||||
contract C {
|
||||
function foo() public pure returns (uint) {
|
||||
string memory s = g();
|
||||
return 100/g();
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// DeclarationError 1686: (0-46): Function with same name and parameter types defined twice.
|
||||
// TypeError 9574: (168-189): Type uint256 is not implicitly convertible to expected type string memory.
|
@ -0,0 +1,4 @@
|
||||
function f() pure returns (uint) { return 1337; }
|
||||
function f() pure returns (uint) { return 42; }
|
||||
// ----
|
||||
// DeclarationError 1686: (0-49): Function with same name and parameter types defined twice.
|
@ -0,0 +1,5 @@
|
||||
function f() pure returns (uint) { return 1337; }
|
||||
function f() pure returns (uint) { return 42; }
|
||||
function f() pure returns (uint) { return 1; }
|
||||
// ----
|
||||
// DeclarationError 1686: (0-49): Function with same name and parameter types defined twice.
|
@ -0,0 +1,8 @@
|
||||
function f() pure returns (uint) { return 1337; }
|
||||
contract C {
|
||||
function f() public pure returns (uint) {
|
||||
return f();
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning 2519: (65-126): This declaration shadows an existing declaration.
|
@ -0,0 +1,9 @@
|
||||
function f() pure returns (uint) { return 1337; }
|
||||
function f() view returns (uint) { return 42; }
|
||||
contract C {
|
||||
function g() public pure virtual returns (uint) {
|
||||
return f();
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// DeclarationError 1686: (0-49): Function with same name and parameter types defined twice.
|
@ -0,0 +1,19 @@
|
||||
==== Source: s1.sol ====
|
||||
function f() pure returns (uint) { return 1337; }
|
||||
function g() pure returns (uint) { return 42; }
|
||||
==== Source: s2.sol ====
|
||||
import {f as g} from "s1.sol";
|
||||
==== Source: s3.sol ====
|
||||
// imports f()->1337 as g()
|
||||
import "s2.sol";
|
||||
// imports f()->1337 as f() and
|
||||
// g()->42 as g
|
||||
import {f as f, g as g} from "s1.sol";
|
||||
contract C {
|
||||
function foo() public pure returns (uint) {
|
||||
// calls f()->1337 / f()->1337
|
||||
return f() / g();
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// DeclarationError 1686: (s1.sol:0-49): Function with same name and parameter types defined twice.
|
@ -0,0 +1,19 @@
|
||||
==== Source: s1.sol ====
|
||||
function f() pure returns (uint) { return 1337; }
|
||||
function g() pure returns (uint) { return 42; }
|
||||
==== Source: s2.sol ====
|
||||
import {f as g} from "s1.sol";
|
||||
==== Source: s3.sol ====
|
||||
// imports f()->1337 as g()
|
||||
import "s2.sol";
|
||||
// imports f()->1337 as f() and
|
||||
// g()->42 as g
|
||||
import "s1.sol";
|
||||
contract C {
|
||||
function foo() public pure returns (uint) {
|
||||
// calls f()->1337 / f()->1337
|
||||
return f() / g();
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// DeclarationError 1686: (s1.sol:0-49): Function with same name and parameter types defined twice.
|
@ -0,0 +1,6 @@
|
||||
==== Source: s1.sol ====
|
||||
import {f as g} from "s2.sol";
|
||||
function f() pure returns (uint) { return 1; }
|
||||
==== Source: s2.sol ====
|
||||
import {f as g} from "s1.sol";
|
||||
function f() pure returns (uint) { return 2; }
|
@ -0,0 +1,7 @@
|
||||
==== Source: s1.sol ====
|
||||
import {f as g, g as h} from "s2.sol";
|
||||
function f() pure returns (uint) { return h() - g(); }
|
||||
==== Source: s2.sol ====
|
||||
import {f as h} from "s1.sol";
|
||||
function f() pure returns (uint) { return 2; }
|
||||
function g() pure returns (uint) { return 4; }
|
@ -0,0 +1,14 @@
|
||||
==== Source: s1.sol ====
|
||||
import {f as g, g as h} from "s2.sol";
|
||||
function f() pure returns (uint) { return h() - g(); }
|
||||
==== Source: s2.sol ====
|
||||
import {f as h} from "s1.sol";
|
||||
function f() pure returns (uint) { return 2; }
|
||||
function g() pure returns (uint) { return 4; }
|
||||
==== Source: s3.sol ====
|
||||
import "s1.sol";
|
||||
import "s2.sol";
|
||||
// ----
|
||||
// DeclarationError 1686: (s1.sol:39-93): Function with same name and parameter types defined twice.
|
||||
// DeclarationError 1686: (s2.sol:31-77): Function with same name and parameter types defined twice.
|
||||
// DeclarationError 1686: (s2.sol:78-124): Function with same name and parameter types defined twice.
|
@ -0,0 +1,9 @@
|
||||
==== Source: s1.sol ====
|
||||
import {f as g, g as h} from "s2.sol";
|
||||
function f() pure returns (uint) { return h() - g(); }
|
||||
==== Source: s2.sol ====
|
||||
import {f as h} from "s1.sol";
|
||||
function f() pure returns (uint) { return 2; }
|
||||
function g() pure returns (uint) { return 4; }
|
||||
==== Source: s3.sol ====
|
||||
import "s1.sol";
|
@ -0,0 +1,9 @@
|
||||
==== Source: s1.sol ====
|
||||
import {f as g, g as h} from "s2.sol";
|
||||
function f() pure returns (uint) { return h() - g(); }
|
||||
==== Source: s2.sol ====
|
||||
import {f as h} from "s1.sol";
|
||||
function f() pure returns (uint) { return 2; }
|
||||
function g() pure returns (uint) { return 4; }
|
||||
==== Source: s3.sol ====
|
||||
import "s2.sol";
|
@ -0,0 +1,10 @@
|
||||
==== Source: s1.sol ====
|
||||
function f() pure returns (uint) { return 1337; }
|
||||
==== Source: s2.sol ====
|
||||
import {f as f} from "s1.sol";
|
||||
import {f as f} from "s1.sol";
|
||||
contract C {
|
||||
function g() public pure returns (uint) {
|
||||
return f();
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
==== Source: s1.sol ====
|
||||
function f(uint) pure returns (uint) { return 24; }
|
||||
function g() pure returns (bool) { return true; }
|
||||
==== Source: s2.sol ====
|
||||
import {f as g, g as g} from "s1.sol";
|
||||
contract C {
|
||||
function foo() public pure returns (uint, bool) {
|
||||
return (g(2), g());
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
==== Source: s1.sol ====
|
||||
function f() pure returns (uint16) { return 1337; }
|
||||
function g() pure returns (uint8) { return 42; }
|
||||
==== Source: s2.sol ====
|
||||
import {f as g} from "s1.sol";
|
||||
==== Source: s3.sol ====
|
||||
// imports f(uint16)->1337 as g(uint16)
|
||||
import "s2.sol";
|
||||
// imports f(uint16)->1337 as f(uint16) and
|
||||
// g(uint8)->42 as g(uint8)
|
||||
import {f as f, g as g} from "s1.sol";
|
||||
contract C {
|
||||
function foo() public pure returns (uint) {
|
||||
// calls f()->1337 / f()->1337
|
||||
return f() / g();
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// DeclarationError 1686: (s1.sol:0-51): Function with same name and parameter types defined twice.
|
@ -0,0 +1,9 @@
|
||||
==== Source: s1.sol ====
|
||||
function f() pure returns (uint) { return 1337; }
|
||||
contract C {}
|
||||
==== Source: s2.sol ====
|
||||
import "s1.sol";
|
||||
function f() pure returns (uint) { return 42; }
|
||||
contract D is C {}
|
||||
// ----
|
||||
// DeclarationError 1686: (s2.sol:17-64): Function with same name and parameter types defined twice.
|
@ -0,0 +1,12 @@
|
||||
==== Source: s1.sol ====
|
||||
function f() pure returns (uint) { return 1337; }
|
||||
contract C {}
|
||||
==== Source: s2.sol ====
|
||||
import "s1.sol";
|
||||
contract D is C {}
|
||||
==== Source: s3.sol ====
|
||||
import "s2.sol";
|
||||
function f() pure returns (uint) { return 42; }
|
||||
contract E is D {}
|
||||
// ----
|
||||
// DeclarationError 1686: (s3.sol:17-64): Function with same name and parameter types defined twice.
|
@ -0,0 +1,19 @@
|
||||
==== Source: s1.sol ====
|
||||
function f() pure returns (uint) { return 1337; }
|
||||
contract C {
|
||||
function f() public pure virtual returns (uint) {
|
||||
return f();
|
||||
}
|
||||
}
|
||||
==== Source: s2.sol ====
|
||||
import "s1.sol";
|
||||
function f() pure returns (uint) { return 42; }
|
||||
contract D is C {
|
||||
function f() public pure override returns (uint) {
|
||||
return f();
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning 2519: (s1.sol:65-134): This declaration shadows an existing declaration.
|
||||
// Warning 2519: (s2.sol:85-155): This declaration shadows an existing declaration.
|
||||
// DeclarationError 1686: (s2.sol:17-64): Function with same name and parameter types defined twice.
|
@ -0,0 +1,10 @@
|
||||
==== Source: s1.sol ====
|
||||
contract C {
|
||||
function f() public pure returns (uint) {
|
||||
return 1337;
|
||||
}
|
||||
}
|
||||
==== Source: s2.sol ====
|
||||
import {C.f as g} from "s1.sol";
|
||||
// ----
|
||||
// ParserError 2314: (s2.sol:9-10): Expected '}' but got '.'
|
@ -0,0 +1,9 @@
|
||||
==== Source: s1.sol ====
|
||||
function f() pure returns (uint) { return 1337; }
|
||||
==== Source: s2.sol ====
|
||||
import "s1.sol";
|
||||
contract C {
|
||||
function g() public pure returns (uint) {
|
||||
return f();
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
==== Source: s1.sol ====
|
||||
function f() pure returns (uint) { return 1337; }
|
||||
==== Source: s2.sol ====
|
||||
import {f as f, f as f, f as f} from "s1.sol";
|
||||
contract C {
|
||||
function g() public pure returns (uint) {
|
||||
return f();
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
==== Source: s1.sol ====
|
||||
function f() pure returns (uint) { return 1337; }
|
||||
==== Source: s2.sol ====
|
||||
import {f as g} from "s1.sol";
|
||||
==== Source: s3.sol ====
|
||||
import {g as h} from "s2.sol";
|
||||
contract C {
|
||||
function foo() public pure returns (uint) {
|
||||
return h();
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
==== Source: s1.sol ====
|
||||
function f() pure returns (uint) { return 1337; }
|
||||
==== Source: s2.sol ====
|
||||
import {f as f, f as f} from "s1.sol";
|
||||
contract C {
|
||||
function g() public pure returns (uint) {
|
||||
return f();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user