已合并
Incorrect cast in the numeric type #10565
Incorrect cast in the numeric type #10565
已合并
fanglou创建于 4月27日
3 个文件变更+208-36
@@ -185,6 +185,69 @@ static void HandleFunctionParam(public_lib::Context *ctx, ir::ETSParameterExpres
185 varsMap->emplace(oldVar, newVar);185 varsMap->emplace(oldVar, newVar);
186}186}
187 187 
188+static ir::Expression *ConvertInitExpression(public_lib::Context *ctx, ir::Expression *init, checker::Type *targetType)
189+{
190+ auto *allocator = ctx->allocator;
191+ auto *parser = ctx->parser->AsETSParser();
192+ auto *checker = ctx->GetChecker()->AsETSChecker();
193+ auto *initType = init->TsType();
194+ auto range = init->Range();
195+ 
196+ if (checker->IsTypeIdenticalTo(initType, targetType)) {
197+ return init;
198+ }
199+ 
200+ if (initType != nullptr && initType->IsBuiltinNumeric() && targetType->IsBuiltinNumeric()) {
201+ auto targetTypeStr = targetType->ToString();
202+ if (!targetTypeStr.empty()) {
203+ std::string format = "@@E1.to" + targetTypeStr + "()";
204+ auto *arg = parser->CreateFormattedExpression(format, init);
205+ arg->SetRange(range);
206+ return arg;
207+ }
208+ }
209+ 
210+ auto *arg = util::NodeAllocator::ForceSetParent<ir::TSAsExpression>(
211+ allocator, init, allocator->New<ir::OpaqueTypeNode>(targetType, allocator), false);
212+ arg->AsTSAsExpression()->TypeAnnotation()->SetRange(range);
213+ arg->SetRange(range);
214+ return arg;
215+}
216+ 
217+static ir::VariableDeclarator *CreateBoxedDeclarator(ArenaAllocator *allocator, ir::VariableDeclarator *declarator,
218+ checker::Type *boxedType, ArenaVector<ir::Expression *> &&initArgs)
219+{
220+ auto *newInit = util::NodeAllocator::ForceSetParent<ir::ETSNewClassInstanceExpression>(
221+ allocator, allocator->New<ir::OpaqueTypeNode>(boxedType, allocator), std::move(initArgs));
222+ auto *id = declarator->Id()->AsIdentifier();
223+ auto *newDeclarator = util::NodeAllocator::ForceSetParent<ir::VariableDeclarator>(
224+ allocator, declarator->Flag(), allocator->New<ir::Identifier>(id->Name(), allocator), newInit);
225+ 
226+ newDeclarator->SetParent(declarator->Parent());
227+ newInit->GetTypeRef()->SetRange(declarator->Range());
228+ newInit->SetRange(declarator->Range());
229+ newDeclarator->Id()->SetRange(declarator->Range());
230+ newDeclarator->SetRange(declarator->Range());
231+ 
232+ return newDeclarator;
233+}
234+ 
235+static varbinder::LocalVariable *SetupNewVariable(ArenaAllocator *allocator, ir::VariableDeclarator *newDeclarator,
236+ varbinder::Variable *oldVar, varbinder::Scope *scope)
237+{
238+ auto *newDecl = allocator->New<varbinder::ConstDecl>(oldVar->Name(), newDeclarator);
239+ auto *newVar = allocator->New<varbinder::LocalVariable>(newDecl, oldVar->Flags());
240+ 
241+ newDeclarator->Id()->AsIdentifier()->SetVariable(newVar);
242+ newVar->AddFlag(varbinder::VariableFlags::INITIALIZED);
243+ newVar->SetScope(scope);
244+ 
245+ scope->EraseBinding(oldVar->Name());
246+ scope->InsertBinding(newVar->Name(), newVar);
247+ 
248+ return newVar;
249+}
250+ 
188static ir::AstNode *HandleVariableDeclarator(public_lib::Context *ctx, ir::VariableDeclarator *declarator,251static ir::AstNode *HandleVariableDeclarator(public_lib::Context *ctx, ir::VariableDeclarator *declarator,
189 ArenaMap<varbinder::Variable *, varbinder::Variable *> *varsMap)252 ArenaMap<varbinder::Variable *, varbinder::Variable *> *varsMap)
190{253{
@@ -197,6 +260,7 @@ static ir::AstNode *HandleVariableDeclarator(public_lib::Context *ctx, ir::Varia
197 auto *scope = oldVar->GetScope();260 auto *scope = oldVar->GetScope();
198 auto *type = oldVar->TsType();261 auto *type = oldVar->TsType();
199 auto *boxedType = checker->GlobalBuiltinBoxType(type);262 auto *boxedType = checker->GlobalBuiltinBoxType(type);
263+ 
200 bool inForInit = (declarator->Parent() != nullptr) && (declarator->Parent()->Parent() != nullptr) &&264 bool inForInit = (declarator->Parent() != nullptr) && (declarator->Parent()->Parent() != nullptr) &&
201 declarator->Parent()->Parent()->IsForUpdateStatement();265 declarator->Parent()->Parent()->IsForUpdateStatement();
202 if (inForInit && oldVar->HasFlag(varbinder::VariableFlags::PER_ITERATION)) {266 if (inForInit && oldVar->HasFlag(varbinder::VariableFlags::PER_ITERATION)) {
@@ -205,44 +269,18 @@ static ir::AstNode *HandleVariableDeclarator(public_lib::Context *ctx, ir::Varia
205 269 
206 auto initArgs = ArenaVector<ir::Expression *>(allocator->Adapter());270 auto initArgs = ArenaVector<ir::Expression *>(allocator->Adapter());
207 if (declarator->Init() != nullptr) {271 if (declarator->Init() != nullptr) {
208- auto *arg = declarator->Init();272+ auto *arg = ConvertInitExpression(ctx, declarator->Init(), type);
209- if (!checker->IsTypeIdenticalTo(arg->TsType(), type)) {
210- arg = util::NodeAllocator::ForceSetParent<ir::TSAsExpression>(
211- allocator, arg, allocator->New<ir::OpaqueTypeNode>(type, allocator), false);
212- arg->AsTSAsExpression()->TypeAnnotation()->SetRange(declarator->Init()->Range());
213- arg->SetRange(declarator->Init()->Range());
214- }
215 initArgs.push_back(arg);273 initArgs.push_back(arg);
216 }274 }
217- auto *newInit = util::NodeAllocator::ForceSetParent<ir::ETSNewClassInstanceExpression>(
218- allocator, allocator->New<ir::OpaqueTypeNode>(boxedType, allocator), std::move(initArgs));
219- auto *newDeclarator = util::NodeAllocator::ForceSetParent<ir::VariableDeclarator>(
220- allocator, declarator->Flag(), allocator->New<ir::Identifier>(id->Name(), allocator), newInit);
221- ES2PANDA_ASSERT(newDeclarator != nullptr);
222 275 
223- newDeclarator->SetParent(declarator->Parent());276+ auto *newDeclarator = CreateBoxedDeclarator(allocator, declarator, boxedType, std::move(initArgs));
224- 277+ auto *newVar = SetupNewVariable(allocator, newDeclarator, oldVar, scope);
225- newInit->GetTypeRef()->SetRange(declarator->Range());
226- newInit->SetRange(declarator->Range());
227- newDeclarator->Id()->SetRange(declarator->Range());
228- newDeclarator->SetRange(declarator->Range());
229- 
230- auto *newDecl = allocator->New<varbinder::ConstDecl>(oldVar->Name(), newDeclarator);
231- auto *newVar = allocator->New<varbinder::LocalVariable>(newDecl, oldVar->Flags());
232- ES2PANDA_ASSERT(newVar != nullptr);
233- newDeclarator->Id()->AsIdentifier()->SetVariable(newVar);
234- newVar->AddFlag(varbinder::VariableFlags::INITIALIZED);
235- newVar->SetScope(scope);
236- 
237- scope->EraseBinding(oldVar->Name());
238- scope->InsertBinding(newVar->Name(), newVar);
239 278 
240 auto lexScope = varbinder::LexicalScope<varbinder::Scope>::Enter(varBinder, scope);279 auto lexScope = varbinder::LexicalScope<varbinder::Scope>::Enter(varBinder, scope);
241 auto savedContext = checker::SavedCheckerContext(checker, checker::CheckerStatus::NO_OPTS);280 auto savedContext = checker::SavedCheckerContext(checker, checker::CheckerStatus::NO_OPTS);
242 auto scopeContext = checker::ScopeContext(checker, scope);281 auto scopeContext = checker::ScopeContext(checker, scope);
243 282 
244 newDeclarator->Check(checker);283 newDeclarator->Check(checker);
245- 
246 varsMap->emplace(oldVar, newVar);284 varsMap->emplace(oldVar, newVar);
247 285 
248 return newDeclarator;286 return newDeclarator;
@@ -305,7 +343,6 @@ static ir::AstNode *HandleReference(public_lib::Context *ctx, ir::Identifier *id
305static ir::AstNode *HandleAssignment(public_lib::Context *ctx, ir::AssignmentExpression *ass,343static ir::AstNode *HandleAssignment(public_lib::Context *ctx, ir::AssignmentExpression *ass,
306 ArenaMap<varbinder::Variable *, varbinder::Variable *> const &varsMap)344 ArenaMap<varbinder::Variable *, varbinder::Variable *> const &varsMap)
307{345{
308- // Should be true after opAssignment lowering
309 ES2PANDA_ASSERT(ass->OperatorType() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION);346 ES2PANDA_ASSERT(ass->OperatorType() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION);
310 347 
311 auto *parser = ctx->parser->AsETSParser();348 auto *parser = ctx->parser->AsETSParser();
@@ -317,12 +354,24 @@ static ir::AstNode *HandleAssignment(public_lib::Context *ctx, ir::AssignmentExp
317 auto *scope = newVar->GetScope();354 auto *scope = newVar->GetScope();
318 newVar->AddFlag(varbinder::VariableFlags::INITIALIZED);355 newVar->AddFlag(varbinder::VariableFlags::INITIALIZED);
319 356 
357+ auto *rightType = ass->Right()->TsType();
358+ auto *targetType = oldVar->TsType();
359+ auto *resultType = ass->TsType();
360+ 
361+ ir::Expression *res = nullptr;
320 // `as never` is prohibited.362 // `as never` is prohibited.
321- auto *res = ass->TsType()->IsETSNeverType()363+ if (resultType->IsETSNeverType()) {
322- ? parser->CreateFormattedExpression("@@I1.set(@@E2 as @@T3)", newVar->Name(), ass->Right(),364+ res = parser->CreateFormattedExpression("@@I1.set(@@E2 as @@T3)", newVar->Name(), ass->Right(), targetType);
323- oldVar->TsType())365+ } else if (rightType != nullptr && rightType->IsBuiltinNumeric() && targetType->IsBuiltinNumeric()) {
324- : parser->CreateFormattedExpression("@@I1.set(@@E2 as @@T3) as @@T4", newVar->Name(), ass->Right(),366+ // Use explicit conversion for numeric types instead of implicit 'as'
325- oldVar->TsType(), ass->TsType());367+ auto targetTypeStr = targetType->ToString();
368+ std::string format = "@@I1.set((@@E2).to" + targetTypeStr + "()) as @@T3";
369+ res = parser->CreateFormattedExpression(format, newVar->Name(), ass->Right(), resultType);
370+ } else {
371+ // Non-numeric types: use 'as' expression
372+ res = parser->CreateFormattedExpression("@@I1.set(@@E2 as @@T3) as @@T4", newVar->Name(), ass->Right(),
373+ targetType, resultType);
374+ }
326 res->SetParent(ass->Parent());375 res->SetParent(ass->Parent());
327 376 
328 // NOTE(gogabr) -- The `get` and `set` properties remain without variable; this is OK for the current checker, but377 // NOTE(gogabr) -- The `get` and `set` properties remain without variable; this is OK for the current checker, but
@@ -334,7 +383,7 @@ static ir::AstNode *HandleAssignment(public_lib::Context *ctx, ir::AssignmentExp
334 varBinder->ResolveReferencesForScopeWithContext(res, scope);383 varBinder->ResolveReferencesForScopeWithContext(res, scope);
335 res->Check(checker);384 res->Check(checker);
336 385 
337- ES2PANDA_ASSERT(ass->TsType()->IsETSNeverType() || res->TsType() == ass->TsType());386+ ES2PANDA_ASSERT(resultType->IsETSNeverType() || res->TsType() == ass->TsType());
338 387 
339 return res;388 return res;
340}389}
@@ -0,0 +1,60 @@
1+/*
2+ * Copyright (c) 2026 Huawei Device Co., Ltd.
3+ * Licensed under the Apache License, Version 2.0 (the "License");
4+ * you may not use this file except in compliance with the License.
5+ * You may obtain a copy of the License at
6+ *
7+ * http://www.apache.org/licenses/LICENSE-2.0
8+ *
9+ * Unless required by applicable law or agreed to in writing, software
10+ * distributed under the License is distributed on an "AS IS" BASIS,
11+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+ * See the License for the specific language governing permissions and
13+ * limitations under the License.
14+ */
15+ 
16+function foo(): Int {
17+ return 42
18+}
19+ 
20+function test_capture_and_assign_number(): void {
21+ let v: number;
22+ let executed = false;
23+ let f = () => {
24+ v = foo()
25+ executed = true
26+ };
27+ f();
28+ arktest.assertTrue(executed)
29+ arktest.assertEQ(v, 42.0)
30+}
31+ 
32+function test_capture_and_assign_int(): void {
33+ let v: Int;
34+ let executed = false;
35+ let f = () => {
36+ v = foo()
37+ executed = true
38+ };
39+ f();
40+ arktest.assertTrue(executed)
41+ arktest.assertEQ(v, 42)
42+}
43+ 
44+function test_capture_and_assign_double(): void {
45+ let d: Double;
46+ let executed = false;
47+ let f = () => {
48+ d = 3.14
49+ executed = true
50+ };
51+ f();
52+ arktest.assertTrue(executed)
53+ arktest.assertEQ(d, 3.14)
54+}
55+ 
56+function main(): void {
57+ test_capture_and_assign_number()
58+ test_capture_and_assign_int()
59+ test_capture_and_assign_double()
60+}
@@ -0,0 +1,63 @@
1+/*
2+ * Copyright (c) 2026 Huawei Device Co., Ltd.
3+ * Licensed under the Apache License, Version 2.0 (the "License");
4+ * you may not use this file except in compliance with the License.
5+ * You may obtain a copy of the License at
6+ *
7+ * http://www.apache.org/licenses/LICENSE-2.0
8+ *
9+ * Unless required by applicable law or agreed to in writing, software
10+ * distributed under the License is distributed on an "AS IS" BASIS,
11+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+ * See the License for the specific language governing permissions and
13+ * limitations under the License.
14+ */
15+ 
16+function test_capture_and_read_number(): void {
17+ let v: number = 100.5;
18+ let result: number = 0.0;
19+ let f = () => {
20+ result = v
21+ };
22+ f();
23+ arktest.assertEQ(result, 100.5)
24+}
25+ 
26+function test_capture_and_read_int(): void {
27+ let v: Int = 55;
28+ let result: Int = 0;
29+ let f = () => {
30+ result = v
31+ };
32+ f();
33+ arktest.assertEQ(result, 55)
34+}
35+ 
36+function test_capture_and_read_double(): void {
37+ let v: Double = 2.718;
38+ let result: Double = 0.0;
39+ let f = () => {
40+ result = v
41+ };
42+ f();
43+ arktest.assertEQ(result, 2.718)
44+}
45+ 
46+function test_capture_read_and_write(): void {
47+ let v: number = 10.0;
48+ let result: number = 0.0;
49+ let f = () => {
50+ result = v
51+ v = 20.0
52+ };
53+ f();
54+ arktest.assertEQ(result, 10.0)
55+ arktest.assertEQ(v, 20.0)
56+}
57+ 
58+function main(): void {
59+ test_capture_and_read_number()
60+ test_capture_and_read_int()
61+ test_capture_and_read_double()
62+ test_capture_read_and_write()
63+}