diff --git a/ets2panda/checker/ets/typeCheckingHelpers.cpp b/ets2panda/checker/ets/typeCheckingHelpers.cpp index 6f0a218600371e76c86403bb4362ff029b81baca..a7619c44dfd4ad97cddcc01ece0040f5595fd3c2 100644 --- a/ets2panda/checker/ets/typeCheckingHelpers.cpp +++ b/ets2panda/checker/ets/typeCheckingHelpers.cpp @@ -411,6 +411,11 @@ bool Type::IsETSPrimitiveOrEnumType() const return IsETSPrimitiveType() || IsETSEnumType(); } +bool Type::IsETSDoubleEnumType() const +{ + return IsETSObjectType() && AsETSObjectType()->HasObjectFlag(ETSObjectFlags::DOUBLE_ENUM_OBJECT); +} + bool Type::IsETSReferenceType() const { // Do not modify diff --git a/ets2panda/checker/ets/typeCreation.cpp b/ets2panda/checker/ets/typeCreation.cpp index c6396ad6435a2aa5eb7b8cc4107e733429543483..74210412c8249460cde8903edbcc70b1369c2279 100644 --- a/ets2panda/checker/ets/typeCreation.cpp +++ b/ets2panda/checker/ets/typeCreation.cpp @@ -375,10 +375,12 @@ ETSObjectType *ETSChecker::CreateETSObjectType(ir::AstNode *declNode, ETSObjectF if (declNode->AsClassDefinition()->IsIntEnumTransformed()) { objectType = ProgramAllocator()->New(ProgramAllocator(), name, internalName, declNode, Relation()); - } else { - ES2PANDA_ASSERT(declNode->AsClassDefinition()->IsStringEnumTransformed()); + } else if (declNode->AsClassDefinition()->IsStringEnumTransformed()) { objectType = ProgramAllocator()->New(ProgramAllocator(), name, internalName, declNode, Relation()); + } else if (declNode->AsClassDefinition()->IsDoubleEnumTransformed()) { + objectType = ProgramAllocator()->New(ProgramAllocator(), name, internalName, declNode, + Relation()); } } else if (internalName == compiler::Signatures::BUILTIN_ARRAY) { objectType = ProgramAllocator()->New(ProgramAllocator(), name, diff --git a/ets2panda/checker/types/ets/etsEnumType.cpp b/ets2panda/checker/types/ets/etsEnumType.cpp index 233a403e0501e8a662fba2b7bd2ad9c056b0df62..368e6f735c0bf3af82f939ad4d60c53716cd126e 100644 --- a/ets2panda/checker/types/ets/etsEnumType.cpp +++ b/ets2panda/checker/types/ets/etsEnumType.cpp @@ -134,4 +134,61 @@ void ETSIntEnumType::CastTarget(TypeRelation *relation, Type *source) conversion::Forbidden(relation); } +bool ETSDoubleEnumType::AssignmentSource(TypeRelation *relation, Type *target) +{ + bool result = false; + if (target->IsETSObjectType()) { + if (target->AsETSObjectType()->IsGlobalETSObjectType() || + target->AsETSObjectType()->Name() == compiler::Signatures::BUILTIN_DOUBLE_CLASS) { + result = true; + relation->GetNode()->AddAstNodeFlags(ir::AstNodeFlags::GENERATE_VALUE_OF); + } else if (target->IsDoubleType()) { + result = true; + relation->GetNode()->AddAstNodeFlags(ir::AstNodeFlags::GENERATE_VALUE_OF); + } + } else if (target->HasTypeFlag(TypeFlag::DOUBLE)) { + result = true; + relation->GetNode()->AddAstNodeFlags(ir::AstNodeFlags::GENERATE_VALUE_OF); + } else if (target->IsETSUnionType()) { + auto &unionConstituentTypes = target->AsETSUnionType()->ConstituentTypes(); + for (auto *constituentType : unionConstituentTypes) { + if (relation->IsIdenticalTo(this, constituentType)) { + result = true; + break; + } + } + } + relation->Result(result); + return relation->IsTrue(); +} + +void ETSDoubleEnumType::AssignmentTarget(TypeRelation *relation, Type *source) +{ + relation->IsIdenticalTo(this, source) ? relation->Result(true) : relation->Result(false); +} + +void ETSDoubleEnumType::Cast(TypeRelation *const relation, Type *const target) +{ + if (relation->IsIdenticalTo(this, target)) { + relation->Result(true); + return; + } + if (target->HasTypeFlag(TypeFlag::ETS_NUMERIC) || target->IsBuiltinNumeric()) { + relation->RaiseError(diagnostic::ENUM_DEPRECATED_CAST, {this, target}, relation->GetNode()->Start()); + relation->Result(true); + return; + } + conversion::Forbidden(relation); +} + +void ETSDoubleEnumType::CastTarget(TypeRelation *relation, Type *source) +{ + if (source->IsFloatType() || source->IsBuiltinNumeric()) { + relation->RaiseError(diagnostic::ENUM_DEPRECATED_CAST, {source, this}, relation->GetNode()->Start()); + relation->Result(true); + return; + } + conversion::Forbidden(relation); +} + } // namespace ark::es2panda::checker diff --git a/ets2panda/checker/types/ets/etsEnumType.h b/ets2panda/checker/types/ets/etsEnumType.h index 3005b78053a406f8ef707e2410d7d7cc090593a4..d09b0274dd7356d8a74a7ab31f4a8862ceb8657c 100644 --- a/ets2panda/checker/types/ets/etsEnumType.h +++ b/ets2panda/checker/types/ets/etsEnumType.h @@ -162,6 +162,27 @@ public: void CastTarget(TypeRelation *relation, Type *source) override; }; +class ETSDoubleEnumType : public ETSEnumType { +public: + explicit ETSDoubleEnumType(ThreadSafeArenaAllocator *allocator, util::StringView name, + util::StringView internalName, ir::AstNode *declNode, TypeRelation *relation) + : ETSEnumType(allocator, name, internalName, declNode, relation, ETSObjectFlags::DOUBLE_ENUM_OBJECT) + { + AddTypeFlag(checker::TypeFlag::ETS_ENUM); // TypeFlag enum is full, cannot add new ETS_DOUBLE_ENUM typeflag + } + + NO_COPY_SEMANTIC(ETSDoubleEnumType); + NO_MOVE_SEMANTIC(ETSDoubleEnumType); + + ETSDoubleEnumType() = delete; + ~ETSDoubleEnumType() override = default; + + bool AssignmentSource(TypeRelation *relation, Type *target) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + void Cast(TypeRelation *relation, Type *target) override; + void CastTarget(TypeRelation *relation, Type *source) override; +}; + } // namespace ark::es2panda::checker #endif diff --git a/ets2panda/checker/types/ets/etsObjectTypeConstants.h b/ets2panda/checker/types/ets/etsObjectTypeConstants.h index b3a4e93f35c0672ccd9053edd73c7b07650a9c12..c627166245b9196579cfbae623d8eaa0bc42b47d 100644 --- a/ets2panda/checker/types/ets/etsObjectTypeConstants.h +++ b/ets2panda/checker/types/ets/etsObjectTypeConstants.h @@ -62,8 +62,9 @@ enum class ETSObjectFlags : std::uint64_t { EXTENSION_FUNCTION = 1ULL << 36U, FUNCTIONAL_REFERENCE = 1ULL << 37U, LAZY_IMPORT_OBJECT = 1ULL << 38U, + DOUBLE_ENUM_OBJECT = 1ULL << 39U, - ENUM_OBJECT = INT_ENUM_OBJECT | STRING_ENUM_OBJECT, + ENUM_OBJECT = INT_ENUM_OBJECT | STRING_ENUM_OBJECT | DOUBLE_ENUM_OBJECT, BUILTIN_FLOATING_POINT = BUILTIN_DOUBLE | BUILTIN_FLOAT, BUILTIN_INTEGRAL = BUILTIN_BYTE | BUILTIN_SHORT | BUILTIN_INT | BUILTIN_LONG, diff --git a/ets2panda/checker/types/type.h b/ets2panda/checker/types/type.h index b0565a97d768a97e48fe6ff99f1413f9df69d67a..b038f7e91d5e7c5c755e92864ba755dbe1c8a20a 100644 --- a/ets2panda/checker/types/type.h +++ b/ets2panda/checker/types/type.h @@ -112,6 +112,7 @@ public: bool IsETSAsyncFuncReturnType() const; bool IsETSUnboxableObject() const; bool IsETSPrimitiveOrEnumType() const; + bool IsETSDoubleEnumType() const; bool PossiblyETSNull() const; bool PossiblyETSUndefined() const; diff --git a/ets2panda/compiler/lowering/ets/enumLowering.cpp b/ets2panda/compiler/lowering/ets/enumLowering.cpp index a36144f45d6b2f8c142c0f01cfdc65786e791fbf..976ae61be6232732c67496bf80f7c8b731297ced 100644 --- a/ets2panda/compiler/lowering/ets/enumLowering.cpp +++ b/ets2panda/compiler/lowering/ets/enumLowering.cpp @@ -292,9 +292,16 @@ ir::ClassDeclaration *EnumLoweringPhase::CreateClass(ir::TSEnumDeclaration *cons { auto *ident = Allocator()->New(enumDecl->Key()->Name(), Allocator()); ident->SetRange(enumDecl->Key()->Range()); - auto enumFlag = enumType == EnumType::INT || enumType == EnumType::LONG - ? ir::ClassDefinitionModifiers::INT_ENUM_TRANSFORMED - : ir::ClassDefinitionModifiers::STRING_ENUM_TRANSFORMED; + + ir::ClassDefinitionModifiers enumFlag = ir::ClassDefinitionModifiers::NONE; + if (enumType == EnumType::INT || enumType == EnumType::LONG) { + enumFlag = ir::ClassDefinitionModifiers::INT_ENUM_TRANSFORMED; + } else if (enumType == EnumType::DOUBLE) { + enumFlag = ir::ClassDefinitionModifiers::DOUBLE_ENUM_TRANSFORMED; + } else if (enumType == EnumType::STRING) { + enumFlag = ir::ClassDefinitionModifiers::STRING_ENUM_TRANSFORMED; + } + auto baseClassDefinitionFlag = ir::ClassDefinitionModifiers::CLASS_DECL | enumFlag; auto typeParamsVector = ArenaVector(Allocator()->Adapter()); diff --git a/ets2panda/ir/base/classDefinition.h b/ets2panda/ir/base/classDefinition.h index b1df4a83c3d87e41adca6f6a0de08a2001097695..05f6e46b84566b705484866dfba3efda0fb44611 100644 --- a/ets2panda/ir/base/classDefinition.h +++ b/ets2panda/ir/base/classDefinition.h @@ -60,6 +60,7 @@ enum class ClassDefinitionModifiers : uint32_t { FUNCTIONAL_REFERENCE = 1U << 17U, LAZY_IMPORT_OBJECT_CLASS = 1U << 18U, INIT_IN_CCTOR = 1U << 19U, + DOUBLE_ENUM_TRANSFORMED = 1U << 20U, DECLARATION_ID_REQUIRED = DECLARATION | ID_REQUIRED, ETS_MODULE = NAMESPACE_TRANSFORMED | GLOBAL }; @@ -257,6 +258,11 @@ public: return (Modifiers() & ClassDefinitionModifiers::INT_ENUM_TRANSFORMED) != 0; } + [[nodiscard]] bool IsDoubleEnumTransformed() const noexcept + { + return (Modifiers() & ClassDefinitionModifiers::DOUBLE_ENUM_TRANSFORMED) != 0; + } + [[nodiscard]] bool IsStringEnumTransformed() const noexcept { return (Modifiers() & ClassDefinitionModifiers::STRING_ENUM_TRANSFORMED) != 0; @@ -264,7 +270,7 @@ public: [[nodiscard]] bool IsEnumTransformed() const noexcept { - return IsIntEnumTransformed() || IsStringEnumTransformed(); + return IsIntEnumTransformed() || IsStringEnumTransformed() || IsDoubleEnumTransformed(); } [[nodiscard]] bool IsNamespaceTransformed() const noexcept diff --git a/ets2panda/test/ast/compiler/ets/enum-double-to-int.ets b/ets2panda/test/ast/compiler/ets/enum-double-to-int.ets new file mode 100644 index 0000000000000000000000000000000000000000..98e3d2373327f7860623ba08579b09dfc3bfe3dd --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/enum-double-to-int.ets @@ -0,0 +1,28 @@ +/* + * 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. + */ + +enum Color: double { + Red = 1.1, + Green = 2.2, + Blue = 3.3 +} + +function main(): void { + let c1: int = /* @@ label1 */Color.Blue; + let c2: int = /* @@ label2 */Color.Red + Color.Green; +} + +/* @@@ label1 Error TypeError: Type 'Color' cannot be assigned to type 'Int' */ +/* @@@ label2 Error TypeError: Type 'Double' cannot be assigned to type 'Int' */ \ No newline at end of file diff --git a/ets2panda/test/runtime/ets/enum-double-operations.ets b/ets2panda/test/runtime/ets/enum-double-operations.ets new file mode 100644 index 0000000000000000000000000000000000000000..a63d1acf704872eb1e49ef50465142a13caf9a90 --- /dev/null +++ b/ets2panda/test/runtime/ets/enum-double-operations.ets @@ -0,0 +1,26 @@ +/* + * 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. + */ + +enum Color: double { + Red = 1.1, + Green = 2.2, + Blue = 3.3 +} + +let c1: double = Color.Red + Color.Green; +let c2: double = Color.Blue; + +arktest.assertDoubleEQ(c1, 3.3, 0.0000001); +arktest.assertDoubleEQ(c2, 3.3, 0.0000001); \ No newline at end of file