From 362b910e4257c3cc52a1315c53ef01b02b798913 Mon Sep 17 00:00:00 2001 From: Maxim Logaev Date: Mon, 12 Feb 2024 11:32:13 +0300 Subject: [PATCH] Fixed bug #I8Y4D1 Signed-off-by: Maxim Logaev --- ets2panda/parser/ETSparser.cpp | 46 +- ets2panda/parser/ETSparser.h | 3 +- ...erface_noreturn_type_function-expected.txt | 864 ++++++++++++++++++ .../ets/interface_noreturn_type_function.ets | 27 + ...ce_abstract_noreturn_function-expected.txt | 1 + .../interface_abstract_noreturn_function.ets | 18 + 6 files changed, 952 insertions(+), 7 deletions(-) create mode 100644 ets2panda/test/compiler/ets/interface_noreturn_type_function-expected.txt create mode 100644 ets2panda/test/compiler/ets/interface_noreturn_type_function.ets create mode 100644 ets2panda/test/parser/ets/interface_abstract_noreturn_function-expected.txt create mode 100644 ets2panda/test/parser/ets/interface_abstract_noreturn_function.ets diff --git a/ets2panda/parser/ETSparser.cpp b/ets2panda/parser/ETSparser.cpp index 7717532ded..63ebf33266 100644 --- a/ets2panda/parser/ETSparser.cpp +++ b/ets2panda/parser/ETSparser.cpp @@ -1840,6 +1840,34 @@ ir::ClassProperty *ETSParser::ParseInterfaceField() return field; } +lexer::SourcePosition ETSParser::ParseEndLocInterfaceMethod(lexer::LexerPosition startPos, ir::ScriptFunction *func, + ir::MethodDefinitionKind methodKind) +{ + if (func->HasBody()) { + return func->Body()->End(); + } + + if (func->ReturnTypeAnnotation() == nullptr) { + auto backupPos = Lexer()->Save(); + Lexer()->Rewind(startPos); + + while (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) { + Lexer()->NextToken(); + } + + auto endLoc = Lexer()->GetToken().End(); + Lexer()->Rewind(backupPos); + + if (methodKind != ir::MethodDefinitionKind::SET) { + ThrowSyntaxError("Interface method must have a return type", endLoc); + } + + return endLoc; + } + + return func->ReturnTypeAnnotation()->End(); +} + ir::MethodDefinition *ETSParser::ParseInterfaceMethod(ir::ModifierFlags flags, ir::MethodDefinitionKind methodKind) { ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT); @@ -1850,6 +1878,7 @@ ir::MethodDefinition *ETSParser::ParseInterfaceMethod(ir::ModifierFlags flags, i FunctionContext functionContext(this, ParserStatus::FUNCTION); lexer::SourcePosition startLoc = Lexer()->GetToken().Start(); + lexer::LexerPosition startPos = Lexer()->Save(); auto [signature, throwMarker] = ParseFunctionSignature(ParserStatus::NEED_RETURN_TYPE); @@ -1871,6 +1900,11 @@ ir::MethodDefinition *ETSParser::ParseInterfaceMethod(ir::ModifierFlags flags, i functionContext.AddFlag(throwMarker); + if ((GetContext().Status() & ParserStatus::FUNCTION_HAS_RETURN_STATEMENT) != 0) { + functionContext.AddFlag(ir::ScriptFunctionFlags::HAS_RETURN); + GetContext().Status() ^= ParserStatus::FUNCTION_HAS_RETURN_STATEMENT; + } + auto *func = AllocNode( std::move(signature), body, ir::ScriptFunction::ScriptFunctionData {functionContext.Flags(), flags, true, GetContext().GetLanguage()}); @@ -1878,9 +1912,9 @@ ir::MethodDefinition *ETSParser::ParseInterfaceMethod(ir::ModifierFlags flags, i if ((flags & ir::ModifierFlags::STATIC) == 0 && body == nullptr) { func->AddModifier(ir::ModifierFlags::ABSTRACT); } - func->SetRange({startLoc, body != nullptr ? body->End() - : func->ReturnTypeAnnotation() != nullptr ? func->ReturnTypeAnnotation()->End() - : (*func->Params().end())->End()}); + + auto endLoc = ParseEndLocInterfaceMethod(startPos, func, methodKind); + func->SetRange({startLoc, endLoc}); auto *funcExpr = AllocNode(func); funcExpr->SetRange(func->Range()); @@ -2362,9 +2396,9 @@ ir::TypeNode *ETSParser::ParseETSTupleType(TypeAnnotationParsingOptions *const o spreadTypePresent = true; Lexer()->NextToken(); // eat '...' } else if (spreadTypePresent) { - // This can't be implemented to any index, with type consistency. If a spread type is in the middle of the - // tuple, then bounds check can't be made for element access, so the type of elements after the spread can't - // be determined in compile time. + // This can't be implemented to any index, with type consistency. If a spread type is in the middle of + // the tuple, then bounds check can't be made for element access, so the type of elements after the + // spread can't be determined in compile time. ThrowSyntaxError("Spread type must be at the last index in the tuple type"); } diff --git a/ets2panda/parser/ETSparser.h b/ets2panda/parser/ETSparser.h index fe94640be0..3b9c9c5d50 100644 --- a/ets2panda/parser/ETSparser.h +++ b/ets2panda/parser/ETSparser.h @@ -172,7 +172,8 @@ private: ir::TypeNode *ParseFunctionReturnType(ParserStatus status) override; ir::ScriptFunctionFlags ParseFunctionThrowMarker(bool isRethrowsAllowed) override; ir::Expression *CreateParameterThis(util::StringView className) override; - + lexer::SourcePosition ParseEndLocInterfaceMethod(lexer::LexerPosition startPos, ir::ScriptFunction *func, + ir::MethodDefinitionKind methodKind); // NOLINTNEXTLINE(google-default-arguments) void ParseClassFieldDefinition(ir::Identifier *fieldName, ir::ModifierFlags modifiers, ArenaVector *declarations, ir::ScriptFunction *initFunction = nullptr, diff --git a/ets2panda/test/compiler/ets/interface_noreturn_type_function-expected.txt b/ets2panda/test/compiler/ets/interface_noreturn_type_function-expected.txt new file mode 100644 index 0000000000..2ce5584ec6 --- /dev/null +++ b/ets2panda/test/compiler/ets/interface_noreturn_type_function-expected.txt @@ -0,0 +1,864 @@ +{ + "type": "Program", + "statements": [ + { + "type": "TSInterfaceDeclaration", + "body": { + "type": "TSInterfaceBody", + "body": [ + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "foo", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 5 + }, + "end": { + "line": 17, + "column": 8 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": false, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "foo", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 5 + }, + "end": { + "line": 17, + "column": 8 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "declare": true, + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "ReturnStatement", + "argument": { + "type": "NumberLiteral", + "value": 99, + "loc": { + "start": { + "line": 18, + "column": 16 + }, + "end": { + "line": 18, + "column": 18 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 9 + }, + "end": { + "line": 18, + "column": 18 + } + } + } + ], + "loc": { + "start": { + "line": 17, + "column": 11 + }, + "end": { + "line": 19, + "column": 6 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 8 + }, + "end": { + "line": 19, + "column": 6 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 8 + }, + "end": { + "line": 19, + "column": 6 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 5 + }, + "end": { + "line": 19, + "column": 6 + } + } + } + ], + "loc": { + "start": { + "line": 16, + "column": 13 + }, + "end": { + "line": 20, + "column": 2 + } + } + }, + "id": { + "type": "Identifier", + "name": "I", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 11 + }, + "end": { + "line": 16, + "column": 12 + } + } + }, + "extends": [], + "loc": { + "start": { + "line": 16, + "column": 1 + }, + "end": { + "line": 22, + "column": 6 + } + } + }, + { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "C", + "decorators": [], + "loc": { + "start": { + "line": 22, + "column": 7 + }, + "end": { + "line": 22, + "column": 8 + } + } + }, + "superClass": null, + "implements": [ + { + "type": "TSClassImplements", + "expression": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "I", + "decorators": [], + "loc": { + "start": { + "line": 22, + "column": 20 + }, + "end": { + "line": 22, + "column": 21 + } + } + }, + "loc": { + "start": { + "line": 22, + "column": 20 + }, + "end": { + "line": 22, + "column": 23 + } + } + }, + "loc": { + "start": { + "line": 22, + "column": 20 + }, + "end": { + "line": 22, + "column": 23 + } + } + }, + "loc": { + "start": { + "line": 22, + "column": 20 + }, + "end": { + "line": 22, + "column": 23 + } + } + } + ], + "body": [ + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "constructor", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "kind": "constructor", + "static": false, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "constructor", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "statements": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 22, + "column": 24 + }, + "end": { + "line": 22, + "column": 24 + } + } + } + ], + "loc": { + "start": { + "line": 22, + "column": 22 + }, + "end": { + "line": 22, + "column": 24 + } + } + }, + "loc": { + "start": { + "line": 22, + "column": 1 + }, + "end": { + "line": 22, + "column": 24 + } + } + }, + { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "ETSGLOBAL", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "superClass": null, + "implements": [], + "body": [ + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "_$init$_", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": true, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "_$init$_", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "body": { + "type": "BlockStatement", + "statements": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "main", + "decorators": [], + "loc": { + "start": { + "line": 24, + "column": 10 + }, + "end": { + "line": 24, + "column": 14 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": true, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "main", + "decorators": [], + "loc": { + "start": { + "line": 24, + "column": 10 + }, + "end": { + "line": 24, + "column": 14 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [], + "returnType": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "void", + "decorators": [], + "loc": { + "start": { + "line": 24, + "column": 18 + }, + "end": { + "line": 24, + "column": 22 + } + } + }, + "loc": { + "start": { + "line": 24, + "column": 18 + }, + "end": { + "line": 24, + "column": 24 + } + } + }, + "loc": { + "start": { + "line": 24, + "column": 18 + }, + "end": { + "line": 24, + "column": 24 + } + } + }, + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "i", + "decorators": [], + "loc": { + "start": { + "line": 25, + "column": 9 + }, + "end": { + "line": 25, + "column": 10 + } + } + }, + "init": { + "type": "ETSNewClassInstanceExpression", + "typeReference": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "C", + "decorators": [], + "loc": { + "start": { + "line": 25, + "column": 17 + }, + "end": { + "line": 25, + "column": 18 + } + } + }, + "loc": { + "start": { + "line": 25, + "column": 17 + }, + "end": { + "line": 25, + "column": 19 + } + } + }, + "loc": { + "start": { + "line": 25, + "column": 17 + }, + "end": { + "line": 25, + "column": 19 + } + } + }, + "arguments": [], + "loc": { + "start": { + "line": 25, + "column": 13 + }, + "end": { + "line": 26, + "column": 8 + } + } + }, + "loc": { + "start": { + "line": 25, + "column": 9 + }, + "end": { + "line": 26, + "column": 8 + } + } + } + ], + "kind": "let", + "loc": { + "start": { + "line": 25, + "column": 5 + }, + "end": { + "line": 26, + "column": 8 + } + } + }, + { + "type": "VariableDeclaration", + "declarations": [ + { + "type": "VariableDeclarator", + "id": { + "type": "Identifier", + "name": "n", + "typeAnnotation": { + "type": "ETSPrimitiveType", + "loc": { + "start": { + "line": 26, + "column": 12 + }, + "end": { + "line": 26, + "column": 15 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 26, + "column": 9 + }, + "end": { + "line": 26, + "column": 10 + } + } + }, + "init": { + "type": "CallExpression", + "callee": { + "type": "MemberExpression", + "object": { + "type": "Identifier", + "name": "i", + "decorators": [], + "loc": { + "start": { + "line": 26, + "column": 18 + }, + "end": { + "line": 26, + "column": 19 + } + } + }, + "property": { + "type": "Identifier", + "name": "foo", + "decorators": [], + "loc": { + "start": { + "line": 26, + "column": 20 + }, + "end": { + "line": 26, + "column": 23 + } + } + }, + "computed": false, + "optional": false, + "loc": { + "start": { + "line": 26, + "column": 18 + }, + "end": { + "line": 26, + "column": 23 + } + } + }, + "arguments": [], + "optional": false, + "loc": { + "start": { + "line": 26, + "column": 18 + }, + "end": { + "line": 26, + "column": 25 + } + } + }, + "loc": { + "start": { + "line": 26, + "column": 9 + }, + "end": { + "line": 26, + "column": 25 + } + } + } + ], + "kind": "let", + "loc": { + "start": { + "line": 26, + "column": 5 + }, + "end": { + "line": 26, + "column": 25 + } + } + } + ], + "loc": { + "start": { + "line": 24, + "column": 23 + }, + "end": { + "line": 27, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 24, + "column": 14 + }, + "end": { + "line": 27, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 24, + "column": 14 + }, + "end": { + "line": 27, + "column": 2 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 24, + "column": 1 + }, + "end": { + "line": 27, + "column": 2 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 28, + "column": 1 + } + } +} diff --git a/ets2panda/test/compiler/ets/interface_noreturn_type_function.ets b/ets2panda/test/compiler/ets/interface_noreturn_type_function.ets new file mode 100644 index 0000000000..58e64b10b2 --- /dev/null +++ b/ets2panda/test/compiler/ets/interface_noreturn_type_function.ets @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +interface I { + foo() { + return 99 + } +} + +class C implements I {} + +function main(): void { + let i = new C() + let n: int = i.foo() +} diff --git a/ets2panda/test/parser/ets/interface_abstract_noreturn_function-expected.txt b/ets2panda/test/parser/ets/interface_abstract_noreturn_function-expected.txt new file mode 100644 index 0000000000..385bb8e930 --- /dev/null +++ b/ets2panda/test/parser/ets/interface_abstract_noreturn_function-expected.txt @@ -0,0 +1 @@ +SyntaxError: Interface method must have a return type [interface_abstract_noreturn_function.ets:17:10] diff --git a/ets2panda/test/parser/ets/interface_abstract_noreturn_function.ets b/ets2panda/test/parser/ets/interface_abstract_noreturn_function.ets new file mode 100644 index 0000000000..78ed09cf8d --- /dev/null +++ b/ets2panda/test/parser/ets/interface_abstract_noreturn_function.ets @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +interface I { + foo() +} -- Gitee