mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #6222 from ethereum/internal-error-maybe
Disallow internal function types as parameters for public/external library function
This commit is contained in:
commit
51ae865b96
@ -13,6 +13,7 @@ Compiler Features:
|
||||
|
||||
Bugfixes:
|
||||
* Code Generator: Defensively pad memory for ``type(Contract).name`` to multiples of 32.
|
||||
* Type System: Detect and disallow internal function pointers as parameters for public/external library functions, even when they are nested/wrapped in structs, arrays or other types.
|
||||
* Yul Optimizer: Properly determine whether a variable can be eliminated during stack compression pass.
|
||||
|
||||
|
||||
|
@ -213,7 +213,7 @@ void ReferencesResolver::endVisit(FunctionTypeName const& _typeName)
|
||||
for (auto const& t: _typeName.parameterTypes() + _typeName.returnParameterTypes())
|
||||
{
|
||||
solAssert(t->annotation().type, "Type not set for parameter.");
|
||||
if (!t->annotation().type->interfaceType(false))
|
||||
if (!t->annotation().type->interfaceType(false).get())
|
||||
{
|
||||
fatalTypeError(t->location(), "Internal type cannot be used for external function type.");
|
||||
return;
|
||||
|
@ -355,8 +355,16 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
|
||||
{
|
||||
if (!type(var)->canLiveOutsideStorage() && _function.isPublic())
|
||||
m_errorReporter.typeError(var.location(), "Type is required to live outside storage.");
|
||||
if (_function.isPublic() && !(type(var)->interfaceType(isLibraryFunction)))
|
||||
m_errorReporter.fatalTypeError(var.location(), "Internal or recursive type is not allowed for public or external functions.");
|
||||
if (_function.isPublic())
|
||||
{
|
||||
auto iType = type(var)->interfaceType(isLibraryFunction);
|
||||
|
||||
if (!iType.get())
|
||||
{
|
||||
solAssert(!iType.message().empty(), "Expected detailed error message!");
|
||||
m_errorReporter.fatalTypeError(var.location(), iType.message());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (
|
||||
_function.isPublic() &&
|
||||
@ -576,7 +584,7 @@ bool TypeChecker::visit(EventDefinition const& _eventDef)
|
||||
numIndexed++;
|
||||
if (!type(*var)->canLiveOutsideStorage())
|
||||
m_errorReporter.typeError(var->location(), "Type is required to live outside storage.");
|
||||
if (!type(*var)->interfaceType(false))
|
||||
if (!type(*var)->interfaceType(false).get())
|
||||
m_errorReporter.typeError(var->location(), "Internal or recursive type is not allowed as event parameter type.");
|
||||
if (
|
||||
!_eventDef.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2) &&
|
||||
@ -599,7 +607,7 @@ void TypeChecker::endVisit(FunctionTypeName const& _funType)
|
||||
{
|
||||
FunctionType const& fun = dynamic_cast<FunctionType const&>(*_funType.annotation().type);
|
||||
if (fun.kind() == FunctionType::Kind::External)
|
||||
solAssert(fun.interfaceType(false), "External function type uses internal types.");
|
||||
solAssert(fun.interfaceType(false).get(), "External function type uses internal types.");
|
||||
}
|
||||
|
||||
bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
|
@ -1869,7 +1869,7 @@ TypePointer ArrayType::decodingType() const
|
||||
return shared_from_this();
|
||||
}
|
||||
|
||||
TypePointer ArrayType::interfaceType(bool _inLibrary) const
|
||||
TypeResult ArrayType::interfaceType(bool _inLibrary) const
|
||||
{
|
||||
if (_inLibrary && m_interfaceType_library.is_initialized())
|
||||
return *m_interfaceType_library;
|
||||
@ -1877,23 +1877,22 @@ TypePointer ArrayType::interfaceType(bool _inLibrary) const
|
||||
if (!_inLibrary && m_interfaceType.is_initialized())
|
||||
return *m_interfaceType;
|
||||
|
||||
TypePointer result;
|
||||
TypeResult result{TypePointer{}};
|
||||
TypeResult baseInterfaceType = m_baseType->interfaceType(_inLibrary);
|
||||
|
||||
if (_inLibrary && location() == DataLocation::Storage)
|
||||
if (!baseInterfaceType.get())
|
||||
{
|
||||
solAssert(!baseInterfaceType.message().empty(), "Expected detailed error message!");
|
||||
result = baseInterfaceType;
|
||||
}
|
||||
else if (_inLibrary && location() == DataLocation::Storage)
|
||||
result = shared_from_this();
|
||||
else if (m_arrayKind != ArrayKind::Ordinary)
|
||||
result = this->copyForLocation(DataLocation::Memory, true);
|
||||
else if (isDynamicallySized())
|
||||
result = TypePointer{make_shared<ArrayType>(DataLocation::Memory, baseInterfaceType)};
|
||||
else
|
||||
{
|
||||
TypePointer baseExt = m_baseType->interfaceType(_inLibrary);
|
||||
|
||||
if (!baseExt)
|
||||
result = TypePointer();
|
||||
else if (isDynamicallySized())
|
||||
result = make_shared<ArrayType>(DataLocation::Memory, baseExt);
|
||||
else
|
||||
result = make_shared<ArrayType>(DataLocation::Memory, baseExt, m_length);
|
||||
}
|
||||
result = TypePointer{make_shared<ArrayType>(DataLocation::Memory, baseInterfaceType, m_length)};
|
||||
|
||||
if (_inLibrary)
|
||||
m_interfaceType_library = result;
|
||||
@ -2084,7 +2083,7 @@ unsigned StructType::calldataOffsetOfMember(std::string const& _member) const
|
||||
|
||||
bool StructType::isDynamicallyEncoded() const
|
||||
{
|
||||
solAssert(!recursive(), "");
|
||||
solAssert(interfaceType(false).get(), "");
|
||||
for (auto t: memoryMemberTypes())
|
||||
{
|
||||
solAssert(t, "Parameter should have external type.");
|
||||
@ -2135,7 +2134,7 @@ MemberList::MemberMap StructType::nativeMembers(ContractDefinition const*) const
|
||||
return members;
|
||||
}
|
||||
|
||||
TypePointer StructType::interfaceType(bool _inLibrary) const
|
||||
TypeResult StructType::interfaceType(bool _inLibrary) const
|
||||
{
|
||||
if (_inLibrary && m_interfaceType_library.is_initialized())
|
||||
return *m_interfaceType_library;
|
||||
@ -2143,47 +2142,87 @@ TypePointer StructType::interfaceType(bool _inLibrary) const
|
||||
if (!_inLibrary && m_interfaceType.is_initialized())
|
||||
return *m_interfaceType;
|
||||
|
||||
TypePointer result = TypePointer{};
|
||||
TypeResult result{TypePointer{}};
|
||||
|
||||
if (_inLibrary && location() == DataLocation::Storage)
|
||||
result = shared_from_this();
|
||||
else if (recursive())
|
||||
result = TypePointer{};
|
||||
else
|
||||
m_recursive = false;
|
||||
|
||||
auto visitor = [&](
|
||||
StructDefinition const& _struct,
|
||||
CycleDetector<StructDefinition>& _cycleDetector,
|
||||
size_t /*_depth*/
|
||||
)
|
||||
{
|
||||
// Check that all members have interface types.
|
||||
// We pass "false" to canBeUsedExternally (_inLibrary), because this struct will be
|
||||
// passed by value and thus the encoding does not differ, but it will disallow
|
||||
// mappings.
|
||||
// Also return false if at least one struct member does not have a type.
|
||||
// This might happen, for example, if the type of the member does not exist,
|
||||
// which is reported as an error.
|
||||
bool allOkay = true;
|
||||
for (auto const& var: m_struct.members())
|
||||
// Return an error if at least one struct member does not have a type.
|
||||
// This might happen, for example, if the type of the member does not exist.
|
||||
for (ASTPointer<VariableDeclaration> const& variable: _struct.members())
|
||||
{
|
||||
// If the struct member does not have a type return false.
|
||||
// A TypeError is expected in this case.
|
||||
if (!var->annotation().type)
|
||||
if (!variable->annotation().type)
|
||||
{
|
||||
allOkay = false;
|
||||
break;
|
||||
result = TypeResult::err("Invalid type!");
|
||||
return;
|
||||
}
|
||||
if (!var->annotation().type->interfaceType(false))
|
||||
|
||||
Type const* memberType = variable->annotation().type.get();
|
||||
|
||||
while (dynamic_cast<ArrayType const*>(memberType))
|
||||
memberType = dynamic_cast<ArrayType const*>(memberType)->baseType().get();
|
||||
|
||||
if (StructType const* innerStruct = dynamic_cast<StructType const*>(memberType))
|
||||
if (
|
||||
innerStruct->m_recursive == true ||
|
||||
_cycleDetector.run(innerStruct->structDefinition())
|
||||
)
|
||||
{
|
||||
m_recursive = true;
|
||||
if (_inLibrary && location() == DataLocation::Storage)
|
||||
continue;
|
||||
else
|
||||
{
|
||||
result = TypeResult::err("Recursive structs can only be passed as storage pointers to libraries, not as memory objects to contract functions.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
auto iType = memberType->interfaceType(_inLibrary);
|
||||
if (!iType.get())
|
||||
{
|
||||
allOkay = false;
|
||||
break;
|
||||
solAssert(!iType.message().empty(), "Expected detailed error message!");
|
||||
result = iType;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (allOkay)
|
||||
result = copyForLocation(DataLocation::Memory, true);
|
||||
}
|
||||
};
|
||||
|
||||
m_recursive = m_recursive.get() || (CycleDetector<StructDefinition>(visitor).run(structDefinition()) != nullptr);
|
||||
|
||||
std::string const recursiveErrMsg = "Recursive type not allowed for public or external contract functions.";
|
||||
|
||||
if (_inLibrary)
|
||||
m_interfaceType_library = result;
|
||||
else
|
||||
m_interfaceType = result;
|
||||
{
|
||||
if (!result.message().empty())
|
||||
m_interfaceType_library = result;
|
||||
else if (location() == DataLocation::Storage)
|
||||
m_interfaceType_library = shared_from_this();
|
||||
else
|
||||
m_interfaceType_library = copyForLocation(DataLocation::Memory, true);
|
||||
|
||||
return result;
|
||||
if (m_recursive.get())
|
||||
m_interfaceType = TypeResult::err(recursiveErrMsg);
|
||||
|
||||
return *m_interfaceType_library;
|
||||
}
|
||||
|
||||
if (m_recursive.get())
|
||||
m_interfaceType = TypeResult::err(recursiveErrMsg);
|
||||
else if (!result.message().empty())
|
||||
m_interfaceType = result;
|
||||
else
|
||||
m_interfaceType = copyForLocation(DataLocation::Memory, true);
|
||||
|
||||
return *m_interfaceType;
|
||||
}
|
||||
|
||||
TypePointer StructType::copyForLocation(DataLocation _location, bool _isPointer) const
|
||||
@ -2204,8 +2243,8 @@ string StructType::signatureInExternalFunction(bool _structsByName) const
|
||||
{
|
||||
solAssert(_t, "Parameter should have external type.");
|
||||
auto t = _t->interfaceType(_structsByName);
|
||||
solAssert(t, "");
|
||||
return t->signatureInExternalFunction(_structsByName);
|
||||
solAssert(t.get(), "");
|
||||
return t.get()->signatureInExternalFunction(_structsByName);
|
||||
});
|
||||
return "(" + boost::algorithm::join(memberTypeStrings, ",") + ")";
|
||||
}
|
||||
@ -2273,27 +2312,6 @@ set<string> StructType::membersMissingInMemory() const
|
||||
return missing;
|
||||
}
|
||||
|
||||
bool StructType::recursive() const
|
||||
{
|
||||
if (!m_recursive.is_initialized())
|
||||
{
|
||||
auto visitor = [&](StructDefinition const& _struct, CycleDetector<StructDefinition>& _cycleDetector, size_t /*_depth*/)
|
||||
{
|
||||
for (ASTPointer<VariableDeclaration> const& variable: _struct.members())
|
||||
{
|
||||
Type const* memberType = variable->annotation().type.get();
|
||||
while (dynamic_cast<ArrayType const*>(memberType))
|
||||
memberType = dynamic_cast<ArrayType const*>(memberType)->baseType().get();
|
||||
if (StructType const* innerStruct = dynamic_cast<StructType const*>(memberType))
|
||||
if (_cycleDetector.run(innerStruct->structDefinition()))
|
||||
return;
|
||||
}
|
||||
};
|
||||
m_recursive = (CycleDetector<StructDefinition>(visitor).run(structDefinition()) != nullptr);
|
||||
}
|
||||
return *m_recursive;
|
||||
}
|
||||
|
||||
TypeResult EnumType::unaryOperatorResult(Token _operator) const
|
||||
{
|
||||
return _operator == Token::Delete ? make_shared<TupleType>() : TypePointer();
|
||||
@ -2574,7 +2592,7 @@ FunctionType::FunctionType(FunctionTypeName const& _typeName):
|
||||
solAssert(t->annotation().type, "Type not set for parameter.");
|
||||
if (m_kind == Kind::External)
|
||||
solAssert(
|
||||
t->annotation().type->interfaceType(false),
|
||||
t->annotation().type->interfaceType(false).get(),
|
||||
"Internal type used as parameter for external function."
|
||||
);
|
||||
m_parameterTypes.push_back(t->annotation().type);
|
||||
@ -2584,7 +2602,7 @@ FunctionType::FunctionType(FunctionTypeName const& _typeName):
|
||||
solAssert(t->annotation().type, "Type not set for return parameter.");
|
||||
if (m_kind == Kind::External)
|
||||
solAssert(
|
||||
t->annotation().type->interfaceType(false),
|
||||
t->annotation().type->interfaceType(false).get(),
|
||||
"Internal type used as return parameter for external function."
|
||||
);
|
||||
m_returnParameterTypes.push_back(t->annotation().type);
|
||||
@ -2885,14 +2903,14 @@ FunctionTypePointer FunctionType::interfaceFunctionType() const
|
||||
|
||||
for (auto type: m_parameterTypes)
|
||||
{
|
||||
if (auto ext = type->interfaceType(isLibraryFunction))
|
||||
if (auto ext = type->interfaceType(isLibraryFunction).get())
|
||||
paramTypes.push_back(ext);
|
||||
else
|
||||
return FunctionTypePointer();
|
||||
}
|
||||
for (auto type: m_returnParameterTypes)
|
||||
{
|
||||
if (auto ext = type->interfaceType(isLibraryFunction))
|
||||
if (auto ext = type->interfaceType(isLibraryFunction).get())
|
||||
retParamTypes.push_back(ext);
|
||||
else
|
||||
return FunctionTypePointer();
|
||||
@ -2978,12 +2996,12 @@ TypePointer FunctionType::encodingType() const
|
||||
return TypePointer();
|
||||
}
|
||||
|
||||
TypePointer FunctionType::interfaceType(bool /*_inLibrary*/) const
|
||||
TypeResult FunctionType::interfaceType(bool /*_inLibrary*/) const
|
||||
{
|
||||
if (m_kind == Kind::External)
|
||||
return shared_from_this();
|
||||
else
|
||||
return TypePointer();
|
||||
return TypeResult::err("Internal type is not allowed for public or external functions.");
|
||||
}
|
||||
|
||||
bool FunctionType::canTakeArguments(
|
||||
@ -3277,6 +3295,26 @@ string MappingType::canonicalName() const
|
||||
return "mapping(" + keyType()->canonicalName() + " => " + valueType()->canonicalName() + ")";
|
||||
}
|
||||
|
||||
TypeResult MappingType::interfaceType(bool _inLibrary) const
|
||||
{
|
||||
solAssert(keyType()->interfaceType(_inLibrary).get(), "Must be an elementary type!");
|
||||
|
||||
if (_inLibrary)
|
||||
{
|
||||
auto iType = valueType()->interfaceType(_inLibrary);
|
||||
|
||||
if (!iType.get())
|
||||
{
|
||||
solAssert(!iType.message().empty(), "Expected detailed error message!");
|
||||
return iType;
|
||||
}
|
||||
}
|
||||
else
|
||||
return TypeResult::err("Only libraries are allowed to use the mapping type in public or external functions.");
|
||||
|
||||
return shared_from_this();
|
||||
}
|
||||
|
||||
string TypeType::richIdentifier() const
|
||||
{
|
||||
return "t_type" + identifierList(actualType());
|
||||
|
@ -304,7 +304,7 @@ public:
|
||||
/// If there is no such type, returns an empty shared pointer.
|
||||
/// @param _inLibrary if set, returns types as used in a library, e.g. struct and contract types
|
||||
/// are returned without modification.
|
||||
virtual TypePointer interfaceType(bool /*_inLibrary*/) const { return TypePointer(); }
|
||||
virtual TypeResult interfaceType(bool /*_inLibrary*/) const { return TypePointer(); }
|
||||
|
||||
private:
|
||||
/// @returns a member list containing all members added to this type by `using for` directives.
|
||||
@ -355,7 +355,7 @@ public:
|
||||
u256 literalValue(Literal const* _literal) const override;
|
||||
|
||||
TypePointer encodingType() const override { return shared_from_this(); }
|
||||
TypePointer interfaceType(bool) const override { return shared_from_this(); }
|
||||
TypeResult interfaceType(bool) const override { return shared_from_this(); }
|
||||
|
||||
StateMutability stateMutability(void) const { return m_stateMutability; }
|
||||
|
||||
@ -395,7 +395,7 @@ public:
|
||||
std::string toString(bool _short) const override;
|
||||
|
||||
TypePointer encodingType() const override { return shared_from_this(); }
|
||||
TypePointer interfaceType(bool) const override { return shared_from_this(); }
|
||||
TypeResult interfaceType(bool) const override { return shared_from_this(); }
|
||||
|
||||
unsigned numBits() const { return m_bits; }
|
||||
bool isSigned() const { return m_modifier == Modifier::Signed; }
|
||||
@ -437,7 +437,7 @@ public:
|
||||
std::string toString(bool _short) const override;
|
||||
|
||||
TypePointer encodingType() const override { return shared_from_this(); }
|
||||
TypePointer interfaceType(bool) const override { return shared_from_this(); }
|
||||
TypeResult interfaceType(bool) const override { return shared_from_this(); }
|
||||
|
||||
/// Number of bits used for this type in total.
|
||||
unsigned numBits() const { return m_totalBits; }
|
||||
@ -583,7 +583,7 @@ public:
|
||||
std::string toString(bool) const override { return "bytes" + dev::toString(m_bytes); }
|
||||
MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
|
||||
TypePointer encodingType() const override { return shared_from_this(); }
|
||||
TypePointer interfaceType(bool) const override { return shared_from_this(); }
|
||||
TypeResult interfaceType(bool) const override { return shared_from_this(); }
|
||||
|
||||
unsigned numBytes() const { return m_bytes; }
|
||||
|
||||
@ -609,7 +609,7 @@ public:
|
||||
std::string toString(bool) const override { return "bool"; }
|
||||
u256 literalValue(Literal const* _literal) const override;
|
||||
TypePointer encodingType() const override { return shared_from_this(); }
|
||||
TypePointer interfaceType(bool) const override { return shared_from_this(); }
|
||||
TypeResult interfaceType(bool) const override { return shared_from_this(); }
|
||||
};
|
||||
|
||||
/**
|
||||
@ -716,7 +716,7 @@ public:
|
||||
MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
|
||||
TypePointer encodingType() const override;
|
||||
TypePointer decodingType() const override;
|
||||
TypePointer interfaceType(bool _inLibrary) const override;
|
||||
TypeResult interfaceType(bool _inLibrary) const override;
|
||||
|
||||
/// @returns true if this is valid to be stored in calldata
|
||||
bool validForCalldata() const;
|
||||
@ -749,8 +749,8 @@ private:
|
||||
TypePointer m_baseType;
|
||||
bool m_hasDynamicLength = true;
|
||||
u256 m_length;
|
||||
mutable boost::optional<TypePointer> m_interfaceType;
|
||||
mutable boost::optional<TypePointer> m_interfaceType_library;
|
||||
mutable boost::optional<TypeResult> m_interfaceType;
|
||||
mutable boost::optional<TypeResult> m_interfaceType_library;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -788,7 +788,7 @@ public:
|
||||
return TypePointer{};
|
||||
return std::make_shared<AddressType>(isPayable() ? StateMutability::Payable : StateMutability::NonPayable);
|
||||
}
|
||||
TypePointer interfaceType(bool _inLibrary) const override
|
||||
TypeResult interfaceType(bool _inLibrary) const override
|
||||
{
|
||||
if (isSuper())
|
||||
return TypePointer{};
|
||||
@ -842,7 +842,17 @@ public:
|
||||
{
|
||||
return location() == DataLocation::Storage ? std::make_shared<IntegerType>(256) : shared_from_this();
|
||||
}
|
||||
TypePointer interfaceType(bool _inLibrary) const override;
|
||||
TypeResult interfaceType(bool _inLibrary) const override;
|
||||
|
||||
bool recursive() const
|
||||
{
|
||||
if (m_recursive.is_initialized())
|
||||
return m_recursive.get();
|
||||
|
||||
interfaceType(false);
|
||||
|
||||
return m_recursive.get();
|
||||
}
|
||||
|
||||
TypePointer copyForLocation(DataLocation _location, bool _isPointer) const override;
|
||||
|
||||
@ -863,17 +873,12 @@ public:
|
||||
TypePointers memoryMemberTypes() const;
|
||||
/// @returns the set of all members that are removed in the memory version (typically mappings).
|
||||
std::set<std::string> membersMissingInMemory() const;
|
||||
|
||||
/// @returns true if the same struct is used recursively in one of its members. Only
|
||||
/// analyses the "memory" representation, i.e. mappings are ignored in all structs.
|
||||
bool recursive() const;
|
||||
|
||||
private:
|
||||
StructDefinition const& m_struct;
|
||||
/// Cache for the recursive() function.
|
||||
// Caches for interfaceType(bool)
|
||||
mutable boost::optional<TypeResult> m_interfaceType;
|
||||
mutable boost::optional<TypeResult> m_interfaceType_library;
|
||||
mutable boost::optional<bool> m_recursive;
|
||||
mutable boost::optional<TypePointer> m_interfaceType;
|
||||
mutable boost::optional<TypePointer> m_interfaceType_library;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -902,7 +907,7 @@ public:
|
||||
{
|
||||
return std::make_shared<IntegerType>(8 * int(storageBytes()));
|
||||
}
|
||||
TypePointer interfaceType(bool _inLibrary) const override
|
||||
TypeResult interfaceType(bool _inLibrary) const override
|
||||
{
|
||||
return _inLibrary ? shared_from_this() : encodingType();
|
||||
}
|
||||
@ -1098,7 +1103,7 @@ public:
|
||||
bool hasSimpleZeroValueInMemory() const override { return false; }
|
||||
MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
|
||||
TypePointer encodingType() const override;
|
||||
TypePointer interfaceType(bool _inLibrary) const override;
|
||||
TypeResult interfaceType(bool _inLibrary) const override;
|
||||
|
||||
/// @returns TypePointer of a new FunctionType object. All input/return parameters are an
|
||||
/// appropriate external types (i.e. the interfaceType()s) of input/return parameters of
|
||||
@ -1223,10 +1228,7 @@ public:
|
||||
{
|
||||
return std::make_shared<IntegerType>(256);
|
||||
}
|
||||
TypePointer interfaceType(bool _inLibrary) const override
|
||||
{
|
||||
return _inLibrary ? shared_from_this() : TypePointer();
|
||||
}
|
||||
TypeResult interfaceType(bool _inLibrary) const override;
|
||||
bool dataStoredIn(DataLocation _location) const override { return _location == DataLocation::Storage; }
|
||||
/// Cannot be stored in memory, but just in case.
|
||||
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
|
||||
|
@ -107,9 +107,9 @@ Json::Value ABI::generate(ContractDefinition const& _contractDef)
|
||||
for (auto const& p: it->parameters())
|
||||
{
|
||||
auto type = p->annotation().type->interfaceType(false);
|
||||
solAssert(type, "");
|
||||
solAssert(type.get(), "");
|
||||
Json::Value input;
|
||||
auto param = formatType(p->name(), *type, false);
|
||||
auto param = formatType(p->name(), *type.get(), false);
|
||||
param["indexed"] = p->isIndexed();
|
||||
params.append(param);
|
||||
}
|
||||
@ -173,8 +173,8 @@ Json::Value ABI::formatType(string const& _name, Type const& _type, bool _forLib
|
||||
{
|
||||
solAssert(member.type, "");
|
||||
auto t = member.type->interfaceType(_forLibrary);
|
||||
solAssert(t, "");
|
||||
ret["components"].append(formatType(member.name, *t, _forLibrary));
|
||||
solAssert(t.get(), "");
|
||||
ret["components"].append(formatType(member.name, *t.get(), _forLibrary));
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -0,0 +1,6 @@
|
||||
library L {
|
||||
// Used to cause internal error
|
||||
function f(function(uint) internal returns (uint)[] memory x) public { }
|
||||
}
|
||||
// ----
|
||||
// TypeError: (63-112): Internal type is not allowed for public or external functions.
|
@ -0,0 +1,6 @@
|
||||
library L {
|
||||
// Used to cause internal error
|
||||
function g(function(uint) internal returns (uint)[] storage x) public { }
|
||||
}
|
||||
// ----
|
||||
// TypeError: (63-113): Internal type is not allowed for public or external functions.
|
@ -5,4 +5,4 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (124-164): Internal or recursive type is not allowed for public or external functions.
|
||||
// TypeError: (124-164): Internal type is not allowed for public or external functions.
|
||||
|
@ -3,4 +3,4 @@ library L {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (27-67): Internal or recursive type is not allowed for public or external functions.
|
||||
// TypeError: (27-67): Internal type is not allowed for public or external functions.
|
||||
|
@ -4,4 +4,4 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (129-169): Internal or recursive type is not allowed for public or external functions.
|
||||
// TypeError: (129-169): Internal type is not allowed for public or external functions.
|
||||
|
@ -0,0 +1,9 @@
|
||||
library L {
|
||||
struct S
|
||||
{
|
||||
function(uint) internal returns (uint)[] x;
|
||||
}
|
||||
function f(S storage s) public { }
|
||||
}
|
||||
// ----
|
||||
// TypeError: (104-115): Internal type is not allowed for public or external functions.
|
@ -6,4 +6,4 @@ contract C {
|
||||
}
|
||||
// ----
|
||||
// Warning: (0-33): Experimental features are turned on. Do not use experimental features on live deployments.
|
||||
// TypeError: (103-111): Internal or recursive type is not allowed for public or external functions.
|
||||
// TypeError: (103-111): Internal type is not allowed for public or external functions.
|
||||
|
@ -6,4 +6,4 @@ contract C {
|
||||
}
|
||||
// ----
|
||||
// Warning: (0-33): Experimental features are turned on. Do not use experimental features on live deployments.
|
||||
// TypeError: (105-113): Internal or recursive type is not allowed for public or external functions.
|
||||
// TypeError: (105-113): Only libraries are allowed to use the mapping type in public or external functions.
|
||||
|
@ -7,4 +7,4 @@ contract C {
|
||||
}
|
||||
// ----
|
||||
// Warning: (0-33): Experimental features are turned on. Do not use experimental features on live deployments.
|
||||
// TypeError: (132-140): Internal or recursive type is not allowed for public or external functions.
|
||||
// TypeError: (132-140): Only libraries are allowed to use the mapping type in public or external functions.
|
||||
|
@ -0,0 +1,10 @@
|
||||
contract Test {
|
||||
struct MyStructName {
|
||||
address addr;
|
||||
MyStructName[] x;
|
||||
}
|
||||
|
||||
function f(MyStructName memory s) public {}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (112-133): Recursive type not allowed for public or external contract functions.
|
@ -0,0 +1,9 @@
|
||||
library Test {
|
||||
struct MyStructName {
|
||||
address addr;
|
||||
MyStructName[] x;
|
||||
}
|
||||
|
||||
function f(MyStructName storage s) public {}
|
||||
}
|
||||
// ----
|
@ -0,0 +1,14 @@
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
library Test {
|
||||
struct MyStructName {
|
||||
address addr;
|
||||
MyStructName[] x;
|
||||
}
|
||||
|
||||
function f(MyStructName memory _x) public {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Warning: (0-33): Experimental features are turned on. Do not use experimental features on live deployments.
|
||||
// TypeError: (146-168): Recursive structs can only be passed as storage pointers to libraries, not as memory objects to contract functions.
|
@ -8,4 +8,4 @@ contract Data {
|
||||
}
|
||||
// ----
|
||||
// Warning: (0-33): Experimental features are turned on. Do not use experimental features on live deployments.
|
||||
// TypeError: (63-78): Internal or recursive type is not allowed for public or external functions.
|
||||
// TypeError: (63-78): Recursive type not allowed for public or external contract functions.
|
||||
|
@ -0,0 +1,11 @@
|
||||
library Test {
|
||||
struct MyStructName {
|
||||
address addr;
|
||||
MyStructName[] x;
|
||||
function() internal y;
|
||||
}
|
||||
|
||||
function f(MyStructName storage s) public {}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (142-164): Internal type is not allowed for public or external functions.
|
@ -4,4 +4,4 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (91-99): Internal or recursive type is not allowed for public or external functions.
|
||||
// TypeError: (91-99): Recursive type not allowed for public or external contract functions.
|
||||
|
@ -4,4 +4,4 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (94-102): Internal or recursive type is not allowed for public or external functions.
|
||||
// TypeError: (94-102): Recursive type not allowed for public or external contract functions.
|
||||
|
@ -5,4 +5,4 @@ contract C {
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError: (119-129): Internal or recursive type is not allowed for public or external functions.
|
||||
// TypeError: (119-129): Recursive type not allowed for public or external contract functions.
|
||||
|
@ -3,4 +3,4 @@ contract c {
|
||||
}
|
||||
// ----
|
||||
// TypeError: (29-61): Type is required to live outside storage.
|
||||
// TypeError: (29-61): Internal or recursive type is not allowed for public or external functions.
|
||||
// TypeError: (29-61): Only libraries are allowed to use the mapping type in public or external functions.
|
||||
|
Loading…
Reference in New Issue
Block a user