mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Syntax for meta type information.
This commit is contained in:
parent
44237211d1
commit
2fcfb216b5
@ -180,6 +180,7 @@ namespace langutil
|
|||||||
K(CallData, "calldata", 0) \
|
K(CallData, "calldata", 0) \
|
||||||
K(Struct, "struct", 0) \
|
K(Struct, "struct", 0) \
|
||||||
K(Throw, "throw", 0) \
|
K(Throw, "throw", 0) \
|
||||||
|
K(Type, "type", 0) \
|
||||||
K(Using, "using", 0) \
|
K(Using, "using", 0) \
|
||||||
K(Var, "var", 0) \
|
K(Var, "var", 0) \
|
||||||
K(View, "view", 0) \
|
K(View, "view", 0) \
|
||||||
@ -256,7 +257,6 @@ namespace langutil
|
|||||||
K(Supports, "supports", 0) \
|
K(Supports, "supports", 0) \
|
||||||
K(Switch, "switch", 0) \
|
K(Switch, "switch", 0) \
|
||||||
K(Try, "try", 0) \
|
K(Try, "try", 0) \
|
||||||
K(Type, "type", 0) \
|
|
||||||
K(Typedef, "typedef", 0) \
|
K(Typedef, "typedef", 0) \
|
||||||
K(TypeOf, "typeof", 0) \
|
K(TypeOf, "typeof", 0) \
|
||||||
K(Unchecked, "unchecked", 0) \
|
K(Unchecked, "unchecked", 0) \
|
||||||
|
@ -61,7 +61,14 @@ m_magicVariables(vector<shared_ptr<MagicVariableDeclaration const>>{
|
|||||||
make_shared<MagicVariableDeclaration>("sha256", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::SHA256, false, StateMutability::Pure)),
|
make_shared<MagicVariableDeclaration>("sha256", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::SHA256, false, StateMutability::Pure)),
|
||||||
make_shared<MagicVariableDeclaration>("sha3", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::KECCAK256, false, StateMutability::Pure)),
|
make_shared<MagicVariableDeclaration>("sha3", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::KECCAK256, false, StateMutability::Pure)),
|
||||||
make_shared<MagicVariableDeclaration>("suicide", make_shared<FunctionType>(strings{"address payable"}, strings{}, FunctionType::Kind::Selfdestruct)),
|
make_shared<MagicVariableDeclaration>("suicide", make_shared<FunctionType>(strings{"address payable"}, strings{}, FunctionType::Kind::Selfdestruct)),
|
||||||
make_shared<MagicVariableDeclaration>("tx", make_shared<MagicType>(MagicType::Kind::Transaction))
|
make_shared<MagicVariableDeclaration>("tx", make_shared<MagicType>(MagicType::Kind::Transaction)),
|
||||||
|
make_shared<MagicVariableDeclaration>("type", make_shared<FunctionType>(
|
||||||
|
strings{"address"} /* accepts any contract type, handled by the type checker */,
|
||||||
|
strings{} /* returns a MagicType, handled by the type checker */,
|
||||||
|
FunctionType::Kind::MetaType,
|
||||||
|
false,
|
||||||
|
StateMutability::Pure
|
||||||
|
)),
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -199,6 +199,38 @@ TypePointers TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall c
|
|||||||
return components;
|
return components;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TypePointers TypeChecker::typeCheckMetaTypeFunctionAndRetrieveReturnType(FunctionCall const& _functionCall)
|
||||||
|
{
|
||||||
|
vector<ASTPointer<Expression const>> arguments = _functionCall.arguments();
|
||||||
|
if (arguments.size() != 1)
|
||||||
|
{
|
||||||
|
m_errorReporter.typeError(
|
||||||
|
_functionCall.location(),
|
||||||
|
"This function takes one argument, but " +
|
||||||
|
toString(arguments.size()) +
|
||||||
|
" were provided."
|
||||||
|
);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
TypePointer firstArgType = type(*arguments.front());
|
||||||
|
if (
|
||||||
|
firstArgType->category() != Type::Category::TypeType ||
|
||||||
|
dynamic_cast<TypeType const&>(*firstArgType).actualType()->category() != TypeType::Category::Contract
|
||||||
|
)
|
||||||
|
{
|
||||||
|
m_errorReporter.typeError(
|
||||||
|
arguments.front()->location(),
|
||||||
|
"Invalid type for argument in function call. "
|
||||||
|
"Contract type required, but " +
|
||||||
|
type(*arguments.front())->toString(true) +
|
||||||
|
" provided."
|
||||||
|
);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {MagicType::metaType(dynamic_cast<TypeType const&>(*firstArgType).actualType())};
|
||||||
|
}
|
||||||
|
|
||||||
void TypeChecker::endVisit(InheritanceSpecifier const& _inheritance)
|
void TypeChecker::endVisit(InheritanceSpecifier const& _inheritance)
|
||||||
{
|
{
|
||||||
auto base = dynamic_cast<ContractDefinition const*>(&dereference(_inheritance.name()));
|
auto base = dynamic_cast<ContractDefinition const*>(&dereference(_inheritance.name()));
|
||||||
@ -1822,6 +1854,9 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
|
|||||||
returnTypes = functionType->returnParameterTypes();
|
returnTypes = functionType->returnParameterTypes();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case FunctionType::Kind::MetaType:
|
||||||
|
returnTypes = typeCheckMetaTypeFunctionAndRetrieveReturnType(_functionCall);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
typeCheckFunctionCall(_functionCall, functionType);
|
typeCheckFunctionCall(_functionCall, functionType);
|
||||||
@ -2062,8 +2097,13 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
|||||||
if (tt->actualType()->category() == Type::Category::Enum)
|
if (tt->actualType()->category() == Type::Category::Enum)
|
||||||
annotation.isPure = true;
|
annotation.isPure = true;
|
||||||
if (auto magicType = dynamic_cast<MagicType const*>(exprType.get()))
|
if (auto magicType = dynamic_cast<MagicType const*>(exprType.get()))
|
||||||
|
{
|
||||||
if (magicType->kind() == MagicType::Kind::ABI)
|
if (magicType->kind() == MagicType::Kind::ABI)
|
||||||
annotation.isPure = true;
|
annotation.isPure = true;
|
||||||
|
else if (magicType->kind() == MagicType::Kind::MetaType)
|
||||||
|
if (memberName == "creationCode" || memberName == "runtimeCode")
|
||||||
|
annotation.isPure = true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -81,6 +81,8 @@ private:
|
|||||||
bool _abiEncoderV2
|
bool _abiEncoderV2
|
||||||
);
|
);
|
||||||
|
|
||||||
|
TypePointers typeCheckMetaTypeFunctionAndRetrieveReturnType(FunctionCall const& _functionCall);
|
||||||
|
|
||||||
/// Performs type checks and determines result types for type conversion FunctionCall nodes.
|
/// Performs type checks and determines result types for type conversion FunctionCall nodes.
|
||||||
TypePointer typeCheckTypeConversionAndRetrieveReturnType(
|
TypePointer typeCheckTypeConversionAndRetrieveReturnType(
|
||||||
FunctionCall const& _functionCall
|
FunctionCall const& _functionCall
|
||||||
|
@ -338,7 +338,9 @@ void ViewPureChecker::endVisit(MemberAccess const& _memberAccess)
|
|||||||
{MagicType::Kind::ABI, "encodeWithSignature"},
|
{MagicType::Kind::ABI, "encodeWithSignature"},
|
||||||
{MagicType::Kind::Block, "blockhash"},
|
{MagicType::Kind::Block, "blockhash"},
|
||||||
{MagicType::Kind::Message, "data"},
|
{MagicType::Kind::Message, "data"},
|
||||||
{MagicType::Kind::Message, "sig"}
|
{MagicType::Kind::Message, "sig"},
|
||||||
|
{MagicType::Kind::MetaType, "creationCode"},
|
||||||
|
{MagicType::Kind::MetaType, "runtimeCode"}
|
||||||
};
|
};
|
||||||
set<MagicMember> static const payableMembers{
|
set<MagicMember> static const payableMembers{
|
||||||
{MagicType::Kind::Message, "value"}
|
{MagicType::Kind::Message, "value"}
|
||||||
|
@ -2626,6 +2626,7 @@ string FunctionType::richIdentifier() const
|
|||||||
case Kind::ABIEncodeWithSelector: id += "abiencodewithselector"; break;
|
case Kind::ABIEncodeWithSelector: id += "abiencodewithselector"; break;
|
||||||
case Kind::ABIEncodeWithSignature: id += "abiencodewithsignature"; break;
|
case Kind::ABIEncodeWithSignature: id += "abiencodewithsignature"; break;
|
||||||
case Kind::ABIDecode: id += "abidecode"; break;
|
case Kind::ABIDecode: id += "abidecode"; break;
|
||||||
|
case Kind::MetaType: id += "metatype"; break;
|
||||||
}
|
}
|
||||||
id += "_" + stateMutabilityToString(m_stateMutability);
|
id += "_" + stateMutabilityToString(m_stateMutability);
|
||||||
id += identifierList(m_parameterTypes) + "returns" + identifierList(m_returnParameterTypes);
|
id += identifierList(m_parameterTypes) + "returns" + identifierList(m_returnParameterTypes);
|
||||||
@ -3037,7 +3038,8 @@ bool FunctionType::isPure() const
|
|||||||
m_kind == Kind::ABIEncodePacked ||
|
m_kind == Kind::ABIEncodePacked ||
|
||||||
m_kind == Kind::ABIEncodeWithSelector ||
|
m_kind == Kind::ABIEncodeWithSelector ||
|
||||||
m_kind == Kind::ABIEncodeWithSignature ||
|
m_kind == Kind::ABIEncodeWithSignature ||
|
||||||
m_kind == Kind::ABIDecode;
|
m_kind == Kind::ABIDecode ||
|
||||||
|
m_kind == Kind::MetaType;
|
||||||
}
|
}
|
||||||
|
|
||||||
TypePointers FunctionType::parseElementaryTypeVector(strings const& _types)
|
TypePointers FunctionType::parseElementaryTypeVector(strings const& _types)
|
||||||
@ -3305,6 +3307,14 @@ string ModuleType::toString(bool) const
|
|||||||
return string("module \"") + m_sourceUnit.annotation().path + string("\"");
|
return string("module \"") + m_sourceUnit.annotation().path + string("\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shared_ptr<MagicType> MagicType::metaType(TypePointer _type)
|
||||||
|
{
|
||||||
|
solAssert(_type && _type->category() == Type::Category::Contract, "Only contracts supported for now.");
|
||||||
|
auto t = make_shared<MagicType>(Kind::MetaType);
|
||||||
|
t->m_typeArgument = std::move(_type);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
string MagicType::richIdentifier() const
|
string MagicType::richIdentifier() const
|
||||||
{
|
{
|
||||||
switch (m_kind)
|
switch (m_kind)
|
||||||
@ -3317,6 +3327,9 @@ string MagicType::richIdentifier() const
|
|||||||
return "t_magic_transaction";
|
return "t_magic_transaction";
|
||||||
case Kind::ABI:
|
case Kind::ABI:
|
||||||
return "t_magic_abi";
|
return "t_magic_abi";
|
||||||
|
case Kind::MetaType:
|
||||||
|
solAssert(m_typeArgument, "");
|
||||||
|
return "t_magic_meta_type_" + m_typeArgument->richIdentifier();
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@ -3403,12 +3416,27 @@ MemberList::MemberMap MagicType::nativeMembers(ContractDefinition const*) const
|
|||||||
StateMutability::Pure
|
StateMutability::Pure
|
||||||
)}
|
)}
|
||||||
});
|
});
|
||||||
default:
|
case Kind::MetaType:
|
||||||
solAssert(false, "Unknown kind of magic.");
|
{
|
||||||
|
solAssert(
|
||||||
|
m_typeArgument && m_typeArgument->category() == Type::Category::Contract,
|
||||||
|
"Only contracts supported for now"
|
||||||
|
);
|
||||||
|
ContractDefinition const& contract = dynamic_cast<ContractType const&>(*m_typeArgument).contractDefinition();
|
||||||
|
if (contract.annotation().unimplementedFunctions.empty() && contract.constructorIsPublic())
|
||||||
|
return MemberList::MemberMap({
|
||||||
|
{"creationCode", std::make_shared<ArrayType>(DataLocation::Memory)},
|
||||||
|
{"runtimeCode", std::make_shared<ArrayType>(DataLocation::Memory)}
|
||||||
|
});
|
||||||
|
else
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
solAssert(false, "Unknown kind of magic.");
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
string MagicType::toString(bool) const
|
string MagicType::toString(bool _short) const
|
||||||
{
|
{
|
||||||
switch (m_kind)
|
switch (m_kind)
|
||||||
{
|
{
|
||||||
@ -3420,7 +3448,10 @@ string MagicType::toString(bool) const
|
|||||||
return "tx";
|
return "tx";
|
||||||
case Kind::ABI:
|
case Kind::ABI:
|
||||||
return "abi";
|
return "abi";
|
||||||
default:
|
case Kind::MetaType:
|
||||||
solAssert(false, "Unknown kind of magic.");
|
solAssert(m_typeArgument, "");
|
||||||
|
return "type(" + m_typeArgument->toString(_short) + ")";
|
||||||
}
|
}
|
||||||
|
solAssert(false, "Unknown kind of magic.");
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -989,6 +989,7 @@ public:
|
|||||||
ABIEncodeWithSignature,
|
ABIEncodeWithSignature,
|
||||||
ABIDecode,
|
ABIDecode,
|
||||||
GasLeft, ///< gasleft()
|
GasLeft, ///< gasleft()
|
||||||
|
MetaType ///< type(...)
|
||||||
};
|
};
|
||||||
|
|
||||||
Category category() const override { return Category::Function; }
|
Category category() const override { return Category::Function; }
|
||||||
@ -1299,16 +1300,23 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Special type for magic variables (block, msg, tx), similar to a struct but without any reference
|
* Special type for magic variables (block, msg, tx, type(...)), similar to a struct but without any reference.
|
||||||
* (it always references a global singleton by name).
|
|
||||||
*/
|
*/
|
||||||
class MagicType: public Type
|
class MagicType: public Type
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum class Kind { Block, Message, Transaction, ABI };
|
enum class Kind {
|
||||||
|
Block, ///< "block"
|
||||||
|
Message, ///< "msg"
|
||||||
|
Transaction, ///< "tx"
|
||||||
|
ABI, ///< "abi"
|
||||||
|
MetaType ///< "type(...)"
|
||||||
|
};
|
||||||
Category category() const override { return Category::Magic; }
|
Category category() const override { return Category::Magic; }
|
||||||
|
|
||||||
explicit MagicType(Kind _kind): m_kind(_kind) {}
|
explicit MagicType(Kind _kind): m_kind(_kind) {}
|
||||||
|
/// Factory function for meta type
|
||||||
|
static std::shared_ptr<MagicType> metaType(TypePointer _type);
|
||||||
|
|
||||||
TypeResult binaryOperatorResult(Token, TypePointer const&) const override
|
TypeResult binaryOperatorResult(Token, TypePointer const&) const override
|
||||||
{
|
{
|
||||||
@ -1329,6 +1337,9 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
Kind m_kind;
|
Kind m_kind;
|
||||||
|
/// Contract type used for contract metadata magic.
|
||||||
|
TypePointer m_typeArgument;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1107,6 +1107,9 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
case FunctionType::Kind::GasLeft:
|
case FunctionType::Kind::GasLeft:
|
||||||
m_context << Instruction::GAS;
|
m_context << Instruction::GAS;
|
||||||
break;
|
break;
|
||||||
|
case FunctionType::Kind::MetaType:
|
||||||
|
// No code to generate.
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -1551,6 +1551,12 @@ ASTPointer<Expression> Parser::parsePrimaryExpression()
|
|||||||
nodeFactory.markEndPosition();
|
nodeFactory.markEndPosition();
|
||||||
expression = nodeFactory.createNode<Identifier>(getLiteralAndAdvance());
|
expression = nodeFactory.createNode<Identifier>(getLiteralAndAdvance());
|
||||||
break;
|
break;
|
||||||
|
case Token::Type:
|
||||||
|
// Inside expressions "type" is the name of a special, globally-available function.
|
||||||
|
nodeFactory.markEndPosition();
|
||||||
|
m_scanner->next();
|
||||||
|
expression = nodeFactory.createNode<Identifier>(make_shared<ASTString>("type"));
|
||||||
|
break;
|
||||||
case Token::LParen:
|
case Token::LParen:
|
||||||
case Token::LBrack:
|
case Token::LBrack:
|
||||||
{
|
{
|
||||||
|
@ -277,7 +277,7 @@
|
|||||||
"name" : "this",
|
"name" : "this",
|
||||||
"nodeType" : "Identifier",
|
"nodeType" : "Identifier",
|
||||||
"overloadedDeclarations" : [],
|
"overloadedDeclarations" : [],
|
||||||
"referencedDeclaration" : 65,
|
"referencedDeclaration" : 66,
|
||||||
"src" : "217:4:1",
|
"src" : "217:4:1",
|
||||||
"typeDescriptions" :
|
"typeDescriptions" :
|
||||||
{
|
{
|
||||||
|
@ -424,7 +424,7 @@
|
|||||||
[
|
[
|
||||||
null
|
null
|
||||||
],
|
],
|
||||||
"referencedDeclaration" : 65,
|
"referencedDeclaration" : 66,
|
||||||
"type" : "contract C",
|
"type" : "contract C",
|
||||||
"value" : "this"
|
"value" : "this"
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user