From 987278385e581ad8cb28b7210092a203912ce148 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Thu, 29 Jun 2023 02:42:10 +0200 Subject: [PATCH] tmp --- .../experimental/analysis/ASTTransform.cpp | 374 ++++++------- .../experimental/analysis/ASTTransform.h | 145 ++--- .../experimental/analysis/TypeCheck.cpp | 519 ++++++++---------- libsolidity/experimental/ast/AST.h | 65 +-- .../experimental/ast/TypeSystemHelper.cpp | 56 +- .../experimental/ast/TypeSystemHelper.h | 5 +- .../semanticTests/experimental/stub.sol | 16 +- 7 files changed, 519 insertions(+), 661 deletions(-) diff --git a/libsolidity/experimental/analysis/ASTTransform.cpp b/libsolidity/experimental/analysis/ASTTransform.cpp index b0129d993..98ca898d9 100644 --- a/libsolidity/experimental/analysis/ASTTransform.cpp +++ b/libsolidity/experimental/analysis/ASTTransform.cpp @@ -39,88 +39,130 @@ ASTTransform::ASTTransform(Analysis& _analysis): m_analysis(_analysis), m_errorR { } -bool ASTTransform::visit(legacy::ContractDefinition const& _contractDefinition) +bool ASTTransform::visit(legacy::TypeDefinition const& _typeDefinition) { - SetNode setNode(*this, _contractDefinition); - auto [it, newlyInserted] = m_ast->contracts.emplace(&_contractDefinition, AST::ContractInfo{}); + SetNode setNode(*this, _typeDefinition); + auto [it, newlyInserted] = m_ast->typeDefinitions.emplace(&_typeDefinition, term(_typeDefinition)); solAssert(newlyInserted); - AST::ContractInfo& contractInfo = it->second; - for (auto const& node: _contractDefinition.subNodes()) - if (auto const* function = dynamic_cast(node.get())) - solAssert(contractInfo.functions.emplace(string{}, functionDefinition(*function)).second); - else - m_errorReporter.typeError(0000_error, node->location(), "Unsupported contract element."); - - return false; -} - -bool ASTTransform::visit(legacy::FunctionDefinition const& _functionDefinition) -{ - SetNode setNode(*this, _functionDefinition); - solAssert(m_ast->functions.emplace(&_functionDefinition, functionDefinition(_functionDefinition)).second); return false; } bool ASTTransform::visit(legacy::TypeClassDefinition const& _typeClassDefinition) { SetNode setNode(*this, _typeClassDefinition); - auto [it, newlyInserted] = m_ast->typeClasses.emplace(&_typeClassDefinition, AST::TypeClassInformation{}); + auto [it, newlyInserted] = m_ast->typeClasses.emplace(&_typeClassDefinition, term(_typeClassDefinition)); solAssert(newlyInserted); - auto& info = it->second; - info.typeVariable = term(_typeClassDefinition.typeVariable()); - info.declaration = reference(_typeClassDefinition); - declare(_typeClassDefinition, *info.declaration); - map& functions = info.functions; - for (auto subNode: _typeClassDefinition.subNodes()) - { - auto const *function = dynamic_cast(subNode.get()); - solAssert(function); - solAssert(functions.emplace(function->name(), functionDefinition(*function)).second); - } return false; } bool ASTTransform::visit(legacy::TypeClassInstantiation const& _typeClassInstantiation) { SetNode setNode(*this, _typeClassInstantiation); - auto [it, newlyInserted] = m_ast->typeClassInstantiations.emplace(&_typeClassInstantiation, AST::TypeClassInstantiationInformation{}); + auto [it, newlyInserted] = m_ast->typeClassInstantiations.emplace(&_typeClassInstantiation, term(_typeClassInstantiation)); solAssert(newlyInserted); - auto& info = it->second; - info.typeClass = std::visit(util::GenericVisitor{ - [&](Token _token) -> unique_ptr { return builtinTypeClass(_token); }, - [&](ASTPointer _identifierPath) -> unique_ptr { - solAssert(_identifierPath->annotation().referencedDeclaration); - return reference(*_identifierPath->annotation().referencedDeclaration); - } - }, _typeClassInstantiation.typeClass().name()); - info.typeConstructor = term(_typeClassInstantiation.typeConstructor()); - info.argumentSorts = termOrConstant(_typeClassInstantiation.argumentSorts(), BuiltinConstant::Unit); - map& functions = info.functions; - for (auto subNode: _typeClassInstantiation.subNodes()) - { - auto const *function = dynamic_cast(subNode.get()); - solAssert(function); - solAssert(functions.emplace(function->name(), functionDefinition(*function)).second); - } return false; } -bool ASTTransform::visit(legacy::TypeDefinition const& _typeDefinition) +bool ASTTransform::visit(legacy::ContractDefinition const& _contractDefinition) +{ + SetNode setNode(*this, _contractDefinition); + auto [it, newlyInserted] = m_ast->contracts.emplace(&_contractDefinition, term(_contractDefinition)); + solAssert(newlyInserted); + return false; +} + +bool ASTTransform::visit(legacy::FunctionDefinition const& _functionDefinition) +{ + SetNode setNode(*this, _functionDefinition); + solAssert(m_ast->functions.emplace(&_functionDefinition, term(_functionDefinition)).second); + return false; +} + +bool ASTTransform::visitNode(ASTNode const& _node) +{ + m_errorReporter.typeError(0000_error, _node.location(), "Unexpected AST node during AST transform."); + return false; +} + +unique_ptr ASTTransform::term(legacy::TypeDefinition const& _typeDefinition) { SetNode setNode(*this, _typeDefinition); - auto [it, newlyInserted] = m_ast->typeDefinitions.emplace(&_typeDefinition, AST::TypeInformation{}); - solAssert(newlyInserted); - auto& info = it->second; - info.declaration = makeTerm(reference(_typeDefinition), nullptr); - declare(_typeDefinition, *info.declaration); - if (_typeDefinition.arguments()) - info.arguments = tuple(_typeDefinition.arguments()->parameters() | ranges::view::transform([&](auto argument){ - solAssert(!argument->typeExpression()); // TODO: error handling - return term(*argument); - }) | ranges::view::move | ranges::to>>); + unique_ptr name = reference(_typeDefinition); + unique_ptr arguments = termOrConstant(_typeDefinition.arguments(), BuiltinConstant::Unit); if (_typeDefinition.typeExpression()) - info.value = term(*_typeDefinition.typeExpression()); - return false; + { + unique_ptr definiens = term(*_typeDefinition.typeExpression()); + return application(BuiltinConstant::TypeDefinition, std::move(name), std::move(arguments), std::move(definiens)); + } + else + return application(BuiltinConstant::TypeDeclaration, std::move(name), std::move(arguments)); +} + +unique_ptr ASTTransform::term(legacy::TypeClassDefinition const& _typeClassDefinition) +{ + SetNode setNode(*this, _typeClassDefinition); + unique_ptr typeVariable = term(_typeClassDefinition.typeVariable()); + unique_ptr name = reference(_typeClassDefinition); + unique_ptr functions = namedFunctionList(_typeClassDefinition.subNodes()); + return application( + BuiltinConstant::TypeClassDefinition, + std::move(typeVariable), + std::move(name), + std::move(functions) + ); +} + +std::unique_ptr ASTTransform::term(legacy::TypeClassInstantiation const& _typeClassInstantiation) +{ + SetNode setNode(*this, _typeClassInstantiation); + unique_ptr typeConstructor = term(_typeClassInstantiation.typeConstructor()); + unique_ptr argumentSorts = termOrConstant(_typeClassInstantiation.argumentSorts(), BuiltinConstant::Unit); + unique_ptr typeClass = term(_typeClassInstantiation.typeClass()); + unique_ptr functions = namedFunctionList(_typeClassInstantiation.subNodes()); + return application( + BuiltinConstant::TypeClassInstantiation, + std::move(typeConstructor), + std::move(argumentSorts), + std::move(typeClass), + std::move(functions) + ); +} + +std::unique_ptr ASTTransform::term(legacy::FunctionDefinition const& _functionDefinition) +{ + SetNode setNode(*this, _functionDefinition); + unique_ptr name = reference(_functionDefinition); + unique_ptr arguments = term(_functionDefinition.parameterList()); + unique_ptr returnType = termOrConstant(_functionDefinition.experimentalReturnExpression(), BuiltinConstant::Unit); + if (_functionDefinition.isImplemented()) + { + unique_ptr body = term(_functionDefinition.body()); + return application( + BuiltinConstant::FunctionDefinition, + std::move(name), + std::move(arguments), + std::move(returnType), + std::move(body) + ); + } + else + return application( + BuiltinConstant::FunctionDeclaration, + std::move(name), + std::move(arguments), + std::move(returnType) + ); +} + +std::unique_ptr ASTTransform::term(legacy::ContractDefinition const& _contractDefinition) +{ + SetNode setNode(*this, _contractDefinition); + unique_ptr name = reference(_contractDefinition); + return application( + BuiltinConstant::ContractDefinition, + std::move(name), + namedFunctionList(_contractDefinition.subNodes()) + ); } unique_ptr ASTTransform::term(legacy::VariableDeclarationStatement const& _declaration) @@ -142,10 +184,44 @@ unique_ptr ASTTransform::term(legacy::Assignment const& _assignment) solAssert(false); } -unique_ptr ASTTransform::term(TypeName const& _name) +unique_ptr ASTTransform::term(legacy::Block const& _block) +{ + SetNode setNode(*this, _block); + if (auto statements = ranges::fold_right_last( + _block.statements() | ranges::view::transform([&](auto stmt) { return term(*stmt); }) | ranges::view::move, + [&](auto stmt, auto acc) { + return application(BuiltinConstant::ChainStatements, std::move(stmt), std::move(acc)); + } + )) + return application(BuiltinConstant::Block, std::move(*statements)); + else + return application(BuiltinConstant::Block, constant(BuiltinConstant::Unit)); +} + +unique_ptr ASTTransform::term(legacy::Statement const& _statement) +{ + SetNode setNode(*this, _statement); + if (auto const* assembly = dynamic_cast(&_statement)) + return application(BuiltinConstant::RegularStatement, *assembly); + else if (auto const* declaration = dynamic_cast(&_statement)) + return application(BuiltinConstant::RegularStatement, *declaration); + else if (auto const* assign = dynamic_cast(&_statement)) + return application(BuiltinConstant::RegularStatement, *assign); + else if (auto const* expressionStatement = dynamic_cast(&_statement)) + return application(BuiltinConstant::RegularStatement, expressionStatement->expression()); + else if (auto const* returnStatement = dynamic_cast(&_statement)) + return application(BuiltinConstant::ReturnStatement, termOrConstant(returnStatement->expression(), BuiltinConstant::Unit)); + else + { + m_analysis.errorReporter().fatalTypeError(0000_error, _statement.location(), "Unsupported statement."); + solAssert(false); + } +} + +unique_ptr ASTTransform::term(legacy::TypeName const& _name) { SetNode setNode(*this, _name); - if (auto const* elementaryTypeName = dynamic_cast(&_name)) + if (auto const* elementaryTypeName = dynamic_cast(&_name)) { switch (elementaryTypeName->typeName().token()) { @@ -178,69 +254,23 @@ unique_ptr ASTTransform::term(TypeName const& _name) solAssert(false); } -unique_ptr ASTTransform::term(legacy::Statement const& _statement) +unique_ptr ASTTransform::term(legacy::TypeClassName const& _typeClassName) { - SetNode setNode(*this, _statement); - if (auto const* assembly = dynamic_cast(&_statement)) - return term(*assembly); - else if (auto const* declaration = dynamic_cast(&_statement)) - return term(*declaration); - else if (auto const* assign = dynamic_cast(&_statement)) - return term(*assign); - else if (auto const* expressionStatement = dynamic_cast(&_statement)) - return term(expressionStatement->expression()); - else if (auto const* returnStatement = dynamic_cast(&_statement)) - return application(BuiltinConstant::Return, termOrConstant(returnStatement->expression(), BuiltinConstant::Unit)); - else - { - m_analysis.errorReporter().fatalTypeError(0000_error, _statement.location(), "Unsupported statement."); - solAssert(false); - } -} - -unique_ptr ASTTransform::term(legacy::Block const& _block) -{ - SetNode setNode(*this, _block); - if (_block.statements().empty()) - return application(BuiltinConstant::Block, constant(BuiltinConstant::Unit)); - auto makeStatement = [&](auto _stmt) { - return application(BuiltinConstant::Statement, *_stmt); - }; - - return application( - BuiltinConstant::Block, - ranges::fold_right( - _block.statements() | ranges::view::drop(1), - makeStatement(_block.statements().front()), - [&](auto stmt, auto acc) { - return application(BuiltinConstant::ChainStatements, std::move(acc), makeStatement(stmt)); - } - ) - ); -} - -AST::FunctionInfo ASTTransform::functionDefinition(legacy::FunctionDefinition const& _functionDefinition) -{ - SetNode setNode(*this, _functionDefinition); - std::unique_ptr body = nullptr; - unique_ptr argumentExpression = term(_functionDefinition.parameterList()); - if (_functionDefinition.isImplemented()) - body = term(_functionDefinition.body()); - unique_ptr returnType = termOrConstant(_functionDefinition.experimentalReturnExpression(), BuiltinConstant::Unit); - unique_ptr name = reference(_functionDefinition); - unique_ptr function = makeTerm(std::move(name), std::move(body)); - declare(_functionDefinition, *function); - return AST::FunctionInfo{ - std::move(function), - std::move(argumentExpression), - std::move(returnType) - }; + SetNode setNode(*this, _typeClassName); + return std::visit(util::GenericVisitor{ + [&](Token _token) -> unique_ptr { return builtinTypeClass(_token); }, + [&](ASTPointer _identifierPath) -> unique_ptr { + solAssert(_identifierPath->annotation().referencedDeclaration); + return reference(*_identifierPath->annotation().referencedDeclaration); + } + }, _typeClassName.name()); } unique_ptr ASTTransform::term(legacy::ParameterList const& _parameterList) { SetNode setNode(*this, _parameterList); return tuple(_parameterList.parameters() | ranges::view::transform([&](auto parameter) { + solAssert(!parameter->value()); return term(*parameter); }) | ranges::view::move | ranges::to>>); } @@ -252,9 +282,10 @@ unique_ptr ASTTransform::term(legacy::VariableDeclaration const& _variable unique_ptr name = reference(_variableDeclaration); if (_variableDeclaration.typeExpression()) name = constrain(std::move(name), term(*_variableDeclaration.typeExpression())); - unique_ptr declaration = makeTerm(std::move(name), std::move(_initialValue)); - declare(_variableDeclaration, *declaration); - return declaration; + if (_initialValue) + return application(BuiltinConstant::VariableDefinition, std::move(name), std::move(_initialValue)); + else + return application(BuiltinConstant::VariableDeclaration, std::move(name)); } unique_ptr ASTTransform::term(legacy::InlineAssembly const& _inlineAssembly) @@ -349,47 +380,17 @@ unique_ptr ASTTransform::term(legacy::Expression const& _expression) } } -unique_ptr ASTTransform::binaryOperation( - Token _operator, - unique_ptr _leftHandSide, - unique_ptr _rightHandSide -) -{ - return application(builtinBinaryOperator(_operator), std::move(_leftHandSide), std::move(_rightHandSide)); -} - unique_ptr ASTTransform::reference(legacy::Declaration const& _declaration) { - auto [it, newlyInserted] = m_declarationIndices.emplace(&_declaration, m_ast->declarations.size()); - if (newlyInserted) - m_ast->declarations.emplace_back(AST::DeclarationInfo{nullptr, {}}); - return makeTerm(it->second); + return makeTerm(static_cast(_declaration.id()), _declaration.name()); } -size_t ASTTransform::declare(legacy::Declaration const& _declaration, Term& _term) +unique_ptr ASTTransform::tuple(list> _components) { - auto [it, newlyInserted] = m_declarationIndices.emplace(&_declaration, m_ast->declarations.size()); - if (newlyInserted) - m_ast->declarations.emplace_back(AST::DeclarationInfo{&_term, _declaration.name()}); + if (auto term = ranges::fold_right_last(_components | ranges::view::move, [&](auto a, auto b) { return pair(std::move(a), std::move(b)); })) + return std::move(*term); else - { - auto& info = m_ast->declarations.at(it->second); - solAssert(!info.target); - info.target = &_term; - info.name = _declaration.name(); - } - termBase(_term).declaration = it->second; - return it->second; -} - -TermBase ASTTransform::makeTermBase() -{ - return TermBase{ - m_currentLocation, - m_currentNode ? make_optional(m_currentNode->id()) : nullopt, - std::monostate{}, - nullopt - }; + return constant(BuiltinConstant::Unit); } unique_ptr ASTTransform::constrain(unique_ptr _value, unique_ptr _constraint) @@ -397,22 +398,18 @@ unique_ptr ASTTransform::constrain(unique_ptr _value, unique_ptr ASTTransform::builtinTypeClass(langutil::Token _token) +std::unique_ptr ASTTransform::namedFunctionList(std::vector> _nodes) { - switch (_token) + list> functionList; + for (auto subNode: _nodes) { - case Token::Mul: - return constant(BuiltinConstant::Mul); - case Token::Add: - return constant(BuiltinConstant::Add); - case Token::Integer: - return constant(BuiltinConstant::Integer); - case Token::Equal: - return constant(BuiltinConstant::Equal); - default: - m_analysis.errorReporter().typeError(0000_error, m_currentLocation, "Invalid type class."); - return constant(BuiltinConstant::Undefined); + auto const *function = dynamic_cast(subNode.get()); + solAssert(function); + unique_ptr functionName = constant(function->name()); + unique_ptr functionDefinition = term(*function); + functionList.emplace_back(application(BuiltinConstant::NamedTerm, std::move(functionName), std::move(functionDefinition))); } + return tuple(std::move(functionList)); } unique_ptr ASTTransform::builtinBinaryOperator(Token _token) @@ -435,26 +432,29 @@ unique_ptr ASTTransform::builtinBinaryOperator(Token _token) } } -unique_ptr ASTTransform::pair(unique_ptr _first, unique_ptr _second) +unique_ptr ASTTransform::builtinTypeClass(langutil::Token _token) { - return application( - application( - BuiltinConstant::Pair, - std::move(_first) - ), - std::move(_second) - ); + switch (_token) + { + case Token::Mul: + return constant(BuiltinConstant::Mul); + case Token::Add: + return constant(BuiltinConstant::Add); + case Token::Integer: + return constant(BuiltinConstant::Integer); + case Token::Equal: + return constant(BuiltinConstant::Equal); + default: + m_analysis.errorReporter().typeError(0000_error, m_currentLocation, "Invalid type class."); + return constant(BuiltinConstant::Undefined); + } } -unique_ptr ASTTransform::tuple(list> _components) +TermBase ASTTransform::makeTermBase() { - if (auto term = ranges::fold_right_last(_components | ranges::view::move, [&](auto a, auto b) { return pair(std::move(a), std::move(b)); })) - return std::move(*term); - else - return constant(BuiltinConstant::Unit); -} - -unique_ptr ASTTransform::application(unique_ptr _function, std::list> _arguments) -{ - return makeTerm(std::move(_function), tuple(std::move(_arguments))); + return TermBase{ + m_currentLocation, + m_currentNode ? make_optional(m_currentNode->id()) : nullopt, + std::monostate{} + }; } diff --git a/libsolidity/experimental/analysis/ASTTransform.h b/libsolidity/experimental/analysis/ASTTransform.h index 06f00aafb..b1d433357 100644 --- a/libsolidity/experimental/analysis/ASTTransform.h +++ b/libsolidity/experimental/analysis/ASTTransform.h @@ -35,52 +35,74 @@ class ASTTransform: public ASTConstVisitor public: ASTTransform(Analysis& _analysis); - std::unique_ptr ast() - { - return std::move(m_ast); - } - + std::unique_ptr ast() { return std::move(m_ast); } private: bool visit(legacy::SourceUnit const&) override { return true; } bool visit(legacy::PragmaDirective const&) override { return true; } bool visit(legacy::ImportDirective const&) override { return true; } - bool visit(legacy::ContractDefinition const& _contractDefinition) override; - bool visit(legacy::FunctionDefinition const& _functionDefinition) override; + + bool visit(legacy::TypeDefinition const& _typeDefinition) override; bool visit(legacy::TypeClassDefinition const& _typeClassDefinition) override; bool visit(legacy::TypeClassInstantiation const& _typeClassInstantiation) override; - bool visit(legacy::TypeDefinition const& _typeDefinition) override; + bool visit(legacy::FunctionDefinition const& _functionDefinition) override; + bool visit(legacy::ContractDefinition const& _contractDefinition) override; + bool visitNode(ASTNode const& _node) override; - AST::FunctionInfo functionDefinition(legacy::FunctionDefinition const& _functionDefinition); - std::unique_ptr term(legacy::ParameterList const& _parameterList); - std::unique_ptr term(legacy::VariableDeclaration const& _variableDeclaration, std::unique_ptr _initialValue = nullptr); - std::unique_ptr term(legacy::Block const& _block); - std::unique_ptr term(std::vector> const& _statements); - std::unique_ptr term(legacy::InlineAssembly const& _assembly); + std::unique_ptr term(legacy::TypeClassDefinition const& _typeClassDefinition); + std::unique_ptr term(legacy::TypeClassInstantiation const& _typeClassInstantiation); + std::unique_ptr term(legacy::TypeDefinition const& _typeDefinition); + std::unique_ptr term(legacy::ContractDefinition const& _contractDefinition); + std::unique_ptr term(legacy::FunctionDefinition const& _functionDefinition); std::unique_ptr term(legacy::VariableDeclarationStatement const& _declaration); - std::unique_ptr term(legacy::Statement const& _statements); - std::unique_ptr term(legacy::Expression const& _expression); std::unique_ptr term(legacy::Assignment const& _assignment); + std::unique_ptr term(legacy::Block const& _block); + std::unique_ptr term(legacy::Statement const& _statements); std::unique_ptr term(legacy::TypeName const& _name); - - std::unique_ptr binaryOperation( - langutil::Token _operator, - std::unique_ptr _leftHandSide, - std::unique_ptr _rightHandSide - ); - - std::unique_ptr constant(BuiltinConstant _constant) - { - return makeTerm(_constant); - } - std::unique_ptr constant(std::string _name) - { - return makeTerm(_name); - } + std::unique_ptr term(legacy::TypeClassName const& _typeClassName); + std::unique_ptr term(legacy::ParameterList const& _parameterList); + std::unique_ptr term(legacy::VariableDeclaration const& _variableDeclaration, std::unique_ptr _initialValue = {}); + std::unique_ptr term(legacy::InlineAssembly const& _assembly); + std::unique_ptr term(legacy::Expression const& _expression); // Allows for easy uniform treatment in the variadic templates below. std::unique_ptr term(std::unique_ptr _term) { return _term; } + std::unique_ptr namedFunctionList(std::vector> _nodes); + std::unique_ptr binaryOperation( + langutil::Token _operator, + std::unique_ptr _leftHandSide, + std::unique_ptr _rightHandSide + ) + { + return application(builtinBinaryOperator(_operator), std::move(_leftHandSide), std::move(_rightHandSide)); + } + std::unique_ptr reference(legacy::Declaration const& _declaration); + std::unique_ptr constant(BuiltinConstant _constant) { return makeTerm(_constant); } + std::unique_ptr constant(std::string _name) { return makeTerm(_name); } + template + std::unique_ptr termOrConstant(T const* _node, BuiltinConstant _constant) + { + return _node ? term(*_node) : constant(_constant); + } + + + std::unique_ptr pair(std::unique_ptr _first, std::unique_ptr _second) + { + // Note: BuiltinConstant::Pair has signature a -> (b -> (a, b)) + // This reduces n-ary functions to unary functions only as primitives. + return application( + application( + BuiltinConstant::Pair, + std::move(_first) + ), + std::move(_second) + ); + } std::unique_ptr tuple(std::list> _components); + std::unique_ptr constrain(std::unique_ptr _value, std::unique_ptr _constraint); + std::unique_ptr builtinBinaryOperator(langutil::Token); + std::unique_ptr builtinTypeClass(langutil::Token); + template std::unique_ptr tuple(Args&&... _args) { @@ -88,8 +110,10 @@ private: (components.emplace_back(term(std::forward(_args))), ...); return tuple(std::move(components)); } - std::unique_ptr pair(std::unique_ptr _first, std::unique_ptr _second); - std::unique_ptr application(std::unique_ptr _function, std::list> _argument); + std::unique_ptr application(std::unique_ptr _function, std::list> _arguments) + { + return makeTerm(std::move(_function), tuple(std::move(_arguments))); + } template std::unique_ptr application(std::unique_ptr _function, Args&&... _args) { @@ -97,7 +121,6 @@ private: (components.emplace_back(term(std::forward(_args))), ...); return application(std::move(_function), std::move(components)); } - template std::unique_ptr application(BuiltinConstant _function, Args&&... _args) { @@ -106,25 +129,34 @@ private: return application(constant(_function), std::move(components)); } - std::unique_ptr constrain(std::unique_ptr _value, std::unique_ptr _constraint); - std::unique_ptr builtinBinaryOperator(langutil::Token); - std::unique_ptr builtinTypeClass(langutil::Token); - std::unique_ptr reference(legacy::Declaration const& _declaration); - size_t declare(legacy::Declaration const& _declaration, Term& _term); + TermBase makeTermBase(); + template + std::unique_ptr makeTerm(Args&&... _args) + { + return std::make_unique(TermKind{ + makeTermBase(), + std::forward(_args)... + }); + } + + Analysis& m_analysis; + langutil::ErrorReporter& m_errorReporter; + + std::unique_ptr m_ast; struct SetNode { SetNode(ASTTransform& _parent, ASTNode const& _node): - m_parent(_parent), - m_previousNode(_parent.m_currentNode), - m_previousLocation(_parent.m_currentLocation) + m_parent(_parent), + m_previousNode(_parent.m_currentNode), + m_previousLocation(_parent.m_currentLocation) { _parent.m_currentNode = &_node; _parent.m_currentLocation = _node.location(); } SetNode(ASTTransform& _parent, langutil::SourceLocation const& _location): - m_parent(_parent), - m_previousNode(_parent.m_currentNode), - m_previousLocation(_parent.m_currentLocation) + m_parent(_parent), + m_previousNode(_parent.m_currentNode), + m_previousLocation(_parent.m_currentLocation) { _parent.m_currentNode = nullptr; _parent.m_currentLocation = _location; @@ -138,31 +170,8 @@ private: ASTNode const* m_previousNode = nullptr; langutil::SourceLocation m_previousLocation; }; - TermBase makeTermBase(); - template - std::unique_ptr makeTerm(Args&&... _args) - { - return std::make_unique(TermKind{ - makeTermBase(), - std::forward(_args)... - }); - } - template - std::unique_ptr termOrConstant(T const* _node, BuiltinConstant _constant) - { - if (_node) - return term(*_node); - else - return constant(_constant); - } - - Analysis& m_analysis; - langutil::ErrorReporter& m_errorReporter; ASTNode const* m_currentNode = nullptr; langutil::SourceLocation m_currentLocation; - std::unique_ptr m_ast; - - std::map> m_declarationIndices; }; } diff --git a/libsolidity/experimental/analysis/TypeCheck.cpp b/libsolidity/experimental/analysis/TypeCheck.cpp index 469670c9d..c5de2fa05 100644 --- a/libsolidity/experimental/analysis/TypeCheck.cpp +++ b/libsolidity/experimental/analysis/TypeCheck.cpp @@ -18,13 +18,17 @@ #include #include #include -#include -#include -#include #include #include +#include +#include +#include + +#include +#include + using namespace std; using namespace solidity; using namespace langutil; @@ -32,8 +36,143 @@ using namespace solidity::frontend::experimental; namespace { -using Term = std::variant; +struct TPat +{ + using Unifier = std::function; + template + TPat(R _f(Args...)): generator([f = _f](TypeEnvironment& _env, Unifier _unifier) -> Type { + return invoke(_env, _unifier, f, std::make_index_sequence{}); + }) {} + TPat(PrimitiveType _type): generator([type = _type](TypeEnvironment& _env, Unifier) { return _env.typeSystem().type(type, {}); }) {} + Type realize(TypeEnvironment& _env, Unifier _unifier) const { return generator(_env, _unifier); } + TPat(std::function _generator):generator(std::move(_generator)) {} + TPat(Type _t): generator([t = _t](TypeEnvironment&, Unifier) -> Type { return t; }) {} +private: + template + static TPat makeFreshVariable(TypeEnvironment& _env) { return TPat{_env.typeSystem().freshTypeVariable({})}; } + template + static Type invoke(TypeEnvironment& _env, Unifier _unifier, Generator const& _generator, std::index_sequence) + { + // Use an auxiliary array to ensure deterministic evaluation order. + [[maybe_unused]] std::array patterns{makeFreshVariable(_env)...}; + return (_generator(std::move(patterns[Is])...)).realize(_env, _unifier); + } + std::function generator; +}; +namespace pattern_ops +{ +using Unifier = std::function; +inline TPat operator>>(TPat _a, TPat _b) +{ + return TPat([a = std::move(_a), b = std::move(_b)](TypeEnvironment& _env, Unifier _unifier) -> Type { + return TypeSystemHelpers{_env.typeSystem()}.functionType(a.realize(_env, _unifier), b.realize(_env, _unifier)); + }); +} +inline TPat operator==(TPat _a, TPat _b) +{ + return TPat([a = std::move(_a), b = std::move(_b)](TypeEnvironment& _env, Unifier _unifier) -> Type { + Type left = a.realize(_env, _unifier); + Type right = b.realize(_env, _unifier); + _unifier(left, right); + return left; + }); +} +template +TPat tuple(Args... args) +{ + return TPat([args = std::array{{std::move(args)...}}](TypeEnvironment& _env, Unifier _unifier) -> Type { + return TypeSystemHelpers{_env.typeSystem()}.tupleType( + args | ranges::view::transform([&](TPat _pat) { return _pat.realize(_env, _unifier); }) | ranges::to> + ); + }); +} +} + +struct BuiltinConstantInfo +{ + std::string name; + std::optional builtinType; +}; +[[maybe_unused]] BuiltinConstantInfo const& builtinConstantInfo(BuiltinConstant _constant) +{ + using namespace pattern_ops; + static const TPat unit{PrimitiveType::Unit}; + static const auto info = std::map{ + {BuiltinConstant::Unit, {"Unit", unit}}, + {BuiltinConstant::Pair, {"Pair", +[](TPat a, TPat b) { return a >> (b >> tuple(a,b)); }}}, + {BuiltinConstant::Fun, {"Fun", +[](TPat a, TPat b) { return tuple(a,b) >> (a >> b); }}}, + {BuiltinConstant::Constrain, {"Constrain", +[](TPat a) { return tuple(a,a) >> a; }}}, + {BuiltinConstant::NamedTerm, {"NamedTerm", +[](TPat a) { return tuple(unit, a) >> a; /* TODO: (name, a) >> a */ }}}, + {BuiltinConstant::TypeDeclaration, {"TypeDeclaration", nullopt}}, + {BuiltinConstant::TypeDefinition, {"TypeDefinition", +[](TPat type, TPat args, TPat value) { + return tuple(type, args, value) >> (args >> type); + }}}, + {BuiltinConstant::TypeClassDefinition, {"TypeClassDefinition", nullopt}}, + {BuiltinConstant::TypeClassInstantiation, {"TypeClassInstantiation", nullopt}}, + {BuiltinConstant::FunctionDeclaration, {"FunctionDeclaration", nullopt}}, + {BuiltinConstant::FunctionDefinition, {"FunctionDefinition", +[](TPat a, TPat r) { + return tuple(a >> r, a, r, r) >> (a >> r); + }}}, + {BuiltinConstant::ContractDefinition, {"ContractDefinition", +[]() { + return tuple(unit, (unit >> unit)) >> unit; + }}}, + {BuiltinConstant::VariableDeclaration, {"VariableDeclaration", +[](TPat a) { return a >> a; }}}, + {BuiltinConstant::VariableDefinition, {"VariableDefinition", nullopt}}, + {BuiltinConstant::Block, {"Block", +[](TPat a) { return a >> a; }}}, + {BuiltinConstant::ReturnStatement, {"ReturnStatement", +[](TPat a) { return a >> a; }}}, + {BuiltinConstant::RegularStatement, {"RegularStatement", +[](TPat a) { return a >> unit; }}}, + {BuiltinConstant::ChainStatements, {"ChainStatements", +[](TPat a, TPat b) { return tuple(a,b) >> b; }}}, + {BuiltinConstant::Assign, {"Assign", +[](TPat a) { return tuple(a,a) >> unit; }}}, + {BuiltinConstant::MemberAccess, {"MemberAccess", nullopt}}, + {BuiltinConstant::Mul, {"Mul", nullopt}}, + {BuiltinConstant::Add, {"Add", nullopt}}, + {BuiltinConstant::Void, {"Void", nullopt}}, + {BuiltinConstant::Word, {"Word", PrimitiveType::Word}}, + {BuiltinConstant::Integer, {"Integer", nullopt}}, + {BuiltinConstant::Bool, {"Bool", nullopt}}, + {BuiltinConstant::Undefined, {"Undefined", nullopt}}, + {BuiltinConstant::Equal, {"Equal", nullopt}}, + }; + return info.at(_constant); +} + +template +void forEachTopLevelTerm(AST& _ast, Visitor _visitor) +{ + for (auto& term: _ast.typeDefinitions | ranges::view::values) + _visitor(*term); + for (auto& term: _ast.typeClasses | ranges::view::values) + _visitor(*term); + for (auto& term: _ast.typeClassInstantiations | ranges::view::values) + _visitor(*term); + for (auto& term: _ast.functions | ranges::views::values) + _visitor(*term); + for (auto& term: _ast.contracts | ranges::views::values) + _visitor(*term); +} + +template +void forEachImmediateSubTerm(Term& _term, Visitor _visitor) +{ + std::visit(util::GenericVisitor{ + [&](Application const& _app) { + _visitor(*_app.expression); + _visitor(*_app.argument); + }, + [&](Lambda const& _lambda) + { + _visitor(*_lambda.argument); + _visitor(*_lambda.value); + }, + [&](InlineAssembly const&) + { + // TODO + }, + [&](Reference const&) {}, + [&](Constant const&) {} + }, _term); +} optional, reference_wrapper>> destPair(Term const& _term) { @@ -71,29 +210,15 @@ void setType(Term& _term, Type _type) std::visit([&](auto& term) { term.type = _type; }, _term); } +string colorize(string _color, string _string) +{ + return _color + _string + util::formatting::RESET; +} + string termPrinter(AST& _ast, Term const& _term, TypeEnvironment* _env = nullptr, bool _sugarPairs = true, bool _sugarConsts = true, size_t _indent = 0) { + using namespace util::formatting; auto recurse = [&](Term const& _next) { return termPrinter(_ast, _next, _env, _sugarPairs, _sugarConsts, _indent); }; - static const std::map builtinConstants = { - {BuiltinConstant::Unit, "()"}, - {BuiltinConstant::Pair, "Pair"}, - {BuiltinConstant::Fun, "Fun"}, - {BuiltinConstant::Constrain, "Constrain"}, - {BuiltinConstant::Return, "Return"}, - {BuiltinConstant::Block, "Block"}, - {BuiltinConstant::Statement, "Statement"}, - {BuiltinConstant::ChainStatements, "ChainStatements"}, - {BuiltinConstant::Assign, "Assign"}, - {BuiltinConstant::MemberAccess, "MemberAccess"}, - {BuiltinConstant::Mul, "Mul"}, - {BuiltinConstant::Add, "Add"}, - {BuiltinConstant::Void, "void"}, - {BuiltinConstant::Word, "word"}, - {BuiltinConstant::Integer, "Integer"}, - {BuiltinConstant::Bool, "Bool"}, - {BuiltinConstant::Undefined, "Undefined"}, - {BuiltinConstant::Equal, "Equal"} - }; string result = std::visit(util::GenericVisitor{ [&](Application const& _app) { if (_sugarPairs) @@ -154,8 +279,10 @@ string termPrinter(AST& _ast, Term const& _term, TypeEnvironment* _env = nullptr if (auto pair = destPair(*_app.argument)) return recurse(pair->first) + "\n" + std::string(_indent, '\t') + recurse(pair->second); break; - case BuiltinConstant::Statement: + case BuiltinConstant::RegularStatement: return recurse(*_app.argument) + ";"; + case BuiltinConstant::ReturnStatement: + return colorize(CYAN, "return ") + recurse(*_app.argument) + ";"; default: break; } @@ -166,23 +293,20 @@ string termPrinter(AST& _ast, Term const& _term, TypeEnvironment* _env = nullptr return "(" + recurse(*_lambda.argument) + " -> " + recurse(*_lambda.value) + ")"; }, [&](InlineAssembly const&) -> string { - return "assembly"; - }, - [&](VariableDeclaration const& _varDecl) { - return "let " + recurse(*_varDecl.namePattern) + (_varDecl.initialValue ? " = " + recurse(*_varDecl.initialValue) : ""); + return colorize(CYAN, "assembly"); }, [&](Reference const& _reference) { - return "" + _ast.declarations.at(_reference.index).name + ""; + return _reference.name.empty() ? util::toString(_reference.index) : _reference.name; }, [&](Constant const& _constant) { - return "" + std::visit(util::GenericVisitor{ + return colorize(BLUE, std::visit(util::GenericVisitor{ [](BuiltinConstant _constant) -> string { - return builtinConstants.at(_constant); + return builtinConstantInfo(_constant).name; }, [](std::string const& _name) { return _name; } - }, _constant.name) + ""; + }, _constant.name)); } }, _term); if (_env) @@ -190,140 +314,39 @@ string termPrinter(AST& _ast, Term const& _term, TypeEnvironment* _env = nullptr Type termType = type(_term); if (!holds_alternative(termType)) { - result += "[:" + TypeEnvironmentHelpers{*_env}.typeToString(termType) + "]"; + result += colorize(GREEN, "[:" + TypeEnvironmentHelpers{*_env}.typeToString(termType) + "]"); } } return result; } -std::string functionPrinter(AST& _ast, AST::FunctionInfo const& _info, TypeEnvironment* _env = nullptr, bool _sugarPairs = true, bool _sugarConsts = true, size_t _indent = 0) -{ - auto printTerm = [&](Term const& _term) { return termPrinter(_ast, _term, _env, _sugarPairs, _sugarConsts, _indent + 1); }; - return "function (" + printTerm(*_info.arguments) + ") -> " + printTerm(*_info.returnType) + " = " + printTerm(*_info.function) + "\n"; -} - std::string astPrinter(AST& _ast, TypeEnvironment* _env = nullptr, bool _sugarPairs = true, bool _sugarConsts = true, size_t _indent = 0) { - auto printTerm = [&](Term const& _term) { return termPrinter(_ast, _term, _env, _sugarPairs, _sugarConsts, _indent + 1); }; - auto printFunction = [&](AST::FunctionInfo const& _info) { return functionPrinter(_ast, _info, _env, _sugarPairs, _sugarConsts, _indent + 1); }; std::string result; - for (auto& info: _ast.typeDefinitions | ranges::view::values) - { - result += "type " + printTerm(*info.declaration); - if (info.arguments) - result += " " + printTerm(*info.arguments); - if (info.value) - result += " = " + printTerm(*info.declaration); - result += "\n\n"; - } - for (auto& info: _ast.typeClasses | ranges::view::values) - { - result += "class " + printTerm(*info.typeVariable) + ":" + printTerm(*info.declaration) + " {"; - _indent++; - for (auto&& functionInfo: info.functions | ranges::view::values) - result += printFunction(functionInfo); - _indent--; - result += "}\n\n"; - } - for (auto& info: _ast.typeClassInstantiations | ranges::view::values) - { - result += "instantiation " + printTerm(*info.typeConstructor) + "(" + printTerm(*info.argumentSorts) + "):" + printTerm(*info.typeClass) + "{\n"; - _indent++; - for (auto&& functionInfo: info.functions | ranges::view::values) - result += printFunction(functionInfo); - _indent--; - } - for (auto& functionInfo: _ast.functions | ranges::views::values) - { - result += printFunction(functionInfo); - result += "\n"; - } - for (auto& [contract, info]: _ast.contracts) - { - result += "contract " + contract->name() + " {\n"; - _indent++; - for(auto& function: info.functions | ranges::view::values) - result += printFunction(function); - _indent--; - result += "}\n\n"; - - } + auto printTerm = [&](Term const& _term) { result += termPrinter(_ast, _term, _env, _sugarPairs, _sugarConsts, _indent + 1) + "\n\n"; }; + forEachTopLevelTerm(_ast, printTerm); return result; } } -namespace -{ -struct TVar -{ - TypeEnvironment& env; - Type type; -}; -inline TVar operator>>(TVar a, TVar b) -{ - TypeSystemHelpers helper{a.env.typeSystem()}; - return TVar{a.env, helper.functionType(a.type, b.type)}; -} -inline TVar operator,(TVar a, TVar b) -{ - TypeSystemHelpers helper{a.env.typeSystem()}; - return TVar{a.env, helper.tupleType({a.type, b.type})}; -} -template -struct ArgumentCount; -template -struct ArgumentCount> { - static constexpr size_t value = sizeof...(Args); -}; -struct TypeGenerator -{ - template - TypeGenerator(Generator&& _generator):generator([generator = std::move(_generator)](TypeEnvironment& _env) -> Type { - return invoke(_env, generator, std::make_index_sequence::value>{}); - }) {} - TypeGenerator(TVar _type):generator([type = _type.type](TypeEnvironment& _env) -> Type { return _env.fresh(type); }) {} - TypeGenerator(PrimitiveType _type): generator([type = _type](TypeEnvironment& _env) -> Type { return _env.typeSystem().type(type, {}); }) {} - Type operator()(TypeEnvironment& _env) const { return generator(_env); } -private: - template - static TVar makeFreshVariable(TypeEnvironment& _env) { return TVar{_env, _env.typeSystem().freshTypeVariable({}) }; } - template - static Type invoke(TypeEnvironment& _env, Generator&& _generator, std::index_sequence) - { - // Use an auxiliary array to ensure deterministic evaluation order. - std::array tvars{makeFreshVariable(_env)...}; - return std::invoke(_generator, tvars[Is]...).type; - } - std::function generator; -}; -} - void TypeCheck::operator()(AST& _ast) { TypeSystem& typeSystem = m_analysis.typeSystem(); TypeSystemHelpers helper{typeSystem}; TypeEnvironment& env = typeSystem.env(); - TVar unit = TVar{env, typeSystem.type(PrimitiveType::Unit, {})}; - TVar word = TVar{env, typeSystem.type(PrimitiveType::Word, {})}; - std::unique_ptr currentReturn; - std::map builtinConstantTypeGenerators{ - {BuiltinConstant::Unit, unit}, - {BuiltinConstant::Pair, [](TVar a, TVar b) { return a >> (b >> (a,b)); }}, - {BuiltinConstant::Word, word}, - {BuiltinConstant::Assign, [=](TVar a) { return (a,a) >> unit; }}, // TODO: (a,a) >> a - {BuiltinConstant::Block, [](TVar a) { return a >> a; }}, - {BuiltinConstant::ChainStatements, [](TVar a, TVar b) { return (a,b) >> b; }}, - {BuiltinConstant::Statement, [=](TVar a) { return a >> unit; }}, - {BuiltinConstant::Return, [&]() { - solAssert(currentReturn); - return *currentReturn >> unit; - }}, - {BuiltinConstant::Fun, [&](TVar a, TVar b) { - return (a,b) >> (a >> b); - }}, - }; + list> toCheck; + forEachTopLevelTerm(_ast, [&](Term& _root) { + list> staged{{_root}}; + while (!staged.empty()) + { + Term& term = staged.front().get(); + staged.pop_front(); + toCheck.push_back(term); + forEachImmediateSubTerm(term, [&](Term& _subTerm) { staged.push_back(_subTerm); }); + } + }); auto unifyForTerm = [&](Type _a, Type _b, Term* _term) { for (auto failure: env.unify(_a, _b)) @@ -361,161 +384,65 @@ void TypeCheck::operator()(AST& _ast) }, failure); } }; - auto checkTerm = [&](Term& _root) { - std::list> heap; - heap.emplace_back(_root); - auto checked = [](Term const& _term) { - return !holds_alternative(type(_term)); - }; - auto canCheck = [&](Term& _term) -> bool { - bool hasUnchecked = false; - auto stage = [&](Term& _term) { - if (!checked(_term)) - { - heap.push_back(_term); - hasUnchecked = true; - } - }; - std::visit(util::GenericVisitor{ - [&](Application const& _app) { - stage(*_app.expression); - stage(*_app.argument); - }, - [&](Lambda const& _lambda) - { - stage(*_lambda.argument); - stage(*_lambda.value); - }, - [&](InlineAssembly const&) - { - // TODO - }, - [&](VariableDeclaration const& _varDecl) - { - stage(*_varDecl.namePattern); - if (_varDecl.initialValue) - stage(*_varDecl.initialValue); - }, - [&](Reference const&) - { - }, - [&](Constant const&) {} - }, _term); - if (hasUnchecked) - { - stage(_term); - return false; - } - return true; - }; - std::map declarationTypes; - while (!heap.empty()) - { - Term& current = heap.front(); - heap.pop_front(); - if (checked(current)) - continue; - if (!canCheck(current)) - continue; - auto unify = [&](Type _a, Type _b) { unifyForTerm(_a, _b, ¤t); }; - - std::visit(util::GenericVisitor{ - [&](Application const& _app) { - if (auto* constant = get_if(_app.expression.get())) - if (auto* builtin = get_if(&constant->name)) - if (*builtin == BuiltinConstant::Constrain) - if (auto args = destPair(*_app.argument)) - { - Type result = type(args->first); - unify(result, type(args->second)); - setType(current, result); - return; - } - Type resultType = typeSystem.freshTypeVariable({}); - unify(helper.functionType(type(*_app.argument), resultType), type(*_app.expression)); - setType(current, resultType); - }, - [&](Lambda const& _lambda) - { - setType(current, helper.functionType(type(*_lambda.argument), type(*_lambda.value))); - }, - [&](InlineAssembly const& _inlineAssembly) - { - // TODO - (void)_inlineAssembly; - setType(current, typeSystem.type(PrimitiveType::Unit, {})); - }, - [&](VariableDeclaration const& _varDecl) - { - Type name = type(*_varDecl.namePattern); - if (_varDecl.initialValue) - unify(name, type(*_varDecl.initialValue)); - setType(current, name); - }, - [&](Reference const& _reference) - { - Type result = typeSystem.freshTypeVariable({}); - if ( - auto [it, newlyInserted] = declarationTypes.emplace(_reference.index, result); - !newlyInserted - ) - unify(result, it->second); - setType(current, result); - }, - [&](Constant const& _constant) - { - bool assigned = std::visit(util::GenericVisitor{ - [&](std::string const&) { return false; }, - [&](BuiltinConstant const& _constant) { - if (auto* generator = util::valueOrNullptr(builtinConstantTypeGenerators, _constant)) + std::map declarationTypes; + for(auto term: toCheck | ranges::view::reverse) + { + auto unify = [&](Type _a, Type _b) { unifyForTerm(_a, _b, &term.get()); }; + std::visit(util::GenericVisitor{ + [&](Application const& _app) { + /*if (auto* constant = get_if(_app.expression.get())) + if (auto* builtin = get_if(&constant->name)) + if (*builtin == BuiltinConstant::Constrain) + if (auto args = destPair(*_app.argument)) { - setType(current, (*generator)(env)); - return true; - } - return false; - } - }, _constant.name); - if (!assigned) - setType(current, typeSystem.freshTypeVariable({})); - } - }, current); - solAssert(checked(current)); - if (auto declaration = termBase(current).declaration) + Type result = type(args->first); + unify(result, type(args->second)); + setType(term, result); + return; + }*/ + Type resultType = typeSystem.freshTypeVariable({}); + unify(helper.functionType(type(*_app.argument), resultType), type(*_app.expression)); + setType(term, resultType); + }, + [&](Lambda const& _lambda) { + setType(term, helper.functionType(type(*_lambda.argument), type(*_lambda.value))); + }, + [&](InlineAssembly const& _inlineAssembly) + { + // TODO + (void)_inlineAssembly; + setType(term, typeSystem.type(PrimitiveType::Unit, {})); + }, + [&](Reference const& _reference) + { + Type result = typeSystem.freshTypeVariable({}); if ( - auto [it, newlyInserted] = declarationTypes.emplace(*declaration, type(current)); + auto [it, newlyInserted] = declarationTypes.emplace(_reference.index, result); !newlyInserted ) - unify(type(current), it->second); + unify(result, it->second); + setType(term, result); + }, + [&](Constant const& _constant) + { + bool assigned = std::visit(util::GenericVisitor{ + [&](std::string const&) { return false; }, + [&](BuiltinConstant const& _constant) { + if (auto generator = builtinConstantInfo(_constant).builtinType) + { + setType(term, (*generator).realize(env, unify)); + return true; + } + return false; + } + }, _constant.name); + if (!assigned) + setType(term, typeSystem.freshTypeVariable({})); } - } - }; - for(auto& info: _ast.typeDefinitions | ranges::view::values) - { - if (info.arguments) - checkTerm(*info.arguments); - if (info.value) - checkTerm(*info.value); - checkTerm(*info.declaration); - } - for(auto& info: _ast.contracts | ranges::view::values) - for(auto& function: info.functions | ranges::view::values) - { - checkTerm(*function.returnType); - ScopedSaveAndRestore returnType{currentReturn, std::make_unique(TVar{env,type(*function.returnType)})}; - checkTerm(*function.function); - checkTerm(*function.arguments); - // TODO: unify stuff? - - } - for(auto&& info: _ast.functions | ranges::view::values) - { - checkTerm(*info.returnType); - ScopedSaveAndRestore returnType{currentReturn, std::make_unique(TVar{env,type(*info.returnType)})}; - checkTerm(*info.function); - checkTerm(*info.arguments); - // TODO: unify stuff + }, term.get()); + solAssert(!holds_alternative(type(term))); } std::cout << astPrinter(_ast, &env) << std::endl; diff --git a/libsolidity/experimental/ast/AST.h b/libsolidity/experimental/ast/AST.h index 510019c46..368503c04 100644 --- a/libsolidity/experimental/ast/AST.h +++ b/libsolidity/experimental/ast/AST.h @@ -34,17 +34,16 @@ struct TermBase langutil::SourceLocation location; std::optional legacyId; Type type; - std::optional declaration; }; struct Application; struct Lambda; struct InlineAssembly; -struct VariableDeclaration; struct Reference: TermBase { size_t index = std::numeric_limits::max(); + std::string name; }; enum class BuiltinConstant @@ -54,9 +53,19 @@ enum class BuiltinConstant Pair, Fun, Constrain, - Return, + NamedTerm, + TypeDeclaration, + TypeDefinition, + TypeClassDefinition, + TypeClassInstantiation, + FunctionDeclaration, + FunctionDefinition, + ContractDefinition, + VariableDeclaration, + VariableDefinition, Block, - Statement, + ReturnStatement, + RegularStatement, ChainStatements, Assign, MemberAccess, @@ -75,7 +84,7 @@ struct Constant: TermBase std::variant name; }; -using Term = std::variant; +using Term = std::variant; struct InlineAssembly: TermBase { @@ -83,12 +92,6 @@ struct InlineAssembly: TermBase std::map> references; }; -struct VariableDeclaration: TermBase -{ - std::unique_ptr namePattern; - std::unique_ptr initialValue; -}; - struct Application: TermBase { std::unique_ptr expression; @@ -145,41 +148,11 @@ langutil::SourceLocation locationOf(T const& _t) struct AST { - struct FunctionInfo { - std::unique_ptr function; - std::unique_ptr arguments; - std::unique_ptr returnType; - }; - std::map> functions; - struct ContractInfo { - std::map functions; - }; - std::map> contracts; - struct TypeInformation { - std::unique_ptr declaration; - std::unique_ptr arguments; - std::unique_ptr value; - }; - std::map> typeDefinitions; - struct TypeClassInformation { - std::unique_ptr declaration; - std::unique_ptr typeVariable; - std::map functions; - }; - struct TypeClassInstantiationInformation { - std::unique_ptr typeConstructor; - std::unique_ptr argumentSorts; - std::unique_ptr typeClass; - std::map functions; - }; - std::map> typeClasses; - std::map> typeClassInstantiations; - struct DeclarationInfo - { - Term const* target = nullptr; - std::string name; - }; - std::vector declarations; + std::map, ASTCompareByID> typeDefinitions; + std::map, ASTCompareByID> typeClasses; + std::map, ASTCompareByID> typeClassInstantiations; + std::map, ASTCompareByID> functions; + std::map, ASTCompareByID> contracts; }; } diff --git a/libsolidity/experimental/ast/TypeSystemHelper.cpp b/libsolidity/experimental/ast/TypeSystemHelper.cpp index b8d72b85b..370ab43e5 100644 --- a/libsolidity/experimental/ast/TypeSystemHelper.cpp +++ b/libsolidity/experimental/ast/TypeSystemHelper.cpp @@ -37,45 +37,6 @@ using namespace solidity::langutil; using namespace solidity::frontend; using namespace solidity::frontend::experimental; -/*std::optional experimental::typeConstructorFromTypeName(Analysis const& _analysis, TypeName const& _typeName) -{ - if (auto const* elementaryTypeName = dynamic_cast(&_typeName)) - { - if (auto constructor = typeConstructorFromToken(_analysis, elementaryTypeName->typeName().token())) - return *constructor; - } - else if (auto const* userDefinedType = dynamic_cast(&_typeName)) - { - if (auto const* referencedDeclaration = userDefinedType->pathNode().annotation().referencedDeclaration) - return _analysis.annotation(*referencedDeclaration).typeConstructor; - } - return nullopt; -}*/ -/* -std::optional experimental::typeConstructorFromToken(Analysis const& _analysis, langutil::Token _token) -{ - TypeSystem const& typeSystem = _analysis.typeSystem(); - switch(_token) - { - case Token::Void: - return typeSystem.builtinConstructor(BuiltinType::Void); - case Token::Fun: - return typeSystem.builtinConstructor(BuiltinType::Function); - case Token::Unit: - return typeSystem.builtinConstructor(BuiltinType::Unit); - case Token::Pair: - return typeSystem.builtinConstructor(BuiltinType::Pair); - case Token::Word: - return typeSystem.builtinConstructor(BuiltinType::Word); - case Token::Integer: - return typeSystem.builtinConstructor(BuiltinType::Integer); - case Token::Bool: - return typeSystem.builtinConstructor(BuiltinType::Bool); - default: - return nullopt; - } -}*/ - std::optional experimental::builtinClassFromToken(langutil::Token _token) { switch (_token) @@ -100,22 +61,7 @@ std::optional experimental::builtinClassFromToken(langutil::Token return nullopt; } } -/* -std::optional experimental::typeClassFromTypeClassName(TypeClassName const& _typeClass) -{ - return std::visit(util::GenericVisitor{ - [&](ASTPointer _path) -> optional { - auto classDefinition = dynamic_cast(_path->annotation().referencedDeclaration); - if (!classDefinition) - return nullopt; - return TypeClass{classDefinition}; - }, - [&](Token _token) -> optional { - return typeClassFromToken(_token); - } - }, _typeClass.name()); -} -*/ + experimental::Type TypeSystemHelpers::tupleType(vector _elements) const { if (_elements.empty()) diff --git a/libsolidity/experimental/ast/TypeSystemHelper.h b/libsolidity/experimental/ast/TypeSystemHelper.h index 5149d34bd..27de9e820 100644 --- a/libsolidity/experimental/ast/TypeSystemHelper.h +++ b/libsolidity/experimental/ast/TypeSystemHelper.h @@ -18,16 +18,13 @@ #pragma once #include -#include #include namespace solidity::frontend::experimental { class Analysis; enum class BuiltinClass; -//std::optional typeConstructorFromTypeName(Analysis const& _analysis, TypeName const& _typeName); -//std::optional typeConstructorFromToken(Analysis const& _analysis, langutil::Token _token); -//std::optional typeClassFromTypeClassName(TypeClassName const& _typeClass); + std::optional builtinClassFromToken(langutil::Token _token); struct TypeSystemHelpers diff --git a/test/libsolidity/semanticTests/experimental/stub.sol b/test/libsolidity/semanticTests/experimental/stub.sol index a4c0fe3ea..0ab3a71e8 100644 --- a/test/libsolidity/semanticTests/experimental/stub.sol +++ b/test/libsolidity/semanticTests/experimental/stub.sol @@ -1,6 +1,8 @@ pragma experimental solidity; type uint256 = word; +/* +type double(a) = (a,a); instantiation uint256: + { function add(x, y) -> uint256 { @@ -51,18 +53,22 @@ instantiation word: == { function f(x:uint256->uint256,y:uint256) -> uint256 { - return x(y); + x(y); } - -function g(x:uint256) -> uint256 +*/ +function g(x) -> word { return x; } contract C { fallback() external { + let z : uint256; let x : word; - assembly { + let y; + y = (x:word); + x = g(x); + /*assembly { x := 0x10 } let w = uint256.abs(x); @@ -75,7 +81,7 @@ contract C { assembly { mstore(0, y) return(0, 32) - } + }*/ } } // ====