libsolidity: Remove dead code wrt. VariableDeclaration::canHaveAutoType()

Closes #4667
This commit is contained in:
Christian Parpart 2018-08-06 18:03:17 +02:00
parent d33e5683f5
commit 4c90ddf64a
No known key found for this signature in database
GPG Key ID: 19BC8DD20312C929
3 changed files with 113 additions and 115 deletions

View File

@ -292,134 +292,138 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable)
if (_variable.annotation().type) if (_variable.annotation().type)
return; return;
TypePointer type; if (!_variable.typeName())
if (_variable.typeName())
{ {
type = _variable.typeName()->annotation().type; // This can still happen in very unusual cases where a developer uses constructs, such as
using Location = VariableDeclaration::Location; // `var a;`, however, such code will have generated errors already.
Location varLoc = _variable.referenceLocation(); // However, we cannot blindingly solAssert() for that here, as the TypeChecker (which is
DataLocation typeLoc = DataLocation::Memory; // invoking ReferencesResolver) is generating it, so the error is most likely(!) generated
// References are forced to calldata for external function parameters (not return) // after this step.
// and memory for parameters (also return) of publicly visible functions. return;
// They default to memory for function parameters and storage for local variables. }
// As an exception, "storage" is allowed for library functions.
if (auto ref = dynamic_cast<ReferenceType const*>(type.get())) TypePointer type;
type = _variable.typeName()->annotation().type;
using Location = VariableDeclaration::Location;
Location varLoc = _variable.referenceLocation();
DataLocation typeLoc = DataLocation::Memory;
// References are forced to calldata for external function parameters (not return)
// and memory for parameters (also return) of publicly visible functions.
// They default to memory for function parameters and storage for local variables.
// As an exception, "storage" is allowed for library functions.
if (auto ref = dynamic_cast<ReferenceType const*>(type.get()))
{
bool isPointer = true;
if (_variable.isExternalCallableParameter())
{ {
bool isPointer = true; auto const& contract = dynamic_cast<ContractDefinition const&>(
if (_variable.isExternalCallableParameter()) *dynamic_cast<Declaration const&>(*_variable.scope()).scope()
);
if (contract.isLibrary())
{ {
auto const& contract = dynamic_cast<ContractDefinition const&>( if (varLoc == Location::Memory)
*dynamic_cast<Declaration const&>(*_variable.scope()).scope()
);
if (contract.isLibrary())
{
if (varLoc == Location::Memory)
fatalTypeError(_variable.location(),
"Location has to be calldata or storage for external "
"library functions (remove the \"memory\" keyword)."
);
}
else
{
// force location of external function parameters (not return) to calldata
if (varLoc != Location::CallData && varLoc != Location::Default)
fatalTypeError(_variable.location(),
"Location has to be calldata for external functions "
"(remove the \"memory\" or \"storage\" keyword)."
);
}
if (varLoc == Location::Default)
typeLoc = DataLocation::CallData;
else
typeLoc = varLoc == Location::Memory ? DataLocation::Memory : DataLocation::Storage;
}
else if (_variable.isCallableParameter() && dynamic_cast<Declaration const&>(*_variable.scope()).isPublic())
{
auto const& contract = dynamic_cast<ContractDefinition const&>(
*dynamic_cast<Declaration const&>(*_variable.scope()).scope()
);
// force locations of public or external function (return) parameters to memory
if (varLoc != Location::Memory && varLoc != Location::Default && !contract.isLibrary())
fatalTypeError(_variable.location(), fatalTypeError(_variable.location(),
"Location has to be memory for publicly visible functions " "Location has to be calldata or storage for external "
"(remove the \"storage\" or \"calldata\" keyword)." "library functions (remove the \"memory\" keyword)."
); );
if (varLoc == Location::Default || !contract.isLibrary()) }
else
{
// force location of external function parameters (not return) to calldata
if (varLoc != Location::CallData && varLoc != Location::Default)
fatalTypeError(_variable.location(),
"Location has to be calldata for external functions "
"(remove the \"memory\" or \"storage\" keyword)."
);
}
if (varLoc == Location::Default)
typeLoc = DataLocation::CallData;
else
typeLoc = varLoc == Location::Memory ? DataLocation::Memory : DataLocation::Storage;
}
else if (_variable.isCallableParameter() && dynamic_cast<Declaration const&>(*_variable.scope()).isPublic())
{
auto const& contract = dynamic_cast<ContractDefinition const&>(
*dynamic_cast<Declaration const&>(*_variable.scope()).scope()
);
// force locations of public or external function (return) parameters to memory
if (varLoc != Location::Memory && varLoc != Location::Default && !contract.isLibrary())
fatalTypeError(_variable.location(),
"Location has to be memory for publicly visible functions "
"(remove the \"storage\" or \"calldata\" keyword)."
);
if (varLoc == Location::Default || !contract.isLibrary())
typeLoc = DataLocation::Memory;
else
{
if (varLoc == Location::CallData)
fatalTypeError(_variable.location(),
"Location cannot be calldata for non-external functions "
"(remove the \"calldata\" keyword)."
);
typeLoc = varLoc == Location::Memory ? DataLocation::Memory : DataLocation::Storage;
}
}
else
{
if (_variable.isConstant())
{
if (varLoc != Location::Default && varLoc != Location::Memory)
fatalTypeError(
_variable.location(),
"Data location has to be \"memory\" (or unspecified) for constants."
);
typeLoc = DataLocation::Memory;
}
else if (varLoc == Location::Default)
{
if (_variable.isCallableParameter())
typeLoc = DataLocation::Memory; typeLoc = DataLocation::Memory;
else else
{ {
if (varLoc == Location::CallData) typeLoc = DataLocation::Storage;
fatalTypeError(_variable.location(), if (_variable.isLocalVariable())
"Location cannot be calldata for non-external functions " typeError(
"(remove the \"calldata\" keyword)." _variable.location(),
"Data location must be specified as either \"memory\" or \"storage\"."
); );
typeLoc = varLoc == Location::Memory ? DataLocation::Memory : DataLocation::Storage;
} }
} }
else else
{ {
if (_variable.isConstant()) switch (varLoc)
{ {
if (varLoc != Location::Default && varLoc != Location::Memory) case Location::Memory:
fatalTypeError(
_variable.location(),
"Data location has to be \"memory\" (or unspecified) for constants."
);
typeLoc = DataLocation::Memory; typeLoc = DataLocation::Memory;
break;
case Location::Storage:
typeLoc = DataLocation::Storage;
break;
case Location::CallData:
fatalTypeError(_variable.location(),
"Variable cannot be declared as \"calldata\" (remove the \"calldata\" keyword)."
);
break;
default:
solAssert(false, "Unknown data location");
} }
else if (varLoc == Location::Default)
{
if (_variable.isCallableParameter())
typeLoc = DataLocation::Memory;
else
{
typeLoc = DataLocation::Storage;
if (_variable.isLocalVariable())
typeError(
_variable.location(),
"Data location must be specified as either \"memory\" or \"storage\"."
);
}
}
else
{
switch (varLoc)
{
case Location::Memory:
typeLoc = DataLocation::Memory;
break;
case Location::Storage:
typeLoc = DataLocation::Storage;
break;
case Location::CallData:
fatalTypeError(_variable.location(),
"Variable cannot be declared as \"calldata\" (remove the \"calldata\" keyword)."
);
break;
default:
solAssert(false, "Unknown data location");
}
}
isPointer = !_variable.isStateVariable();
} }
type = ref->copyForLocation(typeLoc, isPointer); isPointer = !_variable.isStateVariable();
} }
else if (dynamic_cast<MappingType const*>(type.get())) type = ref->copyForLocation(typeLoc, isPointer);
{
if (_variable.isLocalVariable() && varLoc != Location::Storage)
typeError(
_variable.location(),
"Data location for mappings must be specified as \"storage\"."
);
}
else if (varLoc != Location::Default && !ref)
typeError(_variable.location(), "Data location can only be given for array or struct types.");
_variable.annotation().type = type;
} }
else if (!_variable.canHaveAutoType()) else if (dynamic_cast<MappingType const*>(type.get()))
typeError(_variable.location(), "Explicit type needed."); {
// otherwise we have a "var"-declaration whose type is resolved by the first assignment if (_variable.isLocalVariable() && varLoc != Location::Storage)
typeError(
_variable.location(),
"Data location for mappings must be specified as \"storage\"."
);
}
else if (varLoc != Location::Default && !ref)
typeError(_variable.location(), "Data location can only be given for array or struct types.");
_variable.annotation().type = type;
} }
void ReferencesResolver::typeError(SourceLocation const& _location, string const& _description) void ReferencesResolver::typeError(SourceLocation const& _location, string const& _description)

View File

@ -466,11 +466,6 @@ bool VariableDeclaration::isExternalCallableParameter() const
return false; return false;
} }
bool VariableDeclaration::canHaveAutoType() const
{
return isLocalVariable() && !isCallableParameter();
}
TypePointer VariableDeclaration::type() const TypePointer VariableDeclaration::type() const
{ {
return annotation().type; return annotation().type;

View File

@ -696,7 +696,6 @@ public:
bool isExternalCallableParameter() const; bool isExternalCallableParameter() const;
/// @returns true if the type of the variable does not need to be specified, i.e. it is declared /// @returns true if the type of the variable does not need to be specified, i.e. it is declared
/// in the body of a function or modifier. /// in the body of a function or modifier.
bool canHaveAutoType() const;
bool isStateVariable() const { return m_isStateVariable; } bool isStateVariable() const { return m_isStateVariable; }
bool isIndexed() const { return m_isIndexed; } bool isIndexed() const { return m_isIndexed; }
bool isConstant() const { return m_isConstant; } bool isConstant() const { return m_isConstant; }