This commit is contained in:
Daniel Kirchner 2023-06-27 16:49:39 +02:00
parent 9120737f57
commit f9b424418c
12 changed files with 101 additions and 52 deletions

View File

@ -158,7 +158,7 @@ bool ReferencesResolver::visit(Identifier const& _identifier)
bool ReferencesResolver::visit(FunctionDefinition const& _functionDefinition)
{
m_returnParameters.push_back(_functionDefinition.returnParameterList().get());
m_functionDefinitions.push_back(&_functionDefinition);
if (_functionDefinition.documentation())
resolveInheritDoc(*_functionDefinition.documentation(), _functionDefinition.annotation());
@ -168,13 +168,13 @@ bool ReferencesResolver::visit(FunctionDefinition const& _functionDefinition)
void ReferencesResolver::endVisit(FunctionDefinition const&)
{
solAssert(!m_returnParameters.empty(), "");
m_returnParameters.pop_back();
solAssert(!m_functionDefinitions.empty(), "");
m_functionDefinitions.pop_back();
}
bool ReferencesResolver::visit(ModifierDefinition const& _modifierDefinition)
{
m_returnParameters.push_back(nullptr);
m_functionDefinitions.push_back(nullptr);
if (_modifierDefinition.documentation())
resolveInheritDoc(*_modifierDefinition.documentation(), _modifierDefinition.annotation());
@ -184,8 +184,8 @@ bool ReferencesResolver::visit(ModifierDefinition const& _modifierDefinition)
void ReferencesResolver::endVisit(ModifierDefinition const&)
{
solAssert(!m_returnParameters.empty(), "");
m_returnParameters.pop_back();
solAssert(!m_functionDefinitions.empty(), "");
m_functionDefinitions.pop_back();
}
void ReferencesResolver::endVisit(IdentifierPath const& _path)
@ -245,8 +245,9 @@ bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly)
bool ReferencesResolver::visit(Return const& _return)
{
solAssert(!m_returnParameters.empty(), "");
_return.annotation().functionReturnParameters = m_returnParameters.back();
solAssert(!m_functionDefinitions.empty(), "");
_return.annotation().function = m_functionDefinitions.back();
_return.annotation().functionReturnParameters = m_functionDefinitions.back() ? m_functionDefinitions.back()->returnParameterList().get() : nullptr;
return true;
}

View File

@ -99,8 +99,8 @@ private:
langutil::ErrorReporter& m_errorReporter;
NameAndTypeResolver& m_resolver;
langutil::EVMVersion m_evmVersion;
/// Stack of return parameters.
std::vector<ParameterList const*> m_returnParameters;
/// Stack of function definitions.
std::vector<FunctionDefinition const*> m_functionDefinitions;
bool const m_resolveInsideCode;
InlineAssemblyAnnotation* m_yulAnnotation = nullptr;

View File

@ -958,7 +958,8 @@ public:
ASTPointer<ParameterList> const& _parameters,
std::vector<ASTPointer<ModifierInvocation>> _modifiers,
ASTPointer<ParameterList> const& _returnParameters,
ASTPointer<Block> const& _body
ASTPointer<Block> const& _body,
ASTPointer<Expression> const& _experimentalReturnExpression = {}
):
CallableDeclaration(_id, _location, _name, _nameLocation, _visibility, _parameters, _isVirtual, _overrides, _returnParameters),
StructurallyDocumented(_documentation),
@ -967,10 +968,12 @@ public:
m_free(_free),
m_kind(_kind),
m_functionModifiers(std::move(_modifiers)),
m_body(_body)
m_body(_body),
m_experimentalReturnExpression(_experimentalReturnExpression)
{
solAssert(_kind == Token::Constructor || _kind == Token::Function || _kind == Token::Fallback || _kind == Token::Receive, "");
solAssert(isOrdinary() == !name().empty(), "");
// TODO: assert _returnParameters implies non-experimental _experimentalReturnExpression implies experimental
}
void accept(ASTVisitor& _visitor) override;
@ -1028,12 +1031,15 @@ public:
ContractDefinition const* _searchStart = nullptr
) const override;
Expression const* experimentalReturnExpression() const { return m_experimentalReturnExpression.get(); }
private:
StateMutability m_stateMutability;
bool m_free;
Token const m_kind;
std::vector<ASTPointer<ModifierInvocation>> m_functionModifiers;
ASTPointer<Block> m_body;
ASTPointer<Expression> m_experimentalReturnExpression;
};
/**

View File

@ -244,6 +244,8 @@ struct ReturnAnnotation: StatementAnnotation
{
/// Reference to the return parameters of the function.
ParameterList const* functionReturnParameters = nullptr;
/// Reference to the function containing the return statement.
FunctionDefinition const* function = nullptr;
};
struct TypeNameAnnotation: ASTAnnotation

View File

@ -265,6 +265,8 @@ void FunctionDefinition::accept(ASTVisitor& _visitor)
m_parameters->accept(_visitor);
if (m_returnParameters)
m_returnParameters->accept(_visitor);
if (m_experimentalReturnExpression)
m_experimentalReturnExpression->accept(_visitor);
listAccept(m_functionModifiers, _visitor);
if (m_body)
m_body->accept(_visitor);
@ -283,6 +285,8 @@ void FunctionDefinition::accept(ASTConstVisitor& _visitor) const
m_parameters->accept(_visitor);
if (m_returnParameters)
m_returnParameters->accept(_visitor);
if (m_experimentalReturnExpression)
m_experimentalReturnExpression->accept(_visitor);
listAccept(m_functionModifiers, _visitor);
if (m_body)
m_body->accept(_visitor);

View File

@ -59,6 +59,7 @@ bool SyntaxRestrictor::visit(FunctionDefinition const& _functionDefinition)
m_errorReporter.syntaxError(0000_error, _functionDefinition.location(), "Function may not have modifiers.");
if (_functionDefinition.overrides())
m_errorReporter.syntaxError(0000_error, _functionDefinition.location(), "Function may not have override specifiers.");
solAssert(!_functionDefinition.returnParameterList());
if (_functionDefinition.isFree())
{
if (_functionDefinition.stateMutability() != StateMutability::NonPayable)

View File

@ -68,13 +68,15 @@ bool TypeInference::visit(FunctionDefinition const& _functionDefinition)
ScopedSaveAndRestore signatureRestore(m_currentFunctionType, nullopt);
_functionDefinition.parameterList().accept(*this);
if (_functionDefinition.returnParameterList())
_functionDefinition.returnParameterList()->accept(*this);
if (_functionDefinition.experimentalReturnExpression())
{
ScopedSaveAndRestore expressionContext{m_expressionContext, ExpressionContext::Type};
_functionDefinition.experimentalReturnExpression()->accept(*this);
}
auto getListType = [&](ParameterList const* _list) { return _list ? getType(*_list) : m_unitType; };
Type functionType = TypeSystemHelpers{m_typeSystem}.functionType(
getListType(&_functionDefinition.parameterList()),
getListType(_functionDefinition.returnParameterList().get())
getType(_functionDefinition.parameterList()),
_functionDefinition.experimentalReturnExpression() ? getType(*_functionDefinition.experimentalReturnExpression()) : m_unitType
);
m_currentFunctionType = functionType;

View File

@ -140,14 +140,15 @@ string IRGenerator::generate(FunctionDefinition const& _function, Type _type)
if (!_function.parameters().empty())
code << IRNames::localVariable(*_function.parameters().back());
code << ")";
if (_function.returnParameterList() && !_function.returnParameters().empty())
if (_function.experimentalReturnExpression())
{
code << " -> ";
if (_function.returnParameters().size() > 1)
for (auto const& arg: _function.returnParameters() | ranges::views::drop_last(1))
code << IRNames::localVariable(*arg) << ", ";
if (!_function.returnParameters().empty())
code << IRNames::localVariable(*_function.returnParameters().back());
auto returnType = m_context.analysis.annotation<TypeInference>(*_function.experimentalReturnExpression()).type;
solAssert(returnType);
if (!m_env.typeEquals(*returnType, m_context.analysis.typeSystem().type(PrimitiveType::Unit, {})))
{
// TODO: destructure tuples.
code << " -> " << IRNames::localVariable(*_function.experimentalReturnExpression()) << " ";
}
}
code << "{\n";
for (auto _statement: _function.body().statements())

View File

@ -161,11 +161,9 @@ void IRGeneratorForStatements::endVisit(Return const& _return)
{
if (Expression const* value = _return.expression())
{
solAssert(_return.annotation().functionReturnParameters, "Invalid return parameters pointer.");
vector<ASTPointer<VariableDeclaration>> const& returnParameters =
_return.annotation().functionReturnParameters->parameters();
solAssert(returnParameters.size() == 1, "Returning tuples not yet supported.");
m_code << IRNames::localVariable(*returnParameters.front()) << " := " << IRNames::localVariable(*value) << "\n";
solAssert(_return.annotation().function, "Invalid return.");
solAssert(_return.annotation().function->experimentalReturnExpression(), "Invalid return.");
m_code << IRNames::localVariable(*_return.annotation().function->experimentalReturnExpression()) << " := " << IRNames::localVariable(*value) << "\n";
}
m_code << "leave\n";

View File

@ -621,16 +621,25 @@ Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(bool _isStateVari
else
break;
}
if (
m_scanner->currentToken() == (m_experimentalSolidityEnabledInCurrentSourceUnit ? Token::RightArrow : Token::Returns)
)
if (m_experimentalSolidityEnabledInCurrentSourceUnit)
{
bool const permitEmptyParameterList = m_experimentalSolidityEnabledInCurrentSourceUnit;
advance();
result.returnParameters = parseParameterList(options, permitEmptyParameterList);
if (m_scanner->currentToken() == Token::RightArrow)
{
advance();
result.experimentalReturnExpression = parseBinaryExpression();
}
}
else
result.returnParameters = createEmptyParameterList();
{
if (m_scanner->currentToken() == Token::Returns)
{
bool const permitEmptyParameterList = m_experimentalSolidityEnabledInCurrentSourceUnit;
advance();
result.returnParameters = parseParameterList(options, permitEmptyParameterList);
}
else
result.returnParameters = createEmptyParameterList();
}
return result;
}
@ -682,6 +691,11 @@ ASTPointer<ASTNode> Parser::parseFunctionDefinition(bool _freeFunction, bool _al
FunctionHeaderParserResult header = parseFunctionHeader(false);
if (m_experimentalSolidityEnabledInCurrentSourceUnit)
solAssert(!header.returnParameters);
else
solAssert(!header.experimentalReturnExpression);
ASTPointer<Block> block;
nodeFactory.markEndPosition();
if (!_allowBody)
@ -706,7 +720,8 @@ ASTPointer<ASTNode> Parser::parseFunctionDefinition(bool _freeFunction, bool _al
header.parameters,
header.modifiers,
header.returnParameters,
block
block,
header.experimentalReturnExpression
);
}
@ -1224,10 +1239,12 @@ ASTPointer<TypeName> Parser::parseTypeName()
ASTPointer<FunctionTypeName> Parser::parseFunctionType()
{
solAssert(!m_experimentalSolidityEnabledInCurrentSourceUnit);
RecursionGuard recursionGuard(*this);
ASTNodeFactory nodeFactory(*this);
expectToken(Token::Function);
FunctionHeaderParserResult header = parseFunctionHeader(true);
solAssert(!header.experimentalReturnExpression);
return nodeFactory.createNode<FunctionTypeName>(
header.parameters,
header.returnParameters,

View File

@ -77,6 +77,7 @@ private:
Visibility visibility = Visibility::Default;
StateMutability stateMutability = StateMutability::NonPayable;
std::vector<ASTPointer<ModifierInvocation>> modifiers;
ASTPointer<Expression> experimentalReturnExpression;
};
/// Struct to share parsed function call arguments.

View File

@ -2,19 +2,8 @@ pragma experimental solidity;
type uint256 = word;
instantiation uint256: * {
function mul(x, y) -> z {
let a = uint256.rep(x);
let b = uint256.rep(y);
assembly {
a := mul(a,b)
}
return uint256.abs(a);
}
}
instantiation uint256: + {
function add(x, y) -> z {
function add(x, y) -> uint256 {
let a = uint256.rep(x);
let b = uint256.rep(y);
assembly {
@ -24,27 +13,52 @@ instantiation uint256: + {
}
}
instantiation uint256: * {
function mul(x, y) -> uint256 {
let a = uint256.rep(x);
let b = uint256.rep(y);
assembly {
a := mul(a,b)
}
return uint256.abs(a);
}
}
instantiation word: * {
function mul(x, y) -> z {
function mul(x, y) -> word {
let z: word;
assembly {
z := mul(x,y)
}
return z;
}
}
instantiation word: integer {
function fromInteger(x:integer) -> y:word {
function fromInteger(x:integer) -> word {
//x + x;
}
}
instantiation word: == {
function eq(x, y) -> z:bool {
function eq(x, y) -> bool {
assembly {
x := eq(x, y)
}
}
}
function f(x:uint256->uint256,y:uint256) -> uint256
{
return x(y);
}
function g(x:uint256) -> uint256
{
return x;
}
contract C {
fallback() external {
let x : word;
@ -52,8 +66,10 @@ contract C {
x := 0x10
}
let w = uint256.abs(x);
// w = f(g, w);
w = w * w + w;
let y : word;
let z : (uint256,uint256);
assembly { y := 2 }
y = uint256.rep(w) * y;
assembly {