Ejemplo n.º 1
0
bool Compiler::visit(VariableDeclaration const& _variableDeclaration)
{
	solAssert(_variableDeclaration.isStateVariable(), "Compiler visit to non-state variable declaration.");
	CompilerContext::LocationSetter locationSetter(m_context, _variableDeclaration);

	m_context.startFunction(_variableDeclaration);
	m_breakTags.clear();
	m_continueTags.clear();

	ExpressionCompiler(m_context, m_optimize).appendStateVariableAccessor(_variableDeclaration);

	return false;
}
void ReferencesResolver::endVisit(VariableDeclaration const& _variable)
{
    if (_variable.annotation().type)
        return;

    TypePointer type;
    if (_variable.typeName())
    {
        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())
            {
                auto const& contract = dynamic_cast<ContractDefinition 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::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() && _variable.scope()->isPublic())
            {
                auto const& contract = dynamic_cast<ContractDefinition const&>(*_variable.scope()->scope());
                // force locations of public or external function (return) parameters to memory
                if (varLoc == Location::Storage && !contract.isLibrary())
                    fatalTypeError(_variable.location(),
                                   "Location has to be memory for publicly visible functions "
                                   "(remove the \"storage\" keyword)."
                                  );
                if (varLoc == Location::Default || !contract.isLibrary())
                    typeLoc = DataLocation::Memory;
                else
                    typeLoc = varLoc == Location::Memory ? DataLocation::Memory : DataLocation::Storage;
            }
            else
            {
                if (_variable.isConstant())
                {
                    if (varLoc != Location::Default && varLoc != Location::Memory)
                        fatalTypeError(
                            _variable.location(),
                            "Storage location has to be \"memory\" (or unspecified) for constants."
                        );
                    typeLoc = DataLocation::Memory;
                }
                else if (varLoc == Location::Default)
                    typeLoc = _variable.isCallableParameter() ? DataLocation::Memory : DataLocation::Storage;
                else
                    typeLoc = varLoc == Location::Memory ? DataLocation::Memory : DataLocation::Storage;
                isPointer = !_variable.isStateVariable();
            }

            type = ref->copyForLocation(typeLoc, isPointer);
        }
        else if (varLoc != Location::Default && !ref)
            fatalTypeError(_variable.location(), "Storage location can only be given for array or struct types.");

        if (!type)
            fatalTypeError(_variable.location(), "Invalid type name.");

    }
    else if (!_variable.canHaveAutoType())
        fatalTypeError(_variable.location(), "Explicit type needed.");
    // otherwise we have a "var"-declaration whose type is resolved by the first assignment

    _variable.annotation().type = type;
}