/* This file is part of TON Blockchain source code. TON Blockchain is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. TON Blockchain is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with TON Blockchain. If not, see . */ #include "tolk.h" #include "ast.h" #include "ast-visitor.h" #include "platform-utils.h" /* * This pipe checks for impure operations inside pure functions. * It happens after type inferring (after methods binding) since it operates fun_ref of calls. */ namespace tolk { GNU_ATTRIBUTE_NORETURN GNU_ATTRIBUTE_COLD static void fire_error_impure_operation_inside_pure_function(AnyV v) { v->error("an impure operation in a pure function"); } class CheckImpureOperationsInPureFunctionVisitor final : public ASTVisitorFunctionBody { static void fire_if_global_var(AnyExprV v) { if (auto v_ident = v->try_as()) { if (v_ident->sym->try_as()) { fire_error_impure_operation_inside_pure_function(v); } } } void visit(V v) override { fire_if_global_var(v->get_lhs()); parent::visit(v); } void visit(V v) override { fire_if_global_var(v->get_lhs()); parent::visit(v); } void visit(V v) override { // v is `globalF(args)` / `globalF(args)` / `obj.method(args)` / `local_var(args)` / `getF()(args)` if (!v->fun_maybe) { // `local_var(args)` is always impure, no considerations about what's there at runtime fire_error_impure_operation_inside_pure_function(v); } if (!v->fun_maybe->is_marked_as_pure()) { fire_error_impure_operation_inside_pure_function(v); } parent::visit(v); } void visit(V v) override { if (v->passed_as_mutate) { fire_if_global_var(v->get_expr()); } parent::visit(v); } void visit(V v) override { fire_error_impure_operation_inside_pure_function(v); } void visit(V v) override { fire_error_impure_operation_inside_pure_function(v); } public: bool should_visit_function(const FunctionData* fun_ref) override { return fun_ref->is_code_function() && !fun_ref->is_generic_function() && fun_ref->is_marked_as_pure(); } }; void pipeline_check_pure_impure_operations() { visit_ast_of_all_functions(); } } // namespace tolk