Skip to content

Commit 5c6a406

Browse files
committed
Implement struct instance member case.
Struct instance member can be only variable or a library function attached to the struct. For now the only possible way to have constant/pure struct instance is by inline declaring i.e. `S(1).v`
1 parent b1e82f4 commit 5c6a406

4 files changed

Lines changed: 110 additions & 3 deletions

File tree

libsolidity/analysis/TypeChecker.cpp

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3333,9 +3333,44 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
33333333
{
33343334
case Type::Category::Struct:
33353335
{
3336-
auto const* owningObjectStructType = dynamic_cast<StructType const*>(owningObjectType);
3337-
solAssert(owningObjectStructType);
3338-
_memberAccess.annotation().isLValue = !owningObjectStructType->dataStoredIn(DataLocation::CallData);
3336+
_memberAccess.annotation().isLValue = !static_cast<StructType const*>(owningObjectType)->dataStoredIn(DataLocation::CallData);
3337+
3338+
if (
3339+
auto const* accessedVariableDeclaration =
3340+
dynamic_cast<VariableDeclaration const*>(_memberAccess.annotation().referencedDeclaration)
3341+
)
3342+
{
3343+
_memberAccess.annotation().isPure =
3344+
*_memberAccess.expression().annotation().isPure ||
3345+
accessedVariableDeclaration->isConstant(); // It is always false. See below.
3346+
3347+
solUnimplementedAssert(
3348+
!accessedVariableDeclaration->isConstant(),
3349+
"Constant struct members are not yet implemented."
3350+
);
3351+
}
3352+
else if (dynamic_cast<FunctionDefinition const*>(_memberAccess.annotation().referencedDeclaration))
3353+
{
3354+
solAssert(_memberAccess.annotation().type->category() == Type::Category::Function);
3355+
auto const* accessedMemberFunctionType = static_cast<FunctionType const*>(_memberAccess.annotation().type);
3356+
// It is not possible to define a function inside a struct definition, but a library function can be
3357+
// attached to a struct with the `using` keyword. In this case the function invoke kind can be only
3358+
// `internal` or `delegate`.
3359+
solAssert(
3360+
accessedMemberFunctionType->kind() == FunctionType::Kind::Internal ||
3361+
accessedMemberFunctionType->kind() == FunctionType::Kind::DelegateCall,
3362+
"Impossible function call kind for struct type member."
3363+
);
3364+
3365+
// When struct is constant its members are also constant.
3366+
_memberAccess.annotation().isPure = *_memberAccess.expression().annotation().isPure;
3367+
}
3368+
else
3369+
solAssert(
3370+
false,
3371+
"Struct must have all members defined and they must be variables declarations or functions definitions"
3372+
);
3373+
33393374
break;
33403375
}
33413376
case Type::Category::Function:
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
struct S {
2+
uint256 v;
3+
}
4+
5+
library L {
6+
function double(S memory s) pure public returns(uint256) {
7+
return 2 * s.v;
8+
}
9+
}
10+
11+
using L for S;
12+
13+
contract C
14+
{
15+
S private s;
16+
function test() pure private {
17+
s.double;
18+
}
19+
}
20+
// ----
21+
// TypeError 2527: (226-227): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
22+
// TypeError 2527: (226-234): Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires "view".
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
struct S {
2+
uint256 v;
3+
}
4+
5+
library L {
6+
function doubleInternal(S memory s) pure internal returns(uint256) {
7+
return 2 * s.v;
8+
}
9+
10+
function doubleExternal(S memory s) pure external returns(uint256) {
11+
return 2 * s.v;
12+
}
13+
14+
function doublePublic(S memory s) pure public returns(uint256) {
15+
return 2 * s.v;
16+
}
17+
}
18+
19+
using L for S;
20+
21+
contract C
22+
{
23+
uint256 constant s = S(1).v;
24+
25+
function test() pure private {
26+
S(1);
27+
S(1).v;
28+
S(1).doubleInternal;
29+
S(1).doubleExternal;
30+
S(1).doublePublic;
31+
}
32+
}
33+
// ----
34+
// Warning 6133: (457-461): Statement has no effect.
35+
// Warning 6133: (471-477): Statement has no effect.
36+
// Warning 6133: (487-506): Statement has no effect.
37+
// Warning 6133: (516-535): Statement has no effect.
38+
// Warning 6133: (545-562): Statement has no effect.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
struct S {
2+
uint256 v;
3+
}
4+
5+
contract C
6+
{
7+
S private s;
8+
uint256 v = s.v;
9+
uint256 constant vConst = s.v;
10+
}
11+
// ----
12+
// TypeError 8349: (110-113): Initial value for constant variable has to be compile-time constant.

0 commit comments

Comments
 (0)