Skip to content

Conversation

@cameel
Copy link
Collaborator

@cameel cameel commented Jun 1, 2021

Fixes #11445.

Comment on lines +1 to +18
abstract contract I {
function a() internal view virtual returns(uint256);
}

abstract contract C is I {
function f() public view returns(uint256) {
return I.a();
}
}

abstract contract D is I {
function f() public view returns(uint256) {
return super.a();
}
}
// ----
// TypeError 7501: (172-177): Cannot call unimplemented base function.
// TypeError 9582: (278-285): Member "a" not found or not visible after argument-dependent lookup in type(contract super D).
Copy link
Collaborator Author

@cameel cameel Jun 1, 2021

Choose a reason for hiding this comment

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

This test ensures that we'll not hit the final assert in resolveVirtual() when super skips all the unimplemented functions and there are no implemented ones to use.
The error is misleading though. Should just say that the function is not implemented.

Comment on lines +1 to +11
contract A {
function f() public virtual {}
}
abstract contract B is A {
function f() public virtual override;
}
contract C is B {
function f() public virtual override {}
}
// ----
// TypeError 4593: (81-118): Overriding an implemented function with an unimplemented function is not allowed.
Copy link
Collaborator Author

@cameel cameel Jun 1, 2021

Choose a reason for hiding this comment

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

This shows that the same problem does not exist without multiple inheritance because we just do not allow unimplemented functions between implemented ones in the resolution chain.

Comment on lines +1 to +9
contract C {
modifier m() { _; }
}
contract D is C {
function f() super.m public {
}
}
// ----
// DeclarationError 7920: (74-81): Identifier not found or not unique.
Copy link
Collaborator Author

@cameel cameel Jun 1, 2021

Choose a reason for hiding this comment

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

It's also not possible with modifiers because they do not have super (though I found a different problem: #11468).

@cameel
Copy link
Collaborator Author

cameel commented Jun 1, 2021

Comment fixed. I have also added a changelog entry.

@cameel cameel requested a review from christianparpart June 1, 2021 16:11
@cameel cameel force-pushed the make-super-skip-unimplemented-functions branch from 3f7cb20 to b7b7e2f Compare June 1, 2021 16:19
leonardoalt
leonardoalt previously approved these changes Jun 1, 2021
!function->isConstructor() &&
// Lookup via super should skip an unimplemented function because there must be
// another, implemented one behind it (otherwise we would fail at analysis stage).
// For ordinary virtual lookup, on the other hand, the only case in which we might
Copy link
Contributor

Choose a reason for hiding this comment

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

So if this cannot happen for virtual functions, why not also skip unimplemented functions in that case?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It can happen - in the one situation the comment mentions. I.e. when the call is in a function that will never run because it has been overridden. See for example: call_unimplemented_base.sol.

My first implementation was actually what you suggested but it felt a bit like a hack. To cover this single case I had to remember the last seen unimplemented function and go back to it if it turned out there were no implemented ones at all. Doing it only for super makes it simpler.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ok, I see it now: super essentially searches upwards while virtual searches downwards. Can you still shorten this comment to at most two lines? Maybe the second part is not really relevant.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

super essentially searches upwards while virtual searches downwards

I do not understand what you mean by this part. They both walk the linearized hierarchy in the same direction. Can you elaborate a bit more on how you see this situation?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Comment changed.

Was:

// Lookup via super should skip an unimplemented function because there must be
// another, implemented one behind it (otherwise we would fail at analysis stage).
// For ordinary virtual lookup, on the other hand, the only case in which we might
// encounter an unimplemented function is when there is no implementation at all
// and that only happens if the code passed analysis due to the call never actually
// happening (i.e. it's inside a function that gets overridden).

is:

// With super lookup analysis guarantees that there is an implemented function in the chain.
// With virtual lookup there are valid cases where returning an unimplemented one is fine.

@cameel
Copy link
Collaborator Author

cameel commented Jun 1, 2021

@chriseth About cases where we want different behavior between super lookup and ordinary virtual lookup:

  1. call_unimplemented_base_via_super.sol (added in this PR) vs call_unimplemented_base.sol.
    • For non-super lookup resolveVirtual() returns an unimplemented function in this case. With super lookup it's a syntax error instead so resolveVirtual() is not called (which is what my comment points out).
  2. override_implemented_and_unimplemented_with_implemented_call_via_contract.sol vs override_implemented_and_unimplemented_with_implemented_call_via_super.sol (both added in this PR).

@cameel cameel force-pushed the make-super-skip-unimplemented-functions branch from b7b7e2f to d96cc34 Compare June 2, 2021 14:16
@cameel cameel self-assigned this Jun 2, 2021
@chriseth chriseth merged commit 3c350a6 into develop Jun 3, 2021
@chriseth chriseth deleted the make-super-skip-unimplemented-functions branch June 3, 2021 06:37
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.

ICE when calling an unimplemented virtual function via super

4 participants