Merge pull request #13384 from zemse/develop

Allow named parameters in mapping types
This commit is contained in:
Daniel 2023-01-09 17:59:29 +01:00 committed by GitHub
commit f441e1323a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
75 changed files with 530 additions and 30 deletions

View File

@ -1,6 +1,7 @@
### 0.8.18 (unreleased) ### 0.8.18 (unreleased)
Language Features: Language Features:
* Allow named parameters in mapping types.
Compiler Features: Compiler Features:

View File

@ -504,7 +504,7 @@ variableDeclarationTuple:
variableDeclarationStatement: ((variableDeclaration (Assign expression)?) | (variableDeclarationTuple Assign expression)) Semicolon; variableDeclarationStatement: ((variableDeclaration (Assign expression)?) | (variableDeclarationTuple Assign expression)) Semicolon;
expressionStatement: expression Semicolon; expressionStatement: expression Semicolon;
mappingType: Mapping LParen key=mappingKeyType DoubleArrow value=typeName RParen; mappingType: Mapping LParen key=mappingKeyType name=identifier? DoubleArrow value=typeName name=identifier? RParen;
/** /**
* Only elementary types or user defined types are viable as mapping keys. * Only elementary types or user defined types are viable as mapping keys.
*/ */

View File

@ -4,12 +4,13 @@
Mapping Types Mapping Types
============= =============
Mapping types use the syntax ``mapping(KeyType => ValueType)`` and variables Mapping types use the syntax ``mapping(KeyType KeyName? => ValueType ValueName?)`` and variables of
of mapping type are declared using the syntax ``mapping(KeyType => ValueType) VariableName``. mapping type are declared using the syntax ``mapping(KeyType KeyName? => ValueType ValueName?)
The ``KeyType`` can be any VariableName``. The ``KeyType`` can be any built-in value type, ``bytes``, ``string``, or any
built-in value type, ``bytes``, ``string``, or any contract or enum type. Other user-defined contract or enum type. Other user-defined or complex types, such as mappings, structs or array types
or complex types, such as mappings, structs or array types are not allowed. are not allowed. ``ValueType`` can be any type, including mappings, arrays and structs. ``KeyName``
``ValueType`` can be any type, including mappings, arrays and structs. and ``ValueName`` are optional (so ``mapping(KeyType => ValueType)`` works as well) and can be any
valid identifier that is not a type.
You can think of mappings as `hash tables <https://en.wikipedia.org/wiki/Hash_table>`_, which are virtually initialised You can think of mappings as `hash tables <https://en.wikipedia.org/wiki/Hash_table>`_, which are virtually initialised
such that every possible key exists and is mapped to a value whose such that every possible key exists and is mapped to a value whose
@ -29,8 +30,10 @@ of contract functions that are publicly visible.
These restrictions are also true for arrays and structs that contain mappings. These restrictions are also true for arrays and structs that contain mappings.
You can mark state variables of mapping type as ``public`` and Solidity creates a You can mark state variables of mapping type as ``public`` and Solidity creates a
:ref:`getter <visibility-and-getters>` for you. The ``KeyType`` becomes a parameter for the getter. :ref:`getter <visibility-and-getters>` for you. The ``KeyType`` becomes a parameter
If ``ValueType`` is a value type or a struct, the getter returns ``ValueType``. with name ``KeyName`` (if specified) for the getter.
If ``ValueType`` is a value type or a struct, the getter returns ``ValueType`` with
name ``ValueName`` (if specified).
If ``ValueType`` is an array or a mapping, the getter has one parameter for If ``ValueType`` is an array or a mapping, the getter has one parameter for
each ``KeyType``, recursively. each ``KeyType``, recursively.
@ -64,6 +67,25 @@ contract that returns the value at the specified address.
The example below is a simplified version of an The example below is a simplified version of an
`ERC20 token <https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol>`_. `ERC20 token <https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol>`_.
``_allowances`` is an example of a mapping type inside another mapping type. ``_allowances`` is an example of a mapping type inside another mapping type.
In the example below, the optional ``KeyName`` and ``ValueName`` are provided for the mapping.
It does not affect any contract functionality or bytecode, it only sets the ``name`` field
for the inputs and outputs in the ABI for the mapping's getter.
.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.18;
contract MappingExampleWithNames {
mapping(address user => uint balance) public balances;
function update(uint newBalance) public {
balances[msg.sender] = newBalance;
}
}
The example below uses ``_allowances`` to record the amount someone else is allowed to withdraw from your account. The example below uses ``_allowances`` to record the amount someone else is allowed to withdraw from your account.
.. code-block:: solidity .. code-block:: solidity

View File

@ -267,14 +267,59 @@ void DeclarationTypeChecker::endVisit(Mapping const& _mapping)
solAssert(dynamic_cast<ElementaryTypeName const*>(&_mapping.keyType()), ""); solAssert(dynamic_cast<ElementaryTypeName const*>(&_mapping.keyType()), "");
Type const* keyType = _mapping.keyType().annotation().type; Type const* keyType = _mapping.keyType().annotation().type;
ASTString keyName = _mapping.keyName();
Type const* valueType = _mapping.valueType().annotation().type; Type const* valueType = _mapping.valueType().annotation().type;
ASTString valueName = _mapping.valueName();
// Convert key type to memory. // Convert key type to memory.
keyType = TypeProvider::withLocationIfReference(DataLocation::Memory, keyType); keyType = TypeProvider::withLocationIfReference(DataLocation::Memory, keyType);
// Convert value type to storage reference. // Convert value type to storage reference.
valueType = TypeProvider::withLocationIfReference(DataLocation::Storage, valueType); valueType = TypeProvider::withLocationIfReference(DataLocation::Storage, valueType);
_mapping.annotation().type = TypeProvider::mapping(keyType, valueType); _mapping.annotation().type = TypeProvider::mapping(keyType, keyName, valueType, valueName);
// Check if parameter names are conflicting.
if (!keyName.empty())
{
auto childMappingType = dynamic_cast<MappingType const*>(valueType);
ASTString currentValueName = valueName;
bool loop = true;
while (loop)
{
bool isError = false;
// Value type is a mapping.
if (childMappingType)
{
// Compare top mapping's key name with child mapping's key name.
ASTString childKeyName = childMappingType->keyName();
if (keyName == childKeyName)
isError = true;
auto valueType = childMappingType->valueType();
currentValueName = childMappingType->valueName();
childMappingType = dynamic_cast<MappingType const*>(valueType);
}
else
{
// Compare top mapping's key name with the value name.
if (keyName == currentValueName)
isError = true;
loop = false; // We arrived at the end of mapping recursion.
}
// Report error.
if (isError)
{
m_errorReporter.declarationError(
1809_error,
_mapping.location(),
"Conflicting parameter name \"" + keyName + "\" in mapping."
);
}
}
}
} }
void DeclarationTypeChecker::endVisit(ArrayTypeName const& _typeName) void DeclarationTypeChecker::endVisit(ArrayTypeName const& _typeName)

View File

@ -1427,18 +1427,29 @@ public:
int64_t _id, int64_t _id,
SourceLocation const& _location, SourceLocation const& _location,
ASTPointer<TypeName> _keyType, ASTPointer<TypeName> _keyType,
ASTPointer<TypeName> _valueType ASTPointer<ASTString> _keyName,
ASTPointer<TypeName> _valueType,
ASTPointer<ASTString> _valueName
): ):
TypeName(_id, _location), m_keyType(std::move(_keyType)), m_valueType(std::move(_valueType)) {} TypeName(_id, _location),
m_keyType(std::move(_keyType)),
m_keyName(std::move(_keyName)),
m_valueType(std::move(_valueType)),
m_valueName(std::move(_valueName))
{}
void accept(ASTVisitor& _visitor) override; void accept(ASTVisitor& _visitor) override;
void accept(ASTConstVisitor& _visitor) const override; void accept(ASTConstVisitor& _visitor) const override;
TypeName const& keyType() const { return *m_keyType; } TypeName const& keyType() const { return *m_keyType; }
ASTString keyName() const { return *m_keyName; }
TypeName const& valueType() const { return *m_valueType; } TypeName const& valueType() const { return *m_valueType; }
ASTString valueName() const { return *m_valueName; }
private: private:
ASTPointer<TypeName> m_keyType; ASTPointer<TypeName> m_keyType;
ASTPointer<ASTString> m_keyName;
ASTPointer<TypeName> m_valueType; ASTPointer<TypeName> m_valueType;
ASTPointer<ASTString> m_valueName;
}; };
/** /**

View File

@ -598,7 +598,9 @@ bool ASTJsonExporter::visit(Mapping const& _node)
{ {
setJsonNode(_node, "Mapping", { setJsonNode(_node, "Mapping", {
make_pair("keyType", toJson(_node.keyType())), make_pair("keyType", toJson(_node.keyType())),
make_pair("keyName", _node.keyName()),
make_pair("valueType", toJson(_node.valueType())), make_pair("valueType", toJson(_node.valueType())),
make_pair("valueName", _node.valueName()),
make_pair("typeDescriptions", typePointerToJson(_node.annotation().type, true)) make_pair("typeDescriptions", typePointerToJson(_node.annotation().type, true))
}); });
return false; return false;

View File

@ -648,7 +648,9 @@ ASTPointer<Mapping> ASTJsonImporter::createMapping(Json::Value const& _node)
return createASTNode<Mapping>( return createASTNode<Mapping>(
_node, _node,
convertJsonToASTNode<TypeName>(member(_node, "keyType")), convertJsonToASTNode<TypeName>(member(_node, "keyType")),
convertJsonToASTNode<TypeName>(member(_node, "valueType")) memberAsASTString(_node, "keyName"),
convertJsonToASTNode<TypeName>(member(_node, "valueType")),
memberAsASTString(_node, "valueName")
); );
} }

View File

@ -571,9 +571,9 @@ MagicType const* TypeProvider::meta(Type const* _type)
return createAndGet<MagicType>(_type); return createAndGet<MagicType>(_type);
} }
MappingType const* TypeProvider::mapping(Type const* _keyType, Type const* _valueType) MappingType const* TypeProvider::mapping(Type const* _keyType, ASTString _keyName, Type const* _valueType, ASTString _valueName)
{ {
return createAndGet<MappingType>(_keyType, _valueType); return createAndGet<MappingType>(_keyType, _keyName, _valueType, _valueName);
} }
UserDefinedValueType const* TypeProvider::userDefinedValueType(UserDefinedValueTypeDefinition const& _definition) UserDefinedValueType const* TypeProvider::userDefinedValueType(UserDefinedValueTypeDefinition const& _definition)

View File

@ -195,7 +195,7 @@ public:
static MagicType const* meta(Type const* _type); static MagicType const* meta(Type const* _type);
static MappingType const* mapping(Type const* _keyType, Type const* _valueType); static MappingType const* mapping(Type const* _keyType, ASTString _keyName, Type const* _valueType, ASTString _valueName);
static UserDefinedValueType const* userDefinedValueType(UserDefinedValueTypeDefinition const& _definition); static UserDefinedValueType const* userDefinedValueType(UserDefinedValueTypeDefinition const& _definition);

View File

@ -2788,14 +2788,16 @@ FunctionType::FunctionType(VariableDeclaration const& _varDecl):
m_declaration(&_varDecl) m_declaration(&_varDecl)
{ {
auto returnType = _varDecl.annotation().type; auto returnType = _varDecl.annotation().type;
ASTString returnName;
while (true) while (true)
{ {
if (auto mappingType = dynamic_cast<MappingType const*>(returnType)) if (auto mappingType = dynamic_cast<MappingType const*>(returnType))
{ {
m_parameterTypes.push_back(mappingType->keyType()); m_parameterTypes.push_back(mappingType->keyType());
m_parameterNames.emplace_back(""); m_parameterNames.push_back(mappingType->keyName());
returnType = mappingType->valueType(); returnType = mappingType->valueType();
returnName = mappingType->valueName();
} }
else if (auto arrayType = dynamic_cast<ArrayType const*>(returnType)) else if (auto arrayType = dynamic_cast<ArrayType const*>(returnType))
{ {
@ -2834,7 +2836,7 @@ FunctionType::FunctionType(VariableDeclaration const& _varDecl):
DataLocation::Memory, DataLocation::Memory,
returnType returnType
)); ));
m_returnParameterNames.emplace_back(""); m_returnParameterNames.emplace_back(returnName);
} }
solAssert( solAssert(

View File

@ -1510,8 +1510,8 @@ private:
class MappingType: public CompositeType class MappingType: public CompositeType
{ {
public: public:
MappingType(Type const* _keyType, Type const* _valueType): MappingType(Type const* _keyType, ASTString _keyName, Type const* _valueType, ASTString _valueName):
m_keyType(_keyType), m_valueType(_valueType) {} m_keyType(_keyType), m_keyName(_keyName), m_valueType(_valueType), m_valueName(_valueName) {}
Category category() const override { return Category::Mapping; } Category category() const override { return Category::Mapping; }
@ -1531,14 +1531,18 @@ public:
std::vector<std::tuple<std::string, Type const*>> makeStackItems() const override; std::vector<std::tuple<std::string, Type const*>> makeStackItems() const override;
Type const* keyType() const { return m_keyType; } Type const* keyType() const { return m_keyType; }
ASTString keyName() const { return m_keyName; }
Type const* valueType() const { return m_valueType; } Type const* valueType() const { return m_valueType; }
ASTString valueName() const { return m_valueName; }
protected: protected:
std::vector<Type const*> decomposition() const override { return {m_valueType}; } std::vector<Type const*> decomposition() const override { return {m_valueType}; }
private: private:
Type const* m_keyType; Type const* m_keyType;
ASTString m_keyName;
Type const* m_valueType; Type const* m_valueType;
ASTString m_valueName;
}; };
/** /**

View File

@ -1187,11 +1187,21 @@ ASTPointer<Mapping> Parser::parseMapping()
} }
else else
fatalParserError(1005_error, "Expected elementary type name or identifier for mapping key type"); fatalParserError(1005_error, "Expected elementary type name or identifier for mapping key type");
ASTPointer<ASTString> keyName;
if (m_scanner->currentToken() == Token::Identifier)
keyName = getLiteralAndAdvance();
else
keyName = make_shared<ASTString>("");
expectToken(Token::DoubleArrow); expectToken(Token::DoubleArrow);
ASTPointer<TypeName> valueType = parseTypeName(); ASTPointer<TypeName> valueType = parseTypeName();
ASTPointer<ASTString> valueName;
if (m_scanner->currentToken() == Token::Identifier)
valueName = getLiteralAndAdvance();
else
valueName = make_shared<ASTString>("");
nodeFactory.markEndPosition(); nodeFactory.markEndPosition();
expectToken(Token::RParen); expectToken(Token::RParen);
return nodeFactory.createNode<Mapping>(keyType, valueType); return nodeFactory.createNode<Mapping>(keyType, keyName, valueType, valueName);
} }
ASTPointer<ParameterList> Parser::parseParameterList( ASTPointer<ParameterList> Parser::parseParameterList(

View File

@ -0,0 +1,77 @@
contract test {
mapping(address owner => mapping(address spender => uint value)) public allowance;
mapping(bytes32 => address sender) public commits;
mapping(bytes32 => bytes32) public something;
}
// ----
// :test
// [
// {
// "inputs":
// [
// {
// "internalType": "address",
// "name": "owner",
// "type": "address"
// },
// {
// "internalType": "address",
// "name": "spender",
// "type": "address"
// }
// ],
// "name": "allowance",
// "outputs":
// [
// {
// "internalType": "uint256",
// "name": "value",
// "type": "uint256"
// }
// ],
// "stateMutability": "view",
// "type": "function"
// },
// {
// "inputs":
// [
// {
// "internalType": "bytes32",
// "name": "",
// "type": "bytes32"
// }
// ],
// "name": "commits",
// "outputs":
// [
// {
// "internalType": "address",
// "name": "sender",
// "type": "address"
// }
// ],
// "stateMutability": "view",
// "type": "function"
// },
// {
// "inputs":
// [
// {
// "internalType": "bytes32",
// "name": "",
// "type": "bytes32"
// }
// ],
// "name": "something",
// "outputs":
// [
// {
// "internalType": "bytes32",
// "name": "",
// "type": "bytes32"
// }
// ],
// "stateMutability": "view",
// "type": "function"
// }
// ]

View File

@ -48,6 +48,7 @@
"typeName": "typeName":
{ {
"id": 3, "id": 3,
"keyName": "",
"keyType": "keyType":
{ {
"id": 1, "id": 1,
@ -67,6 +68,7 @@
"typeIdentifier": "t_mapping$_t_address_$_t_address_payable_$", "typeIdentifier": "t_mapping$_t_address_$_t_address_payable_$",
"typeString": "mapping(address => address payable)" "typeString": "mapping(address => address payable)"
}, },
"valueName": "",
"valueType": "valueType":
{ {
"id": 2, "id": 2,

View File

@ -29,6 +29,7 @@
"typeName": "typeName":
{ {
"id": 3, "id": 3,
"keyName": "",
"keyType": "keyType":
{ {
"id": 1, "id": 1,
@ -40,6 +41,7 @@
"nodeType": "Mapping", "nodeType": "Mapping",
"src": "17:35:1", "src": "17:35:1",
"typeDescriptions": {}, "typeDescriptions": {},
"valueName": "",
"valueType": "valueType":
{ {
"id": 2, "id": 2,

View File

@ -79,6 +79,7 @@
"typeName": "typeName":
{ {
"id": 8, "id": 8,
"keyName": "",
"keyType": "keyType":
{ {
"id": 6, "id": 6,
@ -110,6 +111,7 @@
"typeIdentifier": "t_mapping$_t_contract$_C_$19_$_t_bool_$", "typeIdentifier": "t_mapping$_t_contract$_C_$19_$_t_bool_$",
"typeString": "mapping(contract C => bool)" "typeString": "mapping(contract C => bool)"
}, },
"valueName": "",
"valueType": "valueType":
{ {
"id": 7, "id": 7,
@ -144,6 +146,7 @@
"typeName": "typeName":
{ {
"id": 12, "id": 12,
"keyName": "",
"keyType": "keyType":
{ {
"id": 10, "id": 10,
@ -163,6 +166,7 @@
"typeIdentifier": "t_mapping$_t_address_$_t_bool_$", "typeIdentifier": "t_mapping$_t_address_$_t_bool_$",
"typeString": "mapping(address => bool)" "typeString": "mapping(address => bool)"
}, },
"valueName": "",
"valueType": "valueType":
{ {
"id": 11, "id": 11,
@ -197,6 +201,7 @@
"typeName": "typeName":
{ {
"id": 17, "id": 17,
"keyName": "",
"keyType": "keyType":
{ {
"id": 15, "id": 15,
@ -228,6 +233,7 @@
"typeIdentifier": "t_mapping$_t_enum$_E_$4_$_t_bool_$", "typeIdentifier": "t_mapping$_t_enum$_E_$4_$_t_bool_$",
"typeString": "mapping(enum C.E => bool)" "typeString": "mapping(enum C.E => bool)"
}, },
"valueName": "",
"valueType": "valueType":
{ {
"id": 16, "id": 16,

View File

@ -60,6 +60,7 @@
"typeName": "typeName":
{ {
"id": 8, "id": 8,
"keyName": "",
"keyType": "keyType":
{ {
"id": 6, "id": 6,
@ -81,6 +82,7 @@
"nodeType": "Mapping", "nodeType": "Mapping",
"src": "40:18:1", "src": "40:18:1",
"typeDescriptions": {}, "typeDescriptions": {},
"valueName": "",
"valueType": "valueType":
{ {
"id": 7, "id": 7,
@ -106,6 +108,7 @@
"typeName": "typeName":
{ {
"id": 12, "id": 12,
"keyName": "",
"keyType": "keyType":
{ {
"id": 10, "id": 10,
@ -117,6 +120,7 @@
"nodeType": "Mapping", "nodeType": "Mapping",
"src": "66:24:1", "src": "66:24:1",
"typeDescriptions": {}, "typeDescriptions": {},
"valueName": "",
"valueType": "valueType":
{ {
"id": 11, "id": 11,
@ -142,6 +146,7 @@
"typeName": "typeName":
{ {
"id": 17, "id": 17,
"keyName": "",
"keyType": "keyType":
{ {
"id": 15, "id": 15,
@ -163,6 +168,7 @@
"nodeType": "Mapping", "nodeType": "Mapping",
"src": "98:18:1", "src": "98:18:1",
"typeDescriptions": {}, "typeDescriptions": {},
"valueName": "",
"valueType": "valueType":
{ {
"id": 16, "id": 16,

View File

@ -287,6 +287,7 @@
"typeName": "typeName":
{ {
"id": 25, "id": 25,
"keyName": "",
"keyType": "keyType":
{ {
"id": 22, "id": 22,
@ -318,6 +319,7 @@
"typeIdentifier": "t_mapping$_t_userDefinedValueType$_MyAddress_$18_$_t_userDefinedValueType$_MyUInt_$20_$", "typeIdentifier": "t_mapping$_t_userDefinedValueType$_MyAddress_$18_$_t_userDefinedValueType$_MyUInt_$20_$",
"typeString": "mapping(C.MyAddress => C.MyUInt)" "typeString": "mapping(C.MyAddress => C.MyUInt)"
}, },
"valueName": "",
"valueType": "valueType":
{ {
"id": 24, "id": 24,

View File

@ -213,6 +213,7 @@
"typeName": "typeName":
{ {
"id": 25, "id": 25,
"keyName": "",
"keyType": "keyType":
{ {
"id": 22, "id": 22,
@ -234,6 +235,7 @@
"nodeType": "Mapping", "nodeType": "Mapping",
"src": "169:28:1", "src": "169:28:1",
"typeDescriptions": {}, "typeDescriptions": {},
"valueName": "",
"valueType": "valueType":
{ {
"id": 24, "id": 24,

View File

@ -97,12 +97,16 @@ BOOST_AUTO_TEST_CASE(storage_layout_mapping)
{"first", TypeProvider::fromElementaryTypeName("uint128")}, {"first", TypeProvider::fromElementaryTypeName("uint128")},
{"second", TypeProvider::mapping( {"second", TypeProvider::mapping(
TypeProvider::fromElementaryTypeName("uint8"), TypeProvider::fromElementaryTypeName("uint8"),
TypeProvider::fromElementaryTypeName("uint8") "",
TypeProvider::fromElementaryTypeName("uint8"),
""
)}, )},
{"third", TypeProvider::fromElementaryTypeName("uint16")}, {"third", TypeProvider::fromElementaryTypeName("uint16")},
{"final", TypeProvider::mapping( {"final", TypeProvider::mapping(
TypeProvider::fromElementaryTypeName("uint8"), TypeProvider::fromElementaryTypeName("uint8"),
TypeProvider::fromElementaryTypeName("uint8") "",
TypeProvider::fromElementaryTypeName("uint8"),
""
)}, )},
})); }));
BOOST_REQUIRE_EQUAL(u256(4), members.storageSize()); BOOST_REQUIRE_EQUAL(u256(4), members.storageSize());
@ -199,8 +203,8 @@ BOOST_AUTO_TEST_CASE(type_identifiers)
FunctionType metaFun(TypePointers{keccak256fun}, TypePointers{s.type()}, strings{""}, strings{""}); FunctionType metaFun(TypePointers{keccak256fun}, TypePointers{s.type()}, strings{""}, strings{""});
BOOST_CHECK_EQUAL(metaFun.identifier(), "t_function_internal_nonpayable$_t_function_keccak256_nonpayable$__$returns$__$_$returns$_t_type$_t_struct$_Struct_$3_storage_ptr_$_$"); BOOST_CHECK_EQUAL(metaFun.identifier(), "t_function_internal_nonpayable$_t_function_keccak256_nonpayable$__$returns$__$_$returns$_t_type$_t_struct$_Struct_$3_storage_ptr_$_$");
Type const* m = TypeProvider::mapping(TypeProvider::fromElementaryTypeName("bytes32"), s.type()); Type const* m = TypeProvider::mapping(TypeProvider::fromElementaryTypeName("bytes32"), "", s.type(), "");
MappingType m2(TypeProvider::fromElementaryTypeName("uint64"), m); MappingType m2(TypeProvider::fromElementaryTypeName("uint64"), "", m, "");
BOOST_CHECK_EQUAL(m2.identifier(), "t_mapping$_t_uint64_$_t_mapping$_t_bytes32_$_t_type$_t_struct$_Struct_$3_storage_ptr_$_$_$"); BOOST_CHECK_EQUAL(m2.identifier(), "t_mapping$_t_uint64_$_t_mapping$_t_bytes32_$_t_type$_t_struct$_Struct_$3_storage_ptr_$_$_$");
// TypeType is tested with contract // TypeType is tested with contract

View File

@ -10,4 +10,6 @@ contract Error2 {
mapping (address => uint balances; // missing ) before "balances" mapping (address => uint balances; // missing ) before "balances"
} }
// ---- // ----
// ParserError 6635: (417-425): Expected ')' but got identifier // ParserError 6635: (425-426): Expected ')' but got ';'
// ParserError 6635: (425-426): Expected identifier but got ';'
// ParserError 6635: (458-459): Expected ';' but got '}'

View File

@ -17,7 +17,8 @@ contract SendCoin {
} }
// ---- // ----
// ParserError 6635: (212-220): Expected ')' but got identifier // ParserError 6635: (235-236): Expected identifier but got '}'
// ParserError 6635: (220-221): Expected ';' but got ')' // ParserError 6635: (276-284): Expected ';' but got 'contract'
// ParserError 9182: (220-221): Function, variable, struct or modifier declaration expected. // ParserError 9182: (276-284): Function, variable, struct or modifier declaration expected.
// Warning 3796: (235-236): Recovered in ContractDefinition at '}'. // Warning 3796: (572-573): Recovered in ContractDefinition at '}'.
// ParserError 7858: (574-575): Expected pragma, import directive or contract/interface/library/struct/enum/constant/function/error definition.

View File

@ -0,0 +1,9 @@
contract C {
mapping(uint a => mapping(uint b => uint c)) public x;
constructor() {
x[1][2] = 3;
}
}
// ----
// x(uint256,uint256): 1, 2 -> 3
// x(uint256,uint256): 0, 0 -> 0

View File

@ -13,3 +13,4 @@ contract Thing is IThing {
mapping(uint256=>Value) public override value; mapping(uint256=>Value) public override value;
} }
// ----

View File

@ -0,0 +1,4 @@
contract test {
mapping(address user => bytes32 ipfs) names;
}
// ----

View File

@ -0,0 +1,4 @@
contract test {
mapping(address => bytes32 ipfs) names;
}
// ----

View File

@ -0,0 +1,4 @@
contract test {
mapping(address user => bytes32) names;
}
// ----

View File

@ -0,0 +1,4 @@
contract test {
mapping(address owner => mapping(address spender => bytes32[] notes)) names;
}
// ----

View File

@ -0,0 +1,5 @@
contract test {
mapping(address uint => bytes32 ipfs) names;
}
// ----
// ParserError 2314: (36-40): Expected '=>' but got 'uint'

View File

@ -0,0 +1,4 @@
contract test {
mapping(address owner => bytes32[] note) notes;
}
// ----

View File

@ -0,0 +1,4 @@
contract test {
mapping(address => mapping(address => address) hello) world;
}
// ----

View File

@ -0,0 +1,5 @@
contract test {
address owner;
mapping(address owner => bytes32 ipfs) names;
}
// ----

View File

@ -0,0 +1,5 @@
contract test {
mapping(address owner => address owner) owner;
}
// ----
// DeclarationError 1809: (20-59): Conflicting parameter name "owner" in mapping.

View File

@ -0,0 +1,7 @@
contract test {
mapping(address owner => mapping(address owner => address owner)) owner;
}
// ----
// DeclarationError 1809: (45-84): Conflicting parameter name "owner" in mapping.
// DeclarationError 1809: (20-85): Conflicting parameter name "owner" in mapping.
// DeclarationError 1809: (20-85): Conflicting parameter name "owner" in mapping.

View File

@ -0,0 +1,5 @@
contract test {
mapping(address owner => mapping(address owner => address hello)) world;
}
// ----
// DeclarationError 1809: (20-85): Conflicting parameter name "owner" in mapping.

View File

@ -0,0 +1,5 @@
contract test {
mapping(address owner => mapping(address hello => address owner)) world;
}
// ----
// DeclarationError 1809: (20-85): Conflicting parameter name "owner" in mapping.

View File

@ -0,0 +1,5 @@
contract test {
mapping(address hello => mapping(address owner => address owner)) world;
}
// ----
// DeclarationError 1809: (45-84): Conflicting parameter name "owner" in mapping.

View File

@ -0,0 +1,6 @@
contract test {
function _main(mapping(uint name1 => uint name2) storage map) internal {
map[1] = 2;
}
}
// ----

View File

@ -0,0 +1,6 @@
contract test {
function _main(mapping(uint name1 => uint) storage map) internal {
map[1] = 2;
}
}
// ----

View File

@ -0,0 +1,6 @@
contract test {
function _main(mapping(uint => uint name2) storage map) internal {
map[1] = 2;
}
}
// ----

View File

@ -0,0 +1,6 @@
contract test {
function _main(mapping(uint name1 => mapping(uint name2 => uint name3) name4) storage map) internal {
map[1][2] = 3;
}
}
// ----

View File

@ -0,0 +1,6 @@
contract test {
function _main(mapping(uint name1 => uint[] name2) storage map) internal {
map[1].push(2);
}
}
// ----

View File

@ -0,0 +1,7 @@
contract test {
function _main(mapping(uint nameSame => mapping(uint name2 => mapping(uint nameSame => uint name3) name4) name5) storage map) internal {
map[1][2][3] = 4;
}
}
// ----
// DeclarationError 1809: (35-132): Conflicting parameter name "nameSame" in mapping.

View File

@ -0,0 +1,6 @@
contract test {
function _main(mapping(uint name1 => mapping(uint name2 => mapping(uint name3 => uint name4) name5) name6) storage map) internal {
map[1][2][3] = 4;
}
}
// ----

View File

@ -0,0 +1,4 @@
contract test {
function(mapping(uint name1 => uint name2) storage) internal stateVariableName;
}
// ----

View File

@ -0,0 +1,4 @@
contract test {
function(mapping(uint name1 => uint) storage) internal stateVariableName;
}
// ----

View File

@ -0,0 +1,4 @@
contract test {
function(mapping(uint => uint name2) storage) internal stateVariableName;
}
// ----

View File

@ -0,0 +1,4 @@
contract test {
function(mapping(uint name1 => mapping(uint name2 => uint name3) name4) storage) internal stateVariableName;
}
// ----

View File

@ -0,0 +1,4 @@
contract test {
function(mapping(uint name1 => uint[] name2) storage) internal stateVariableName;
}
// ----

View File

@ -0,0 +1,5 @@
contract test {
function(mapping(uint nameSame => mapping(uint name2 => mapping(uint nameSame => uint name3) name4) name5) storage) internal stateVariableName;
}
// ----
// DeclarationError 1809: (29-126): Conflicting parameter name "nameSame" in mapping.

View File

@ -0,0 +1,4 @@
contract test {
function(mapping(uint name1 => mapping(uint name2 => mapping(uint name3 => uint name4) name5) name6) storage) internal stateVariableName;
}
// ----

View File

@ -0,0 +1,9 @@
contract test {
mapping(uint name1 => uint name2) map;
function main() external {
mapping(uint name3 => uint name4) storage _map = map;
_map[1] = 2;
}
}
// ----

View File

@ -0,0 +1,9 @@
contract test {
mapping(uint name1 => uint) map;
function main() external {
mapping(uint => uint name4) storage _map = map;
_map[1] = 2;
}
}
// ----

View File

@ -0,0 +1,9 @@
contract test {
mapping(uint => uint name2) map;
function main() external {
mapping(uint name3 => uint) storage _map = map;
_map[1] = 2;
}
}
// ----

View File

@ -0,0 +1,9 @@
contract test {
mapping(uint name1 => mapping(uint name2 => uint name3) name4) map;
function main() external {
mapping(uint name5 => uint name6) storage _map = map[1];
_map[1] = 2;
}
}
// ----

View File

@ -0,0 +1,9 @@
contract test {
mapping(uint name1 => uint[] name4) map;
function main() external {
mapping(uint name5 => uint[] name6) storage _map = map;
_map[1].push(2);
}
}
// ----

View File

@ -0,0 +1,10 @@
contract test {
mapping(uint name1 => mapping(uint name2 => uint name3) name4) map;
function main() external {
mapping(uint nameSame => mapping(uint name2 => uint nameSame) name4) storage _map = map;
_map[1][2] = 3;
}
}
// ----
// DeclarationError 1809: (128-196): Conflicting parameter name "nameSame" in mapping.

View File

@ -0,0 +1,11 @@
contract test {
mapping(uint nameSame => mapping(uint name1 => mapping(uint nameSame => uint name3) name6) name4) map;
function main() external {
mapping(uint nameSame => mapping(uint name1 => mapping(uint nameSame => uint name3) name6) name4) storage _map = map;
_map[1][2][3] = 4;
}
}
// ----
// DeclarationError 1809: (20-117): Conflicting parameter name "nameSame" in mapping.
// DeclarationError 1809: (163-260): Conflicting parameter name "nameSame" in mapping.

View File

@ -0,0 +1,9 @@
contract test {
mapping(uint name1 => mapping(uint name2 => mapping(uint name3 => uint name4) name5) name6) map;
function main() external {
mapping(uint name1 => mapping(uint name2 => mapping(uint name3 => uint name4) name5) name6) storage _map = map;
_map[1][2][3] = 4;
}
}
// ----

View File

@ -0,0 +1,4 @@
contract test {
mapping(address owner => mapping(address spender => bytes32 note)) names;
}
// ----

View File

@ -0,0 +1,4 @@
contract test {
mapping(address => mapping(address spender => bytes32 note)) names;
}
// ----

View File

@ -0,0 +1,4 @@
contract test {
mapping(address owner => mapping(address => bytes32 note)) names;
}
// ----

View File

@ -0,0 +1,4 @@
contract test {
mapping(address owner => mapping(address spender => bytes32)) names;
}
// ----

View File

@ -0,0 +1,5 @@
contract test {
mapping(address owner => mapping(address spender => bytes32 note));
}
// ----
// ParserError 2314: (86-87): Expected identifier but got ';'

View File

@ -0,0 +1,5 @@
contract test {
mapping(uint nameSame => mapping(uint name1 => mapping(uint nameSame => uint name2) name3) name4) name5;
}
// ----
// DeclarationError 1809: (20-117): Conflicting parameter name "nameSame" in mapping.

View File

@ -0,0 +1,5 @@
contract test {
mapping(uint nameSame => mapping(uint name1 => mapping(uint nameSame => uint name3) name6) name4) public name5;
}
// ----
// DeclarationError 1809: (20-117): Conflicting parameter name "nameSame" in mapping.

View File

@ -0,0 +1,4 @@
contract test {
mapping(uint name1 => mapping(uint name2 => mapping(uint name3 => uint name4) name5) name6) public name7;
}
// ----

View File

@ -0,0 +1,6 @@
contract test {
struct Person {
mapping(uint phone => uint calls) friends;
}
}
// ----

View File

@ -0,0 +1,6 @@
contract test {
struct Person {
mapping(uint phone => uint) friends;
}
}
// ----

View File

@ -0,0 +1,6 @@
contract test {
struct Person {
mapping(uint => uint calls) friends;
}
}
// ----

View File

@ -0,0 +1,6 @@
contract test {
struct Person {
mapping(uint phone => mapping(uint call => uint time) callTimes) friends;
}
}
// ----

View File

@ -0,0 +1,6 @@
contract test {
struct Person {
mapping(uint phone => uint[] calls) friends;
}
}
// ----

View File

@ -0,0 +1,7 @@
contract test {
struct Person {
mapping(uint nameSame => mapping(uint name1 => mapping(uint nameSame => uint name2) name3) name4) name5;
}
}
// ----
// DeclarationError 1809: (44-141): Conflicting parameter name "nameSame" in mapping.

View File

@ -0,0 +1,6 @@
contract test {
struct Person {
mapping(uint name1 => mapping(uint name2 => mapping(uint name3 => uint name4) name5) name6) name7;
}
}
// ----

View File

@ -2,3 +2,4 @@ type MyInt is int;
contract C { contract C {
mapping(MyInt => int) m; mapping(MyInt => int) m;
} }
// ----