diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index 2c0fd6a3fc8343d00a78b72c70677cc2e13d5cbd..86485d23f652513ede9b8809b36e8e6d5cb607a0 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -2980,7 +2980,7 @@ checker::Type *ETSAnalyzer::Check(ir::ForOfStatement *const st) const return checker->GlobalTypeError(); } - checker::Type *elemType = nullptr; + checker::Type *elemType = checker->GlobalTypeError(); if (exprType->IsETSStringType()) { elemType = checker->GetGlobalTypesHolder()->GlobalCharType(); @@ -2990,7 +2990,7 @@ checker::Type *ETSAnalyzer::Check(ir::ForOfStatement *const st) const elemType = st->CheckIteratorMethod(checker); } - if (elemType == nullptr) { + if (elemType == checker->GlobalTypeError()) { checker->LogError(diagnostic::FOROF_SOURCE_NONITERABLE, {}, st->Right()->Start()); return checker->GlobalTypeError(); } diff --git a/ets2panda/checker/types/ets/etsUnionType.cpp b/ets2panda/checker/types/ets/etsUnionType.cpp index 2bbdf54442f4f6e4e746f7b52b6a3795a33aedc4..7893a517a96567f583f9e474efa25dbfa71d7f6d 100644 --- a/ets2panda/checker/types/ets/etsUnionType.cpp +++ b/ets2panda/checker/types/ets/etsUnionType.cpp @@ -265,6 +265,7 @@ void ETSUnionType::LinearizeAndEraseIdentical(TypeRelation *relation, ArenaVecto size_t const initialSz = types.size(); for (size_t i = 0; i < initialSz; ++i) { auto ct = types[i]; + ES2PANDA_ASSERT(ct != nullptr); if (ct->IsETSUnionType()) { auto const &otherTypes = ct->AsETSUnionType()->ConstituentTypes(); types.insert(types.end(), otherTypes.begin(), otherTypes.end()); diff --git a/ets2panda/ir/statements/forOfStatement.cpp b/ets2panda/ir/statements/forOfStatement.cpp index 31198b09a9755209b6fb1ade0c2322948c9db476..d6eee195c8143ddda3e66a62bceb22336dc81d13 100644 --- a/ets2panda/ir/statements/forOfStatement.cpp +++ b/ets2panda/ir/statements/forOfStatement.cpp @@ -35,7 +35,7 @@ checker::Type *ForOfStatement::CreateUnionIteratorTypes(checker::ETSChecker *che checker->GetGlobalTypesHolder())); types.back()->RemoveTypeFlag(checker::TypeFlag::CONSTANT); } else { - return nullptr; + return checker->GlobalTypeError(); } } @@ -158,7 +158,7 @@ checker::Type *ForOfStatement::CheckIteratorMethodForObject(checker::ETSChecker auto *const method = sourceType->GetProperty(compiler::Signatures::ITERATOR_METHOD, searchFlag); if (method == nullptr || !method->HasFlag(varbinder::VariableFlags::METHOD)) { checker->LogError(diagnostic::MISSING_ITERATOR_METHOD, {}, position); - return nullptr; + return checker->GlobalTypeError(); } ArenaVector arguments {checker->Allocator()->Adapter()}; @@ -167,27 +167,27 @@ checker::Type *ForOfStatement::CheckIteratorMethodForObject(checker::ETSChecker checker::TypeRelationFlag::NO_THROW); if (signature == nullptr) { checker->LogError(diagnostic::MISSING_ITERATOR_METHOD_WITH_SIG, {}, position); - return nullptr; + return checker->GlobalTypeError(); } checker->ValidateSignatureAccessibility(sourceType, signature, position, {{diagnostic::INVISIBLE_ITERATOR, {}}}); ES2PANDA_ASSERT(signature->Function() != nullptr); if (!CheckReturnTypeOfIteratorMethod(checker, sourceType, signature, position)) { - return nullptr; + return checker->GlobalTypeError(); } if (checker->IsClassStaticMethod(sourceType, signature)) { checker->LogError(diagnostic::PROP_IS_STATIC, {compiler::Signatures::ITERATOR_METHOD, sourceType->Name()}, position); - return nullptr; + return checker->GlobalTypeError(); } auto *const nextMethod = signature->ReturnType()->AsETSObjectType()->GetProperty(ITERATOR_INTERFACE_METHOD, searchFlag); if (nextMethod == nullptr || !nextMethod->HasFlag(varbinder::VariableFlags::METHOD)) { checker->LogError(diagnostic::ITERATOR_MISSING_NEXT, {}, position); - return nullptr; + return checker->GlobalTypeError(); } auto &nextSignatures = checker->GetTypeOfVariable(nextMethod)->AsETSFunctionType()->CallSignatures(); @@ -200,7 +200,7 @@ checker::Type *ForOfStatement::CheckIteratorMethodForObject(checker::ETSChecker } } - return nullptr; + return checker->GlobalTypeError(); } bool ForOfStatement::CheckReturnTypeOfIteratorMethod(checker::ETSChecker *checker, checker::ETSObjectType *sourceType, @@ -251,6 +251,6 @@ checker::Type *ForOfStatement::CheckIteratorMethod(checker::ETSChecker *const ch } } - return nullptr; + return checker->GlobalTypeError(); } } // namespace ark::es2panda::ir diff --git a/ets2panda/test/ast/compiler/ets/forof_iterator_doesnt_return_iteartor.ets b/ets2panda/test/ast/compiler/ets/forof_iterator_doesnt_return_iteartor.ets new file mode 100644 index 0000000000000000000000000000000000000000..e340e0579b0de0ac364512cdacfe3c67a47909db --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/forof_iterator_doesnt_return_iteartor.ets @@ -0,0 +1,54 @@ +/* + * 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 A { + data: FixedArray = [1,2,3]; + $_iterator() : CIterator | undefined { + return new CIterator(this); + } +} + +class CIterator implements Iterator { + index = 0; + base: A; + constructor (base: A) { + this.base = base; + } + next(): IteratorResult { + if (this.index >= this.base.data.length) { + return { + done: true, + value: undefined + } + } + return { + done: this.index >= this.base.data.length, + value: this.base.data[this.index++] + } + } +} + +function main(): void { + let res = 0; + let a = new A(); + for (let x of a) res += x; + arktest.assertEQ(res, 6); +} + + +/* @@? 18:15 Error TypeError: The return type of '$_iterator' must be a type that implements Iterator interface.*/ +/* @@? 46:19 Error TypeError: Iterator method must return an object which implements Iterator */ +/* @@? 46:19 Error TypeError: 'For-of' statement source expression is not of iterable type. */ + diff --git a/ets2panda/test/ast/compiler/ets/forof_iterator_missing_next.ets b/ets2panda/test/ast/compiler/ets/forof_iterator_missing_next.ets new file mode 100644 index 0000000000000000000000000000000000000000..f513a77c6e85deebbe8b98aa645ed8d95c84e15f --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/forof_iterator_missing_next.ets @@ -0,0 +1,40 @@ +/* + * 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 A { + data: FixedArray = [1,2,3]; + $_iterator() : CIterator | undefined { + return new CIterator(this); + } +} + +class CIterator { + index = 0; + base: A; + constructor (base: A) { + this.base = base; + } +} + +function main(): void { + let res = 0; + let a = new A(); + for (let x of a) res += x; + arktest.assertEQ(res, 6); +} + +/* @@? 18:15 Error TypeError: The return type of '$_iterator' must be a type that implements Iterator interface.*/ +/* @@? 34:19 Error TypeError: Iterator method must return an object which implements Iterator */ +/* @@? 34:19 Error TypeError: 'For-of' statement source expression is not of iterable type. */ \ No newline at end of file diff --git a/ets2panda/test/ast/compiler/ets/forof_missing_iterator_method.ets b/ets2panda/test/ast/compiler/ets/forof_missing_iterator_method.ets new file mode 100644 index 0000000000000000000000000000000000000000..8952030938ed9e0299fe4d66d42505ead97d20d6 --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/forof_missing_iterator_method.ets @@ -0,0 +1,31 @@ +/* + * 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 C { + index = 0 +} + +function main(): int { + let c = new C() + let res = '' + for (let x of c) { + res += x + } + if (res != '6') return 1 + return 0 +} + +/* @@? 23:17 Error TypeError: Object type doesn't have proper iterator method. */ +/* @@? 23:17 Error TypeError: 'For-of' statement source expression is not of iterable type. */ diff --git a/ets2panda/test/ast/compiler/ets/forof_missing_iterator_method_with_sig.ets b/ets2panda/test/ast/compiler/ets/forof_missing_iterator_method_with_sig.ets new file mode 100644 index 0000000000000000000000000000000000000000..0adcb03bf1eb9a1fae580c5187ba574b6aa21732 --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/forof_missing_iterator_method_with_sig.ets @@ -0,0 +1,37 @@ +/* + * 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 C { + $_iterator(param: int): string { + return "notAnIterator"; + } +} + +function main(): int { + let c = new C(); + let res = ""; + + for (let x of c) { + res += x; + } + + if (res != "6") return 1; + return 0; +} + +/* @@? 17:3 Error SyntaxError: The special predefined method '$_iterator' should not have parameters. */ +/* @@? 17:13 Error TypeError: The return type of '$_iterator' must be a type that implements Iterator interface. */ +/* @@? 26:17 Error TypeError: Cannot find iterator method with the required signature. */ +/* @@? 26:17 Error TypeError: 'For-of' statement source expression is not of iterable type. */ \ No newline at end of file diff --git a/ets2panda/test/ast/compiler/ets/forof_prop_is_static.ets b/ets2panda/test/ast/compiler/ets/forof_prop_is_static.ets new file mode 100644 index 0000000000000000000000000000000000000000..ff9986cb413d7253e4be1848410181fa7fe88526 --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/forof_prop_is_static.ets @@ -0,0 +1,47 @@ +/* + * 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 C { + data: int[] = [1,2,3] + static $_iterator() { + return new CIterator(new C()) + } +} +class CIterator implements Iterator { + index = 0 + base: C + constructor (base: C) { + this.base = base + } + next(): IteratorResult { + return { + done: this.index >= this.base.data.length, + value: this.index >= this.base.data.length ? undefined : this.base.data[this.index++] + } + } +} + +function main(): int { + let c = new C() + let res = '' + for (let x of c) { + res += x + } + if (res != '6') return 1 + return 0 +} + +/* @@? 39:17 Error TypeError: '$_iterator' is a static property of 'C' */ +/* @@? 39:17 Error TypeError: 'For-of' statement source expression is not of iterable type. */ diff --git a/ets2panda/test/ast/compiler/ets/union_types_forof_1.ets b/ets2panda/test/ast/compiler/ets/union_types_forof_1.ets new file mode 100644 index 0000000000000000000000000000000000000000..b13724b2d10945e3c15315d3c042c2b2c7793f73 --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/union_types_forof_1.ets @@ -0,0 +1,34 @@ +/* + * 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. + */ + +function processValue(value: string | number): void { + if (typeof value === 'string') { + // Handle string case + for (const it of value) { + console.log(it); + } + } else { + // Handle number case + console.log(value.toString()); + } +} + +const testValues: (string | number)[] = ['hello', 42, 'world', 7]; + +for (const item of testValues) { + processValue(item); +} + +/* @@? 19:26 Error TypeError: Object type doesn't have proper iterator method. */