diff --git a/ets2panda/ir/expressions/memberExpression.cpp b/ets2panda/ir/expressions/memberExpression.cpp index 4fde4e957d99a2fd32e7ad385d5f501982c68d51..e94ac965c41438b348288b3164b2c33c26c85377 100644 --- a/ets2panda/ir/expressions/memberExpression.cpp +++ b/ets2panda/ir/expressions/memberExpression.cpp @@ -409,7 +409,7 @@ checker::Type *MemberExpression::CheckIndexAccessMethod(checker::ETSChecker *che isSetter ? compiler::Signatures::SET_INDEX_METHOD : compiler::Signatures::GET_INDEX_METHOD; auto *const method = objType_->GetProperty(methodName, searchFlag); if (method == nullptr || !method->HasFlag(varbinder::VariableFlags::METHOD)) { - checker->LogError(diagnostic::ERROR_ARKTS_NO_PROPERTIES_BY_INDEX, {}, Start()); + checker->LogError(diagnostic::NO_INDEX_ACCESS_METHOD, {}, Start()); return nullptr; } diff --git a/ets2panda/parser/ETSparser.cpp b/ets2panda/parser/ETSparser.cpp index fff197fa753476379ecbecae8049ce8b4fe94b6d..c64b3a145144a019c991073e6fc38919e9740546 100644 --- a/ets2panda/parser/ETSparser.cpp +++ b/ets2panda/parser/ETSparser.cpp @@ -701,6 +701,9 @@ ir::AstNode *ETSParser::ParseInnerRest(const ArenaVector &propert Lexer()->NextToken(); return AllocBrokenStatement(rangeToken); } + if (memberName->IsErrorPlaceHolder()) { + return AllocBrokenStatement(startLoc); + } if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS || Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN) { diff --git a/ets2panda/parser/ETSparser.h b/ets2panda/parser/ETSparser.h index 250f09b7cee0f575415962a1c3e26f435d725ce3..a30ab0a74c72a1f5f5670c12f5c63acf5b97355f 100644 --- a/ets2panda/parser/ETSparser.h +++ b/ets2panda/parser/ETSparser.h @@ -228,6 +228,7 @@ private: ir::ModifierFlags ParseClassModifiers(); ir::ModifierFlags ParseInterfaceMethodModifiers(); ir::AstNode *ParseInterfaceField(); + void ParseIndexedSignature(); ir::TypeNode *ParseInterfaceTypeAnnotation(ir::Identifier *name); void ParseInterfaceModifiers(ir::ModifierFlags &fieldModifiers, bool &optionalField); ir::MethodDefinition *ParseInterfaceMethod(ir::ModifierFlags flags, ir::MethodDefinitionKind methodKind); diff --git a/ets2panda/parser/ETSparserClasses.cpp b/ets2panda/parser/ETSparserClasses.cpp index 1ca0f3e10c6e4dbce91bc1408838fa283f54bce5..45c9fe6ba89b834f7a5bc2318808eaf841e66d05 100644 --- a/ets2panda/parser/ETSparserClasses.cpp +++ b/ets2panda/parser/ETSparserClasses.cpp @@ -988,11 +988,30 @@ void ETSParser::ParseInterfaceModifiers(ir::ModifierFlags &fieldModifiers, bool } } +void ETSParser::ParseIndexedSignature() +{ + ES2PANDA_ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET); + Lexer()->NextToken(); + if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) { + return; + } + auto *name = AllocNode(Lexer()->GetToken().Ident(), Allocator()); + Lexer()->NextToken(); + ParseInterfaceTypeAnnotation(name); + + if (!Lexer()->TryEatTokenType(lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET)) { + return; + } + Lexer()->NextToken(); + ParseInterfaceTypeAnnotation(name); +} + ir::AstNode *ETSParser::ParseInterfaceField() { ES2PANDA_ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT || Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET || Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS); + ir::ModifierFlags fieldModifiers = ir::ModifierFlags::PUBLIC; auto startLoc = Lexer()->GetToken().Start(); @@ -1010,6 +1029,11 @@ ir::AstNode *ETSParser::ParseInterfaceField() return property; } } + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET) { + ParseIndexedSignature(); + LogError(diagnostic::ERROR_ARKTS_NO_PROPERTIES_BY_INDEX, {}, startLoc); + return AllocBrokenExpression(Lexer()->GetToken().Start()); + } name->SetRange(Lexer()->GetToken().Loc()); Lexer()->NextToken(); diff --git a/ets2panda/parser/parserImpl.cpp b/ets2panda/parser/parserImpl.cpp index 4f66296e627555da3127cf70f15b71aedd5f342d..f3c6cb44f7cb2f5ae55aec805f32e5e210e97565 100644 --- a/ets2panda/parser/parserImpl.cpp +++ b/ets2panda/parser/parserImpl.cpp @@ -1231,6 +1231,51 @@ util::StringView ParserImpl::ParseSymbolIteratorIdentifier() const noexcept return util::StringView {compiler::Signatures::ITERATOR_METHOD}; } +void ParserImpl::EatTypeAnnotation() +{ + lexer_->NextToken(); // eat ':' or '|' + if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) { + LogUnexpectedToken(lexer_->GetToken()); + auto pos = lexer_->Save(); + lexer_->NextToken(); + while (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) { + // just skip usls tokens, we have an identifier after + lexer_->Rewind(pos); + lexer_->NextToken(); + pos = lexer_->Save(); + } + if (lexer_->GetToken().Type() == lexer::TokenType::LITERAL_IDENT) { + // if next token is not an ident, so current token should be an identifier + // and we set it as literal ident + lexer_->GetToken().SetTokenType(lexer::TokenType::LITERAL_IDENT); + lexer_->GetToken().SetTokenStr(ERROR_LITERAL); + } + } + lexer_->NextToken(); // eat type + if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_BITWISE_OR) { + EatTypeAnnotation(); + } +} + +void ParserImpl::ParseIndexSignature() +{ + if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) { + return; + } + lexer_->NextToken(); // eat param + + if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COLON) { + return; + } + + EatTypeAnnotation(); + + if (!lexer_->TryEatTokenType(lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET)) { + return; + } + EatTypeAnnotation(); +} + ir::Identifier *ParserImpl::ExpectIdentifier([[maybe_unused]] bool isReference, bool isUserDefinedType, TypeAnnotationParsingOptions options) { @@ -1261,6 +1306,11 @@ ir::Identifier *ParserImpl::ExpectIdentifier([[maybe_unused]] bool isReference, } else if (tokenType == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET) { // Special case for processing of special '[Symbol.iterator]` identifier using in stdlib. tokenName = ParseSymbolIteratorIdentifier(); + if (tokenName.Empty()) { + LogError(diagnostic::ERROR_ARKTS_NO_PROPERTIES_BY_INDEX, {}); + ParseIndexSignature(); + return AllocBrokenExpression(Lexer()->GetToken().Start()); + } } if (tokenName.Empty()) { diff --git a/ets2panda/parser/parserImpl.h b/ets2panda/parser/parserImpl.h index c71ad06628d3c17756b408eace5e79973cf7e316..85fd5e6d6eaef1116d5e204536596463c8885f6e 100644 --- a/ets2panda/parser/parserImpl.h +++ b/ets2panda/parser/parserImpl.h @@ -241,6 +241,8 @@ protected: return false; } + void ParseIndexSignature(); + void EatTypeAnnotation(); util::StringView ParseSymbolIteratorIdentifier() const noexcept; ir::Identifier *ExpectIdentifier(bool isReference = false, bool isUserDefinedType = false, TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::REPORT_ERROR); diff --git a/ets2panda/test/ast/compiler/ets/dynamic-field-declaration.ets b/ets2panda/test/ast/compiler/ets/dynamic-field-declaration.ets index 1213452ed79f3ff389fc5fb8a009094cf82e2c2c..ad2a27ac6c01065f51dfdc606850ad286339e0cc 100644 --- a/ets2panda/test/ast/compiler/ets/dynamic-field-declaration.ets +++ b/ets2panda/test/ast/compiler/ets/dynamic-field-declaration.ets @@ -20,4 +20,4 @@ class Point { let p: Point = {x: 1, y: 2} console.log(p["x"]) -/* @@? 21:13 Error TypeError: Indexed signatures are not allowed. Use arrays instead! */ \ No newline at end of file +/* @@? 21:13 Error TypeError: Object type doesn't have proper index access method. */ \ No newline at end of file diff --git a/ets2panda/test/ast/compiler/ets/type_error_processing/not_constructible_types.ets b/ets2panda/test/ast/compiler/ets/type_error_processing/not_constructible_types.ets index 4341a3928cf2a97ebbc724a072faf3bf72b0f1bc..46b03a8e16d9cb89c6776cf7ad86ced8efba602c 100644 --- a/ets2panda/test/ast/compiler/ets/type_error_processing/not_constructible_types.ets +++ b/ets2panda/test/ast/compiler/ets/type_error_processing/not_constructible_types.ets @@ -34,6 +34,6 @@ WeakSet [12] = new undefined() /* @@? 19:1 Error TypeError: Type 'never' is not constructible. */ /* @@? 20:1 Error TypeError: This expression is not constructible. */ /* @@? 23:1 Error TypeError: The union type is not constructible. */ -/* @@? 26:1 Error TypeError: Indexed signatures are not allowed. Use arrays instead! */ +/* @@? 26:1 Error TypeError: Object type doesn't have proper index access method. */ /* @@? 26:1 Error SyntaxError: Class cannot be used as object. */ /* @@? 26:16 Error TypeError: Type 'undefined' is not constructible. */ diff --git a/ets2panda/test/ast/parser/ets/FixedArray/unexpected_token_31.ets b/ets2panda/test/ast/parser/ets/FixedArray/unexpected_token_31.ets index b7a262d89ee3a7364d8edede6363f52f6d6d09d3..0c350b3e7faf4d3666382a9013edc5f2f677dc6f 100644 --- a/ets2panda/test/ast/parser/ets/FixedArray/unexpected_token_31.ets +++ b/ets2panda/test/ast/parser/ets/FixedArray/unexpected_token_31.ets @@ -27,5 +27,5 @@ function foo(...^number: FixedArray): int { /* @@? 16:48 Error SyntaxError: Unexpected token '{'. */ /* @@? 17:5 Error SyntaxError: return keyword should be used in function body. */ /* @@? 17:12 Error TypeError: Type name 'number' used in the wrong context */ -/* @@? 17:12 Error TypeError: Indexed signatures are not allowed. Use arrays instead! */ +/* @@? 17:12 Error TypeError: Object type doesn't have proper index access method. */ /* @@? 17:12 Error TypeError: All return statements in the function should be empty or have a value. */ diff --git a/ets2panda/test/ast/parser/ets/ambient_indexer_2.ets b/ets2panda/test/ast/parser/ets/ambient_indexer_2.ets index 7b5c41ba881ae1ae8068e8473f0fd3e9d8cc432a..d1c5273f0c247d8fe5770b7b5d1c50c9ca0d7117 100644 --- a/ets2panda/test/ast/parser/ets/ambient_indexer_2.ets +++ b/ets2panda/test/ast/parser/ets/ambient_indexer_2.ets @@ -21,10 +21,4 @@ function main() { let a : A = new A(); } -/* @@? 17:6 Error SyntaxError: Unexpected token 'index'. */ -/* @@? 17:12 Error SyntaxError: Unexpected token ':'. */ -/* @@? 17:14 Error SyntaxError: number is a predefined type, cannot be used as an identifier */ -/* @@? 17:20 Error SyntaxError: Field type annotation expected. */ -/* @@? 17:20 Error SyntaxError: Unexpected token ']'. */ -/* @@? 17:22 Error SyntaxError: Unexpected token ':'. */ -/* @@? 18:1 Error SyntaxError: Field type annotation expected. */ +/* @@? 17:6 Error TypeError: Indexed signatures are not allowed. Use arrays instead! */ \ No newline at end of file diff --git a/ets2panda/test/ast/parser/ets/index_not_support_such_type.ets b/ets2panda/test/ast/parser/ets/index_not_support_such_type.ets index 5a82a6fe4afc76a8afe4928744f3eef3fb0e8694..c713e3133391f444913437cfa2c9202fed1f4723 100644 --- a/ets2panda/test/ast/parser/ets/index_not_support_such_type.ets +++ b/ets2panda/test/ast/parser/ets/index_not_support_such_type.ets @@ -26,4 +26,4 @@ function main() { /* @@? 18:5 Error TypeError: Call to `log` is ambiguous as `2` versions of `log` are available: `log(i: String): void` and `log(i: Long): void` */ /* @@? 18:5 Error TypeError: Call to `log` is ambiguous as `2` versions of `log` are available: `log(i: String): void` and `log(i: Float): void` */ /* @@? 18:5 Error TypeError: Call to `log` is ambiguous as `2` versions of `log` are available: `log(i: String): void` and `log(i: Double): void` */ -/* @@@ label Error TypeError: Indexed signatures are not allowed. Use arrays instead! */ +/* @@@ label Error TypeError: Object type doesn't have proper index access method. */ diff --git a/ets2panda/test/ast/parser/ets/index_signature_error_1.ets b/ets2panda/test/ast/parser/ets/index_signature_error_1.ets new file mode 100644 index 0000000000000000000000000000000000000000..1b35a8935cd1cc2272f60787d375109beb7f69df --- /dev/null +++ b/ets2panda/test/ast/parser/ets/index_signature_error_1.ets @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025 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. + */ + +class StringArray { + [/* @@ label1 */index: number]: string +} +function getStringArray(): StringArray { + return /* @@ label2 */["a", "b", "c"] +} +let myArray: StringArray = getStringArray() +let secondItem = /* @@ label3 */myArray[1] + +/* @@@ label1 Error TypeError: Indexed signatures are not allowed. Use arrays instead! */ +/* @@@ label2 Error TypeError: Type 'Array' is not compatible with the enclosing method's return type 'StringArray' */ +/* @@@ label3 Error TypeError: Object type doesn't have proper index access method. */ diff --git a/ets2panda/test/ast/parser/ets/index_signature_error_2.ets b/ets2panda/test/ast/parser/ets/index_signature_error_2.ets new file mode 100644 index 0000000000000000000000000000000000000000..8eee907561bbfa0bce864432ac495e2390222ce0 --- /dev/null +++ b/ets2panda/test/ast/parser/ets/index_signature_error_2.ets @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025 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 StringArray { + /* @@ label1 */[index: number]: string +} +function getStringArray(): StringArray { + return /* @@ label2 */["a", "b", "c"] +} +let myArray: StringArray = getStringArray() +let secondItem = /* @@ label3 */myArray[1] + +/* @@@ label1 Error TypeError: Indexed signatures are not allowed. Use arrays instead! */ +/* @@@ label2 Error TypeError: Type 'Array' is not compatible with the enclosing method's return type 'StringArray' */ +/* @@@ label3 Error TypeError: Object type doesn't have proper index access method. */ diff --git a/ets2panda/test/ast/parser/ets/non-ambient_call_signature.ets b/ets2panda/test/ast/parser/ets/non-ambient_call_signature.ets index a2ab27116b790369f9c63c526746bc63492b5dc9..a61d358039ad25a947fa017048732fd46b03ca46 100644 --- a/ets2panda/test/ast/parser/ets/non-ambient_call_signature.ets +++ b/ets2panda/test/ast/parser/ets/non-ambient_call_signature.ets @@ -15,10 +15,9 @@ class A{ /* @@ label */(a:number/* @@ label1 */)/* @@ label2 */:number -/* @@ label3 */} +} /* @@@ label Error SyntaxError: Unexpected token '('. */ /* @@@ label1 Error SyntaxError: Unexpected token ')'. */ /* @@@ label2 Error SyntaxError: Unexpected token ':'. */ /* @@? 17:60 Error SyntaxError: number is a predefined type, cannot be used as an identifier */ -/* @@@ label3 Error SyntaxError: Field type annotation expected. */ diff --git a/ets2panda/test/ast/parser/ets/non_proper_index_method.ets b/ets2panda/test/ast/parser/ets/non_proper_index_method.ets index 33fbc6131a3245ef7c10f91df6d5b59fad4bba66..49fbed1717f6f4501e8770972ccbcfa9f7480e15 100644 --- a/ets2panda/test/ast/parser/ets/non_proper_index_method.ets +++ b/ets2panda/test/ast/parser/ets/non_proper_index_method.ets @@ -30,4 +30,4 @@ function main() { /* @@? 22:5 Error TypeError: Call to `log` is ambiguous as `2` versions of `log` are available: `log(i: String): void` and `log(i: Long): void` */ /* @@? 22:5 Error TypeError: Call to `log` is ambiguous as `2` versions of `log` are available: `log(i: String): void` and `log(i: Float): void` */ /* @@? 22:5 Error TypeError: Call to `log` is ambiguous as `2` versions of `log` are available: `log(i: String): void` and `log(i: Double): void` */ -/* @@@ label Error TypeError: Indexed signatures are not allowed. Use arrays instead! */ +/* @@@ label Error TypeError: Object type doesn't have proper index access method. */ diff --git a/ets2panda/test/ast/parser/ets/recursive_exported_structure.ets b/ets2panda/test/ast/parser/ets/recursive_exported_structure.ets index bf13d520c1531a313db6cefc4086721a198dc4b7..1b0fd7b47ce4bd40843b980add2a4c662a8e6ee5 100644 --- a/ets2panda/test/ast/parser/ets/recursive_exported_structure.ets +++ b/ets2panda/test/ast/parser/ets/recursive_exported_structure.ets @@ -98,13 +98,6 @@ export default _exported; /* @@? 62:12 Error SyntaxError: Label must be followed by a loop statement. */ /* @@? 62:12 Error TypeError: Type name 'IndexableType' used in the wrong context */ /* @@? 66:36 Error TypeError: Interfaces cannot extend classes, only other interfaces. */ -/* @@? 73:6 Error SyntaxError: Unexpected token 'key'. */ -/* @@? 73:9 Error SyntaxError: Unexpected token ':'. */ -/* @@? 73:17 Error SyntaxError: Field type annotation expected. */ -/* @@? 73:17 Error SyntaxError: Unexpected token ']'. */ -/* @@? 73:18 Error SyntaxError: Unexpected token ':'. */ -/* @@? 73:31 Error SyntaxError: Unexpected token '|'. */ -/* @@? 73:31 Error SyntaxError: Field type annotation expected. */ -/* @@? 73:46 Error SyntaxError: Field type annotation expected. */ +/* @@? 73:6 Error TypeError: Indexed signatures are not allowed. Use arrays instead! */ /* @@? 76:16 Error TypeError: Cannot cast type 'ExportedStructure' to 'Record Double|Record Double>>' */ /* @@? 82:44 Error SyntaxError: Property or signature expected. */ diff --git a/ets2panda/test/ast/parser/ets/unexpected_token_31.ets b/ets2panda/test/ast/parser/ets/unexpected_token_31.ets index 111827541b713c8ffdea0c30e6ed7b86f303c37e..dc353cf701ccbf9f71402180c0db5ff7a057193c 100644 --- a/ets2panda/test/ast/parser/ets/unexpected_token_31.ets +++ b/ets2panda/test/ast/parser/ets/unexpected_token_31.ets @@ -27,5 +27,5 @@ function foo(...^number: int[]): int { /* @@? 16:38 Error SyntaxError: Unexpected token '{'. */ /* @@? 17:5 Error SyntaxError: return keyword should be used in function body. */ /* @@? 17:12 Error TypeError: Type name 'number' used in the wrong context */ -/* @@? 17:12 Error TypeError: Indexed signatures are not allowed. Use arrays instead! */ +/* @@? 17:12 Error TypeError: Object type doesn't have proper index access method. */ /* @@? 17:12 Error TypeError: All return statements in the function should be empty or have a value. */ diff --git a/ets2panda/test/ast/parser/ets/unexpected_token_63.ets b/ets2panda/test/ast/parser/ets/unexpected_token_63.ets index ec6024e988612d96e494bd356eb07334d126a281..342f45a066311abc9aa70196147db4170f458e35 100644 --- a/ets2panda/test/ast/parser/ets/unexpected_token_63.ets +++ b/ets2panda/test/ast/parser/ets/unexpected_token_63.ets @@ -33,7 +33,6 @@ class A { /* @@? 17:29 Error SyntaxError: Unexpected token ':'. */ /* @@? 17:31 Error SyntaxError: number is a predefined type, cannot be used as an identifier */ /* @@? 17:37 Error SyntaxError: Unexpected token ')'. */ -/* @@? 17:37 Error SyntaxError: Field type annotation expected. */ /* @@? 17:39 Error SyntaxError: Unexpected token '{'. */ /* @@? 18:3 Error SyntaxError: Unexpected token 'while'. */ /* @@? 18:8 Error SyntaxError: Unexpected token '('. */ diff --git a/ets2panda/test/ast/parser/ets/wrong_context_class_4.ets b/ets2panda/test/ast/parser/ets/wrong_context_class_4.ets index 531f3707e9d4884f12e13970a64c909b609d5960..79ccb2bf3b42f75c8be831257608c268bd56f91a 100644 --- a/ets2panda/test/ast/parser/ets/wrong_context_class_4.ets +++ b/ets2panda/test/ast/parser/ets/wrong_context_class_4.ets @@ -26,5 +26,5 @@ function main() a[3] } -/* @@? 26:5 Error TypeError: Indexed signatures are not allowed. Use arrays instead! */ +/* @@? 26:5 Error TypeError: Object type doesn't have proper index access method. */ /* @@? 26:5 Error SyntaxError: Class cannot be used as object. */