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

View File

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

View File

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

View File

@ -265,6 +265,8 @@ void FunctionDefinition::accept(ASTVisitor& _visitor)
m_parameters->accept(_visitor); m_parameters->accept(_visitor);
if (m_returnParameters) if (m_returnParameters)
m_returnParameters->accept(_visitor); m_returnParameters->accept(_visitor);
if (m_experimentalReturnExpression)
m_experimentalReturnExpression->accept(_visitor);
listAccept(m_functionModifiers, _visitor); listAccept(m_functionModifiers, _visitor);
if (m_body) if (m_body)
m_body->accept(_visitor); m_body->accept(_visitor);
@ -283,6 +285,8 @@ void FunctionDefinition::accept(ASTConstVisitor& _visitor) const
m_parameters->accept(_visitor); m_parameters->accept(_visitor);
if (m_returnParameters) if (m_returnParameters)
m_returnParameters->accept(_visitor); m_returnParameters->accept(_visitor);
if (m_experimentalReturnExpression)
m_experimentalReturnExpression->accept(_visitor);
listAccept(m_functionModifiers, _visitor); listAccept(m_functionModifiers, _visitor);
if (m_body) if (m_body)
m_body->accept(_visitor); 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."); m_errorReporter.syntaxError(0000_error, _functionDefinition.location(), "Function may not have modifiers.");
if (_functionDefinition.overrides()) if (_functionDefinition.overrides())
m_errorReporter.syntaxError(0000_error, _functionDefinition.location(), "Function may not have override specifiers."); m_errorReporter.syntaxError(0000_error, _functionDefinition.location(), "Function may not have override specifiers.");
solAssert(!_functionDefinition.returnParameterList());
if (_functionDefinition.isFree()) if (_functionDefinition.isFree())
{ {
if (_functionDefinition.stateMutability() != StateMutability::NonPayable) if (_functionDefinition.stateMutability() != StateMutability::NonPayable)

View File

@ -68,13 +68,15 @@ bool TypeInference::visit(FunctionDefinition const& _functionDefinition)
ScopedSaveAndRestore signatureRestore(m_currentFunctionType, nullopt); ScopedSaveAndRestore signatureRestore(m_currentFunctionType, nullopt);
_functionDefinition.parameterList().accept(*this); _functionDefinition.parameterList().accept(*this);
if (_functionDefinition.returnParameterList()) if (_functionDefinition.experimentalReturnExpression())
_functionDefinition.returnParameterList()->accept(*this); {
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( Type functionType = TypeSystemHelpers{m_typeSystem}.functionType(
getListType(&_functionDefinition.parameterList()), getType(_functionDefinition.parameterList()),
getListType(_functionDefinition.returnParameterList().get()) _functionDefinition.experimentalReturnExpression() ? getType(*_functionDefinition.experimentalReturnExpression()) : m_unitType
); );
m_currentFunctionType = functionType; m_currentFunctionType = functionType;

View File

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

View File

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

View File

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

View File

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

View File

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