From 02ac7a09a2f424732d074d55795c07f64829a388 Mon Sep 17 00:00:00 2001 From: "584648456@qq.com" Date: Wed, 14 May 2025 12:23:00 +0800 Subject: [PATCH] Title: for-of union type recognition Description(optional): for-of union type recognition Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/IC7OBY Signed-off-by: semon <584648456@qq.com> --- ets2panda/checker/ETSAnalyzer.cpp | 2 +- ets2panda/compiler/core/ETSCompiler.cpp | 12 +++-- ets2panda/compiler/core/ETSGen.cpp | 14 +++--- ets2panda/compiler/core/ETSGen.h | 5 ++- ets2panda/compiler/scripts/signatures.yaml | 4 +- ets2panda/ir/statements/forOfStatement.cpp | 2 +- .../test/ast/compiler/ets/func_as_param.ets | 3 +- .../ast/parser/ets/FixedArray/for_of_02.ets | 7 +-- ets2panda/test/ast/parser/ets/for_of_02.ets | 7 +-- ets2panda/test/parser/ets/for_of-expected.txt | 44 ++++++++++++++++--- ets2panda/test/parser/ets/for_of.ets | 4 +- ets2panda/test/runtime/ets/ForOfBoxing.ets | 2 +- ets2panda/test/runtime/ets/ForOfUnion.ets | 20 ++++----- 13 files changed, 82 insertions(+), 44 deletions(-) diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index 43ab9c71bf..ec6c0228bf 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -3051,7 +3051,7 @@ checker::Type *ETSAnalyzer::Check(ir::ForOfStatement *const st) const checker::Type *elemType = nullptr; if (exprType->IsETSStringType()) { - elemType = checker->GlobalCharBuiltinType(); + elemType = checker->GetGlobalTypesHolder()->GlobalETSStringBuiltinType(); } else if (exprType->IsETSArrayType() || exprType->IsETSResizableArrayType()) { elemType = checker->GetElementTypeOfArray(exprType); } else if (exprType->IsETSObjectType() || exprType->IsETSUnionType() || exprType->IsETSTypeParameter()) { diff --git a/ets2panda/compiler/core/ETSCompiler.cpp b/ets2panda/compiler/core/ETSCompiler.cpp index bae951abe4..871bc02075 100644 --- a/ets2panda/compiler/core/ETSCompiler.cpp +++ b/ets2panda/compiler/core/ETSCompiler.cpp @@ -229,9 +229,13 @@ static void HandleUnionTypeInForOf(compiler::ETSGen *etsg, checker::Type const * labels.push_back(etsg->AllocLabel()); - for (size_t i = 0; i < exprType->AsETSUnionType()->ConstituentTypes().size(); i++) { + auto types = exprType->AsETSUnionType()->ConstituentTypes(); + bool withStringTypeInUnion = types.size() == 2 && std::find_if(types.begin(), types.end(), [](const auto t) { + return t != nullptr && t->IsETSStringType(); + }) != types.end(); + for (size_t i = 0; i < types.size(); i++) { compiler::VReg unionReg = etsg->AllocReg(); - auto currentType = exprType->AsETSUnionType()->ConstituentTypes()[i]; + auto currentType = types[i]; etsg->SetLabel(st->Right(), labels[i]); etsg->LoadAccumulator(st, objReg); etsg->CastToReftype(st->Right(), currentType, false); @@ -250,9 +254,9 @@ static void HandleUnionTypeInForOf(compiler::ETSGen *etsg, checker::Type const * etsg->LoadAccumulator(st, *countReg); etsg->LoadArrayElement(st, unionReg); } else if (currentType->IsETSResizableArrayType()) { - etsg->LoadResizableArrayElement(st, unionReg, *countReg); + etsg->LoadResizableArrayElement(st, unionReg, *countReg, withStringTypeInUnion); } else { - etsg->LoadStringChar(st, unionReg, *countReg, true); + etsg->LoadStringChar(st, unionReg, *countReg); } } diff --git a/ets2panda/compiler/core/ETSGen.cpp b/ets2panda/compiler/core/ETSGen.cpp index fde13df423..60e3574507 100644 --- a/ets2panda/compiler/core/ETSGen.cpp +++ b/ets2panda/compiler/core/ETSGen.cpp @@ -2896,12 +2896,16 @@ void ETSGen::LoadResizableArrayLength(const ir::AstNode *node) SetAccumulatorType(Checker()->GlobalIntType()); } -void ETSGen::LoadResizableArrayElement(const ir::AstNode *node, const VReg arrObj, const VReg arrIndex) +void ETSGen::LoadResizableArrayElement(const ir::AstNode *node, const VReg arrObj, const VReg arrIndex, + const bool withStringTypeInUnion) { auto *vRegType = GetVRegType(arrObj); auto *elementType = vRegType->AsETSResizableArrayType()->ElementType(); Ra().Emit(node, Signatures::BUILTIN_ARRAY_GET_ELEMENT, arrObj, arrIndex); SetAccumulatorType(elementType); + if (withStringTypeInUnion && elementType->IsETSStringType()) { + InternalCheckCast(node, Checker()->GetGlobalTypesHolder()->GlobalETSStringBuiltinType()); + } } void ETSGen::LoadArrayLength(const ir::AstNode *node, VReg arrayReg) @@ -3081,14 +3085,10 @@ void ETSGen::DoubleIsNaN(const ir::AstNode *node) SetAccumulatorType(Checker()->GlobalETSBooleanType()); } -void ETSGen::LoadStringChar(const ir::AstNode *node, const VReg stringObj, const VReg charIndex, bool needBox) +void ETSGen::LoadStringChar(const ir::AstNode *node, const VReg stringObj, const VReg charIndex) { Ra().Emit(node, Signatures::BUILTIN_STRING_CHAR_AT, stringObj, charIndex); - SetAccumulatorType(Checker()->GlobalCharType()); - if (needBox) { - Ra().Emit(node, Signatures::BUILTIN_CHAR_VALUE_OF, dummyReg_, 0); - SetAccumulatorType(Checker()->GlobalCharBuiltinType()); - } + SetAccumulatorType(Checker()->GetGlobalTypesHolder()->GlobalETSStringBuiltinType()); } void ETSGen::ThrowException(const ir::Expression *expr) diff --git a/ets2panda/compiler/core/ETSGen.h b/ets2panda/compiler/core/ETSGen.h index 9ebeb8790f..222ede8caa 100644 --- a/ets2panda/compiler/core/ETSGen.h +++ b/ets2panda/compiler/core/ETSGen.h @@ -235,7 +235,8 @@ public: VReg MoveAccToReg(const ir::AstNode *node); void LoadResizableArrayLength(const ir::AstNode *node); - void LoadResizableArrayElement(const ir::AstNode *node, const VReg arrObj, const VReg arrIndex); + void LoadResizableArrayElement(const ir::AstNode *node, const VReg arrObj, const VReg arrIndex, + bool withStringTypeInUnion); void LoadArrayLength(const ir::AstNode *node, VReg arrayReg); void LoadArrayElement(const ir::AstNode *node, VReg objectReg); void StoreArrayElement(const ir::AstNode *node, VReg objectReg, VReg index, const checker::Type *elementType); @@ -259,7 +260,7 @@ public: } void LoadStringLength(const ir::AstNode *node); - void LoadStringChar(const ir::AstNode *node, VReg stringObj, VReg charIndex, bool needBox = false); + void LoadStringChar(const ir::AstNode *node, VReg stringObj, VReg charIndex); void FloatIsNaN(const ir::AstNode *node); void DoubleIsNaN(const ir::AstNode *node); diff --git a/ets2panda/compiler/scripts/signatures.yaml b/ets2panda/compiler/scripts/signatures.yaml index 7cfa309206..3962a0872c 100644 --- a/ets2panda/compiler/scripts/signatures.yaml +++ b/ets2panda/compiler/scripts/signatures.yaml @@ -744,9 +744,9 @@ signatures: ref: BUILTIN_STRING_LENGTH - callee: BUILTIN_STRING - method_name: charAt + method_name: charAtString params: [PRIMITIVE_INT] - return_type: PRIMITIVE_CHAR + return_type: BUILTIN_STRING ref: BUILTIN_STRING_CHAR_AT - callee: BUILTIN_ARRAY diff --git a/ets2panda/ir/statements/forOfStatement.cpp b/ets2panda/ir/statements/forOfStatement.cpp index 953d282268..93683d6cb6 100644 --- a/ets2panda/ir/statements/forOfStatement.cpp +++ b/ets2panda/ir/statements/forOfStatement.cpp @@ -27,7 +27,7 @@ checker::Type *ForOfStatement::CreateUnionIteratorTypes(checker::ETSChecker *che for (auto it : exprType->AsETSUnionType()->ConstituentTypes()) { if (it->IsETSStringType()) { - types.emplace_back(checker->GlobalCharBuiltinType()); + types.push_back(checker->GetGlobalTypesHolder()->GlobalETSStringBuiltinType()); } else if (it->IsETSObjectType()) { types.emplace_back(this->CheckIteratorMethodForObject(checker, it->AsETSObjectType())); } else if (it->IsETSArrayType()) { diff --git a/ets2panda/test/ast/compiler/ets/func_as_param.ets b/ets2panda/test/ast/compiler/ets/func_as_param.ets index 43f1c47d80..7d03377605 100644 --- a/ets2panda/test/ast/compiler/ets/func_as_param.ets +++ b/ets2panda/test/ast/compiler/ets/func_as_param.ets @@ -26,8 +26,7 @@ function getFuncWithArgsZero(func: (() => void) | (() => Promise)) { function getFunctionArgumentsCount(funcStr: string): number { const regex = new RegExp("^[0123456789]$", "g") let count = "" - for(let ch of funcStr) { - let str = new Char(ch).toString(); + for(let str of funcStr) { if(regex.test(str)) { count = str } diff --git a/ets2panda/test/ast/parser/ets/FixedArray/for_of_02.ets b/ets2panda/test/ast/parser/ets/FixedArray/for_of_02.ets index 25779dcb62..1a529dc6f5 100644 --- a/ets2panda/test/ast/parser/ets/FixedArray/for_of_02.ets +++ b/ets2panda/test/ast/parser/ets/FixedArray/for_of_02.ets @@ -16,7 +16,7 @@ let a: FixedArray = [1, 2, 3]; function forins(): int { - for (let i: int of "abcdef") { + /* @@ label */for (let i: int of "abcdef") { return i; } return c'*'; @@ -27,9 +27,10 @@ function main(): void { for (let v: double of a) { res += v; } - /* @@ label */for (let v: float of [4.1, 5.4, 6.0]) { + /* @@ label2 */for (let v: float of [4.1, 5.4, 6.0]) { res += v; } } -/* @@@ label Error TypeError: Source element type 'Double' is not assignable to the loop iterator type 'Float'. */ +/* @@@ label Error TypeError: Source element type 'String' is not assignable to the loop iterator type 'int'. */ +/* @@@ label2 Error TypeError: Source element type 'Double' is not assignable to the loop iterator type 'float'. */ diff --git a/ets2panda/test/ast/parser/ets/for_of_02.ets b/ets2panda/test/ast/parser/ets/for_of_02.ets index b30a1e168d..dbb1bb1eee 100644 --- a/ets2panda/test/ast/parser/ets/for_of_02.ets +++ b/ets2panda/test/ast/parser/ets/for_of_02.ets @@ -16,7 +16,7 @@ let a: int[] = [1, 2, 3]; function forins(): int { - for (let i: int of "abcdef") { + /* @@ label */for (let i: int of "abcdef") { return i; } return c'*'; @@ -27,9 +27,10 @@ function main(): void { for (let v: double of a) { res += v; } - /* @@ label */for (let v: float of [4.1, 5.4, 6.0]) { + /* @@ label2 */for (let v: float of [4.1, 5.4, 6.0]) { res += v; } } -/* @@@ label Error TypeError: Source element type 'Double' is not assignable to the loop iterator type 'Float'. */ +/* @@@ label Error TypeError: Source element type 'String' is not assignable to the loop iterator type 'int'. */ +/* @@@ label2 Error TypeError: Source element type 'Double' is not assignable to the loop iterator type 'float'. */ diff --git a/ets2panda/test/parser/ets/for_of-expected.txt b/ets2panda/test/parser/ets/for_of-expected.txt index 2a62e69595..149a169895 100644 --- a/ets2panda/test/parser/ets/for_of-expected.txt +++ b/ets2panda/test/parser/ets/for_of-expected.txt @@ -981,7 +981,39 @@ "expression": false, "params": [], "returnType": { - "type": "ETSPrimitiveType", + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "string", + "decorators": [], + "loc": { + "start": { + "line": 28, + "column": 20, + "program": "for_of.ets" + }, + "end": { + "line": 28, + "column": 26, + "program": "for_of.ets" + } + } + }, + "loc": { + "start": { + "line": 28, + "column": 20, + "program": "for_of.ets" + }, + "end": { + "line": 28, + "column": 28, + "program": "for_of.ets" + } + } + }, "loc": { "start": { "line": 28, @@ -990,7 +1022,7 @@ }, "end": { "line": 28, - "column": 24, + "column": 28, "program": "for_of.ets" } } @@ -1133,7 +1165,7 @@ { "type": "ReturnStatement", "argument": { - "type": "CharLiteral", + "type": "StringLiteral", "value": "*", "loc": { "start": { @@ -1143,7 +1175,7 @@ }, "end": { "line": 32, - "column": 14, + "column": 13, "program": "for_of.ets" } } @@ -1156,7 +1188,7 @@ }, "end": { "line": 32, - "column": 15, + "column": 14, "program": "for_of.ets" } } @@ -1165,7 +1197,7 @@ "loc": { "start": { "line": 28, - "column": 25, + "column": 27, "program": "for_of.ets" }, "end": { diff --git a/ets2panda/test/parser/ets/for_of.ets b/ets2panda/test/parser/ets/for_of.ets index 66d3ee60eb..ddbb5b4e82 100644 --- a/ets2panda/test/parser/ets/for_of.ets +++ b/ets2panda/test/parser/ets/for_of.ets @@ -25,9 +25,9 @@ function main(): void { } } -function forins(): char { +function forins(): string { for (let i of "abcdef") { return i; } - return c'*'; + return '*'; } diff --git a/ets2panda/test/runtime/ets/ForOfBoxing.ets b/ets2panda/test/runtime/ets/ForOfBoxing.ets index 4a7d4d02cd..45c0e3a150 100644 --- a/ets2panda/test/runtime/ets/ForOfBoxing.ets +++ b/ets2panda/test/runtime/ets/ForOfBoxing.ets @@ -97,7 +97,7 @@ function check6() { function check7() { let str = ""; let a7 : string = "ffff" - for (let idx7 : char of a7) { + for (let idx7 : string of a7) { let b7 = idx7 str += b7; } diff --git a/ets2panda/test/runtime/ets/ForOfUnion.ets b/ets2panda/test/runtime/ets/ForOfUnion.ets index 3e6929ee0e..bfbb75b648 100644 --- a/ets2panda/test/runtime/ets/ForOfUnion.ets +++ b/ets2panda/test/runtime/ets/ForOfUnion.ets @@ -16,9 +16,9 @@ function check1() { let a8 : string|Int[] = "abc" let str = ""; - for (let character : Char|Int of a8) { - if (character instanceof Char) { - str += character; + for (let index : string|Int of a8) { + if (index instanceof string) { + str += index; } } @@ -28,7 +28,7 @@ function check1() { function check2() { let a9 : string|Int[] = [1,2] as Int[] let sum = 0; - for (let val : Char|Int of a9) { + for (let val : string|Int of a9) { let b9 = val if (b9 instanceof Int) { sum += b9; @@ -45,12 +45,12 @@ function fooStr() : string|Int[] { function check3() { let a8 : string|Int[] = fooStr(); - let target : Char|Int = 0; - for (let character : Char|Int of a8) { - target = character; + let target : string|Int = 0; + for (let index : string|Int of a8) { + target = index; } - assertTrue(target instanceof Char) + assertTrue(target instanceof string) } function fooInt() : string|Int[] { @@ -60,8 +60,8 @@ function fooInt() : string|Int[] { function check4() { let a8 : string|Int[] = fooInt(); - let target : Char|Int = 0; - for (let val : Char|Int of a8) { + let target : string|Int = 0; + for (let val : string|Int of a8) { target = val; } -- Gitee