solidity/libsolidity/analysis/TypeChecker.cpp

2480 lines
84 KiB
C++
Raw Normal View History

/*
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @author Christian <c@ethdev.com>
* @date 2015
* Type analyzer and checker.
*/
2015-10-20 22:21:52 +00:00
#include <libsolidity/analysis/TypeChecker.h>
#include <libsolidity/ast/AST.h>
#include <libyul/AsmAnalysis.h>
#include <libyul/AsmAnalysisInfo.h>
#include <libyul/AsmData.h>
2018-12-06 23:56:16 +00:00
#include <libyul/backends/evm/EVMDialect.h>
#include <liblangutil/ErrorReporter.h>
#include <libdevcore/Algorithms.h>
#include <libdevcore/StringUtils.h>
#include <boost/algorithm/cxx11/all_of.hpp>
#include <boost/algorithm/string/join.hpp>
2018-12-17 11:30:08 +00:00
#include <boost/algorithm/string/predicate.hpp>
#include <memory>
#include <vector>
using namespace std;
using namespace dev;
using namespace langutil;
using namespace dev::solidity;
namespace
{
bool typeSupportedByOldABIEncoder(Type const& _type, bool _isLibraryCall)
{
if (_isLibraryCall && _type.dataStoredIn(DataLocation::Storage))
return true;
if (_type.category() == Type::Category::Struct)
return false;
if (_type.category() == Type::Category::Array)
{
auto const& arrayType = dynamic_cast<ArrayType const&>(_type);
auto base = arrayType.baseType();
if (!typeSupportedByOldABIEncoder(*base, _isLibraryCall) || (base->category() == Type::Category::Array && base->isDynamicallySized()))
return false;
}
return true;
}
}
bool TypeChecker::checkTypeRequirements(ASTNode const& _contract)
{
_contract.accept(*this);
return Error::containsOnlyWarnings(m_errorReporter.errors());
}
TypePointer const& TypeChecker::type(Expression const& _expression) const
{
solAssert(!!_expression.annotation().type, "Type requested but not present.");
return _expression.annotation().type;
}
TypePointer const& TypeChecker::type(VariableDeclaration const& _variable) const
{
solAssert(!!_variable.annotation().type, "Type requested but not present.");
return _variable.annotation().type;
}
bool TypeChecker::visit(ContractDefinition const& _contract)
{
2015-11-19 17:02:04 +00:00
m_scope = &_contract;
ASTNode::listAccept(_contract.baseContracts(), *this);
2017-03-21 14:05:59 +00:00
for (auto const& n: _contract.subNodes())
2018-11-29 17:18:17 +00:00
n->accept(*this);
return false;
}
void TypeChecker::checkDoubleStorageAssignment(Assignment const& _assignment)
{
TupleType const& lhs = dynamic_cast<TupleType const&>(*type(_assignment.leftHandSide()));
TupleType const& rhs = dynamic_cast<TupleType const&>(*type(_assignment.rightHandSide()));
if (lhs.components().size() != rhs.components().size())
{
solAssert(m_errorReporter.hasErrors(), "");
return;
}
size_t storageToStorageCopies = 0;
size_t toStorageCopies = 0;
for (size_t i = 0; i < lhs.components().size(); ++i)
{
ReferenceType const* ref = dynamic_cast<ReferenceType const*>(lhs.components()[i].get());
if (!ref || !ref->dataStoredIn(DataLocation::Storage) || ref->isPointer())
continue;
toStorageCopies++;
if (rhs.components()[i]->dataStoredIn(DataLocation::Storage))
storageToStorageCopies++;
}
if (storageToStorageCopies >= 1 && toStorageCopies >= 2)
m_errorReporter.warning(
_assignment.location(),
"This assignment performs two copies to storage. Since storage copies do not first "
"copy to a temporary location, one of them might be overwritten before the second "
"is executed and thus may have unexpected effects. It is safer to perform the copies "
"separately or assign to storage pointers first."
);
}
2018-09-04 14:24:21 +00:00
TypePointers TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall const& _functionCall, bool _abiEncoderV2)
2018-06-30 16:09:13 +00:00
{
vector<ASTPointer<Expression const>> arguments = _functionCall.arguments();
if (arguments.size() != 2)
m_errorReporter.typeError(
_functionCall.location(),
"This function takes two arguments, but " +
toString(arguments.size()) +
" were provided."
);
if (arguments.size() >= 1 && !type(*arguments.front())->isImplicitlyConvertibleTo(ArrayType::bytesMemory()))
2018-06-30 16:09:13 +00:00
m_errorReporter.typeError(
arguments.front()->location(),
"Invalid type for argument in function call. "
"Invalid implicit conversion from " +
type(*arguments.front())->toString() +
" to bytes memory requested."
);
if (arguments.size() < 2)
2018-09-04 14:24:21 +00:00
return {};
2018-06-30 16:09:13 +00:00
// The following is a rather syntactic restriction, but we check it here anyway:
// The second argument has to be a tuple expression containing type names.
TupleExpression const* tupleExpression = dynamic_cast<TupleExpression const*>(arguments[1].get());
if (!tupleExpression)
{
m_errorReporter.typeError(
arguments[1]->location(),
"The second argument to \"abi.decode\" has to be a tuple of types."
);
2018-09-04 14:24:21 +00:00
return {};
2018-06-30 16:09:13 +00:00
}
2018-09-04 14:24:21 +00:00
TypePointers components;
2018-06-30 16:09:13 +00:00
for (auto const& typeArgument: tupleExpression->components())
{
solAssert(typeArgument, "");
if (TypeType const* argTypeType = dynamic_cast<TypeType const*>(type(*typeArgument).get()))
{
TypePointer actualType = argTypeType->actualType();
solAssert(actualType, "");
// We force memory because the parser currently cannot handle
// data locations. Furthermore, storage can be a little dangerous and
// calldata is not really implemented anyway.
actualType = ReferenceType::copyForLocationIfReference(DataLocation::Memory, actualType);
// We force address payable for address types.
if (actualType->category() == Type::Category::Address)
actualType = make_shared<AddressType>(StateMutability::Payable);
2018-06-30 16:09:13 +00:00
solAssert(
!actualType->dataStoredIn(DataLocation::CallData) &&
!actualType->dataStoredIn(DataLocation::Storage),
""
);
if (!actualType->fullEncodingType(false, _abiEncoderV2, false))
m_errorReporter.typeError(
typeArgument->location(),
"Decoding type " + actualType->toString(false) + " not supported."
2018-06-30 16:09:13 +00:00
);
components.push_back(actualType);
}
else
{
m_errorReporter.typeError(typeArgument->location(), "Argument has to be a type name.");
components.push_back(make_shared<TupleType>());
}
}
2018-09-04 14:24:21 +00:00
return components;
2018-06-30 16:09:13 +00:00
}
2019-01-10 15:28:39 +00:00
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()));
solAssert(base, "Base contract not available.");
2019-01-17 11:59:11 +00:00
if (m_scope->isInterface())
m_errorReporter.typeError(_inheritance.location(), "Interfaces cannot inherit.");
if (base->isLibrary())
m_errorReporter.typeError(_inheritance.location(), "Libraries cannot be inherited from.");
auto const& arguments = _inheritance.arguments();
TypePointers parameterTypes;
2019-01-17 11:59:11 +00:00
if (!base->isInterface())
// Interfaces do not have constructors, so there are zero parameters.
parameterTypes = ContractType(*base).newExpressionType()->parameterTypes();
if (arguments)
{
if (parameterTypes.size() != arguments->size())
{
m_errorReporter.typeError(
_inheritance.location(),
"Wrong argument count for constructor call: " +
toString(arguments->size()) +
" arguments given but expected " +
toString(parameterTypes.size()) +
". Remove parentheses if you do not want to provide arguments here."
);
}
for (size_t i = 0; i < std::min(arguments->size(), parameterTypes.size()); ++i)
if (!type(*(*arguments)[i])->isImplicitlyConvertibleTo(*parameterTypes[i]))
m_errorReporter.typeError(
(*arguments)[i]->location(),
"Invalid type for argument in constructor call. "
"Invalid implicit conversion from " +
type(*(*arguments)[i])->toString() +
" to " +
parameterTypes[i]->toString() +
" requested."
);
}
2015-11-22 19:39:10 +00:00
}
void TypeChecker::endVisit(UsingForDirective const& _usingFor)
{
ContractDefinition const* library = dynamic_cast<ContractDefinition const*>(
_usingFor.libraryName().annotation().referencedDeclaration
);
if (!library || !library->isLibrary())
m_errorReporter.fatalTypeError(_usingFor.libraryName().location(), "Library name expected.");
}
bool TypeChecker::visit(StructDefinition const& _struct)
{
for (ASTPointer<VariableDeclaration> const& member: _struct.members())
solAssert(type(*member)->canBeStored(), "Type cannot be used in struct.");
// Check recursion, fatal error if detected.
auto visitor = [&](StructDefinition const& _struct, CycleDetector<StructDefinition>& _cycleDetector, size_t _depth)
{
if (_depth >= 256)
m_errorReporter.fatalDeclarationError(_struct.location(), "Struct definition exhausting cyclic dependency validator.");
for (ASTPointer<VariableDeclaration> const& member: _struct.members())
{
Type const* memberType = type(*member).get();
while (auto arrayType = dynamic_cast<ArrayType const*>(memberType))
{
if (arrayType->isDynamicallySized())
break;
memberType = arrayType->baseType().get();
}
if (auto structType = dynamic_cast<StructType const*>(memberType))
if (_cycleDetector.run(structType->structDefinition()))
return;
}
};
if (CycleDetector<StructDefinition>(visitor).run(_struct) != nullptr)
m_errorReporter.fatalTypeError(_struct.location(), "Recursive struct definition.");
bool insideStruct = true;
swap(insideStruct, m_insideStruct);
ASTNode::listAccept(_struct.members(), *this);
m_insideStruct = insideStruct;
return false;
}
bool TypeChecker::visit(FunctionDefinition const& _function)
{
bool isLibraryFunction = _function.inContractKind() == ContractDefinition::ContractKind::Library;
if (_function.isPayable())
{
if (isLibraryFunction)
m_errorReporter.typeError(_function.location(), "Library functions cannot be payable.");
2017-07-27 19:55:55 +00:00
if (!_function.isConstructor() && !_function.isFallback() && !_function.isPartOfExternalInterface())
m_errorReporter.typeError(_function.location(), "Internal functions cannot be payable.");
}
auto checkArgumentAndReturnParameter = [&](VariableDeclaration const& var) {
if (type(var)->category() == Type::Category::Mapping)
{
if (var.referenceLocation() != VariableDeclaration::Location::Storage)
{
if (!isLibraryFunction && _function.isPublic())
m_errorReporter.typeError(var.location(), "Mapping types can only have a data location of \"storage\" and thus only be parameters or return variables for internal or library functions.");
else
m_errorReporter.typeError(var.location(), "Mapping types can only have a data location of \"storage\"." );
}
else
{
solAssert(isLibraryFunction || !_function.isPublic(), "Mapping types for parameters or return variables can only be used in internal or library functions.");
}
}
else
{
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() &&
!_function.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2) &&
!typeSupportedByOldABIEncoder(*type(var), isLibraryFunction)
)
m_errorReporter.typeError(
var.location(),
"This type is only supported in the new experimental ABI encoder. "
"Use \"pragma experimental ABIEncoderV2;\" to enable the feature."
);
};
for (ASTPointer<VariableDeclaration> const& var: _function.parameters())
{
2019-01-17 11:59:11 +00:00
TypePointer baseType = type(*var);
if (auto const* arrayType = dynamic_cast<ArrayType const*>(baseType.get()))
{
baseType = arrayType->baseType();
if (
!m_scope->isInterface() &&
baseType->dataStoredIn(DataLocation::CallData) &&
baseType->isDynamicallyEncoded()
)
m_errorReporter.typeError(var->location(), "Calldata arrays with dynamically encoded base types are not yet supported.");
}
2019-01-17 11:59:11 +00:00
while (auto const* arrayType = dynamic_cast<ArrayType const*>(baseType.get()))
baseType = arrayType->baseType();
if (
!m_scope->isInterface() &&
baseType->dataStoredIn(DataLocation::CallData)
)
if (auto const* structType = dynamic_cast<StructType const*>(baseType.get()))
if (structType->isDynamicallyEncoded())
m_errorReporter.typeError(var->location(), "Dynamically encoded calldata structs are not yet supported.");
checkArgumentAndReturnParameter(*var);
var->accept(*this);
}
for (ASTPointer<VariableDeclaration> const& var: _function.returnParameters())
{
checkArgumentAndReturnParameter(*var);
var->accept(*this);
}
set<Declaration const*> modifiers;
for (ASTPointer<ModifierInvocation> const& modifier: _function.modifiers())
{
visitManually(
*modifier,
_function.isConstructor() ?
2015-09-21 16:55:58 +00:00
dynamic_cast<ContractDefinition const&>(*_function.scope()).annotation().linearizedBaseContracts :
vector<ContractDefinition const*>()
);
Declaration const* decl = &dereference(*modifier->name());
if (modifiers.count(decl))
{
if (dynamic_cast<ContractDefinition const*>(decl))
m_errorReporter.declarationError(modifier->location(), "Base constructor already provided.");
}
else
modifiers.insert(decl);
}
2019-01-17 11:59:11 +00:00
if (m_scope->isInterface())
{
if (_function.isImplemented())
m_errorReporter.typeError(_function.location(), "Functions in interfaces cannot have an implementation.");
if (_function.visibility() != FunctionDefinition::Visibility::External)
m_errorReporter.typeError(_function.location(), "Functions in interfaces must be declared external.");
if (_function.isConstructor())
m_errorReporter.typeError(_function.location(), "Constructor cannot be defined in interfaces.");
}
2017-08-16 21:19:08 +00:00
else if (m_scope->contractKind() == ContractDefinition::ContractKind::Library)
if (_function.isConstructor())
m_errorReporter.typeError(_function.location(), "Constructor cannot be defined in libraries.");
if (_function.isImplemented())
_function.body().accept(*this);
else if (_function.isConstructor())
m_errorReporter.typeError(_function.location(), "Constructor must be implemented if declared.");
else if (isLibraryFunction && _function.visibility() <= FunctionDefinition::Visibility::Internal)
m_errorReporter.typeError(_function.location(), "Internal library function must be implemented if declared.");
return false;
}
bool TypeChecker::visit(VariableDeclaration const& _variable)
{
// Forbid any variable declarations inside interfaces unless they are part of
// * a function's input/output parameters,
// * or inside of a struct definition.
if (
2019-01-17 11:59:11 +00:00
m_scope->isInterface()
&& !_variable.isCallableParameter()
&& !m_insideStruct
)
m_errorReporter.typeError(_variable.location(), "Variables cannot be declared in interfaces.");
// type is filled either by ReferencesResolver directly from the type name or by
// TypeChecker at the VariableDeclarationStatement level.
TypePointer varType = _variable.annotation().type;
2018-11-28 10:48:51 +00:00
solAssert(!!varType, "Variable type not provided.");
2017-03-01 18:12:40 +00:00
if (_variable.value())
expectType(*_variable.value(), *varType);
if (_variable.isConstant())
{
if (!_variable.type()->isValueType())
{
bool allowed = false;
if (auto arrayType = dynamic_cast<ArrayType const*>(_variable.type().get()))
2017-09-18 10:31:55 +00:00
allowed = arrayType->isByteArray();
if (!allowed)
m_errorReporter.typeError(_variable.location(), "Constants of non-value type not yet implemented.");
}
if (!_variable.value())
m_errorReporter.typeError(_variable.location(), "Uninitialized \"constant\" variable.");
2017-03-01 18:12:40 +00:00
else if (!_variable.value()->annotation().isPure)
m_errorReporter.typeError(
_variable.value()->location(),
"Initial value for constant variable has to be compile-time constant."
);
}
if (!_variable.isStateVariable())
{
if (varType->dataStoredIn(DataLocation::Memory) || varType->dataStoredIn(DataLocation::CallData))
if (!varType->canLiveOutsideStorage())
m_errorReporter.typeError(_variable.location(), "Type " + varType->toString() + " is only valid in storage.");
}
else if (_variable.visibility() >= VariableDeclaration::Visibility::Public)
{
FunctionType getter(_variable);
if (!_variable.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2))
{
vector<string> unsupportedTypes;
for (auto const& param: getter.parameterTypes() + getter.returnParameterTypes())
if (!typeSupportedByOldABIEncoder(*param, false /* isLibrary */))
unsupportedTypes.emplace_back(param->toString());
if (!unsupportedTypes.empty())
m_errorReporter.typeError(_variable.location(),
"The following types are only supported for getters in the new experimental ABI encoder: " +
joinHumanReadable(unsupportedTypes) +
". Either remove \"public\" or use \"pragma experimental ABIEncoderV2;\" to enable the feature."
);
}
if (!getter.interfaceFunctionType())
m_errorReporter.typeError(_variable.location(), "Internal or recursive type is not allowed for public state variables.");
}
switch (varType->category())
{
case Type::Category::Array:
if (auto arrayType = dynamic_cast<ArrayType const*>(varType.get()))
if (
((arrayType->location() == DataLocation::Memory) ||
(arrayType->location() == DataLocation::CallData)) &&
!arrayType->validForCalldata()
)
m_errorReporter.typeError(_variable.location(), "Array is too large to be encoded.");
break;
case Type::Category::Mapping:
if (auto mappingType = dynamic_cast<MappingType const*>(varType.get()))
if (
mappingType->keyType()->isDynamicallySized() &&
_variable.visibility() == Declaration::Visibility::Public
)
m_errorReporter.typeError(_variable.location(), "Dynamically-sized keys for public mappings are not supported.");
break;
default:
break;
}
return false;
}
void TypeChecker::visitManually(
ModifierInvocation const& _modifier,
vector<ContractDefinition const*> const& _bases
)
{
std::vector<ASTPointer<Expression>> const& arguments =
_modifier.arguments() ? *_modifier.arguments() : std::vector<ASTPointer<Expression>>();
for (ASTPointer<Expression> const& argument: arguments)
argument->accept(*this);
_modifier.name()->accept(*this);
auto const* declaration = &dereference(*_modifier.name());
vector<ASTPointer<VariableDeclaration>> emptyParameterList;
vector<ASTPointer<VariableDeclaration>> const* parameters = nullptr;
if (auto modifierDecl = dynamic_cast<ModifierDefinition const*>(declaration))
parameters = &modifierDecl->parameters();
else
// check parameters for Base constructors
for (ContractDefinition const* base: _bases)
if (declaration == base)
{
if (auto referencedConstructor = base->constructor())
parameters = &referencedConstructor->parameters();
else
parameters = &emptyParameterList;
break;
}
if (!parameters)
2016-01-08 14:20:20 +00:00
{
m_errorReporter.typeError(_modifier.location(), "Referenced declaration is neither modifier nor base class.");
2016-01-08 14:20:20 +00:00
return;
}
if (parameters->size() != arguments.size())
{
m_errorReporter.typeError(
_modifier.location(),
"Wrong argument count for modifier invocation: " +
toString(arguments.size()) +
" arguments given but expected " +
toString(parameters->size()) +
"."
);
return;
}
for (size_t i = 0; i < arguments.size(); ++i)
if (!type(*arguments[i])->isImplicitlyConvertibleTo(*type(*(*parameters)[i])))
m_errorReporter.typeError(
arguments[i]->location(),
"Invalid type for argument in modifier invocation. "
"Invalid implicit conversion from " +
type(*arguments[i])->toString() +
" to " +
type(*(*parameters)[i])->toString() +
" requested."
);
}
bool TypeChecker::visit(EventDefinition const& _eventDef)
{
solAssert(_eventDef.visibility() > Declaration::Visibility::Internal, "");
unsigned numIndexed = 0;
for (ASTPointer<VariableDeclaration> const& var: _eventDef.parameters())
{
if (var->isIndexed())
numIndexed++;
if (!type(*var)->canLiveOutsideStorage())
m_errorReporter.typeError(var->location(), "Type is required to live outside storage.");
if (!type(*var)->interfaceType(false))
2017-06-01 09:48:38 +00:00
m_errorReporter.typeError(var->location(), "Internal or recursive type is not allowed as event parameter type.");
if (
!_eventDef.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2) &&
!typeSupportedByOldABIEncoder(*type(*var), false /* isLibrary */)
)
m_errorReporter.typeError(
var->location(),
"This type is only supported in the new experimental ABI encoder. "
"Use \"pragma experimental ABIEncoderV2;\" to enable the feature."
);
}
if (_eventDef.isAnonymous() && numIndexed > 4)
m_errorReporter.typeError(_eventDef.location(), "More than 4 indexed arguments for anonymous event.");
else if (!_eventDef.isAnonymous() && numIndexed > 3)
m_errorReporter.typeError(_eventDef.location(), "More than 3 indexed arguments for event.");
return false;
}
void TypeChecker::endVisit(FunctionTypeName const& _funType)
{
FunctionType const& fun = dynamic_cast<FunctionType const&>(*_funType.annotation().type);
if (fun.kind() == FunctionType::Kind::External)
solAssert(fun.canBeUsedExternally(false), "External function type uses internal types.");
}
bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
{
// External references have already been resolved in a prior stage and stored in the annotation.
// We run the resolve step again regardless.
yul::ExternalIdentifierAccess::Resolver identifierAccess = [&](
yul::Identifier const& _identifier,
yul::IdentifierContext _context,
bool
2017-02-23 16:38:42 +00:00
)
{
auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier);
if (ref == _inlineAssembly.annotation().externalReferences.end())
return size_t(-1);
Declaration const* declaration = ref->second.declaration;
solAssert(!!declaration, "");
bool requiresStorage = ref->second.isSlot || ref->second.isOffset;
if (auto var = dynamic_cast<VariableDeclaration const*>(declaration))
{
if (var->isConstant())
{
m_errorReporter.typeError(_identifier.location, "Constant variables not supported by inline assembly.");
return size_t(-1);
}
else if (requiresStorage)
{
2017-04-21 17:13:46 +00:00
if (!var->isStateVariable() && !var->type()->dataStoredIn(DataLocation::Storage))
{
m_errorReporter.typeError(_identifier.location, "The suffixes _offset and _slot can only be used on storage variables.");
2017-04-21 17:13:46 +00:00
return size_t(-1);
}
else if (_context != yul::IdentifierContext::RValue)
2017-04-21 17:13:46 +00:00
{
m_errorReporter.typeError(_identifier.location, "Storage variables cannot be assigned to.");
2017-04-21 17:13:46 +00:00
return size_t(-1);
}
}
else if (!var->isLocalVariable())
{
m_errorReporter.typeError(_identifier.location, "Only local variables are supported. To access storage variables, use the _slot and _offset suffixes.");
return size_t(-1);
}
2017-04-21 17:13:46 +00:00
else if (var->type()->dataStoredIn(DataLocation::Storage))
{
m_errorReporter.typeError(_identifier.location, "You have to use the _slot or _offset suffix to access storage reference variables.");
return size_t(-1);
}
2017-04-21 17:13:46 +00:00
else if (var->type()->sizeOnStack() != 1)
{
if (var->type()->dataStoredIn(DataLocation::CallData))
m_errorReporter.typeError(_identifier.location, "Call data elements cannot be accessed directly. Copy to a local variable first or use \"calldataload\" or \"calldatacopy\" with manually determined offsets and sizes.");
else
m_errorReporter.typeError(_identifier.location, "Only types that use one stack slot are supported.");
return size_t(-1);
}
}
else if (requiresStorage)
{
m_errorReporter.typeError(_identifier.location, "The suffixes _offset and _slot can only be used on storage variables.");
return size_t(-1);
}
else if (_context == yul::IdentifierContext::LValue)
{
m_errorReporter.typeError(_identifier.location, "Only local variables can be assigned to in inline assembly.");
return size_t(-1);
}
if (_context == yul::IdentifierContext::RValue)
{
solAssert(!!declaration->type(), "Type of declaration required but not yet determined.");
if (dynamic_cast<FunctionDefinition const*>(declaration))
{
}
else if (dynamic_cast<VariableDeclaration const*>(declaration))
{
}
else if (auto contract = dynamic_cast<ContractDefinition const*>(declaration))
{
if (!contract->isLibrary())
{
m_errorReporter.typeError(_identifier.location, "Expected a library.");
return size_t(-1);
}
}
else
return size_t(-1);
}
ref->second.valueSize = 1;
return size_t(1);
2017-02-23 16:38:42 +00:00
};
solAssert(!_inlineAssembly.annotation().analysisInfo, "");
_inlineAssembly.annotation().analysisInfo = make_shared<yul::AsmAnalysisInfo>();
yul::AsmAnalyzer analyzer(
*_inlineAssembly.annotation().analysisInfo,
m_errorReporter,
m_evmVersion,
Error::Type::SyntaxError,
2018-12-06 23:56:16 +00:00
yul::EVMDialect::looseAssemblyForEVM(),
identifierAccess
);
if (!analyzer.analyze(_inlineAssembly.operations()))
2017-02-15 15:47:54 +00:00
return false;
return true;
}
bool TypeChecker::visit(IfStatement const& _ifStatement)
{
expectType(_ifStatement.condition(), BoolType());
_ifStatement.trueStatement().accept(*this);
if (_ifStatement.falseStatement())
_ifStatement.falseStatement()->accept(*this);
return false;
}
bool TypeChecker::visit(WhileStatement const& _whileStatement)
{
expectType(_whileStatement.condition(), BoolType());
_whileStatement.body().accept(*this);
return false;
}
bool TypeChecker::visit(ForStatement const& _forStatement)
{
if (_forStatement.initializationExpression())
_forStatement.initializationExpression()->accept(*this);
if (_forStatement.condition())
expectType(*_forStatement.condition(), BoolType());
if (_forStatement.loopExpression())
_forStatement.loopExpression()->accept(*this);
_forStatement.body().accept(*this);
return false;
}
void TypeChecker::endVisit(Return const& _return)
{
ParameterList const* params = _return.annotation().functionReturnParameters;
if (!_return.expression())
{
if (params && !params->parameters().empty())
m_errorReporter.typeError(_return.location(), "Return arguments required.");
return;
}
if (!params)
2015-10-12 21:02:35 +00:00
{
m_errorReporter.typeError(_return.location(), "Return arguments not allowed.");
2015-10-12 21:02:35 +00:00
return;
}
TypePointers returnTypes;
for (auto const& var: params->parameters())
returnTypes.push_back(type(*var));
if (auto tupleType = dynamic_cast<TupleType const*>(type(*_return.expression()).get()))
{
if (tupleType->components().size() != params->parameters().size())
m_errorReporter.typeError(_return.location(), "Different number of arguments in return statement than in returns declaration.");
2015-10-12 21:02:35 +00:00
else if (!tupleType->isImplicitlyConvertibleTo(TupleType(returnTypes)))
m_errorReporter.typeError(
_return.expression()->location(),
2015-10-12 21:02:35 +00:00
"Return argument type " +
type(*_return.expression())->toString() +
" is not implicitly convertible to expected type " +
TupleType(returnTypes).toString(false) +
"."
);
}
else if (params->parameters().size() != 1)
m_errorReporter.typeError(_return.location(), "Different number of arguments in return statement than in returns declaration.");
else
{
TypePointer const& expected = type(*params->parameters().front());
if (!type(*_return.expression())->isImplicitlyConvertibleTo(*expected))
m_errorReporter.typeError(
_return.expression()->location(),
"Return argument type " +
type(*_return.expression())->toString() +
" is not implicitly convertible to expected type (type of first return variable) " +
expected->toString() +
"."
);
}
}
2018-02-16 15:55:21 +00:00
void TypeChecker::endVisit(EmitStatement const& _emit)
{
if (
_emit.eventCall().annotation().kind != FunctionCallKind::FunctionCall ||
type(_emit.eventCall().expression())->category() != Type::Category::Function ||
2018-02-16 15:55:21 +00:00
dynamic_cast<FunctionType const&>(*type(_emit.eventCall().expression())).kind() != FunctionType::Kind::Event
)
2018-02-16 16:32:41 +00:00
m_errorReporter.typeError(_emit.eventCall().expression().location(), "Expression has to be an event invocation.");
m_insideEmitStatement = false;
2018-02-16 15:55:21 +00:00
}
2018-07-10 20:20:10 +00:00
namespace
{
/**
2018-07-10 20:20:10 +00:00
* @returns a suggested left-hand-side of a multi-variable declaration contairing
* the variable declarations given in @a _decls.
*/
string createTupleDecl(vector<ASTPointer<VariableDeclaration>> const& _decls)
{
vector<string> components;
for (ASTPointer<VariableDeclaration> const& decl: _decls)
if (decl)
{
solAssert(decl->annotation().type, "");
components.emplace_back(decl->annotation().type->toString(false) + " " + decl->name());
}
else
components.emplace_back();
2018-07-10 20:20:10 +00:00
if (_decls.size() == 1)
return components.front();
else
return "(" + boost::algorithm::join(components, ", ") + ")";
}
bool typeCanBeExpressed(vector<ASTPointer<VariableDeclaration>> const& decls)
{
for (ASTPointer<VariableDeclaration> const& decl: decls)
{
// skip empty tuples (they can be expressed of course)
if (!decl)
continue;
if (!decl->annotation().type)
return false;
if (auto functionType = dynamic_cast<FunctionType const*>(decl->annotation().type.get()))
if (
functionType->kind() != FunctionType::Kind::Internal &&
functionType->kind() != FunctionType::Kind::External
)
return false;
}
return true;
}
2018-07-10 20:20:10 +00:00
}
bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
{
if (!_statement.initialValue())
{
// No initial value is only permitted for single variables with specified type.
if (_statement.declarations().size() != 1 || !_statement.declarations().front())
{
if (boost::algorithm::all_of_equal(_statement.declarations(), nullptr))
{
// The syntax checker has already generated an error for this case (empty LHS tuple).
solAssert(m_errorReporter.hasErrors(), "");
// It is okay to return here, as there are no named components on the
// left-hand-side that could cause any damage later.
return false;
}
else
// Bailing out *fatal* here, as those (untyped) vars may be used later, and diagnostics wouldn't be helpful then.
m_errorReporter.fatalTypeError(_statement.location(), "Use of the \"var\" keyword is disallowed.");
}
VariableDeclaration const& varDecl = *_statement.declarations().front();
if (!varDecl.annotation().type)
m_errorReporter.fatalTypeError(_statement.location(), "Use of the \"var\" keyword is disallowed.");
2015-10-12 21:02:35 +00:00
if (auto ref = dynamic_cast<ReferenceType const*>(type(varDecl).get()))
{
if (ref->dataStoredIn(DataLocation::Storage))
{
string errorText{"Uninitialized storage pointer."};
solAssert(varDecl.referenceLocation() != VariableDeclaration::Location::Unspecified, "Expected a specified location at this point");
solAssert(m_scope, "");
m_errorReporter.declarationError(varDecl.location(), errorText);
}
}
else if (dynamic_cast<MappingType const*>(type(varDecl).get()))
m_errorReporter.typeError(
varDecl.location(),
"Uninitialized mapping. Mappings cannot be created dynamically, you have to assign them from a state variable."
);
varDecl.accept(*this);
return false;
}
// Here we have an initial value and might have to derive some types before we can visit
// the variable declaration(s).
_statement.initialValue()->accept(*this);
2015-10-09 18:44:56 +00:00
TypePointers valueTypes;
2015-10-12 21:02:35 +00:00
if (auto tupleType = dynamic_cast<TupleType const*>(type(*_statement.initialValue()).get()))
2015-10-09 18:44:56 +00:00
valueTypes = tupleType->components();
else
2015-10-12 21:02:35 +00:00
valueTypes = TypePointers{type(*_statement.initialValue())};
2015-10-09 18:44:56 +00:00
vector<ASTPointer<VariableDeclaration>> const& variables = _statement.declarations();
2015-10-13 12:31:24 +00:00
if (variables.empty())
// We already have an error for this in the SyntaxChecker.
solAssert(m_errorReporter.hasErrors(), "");
2018-05-03 17:21:42 +00:00
else if (valueTypes.size() != variables.size())
m_errorReporter.typeError(
_statement.location(),
"Different number of components on the left hand side (" +
toString(variables.size()) +
") than on the right hand side (" +
2015-10-09 18:44:56 +00:00
toString(valueTypes.size()) +
")."
2015-10-09 18:44:56 +00:00
);
bool autoTypeDeductionNeeded = false;
for (size_t i = 0; i < min(variables.size(), valueTypes.size()); ++i)
{
if (!variables[i])
continue;
VariableDeclaration const& var = *variables[i];
solAssert(!var.value(), "Value has to be tied to statement.");
2015-10-09 18:44:56 +00:00
TypePointer const& valueComponentType = valueTypes[i];
solAssert(!!valueComponentType, "");
if (!var.annotation().type)
{
autoTypeDeductionNeeded = true;
// Infer type from value.
solAssert(!var.typeName(), "");
var.annotation().type = valueComponentType->mobileType();
if (!var.annotation().type)
{
if (valueComponentType->category() == Type::Category::RationalNumber)
m_errorReporter.fatalTypeError(
_statement.initialValue()->location(),
"Invalid rational " +
valueComponentType->toString() +
2017-10-05 13:23:25 +00:00
" (absolute value too large or division by zero)."
);
else
solAssert(false, "");
}
else if (*var.annotation().type == TupleType())
solAssert(false, "Cannot declare variable with void (empty tuple) type.");
2017-06-22 14:08:59 +00:00
else if (valueComponentType->category() == Type::Category::RationalNumber)
{
string typeName = var.annotation().type->toString(true);
string extension;
if (auto type = dynamic_cast<IntegerType const*>(var.annotation().type.get()))
{
2018-04-30 21:56:30 +00:00
unsigned numBits = type->numBits();
2017-06-22 14:08:59 +00:00
bool isSigned = type->isSigned();
2018-04-30 21:56:30 +00:00
solAssert(numBits > 0, "");
string minValue;
string maxValue;
2017-06-22 14:08:59 +00:00
if (isSigned)
{
2017-06-22 14:08:59 +00:00
numBits--;
minValue = "-" + bigint(bigint(1) << numBits).str();
}
else
minValue = "0";
maxValue = bigint((bigint(1) << numBits) - 1).str();
extension = ", which can hold values between " + minValue + " and " + maxValue;
2017-06-22 14:08:59 +00:00
}
else
solAssert(dynamic_cast<FixedPointType const*>(var.annotation().type.get()), "Unknown type.");
}
var.accept(*this);
}
else
{
var.accept(*this);
if (!valueComponentType->isImplicitlyConvertibleTo(*var.annotation().type))
{
auto errorMsg = "Type " +
valueComponentType->toString() +
" is not implicitly convertible to expected type " +
var.annotation().type->toString();
if (
valueComponentType->category() == Type::Category::RationalNumber &&
2016-05-10 12:30:24 +00:00
dynamic_cast<RationalNumberType const&>(*valueComponentType).isFractional() &&
valueComponentType->mobileType()
)
{
if (var.annotation().type->operator==(*valueComponentType->mobileType()))
m_errorReporter.typeError(
_statement.location(),
errorMsg + ", but it can be explicitly converted."
);
else
m_errorReporter.typeError(
_statement.location(),
errorMsg +
". Try converting to type " +
valueComponentType->mobileType()->toString() +
" or use an explicit conversion."
);
}
else
m_errorReporter.typeError(_statement.location(), errorMsg + ".");
}
}
}
if (autoTypeDeductionNeeded)
{
if (!typeCanBeExpressed(variables))
2018-07-10 20:20:10 +00:00
m_errorReporter.syntaxError(
_statement.location(),
"Use of the \"var\" keyword is disallowed. "
2018-07-10 20:20:10 +00:00
"Type cannot be expressed in syntax."
);
else
2018-07-10 20:20:10 +00:00
m_errorReporter.syntaxError(
_statement.location(),
"Use of the \"var\" keyword is disallowed. "
"Use explicit declaration `" + createTupleDecl(variables) + " = ...´ instead."
2018-07-10 20:20:10 +00:00
);
}
return false;
}
void TypeChecker::endVisit(ExpressionStatement const& _statement)
{
if (type(_statement.expression())->category() == Type::Category::RationalNumber)
if (!dynamic_cast<RationalNumberType const&>(*type(_statement.expression())).mobileType())
m_errorReporter.typeError(_statement.expression().location(), "Invalid rational number.");
2016-06-21 12:36:23 +00:00
if (auto call = dynamic_cast<FunctionCall const*>(&_statement.expression()))
{
if (auto callType = dynamic_cast<FunctionType const*>(type(call->expression()).get()))
{
auto kind = callType->kind();
if (
2017-08-01 09:32:23 +00:00
kind == FunctionType::Kind::BareCall ||
kind == FunctionType::Kind::BareCallCode ||
2018-08-15 12:40:20 +00:00
kind == FunctionType::Kind::BareDelegateCall ||
kind == FunctionType::Kind::BareStaticCall
)
m_errorReporter.warning(_statement.location(), "Return value of low-level calls not used.");
else if (kind == FunctionType::Kind::Send)
m_errorReporter.warning(_statement.location(), "Failure condition of 'send' ignored. Consider using 'transfer' instead.");
}
}
}
bool TypeChecker::visit(Conditional const& _conditional)
2015-12-22 16:50:06 +00:00
{
expectType(_conditional.condition(), BoolType());
_conditional.trueExpression().accept(*this);
_conditional.falseExpression().accept(*this);
TypePointer trueType = type(_conditional.trueExpression())->mobileType();
TypePointer falseType = type(_conditional.falseExpression())->mobileType();
TypePointer commonType;
2016-10-21 10:30:58 +00:00
if (!trueType)
m_errorReporter.typeError(_conditional.trueExpression().location(), "Invalid mobile type in true expression.");
else
commonType = trueType;
2016-10-21 10:30:58 +00:00
if (!falseType)
m_errorReporter.typeError(_conditional.falseExpression().location(), "Invalid mobile type in false expression.");
else
commonType = falseType;
if (!trueType && !falseType)
BOOST_THROW_EXCEPTION(FatalError());
else if (trueType && falseType)
{
commonType = Type::commonType(trueType, falseType);
if (!commonType)
{
m_errorReporter.typeError(
_conditional.location(),
"True expression's type " +
trueType->toString() +
" doesn't match false expression's type " +
falseType->toString() +
"."
);
// even we can't find a common type, we have to set a type here,
// otherwise the upper statement will not be able to check the type.
commonType = trueType;
}
}
_conditional.annotation().type = commonType;
2017-03-01 18:12:40 +00:00
_conditional.annotation().isPure =
_conditional.condition().annotation().isPure &&
_conditional.trueExpression().annotation().isPure &&
_conditional.falseExpression().annotation().isPure;
if (_conditional.annotation().lValueRequested)
m_errorReporter.typeError(
_conditional.location(),
"Conditional expression as left value is not supported yet."
);
return false;
2015-12-22 16:50:06 +00:00
}
void TypeChecker::checkExpressionAssignment(Type const& _type, Expression const& _expression)
{
if (auto const* tupleExpression = dynamic_cast<TupleExpression const*>(&_expression))
{
2018-08-03 15:38:06 +00:00
auto const* tupleType = dynamic_cast<TupleType const*>(&_type);
auto const& types = tupleType ? tupleType->components() : vector<TypePointer> { _type.shared_from_this() };
solAssert(
tupleExpression->components().size() == types.size() || m_errorReporter.hasErrors(),
"Array sizes don't match or no errors generated."
);
for (size_t i = 0; i < min(tupleExpression->components().size(), types.size()); i++)
2018-08-03 15:38:06 +00:00
if (types[i])
{
solAssert(!!tupleExpression->components()[i], "");
checkExpressionAssignment(*types[i], *tupleExpression->components()[i]);
}
}
else if (_type.category() == Type::Category::Mapping)
{
bool isLocalOrReturn = false;
if (auto const* identifier = dynamic_cast<Identifier const*>(&_expression))
if (auto const *variableDeclaration = dynamic_cast<VariableDeclaration const*>(identifier->annotation().referencedDeclaration))
if (variableDeclaration->isLocalOrReturn())
isLocalOrReturn = true;
if (!isLocalOrReturn)
m_errorReporter.typeError(_expression.location(), "Mappings cannot be assigned to.");
}
}
bool TypeChecker::visit(Assignment const& _assignment)
{
requireLValue(_assignment.leftHandSide());
TypePointer t = type(_assignment.leftHandSide());
_assignment.annotation().type = t;
checkExpressionAssignment(*t, _assignment.leftHandSide());
2015-10-14 13:19:50 +00:00
if (TupleType const* tupleType = dynamic_cast<TupleType const*>(t.get()))
{
if (_assignment.assignmentOperator() != Token::Assign)
m_errorReporter.typeError(
_assignment.location(),
"Compound assignment is not allowed for tuple types."
);
2015-10-15 14:02:00 +00:00
// Sequenced assignments of tuples is not valid, make the result a "void" type.
_assignment.annotation().type = make_shared<TupleType>();
2018-05-03 17:21:42 +00:00
2015-10-14 13:19:50 +00:00
expectType(_assignment.rightHandSide(), *tupleType);
2017-07-26 12:19:46 +00:00
// expectType does not cause fatal errors, so we have to check again here.
if (dynamic_cast<TupleType const*>(type(_assignment.rightHandSide()).get()))
2017-07-26 12:19:46 +00:00
checkDoubleStorageAssignment(_assignment);
2015-10-14 13:19:50 +00:00
}
else if (_assignment.assignmentOperator() == Token::Assign)
expectType(_assignment.rightHandSide(), *t);
else
{
// compound assignment
_assignment.rightHandSide().accept(*this);
TypePointer resultType = t->binaryOperatorResult(
TokenTraits::AssignmentToBinaryOp(_assignment.assignmentOperator()),
type(_assignment.rightHandSide())
);
if (!resultType || *resultType != *t)
m_errorReporter.typeError(
_assignment.location(),
"Operator " +
string(TokenTraits::toString(_assignment.assignmentOperator())) +
" not compatible with types " +
t->toString() +
" and " +
type(_assignment.rightHandSide())->toString()
);
}
return false;
}
2015-10-12 21:02:35 +00:00
bool TypeChecker::visit(TupleExpression const& _tuple)
{
vector<ASTPointer<Expression>> const& components = _tuple.components();
TypePointers types;
2015-10-12 21:02:35 +00:00
if (_tuple.annotation().lValueRequested)
{
if (_tuple.isInlineArray())
m_errorReporter.fatalTypeError(_tuple.location(), "Inline array type cannot be declared as LValue.");
2015-10-12 21:02:35 +00:00
for (auto const& component: components)
if (component)
{
requireLValue(*component);
types.push_back(type(*component));
}
else
types.push_back(TypePointer());
if (components.size() == 1)
_tuple.annotation().type = type(*components[0]);
else
_tuple.annotation().type = make_shared<TupleType>(types);
2015-10-12 21:02:35 +00:00
// If some of the components are not LValues, the error is reported above.
_tuple.annotation().isLValue = true;
}
else
{
2017-03-01 18:12:40 +00:00
bool isPure = true;
TypePointer inlineArrayType;
2015-10-12 21:02:35 +00:00
for (size_t i = 0; i < components.size(); ++i)
{
2018-07-10 10:37:09 +00:00
if (!components[i])
m_errorReporter.fatalTypeError(_tuple.location(), "Tuple component cannot be empty.");
2015-10-12 21:02:35 +00:00
else if (components[i])
{
components[i]->accept(*this);
types.push_back(type(*components[i]));
2017-09-18 10:39:17 +00:00
if (types[i]->category() == Type::Category::Tuple)
if (dynamic_cast<TupleType const&>(*types[i]).components().empty())
{
2018-04-23 15:11:41 +00:00
if (_tuple.isInlineArray())
m_errorReporter.fatalTypeError(components[i]->location(), "Array component cannot be empty.");
2018-07-10 10:37:09 +00:00
m_errorReporter.typeError(components[i]->location(), "Tuple component cannot be empty.");
}
2017-09-18 10:39:17 +00:00
// Note: code generation will visit each of the expression even if they are not assigned from.
if (types[i]->category() == Type::Category::RationalNumber && components.size() > 1)
2017-09-18 10:39:17 +00:00
if (!dynamic_cast<RationalNumberType const&>(*types[i]).mobileType())
m_errorReporter.fatalTypeError(components[i]->location(), "Invalid rational number.");
2016-10-21 10:30:58 +00:00
if (_tuple.isInlineArray())
{
2019-02-07 14:53:49 +00:00
solAssert(!!types[i], "Inline array cannot have empty components");
2016-10-21 10:30:58 +00:00
if ((i == 0 || inlineArrayType) && !types[i]->mobileType())
m_errorReporter.fatalTypeError(components[i]->location(), "Invalid mobile type.");
2016-10-21 10:30:58 +00:00
if (i == 0)
2017-03-06 13:38:29 +00:00
inlineArrayType = types[i]->mobileType();
2016-10-21 10:30:58 +00:00
else if (inlineArrayType)
inlineArrayType = Type::commonType(inlineArrayType, types[i]);
2016-10-21 10:30:58 +00:00
}
2017-03-01 18:12:40 +00:00
if (!components[i]->annotation().isPure)
isPure = false;
2015-10-12 21:02:35 +00:00
}
else
types.push_back(TypePointer());
}
2017-03-01 18:12:40 +00:00
_tuple.annotation().isPure = isPure;
if (_tuple.isInlineArray())
{
if (!inlineArrayType)
m_errorReporter.fatalTypeError(_tuple.location(), "Unable to deduce common type for array elements.");
else if (!inlineArrayType->canLiveOutsideStorage())
m_errorReporter.fatalTypeError(_tuple.location(), "Type " + inlineArrayType->toString() + " is only valid in storage.");
_tuple.annotation().type = make_shared<ArrayType>(DataLocation::Memory, inlineArrayType, types.size());
}
2015-10-12 21:02:35 +00:00
else
{
if (components.size() == 1)
_tuple.annotation().type = type(*components[0]);
else
_tuple.annotation().type = make_shared<TupleType>(types);
2015-10-12 21:02:35 +00:00
}
2015-10-12 21:02:35 +00:00
}
return false;
}
bool TypeChecker::visit(UnaryOperation const& _operation)
{
// Inc, Dec, Add, Sub, Not, BitNot, Delete
Token op = _operation.getOperator();
bool const modifying = (op == Token::Inc || op == Token::Dec || op == Token::Delete);
2017-03-01 18:12:40 +00:00
if (modifying)
requireLValue(_operation.subExpression());
else
_operation.subExpression().accept(*this);
TypePointer const& subExprType = type(_operation.subExpression());
TypePointer t = type(_operation.subExpression())->unaryOperatorResult(op);
if (!t)
{
m_errorReporter.typeError(
_operation.location(),
"Unary operator " +
string(TokenTraits::toString(op)) +
" cannot be applied to type " +
subExprType->toString()
);
t = subExprType;
}
_operation.annotation().type = t;
2017-03-01 18:12:40 +00:00
_operation.annotation().isPure = !modifying && _operation.subExpression().annotation().isPure;
return false;
}
void TypeChecker::endVisit(BinaryOperation const& _operation)
{
TypePointer const& leftType = type(_operation.leftExpression());
TypePointer const& rightType = type(_operation.rightExpression());
TypeResult result = leftType->binaryOperatorResult(_operation.getOperator(), rightType);
TypePointer commonType = result.get();
if (!commonType)
{
m_errorReporter.typeError(
_operation.location(),
"Operator " +
string(TokenTraits::toString(_operation.getOperator())) +
" not compatible with types " +
leftType->toString() +
" and " +
rightType->toString() +
(!result.message().empty() ? ". " + result.message() : "")
);
commonType = leftType;
}
_operation.annotation().commonType = commonType;
_operation.annotation().type =
TokenTraits::isCompareOp(_operation.getOperator()) ?
make_shared<BoolType>() :
commonType;
2017-03-01 18:12:40 +00:00
_operation.annotation().isPure =
_operation.leftExpression().annotation().isPure &&
_operation.rightExpression().annotation().isPure;
2017-08-16 11:52:06 +00:00
if (_operation.getOperator() == Token::Exp || _operation.getOperator() == Token::SHL)
{
2017-08-16 11:52:06 +00:00
string operation = _operation.getOperator() == Token::Exp ? "exponentiation" : "shift";
if (
leftType->category() == Type::Category::RationalNumber &&
rightType->category() != Type::Category::RationalNumber
)
if ((
commonType->category() == Type::Category::Integer &&
dynamic_cast<IntegerType const&>(*commonType).numBits() != 256
) || (
commonType->category() == Type::Category::FixedPoint &&
dynamic_cast<FixedPointType const&>(*commonType).numBits() != 256
))
m_errorReporter.warning(
_operation.location(),
2017-08-16 11:52:06 +00:00
"Result of " + operation + " has type " + commonType->toString() + " and thus "
"might overflow. Silence this warning by converting the literal to the "
"expected type."
);
}
}
TypePointer TypeChecker::typeCheckTypeConversionAndRetrieveReturnType(
FunctionCall const& _functionCall
)
{
solAssert(_functionCall.annotation().kind == FunctionCallKind::TypeConversion, "");
TypePointer const& expressionType = type(_functionCall.expression());
vector<ASTPointer<Expression const>> const& arguments = _functionCall.arguments();
bool const isPositionalCall = _functionCall.names().empty();
2017-05-19 13:45:01 +00:00
TypePointer resultType = dynamic_cast<TypeType const&>(*expressionType).actualType();
if (arguments.size() != 1)
m_errorReporter.typeError(
_functionCall.location(),
"Exactly one argument expected for explicit type conversion."
);
else if (!isPositionalCall)
m_errorReporter.typeError(
_functionCall.location(),
"Type conversion cannot allow named arguments."
);
else
{
TypePointer const& argType = type(*arguments.front());
// Resulting data location is memory unless we are converting from a reference
// type with a different data location.
// (data location cannot yet be specified for type conversions)
DataLocation dataLoc = DataLocation::Memory;
if (auto argRefType = dynamic_cast<ReferenceType const*>(argType.get()))
dataLoc = argRefType->location();
if (auto type = dynamic_cast<ReferenceType const*>(resultType.get()))
resultType = type->copyForLocation(dataLoc, type->isPointer());
if (argType->isExplicitlyConvertibleTo(*resultType))
{
if (auto argArrayType = dynamic_cast<ArrayType const*>(argType.get()))
{
auto resultArrayType = dynamic_cast<ArrayType const*>(resultType.get());
solAssert(!!resultArrayType, "");
solAssert(
argArrayType->location() != DataLocation::Storage ||
(
(
resultArrayType->isPointer() ||
(argArrayType->isByteArray() && resultArrayType->isByteArray())
) &&
resultArrayType->location() == DataLocation::Storage
),
"Invalid explicit conversion to storage type."
);
}
}
else
{
if (
resultType->category() == Type::Category::Contract &&
argType->category() == Type::Category::Address
)
{
solAssert(dynamic_cast<ContractType const*>(resultType.get())->isPayable(), "");
solAssert(
dynamic_cast<AddressType const*>(argType.get())->stateMutability() <
StateMutability::Payable,
""
);
SecondarySourceLocation ssl;
if (
auto const* identifier = dynamic_cast<Identifier const*>(arguments.front().get())
)
if (
auto const* variableDeclaration = dynamic_cast<VariableDeclaration const*>(
identifier->annotation().referencedDeclaration
)
)
ssl.append(
"Did you mean to declare this variable as \"address payable\"?",
variableDeclaration->location()
);
m_errorReporter.typeError(
_functionCall.location(), ssl,
"Explicit type conversion not allowed from non-payable \"address\" to \"" +
resultType->toString() +
"\", which has a payable fallback function."
);
}
else
m_errorReporter.typeError(
_functionCall.location(),
"Explicit type conversion not allowed from \"" +
argType->toString() +
"\" to \"" +
resultType->toString() +
"\"."
);
}
if (resultType->category() == Type::Category::Address)
{
bool const payable = argType->isExplicitlyConvertibleTo(AddressType::addressPayable());
resultType = make_shared<AddressType>(
payable ? StateMutability::Payable : StateMutability::NonPayable
);
}
}
return resultType;
}
void TypeChecker::typeCheckFunctionCall(
FunctionCall const& _functionCall,
FunctionTypePointer _functionType
)
{
// Actual function call or struct constructor call.
solAssert(!!_functionType, "");
solAssert(_functionType->kind() != FunctionType::Kind::ABIDecode, "");
// Check for unsupported use of bare static call
if (
_functionType->kind() == FunctionType::Kind::BareStaticCall &&
!m_evmVersion.hasStaticCall()
)
m_errorReporter.typeError(
_functionCall.location(),
"\"staticcall\" is not supported by the VM version."
);
// Check for event outside of emit statement
if (!m_insideEmitStatement && _functionType->kind() == FunctionType::Kind::Event)
m_errorReporter.typeError(
_functionCall.location(),
"Event invocations have to be prefixed by \"emit\"."
);
// Perform standard function call type checking
typeCheckFunctionGeneralChecks(_functionCall, _functionType);
}
void TypeChecker::typeCheckABIEncodeFunctions(
FunctionCall const& _functionCall,
FunctionTypePointer _functionType
)
{
solAssert(!!_functionType, "");
solAssert(
_functionType->kind() == FunctionType::Kind::ABIEncode ||
_functionType->kind() == FunctionType::Kind::ABIEncodePacked ||
_functionType->kind() == FunctionType::Kind::ABIEncodeWithSelector ||
_functionType->kind() == FunctionType::Kind::ABIEncodeWithSignature,
"ABI function has unexpected FunctionType::Kind."
);
solAssert(_functionType->takesArbitraryParameters(), "ABI functions should be variadic.");
bool const isPacked = _functionType->kind() == FunctionType::Kind::ABIEncodePacked;
solAssert(_functionType->padArguments() != isPacked, "ABI function with unexpected padding");
2018-08-15 12:40:20 +00:00
bool const abiEncoderV2 = m_scope->sourceUnit().annotation().experimentalFeatures.count(
ExperimentalFeature::ABIEncoderV2
);
// Check for named arguments
if (!_functionCall.names().empty())
2017-07-31 19:31:12 +00:00
{
m_errorReporter.typeError(
_functionCall.location(),
"Named arguments cannot be used for functions that take arbitrary parameters."
);
return;
2017-07-31 19:31:12 +00:00
}
// Perform standard function call type checking
typeCheckFunctionGeneralChecks(_functionCall, _functionType);
// Check additional arguments for variadic functions
vector<ASTPointer<Expression const>> const& arguments = _functionCall.arguments();
for (size_t i = 0; i < arguments.size(); ++i)
{
auto const& argType = type(*arguments[i]);
if (argType->category() == Type::Category::RationalNumber)
{
auto const& rationalType = dynamic_cast<RationalNumberType const&>(*argType);
if (rationalType.isFractional())
{
m_errorReporter.typeError(
arguments[i]->location(),
2019-01-17 12:54:31 +00:00
"Fractional numbers cannot yet be encoded."
);
continue;
}
else if (!argType->mobileType())
{
m_errorReporter.typeError(
arguments[i]->location(),
"Invalid rational number (too large or division by zero)."
);
continue;
}
else if (isPacked)
{
m_errorReporter.typeError(
arguments[i]->location(),
"Cannot perform packed encoding for a literal."
" Please convert it to an explicit type first."
);
continue;
}
}
if (isPacked && !typeSupportedByOldABIEncoder(*argType, false /* isLibrary */))
{
m_errorReporter.typeError(
arguments[i]->location(),
"Type not supported in packed mode."
);
continue;
}
if (!argType->fullEncodingType(false, abiEncoderV2, !_functionType->padArguments()))
m_errorReporter.typeError(
arguments[i]->location(),
"This type cannot be encoded."
);
}
}
void TypeChecker::typeCheckFunctionGeneralChecks(
FunctionCall const& _functionCall,
FunctionTypePointer _functionType
)
{
// Actual function call or struct constructor call.
2018-06-30 16:09:13 +00:00
solAssert(!!_functionType, "");
solAssert(_functionType->kind() != FunctionType::Kind::ABIDecode, "");
2018-09-04 14:24:21 +00:00
bool const isPositionalCall = _functionCall.names().empty();
bool const isVariadic = _functionType->takesArbitraryParameters();
solAssert(
!isVariadic || _functionCall.annotation().kind == FunctionCallKind::FunctionCall,
"Struct constructor calls cannot be variadic."
);
TypePointers const& parameterTypes = _functionType->parameterTypes();
vector<ASTPointer<Expression const>> const& arguments = _functionCall.arguments();
vector<ASTPointer<ASTString>> const& argumentNames = _functionCall.names();
// Check number of passed in arguments
if (
arguments.size() < parameterTypes.size() ||
(!isVariadic && arguments.size() > parameterTypes.size())
)
{
bool const isStructConstructorCall =
_functionCall.annotation().kind == FunctionCallKind::StructConstructorCall;
string msg;
if (isVariadic)
msg +=
"Need at least " +
toString(parameterTypes.size()) +
" arguments for " +
string(isStructConstructorCall ? "struct constructor" : "function call") +
", but provided only " +
toString(arguments.size()) +
".";
else
msg +=
"Wrong argument count for " +
string(isStructConstructorCall ? "struct constructor" : "function call") +
": " +
toString(arguments.size()) +
" arguments given but " +
string(isVariadic ? "need at least " : "expected ") +
toString(parameterTypes.size()) +
".";
// Extend error message in case we try to construct a struct with mapping member.
if (isStructConstructorCall)
{
/// For error message: Struct members that were removed during conversion to memory.
TypePointer const expressionType = type(_functionCall.expression());
TypeType const& t = dynamic_cast<TypeType const&>(*expressionType);
auto const& structType = dynamic_cast<StructType const&>(*t.actualType());
set<string> membersRemovedForStructConstructor = structType.membersMissingInMemory();
if (!membersRemovedForStructConstructor.empty())
{
msg += " Members that have to be skipped in memory:";
for (auto const& member: membersRemovedForStructConstructor)
msg += " " + member;
}
}
else if (
_functionType->kind() == FunctionType::Kind::BareCall ||
_functionType->kind() == FunctionType::Kind::BareCallCode ||
_functionType->kind() == FunctionType::Kind::BareDelegateCall ||
_functionType->kind() == FunctionType::Kind::BareStaticCall
)
{
if (arguments.empty())
msg +=
" This function requires a single bytes argument."
" Use \"\" as argument to provide empty calldata.";
else
msg +=
" This function requires a single bytes argument."
" If all your arguments are value types, you can use"
" abi.encode(...) to properly generate it.";
}
else if (
_functionType->kind() == FunctionType::Kind::KECCAK256 ||
_functionType->kind() == FunctionType::Kind::SHA256 ||
_functionType->kind() == FunctionType::Kind::RIPEMD160
)
msg +=
" This function requires a single bytes argument."
" Use abi.encodePacked(...) to obtain the pre-0.5.0"
" behaviour or abi.encode(...) to use ABI encoding.";
m_errorReporter.typeError(_functionCall.location(), msg);
return;
}
// Parameter to argument map
std::vector<Expression const*> paramArgMap(parameterTypes.size());
// Map parameters to arguments - trivially for positional calls, less so for named calls
if (isPositionalCall)
for (size_t i = 0; i < paramArgMap.size(); ++i)
paramArgMap[i] = arguments[i].get();
else
{
auto const& parameterNames = _functionType->parameterNames();
solAssert(
parameterNames.size() == argumentNames.size(),
"Unexpected parameter length mismatch!"
);
// Check for duplicate argument names
{
bool duplication = false;
for (size_t i = 0; i < argumentNames.size(); i++)
for (size_t j = i + 1; j < argumentNames.size(); j++)
if (*argumentNames[i] == *argumentNames[j])
{
duplication = true;
m_errorReporter.typeError(
arguments[i]->location(),
"Duplicate named argument \"" + *argumentNames[i] + "\"."
);
}
if (duplication)
return;
}
// map parameter names to argument names
{
bool not_all_mapped = false;
for (size_t i = 0; i < paramArgMap.size(); i++)
{
size_t j;
for (j = 0; j < argumentNames.size(); j++)
if (parameterNames[i] == *argumentNames[j])
break;
if (j < argumentNames.size())
paramArgMap[i] = arguments[j].get();
else
{
paramArgMap[i] = nullptr;
not_all_mapped = true;
m_errorReporter.typeError(
_functionCall.location(),
"Named argument \"" +
*argumentNames[i] +
"\" does not match function declaration."
);
}
}
if (not_all_mapped)
return;
}
}
// Check for compatible types between arguments and parameters
for (size_t i = 0; i < paramArgMap.size(); ++i)
{
solAssert(!!paramArgMap[i], "unmapped parameter");
if (!type(*paramArgMap[i])->isImplicitlyConvertibleTo(*parameterTypes[i]))
{
string msg =
"Invalid type for argument in function call. "
"Invalid implicit conversion from " +
type(*paramArgMap[i])->toString() +
" to " +
parameterTypes[i]->toString() +
" requested.";
if (
_functionType->kind() == FunctionType::Kind::BareCall ||
_functionType->kind() == FunctionType::Kind::BareCallCode ||
_functionType->kind() == FunctionType::Kind::BareDelegateCall ||
_functionType->kind() == FunctionType::Kind::BareStaticCall
)
msg +=
" This function requires a single bytes argument."
" If all your arguments are value types, you can"
" use abi.encode(...) to properly generate it.";
else if (
_functionType->kind() == FunctionType::Kind::KECCAK256 ||
_functionType->kind() == FunctionType::Kind::SHA256 ||
_functionType->kind() == FunctionType::Kind::RIPEMD160
)
msg +=
" This function requires a single bytes argument."
" Use abi.encodePacked(...) to obtain the pre-0.5.0"
" behaviour or abi.encode(...) to use ABI encoding.";
m_errorReporter.typeError(paramArgMap[i]->location(), msg);
}
}
}
bool TypeChecker::visit(FunctionCall const& _functionCall)
{
vector<ASTPointer<Expression const>> const& arguments = _functionCall.arguments();
bool argumentsArePure = true;
// We need to check arguments' type first as they will be needed for overload resolution.
for (ASTPointer<Expression const> const& argument: arguments)
{
argument->accept(*this);
if (!argument->annotation().isPure)
argumentsArePure = false;
}
// For positional calls only, store argument types
if (_functionCall.names().empty())
{
shared_ptr<TypePointers> argumentTypes = make_shared<TypePointers>();
for (ASTPointer<Expression const> const& argument: arguments)
argumentTypes->push_back(type(*argument));
_functionCall.expression().annotation().argumentTypes = move(argumentTypes);
}
_functionCall.expression().accept(*this);
TypePointer const& expressionType = type(_functionCall.expression());
// Determine function call kind and function type for this FunctionCall node
FunctionCallAnnotation& funcCallAnno = _functionCall.annotation();
FunctionTypePointer functionType;
// Determine and assign function call kind, purity and function type for this FunctionCall node
switch (expressionType->category())
{
case Type::Category::Function:
functionType = dynamic_pointer_cast<FunctionType const>(expressionType);
funcCallAnno.kind = FunctionCallKind::FunctionCall;
// Purity for function calls also depends upon the callee and its FunctionType
funcCallAnno.isPure =
argumentsArePure &&
_functionCall.expression().annotation().isPure &&
functionType &&
functionType->isPure();
break;
case Type::Category::TypeType:
{
// Determine type for type conversion or struct construction expressions
TypePointer const& actualType = dynamic_cast<TypeType const&>(*expressionType).actualType();
solAssert(!!actualType, "");
if (actualType->category() == Type::Category::Struct)
{
functionType = dynamic_cast<StructType const&>(*actualType).constructorType();
funcCallAnno.kind = FunctionCallKind::StructConstructorCall;
funcCallAnno.isPure = argumentsArePure;
}
else
{
funcCallAnno.kind = FunctionCallKind::TypeConversion;
funcCallAnno.isPure = argumentsArePure;
}
break;
}
default:
m_errorReporter.typeError(_functionCall.location(), "Type is not callable");
funcCallAnno.kind = FunctionCallKind::Unset;
funcCallAnno.isPure = argumentsArePure;
break;
}
// Determine return types
switch (funcCallAnno.kind)
{
case FunctionCallKind::TypeConversion:
funcCallAnno.type = typeCheckTypeConversionAndRetrieveReturnType(_functionCall);
break;
case FunctionCallKind::StructConstructorCall: // fall-through
case FunctionCallKind::FunctionCall:
{
TypePointers returnTypes;
switch (functionType->kind())
{
case FunctionType::Kind::ABIDecode:
{
bool const abiEncoderV2 =
m_scope->sourceUnit().annotation().experimentalFeatures.count(
ExperimentalFeature::ABIEncoderV2
);
returnTypes = typeCheckABIDecodeAndRetrieveReturnType(_functionCall, abiEncoderV2);
break;
}
case FunctionType::Kind::ABIEncode:
case FunctionType::Kind::ABIEncodePacked:
case FunctionType::Kind::ABIEncodeWithSelector:
case FunctionType::Kind::ABIEncodeWithSignature:
{
typeCheckABIEncodeFunctions(_functionCall, functionType);
returnTypes = functionType->returnParameterTypes();
break;
}
2019-01-10 15:28:39 +00:00
case FunctionType::Kind::MetaType:
returnTypes = typeCheckMetaTypeFunctionAndRetrieveReturnType(_functionCall);
break;
default:
{
typeCheckFunctionCall(_functionCall, functionType);
returnTypes = m_evmVersion.supportsReturndata() ?
functionType->returnParameterTypes() :
functionType->returnParameterTypesWithoutDynamicTypes();
break;
}
}
funcCallAnno.type = returnTypes.size() == 1 ?
move(returnTypes.front()) :
make_shared<TupleType>(move(returnTypes));
break;
}
case FunctionCallKind::Unset: // fall-through
default:
// for non-callables, ensure error reported and annotate node to void function
solAssert(m_errorReporter.hasErrors(), "");
funcCallAnno.kind = FunctionCallKind::FunctionCall;
funcCallAnno.type = make_shared<TupleType>();
break;
}
2018-09-04 14:24:21 +00:00
return false;
}
void TypeChecker::endVisit(NewExpression const& _newExpression)
{
2015-11-17 00:47:47 +00:00
TypePointer type = _newExpression.typeName().annotation().type;
solAssert(!!type, "Type name not resolved.");
if (auto contractName = dynamic_cast<UserDefinedTypeName const*>(&_newExpression.typeName()))
{
auto contract = dynamic_cast<ContractDefinition const*>(&dereference(*contractName));
if (!contract)
m_errorReporter.fatalTypeError(_newExpression.location(), "Identifier is not a contract.");
2019-01-17 11:59:11 +00:00
if (contract->isInterface())
2018-09-25 17:40:39 +00:00
m_errorReporter.fatalTypeError(_newExpression.location(), "Cannot instantiate an interface.");
if (!contract->annotation().unimplementedFunctions.empty())
{
SecondarySourceLocation ssl;
for (auto function: contract->annotation().unimplementedFunctions)
ssl.append("Missing implementation:", function->location());
string msg = "Trying to create an instance of an abstract contract.";
ssl.limitSize(msg);
m_errorReporter.typeError(
_newExpression.location(),
ssl,
msg
);
}
if (!contract->constructorIsPublic())
m_errorReporter.typeError(_newExpression.location(), "Contract with internal constructor cannot be created directly.");
2015-11-19 17:02:04 +00:00
solAssert(!!m_scope, "");
m_scope->annotation().contractDependencies.insert(contract);
solAssert(
!contract->annotation().linearizedBaseContracts.empty(),
"Linearized base contracts not yet available."
);
2015-11-19 17:02:04 +00:00
if (contractDependenciesAreCyclic(*m_scope))
m_errorReporter.typeError(
_newExpression.location(),
"Circular reference for contract creation (cannot create instance of derived or same contract)."
);
_newExpression.annotation().type = FunctionType::newExpressionType(*contract);
}
2015-11-17 00:47:47 +00:00
else if (type->category() == Type::Category::Array)
{
2015-11-17 00:47:47 +00:00
if (!type->canLiveOutsideStorage())
m_errorReporter.fatalTypeError(
2015-11-17 00:47:47 +00:00
_newExpression.typeName().location(),
"Type cannot live outside storage."
);
if (!type->isDynamicallySized())
m_errorReporter.typeError(
2015-11-17 00:47:47 +00:00
_newExpression.typeName().location(),
"Length has to be placed in parentheses after the array type for new expression."
);
type = ReferenceType::copyForLocationIfReference(DataLocation::Memory, type);
_newExpression.annotation().type = make_shared<FunctionType>(
TypePointers{make_shared<IntegerType>(256)},
TypePointers{type},
strings(1, ""),
strings(1, ""),
FunctionType::Kind::ObjectCreation,
false,
StateMutability::Pure
2015-11-17 00:47:47 +00:00
);
2017-03-01 18:12:40 +00:00
_newExpression.annotation().isPure = true;
}
else
m_errorReporter.fatalTypeError(_newExpression.location(), "Contract or array type expected.");
}
bool TypeChecker::visit(MemberAccess const& _memberAccess)
{
_memberAccess.expression().accept(*this);
TypePointer exprType = type(_memberAccess.expression());
ASTString const& memberName = _memberAccess.memberName();
// Retrieve the types of the arguments if this is used to call a function.
auto const& argumentTypes = _memberAccess.annotation().argumentTypes;
2015-11-19 17:02:04 +00:00
MemberList::MemberMap possibleMembers = exprType->members(m_scope).membersByName(memberName);
size_t const initialMemberCount = possibleMembers.size();
if (initialMemberCount > 1 && argumentTypes)
{
// do overload resolution
for (auto it = possibleMembers.begin(); it != possibleMembers.end();)
if (
it->type->category() == Type::Category::Function &&
!dynamic_cast<FunctionType const&>(*it->type).canTakeArguments(*argumentTypes, exprType)
)
it = possibleMembers.erase(it);
else
++it;
}
2018-07-17 12:31:21 +00:00
auto& annotation = _memberAccess.annotation();
2018-10-09 03:29:37 +00:00
if (possibleMembers.empty())
{
if (initialMemberCount == 0)
{
// Try to see if the member was removed because it is only available for storage types.
auto storageType = ReferenceType::copyForLocationIfReference(
DataLocation::Storage,
exprType
);
if (!storageType->members(m_scope).membersByName(memberName).empty())
m_errorReporter.fatalTypeError(
_memberAccess.location(),
"Member \"" + memberName + "\" is not available in " +
exprType->toString() +
" outside of storage."
);
}
2018-07-17 12:31:21 +00:00
string errorMsg = "Member \"" + memberName + "\" not found or not visible "
"after argument-dependent lookup in " + exprType->toString() + ".";
if (memberName == "value")
{
errorMsg.pop_back();
errorMsg += " - did you forget the \"payable\" modifier?";
}
else if (exprType->category() == Type::Category::Function)
{
if (auto const& funType = dynamic_pointer_cast<FunctionType const>(exprType))
{
auto const& t = funType->returnParameterTypes();
if (t.size() == 1)
if (
t.front()->category() == Type::Category::Contract ||
t.front()->category() == Type::Category::Struct
)
errorMsg += " Did you intend to call the function?";
}
}
2018-07-17 12:31:21 +00:00
if (exprType->category() == Type::Category::Contract)
for (auto const& addressMember: AddressType::addressPayable().nativeMembers(nullptr))
2018-07-17 12:31:21 +00:00
if (addressMember.name == memberName)
{
2018-07-18 17:51:24 +00:00
Identifier const* var = dynamic_cast<Identifier const*>(&_memberAccess.expression());
string varName = var ? var->name() : "...";
errorMsg += " Use \"address(" + varName + ")." + memberName + "\" to access this address member.";
2018-07-17 12:31:21 +00:00
break;
}
m_errorReporter.fatalTypeError(
_memberAccess.location(),
2018-07-17 12:31:21 +00:00
errorMsg
);
}
else if (possibleMembers.size() > 1)
m_errorReporter.fatalTypeError(
_memberAccess.location(),
"Member \"" + memberName + "\" not unique "
"after argument-dependent lookup in " + exprType->toString() +
(memberName == "value" ? " - did you forget the \"payable\" modifier?" : ".")
);
annotation.referencedDeclaration = possibleMembers.front().declaration;
annotation.type = possibleMembers.front().type;
if (auto funType = dynamic_cast<FunctionType const*>(annotation.type.get()))
solAssert(
!funType->bound() || exprType->isImplicitlyConvertibleTo(*funType->selfType()),
"Function \"" + memberName + "\" cannot be called on an object of type " +
exprType->toString() + " (expected " + funType->selfType()->toString() + ")."
);
if (auto const* structType = dynamic_cast<StructType const*>(exprType.get()))
annotation.isLValue = !structType->dataStoredIn(DataLocation::CallData);
else if (exprType->category() == Type::Category::Array)
{
auto const& arrayType(dynamic_cast<ArrayType const&>(*exprType));
annotation.isLValue = (
memberName == "length" &&
arrayType.location() == DataLocation::Storage &&
arrayType.isDynamicallySized()
);
}
2016-02-03 20:34:24 +00:00
else if (exprType->category() == Type::Category::FixedBytes)
annotation.isLValue = false;
else if (TypeType const* typeType = dynamic_cast<decltype(typeType)>(exprType.get()))
{
if (ContractType const* contractType = dynamic_cast<decltype(contractType)>(typeType->actualType().get()))
annotation.isLValue = annotation.referencedDeclaration->isLValue();
}
if (exprType->category() == Type::Category::Contract)
{
// Warn about using send or transfer with a non-payable fallback function.
if (auto callType = dynamic_cast<FunctionType const*>(type(_memberAccess).get()))
{
auto kind = callType->kind();
auto contractType = dynamic_cast<ContractType const*>(exprType.get());
solAssert(!!contractType, "Should be contract type.");
if (
(kind == FunctionType::Kind::Send || kind == FunctionType::Kind::Transfer) &&
!contractType->isPayable()
)
m_errorReporter.typeError(
_memberAccess.location(),
"Value transfer to a contract without a payable fallback function."
);
}
}
2017-03-01 18:12:40 +00:00
// TODO some members might be pure, but for example `address(0x123).balance` is not pure
2017-03-01 18:49:15 +00:00
// although every subexpression is, so leaving this limited for now.
if (auto tt = dynamic_cast<TypeType const*>(exprType.get()))
if (tt->actualType()->category() == Type::Category::Enum)
annotation.isPure = true;
if (auto magicType = dynamic_cast<MagicType const*>(exprType.get()))
2019-01-10 15:28:39 +00:00
{
if (magicType->kind() == MagicType::Kind::ABI)
annotation.isPure = true;
2019-01-14 23:14:10 +00:00
else if (magicType->kind() == MagicType::Kind::MetaType && (
memberName == "creationCode" || memberName == "runtimeCode"
))
{
annotation.isPure = true;
m_scope->annotation().contractDependencies.insert(
&dynamic_cast<ContractType const&>(*magicType->typeArgument()).contractDefinition()
);
if (contractDependenciesAreCyclic(*m_scope))
m_errorReporter.typeError(
_memberAccess.location(),
"Circular reference for contract code access."
);
}
2019-01-10 15:28:39 +00:00
}
2017-03-01 18:12:40 +00:00
return false;
}
bool TypeChecker::visit(IndexAccess const& _access)
{
_access.baseExpression().accept(*this);
TypePointer baseType = type(_access.baseExpression());
TypePointer resultType;
bool isLValue = false;
2017-03-01 18:12:40 +00:00
bool isPure = _access.baseExpression().annotation().isPure;
Expression const* index = _access.indexExpression();
switch (baseType->category())
{
case Type::Category::Array:
{
ArrayType const& actualType = dynamic_cast<ArrayType const&>(*baseType);
if (!index)
m_errorReporter.typeError(_access.location(), "Index expression cannot be omitted.");
else if (actualType.isString())
{
m_errorReporter.typeError(_access.location(), "Index access for string is not possible.");
index->accept(*this);
}
else
{
expectType(*index, IntegerType::uint256());
if (!m_errorReporter.hasErrors())
if (auto numberType = dynamic_cast<RationalNumberType const*>(type(*index).get()))
{
solAssert(!numberType->isFractional(), "");
2016-05-10 12:30:24 +00:00
if (!actualType.isDynamicallySized() && actualType.length() <= numberType->literalValue(nullptr))
m_errorReporter.typeError(_access.location(), "Out of bounds array access.");
}
}
resultType = actualType.baseType();
isLValue = actualType.location() != DataLocation::CallData;
break;
}
case Type::Category::Mapping:
{
MappingType const& actualType = dynamic_cast<MappingType const&>(*baseType);
if (!index)
m_errorReporter.typeError(_access.location(), "Index expression cannot be omitted.");
else
expectType(*index, *actualType.keyType());
resultType = actualType.valueType();
isLValue = true;
break;
}
case Type::Category::TypeType:
{
TypeType const& typeType = dynamic_cast<TypeType const&>(*baseType);
if (!index)
resultType = make_shared<TypeType>(make_shared<ArrayType>(DataLocation::Memory, typeType.actualType()));
else
{
u256 length = 1;
if (expectType(*index, IntegerType::uint256()))
{
if (auto indexValue = dynamic_cast<RationalNumberType const*>(type(*index).get()))
length = indexValue->literalValue(nullptr);
else
m_errorReporter.fatalTypeError(index->location(), "Integer constant expected.");
}
else
solAssert(m_errorReporter.hasErrors(), "Expected errors as expectType returned false");
resultType = make_shared<TypeType>(make_shared<ArrayType>(
DataLocation::Memory,
typeType.actualType(),
length
));
}
break;
}
2016-02-03 20:34:24 +00:00
case Type::Category::FixedBytes:
{
FixedBytesType const& bytesType = dynamic_cast<FixedBytesType const&>(*baseType);
if (!index)
m_errorReporter.typeError(_access.location(), "Index expression cannot be omitted.");
2016-02-03 20:34:24 +00:00
else
{
if (!expectType(*index, IntegerType::uint256()))
m_errorReporter.fatalTypeError(_access.location(), "Index expression cannot be represented as an unsigned integer.");
if (auto integerType = dynamic_cast<RationalNumberType const*>(type(*index).get()))
2016-02-03 20:34:24 +00:00
if (bytesType.numBytes() <= integerType->literalValue(nullptr))
m_errorReporter.typeError(_access.location(), "Out of bounds array access.");
2016-02-03 20:34:24 +00:00
}
resultType = make_shared<FixedBytesType>(1);
isLValue = false; // @todo this heavily depends on how it is embedded
break;
}
default:
m_errorReporter.fatalTypeError(
_access.baseExpression().location(),
"Indexed expression has to be a type, mapping or array (is " + baseType->toString() + ")"
);
}
_access.annotation().type = move(resultType);
_access.annotation().isLValue = isLValue;
2017-03-01 18:12:40 +00:00
if (index && !index->annotation().isPure)
isPure = false;
_access.annotation().isPure = isPure;
return false;
}
bool TypeChecker::visit(Identifier const& _identifier)
{
2015-09-21 16:55:58 +00:00
IdentifierAnnotation& annotation = _identifier.annotation();
if (!annotation.referencedDeclaration)
{
if (!annotation.argumentTypes)
{
// The identifier should be a public state variable shadowing other functions
vector<Declaration const*> candidates;
for (Declaration const* declaration: annotation.overloadedDeclarations)
{
if (VariableDeclaration const* variableDeclaration = dynamic_cast<decltype(variableDeclaration)>(declaration))
candidates.push_back(declaration);
}
if (candidates.empty())
m_errorReporter.fatalTypeError(_identifier.location(), "No matching declaration found after variable lookup.");
else if (candidates.size() == 1)
annotation.referencedDeclaration = candidates.front();
else
m_errorReporter.fatalTypeError(_identifier.location(), "No unique declaration found after variable lookup.");
}
else if (annotation.overloadedDeclarations.empty())
m_errorReporter.fatalTypeError(_identifier.location(), "No candidates for overload resolution found.");
else if (annotation.overloadedDeclarations.size() == 1)
annotation.referencedDeclaration = *annotation.overloadedDeclarations.begin();
else
{
vector<Declaration const*> candidates;
for (Declaration const* declaration: annotation.overloadedDeclarations)
{
FunctionTypePointer functionType = declaration->functionType(true);
solAssert(!!functionType, "Requested type not present.");
if (functionType->canTakeArguments(*annotation.argumentTypes))
candidates.push_back(declaration);
}
if (candidates.empty())
m_errorReporter.fatalTypeError(_identifier.location(), "No matching declaration found after argument-dependent lookup.");
else if (candidates.size() == 1)
annotation.referencedDeclaration = candidates.front();
else
m_errorReporter.fatalTypeError(_identifier.location(), "No unique declaration found after argument-dependent lookup.");
}
}
solAssert(
!!annotation.referencedDeclaration,
"Referenced declaration is null after overload resolution."
);
annotation.isLValue = annotation.referencedDeclaration->isLValue();
2015-11-19 17:02:04 +00:00
annotation.type = annotation.referencedDeclaration->type();
if (!annotation.type)
m_errorReporter.fatalTypeError(_identifier.location(), "Declaration referenced before type could be determined.");
2017-03-01 18:12:40 +00:00
if (auto variableDeclaration = dynamic_cast<VariableDeclaration const*>(annotation.referencedDeclaration))
annotation.isPure = annotation.isConstant = variableDeclaration->isConstant();
else if (dynamic_cast<MagicVariableDeclaration const*>(annotation.referencedDeclaration))
if (dynamic_cast<FunctionType const*>(annotation.type.get()))
annotation.isPure = true;
// Check for deprecated function names.
// The check is done here for the case without an actual function call.
if (FunctionType const* fType = dynamic_cast<FunctionType const*>(_identifier.annotation().type.get()))
{
if (_identifier.name() == "sha3" && fType->kind() == FunctionType::Kind::KECCAK256)
m_errorReporter.typeError(
_identifier.location(),
"\"sha3\" has been deprecated in favour of \"keccak256\""
);
else if (_identifier.name() == "suicide" && fType->kind() == FunctionType::Kind::Selfdestruct)
m_errorReporter.typeError(
_identifier.location(),
"\"suicide\" has been deprecated in favour of \"selfdestruct\""
);
}
return false;
}
void TypeChecker::endVisit(ElementaryTypeNameExpression const& _expr)
{
_expr.annotation().type = make_shared<TypeType>(Type::fromElementaryTypeName(_expr.typeName()));
2017-03-01 18:12:40 +00:00
_expr.annotation().isPure = true;
}
void TypeChecker::endVisit(Literal const& _literal)
{
if (_literal.looksLikeAddress())
{
// Assign type here if it even looks like an address. This prevents double errors for invalid addresses
_literal.annotation().type = make_shared<AddressType>(StateMutability::Payable);
string msg;
if (_literal.valueWithoutUnderscores().length() != 42) // "0x" + 40 hex digits
// looksLikeAddress enforces that it is a hex literal starting with "0x"
msg =
"This looks like an address but is not exactly 40 hex digits. It is " +
to_string(_literal.valueWithoutUnderscores().length() - 2) +
" hex digits.";
else if (!_literal.passesAddressChecksum())
{
msg = "This looks like an address but has an invalid checksum.";
if (!_literal.getChecksummedAddress().empty())
msg += " Correct checksummed address: \"" + _literal.getChecksummedAddress() + "\".";
}
if (!msg.empty())
m_errorReporter.syntaxError(
2017-03-06 12:31:57 +00:00
_literal.location(),
msg +
" If this is not used as an address, please prepend '00'. " +
"For more information please see https://solidity.readthedocs.io/en/develop/types.html#address-literals"
2017-03-06 12:31:57 +00:00
);
}
2018-04-23 13:54:45 +00:00
if (_literal.isHexNumber() && _literal.subDenomination() != Literal::SubDenomination::None)
m_errorReporter.fatalTypeError(
_literal.location(),
"Hexadecimal numbers cannot be used with unit denominations. "
"You can use an expression of the form \"0x1234 * 1 day\" instead."
);
2018-04-23 13:54:45 +00:00
if (_literal.subDenomination() == Literal::SubDenomination::Year)
m_errorReporter.typeError(
_literal.location(),
"Using \"years\" as a unit denomination is deprecated."
);
2018-04-23 13:54:45 +00:00
if (!_literal.annotation().type)
_literal.annotation().type = Type::forLiteral(_literal);
if (!_literal.annotation().type)
m_errorReporter.fatalTypeError(_literal.location(), "Invalid literal value.");
_literal.annotation().isPure = true;
}
2015-10-07 13:57:17 +00:00
bool TypeChecker::contractDependenciesAreCyclic(
ContractDefinition const& _contract,
std::set<ContractDefinition const*> const& _seenContracts
) const
{
// Naive depth-first search that remembers nodes already seen.
if (_seenContracts.count(&_contract))
return true;
set<ContractDefinition const*> seen(_seenContracts);
seen.insert(&_contract);
for (auto const* c: _contract.annotation().contractDependencies)
if (contractDependenciesAreCyclic(*c, seen))
return true;
return false;
}
2015-11-24 15:34:02 +00:00
Declaration const& TypeChecker::dereference(Identifier const& _identifier) const
{
solAssert(!!_identifier.annotation().referencedDeclaration, "Declaration not stored.");
return *_identifier.annotation().referencedDeclaration;
}
2015-11-24 15:34:02 +00:00
Declaration const& TypeChecker::dereference(UserDefinedTypeName const& _typeName) const
{
solAssert(!!_typeName.annotation().referencedDeclaration, "Declaration not stored.");
return *_typeName.annotation().referencedDeclaration;
}
bool TypeChecker::expectType(Expression const& _expression, Type const& _expectedType)
{
_expression.accept(*this);
if (!type(_expression)->isImplicitlyConvertibleTo(_expectedType))
{
auto errorMsg = "Type " +
type(_expression)->toString() +
" is not implicitly convertible to expected type " +
_expectedType.toString();
if (
type(_expression)->category() == Type::Category::RationalNumber &&
2016-05-10 12:30:24 +00:00
dynamic_pointer_cast<RationalNumberType const>(type(_expression))->isFractional() &&
type(_expression)->mobileType()
)
{
if (_expectedType.operator==(*type(_expression)->mobileType()))
m_errorReporter.typeError(
_expression.location(),
errorMsg + ", but it can be explicitly converted."
);
else
m_errorReporter.typeError(
_expression.location(),
errorMsg +
". Try converting to type " +
type(_expression)->mobileType()->toString() +
" or use an explicit conversion."
);
}
else
m_errorReporter.typeError(_expression.location(), errorMsg + ".");
return false;
}
return true;
}
void TypeChecker::requireLValue(Expression const& _expression)
{
2015-10-12 21:02:35 +00:00
_expression.annotation().lValueRequested = true;
_expression.accept(*this);
if (_expression.annotation().isConstant)
m_errorReporter.typeError(_expression.location(), "Cannot assign to a constant variable.");
else if (!_expression.annotation().isLValue)
m_errorReporter.typeError(_expression.location(), "Expression has to be an lvalue.");
}