mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Refactor error reporting
This commit introduces ErrorReporter, a utility class which consolidates all of the error logging functionality into a common set of functions. It also replaces all direct interactions with an ErrorList with calls to an ErrorReporter. This commit resolves issue #2209
This commit is contained in:
@@ -27,6 +27,7 @@
|
||||
#include <libsolidity/inlineasm/AsmAnalysis.h>
|
||||
#include <libsolidity/inlineasm/AsmAnalysisInfo.h>
|
||||
#include <libsolidity/inlineasm/AsmData.h>
|
||||
#include <libsolidity/interface/ErrorReporter.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace dev;
|
||||
@@ -43,10 +44,10 @@ bool TypeChecker::checkTypeRequirements(ASTNode const& _contract)
|
||||
{
|
||||
// We got a fatal error which required to stop further type checking, but we can
|
||||
// continue normally from here.
|
||||
if (m_errors.empty())
|
||||
if (m_errorReporter.errors().empty())
|
||||
throw; // Something is weird here, rather throw again.
|
||||
}
|
||||
return Error::containsOnlyWarnings(m_errors);
|
||||
return Error::containsOnlyWarnings(m_errorReporter.errors());
|
||||
}
|
||||
|
||||
TypePointer const& TypeChecker::type(Expression const& _expression) const
|
||||
@@ -81,11 +82,11 @@ bool TypeChecker::visit(ContractDefinition const& _contract)
|
||||
if (function)
|
||||
{
|
||||
if (!function->returnParameters().empty())
|
||||
typeError(function->returnParameterList()->location(), "Non-empty \"returns\" directive for constructor.");
|
||||
m_errorReporter.typeError(function->returnParameterList()->location(), "Non-empty \"returns\" directive for constructor.");
|
||||
if (function->isDeclaredConst())
|
||||
typeError(function->location(), "Constructor cannot be defined as constant.");
|
||||
m_errorReporter.typeError(function->location(), "Constructor cannot be defined as constant.");
|
||||
if (function->visibility() != FunctionDefinition::Visibility::Public && function->visibility() != FunctionDefinition::Visibility::Internal)
|
||||
typeError(function->location(), "Constructor must be public or internal.");
|
||||
m_errorReporter.typeError(function->location(), "Constructor must be public or internal.");
|
||||
}
|
||||
|
||||
FunctionDefinition const* fallbackFunction = nullptr;
|
||||
@@ -95,21 +96,19 @@ bool TypeChecker::visit(ContractDefinition const& _contract)
|
||||
{
|
||||
if (fallbackFunction)
|
||||
{
|
||||
auto err = make_shared<Error>(Error::Type::DeclarationError);
|
||||
*err << errinfo_comment("Only one fallback function is allowed.");
|
||||
m_errors.push_back(err);
|
||||
m_errorReporter.declarationError(function->location(), "Only one fallback function is allowed.");
|
||||
}
|
||||
else
|
||||
{
|
||||
fallbackFunction = function;
|
||||
if (_contract.isLibrary())
|
||||
typeError(fallbackFunction->location(), "Libraries cannot have fallback functions.");
|
||||
m_errorReporter.typeError(fallbackFunction->location(), "Libraries cannot have fallback functions.");
|
||||
if (fallbackFunction->isDeclaredConst())
|
||||
typeError(fallbackFunction->location(), "Fallback function cannot be declared constant.");
|
||||
m_errorReporter.typeError(fallbackFunction->location(), "Fallback function cannot be declared constant.");
|
||||
if (!fallbackFunction->parameters().empty())
|
||||
typeError(fallbackFunction->parameterList().location(), "Fallback function cannot take parameters.");
|
||||
m_errorReporter.typeError(fallbackFunction->parameterList().location(), "Fallback function cannot take parameters.");
|
||||
if (!fallbackFunction->returnParameters().empty())
|
||||
typeError(fallbackFunction->returnParameterList()->location(), "Fallback function cannot return values.");
|
||||
m_errorReporter.typeError(fallbackFunction->returnParameterList()->location(), "Fallback function cannot return values.");
|
||||
}
|
||||
}
|
||||
if (!function->isImplemented())
|
||||
@@ -127,7 +126,7 @@ bool TypeChecker::visit(ContractDefinition const& _contract)
|
||||
{
|
||||
FixedHash<4> const& hash = it.first;
|
||||
if (hashes.count(hash))
|
||||
typeError(
|
||||
m_errorReporter.typeError(
|
||||
_contract.location(),
|
||||
string("Function signature hash collision for ") + it.second->externalSignature()
|
||||
);
|
||||
@@ -156,12 +155,11 @@ void TypeChecker::checkContractDuplicateFunctions(ContractDefinition const& _con
|
||||
for (; it != functions[_contract.name()].end(); ++it)
|
||||
ssl.append("Another declaration is here:", (*it)->location());
|
||||
|
||||
auto err = make_shared<Error>(Error(Error::Type::DeclarationError));
|
||||
*err <<
|
||||
errinfo_sourceLocation(functions[_contract.name()].front()->location()) <<
|
||||
errinfo_comment("More than one constructor defined.") <<
|
||||
errinfo_secondarySourceLocation(ssl);
|
||||
m_errors.push_back(err);
|
||||
m_errorReporter.declarationError(
|
||||
functions[_contract.name()].front()->location(),
|
||||
ssl,
|
||||
"More than one constructor defined."
|
||||
);
|
||||
}
|
||||
for (auto const& it: functions)
|
||||
{
|
||||
@@ -170,13 +168,14 @@ void TypeChecker::checkContractDuplicateFunctions(ContractDefinition const& _con
|
||||
for (size_t j = i + 1; j < overloads.size(); ++j)
|
||||
if (FunctionType(*overloads[i]).hasEqualArgumentTypes(FunctionType(*overloads[j])))
|
||||
{
|
||||
auto err = make_shared<Error>(Error(Error::Type::DeclarationError));
|
||||
*err <<
|
||||
errinfo_sourceLocation(overloads[j]->location()) <<
|
||||
errinfo_comment("Function with same name and arguments defined twice.") <<
|
||||
errinfo_secondarySourceLocation(SecondarySourceLocation().append(
|
||||
"Other declaration is here:", overloads[i]->location()));
|
||||
m_errors.push_back(err);
|
||||
m_errorReporter.declarationError(
|
||||
overloads[j]->location(),
|
||||
SecondarySourceLocation().append(
|
||||
"Other declaration is here:",
|
||||
overloads[i]->location()
|
||||
),
|
||||
"Function with same name and arguments defined twice."
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -213,7 +212,7 @@ void TypeChecker::checkContractAbstractFunctions(ContractDefinition const& _cont
|
||||
else if (it->second)
|
||||
{
|
||||
if (!function->isImplemented())
|
||||
typeError(function->location(), "Redeclaring an already implemented function as abstract");
|
||||
m_errorReporter.typeError(function->location(), "Redeclaring an already implemented function as abstract");
|
||||
}
|
||||
else if (function->isImplemented())
|
||||
it->second = true;
|
||||
@@ -285,7 +284,7 @@ void TypeChecker::checkContractIllegalOverrides(ContractDefinition const& _contr
|
||||
continue; // constructors can neither be overridden nor override anything
|
||||
string const& name = function->name();
|
||||
if (modifiers.count(name))
|
||||
typeError(modifiers[name]->location(), "Override changes function to modifier.");
|
||||
m_errorReporter.typeError(modifiers[name]->location(), "Override changes function to modifier.");
|
||||
FunctionType functionType(*function);
|
||||
// function should not change the return type
|
||||
for (FunctionDefinition const* overriding: functions[name])
|
||||
@@ -299,7 +298,7 @@ void TypeChecker::checkContractIllegalOverrides(ContractDefinition const& _contr
|
||||
overriding->isPayable() != function->isPayable() ||
|
||||
overridingType != functionType
|
||||
)
|
||||
typeError(overriding->location(), "Override changes extended function signature.");
|
||||
m_errorReporter.typeError(overriding->location(), "Override changes extended function signature.");
|
||||
}
|
||||
functions[name].push_back(function);
|
||||
}
|
||||
@@ -310,9 +309,9 @@ void TypeChecker::checkContractIllegalOverrides(ContractDefinition const& _contr
|
||||
if (!override)
|
||||
override = modifier;
|
||||
else if (ModifierType(*override) != ModifierType(*modifier))
|
||||
typeError(override->location(), "Override changes modifier signature.");
|
||||
m_errorReporter.typeError(override->location(), "Override changes modifier signature.");
|
||||
if (!functions[name].empty())
|
||||
typeError(override->location(), "Override changes modifier to function.");
|
||||
m_errorReporter.typeError(override->location(), "Override changes modifier to function.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -347,7 +346,7 @@ void TypeChecker::checkContractExternalTypeClashes(ContractDefinition const& _co
|
||||
for (size_t i = 0; i < it.second.size(); ++i)
|
||||
for (size_t j = i + 1; j < it.second.size(); ++j)
|
||||
if (!it.second[i].second->hasEqualArgumentTypes(*it.second[j].second))
|
||||
typeError(
|
||||
m_errorReporter.typeError(
|
||||
it.second[j].first->location(),
|
||||
"Function overload clash during conversion to external types for arguments."
|
||||
);
|
||||
@@ -357,11 +356,11 @@ void TypeChecker::checkLibraryRequirements(ContractDefinition const& _contract)
|
||||
{
|
||||
solAssert(_contract.isLibrary(), "");
|
||||
if (!_contract.baseContracts().empty())
|
||||
typeError(_contract.location(), "Library is not allowed to inherit.");
|
||||
m_errorReporter.typeError(_contract.location(), "Library is not allowed to inherit.");
|
||||
|
||||
for (auto const& var: _contract.stateVariables())
|
||||
if (!var->isConstant())
|
||||
typeError(var->location(), "Library cannot have non-constant state variables");
|
||||
m_errorReporter.typeError(var->location(), "Library cannot have non-constant state variables");
|
||||
}
|
||||
|
||||
void TypeChecker::endVisit(InheritanceSpecifier const& _inheritance)
|
||||
@@ -370,16 +369,16 @@ void TypeChecker::endVisit(InheritanceSpecifier const& _inheritance)
|
||||
solAssert(base, "Base contract not available.");
|
||||
|
||||
if (m_scope->contractKind() == ContractDefinition::ContractKind::Interface)
|
||||
typeError(_inheritance.location(), "Interfaces cannot inherit.");
|
||||
m_errorReporter.typeError(_inheritance.location(), "Interfaces cannot inherit.");
|
||||
|
||||
if (base->isLibrary())
|
||||
typeError(_inheritance.location(), "Libraries cannot be inherited from.");
|
||||
m_errorReporter.typeError(_inheritance.location(), "Libraries cannot be inherited from.");
|
||||
|
||||
auto const& arguments = _inheritance.arguments();
|
||||
TypePointers parameterTypes = ContractType(*base).newExpressionType()->parameterTypes();
|
||||
if (!arguments.empty() && parameterTypes.size() != arguments.size())
|
||||
{
|
||||
typeError(
|
||||
m_errorReporter.typeError(
|
||||
_inheritance.location(),
|
||||
"Wrong argument count for constructor call: " +
|
||||
toString(arguments.size()) +
|
||||
@@ -392,7 +391,7 @@ void TypeChecker::endVisit(InheritanceSpecifier const& _inheritance)
|
||||
|
||||
for (size_t i = 0; i < arguments.size(); ++i)
|
||||
if (!type(*arguments[i])->isImplicitlyConvertibleTo(*parameterTypes[i]))
|
||||
typeError(
|
||||
m_errorReporter.typeError(
|
||||
arguments[i]->location(),
|
||||
"Invalid type for argument in constructor call. "
|
||||
"Invalid implicit conversion from " +
|
||||
@@ -409,17 +408,17 @@ void TypeChecker::endVisit(UsingForDirective const& _usingFor)
|
||||
_usingFor.libraryName().annotation().referencedDeclaration
|
||||
);
|
||||
if (!library || !library->isLibrary())
|
||||
typeError(_usingFor.libraryName().location(), "Library name expected.");
|
||||
m_errorReporter.typeError(_usingFor.libraryName().location(), "Library name expected.");
|
||||
}
|
||||
|
||||
bool TypeChecker::visit(StructDefinition const& _struct)
|
||||
{
|
||||
if (m_scope->contractKind() == ContractDefinition::ContractKind::Interface)
|
||||
typeError(_struct.location(), "Structs cannot be defined in interfaces.");
|
||||
m_errorReporter.typeError(_struct.location(), "Structs cannot be defined in interfaces.");
|
||||
|
||||
for (ASTPointer<VariableDeclaration> const& member: _struct.members())
|
||||
if (!type(*member)->canBeStored())
|
||||
typeError(member->location(), "Type cannot be used in struct.");
|
||||
m_errorReporter.typeError(member->location(), "Type cannot be used in struct.");
|
||||
|
||||
// Check recursion, fatal error if detected.
|
||||
using StructPointer = StructDefinition const*;
|
||||
@@ -427,7 +426,7 @@ bool TypeChecker::visit(StructDefinition const& _struct)
|
||||
function<void(StructPointer,StructPointersSet const&)> check = [&](StructPointer _struct, StructPointersSet const& _parents)
|
||||
{
|
||||
if (_parents.count(_struct))
|
||||
fatalTypeError(_struct->location(), "Recursive struct definition.");
|
||||
m_errorReporter.fatalTypeError(_struct->location(), "Recursive struct definition.");
|
||||
StructPointersSet parents = _parents;
|
||||
parents.insert(_struct);
|
||||
for (ASTPointer<VariableDeclaration> const& member: _struct->members())
|
||||
@@ -452,18 +451,18 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
|
||||
if (_function.isPayable())
|
||||
{
|
||||
if (isLibraryFunction)
|
||||
typeError(_function.location(), "Library functions cannot be payable.");
|
||||
m_errorReporter.typeError(_function.location(), "Library functions cannot be payable.");
|
||||
if (!_function.isConstructor() && !_function.name().empty() && !_function.isPartOfExternalInterface())
|
||||
typeError(_function.location(), "Internal functions cannot be payable.");
|
||||
m_errorReporter.typeError(_function.location(), "Internal functions cannot be payable.");
|
||||
if (_function.isDeclaredConst())
|
||||
typeError(_function.location(), "Functions cannot be constant and payable at the same time.");
|
||||
m_errorReporter.typeError(_function.location(), "Functions cannot be constant and payable at the same time.");
|
||||
}
|
||||
for (ASTPointer<VariableDeclaration> const& var: _function.parameters() + _function.returnParameters())
|
||||
{
|
||||
if (!type(*var)->canLiveOutsideStorage())
|
||||
typeError(var->location(), "Type is required to live outside storage.");
|
||||
m_errorReporter.typeError(var->location(), "Type is required to live outside storage.");
|
||||
if (_function.visibility() >= FunctionDefinition::Visibility::Public && !(type(*var)->interfaceType(isLibraryFunction)))
|
||||
fatalTypeError(var->location(), "Internal type is not allowed for public or external functions.");
|
||||
m_errorReporter.fatalTypeError(var->location(), "Internal type is not allowed for public or external functions.");
|
||||
}
|
||||
for (ASTPointer<ModifierInvocation> const& modifier: _function.modifiers())
|
||||
visitManually(
|
||||
@@ -475,11 +474,11 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
|
||||
if (m_scope->contractKind() == ContractDefinition::ContractKind::Interface)
|
||||
{
|
||||
if (_function.isImplemented())
|
||||
typeError(_function.location(), "Functions in interfaces cannot have an implementation.");
|
||||
m_errorReporter.typeError(_function.location(), "Functions in interfaces cannot have an implementation.");
|
||||
if (_function.visibility() < FunctionDefinition::Visibility::Public)
|
||||
typeError(_function.location(), "Functions in interfaces cannot be internal or private.");
|
||||
m_errorReporter.typeError(_function.location(), "Functions in interfaces cannot be internal or private.");
|
||||
if (_function.isConstructor())
|
||||
typeError(_function.location(), "Constructor cannot be defined in interfaces.");
|
||||
m_errorReporter.typeError(_function.location(), "Constructor cannot be defined in interfaces.");
|
||||
}
|
||||
if (_function.isImplemented())
|
||||
_function.body().accept(*this);
|
||||
@@ -489,7 +488,7 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
|
||||
bool TypeChecker::visit(VariableDeclaration const& _variable)
|
||||
{
|
||||
if (m_scope->contractKind() == ContractDefinition::ContractKind::Interface)
|
||||
typeError(_variable.location(), "Variables cannot be declared in interfaces.");
|
||||
m_errorReporter.typeError(_variable.location(), "Variables cannot be declared in interfaces.");
|
||||
|
||||
// Variables can be declared without type (with "var"), in which case the first assignment
|
||||
// sets the type.
|
||||
@@ -505,19 +504,19 @@ bool TypeChecker::visit(VariableDeclaration const& _variable)
|
||||
if (_variable.isConstant())
|
||||
{
|
||||
if (!_variable.isStateVariable())
|
||||
typeError(_variable.location(), "Illegal use of \"constant\" specifier.");
|
||||
m_errorReporter.typeError(_variable.location(), "Illegal use of \"constant\" specifier.");
|
||||
if (!_variable.type()->isValueType())
|
||||
{
|
||||
bool allowed = false;
|
||||
if (auto arrayType = dynamic_cast<ArrayType const*>(_variable.type().get()))
|
||||
allowed = arrayType->isString();
|
||||
if (!allowed)
|
||||
typeError(_variable.location(), "Constants of non-value type not yet implemented.");
|
||||
m_errorReporter.typeError(_variable.location(), "Constants of non-value type not yet implemented.");
|
||||
}
|
||||
if (!_variable.value())
|
||||
typeError(_variable.location(), "Uninitialized \"constant\" variable.");
|
||||
m_errorReporter.typeError(_variable.location(), "Uninitialized \"constant\" variable.");
|
||||
else if (!_variable.value()->annotation().isPure)
|
||||
warning(
|
||||
m_errorReporter.warning(
|
||||
_variable.value()->location(),
|
||||
"Initial value for constant variable has to be compile-time constant. "
|
||||
"This will fail to compile with the next breaking version change."
|
||||
@@ -527,20 +526,20 @@ bool TypeChecker::visit(VariableDeclaration const& _variable)
|
||||
{
|
||||
if (varType->dataStoredIn(DataLocation::Memory) || varType->dataStoredIn(DataLocation::CallData))
|
||||
if (!varType->canLiveOutsideStorage())
|
||||
typeError(_variable.location(), "Type " + varType->toString() + " is only valid in storage.");
|
||||
m_errorReporter.typeError(_variable.location(), "Type " + varType->toString() + " is only valid in storage.");
|
||||
}
|
||||
else if (
|
||||
_variable.visibility() >= VariableDeclaration::Visibility::Public &&
|
||||
!FunctionType(_variable).interfaceFunctionType()
|
||||
)
|
||||
typeError(_variable.location(), "Internal type is not allowed for public state variables.");
|
||||
m_errorReporter.typeError(_variable.location(), "Internal type is not allowed for public state variables.");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TypeChecker::visit(EnumDefinition const& _enum)
|
||||
{
|
||||
if (m_scope->contractKind() == ContractDefinition::ContractKind::Interface)
|
||||
typeError(_enum.location(), "Enumerable cannot be declared in interfaces.");
|
||||
m_errorReporter.typeError(_enum.location(), "Enumerable cannot be declared in interfaces.");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -572,12 +571,12 @@ void TypeChecker::visitManually(
|
||||
}
|
||||
if (!parameters)
|
||||
{
|
||||
typeError(_modifier.location(), "Referenced declaration is neither modifier nor base class.");
|
||||
m_errorReporter.typeError(_modifier.location(), "Referenced declaration is neither modifier nor base class.");
|
||||
return;
|
||||
}
|
||||
if (parameters->size() != arguments.size())
|
||||
{
|
||||
typeError(
|
||||
m_errorReporter.typeError(
|
||||
_modifier.location(),
|
||||
"Wrong argument count for modifier invocation: " +
|
||||
toString(arguments.size()) +
|
||||
@@ -589,7 +588,7 @@ void TypeChecker::visitManually(
|
||||
}
|
||||
for (size_t i = 0; i < _modifier.arguments().size(); ++i)
|
||||
if (!type(*arguments[i])->isImplicitlyConvertibleTo(*type(*(*parameters)[i])))
|
||||
typeError(
|
||||
m_errorReporter.typeError(
|
||||
arguments[i]->location(),
|
||||
"Invalid type for argument in modifier invocation. "
|
||||
"Invalid implicit conversion from " +
|
||||
@@ -608,13 +607,13 @@ bool TypeChecker::visit(EventDefinition const& _eventDef)
|
||||
if (var->isIndexed())
|
||||
numIndexed++;
|
||||
if (_eventDef.isAnonymous() && numIndexed > 4)
|
||||
typeError(_eventDef.location(), "More than 4 indexed arguments for anonymous event.");
|
||||
m_errorReporter.typeError(_eventDef.location(), "More than 4 indexed arguments for anonymous event.");
|
||||
else if (!_eventDef.isAnonymous() && numIndexed > 3)
|
||||
typeError(_eventDef.location(), "More than 3 indexed arguments for event.");
|
||||
m_errorReporter.typeError(_eventDef.location(), "More than 3 indexed arguments for event.");
|
||||
if (!type(*var)->canLiveOutsideStorage())
|
||||
typeError(var->location(), "Type is required to live outside storage.");
|
||||
m_errorReporter.typeError(var->location(), "Type is required to live outside storage.");
|
||||
if (!type(*var)->interfaceType(false))
|
||||
typeError(var->location(), "Internal type is not allowed as event parameter type.");
|
||||
m_errorReporter.typeError(var->location(), "Internal type is not allowed as event parameter type.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -624,7 +623,7 @@ void TypeChecker::endVisit(FunctionTypeName const& _funType)
|
||||
FunctionType const& fun = dynamic_cast<FunctionType const&>(*_funType.annotation().type);
|
||||
if (fun.kind() == FunctionType::Kind::External)
|
||||
if (!fun.canBeUsedExternally(false))
|
||||
typeError(_funType.location(), "External function type uses internal types.");
|
||||
m_errorReporter.typeError(_funType.location(), "External function type uses internal types.");
|
||||
}
|
||||
|
||||
bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
@@ -647,39 +646,39 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
{
|
||||
if (!var->isStateVariable() && !var->type()->dataStoredIn(DataLocation::Storage))
|
||||
{
|
||||
typeError(_identifier.location, "The suffixes _offset and _slot can only be used on storage variables.");
|
||||
m_errorReporter.typeError(_identifier.location, "The suffixes _offset and _slot can only be used on storage variables.");
|
||||
return size_t(-1);
|
||||
}
|
||||
else if (_context != julia::IdentifierContext::RValue)
|
||||
{
|
||||
typeError(_identifier.location, "Storage variables cannot be assigned to.");
|
||||
m_errorReporter.typeError(_identifier.location, "Storage variables cannot be assigned to.");
|
||||
return size_t(-1);
|
||||
}
|
||||
}
|
||||
else if (var->isConstant())
|
||||
{
|
||||
typeError(_identifier.location, "Constant variables not supported by inline assembly.");
|
||||
m_errorReporter.typeError(_identifier.location, "Constant variables not supported by inline assembly.");
|
||||
return size_t(-1);
|
||||
}
|
||||
else if (!var->isLocalVariable())
|
||||
{
|
||||
typeError(_identifier.location, "Only local variables are supported. To access storage variables, use the _slot and _offset suffixes.");
|
||||
m_errorReporter.typeError(_identifier.location, "Only local variables are supported. To access storage variables, use the _slot and _offset suffixes.");
|
||||
return size_t(-1);
|
||||
}
|
||||
else if (var->type()->dataStoredIn(DataLocation::Storage))
|
||||
{
|
||||
typeError(_identifier.location, "You have to use the _slot or _offset prefix to access storage reference variables.");
|
||||
m_errorReporter.typeError(_identifier.location, "You have to use the _slot or _offset prefix to access storage reference variables.");
|
||||
return size_t(-1);
|
||||
}
|
||||
else if (var->type()->sizeOnStack() != 1)
|
||||
{
|
||||
typeError(_identifier.location, "Only types that use one stack slot are supported.");
|
||||
m_errorReporter.typeError(_identifier.location, "Only types that use one stack slot are supported.");
|
||||
return size_t(-1);
|
||||
}
|
||||
}
|
||||
else if (_context == julia::IdentifierContext::LValue)
|
||||
{
|
||||
typeError(_identifier.location, "Only local variables can be assigned to in inline assembly.");
|
||||
m_errorReporter.typeError(_identifier.location, "Only local variables can be assigned to in inline assembly.");
|
||||
return size_t(-1);
|
||||
}
|
||||
|
||||
@@ -696,7 +695,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
{
|
||||
if (!contract->isLibrary())
|
||||
{
|
||||
typeError(_identifier.location, "Expected a library.");
|
||||
m_errorReporter.typeError(_identifier.location, "Expected a library.");
|
||||
return size_t(-1);
|
||||
}
|
||||
}
|
||||
@@ -710,7 +709,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
_inlineAssembly.annotation().analysisInfo = make_shared<assembly::AsmAnalysisInfo>();
|
||||
assembly::AsmAnalyzer analyzer(
|
||||
*_inlineAssembly.annotation().analysisInfo,
|
||||
m_errors,
|
||||
m_errorReporter,
|
||||
false,
|
||||
identifierAccess
|
||||
);
|
||||
@@ -754,7 +753,7 @@ void TypeChecker::endVisit(Return const& _return)
|
||||
ParameterList const* params = _return.annotation().functionReturnParameters;
|
||||
if (!params)
|
||||
{
|
||||
typeError(_return.location(), "Return arguments not allowed.");
|
||||
m_errorReporter.typeError(_return.location(), "Return arguments not allowed.");
|
||||
return;
|
||||
}
|
||||
TypePointers returnTypes;
|
||||
@@ -763,9 +762,9 @@ void TypeChecker::endVisit(Return const& _return)
|
||||
if (auto tupleType = dynamic_cast<TupleType const*>(type(*_return.expression()).get()))
|
||||
{
|
||||
if (tupleType->components().size() != params->parameters().size())
|
||||
typeError(_return.location(), "Different number of arguments in return statement than in returns declaration.");
|
||||
m_errorReporter.typeError(_return.location(), "Different number of arguments in return statement than in returns declaration.");
|
||||
else if (!tupleType->isImplicitlyConvertibleTo(TupleType(returnTypes)))
|
||||
typeError(
|
||||
m_errorReporter.typeError(
|
||||
_return.expression()->location(),
|
||||
"Return argument type " +
|
||||
type(*_return.expression())->toString() +
|
||||
@@ -775,12 +774,12 @@ void TypeChecker::endVisit(Return const& _return)
|
||||
);
|
||||
}
|
||||
else if (params->parameters().size() != 1)
|
||||
typeError(_return.location(), "Different number of arguments in return statement than in returns declaration.");
|
||||
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))
|
||||
typeError(
|
||||
m_errorReporter.typeError(
|
||||
_return.expression()->location(),
|
||||
"Return argument type " +
|
||||
type(*_return.expression())->toString() +
|
||||
@@ -797,20 +796,20 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
|
||||
{
|
||||
// No initial value is only permitted for single variables with specified type.
|
||||
if (_statement.declarations().size() != 1 || !_statement.declarations().front())
|
||||
fatalTypeError(_statement.location(), "Assignment necessary for type detection.");
|
||||
m_errorReporter.fatalTypeError(_statement.location(), "Assignment necessary for type detection.");
|
||||
VariableDeclaration const& varDecl = *_statement.declarations().front();
|
||||
if (!varDecl.annotation().type)
|
||||
fatalTypeError(_statement.location(), "Assignment necessary for type detection.");
|
||||
m_errorReporter.fatalTypeError(_statement.location(), "Assignment necessary for type detection.");
|
||||
if (auto ref = dynamic_cast<ReferenceType const*>(type(varDecl).get()))
|
||||
{
|
||||
if (ref->dataStoredIn(DataLocation::Storage))
|
||||
warning(
|
||||
m_errorReporter.warning(
|
||||
varDecl.location(),
|
||||
"Uninitialized storage pointer. Did you mean '<type> memory " + varDecl.name() + "'?"
|
||||
);
|
||||
}
|
||||
else if (dynamic_cast<MappingType const*>(type(varDecl).get()))
|
||||
typeError(
|
||||
m_errorReporter.typeError(
|
||||
varDecl.location(),
|
||||
"Uninitialized mapping. Mappings cannot be created dynamically, you have to assign them from a state variable."
|
||||
);
|
||||
@@ -836,7 +835,7 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
|
||||
if (variables.empty())
|
||||
{
|
||||
if (!valueTypes.empty())
|
||||
fatalTypeError(
|
||||
m_errorReporter.fatalTypeError(
|
||||
_statement.location(),
|
||||
"Too many components (" +
|
||||
toString(valueTypes.size()) +
|
||||
@@ -844,7 +843,7 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
|
||||
);
|
||||
}
|
||||
else if (valueTypes.size() != variables.size() && !variables.front() && !variables.back())
|
||||
fatalTypeError(
|
||||
m_errorReporter.fatalTypeError(
|
||||
_statement.location(),
|
||||
"Wildcard both at beginning and end of variable declaration list is only allowed "
|
||||
"if the number of components is equal."
|
||||
@@ -853,7 +852,7 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
|
||||
if (!variables.empty() && (!variables.back() || !variables.front()))
|
||||
--minNumValues;
|
||||
if (valueTypes.size() < minNumValues)
|
||||
fatalTypeError(
|
||||
m_errorReporter.fatalTypeError(
|
||||
_statement.location(),
|
||||
"Not enough components (" +
|
||||
toString(valueTypes.size()) +
|
||||
@@ -861,7 +860,7 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
|
||||
toString(minNumValues) + ")."
|
||||
);
|
||||
if (valueTypes.size() > variables.size() && variables.front() && variables.back())
|
||||
fatalTypeError(
|
||||
m_errorReporter.fatalTypeError(
|
||||
_statement.location(),
|
||||
"Too many components (" +
|
||||
toString(valueTypes.size()) +
|
||||
@@ -892,7 +891,7 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
|
||||
if (!var.annotation().type)
|
||||
{
|
||||
if (valueComponentType->category() == Type::Category::RationalNumber)
|
||||
fatalTypeError(
|
||||
m_errorReporter.fatalTypeError(
|
||||
_statement.initialValue()->location(),
|
||||
"Invalid rational " +
|
||||
valueComponentType->toString() +
|
||||
@@ -902,7 +901,7 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
|
||||
solAssert(false, "");
|
||||
}
|
||||
else if (*var.annotation().type == TupleType())
|
||||
typeError(
|
||||
m_errorReporter.typeError(
|
||||
var.location(),
|
||||
"Cannot declare variable with void (empty tuple) type."
|
||||
);
|
||||
@@ -918,7 +917,7 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
|
||||
dynamic_cast<RationalNumberType const&>(*valueComponentType).isFractional() &&
|
||||
valueComponentType->mobileType()
|
||||
)
|
||||
typeError(
|
||||
m_errorReporter.typeError(
|
||||
_statement.location(),
|
||||
"Type " +
|
||||
valueComponentType->toString() +
|
||||
@@ -929,7 +928,7 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
|
||||
" or use an explicit conversion."
|
||||
);
|
||||
else
|
||||
typeError(
|
||||
m_errorReporter.typeError(
|
||||
_statement.location(),
|
||||
"Type " +
|
||||
valueComponentType->toString() +
|
||||
@@ -947,7 +946,7 @@ void TypeChecker::endVisit(ExpressionStatement const& _statement)
|
||||
{
|
||||
if (type(_statement.expression())->category() == Type::Category::RationalNumber)
|
||||
if (!dynamic_cast<RationalNumberType const&>(*type(_statement.expression())).mobileType())
|
||||
typeError(_statement.expression().location(), "Invalid rational number.");
|
||||
m_errorReporter.typeError(_statement.expression().location(), "Invalid rational number.");
|
||||
|
||||
if (auto call = dynamic_cast<FunctionCall const*>(&_statement.expression()))
|
||||
{
|
||||
@@ -959,9 +958,9 @@ void TypeChecker::endVisit(ExpressionStatement const& _statement)
|
||||
kind == FunctionType::Kind::BareCallCode ||
|
||||
kind == FunctionType::Kind::BareDelegateCall
|
||||
)
|
||||
warning(_statement.location(), "Return value of low-level calls not used.");
|
||||
m_errorReporter.warning(_statement.location(), "Return value of low-level calls not used.");
|
||||
else if (kind == FunctionType::Kind::Send)
|
||||
warning(_statement.location(), "Failure condition of 'send' ignored. Consider using 'transfer' instead.");
|
||||
m_errorReporter.warning(_statement.location(), "Failure condition of 'send' ignored. Consider using 'transfer' instead.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -976,14 +975,14 @@ bool TypeChecker::visit(Conditional const& _conditional)
|
||||
TypePointer trueType = type(_conditional.trueExpression())->mobileType();
|
||||
TypePointer falseType = type(_conditional.falseExpression())->mobileType();
|
||||
if (!trueType)
|
||||
fatalTypeError(_conditional.trueExpression().location(), "Invalid mobile type.");
|
||||
m_errorReporter.fatalTypeError(_conditional.trueExpression().location(), "Invalid mobile type.");
|
||||
if (!falseType)
|
||||
fatalTypeError(_conditional.falseExpression().location(), "Invalid mobile type.");
|
||||
m_errorReporter.fatalTypeError(_conditional.falseExpression().location(), "Invalid mobile type.");
|
||||
|
||||
TypePointer commonType = Type::commonType(trueType, falseType);
|
||||
if (!commonType)
|
||||
{
|
||||
typeError(
|
||||
m_errorReporter.typeError(
|
||||
_conditional.location(),
|
||||
"True expression's type " +
|
||||
trueType->toString() +
|
||||
@@ -1003,7 +1002,7 @@ bool TypeChecker::visit(Conditional const& _conditional)
|
||||
_conditional.falseExpression().annotation().isPure;
|
||||
|
||||
if (_conditional.annotation().lValueRequested)
|
||||
typeError(
|
||||
m_errorReporter.typeError(
|
||||
_conditional.location(),
|
||||
"Conditional expression as left value is not supported yet."
|
||||
);
|
||||
@@ -1019,7 +1018,7 @@ bool TypeChecker::visit(Assignment const& _assignment)
|
||||
if (TupleType const* tupleType = dynamic_cast<TupleType const*>(t.get()))
|
||||
{
|
||||
if (_assignment.assignmentOperator() != Token::Assign)
|
||||
typeError(
|
||||
m_errorReporter.typeError(
|
||||
_assignment.location(),
|
||||
"Compound assignment is not allowed for tuple types."
|
||||
);
|
||||
@@ -1029,7 +1028,7 @@ bool TypeChecker::visit(Assignment const& _assignment)
|
||||
}
|
||||
else if (t->category() == Type::Category::Mapping)
|
||||
{
|
||||
typeError(_assignment.location(), "Mappings cannot be assigned to.");
|
||||
m_errorReporter.typeError(_assignment.location(), "Mappings cannot be assigned to.");
|
||||
_assignment.rightHandSide().accept(*this);
|
||||
}
|
||||
else if (_assignment.assignmentOperator() == Token::Assign)
|
||||
@@ -1043,7 +1042,7 @@ bool TypeChecker::visit(Assignment const& _assignment)
|
||||
type(_assignment.rightHandSide())
|
||||
);
|
||||
if (!resultType || *resultType != *t)
|
||||
typeError(
|
||||
m_errorReporter.typeError(
|
||||
_assignment.location(),
|
||||
"Operator " +
|
||||
string(Token::toString(_assignment.assignmentOperator())) +
|
||||
@@ -1064,7 +1063,7 @@ bool TypeChecker::visit(TupleExpression const& _tuple)
|
||||
if (_tuple.annotation().lValueRequested)
|
||||
{
|
||||
if (_tuple.isInlineArray())
|
||||
fatalTypeError(_tuple.location(), "Inline array type cannot be declared as LValue.");
|
||||
m_errorReporter.fatalTypeError(_tuple.location(), "Inline array type cannot be declared as LValue.");
|
||||
for (auto const& component: components)
|
||||
if (component)
|
||||
{
|
||||
@@ -1088,7 +1087,7 @@ bool TypeChecker::visit(TupleExpression const& _tuple)
|
||||
{
|
||||
// Outside of an lvalue-context, the only situation where a component can be empty is (x,).
|
||||
if (!components[i] && !(i == 1 && components.size() == 2))
|
||||
fatalTypeError(_tuple.location(), "Tuple component cannot be empty.");
|
||||
m_errorReporter.fatalTypeError(_tuple.location(), "Tuple component cannot be empty.");
|
||||
else if (components[i])
|
||||
{
|
||||
components[i]->accept(*this);
|
||||
@@ -1098,7 +1097,7 @@ bool TypeChecker::visit(TupleExpression const& _tuple)
|
||||
if (_tuple.isInlineArray())
|
||||
{
|
||||
if ((i == 0 || inlineArrayType) && !types[i]->mobileType())
|
||||
fatalTypeError(components[i]->location(), "Invalid mobile type.");
|
||||
m_errorReporter.fatalTypeError(components[i]->location(), "Invalid mobile type.");
|
||||
|
||||
if (i == 0)
|
||||
inlineArrayType = types[i]->mobileType();
|
||||
@@ -1115,7 +1114,7 @@ bool TypeChecker::visit(TupleExpression const& _tuple)
|
||||
if (_tuple.isInlineArray())
|
||||
{
|
||||
if (!inlineArrayType)
|
||||
fatalTypeError(_tuple.location(), "Unable to deduce common type for array elements.");
|
||||
m_errorReporter.fatalTypeError(_tuple.location(), "Unable to deduce common type for array elements.");
|
||||
_tuple.annotation().type = make_shared<ArrayType>(DataLocation::Memory, inlineArrayType, types.size());
|
||||
}
|
||||
else
|
||||
@@ -1147,7 +1146,7 @@ bool TypeChecker::visit(UnaryOperation const& _operation)
|
||||
TypePointer t = type(_operation.subExpression())->unaryOperatorResult(op);
|
||||
if (!t)
|
||||
{
|
||||
typeError(
|
||||
m_errorReporter.typeError(
|
||||
_operation.location(),
|
||||
"Unary operator " +
|
||||
string(Token::toString(op)) +
|
||||
@@ -1168,7 +1167,7 @@ void TypeChecker::endVisit(BinaryOperation const& _operation)
|
||||
TypePointer commonType = leftType->binaryOperatorResult(_operation.getOperator(), rightType);
|
||||
if (!commonType)
|
||||
{
|
||||
typeError(
|
||||
m_errorReporter.typeError(
|
||||
_operation.location(),
|
||||
"Operator " +
|
||||
string(Token::toString(_operation.getOperator())) +
|
||||
@@ -1201,7 +1200,7 @@ void TypeChecker::endVisit(BinaryOperation const& _operation)
|
||||
commonType->category() == Type::Category::FixedPoint &&
|
||||
dynamic_cast<FixedPointType const&>(*commonType).numBits() != 256
|
||||
))
|
||||
warning(
|
||||
m_errorReporter.warning(
|
||||
_operation.location(),
|
||||
"Result of exponentiation has type " + commonType->toString() + " and thus "
|
||||
"might overflow. Silence this warning by converting the literal to the "
|
||||
@@ -1254,9 +1253,9 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
|
||||
TypeType const& t = dynamic_cast<TypeType const&>(*expressionType);
|
||||
TypePointer resultType = t.actualType();
|
||||
if (arguments.size() != 1)
|
||||
typeError(_functionCall.location(), "Exactly one argument expected for explicit type conversion.");
|
||||
m_errorReporter.typeError(_functionCall.location(), "Exactly one argument expected for explicit type conversion.");
|
||||
else if (!isPositionalCall)
|
||||
typeError(_functionCall.location(), "Type conversion cannot allow named arguments.");
|
||||
m_errorReporter.typeError(_functionCall.location(), "Type conversion cannot allow named arguments.");
|
||||
else
|
||||
{
|
||||
TypePointer const& argType = type(*arguments.front());
|
||||
@@ -1265,7 +1264,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
|
||||
// (data location cannot yet be specified for type conversions)
|
||||
resultType = ReferenceType::copyForLocationIfReference(argRefType->location(), resultType);
|
||||
if (!argType->isExplicitlyConvertibleTo(*resultType))
|
||||
typeError(_functionCall.location(), "Explicit type conversion not allowed.");
|
||||
m_errorReporter.typeError(_functionCall.location(), "Explicit type conversion not allowed.");
|
||||
}
|
||||
_functionCall.annotation().type = resultType;
|
||||
_functionCall.annotation().isPure = isPure;
|
||||
@@ -1298,7 +1297,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
|
||||
|
||||
if (!functionType)
|
||||
{
|
||||
typeError(_functionCall.location(), "Type is not callable");
|
||||
m_errorReporter.typeError(_functionCall.location(), "Type is not callable");
|
||||
_functionCall.annotation().type = make_shared<TupleType>();
|
||||
return false;
|
||||
}
|
||||
@@ -1323,7 +1322,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
|
||||
for (auto const& member: membersRemovedForStructConstructor)
|
||||
msg += " " + member;
|
||||
}
|
||||
typeError(_functionCall.location(), msg);
|
||||
m_errorReporter.typeError(_functionCall.location(), msg);
|
||||
}
|
||||
else if (isPositionalCall)
|
||||
{
|
||||
@@ -1335,10 +1334,10 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
|
||||
{
|
||||
if (auto t = dynamic_cast<RationalNumberType const*>(argType.get()))
|
||||
if (!t->mobileType())
|
||||
typeError(arguments[i]->location(), "Invalid rational number (too large or division by zero).");
|
||||
m_errorReporter.typeError(arguments[i]->location(), "Invalid rational number (too large or division by zero).");
|
||||
}
|
||||
else if (!type(*arguments[i])->isImplicitlyConvertibleTo(*parameterTypes[i]))
|
||||
typeError(
|
||||
m_errorReporter.typeError(
|
||||
arguments[i]->location(),
|
||||
"Invalid type for argument in function call. "
|
||||
"Invalid implicit conversion from " +
|
||||
@@ -1354,14 +1353,14 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
|
||||
// call by named arguments
|
||||
auto const& parameterNames = functionType->parameterNames();
|
||||
if (functionType->takesArbitraryParameters())
|
||||
typeError(
|
||||
m_errorReporter.typeError(
|
||||
_functionCall.location(),
|
||||
"Named arguments cannnot be used for functions that take arbitrary parameters."
|
||||
);
|
||||
else if (parameterNames.size() > argumentNames.size())
|
||||
typeError(_functionCall.location(), "Some argument names are missing.");
|
||||
m_errorReporter.typeError(_functionCall.location(), "Some argument names are missing.");
|
||||
else if (parameterNames.size() < argumentNames.size())
|
||||
typeError(_functionCall.location(), "Too many arguments.");
|
||||
m_errorReporter.typeError(_functionCall.location(), "Too many arguments.");
|
||||
else
|
||||
{
|
||||
// check duplicate names
|
||||
@@ -1371,7 +1370,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
|
||||
if (*argumentNames[i] == *argumentNames[j])
|
||||
{
|
||||
duplication = true;
|
||||
typeError(arguments[i]->location(), "Duplicate named argument.");
|
||||
m_errorReporter.typeError(arguments[i]->location(), "Duplicate named argument.");
|
||||
}
|
||||
|
||||
// check actual types
|
||||
@@ -1385,7 +1384,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
|
||||
found = true;
|
||||
// check type convertible
|
||||
if (!type(*arguments[i])->isImplicitlyConvertibleTo(*parameterTypes[j]))
|
||||
typeError(
|
||||
m_errorReporter.typeError(
|
||||
arguments[i]->location(),
|
||||
"Invalid type for argument in function call. "
|
||||
"Invalid implicit conversion from " +
|
||||
@@ -1398,7 +1397,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
|
||||
}
|
||||
|
||||
if (!found)
|
||||
typeError(
|
||||
m_errorReporter.typeError(
|
||||
_functionCall.location(),
|
||||
"Named argument does not match function declaration."
|
||||
);
|
||||
@@ -1419,11 +1418,11 @@ void TypeChecker::endVisit(NewExpression const& _newExpression)
|
||||
auto contract = dynamic_cast<ContractDefinition const*>(&dereference(*contractName));
|
||||
|
||||
if (!contract)
|
||||
fatalTypeError(_newExpression.location(), "Identifier is not a contract.");
|
||||
m_errorReporter.fatalTypeError(_newExpression.location(), "Identifier is not a contract.");
|
||||
if (!contract->annotation().isFullyImplemented)
|
||||
typeError(_newExpression.location(), "Trying to create an instance of an abstract contract.");
|
||||
m_errorReporter.typeError(_newExpression.location(), "Trying to create an instance of an abstract contract.");
|
||||
if (!contract->constructorIsPublic())
|
||||
typeError(_newExpression.location(), "Contract with internal constructor cannot be created directly.");
|
||||
m_errorReporter.typeError(_newExpression.location(), "Contract with internal constructor cannot be created directly.");
|
||||
|
||||
solAssert(!!m_scope, "");
|
||||
m_scope->annotation().contractDependencies.insert(contract);
|
||||
@@ -1432,7 +1431,7 @@ void TypeChecker::endVisit(NewExpression const& _newExpression)
|
||||
"Linearized base contracts not yet available."
|
||||
);
|
||||
if (contractDependenciesAreCyclic(*m_scope))
|
||||
typeError(
|
||||
m_errorReporter.typeError(
|
||||
_newExpression.location(),
|
||||
"Circular reference for contract creation (cannot create instance of derived or same contract)."
|
||||
);
|
||||
@@ -1442,12 +1441,12 @@ void TypeChecker::endVisit(NewExpression const& _newExpression)
|
||||
else if (type->category() == Type::Category::Array)
|
||||
{
|
||||
if (!type->canLiveOutsideStorage())
|
||||
fatalTypeError(
|
||||
m_errorReporter.fatalTypeError(
|
||||
_newExpression.typeName().location(),
|
||||
"Type cannot live outside storage."
|
||||
);
|
||||
if (!type->isDynamicallySized())
|
||||
typeError(
|
||||
m_errorReporter.typeError(
|
||||
_newExpression.typeName().location(),
|
||||
"Length has to be placed in parentheses after the array type for new expression."
|
||||
);
|
||||
@@ -1462,7 +1461,7 @@ void TypeChecker::endVisit(NewExpression const& _newExpression)
|
||||
_newExpression.annotation().isPure = true;
|
||||
}
|
||||
else
|
||||
fatalTypeError(_newExpression.location(), "Contract or array type expected.");
|
||||
m_errorReporter.fatalTypeError(_newExpression.location(), "Contract or array type expected.");
|
||||
}
|
||||
|
||||
bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
||||
@@ -1493,13 +1492,13 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
||||
exprType
|
||||
);
|
||||
if (!storageType->members(m_scope).membersByName(memberName).empty())
|
||||
fatalTypeError(
|
||||
m_errorReporter.fatalTypeError(
|
||||
_memberAccess.location(),
|
||||
"Member \"" + memberName + "\" is not available in " +
|
||||
exprType->toString() +
|
||||
" outside of storage."
|
||||
);
|
||||
fatalTypeError(
|
||||
m_errorReporter.fatalTypeError(
|
||||
_memberAccess.location(),
|
||||
"Member \"" + memberName + "\" not found or not visible "
|
||||
"after argument-dependent lookup in " + exprType->toString() +
|
||||
@@ -1507,7 +1506,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
||||
);
|
||||
}
|
||||
else if (possibleMembers.size() > 1)
|
||||
fatalTypeError(
|
||||
m_errorReporter.fatalTypeError(
|
||||
_memberAccess.location(),
|
||||
"Member \"" + memberName + "\" not unique "
|
||||
"after argument-dependent lookup in " + exprType->toString() +
|
||||
@@ -1520,7 +1519,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
||||
|
||||
if (auto funType = dynamic_cast<FunctionType const*>(annotation.type.get()))
|
||||
if (funType->bound() && !exprType->isImplicitlyConvertibleTo(*funType->selfType()))
|
||||
typeError(
|
||||
m_errorReporter.typeError(
|
||||
_memberAccess.location(),
|
||||
"Function \"" + memberName + "\" cannot be called on an object of type " +
|
||||
exprType->toString() + " (expected " + funType->selfType()->toString() + ")"
|
||||
@@ -1568,10 +1567,10 @@ bool TypeChecker::visit(IndexAccess const& _access)
|
||||
{
|
||||
ArrayType const& actualType = dynamic_cast<ArrayType const&>(*baseType);
|
||||
if (!index)
|
||||
typeError(_access.location(), "Index expression cannot be omitted.");
|
||||
m_errorReporter.typeError(_access.location(), "Index expression cannot be omitted.");
|
||||
else if (actualType.isString())
|
||||
{
|
||||
typeError(_access.location(), "Index access for string is not possible.");
|
||||
m_errorReporter.typeError(_access.location(), "Index access for string is not possible.");
|
||||
index->accept(*this);
|
||||
}
|
||||
else
|
||||
@@ -1581,7 +1580,7 @@ bool TypeChecker::visit(IndexAccess const& _access)
|
||||
{
|
||||
if (!numberType->isFractional()) // error is reported above
|
||||
if (!actualType.isDynamicallySized() && actualType.length() <= numberType->literalValue(nullptr))
|
||||
typeError(_access.location(), "Out of bounds array access.");
|
||||
m_errorReporter.typeError(_access.location(), "Out of bounds array access.");
|
||||
}
|
||||
}
|
||||
resultType = actualType.baseType();
|
||||
@@ -1592,7 +1591,7 @@ bool TypeChecker::visit(IndexAccess const& _access)
|
||||
{
|
||||
MappingType const& actualType = dynamic_cast<MappingType const&>(*baseType);
|
||||
if (!index)
|
||||
typeError(_access.location(), "Index expression cannot be omitted.");
|
||||
m_errorReporter.typeError(_access.location(), "Index expression cannot be omitted.");
|
||||
else
|
||||
expectType(*index, *actualType.keyType());
|
||||
resultType = actualType.valueType();
|
||||
@@ -1614,7 +1613,7 @@ bool TypeChecker::visit(IndexAccess const& _access)
|
||||
length->literalValue(nullptr)
|
||||
));
|
||||
else
|
||||
fatalTypeError(index->location(), "Integer constant expected.");
|
||||
m_errorReporter.fatalTypeError(index->location(), "Integer constant expected.");
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1622,20 +1621,20 @@ bool TypeChecker::visit(IndexAccess const& _access)
|
||||
{
|
||||
FixedBytesType const& bytesType = dynamic_cast<FixedBytesType const&>(*baseType);
|
||||
if (!index)
|
||||
typeError(_access.location(), "Index expression cannot be omitted.");
|
||||
m_errorReporter.typeError(_access.location(), "Index expression cannot be omitted.");
|
||||
else
|
||||
{
|
||||
expectType(*index, IntegerType(256));
|
||||
if (auto integerType = dynamic_cast<RationalNumberType const*>(type(*index).get()))
|
||||
if (bytesType.numBytes() <= integerType->literalValue(nullptr))
|
||||
typeError(_access.location(), "Out of bounds array access.");
|
||||
m_errorReporter.typeError(_access.location(), "Out of bounds array access.");
|
||||
}
|
||||
resultType = make_shared<FixedBytesType>(1);
|
||||
isLValue = false; // @todo this heavily depends on how it is embedded
|
||||
break;
|
||||
}
|
||||
default:
|
||||
fatalTypeError(
|
||||
m_errorReporter.fatalTypeError(
|
||||
_access.baseExpression().location(),
|
||||
"Indexed expression has to be a type, mapping or array (is " + baseType->toString() + ")"
|
||||
);
|
||||
@@ -1665,14 +1664,14 @@ bool TypeChecker::visit(Identifier const& _identifier)
|
||||
candidates.push_back(declaration);
|
||||
}
|
||||
if (candidates.empty())
|
||||
fatalTypeError(_identifier.location(), "No matching declaration found after variable lookup.");
|
||||
m_errorReporter.fatalTypeError(_identifier.location(), "No matching declaration found after variable lookup.");
|
||||
else if (candidates.size() == 1)
|
||||
annotation.referencedDeclaration = candidates.front();
|
||||
else
|
||||
fatalTypeError(_identifier.location(), "No unique declaration found after variable lookup.");
|
||||
m_errorReporter.fatalTypeError(_identifier.location(), "No unique declaration found after variable lookup.");
|
||||
}
|
||||
else if (annotation.overloadedDeclarations.empty())
|
||||
fatalTypeError(_identifier.location(), "No candidates for overload resolution found.");
|
||||
m_errorReporter.fatalTypeError(_identifier.location(), "No candidates for overload resolution found.");
|
||||
else if (annotation.overloadedDeclarations.size() == 1)
|
||||
annotation.referencedDeclaration = *annotation.overloadedDeclarations.begin();
|
||||
else
|
||||
@@ -1688,11 +1687,11 @@ bool TypeChecker::visit(Identifier const& _identifier)
|
||||
candidates.push_back(declaration);
|
||||
}
|
||||
if (candidates.empty())
|
||||
fatalTypeError(_identifier.location(), "No matching declaration found after argument-dependent lookup.");
|
||||
m_errorReporter.fatalTypeError(_identifier.location(), "No matching declaration found after argument-dependent lookup.");
|
||||
else if (candidates.size() == 1)
|
||||
annotation.referencedDeclaration = candidates.front();
|
||||
else
|
||||
fatalTypeError(_identifier.location(), "No unique declaration found after argument-dependent lookup.");
|
||||
m_errorReporter.fatalTypeError(_identifier.location(), "No unique declaration found after argument-dependent lookup.");
|
||||
}
|
||||
}
|
||||
solAssert(
|
||||
@@ -1702,7 +1701,7 @@ bool TypeChecker::visit(Identifier const& _identifier)
|
||||
annotation.isLValue = annotation.referencedDeclaration->isLValue();
|
||||
annotation.type = annotation.referencedDeclaration->type();
|
||||
if (!annotation.type)
|
||||
fatalTypeError(_identifier.location(), "Declaration referenced before type could be determined.");
|
||||
m_errorReporter.fatalTypeError(_identifier.location(), "Declaration referenced before type could be determined.");
|
||||
if (auto variableDeclaration = dynamic_cast<VariableDeclaration const*>(annotation.referencedDeclaration))
|
||||
annotation.isPure = annotation.isConstant = variableDeclaration->isConstant();
|
||||
else if (dynamic_cast<MagicVariableDeclaration const*>(annotation.referencedDeclaration))
|
||||
@@ -1727,7 +1726,7 @@ void TypeChecker::endVisit(Literal const& _literal)
|
||||
return;
|
||||
}
|
||||
else
|
||||
warning(
|
||||
m_errorReporter.warning(
|
||||
_literal.location(),
|
||||
"This looks like an address but has an invalid checksum. "
|
||||
"If this is not used as an address, please prepend '00'."
|
||||
@@ -1736,7 +1735,7 @@ void TypeChecker::endVisit(Literal const& _literal)
|
||||
_literal.annotation().type = Type::forLiteral(_literal);
|
||||
_literal.annotation().isPure = true;
|
||||
if (!_literal.annotation().type)
|
||||
fatalTypeError(_literal.location(), "Invalid literal value.");
|
||||
m_errorReporter.fatalTypeError(_literal.location(), "Invalid literal value.");
|
||||
}
|
||||
|
||||
bool TypeChecker::contractDependenciesAreCyclic(
|
||||
@@ -1777,7 +1776,7 @@ void TypeChecker::expectType(Expression const& _expression, Type const& _expecte
|
||||
dynamic_pointer_cast<RationalNumberType const>(type(_expression))->isFractional() &&
|
||||
type(_expression)->mobileType()
|
||||
)
|
||||
typeError(
|
||||
m_errorReporter.typeError(
|
||||
_expression.location(),
|
||||
"Type " +
|
||||
type(_expression)->toString() +
|
||||
@@ -1788,7 +1787,7 @@ void TypeChecker::expectType(Expression const& _expression, Type const& _expecte
|
||||
" or use an explicit conversion."
|
||||
);
|
||||
else
|
||||
typeError(
|
||||
m_errorReporter.typeError(
|
||||
_expression.location(),
|
||||
"Type " +
|
||||
type(_expression)->toString() +
|
||||
@@ -1805,33 +1804,8 @@ void TypeChecker::requireLValue(Expression const& _expression)
|
||||
_expression.accept(*this);
|
||||
|
||||
if (_expression.annotation().isConstant)
|
||||
typeError(_expression.location(), "Cannot assign to a constant variable.");
|
||||
m_errorReporter.typeError(_expression.location(), "Cannot assign to a constant variable.");
|
||||
else if (!_expression.annotation().isLValue)
|
||||
typeError(_expression.location(), "Expression has to be an lvalue.");
|
||||
m_errorReporter.typeError(_expression.location(), "Expression has to be an lvalue.");
|
||||
}
|
||||
|
||||
void TypeChecker::typeError(SourceLocation const& _location, string const& _description)
|
||||
{
|
||||
auto err = make_shared<Error>(Error::Type::TypeError);
|
||||
*err <<
|
||||
errinfo_sourceLocation(_location) <<
|
||||
errinfo_comment(_description);
|
||||
|
||||
m_errors.push_back(err);
|
||||
}
|
||||
|
||||
void TypeChecker::warning(SourceLocation const& _location, string const& _description)
|
||||
{
|
||||
auto err = make_shared<Error>(Error::Type::Warning);
|
||||
*err <<
|
||||
errinfo_sourceLocation(_location) <<
|
||||
errinfo_comment(_description);
|
||||
|
||||
m_errors.push_back(err);
|
||||
}
|
||||
|
||||
void TypeChecker::fatalTypeError(SourceLocation const& _location, string const& _description)
|
||||
{
|
||||
typeError(_location, _description);
|
||||
BOOST_THROW_EXCEPTION(FatalError());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user