aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--liblangutil/Token.h2
-rw-r--r--libsolidity/analysis/GlobalContext.cpp9
-rw-r--r--libsolidity/analysis/TypeChecker.cpp40
-rw-r--r--libsolidity/analysis/TypeChecker.h2
-rw-r--r--libsolidity/analysis/ViewPureChecker.cpp4
-rw-r--r--libsolidity/ast/Types.cpp43
-rw-r--r--libsolidity/ast/Types.h17
-rw-r--r--libsolidity/codegen/ExpressionCompiler.cpp3
-rw-r--r--libsolidity/parsing/Parser.cpp6
-rw-r--r--test/libsolidity/ASTJSON/address_payable.json2
-rw-r--r--test/libsolidity/ASTJSON/address_payable_legacy.json2
11 files changed, 116 insertions, 14 deletions
diff --git a/liblangutil/Token.h b/liblangutil/Token.h
index f832fdf7..b3a1acb1 100644
--- a/liblangutil/Token.h
+++ b/liblangutil/Token.h
@@ -180,6 +180,7 @@ namespace langutil
K(CallData, "calldata", 0) \
K(Struct, "struct", 0) \
K(Throw, "throw", 0) \
+ K(Type, "type", 0) \
K(Using, "using", 0) \
K(Var, "var", 0) \
K(View, "view", 0) \
@@ -256,7 +257,6 @@ namespace langutil
K(Supports, "supports", 0) \
K(Switch, "switch", 0) \
K(Try, "try", 0) \
- K(Type, "type", 0) \
K(Typedef, "typedef", 0) \
K(TypeOf, "typeof", 0) \
K(Unchecked, "unchecked", 0) \
diff --git a/libsolidity/analysis/GlobalContext.cpp b/libsolidity/analysis/GlobalContext.cpp
index cd5fe07d..2276d783 100644
--- a/libsolidity/analysis/GlobalContext.cpp
+++ b/libsolidity/analysis/GlobalContext.cpp
@@ -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>("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>("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
+ )),
})
{
}
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp
index 507a2c94..4cdfcc0c 100644
--- a/libsolidity/analysis/TypeChecker.cpp
+++ b/libsolidity/analysis/TypeChecker.cpp
@@ -199,6 +199,38 @@ TypePointers TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall c
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)
{
auto base = dynamic_cast<ContractDefinition const*>(&dereference(_inheritance.name()));
@@ -1822,6 +1854,9 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
returnTypes = functionType->returnParameterTypes();
break;
}
+ case FunctionType::Kind::MetaType:
+ returnTypes = typeCheckMetaTypeFunctionAndRetrieveReturnType(_functionCall);
+ break;
default:
{
typeCheckFunctionCall(_functionCall, functionType);
@@ -2062,8 +2097,13 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
if (tt->actualType()->category() == Type::Category::Enum)
annotation.isPure = true;
if (auto magicType = dynamic_cast<MagicType const*>(exprType.get()))
+ {
if (magicType->kind() == MagicType::Kind::ABI)
annotation.isPure = true;
+ else if (magicType->kind() == MagicType::Kind::MetaType)
+ if (memberName == "creationCode" || memberName == "runtimeCode")
+ annotation.isPure = true;
+ }
return false;
}
diff --git a/libsolidity/analysis/TypeChecker.h b/libsolidity/analysis/TypeChecker.h
index b60c571a..d5f3645c 100644
--- a/libsolidity/analysis/TypeChecker.h
+++ b/libsolidity/analysis/TypeChecker.h
@@ -81,6 +81,8 @@ private:
bool _abiEncoderV2
);
+ TypePointers typeCheckMetaTypeFunctionAndRetrieveReturnType(FunctionCall const& _functionCall);
+
/// Performs type checks and determines result types for type conversion FunctionCall nodes.
TypePointer typeCheckTypeConversionAndRetrieveReturnType(
FunctionCall const& _functionCall
diff --git a/libsolidity/analysis/ViewPureChecker.cpp b/libsolidity/analysis/ViewPureChecker.cpp
index eb019481..7df7ac17 100644
--- a/libsolidity/analysis/ViewPureChecker.cpp
+++ b/libsolidity/analysis/ViewPureChecker.cpp
@@ -338,7 +338,9 @@ void ViewPureChecker::endVisit(MemberAccess const& _memberAccess)
{MagicType::Kind::ABI, "encodeWithSignature"},
{MagicType::Kind::Block, "blockhash"},
{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{
{MagicType::Kind::Message, "value"}
diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp
index cc978b4a..20859d28 100644
--- a/libsolidity/ast/Types.cpp
+++ b/libsolidity/ast/Types.cpp
@@ -2626,6 +2626,7 @@ string FunctionType::richIdentifier() const
case Kind::ABIEncodeWithSelector: id += "abiencodewithselector"; break;
case Kind::ABIEncodeWithSignature: id += "abiencodewithsignature"; break;
case Kind::ABIDecode: id += "abidecode"; break;
+ case Kind::MetaType: id += "metatype"; break;
}
id += "_" + stateMutabilityToString(m_stateMutability);
id += identifierList(m_parameterTypes) + "returns" + identifierList(m_returnParameterTypes);
@@ -3037,7 +3038,8 @@ bool FunctionType::isPure() const
m_kind == Kind::ABIEncodePacked ||
m_kind == Kind::ABIEncodeWithSelector ||
m_kind == Kind::ABIEncodeWithSignature ||
- m_kind == Kind::ABIDecode;
+ m_kind == Kind::ABIDecode ||
+ m_kind == Kind::MetaType;
}
TypePointers FunctionType::parseElementaryTypeVector(strings const& _types)
@@ -3305,6 +3307,14 @@ string ModuleType::toString(bool) const
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
{
switch (m_kind)
@@ -3317,6 +3327,9 @@ string MagicType::richIdentifier() const
return "t_magic_transaction";
case Kind::ABI:
return "t_magic_abi";
+ case Kind::MetaType:
+ solAssert(m_typeArgument, "");
+ return "t_magic_meta_type_" + m_typeArgument->richIdentifier();
}
return "";
}
@@ -3403,12 +3416,27 @@ MemberList::MemberMap MagicType::nativeMembers(ContractDefinition const*) const
StateMutability::Pure
)}
});
- default:
- solAssert(false, "Unknown kind of magic.");
+ case Kind::MetaType:
+ {
+ 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)
{
@@ -3420,7 +3448,10 @@ string MagicType::toString(bool) const
return "tx";
case Kind::ABI:
return "abi";
- default:
- solAssert(false, "Unknown kind of magic.");
+ case Kind::MetaType:
+ solAssert(m_typeArgument, "");
+ return "type(" + m_typeArgument->toString(_short) + ")";
}
+ solAssert(false, "Unknown kind of magic.");
+ return {};
}
diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h
index bee00661..5427786a 100644
--- a/libsolidity/ast/Types.h
+++ b/libsolidity/ast/Types.h
@@ -989,6 +989,7 @@ public:
ABIEncodeWithSignature,
ABIDecode,
GasLeft, ///< gasleft()
+ MetaType ///< type(...)
};
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
- * (it always references a global singleton by name).
+ * Special type for magic variables (block, msg, tx, type(...)), similar to a struct but without any reference.
*/
class MagicType: public Type
{
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; }
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
{
@@ -1329,6 +1337,9 @@ public:
private:
Kind m_kind;
+ /// Contract type used for contract metadata magic.
+ TypePointer m_typeArgument;
+
};
/**
diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp
index be2709ae..5c2fa6d0 100644
--- a/libsolidity/codegen/ExpressionCompiler.cpp
+++ b/libsolidity/codegen/ExpressionCompiler.cpp
@@ -1107,6 +1107,9 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
case FunctionType::Kind::GasLeft:
m_context << Instruction::GAS;
break;
+ case FunctionType::Kind::MetaType:
+ // No code to generate.
+ break;
}
}
return false;
diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp
index 8a6bc343..35476a76 100644
--- a/libsolidity/parsing/Parser.cpp
+++ b/libsolidity/parsing/Parser.cpp
@@ -1551,6 +1551,12 @@ ASTPointer<Expression> Parser::parsePrimaryExpression()
nodeFactory.markEndPosition();
expression = nodeFactory.createNode<Identifier>(getLiteralAndAdvance());
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::LBrack:
{
diff --git a/test/libsolidity/ASTJSON/address_payable.json b/test/libsolidity/ASTJSON/address_payable.json
index 0f30e8e8..c8b71628 100644
--- a/test/libsolidity/ASTJSON/address_payable.json
+++ b/test/libsolidity/ASTJSON/address_payable.json
@@ -277,7 +277,7 @@
"name" : "this",
"nodeType" : "Identifier",
"overloadedDeclarations" : [],
- "referencedDeclaration" : 65,
+ "referencedDeclaration" : 66,
"src" : "217:4:1",
"typeDescriptions" :
{
diff --git a/test/libsolidity/ASTJSON/address_payable_legacy.json b/test/libsolidity/ASTJSON/address_payable_legacy.json
index dd8a5582..8abebce0 100644
--- a/test/libsolidity/ASTJSON/address_payable_legacy.json
+++ b/test/libsolidity/ASTJSON/address_payable_legacy.json
@@ -424,7 +424,7 @@
[
null
],
- "referencedDeclaration" : 65,
+ "referencedDeclaration" : 66,
"type" : "contract C",
"value" : "this"
},