Add InlineArrayType to support literals conversion to statically and dynamically allocated arrays.

This commit is contained in:
wechman
2022-08-29 07:18:35 +02:00
parent 7bfec3ba70
commit 1ef2f60049
63 changed files with 1581 additions and 384 deletions
+50 -43
View File
@@ -67,6 +67,13 @@ bool TypeChecker::typeSupportedByOldABIEncoder(Type const& _type, bool _isLibrar
if (!typeSupportedByOldABIEncoder(*base, _isLibraryCall) || (base->category() == Type::Category::Array && base->isDynamicallySized()))
return false;
}
if (_type.category() == Type::Category::InlineArray)
{
auto const& mobileType = dynamic_cast<InlineArrayType const&>(_type).mobileType();
if (!mobileType)
return false;
return typeSupportedByOldABIEncoder(*mobileType, _isLibraryCall);
}
return true;
}
@@ -1647,7 +1654,6 @@ bool TypeChecker::visit(TupleExpression const& _tuple)
else
{
bool isPure = true;
Type const* inlineArrayType = nullptr;
for (size_t i = 0; i < components.size(); ++i)
{
@@ -1662,7 +1668,8 @@ bool TypeChecker::visit(TupleExpression const& _tuple)
{
if (_tuple.isInlineArray())
m_errorReporter.fatalTypeError(5604_error, components[i]->location(), "Array component cannot be empty.");
m_errorReporter.typeError(6473_error, components[i]->location(), "Tuple component cannot be empty.");
else
m_errorReporter.typeError(6473_error, components[i]->location(), "Tuple component cannot be empty.");
}
// Note: code generation will visit each of the expression even if they are not assigned from.
@@ -1670,48 +1677,37 @@ bool TypeChecker::visit(TupleExpression const& _tuple)
if (!dynamic_cast<RationalNumberType const&>(*types[i]).mobileType())
m_errorReporter.fatalTypeError(3390_error, components[i]->location(), "Invalid rational number.");
if (_tuple.isInlineArray())
if (_tuple.isInlineArray() &&
types[i]->category() != Type::Category::InlineArray)
{
solAssert(!!types[i], "Inline array cannot have empty components");
if ((i == 0 || inlineArrayType) && !types[i]->mobileType())
Type const* mobileType = types[i]->mobileType();
if (!mobileType)
m_errorReporter.fatalTypeError(9563_error, components[i]->location(), "Invalid mobile type.");
if (i == 0)
inlineArrayType = types[i]->mobileType();
else if (inlineArrayType)
inlineArrayType = Type::commonType(inlineArrayType, types[i]);
else if (!mobileType->nameable())
m_errorReporter.fatalTypeError(
9656_error,
_tuple.location(),
"Unable to deduce nameable type for array elements. Try adding explicit type conversion for the first element."
);
else if (mobileType->containsNestedMapping())
m_errorReporter.fatalTypeError(
1545_error,
_tuple.location(),
"Type " + types[i]->humanReadableName() + " is only valid in storage."
);
}
if (!*components[i]->annotation().isPure)
isPure = false;
}
_tuple.annotation().isPure = isPure;
if (_tuple.isInlineArray())
{
if (!inlineArrayType)
m_errorReporter.fatalTypeError(6378_error, _tuple.location(), "Unable to deduce common type for array elements.");
else if (!inlineArrayType->nameable())
m_errorReporter.fatalTypeError(
9656_error,
_tuple.location(),
"Unable to deduce nameable type for array elements. Try adding explicit type conversion for the first element."
);
else if (inlineArrayType->containsNestedMapping())
m_errorReporter.fatalTypeError(
1545_error,
_tuple.location(),
"Type " + inlineArrayType->humanReadableName() + " is only valid in storage."
);
_tuple.annotation().type = TypeProvider::array(DataLocation::Memory, inlineArrayType, types.size());
}
if (_tuple.isInlineArray())
_tuple.annotation().type = TypeProvider::inlineArray(move(types));
else if (components.size() == 1)
_tuple.annotation().type = type(*components[0]);
else
{
if (components.size() == 1)
_tuple.annotation().type = type(*components[0]);
else
_tuple.annotation().type = TypeProvider::tuple(move(types));
}
_tuple.annotation().type = TypeProvider::tuple(move(types));
_tuple.annotation().isLValue = false;
}
@@ -2105,10 +2101,9 @@ void TypeChecker::typeCheckABIEncodeFunctions(
}
// Check additional arguments for variadic functions
vector<ASTPointer<Expression const>> const& arguments = _functionCall.arguments();
for (size_t i = 0; i < arguments.size(); ++i)
for (auto const& argument: _functionCall.arguments())
{
auto const& argType = type(*arguments[i]);
Type const* argType = type(*argument);
if (argType->category() == Type::Category::RationalNumber)
{
@@ -2117,7 +2112,7 @@ void TypeChecker::typeCheckABIEncodeFunctions(
{
m_errorReporter.typeError(
6090_error,
arguments[i]->location(),
argument->location(),
"Fractional numbers cannot yet be encoded."
);
continue;
@@ -2126,7 +2121,7 @@ void TypeChecker::typeCheckABIEncodeFunctions(
{
m_errorReporter.typeError(
8009_error,
arguments[i]->location(),
argument->location(),
"Invalid rational number (too large or division by zero)."
);
continue;
@@ -2135,7 +2130,7 @@ void TypeChecker::typeCheckABIEncodeFunctions(
{
m_errorReporter.typeError(
7279_error,
arguments[i]->location(),
argument->location(),
"Cannot perform packed encoding for a literal."
" Please convert it to an explicit type first."
);
@@ -2147,7 +2142,7 @@ void TypeChecker::typeCheckABIEncodeFunctions(
{
m_errorReporter.typeError(
9578_error,
arguments[i]->location(),
argument->location(),
"Type not supported in packed mode."
);
continue;
@@ -2156,7 +2151,7 @@ void TypeChecker::typeCheckABIEncodeFunctions(
if (!argType->fullEncodingType(false, abiEncoderV2, !_functionType->padArguments()))
m_errorReporter.typeError(
2056_error,
arguments[i]->location(),
argument->location(),
"This type cannot be encoded."
);
}
@@ -3361,6 +3356,16 @@ bool TypeChecker::visit(IndexAccess const& _access)
isLValue = actualType.location() != DataLocation::CallData;
break;
}
case Type::Category::InlineArray:
{
if (!index)
m_errorReporter.typeError(5093_error, _access.location(), "Index expression cannot be omitted.");
else
expectType(*index, *TypeProvider::uint256());
resultType = dynamic_cast<InlineArrayType const&>(*baseType).componentsCommonMobileType();
break;
}
case Type::Category::Mapping:
{
MappingType const& actualType = dynamic_cast<MappingType const&>(*baseType);
@@ -3469,6 +3474,8 @@ bool TypeChecker::visit(IndexRangeAccess const& _access)
ArrayType const* arrayType = nullptr;
if (auto const* arraySlice = dynamic_cast<ArraySliceType const*>(exprType))
arrayType = &arraySlice->arrayType();
else if (auto const* inlineArray = dynamic_cast<InlineArrayType const*>(exprType))
arrayType = TypeProvider::array(DataLocation::Memory, inlineArray->componentsCommonMobileType(), inlineArray->components().size());
else if (!(arrayType = dynamic_cast<ArrayType const*>(exprType)))
m_errorReporter.fatalTypeError(4781_error, _access.location(), "Index range access is only possible for arrays and array slices.");