Some changes to "abstract".

This commit is contained in:
chriseth 2019-11-04 14:12:58 +01:00
parent cac2e843e6
commit 5388c919f0
20 changed files with 52 additions and 20 deletions

View File

@ -345,7 +345,7 @@ commandline compiler for linking):
:: ::
// This will not compile with 0.6.0 anymore. // This will not compile after 0.6.0
pragma solidity >=0.5.0 <0.5.99; pragma solidity >=0.5.0 <0.5.99;
library OldLibrary { library OldLibrary {

View File

@ -134,8 +134,8 @@ bool ContractLevelChecker::check(ContractDefinition const& _contract)
checkDuplicateEvents(_contract); checkDuplicateEvents(_contract);
checkIllegalOverrides(_contract); checkIllegalOverrides(_contract);
checkAmbiguousOverrides(_contract); checkAmbiguousOverrides(_contract);
checkAbstractFunctions(_contract);
checkBaseConstructorArguments(_contract); checkBaseConstructorArguments(_contract);
checkAbstractFunctions(_contract);
checkExternalTypeClashes(_contract); checkExternalTypeClashes(_contract);
checkHashCollisions(_contract); checkHashCollisions(_contract);
checkLibraryRequirements(_contract); checkLibraryRequirements(_contract);
@ -395,6 +395,8 @@ void ContractLevelChecker::checkAbstractFunctions(ContractDefinition const& _con
} }
// Set to not fully implemented if at least one flag is false. // Set to not fully implemented if at least one flag is false.
// Note that `_contract.annotation().unimplementedFunctions` has already been
// pre-filled by `checkBaseConstructorArguments`.
for (auto const& it: functions) for (auto const& it: functions)
for (auto const& funAndFlag: it.second) for (auto const& funAndFlag: it.second)
if (!funAndFlag.second) if (!funAndFlag.second)
@ -405,13 +407,22 @@ void ContractLevelChecker::checkAbstractFunctions(ContractDefinition const& _con
break; break;
} }
if (_contract.abstract() && _contract.contractKind() != ContractDefinition::ContractKind::Contract) if (_contract.abstract())
m_errorReporter.typeError(_contract.location(), "Only contracts can be abstract."); {
if (_contract.contractKind() == ContractDefinition::ContractKind::Interface)
m_errorReporter.typeError(_contract.location(), "Interfaces do not need the \"abstract\" keyword, they are abstract implicitly.");
else if (_contract.contractKind() == ContractDefinition::ContractKind::Library)
m_errorReporter.typeError(_contract.location(), "Libraries cannot be abstract.");
else
solAssert(_contract.contractKind() == ContractDefinition::ContractKind::Contract, "");
}
// For libraries, we emit errors on function-level, so this is fine as long as we do
// not have inheritance for libraries.
if ( if (
_contract.contractKind() == ContractDefinition::ContractKind::Contract && _contract.contractKind() == ContractDefinition::ContractKind::Contract &&
!_contract.annotation().unimplementedFunctions.empty() && !_contract.abstract() &&
!_contract.abstract() !_contract.annotation().unimplementedFunctions.empty()
) )
m_errorReporter.typeError( m_errorReporter.typeError(
_contract.location(), _contract.location(),

View File

@ -77,6 +77,8 @@ private:
void overrideListError(FunctionDefinition const& function, std::set<ContractDefinition const*, LessFunction> _secondary, std::string const& _message1, std::string const& _message2); void overrideListError(FunctionDefinition const& function, std::set<ContractDefinition const*, LessFunction> _secondary, std::string const& _message1, std::string const& _message2);
void overrideError(CallableDeclaration const& function, CallableDeclaration const& super, std::string message); void overrideError(CallableDeclaration const& function, CallableDeclaration const& super, std::string message);
void checkAbstractFunctions(ContractDefinition const& _contract); void checkAbstractFunctions(ContractDefinition const& _contract);
/// Checks that the base constructor arguments are properly provided.
/// Fills the list of unimplemented functions in _contract's annotations.
void checkBaseConstructorArguments(ContractDefinition const& _contract); void checkBaseConstructorArguments(ContractDefinition const& _contract);
void annotateBaseConstructorArguments( void annotateBaseConstructorArguments(
ContractDefinition const& _currentContract, ContractDefinition const& _currentContract,

View File

@ -423,8 +423,8 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
_function.body().accept(*this); _function.body().accept(*this);
else if (_function.isConstructor()) else if (_function.isConstructor())
m_errorReporter.typeError(_function.location(), "Constructor must be implemented if declared."); m_errorReporter.typeError(_function.location(), "Constructor must be implemented if declared.");
else if (isLibraryFunction && _function.visibility() <= FunctionDefinition::Visibility::Internal) else if (isLibraryFunction)
m_errorReporter.typeError(_function.location(), "Internal library function must be implemented if declared."); m_errorReporter.typeError(_function.location(), "Library functions must be implemented if declared.");
if (_function.isFallback()) if (_function.isFallback())
@ -2228,7 +2228,7 @@ void TypeChecker::endVisit(NewExpression const& _newExpression)
m_errorReporter.fatalTypeError(_newExpression.location(), "Cannot instantiate an interface."); m_errorReporter.fatalTypeError(_newExpression.location(), "Cannot instantiate an interface.");
if (!contract->constructorIsPublic()) if (!contract->constructorIsPublic())
m_errorReporter.typeError(_newExpression.location(), "Contract with internal constructor cannot be created directly."); m_errorReporter.typeError(_newExpression.location(), "Contract with internal constructor cannot be created directly.");
if (contract->abstract() || !contract->annotation().unimplementedFunctions.empty()) if (contract->abstract())
m_errorReporter.typeError(_newExpression.location(), "Cannot instantiate an abstract contract."); m_errorReporter.typeError(_newExpression.location(), "Cannot instantiate an abstract contract.");
solAssert(!!m_scope, ""); solAssert(!!m_scope, "");

View File

@ -151,7 +151,7 @@ bool ContractDefinition::constructorIsPublic() const
bool ContractDefinition::canBeDeployed() const bool ContractDefinition::canBeDeployed() const
{ {
return constructorIsPublic() && annotation().unimplementedFunctions.empty() && !abstract(); return constructorIsPublic() && !abstract() && !isInterface();
} }
FunctionDefinition const* ContractDefinition::fallbackFunction() const FunctionDefinition const* ContractDefinition::fallbackFunction() const

View File

@ -1,3 +1,4 @@
interface B { }
abstract interface A { } abstract interface A { }
// ---- // ----
// TypeError: (0-24): Only contracts can be abstract. // TypeError: (16-40): Interfaces do not need the "abstract" keyword, they are abstract implicitly.

View File

@ -1,3 +1,3 @@
abstract library A { } abstract library A { }
// ---- // ----
// TypeError: (0-22): Only contracts can be abstract. // TypeError: (0-22): Libraries cannot be abstract.

View File

@ -12,4 +12,4 @@ contract Parent {
contract Child is Parent { contract Child is Parent {
} }
// ---- // ----
// TypeError: (146-155): Cannot instantiate an abstract contract. // TypeError: (233-261): Contract "Child" should be marked as abstract.

View File

@ -9,4 +9,5 @@ contract B is A {
} }
} }
// ---- // ----
// TypeError: (131-301): Contract "B" should be marked as abstract.
// TypeError: (250-254): Explicit type conversion not allowed from "string memory" to "contract A". // TypeError: (250-254): Explicit type conversion not allowed from "string memory" to "contract A".

View File

@ -1,4 +1,15 @@
// This used to work pre-0.6.0.
library L { library L {
function f() public returns(uint[] storage); function f() public returns(uint[] storage);
function g() public returns(uint[] storage s); function g() public returns(uint[] storage s);
} }
abstract library T {
function f() public returns(uint[] storage);
function g() public returns(uint[] storage s);
}
// ----
// TypeError: (146-268): Libraries cannot be abstract.
// TypeError: (48-92): Library functions must be implemented if declared.
// TypeError: (97-143): Library functions must be implemented if declared.
// TypeError: (171-215): Library functions must be implemented if declared.
// TypeError: (220-266): Library functions must be implemented if declared.

View File

@ -1,3 +1,4 @@
library test { library test {
function f(bytes calldata) external; function f(bytes calldata) external {}
} }
// ----

View File

@ -1,5 +1,5 @@
library test { library test {
function f(bytes memory) external; function f(bytes memory) external {}
} }
// ---- // ----
// TypeError: (30-42): Data location must be "storage" or "calldata" for parameter in external function, but "memory" was given. // TypeError: (30-42): Data location must be "storage" or "calldata" for parameter in external function, but "memory" was given.

View File

@ -1,3 +1,3 @@
library test { library test {
function f(bytes storage) external; function f(bytes storage) external {}
} }

View File

@ -5,4 +5,3 @@ contract derived {
} }
// ---- // ----
// TypeError: (0-40): Contract "base" should be marked as abstract. // TypeError: (0-40): Contract "base" should be marked as abstract.
// TypeError: (104-112): Cannot instantiate an abstract contract.

View File

@ -1,3 +1,4 @@
contract A { constructor(uint a) public { } } contract A { constructor(uint a) public { } }
contract B is A { } contract B is A { }
// ---- // ----
// TypeError: (46-65): Contract "B" should be marked as abstract.

View File

@ -1,3 +1,4 @@
contract A { constructor(uint a) public { } } contract A { constructor(uint a) public { } }
contract B is A { } contract B is A { }
// ---- // ----
// TypeError: (46-65): Contract "B" should be marked as abstract.

View File

@ -1,3 +1,4 @@
// This used to work in pre-0.6.0.
library Lib { library Lib {
function min(uint, uint) public returns (uint); function min(uint, uint) public returns (uint);
} }
@ -7,4 +8,4 @@ contract Test {
} }
} }
// ---- // ----
// Warning: (118-124): Unused local variable. // TypeError: (53-100): Library functions must be implemented if declared.

View File

@ -1,4 +1,7 @@
// This used to work pre-0.6.0.
library L { library L {
// This can be used as an "interface", hence it is allowed. // This can be used as an "interface", hence it is allowed.
function f() public; function f() public;
} }
// ----
// TypeError: (112-132): Library functions must be implemented if declared.

View File

@ -2,4 +2,4 @@ library L {
function f() internal; function f() internal;
} }
// ---- // ----
// TypeError: (16-38): Internal library function must be implemented if declared. // TypeError: (16-38): Library functions must be implemented if declared.

View File

@ -2,4 +2,4 @@ library L {
function f() private; function f() private;
} }
// ---- // ----
// TypeError: (16-37): Internal library function must be implemented if declared. // TypeError: (16-37): Library functions must be implemented if declared.