Skip to content

[BREAKING] Disallow legacy constructor#4215

Merged
erak merged 3 commits intodevelopfrom
constructorWorkaround
Jul 18, 2018
Merged

[BREAKING] Disallow legacy constructor#4215
erak merged 3 commits intodevelopfrom
constructorWorkaround

Conversation

@erak
Copy link
Copy Markdown
Collaborator

@erak erak commented Jun 1, 2018

Closes #4106.

@erak erak force-pushed the constructorWorkaround branch 5 times, most recently from 8dc5a06 to df89722 Compare June 2, 2018 00:22
@axic
Copy link
Copy Markdown
Contributor

axic commented Jun 2, 2018

Sorry I forgot to assign the issue to myself, but did mention the last call I started this work. Anyway it is not a big amount of duplicate effort :)

However we should only merge this after #4208

@erak
Copy link
Copy Markdown
Collaborator Author

erak commented Jun 2, 2018

@axic Oh sorry, did not get this in the last call. We should try to keep the project board up to date ;)
So, should we use with this branch / PR?

I agree, let's merge the other PR first.

@axic
Copy link
Copy Markdown
Contributor

axic commented Jun 2, 2018

@bit-shift I will have a look at the differences between the two PRs. Do you want to review #4208 ?

@axic
Copy link
Copy Markdown
Contributor

axic commented Jun 3, 2018

My local version of these changes are all included int this PR.

@erak
Copy link
Copy Markdown
Collaborator Author

erak commented Jun 5, 2018

@christianparpart I removed the expected shadowing warning of override_constructor.sol and constructor_old.sol. The old version of override_constructor.sol was basically testing that you can have a function that is called like the constructor of a contracts base contract. Since this construct is not possible anymore, we also should not warn anymore.
And getting the warning if contract A { function A() public {} } feels a little bit like clutter.

Copy link
Copy Markdown
Contributor

@chriseth chriseth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a test for

contract C {
function constructor() { ... }
}

?

bool SyntaxChecker::visit(ContractDefinition const& _contract)
{
ASTString const& contractName = _contract.name();
for (const FunctionDefinition* const function : _contract.definedFunctions())
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be FunctionDefinition const* const function, but I think the last const does not really help readability and thus could be dropped.

for (const FunctionDefinition* const function : _contract.definedFunctions())
if (function->name() == contractName)
m_errorReporter.syntaxError(function->location(),
"Defining constructors as functions with the same name as the contract is not allowed. "
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use the original v050 message and not the message of the pre-050 warning. Also, the indentation and line breaks are not according to coding style.

m_errorReporter.warning(_function.location(), "Modifiers of functions without implementation are ignored." );
}
if (_function.name() == "constructor")
if (_function.name() == "constructor" && !_function.isConstructor())
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't add !_function.isConstructor(). Currently, it looks like this is a good thing to add, but it might hide errors that are introduced when we change the logic of isConstructor.


if (result.isConstructor || _forceEmptyName || m_scanner->currentToken() == Token::LParen)
if (result.isConstructor)
result.name = make_shared<ASTString>("constructor");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the name should still be empty.

result.name = make_shared<ASTString>("constructor");
else if (_forceEmptyName || m_scanner->currentToken() == Token::LParen)
result.name = make_shared<ASTString>();
else if (m_scanner->currentToken() == Token::Constructor && !result.isConstructor)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this to still allow function constructor(...) { ..}? I don't think we have to support that - constructor is now a real keyword and thus functions cannot be named constructor.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the idea was to still allow it, but warn about it's usage. But you're right, since this is keyword now, we should not allow it anymore.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

!result.isConstructor can be removed (it is an else if).

// It is fine to "override" constructor of a base class since it is invisible
contract A { function A() public { } }
contract A { constructor() public {} }
contract B is A { function A() public pure returns (uint8) {} }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, that is exactly what we should test here!

function Main() payable {
h = (new Helper).value(10)("abc", true);
constructor() payable {
h = (new Helper).value(10)('abc', true);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason for this change?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, this was an unconscious change due to broken code highlighting in my editor. We can revert to "abc"

"after",
"case",
"catch",
"constructor"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

constructor should not be reserved, it should be a keyword "in use".

@erak erak force-pushed the constructorWorkaround branch from 10a63bb to ef49d2c Compare June 11, 2018 10:25
@axic
Copy link
Copy Markdown
Contributor

axic commented Jun 11, 2018

Depends on #4206.

@axic
Copy link
Copy Markdown
Contributor

axic commented Jun 11, 2018

This could be fixed without the external tests:

ASSERTION FAILURE:
- file   : SolidityABIJSON.cpp
- line   : 49
- message: Parsing contract failed

Also syntax test expectations need to be updated.

result.name = make_shared<ASTString>();
else if (_forceEmptyName || m_scanner->currentToken() == Token::LParen)
result.name = make_shared<ASTString>();
else if (m_scanner->currentToken() == Token::Constructor && !result.isConstructor)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this can happen since expectIdentifierToken shouldn't allow a non-identifier, such as Token::Constructor. Is there a test for this which needs this extra condition here?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@axic This check should have been removed already. Thanks!

@erak
Copy link
Copy Markdown
Collaborator Author

erak commented Jun 12, 2018

@axic I updated the broken ABI tests.

@erak
Copy link
Copy Markdown
Collaborator Author

erak commented Jun 12, 2018

@chriseth The file function_named_constructor.sol contains a test for

contract C { function constructor() { ... }}

@axic axic changed the title [WIP] Disallow legacy constructor [WIP] [BRAKING] Disallow legacy constructor Jun 12, 2018
@axic axic changed the title [WIP] [BRAKING] Disallow legacy constructor [WIP] [BREAKING] Disallow legacy constructor Jun 12, 2018
@erak erak force-pushed the constructorWorkaround branch from df180f5 to 024e897 Compare June 13, 2018 10:06
@chriseth
Copy link
Copy Markdown
Contributor

Please rebase to trigger the tests.

@erak erak force-pushed the constructorWorkaround branch 5 times, most recently from 91ad649 to b4aaa30 Compare June 13, 2018 15:17
@chriseth
Copy link
Copy Markdown
Contributor

Tests are failing.

@erak
Copy link
Copy Markdown
Collaborator Author

erak commented Jun 27, 2018

We need to merge #4354 first. After merging, this PR needs to be updated such that it removes the old syntax tests that expect a warning instead of an error.

@erak erak force-pushed the constructorWorkaround branch from 85ca746 to 5b3e08b Compare June 29, 2018 15:05
@erak
Copy link
Copy Markdown
Collaborator Author

erak commented Jun 29, 2018

Updated this PR again after #4354 got merged. Should be ready for final review now.

@erak
Copy link
Copy Markdown
Collaborator Author

erak commented Jun 29, 2018

I missed the docs here, but will add these changes.

@erak erak force-pushed the constructorWorkaround branch 2 times, most recently from 96d449c to bc5f671 Compare July 2, 2018 14:24
@erak
Copy link
Copy Markdown
Collaborator Author

erak commented Jul 2, 2018

I've split out the required changes to the documentation: #4402. After that PR got merged, we can merge this one.

@leonardoalt leonardoalt mentioned this pull request Jul 2, 2018
29 tasks
@erak erak force-pushed the constructorWorkaround branch from bc5f671 to 7510875 Compare July 4, 2018 09:59
dynamic_cast<FunctionDefinition const*>(&_declaration) &&
name == decl->name())
)
shadowedDeclaration = decl;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So only something that is a function can be shadowed by something that's not a contract with the same name?
What about contract C { uint msg; }? Currently this warns: This declaration shadows a builtin symbol.. And I think this comes from below in this function (I may be wrong) - does that still work? Is there a test for it?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have a test for the case you've mentioned: 452_shadowing_builtins_with_storage_variables.sol

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After we talked about that: I've improved the formatting to make the condition easier to understand 😄

ekpyron
ekpyron previously approved these changes Jul 4, 2018
Copy link
Copy Markdown
Collaborator

@ekpyron ekpyron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks fine to me now.

@erak erak self-assigned this Jul 6, 2018
@@ -476,7 +476,15 @@ bool DeclarationRegistrationHelper::registerDeclaration(
Declaration const* shadowedDeclaration = nullptr;
if (_warnOnShadow && !name.empty() && _container.enclosingContainer())
for (auto const* decl: _container.enclosingContainer()->resolveName(name, true, true))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unrelated to this PR, but why do we have a for loop here?

if (_warnOnShadow && !name.empty() && _container.enclosingContainer())
for (auto const* decl: _container.enclosingContainer()->resolveName(name, true, true))
shadowedDeclaration = decl;
// Do not warn about functions shadowing a contract.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain the reason for this?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@chriseth Without this change, the following code would result in a warning about function A() shadowing contract A:

contract A { constructor() public {} }
contract B is A { function A() public pure returns (uint8) {} }

Since functions can now have the same name as a previously declared contract, this should not warn. We also have a test for that: overriding_constructor.sol.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would say the warning is correct, since it does shadow A. Note the following does not work because the function A shadows the contract A:

contract A { function f() public {} }
contract B is A {
  function A() public pure returns (uint8) {}
  function g() public {
    A.f();
  }
}

bool SyntaxChecker::visit(ContractDefinition const& _contract)
{
ASTString const& contractName = _contract.name();
for (FunctionDefinition const* function : _contract.definedFunctions())
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No space in front of :.

@erak erak force-pushed the constructorWorkaround branch 2 times, most recently from 015c823 to 2c01950 Compare July 17, 2018 21:50
@erak
Copy link
Copy Markdown
Collaborator Author

erak commented Jul 17, 2018

Rebased and squashed some commits. @chriseth I've also addressed your comment about a function shadowing a contract: #4215 (comment).

@@ -0,0 +1,9 @@
contract A {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please move the positive case into its own test.

@erak erak force-pushed the constructorWorkaround branch from 2c01950 to b0b35e1 Compare July 18, 2018 12:42
@erak
Copy link
Copy Markdown
Collaborator Author

erak commented Jul 18, 2018

@chriseth I reverted merging both, the new and the old constructor syntax, into one file. I also rebased the branch.

@erak erak merged commit ccb5fcc into develop Jul 18, 2018
@chriseth chriseth deleted the constructorWorkaround branch August 16, 2018 12:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants