diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index 0a8939f6c6f0260c02e72b30b1bcd1fbfaece7f4..8c43e166e6bcfbccdfc3e2b3951eaf9e17df72be 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -2741,7 +2741,7 @@ static checker::Type *GetTypeOfStringType(checker::Type *argType, ETSChecker *ch if (argType->IsETSFunctionType()) { return checker->CreateETSStringLiteralType("function"); } - if (argType->IsETSIntEnumType()) { + if (argType->IsETSNumericEnumType()) { return checker->CreateETSStringLiteralType("number"); } if (argType->IsETSStringEnumType()) { diff --git a/ets2panda/checker/ETSAnalyzerHelpers.cpp b/ets2panda/checker/ETSAnalyzerHelpers.cpp index 2075563dcdcb51dd0e0c1ee36fc41d6a775046e7..7c12aa61d3f5a35bd09e68c62d6723b36de031e6 100644 --- a/ets2panda/checker/ETSAnalyzerHelpers.cpp +++ b/ets2panda/checker/ETSAnalyzerHelpers.cpp @@ -536,7 +536,7 @@ void SetTsTypeForUnaryExpression(ETSChecker *checker, ir::UnaryExpression *expr, break; } auto exprType = expr->SetTsType(checker->SelectGlobalIntegerTypeForNumeric(operandType)); - if (!expr->Argument()->TsType()->IsETSIntEnumType()) { + if (!expr->Argument()->TsType()->IsETSNumericEnumType()) { expr->Argument()->SetTsType(exprType); } break; diff --git a/ets2panda/checker/ETSchecker.cpp b/ets2panda/checker/ETSchecker.cpp index 88a71002f8b233850bcbf3444e179df12e41f060..4498becfc72b71ae0b5613743901f61c997d798f 100644 --- a/ets2panda/checker/ETSchecker.cpp +++ b/ets2panda/checker/ETSchecker.cpp @@ -432,7 +432,7 @@ bool ETSChecker::IsClassStaticMethod(checker::ETSObjectType *objType, checker::S [[nodiscard]] TypeFlag ETSChecker::TypeKind(const Type *const type) noexcept { // These types were not present in the ETS_TYPE list. Some of them are omitted intentionally, other are just bugs - static constexpr auto TO_CLEAR = TypeFlag::CONSTANT | TypeFlag::GENERIC | TypeFlag::ETS_INT_ENUM | + static constexpr auto TO_CLEAR = TypeFlag::CONSTANT | TypeFlag::GENERIC | TypeFlag::ETS_NUMERIC_ENUM | TypeFlag::ETS_STRING_ENUM | TypeFlag::READONLY | TypeFlag::BIGINT_LITERAL | TypeFlag::ETS_TYPE_ALIAS | TypeFlag::TYPE_ERROR; diff --git a/ets2panda/checker/ETSchecker.h b/ets2panda/checker/ETSchecker.h index 490d90f351f1c7cf69cd199ee779b4e9b0d080ee..3efe50b92a5330248081dc2890d4d251a4a96f9a 100644 --- a/ets2panda/checker/ETSchecker.h +++ b/ets2panda/checker/ETSchecker.h @@ -374,7 +374,7 @@ public: std::tuple op, bool isEqualOp, std::tuple types); - checker::Type *CheckBinaryBitwiseOperatorForIntEnums(const checker::Type *const leftType, + checker::Type *CheckBinaryBitwiseOperatorForNumericEnums(const checker::Type *const leftType, const checker::Type *const rightType); checker::Type *CheckBinaryOperatorPlus( std::tuple op, bool isEqualOp, diff --git a/ets2panda/checker/ets/arithmetic.cpp b/ets2panda/checker/ets/arithmetic.cpp index 0415b8a2ed995975f24f4a9b63ce0343b3302612..15dfcca78ce6a06df852df8d8be405e3be6ffa38 100644 --- a/ets2panda/checker/ets/arithmetic.cpp +++ b/ets2panda/checker/ets/arithmetic.cpp @@ -129,7 +129,7 @@ static Type *TryConvertToPrimitiveType(ETSChecker *checker, Type *type) return nullptr; } - if (type->IsETSIntEnumType()) { + if (type->IsETSNumericEnumType()) { // Pull out the type argument to BaseEnum if (type->AsETSObjectType()->SuperType() != nullptr && !type->AsETSObjectType()->SuperType()->TypeArguments().empty()) { @@ -286,22 +286,22 @@ static bool TypeIsAppropriateForArithmetic(const checker::Type *type, ETSChecker checker->Relation()->IsSupertypeOf(checker->GetGlobalTypesHolder()->GlobalNumericBuiltinType(), type)); } -static checker::Type *CheckBinaryOperatorForIntEnums(ETSChecker *checker, checker::Type *const leftType, - checker::Type *const rightType) +static checker::Type *CheckBinaryOperatorForNumericEnums(ETSChecker *checker, checker::Type *const leftType, + checker::Type *const rightType) { if (!leftType->IsETSEnumType() && !rightType->IsETSEnumType()) { return nullptr; } if (TypeIsAppropriateForArithmetic(leftType, checker) && TypeIsAppropriateForArithmetic(rightType, checker)) { Type *leftNumeric; - if (leftType->IsETSIntEnumType()) { + if (leftType->IsETSNumericEnumType()) { leftNumeric = checker->MaybeBoxInRelation(TryConvertToPrimitiveType(checker, leftType)); } else { leftNumeric = leftType; } Type *rightNumeric; - if (rightType->IsETSIntEnumType()) { + if (rightType->IsETSNumericEnumType()) { rightNumeric = checker->MaybeBoxInRelation(TryConvertToPrimitiveType(checker, rightType)); } else { rightNumeric = rightType; @@ -331,7 +331,7 @@ checker::Type *ETSChecker::CheckBinaryOperatorMulDivMod( } if (promotedType == nullptr || !CheckIfNumeric(leftType) || !CheckIfNumeric(rightType)) { - auto type = CheckBinaryOperatorForIntEnums(this, leftType, rightType); + auto type = CheckBinaryOperatorForNumericEnums(this, leftType, rightType); if (type != nullptr) { return type; } @@ -342,14 +342,14 @@ checker::Type *ETSChecker::CheckBinaryOperatorMulDivMod( return promotedType; } -checker::Type *ETSChecker::CheckBinaryBitwiseOperatorForIntEnums(const checker::Type *const leftType, - const checker::Type *const rightType) +checker::Type *ETSChecker::CheckBinaryBitwiseOperatorForNumericEnums(const checker::Type *const leftType, + const checker::Type *const rightType) { if (!leftType->IsETSEnumType() && !rightType->IsETSEnumType()) { return nullptr; } if (TypeIsAppropriateForArithmetic(leftType, this) && TypeIsAppropriateForArithmetic(rightType, this)) { - if (leftType->IsETSIntEnumType() && rightType->IsETSIntEnumType()) { + if (leftType->IsETSNumericEnumType() && rightType->IsETSNumericEnumType()) { return GlobalIntBuiltinType(); } if (leftType->IsFloatType() || rightType->IsFloatType()) { @@ -369,7 +369,7 @@ checker::Type *ETSChecker::CheckBinaryBitwiseOperatorForIntEnums(const checker:: static checker::Type *CheckBinaryOperatorPlusForEnums(ETSChecker *checker, checker::Type *const leftType, checker::Type *const rightType) { - if (auto numericType = CheckBinaryOperatorForIntEnums(checker, leftType, rightType); numericType != nullptr) { + if (auto numericType = CheckBinaryOperatorForNumericEnums(checker, leftType, rightType); numericType != nullptr) { return numericType; } if ((leftType->IsETSStringEnumType() && (rightType->IsETSStringType() || rightType->IsETSStringEnumType())) || @@ -464,7 +464,7 @@ checker::Type *ETSChecker::CheckBinaryOperatorShift( auto promotedRightType = GetUnaryOperatorPromotedType(rightType, !isEqualOp); if (promotedLeftType == nullptr || promotedRightType == nullptr || !CheckIfNumeric(promotedLeftType) || !CheckIfNumeric(promotedRightType)) { - auto type = CheckBinaryBitwiseOperatorForIntEnums(leftType, rightType); + auto type = CheckBinaryBitwiseOperatorForNumericEnums(leftType, rightType); if (type != nullptr) { return type; } @@ -512,7 +512,7 @@ checker::Type *ETSChecker::CheckBinaryOperatorBitwise( auto const promotedType = BinaryGetPromotedType(this, leftType, rightType, !isEqualOp); if (promotedType == nullptr || !CheckIfNumeric(rightType) || !CheckIfNumeric(leftType)) { - auto type = CheckBinaryBitwiseOperatorForIntEnums(leftType, rightType); + auto type = CheckBinaryBitwiseOperatorForNumericEnums(leftType, rightType); if (type != nullptr) { return type; } @@ -734,8 +734,8 @@ static bool NonNumericTypesAreAppropriateForComparison(ETSChecker *checker, Type (leftType->IsETSStringType() && rightType->IsETSStringEnumType())) { return true; } - if ((leftType->IsETSPrimitiveType() && rightType->IsETSIntEnumType()) || - (leftType->IsETSIntEnumType() && rightType->IsETSPrimitiveType())) { + if ((leftType->IsETSPrimitiveType() && rightType->IsETSNumericEnumType()) || + (leftType->IsETSNumericEnumType() && rightType->IsETSPrimitiveType())) { return true; } return false; @@ -1038,13 +1038,13 @@ static void TryAddValueOfFlagToStringEnumOperand(ir::Expression *op, const ir::E } } -static void TryAddValueOfFlagToIntEnumOperand(ir::Expression *op, const ir::Expression *otherOp) +static void TryAddValueOfFlagToNumericEnumOperand(ir::Expression *op, const ir::Expression *otherOp) { auto type = op->TsType(); auto otherType = otherOp->TsType(); - if (type->IsETSIntEnumType() && + if (type->IsETSNumericEnumType() && ((otherType->IsETSObjectType() && otherType->AsETSObjectType()->IsBoxedPrimitive()) || - otherType->IsETSIntEnumType())) { + otherType->IsETSNumericEnumType())) { op->AddAstNodeFlags(ir::AstNodeFlags::GENERATE_VALUE_OF); } } @@ -1084,8 +1084,8 @@ static void CheckEnumInOperatorContext(ir::Expression *expression, lexer::TokenT case lexer::TokenType::PUNCTUATOR_BITWISE_XOR: case lexer::TokenType::PUNCTUATOR_LOGICAL_AND: case lexer::TokenType::PUNCTUATOR_LOGICAL_OR: { - TryAddValueOfFlagToIntEnumOperand(left, right); - TryAddValueOfFlagToIntEnumOperand(right, left); + TryAddValueOfFlagToNumericEnumOperand(left, right); + TryAddValueOfFlagToNumericEnumOperand(right, left); break; } default: diff --git a/ets2panda/checker/ets/helpers.cpp b/ets2panda/checker/ets/helpers.cpp index 58e96dfd9c6d89acd233cac5ed2519b140b7b588..8c39fb53719d7a403f2f020339385c215eed5617 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -419,7 +419,7 @@ Type *ETSChecker::ApplyUnaryOperatorPromotion(ir::Expression *expr, Type *type, { Type *unboxedType = isCondExpr ? MaybeUnboxConditionalInRelation(type) : MaybeUnboxInRelation(type); - if (type != nullptr && type->IsETSIntEnumType()) { + if (type != nullptr && type->IsETSNumericEnumType()) { expr->AddAstNodeFlags(ir::AstNodeFlags::GENERATE_VALUE_OF); unboxedType = type->AsETSEnumType()->GetBaseEnumElementType(this); } diff --git a/ets2panda/checker/ets/typeCreation.cpp b/ets2panda/checker/ets/typeCreation.cpp index 0647747376011ea0ca40b6d0e99112785e9e2462..86ba091e7c1987bd7b629dc804b7f97ca3968adf 100644 --- a/ets2panda/checker/ets/typeCreation.cpp +++ b/ets2panda/checker/ets/typeCreation.cpp @@ -367,14 +367,21 @@ ETSObjectType *ETSChecker::CreateETSObjectType(ir::AstNode *declNode, ETSObjectF auto const [name, internalName] = GetObjectTypeDeclNames(declNode); ETSObjectType *objectType = nullptr; if (declNode->IsClassDefinition() && (declNode->AsClassDefinition()->IsEnumTransformed())) { - if (declNode->AsClassDefinition()->IsIntEnumTransformed()) { - objectType = - ProgramAllocator()->New(ProgramAllocator(), name, internalName, declNode, Relation()); + ETSEnumType *enumObject = nullptr; + if (declNode->AsClassDefinition()->IsNumericEnumTransformed()) { + enumObject = ProgramAllocator()->New(ProgramAllocator(), name, internalName, declNode, + Relation()); } else { ES2PANDA_ASSERT(declNode->AsClassDefinition()->IsStringEnumTransformed()); - objectType = ProgramAllocator()->New(ProgramAllocator(), name, internalName, declNode, + enumObject = ProgramAllocator()->New(ProgramAllocator(), name, internalName, declNode, Relation()); } + + ir::TSEnumDeclaration *originalDecl = declNode->AsClassDefinition()->OrigEnumDecl()->AsTSEnumDeclaration(); + if (originalDecl->TypeAnnotation() != nullptr) { + enumObject->SetEnumType(originalDecl->TypeAnnotation(), this); + } + return enumObject; } else if (internalName == compiler::Signatures::BUILTIN_ARRAY) { objectType = ProgramAllocator()->New(ProgramAllocator(), name, std::make_tuple(declNode, flags, Relation())); diff --git a/ets2panda/checker/types/ets/etsEnumType.cpp b/ets2panda/checker/types/ets/etsEnumType.cpp index 233a403e0501e8a662fba2b7bd2ad9c056b0df62..15d64090691b985146934313492fcfc0fbcbbc41 100644 --- a/ets2panda/checker/types/ets/etsEnumType.cpp +++ b/ets2panda/checker/types/ets/etsEnumType.cpp @@ -21,6 +21,15 @@ namespace ark::es2panda::checker { +void ETSEnumType::SetEnumType(ir::TypeNode *typeNode, ETSChecker *checker) noexcept +{ + ES2PANDA_ASSERT(typeNode != nullptr); + ES2PANDA_ASSERT(checker != nullptr); + + typeNode->Check(checker); + enumType_ = typeNode->GetType(checker); +} + Type *ETSEnumType::GetBaseEnumElementType(ETSChecker *checker) { return checker->MaybeUnboxType(SuperType()->TypeArguments()[0]); @@ -78,7 +87,7 @@ void ETSStringEnumType::CastTarget(TypeRelation *relation, Type *source) conversion::Forbidden(relation); } -bool ETSIntEnumType::AssignmentSource(TypeRelation *relation, Type *target) +bool ETSNumericEnumType::AssignmentSource(TypeRelation *relation, Type *target) { bool result = false; if (target->IsETSObjectType()) { @@ -105,12 +114,12 @@ bool ETSIntEnumType::AssignmentSource(TypeRelation *relation, Type *target) return relation->IsTrue(); } -void ETSIntEnumType::AssignmentTarget(TypeRelation *relation, Type *source) +void ETSNumericEnumType::AssignmentTarget(TypeRelation *relation, Type *source) { relation->IsIdenticalTo(this, source) ? relation->Result(true) : relation->Result(false); } -void ETSIntEnumType::Cast(TypeRelation *const relation, Type *const target) +void ETSNumericEnumType::Cast(TypeRelation *const relation, Type *const target) { if (relation->IsIdenticalTo(this, target)) { relation->Result(true); @@ -124,7 +133,7 @@ void ETSIntEnumType::Cast(TypeRelation *const relation, Type *const target) conversion::Forbidden(relation); } -void ETSIntEnumType::CastTarget(TypeRelation *relation, Type *source) +void ETSNumericEnumType::CastTarget(TypeRelation *relation, Type *source) { if (source->IsIntType() || source->IsBuiltinNumeric()) { relation->RaiseError(diagnostic::ENUM_DEPRECATED_CAST, {source, this}, relation->GetNode()->Start()); diff --git a/ets2panda/checker/types/ets/etsEnumType.h b/ets2panda/checker/types/ets/etsEnumType.h index 3005b78053a406f8ef707e2410d7d7cc090593a4..430f2d10a964a0152fbc9ed4e88edeab767dca85 100644 --- a/ets2panda/checker/types/ets/etsEnumType.h +++ b/ets2panda/checker/types/ets/etsEnumType.h @@ -91,6 +91,19 @@ public: } return false; } + + [[nodiscard]] Type *EnumType() noexcept + { + return enumType_; + } + + void SetEnumType(ir::TypeNode *typeNode, ETSChecker *checker) noexcept; + + [[nodiscard]] const Type *EnumType() const noexcept + { + return enumType_; + } + Type *GetBaseEnumElementType(ETSChecker *checker); private: @@ -118,22 +131,23 @@ private: private: ArenaMap memberNameToOrdinal_; ir::ArrayExpression *membersValues_; + Type *enumType_ {nullptr}; }; -class ETSIntEnumType : public ETSEnumType { +class ETSNumericEnumType : public ETSEnumType { public: - explicit ETSIntEnumType(ThreadSafeArenaAllocator *allocator, util::StringView name, util::StringView internalName, - ir::AstNode *declNode, TypeRelation *relation) - : ETSEnumType(allocator, name, internalName, declNode, relation, ETSObjectFlags::INT_ENUM_OBJECT) + explicit ETSNumericEnumType(ThreadSafeArenaAllocator *allocator, util::StringView name, + util::StringView internalName, ir::AstNode *declNode, TypeRelation *relation) + : ETSEnumType(allocator, name, internalName, declNode, relation, ETSObjectFlags::NUMERIC_ENUM_OBJECT) { - AddTypeFlag(checker::TypeFlag::ETS_INT_ENUM); + AddTypeFlag(checker::TypeFlag::ETS_NUMERIC_ENUM); } - NO_COPY_SEMANTIC(ETSIntEnumType); - NO_MOVE_SEMANTIC(ETSIntEnumType); + NO_COPY_SEMANTIC(ETSNumericEnumType); + NO_MOVE_SEMANTIC(ETSNumericEnumType); - ETSIntEnumType() = delete; - ~ETSIntEnumType() override = default; + ETSNumericEnumType() = delete; + ~ETSNumericEnumType() override = default; bool AssignmentSource(TypeRelation *relation, Type *target) override; void AssignmentTarget(TypeRelation *relation, Type *source) override; diff --git a/ets2panda/checker/types/ets/etsObjectType.cpp b/ets2panda/checker/types/ets/etsObjectType.cpp index f4aecd59add6a5ee39d6c2d49ca7b9dd89b37b84..2186a8426d6d42acd745a4c7e921e662138c280c 100644 --- a/ets2panda/checker/types/ets/etsObjectType.cpp +++ b/ets2panda/checker/types/ets/etsObjectType.cpp @@ -1338,11 +1338,19 @@ ETSObjectType *ETSObjectType::CreateETSObjectType(ir::AstNode *declNode, ETSObje auto const [name, internalName] = GetObjectTypeDeclNames(declNode); if (declNode->IsClassDefinition() && (declNode->AsClassDefinition()->IsEnumTransformed())) { - if (declNode->AsClassDefinition()->IsIntEnumTransformed()) { - return Allocator()->New(Allocator(), name, internalName, declNode, GetRelation()); + ETSEnumType *enumObject = nullptr; + + if (declNode->AsClassDefinition()->IsNumericEnumTransformed()) { + enumObject = Allocator()->New(Allocator(), name, internalName, declNode, GetRelation()); + } else { + ES2PANDA_ASSERT(declNode->AsClassDefinition()->IsStringEnumTransformed()); + enumObject = Allocator()->New(Allocator(), name, internalName, declNode, GetRelation()); + } + ir::TSEnumDeclaration *originalDecl = declNode->AsClassDefinition()->OrigEnumDecl()->AsTSEnumDeclaration(); + if (originalDecl->TypeAnnotation() != nullptr) { + enumObject->SetEnumType(originalDecl->TypeAnnotation(), GetETSChecker()); } - ES2PANDA_ASSERT(declNode->AsClassDefinition()->IsStringEnumTransformed()); - return Allocator()->New(Allocator(), name, internalName, declNode, GetRelation()); + return enumObject; } if (internalName == compiler::Signatures::BUILTIN_ARRAY) { return Allocator()->New(Allocator(), name, diff --git a/ets2panda/checker/types/ets/etsObjectTypeConstants.h b/ets2panda/checker/types/ets/etsObjectTypeConstants.h index b3a4e93f35c0672ccd9053edd73c7b07650a9c12..52db7d8ad30f1d9bdc3f24acd3e1d9efb82034c0 100644 --- a/ets2panda/checker/types/ets/etsObjectTypeConstants.h +++ b/ets2panda/checker/types/ets/etsObjectTypeConstants.h @@ -56,14 +56,14 @@ enum class ETSObjectFlags : std::uint64_t { BUILTIN_ARRAY = 1ULL << 32U, BUILTIN_READONLY_ARRAY = 1ULL << 33U, - INT_ENUM_OBJECT = 1ULL << 34U, + NUMERIC_ENUM_OBJECT = 1ULL << 34U, STRING_ENUM_OBJECT = 1ULL << 35U, EXTENSION_FUNCTION = 1ULL << 36U, FUNCTIONAL_REFERENCE = 1ULL << 37U, LAZY_IMPORT_OBJECT = 1ULL << 38U, - ENUM_OBJECT = INT_ENUM_OBJECT | STRING_ENUM_OBJECT, + ENUM_OBJECT = NUMERIC_ENUM_OBJECT | STRING_ENUM_OBJECT, BUILTIN_FLOATING_POINT = BUILTIN_DOUBLE | BUILTIN_FLOAT, BUILTIN_INTEGRAL = BUILTIN_BYTE | BUILTIN_SHORT | BUILTIN_INT | BUILTIN_LONG, @@ -76,7 +76,7 @@ enum class ETSObjectFlags : std::uint64_t { VALUE_TYPED = BUILTIN_BOOLEAN | BUILTIN_CHAR | BUILTIN_NUMERIC | BUILTIN_BIGINT | STRING, UNBOXABLE_TYPE = BUILTIN_BOOLEAN | BUILTIN_CHAR | BUILTIN_NUMERIC, BUILTIN_TYPE = BUILTIN_STRING | BUILTIN_BIGINT | UNBOXABLE_TYPE, - CONVERTIBLE_TO_NUMERIC = BUILTIN_NUMERIC | BUILTIN_CHAR | INT_ENUM_OBJECT, + CONVERTIBLE_TO_NUMERIC = BUILTIN_NUMERIC | BUILTIN_CHAR | NUMERIC_ENUM_OBJECT, GLOBAL_CLASS = CLASS | GLOBAL, FUNCTIONAL_INTERFACE = INTERFACE | ABSTRACT | FUNCTIONAL, diff --git a/ets2panda/checker/types/typeFlag.h b/ets2panda/checker/types/typeFlag.h index 5f01ae82252c6d2fcf311bbdfc2804c5f010a98c..3bd1872056dbf072e1b4de6afbca9d1ab6d6e08a 100644 --- a/ets2panda/checker/types/typeFlag.h +++ b/ets2panda/checker/types/typeFlag.h @@ -70,7 +70,7 @@ enum class TypeFlag : uint64_t { WILDCARD = 1ULL << 42ULL, // new A() ETS_TYPE_PARAMETER = 1ULL << 43ULL, // ETS type parameter GENERIC = 1ULL << 45ULL, // ETS Generic - ETS_INT_ENUM = 1ULL << 46ULL, // ETS Enum + ETS_NUMERIC_ENUM = 1ULL << 46ULL, // ETS Enum ETS_STRING_ENUM = 1ULL << 47ULL, // ETS string-type Enumeration GRADUAL_TYPE = 1ULL << 48ULL, // gradual type GETTER = 1ULL << 49ULL, // ETS Getter @@ -93,9 +93,9 @@ enum class TypeFlag : uint64_t { ETS_FLOATING_POINT = FLOAT | DOUBLE, ETS_NUMERIC = ETS_INTEGRAL_NUMERIC | ETS_FLOATING_POINT, ETS_INTEGRAL = ETS_INTEGRAL_NUMERIC | CHAR, - ETS_ENUM = ETS_INT_ENUM | ETS_STRING_ENUM, + ETS_ENUM = ETS_NUMERIC_ENUM | ETS_STRING_ENUM, ETS_ARRAY_INDEX = BYTE | SHORT | INT, - ETS_CONVERTIBLE_TO_NUMERIC = ETS_NUMERIC | CHAR | ETS_INT_ENUM, + ETS_CONVERTIBLE_TO_NUMERIC = ETS_NUMERIC | CHAR | ETS_NUMERIC_ENUM, VALID_SWITCH_TYPE = ETS_INTEGRAL, ETS_ARRAY_OR_OBJECT = ETS_ARRAY | ETS_OBJECT, ANY_OR_UNKNOWN = ANY | UNKNOWN, diff --git a/ets2panda/checker/types/typeMapping.h b/ets2panda/checker/types/typeMapping.h index 84e3ba9cfef6fdf49983f38bf38c92e203b2e5b3..005678779ab7eca01fc2cf69c47ec8ccd249930f 100644 --- a/ets2panda/checker/types/typeMapping.h +++ b/ets2panda/checker/types/typeMapping.h @@ -64,7 +64,7 @@ _(TypeFlag::ETS_TYPE_PARAMETER, ETSTypeParameter) \ _(TypeFlag::ETS_NONNULLISH, ETSNonNullishType) \ _(TypeFlag::ETS_READONLY, ETSReadonlyType) \ - _(TypeFlag::ETS_INT_ENUM, ETSIntEnumType) \ + _(TypeFlag::ETS_NUMERIC_ENUM, ETSNumericEnumType) \ _(TypeFlag::ETS_STRING_ENUM, ETSStringEnumType) \ _(TypeFlag::ETS_ENUM, ETSEnumType) \ _(TypeFlag::ETS_EXTENSION_FUNC_HELPER, ETSExtensionFuncHelperType) \ diff --git a/ets2panda/checker/types/typeRelation.cpp b/ets2panda/checker/types/typeRelation.cpp index c4b2fbb0869b7b727e396bd6b0eafb50eb559609..87f9f9261a869b4e6d445150dbd3f4fc8323f94e 100644 --- a/ets2panda/checker/types/typeRelation.cpp +++ b/ets2panda/checker/types/typeRelation.cpp @@ -234,7 +234,7 @@ bool TypeRelation::IsLegalBoxedPrimitiveConversion(Type *target, Type *source) Type *targetUnboxedType = checker->MaybeUnboxType(target); Type *sourceUnboxedType = checker->MaybeUnboxType(source); - if (source->IsETSIntEnumType()) { + if (source->IsETSNumericEnumType()) { targetUnboxedType = checker->GlobalIntType(); } diff --git a/ets2panda/compiler/core/ETSemitter.cpp b/ets2panda/compiler/core/ETSemitter.cpp index 1151febda86663cf246872e802c7f7cee77ad1ef..31b4516019e256967687c3d733a84eaa5bcdd0fb 100644 --- a/ets2panda/compiler/core/ETSemitter.cpp +++ b/ets2panda/compiler/core/ETSemitter.cpp @@ -884,10 +884,10 @@ static pandasm::AnnotationElement ProcessETSEnumType(std::string &baseName, cons ES2PANDA_ASSERT(init->AsMemberExpression()->PropVar() != nullptr); auto declNode = init->AsMemberExpression()->PropVar()->Declaration()->Node(); auto *initValue = declNode->AsClassProperty()->OriginEnumMember()->Init(); - if (type->IsETSIntEnumType()) { + if (type->IsETSNumericEnumType()) { auto enumValue = static_cast(initValue->AsNumberLiteral()->Number().GetInt()); - auto intEnumValue = pandasm::ScalarValue::Create(enumValue); - return pandasm::AnnotationElement {baseName, std::make_unique(intEnumValue)}; + auto numericEnumValue = pandasm::ScalarValue::Create(enumValue); + return pandasm::AnnotationElement {baseName, std::make_unique(numericEnumValue)}; } ES2PANDA_ASSERT(type->IsETSStringEnumType()); auto enumValue = initValue->AsStringLiteral()->Str().Mutf8(); diff --git a/ets2panda/compiler/lowering/ets/enumLowering.cpp b/ets2panda/compiler/lowering/ets/enumLowering.cpp index a36144f45d6b2f8c142c0f01cfdc65786e791fbf..6c2c53e4a44a798baf305a0e71f0a3dde10543cc 100644 --- a/ets2panda/compiler/lowering/ets/enumLowering.cpp +++ b/ets2panda/compiler/lowering/ets/enumLowering.cpp @@ -15,6 +15,7 @@ #include "enumLowering.h" #include +#include #include #include "checker/ETSchecker.h" @@ -83,10 +84,27 @@ bool EnumLoweringPhase::CheckEnumMemberType(const ArenaVector &en { for (auto *member : enumMembers) { auto *init = member->AsTSEnumMember()->Init(); + + auto mixedTypesError = [&]() { + LogError(diagnostic::ERROR_ARKTS_NO_ENUM_MIXED_TYPES, {}, init->Start()); + hasLoggedError = true; + }; + + if constexpr (TYPE_NODE == EnumLoweringPhase::EnumType::STRING) { + if (!init->IsStringLiteral()) { + mixedTypesError(); + } + continue; + } + + if (!init->IsNumberLiteral()) { + mixedTypesError(); + continue; + } + if constexpr (TYPE_NODE == EnumLoweringPhase::EnumType::INT) { - if (!init->IsNumberLiteral() || !init->AsNumberLiteral()->Number().IsInteger()) { - LogError(diagnostic::ERROR_ARKTS_NO_ENUM_MIXED_TYPES, {}, init->Start()); - hasLoggedError = true; + if (!init->AsNumberLiteral()->Number().IsInteger()) { + mixedTypesError(); continue; } @@ -98,33 +116,42 @@ bool EnumLoweringPhase::CheckEnumMemberType(const ArenaVector &en // Invalid generated value. if (member->AsTSEnumMember()->IsGenerated() && init->AsNumberLiteral()->Number().GetLong() == std::numeric_limits::min()) { - LogError(diagnostic::ERROR_ARKTS_NO_ENUM_MIXED_TYPES, {}, init->Start()); + LogError(diagnostic::ENUM_NON_INT_TYPE_ALL_ITEMS_INIT, {}, init->Start()); hasLoggedError = true; } - } else if constexpr (TYPE_NODE == EnumLoweringPhase::EnumType::DOUBLE) { - if (!init->IsNumberLiteral() || - !(init->AsNumberLiteral()->Number().IsDouble() || init->AsNumberLiteral()->Number().IsFloat())) { - LogError(diagnostic::ERROR_ARKTS_NO_ENUM_MIXED_TYPES, {}, init->Start()); - hasLoggedError = true; - - continue; + } else if constexpr (TYPE_NODE == EnumLoweringPhase::EnumType::FLOAT) { + if (!init->AsNumberLiteral()->Number().IsFloat()) { + mixedTypesError(); } + if (member->AsTSEnumMember()->IsGenerated()) { - LogError(diagnostic::ERROR_ARKTS_NO_ENUM_MIXED_TYPES, {}, init->Start()); + LogError(diagnostic::ENUM_NON_INT_TYPE_ALL_ITEMS_INIT, {}, init->Start()); hasLoggedError = true; } - } else if constexpr (TYPE_NODE == EnumLoweringPhase::EnumType::STRING) { - if (!init->IsStringLiteral()) { - LogError(diagnostic::ERROR_ARKTS_NO_ENUM_MIXED_TYPES, {}, init->Start()); - hasLoggedError = true; + continue; + } else if constexpr (TYPE_NODE == EnumLoweringPhase::EnumType::DOUBLE) { + if (!init->AsNumberLiteral()->Number().IsDouble()) { + mixedTypesError(); } + if (member->AsTSEnumMember()->IsGenerated()) { - LogError(diagnostic::ENUM_STRING_TYPE_ALL_ITEMS_INIT, {}, init->Start()); + LogError(diagnostic::ENUM_NON_INT_TYPE_ALL_ITEMS_INIT, {}, init->Start()); hasLoggedError = true; } + continue; + } else if constexpr (TYPE_NODE == EnumLoweringPhase::EnumType::BYTE) { + if (!init->AsNumberLiteral()->Number().IsByte()) { + mixedTypesError(); + } + continue; + } else if constexpr (TYPE_NODE == EnumLoweringPhase::EnumType::SHORT) { + if (!init->AsNumberLiteral()->Number().IsShort()) { + mixedTypesError(); + } + continue; } else { - static_assert(TYPE_NODE == - EnumLoweringPhase::EnumType::NOT_SPECIFIED); // Unsupported TypeNode in CheckEnumMemberType. + ES2PANDA_UNREACHABLE(); // static_assert(TYPE_NODE == EnumLoweringPhase::EnumType::NOT_SPECIFIED); // + // Unsupported TypeNode in CheckEnumMemberType. } } return !hasLoggedError; @@ -196,6 +223,21 @@ ir::Expression *EnumLoweringPhase::CheckEnumTypeForItemFields(EnumType enumType, valueArgument = AllocNode(lexer::Number(enumFieldValue)); break; } + case EnumType::FLOAT: { + auto enumFieldValue = member->AsTSEnumMember()->Init()->AsNumberLiteral()->Number().GetValue(); + valueArgument = AllocNode(lexer::Number(enumFieldValue)); + break; + } + case EnumType::BYTE: { + auto enumFieldValue = member->AsTSEnumMember()->Init()->AsNumberLiteral()->Number().GetValue(); + valueArgument = AllocNode(lexer::Number(enumFieldValue)); + break; + } + case EnumType::SHORT: { + auto enumFieldValue = member->AsTSEnumMember()->Init()->AsNumberLiteral()->Number().GetValue(); + valueArgument = AllocNode(lexer::Number(enumFieldValue)); + break; + } case EnumType::STRING: { auto enumFieldValue = member->AsTSEnumMember()->Init()->AsStringLiteral()->Str(); valueArgument = AllocNode(enumFieldValue); @@ -276,6 +318,15 @@ static ir::TypeNode *CreateType(public_lib::Context *ctx, EnumLoweringPhase::Enu case EnumLoweringPhase::EnumType::DOUBLE: { return ctx->AllocNode(ir::PrimitiveType::DOUBLE, ctx->Allocator()); } + case EnumLoweringPhase::EnumType::FLOAT: { + return ctx->AllocNode(ir::PrimitiveType::FLOAT, ctx->Allocator()); + } + case EnumLoweringPhase::EnumType::BYTE: { + return ctx->AllocNode(ir::PrimitiveType::BYTE, ctx->Allocator()); + } + case EnumLoweringPhase::EnumType::SHORT: { + return ctx->AllocNode(ir::PrimitiveType::SHORT, ctx->Allocator()); + } case EnumLoweringPhase::EnumType::STRING: { return MakeTypeReference(ctx, EnumLoweringPhase::STRING_REFERENCE_TYPE); } @@ -292,9 +343,8 @@ 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; + auto enumFlag = !(enumType == EnumType::STRING) ? ir::ClassDefinitionModifiers::NUMERIC_ENUM_TRANSFORMED + : ir::ClassDefinitionModifiers::STRING_ENUM_TRANSFORMED; auto baseClassDefinitionFlag = ir::ClassDefinitionModifiers::CLASS_DECL | enumFlag; auto typeParamsVector = ArenaVector(Allocator()->Adapter()); @@ -327,7 +377,13 @@ ir::ClassDeclaration *EnumLoweringPhase::CreateClass(ir::TSEnumDeclaration *cons if (!enumDecl->IsDeclare()) { CreateCCtorForEnumClass(classDef); } - CreateCtorForEnumClass(classDef, enumType); + ir::TypeNode *enumTypeAnnotation; + if (enumDecl->TypeAnnotation() != nullptr) { + enumTypeAnnotation = enumDecl->TypeAnnotation()->Clone(Allocator(), classDef); + } else { + enumTypeAnnotation = CreateType(context_, enumType); + } + CreateCtorForEnumClass(classDef, enumTypeAnnotation); classDecl->SetRange(enumDecl->Range()); return classDecl; @@ -375,7 +431,7 @@ ir::ClassProperty *EnumLoweringPhase::CreateOrdinalField(ir::ClassDefinition *co } ir::ScriptFunction *EnumLoweringPhase::CreateFunctionForCtorOfEnumClass(ir::ClassDefinition *const enumClass, - EnumType enumType) + ir::TypeNode *enumType) { ArenaVector params(Allocator()->Adapter()); @@ -383,8 +439,7 @@ ir::ScriptFunction *EnumLoweringPhase::CreateFunctionForCtorOfEnumClass(ir::Clas auto *const inputOrdinalParam = MakeFunctionParam(context_, PARAM_ORDINAL, intTypeAnnotation); params.push_back(inputOrdinalParam); - ir::TypeNode *typeAnnotation = CreateType(context_, enumType); - auto *const inputValueParam = MakeFunctionParam(context_, PARAM_VALUE, typeAnnotation); + auto *const inputValueParam = MakeFunctionParam(context_, PARAM_VALUE, enumType); params.push_back(inputValueParam); auto *id = AllocNode("constructor", Allocator()); @@ -438,7 +493,7 @@ ir::ScriptFunction *EnumLoweringPhase::CreateFunctionForCtorOfEnumClass(ir::Clas return func; } -void EnumLoweringPhase::CreateCtorForEnumClass(ir::ClassDefinition *const enumClass, EnumType enumType) +void EnumLoweringPhase::CreateCtorForEnumClass(ir::ClassDefinition *const enumClass, ir::TypeNode *enumType) { auto *func = CreateFunctionForCtorOfEnumClass(enumClass, enumType); auto *funcExpr = AllocNode(func); @@ -491,60 +546,61 @@ void EnumLoweringPhase::ProcessEnumClassDeclaration(ir::TSEnumDeclaration *const } } -template -ir::ClassDeclaration *EnumLoweringPhase::CreateEnumIntClassFromEnumDeclaration(ir::TSEnumDeclaration *const enumDecl, - const DeclarationFlags flags) +template +ir::ClassDeclaration *EnumLoweringPhase::CreateEnumNumericClassFromEnumDeclaration( + ir::TSEnumDeclaration *const enumDecl, const DeclarationFlags flags) { - EnumType enumType = EnumType::INT; - if constexpr (TYPE == ir::PrimitiveType::LONG) { - enumType = EnumType::LONG; + ir::PrimitiveType enumType = ir::PrimitiveType::VOID; + + if constexpr (TYPE == EnumType::INT) { + enumType = ir::PrimitiveType::INT; + } else if constexpr (TYPE == EnumType::LONG) { + enumType = ir::PrimitiveType::LONG; + } else if constexpr (TYPE == EnumType::FLOAT) { + enumType = ir::PrimitiveType::FLOAT; + } else if constexpr (TYPE == EnumType::DOUBLE) { + enumType = ir::PrimitiveType::DOUBLE; + } else if constexpr (TYPE == EnumType::SHORT) { + enumType = ir::PrimitiveType::SHORT; + } else if constexpr (TYPE == EnumType::BYTE) { + enumType = ir::PrimitiveType::BYTE; } - auto *const enumClassDecl = CreateClass(enumDecl, flags, enumType); + auto *const enumClassDecl = CreateClass(enumDecl, flags, TYPE); auto *const enumClass = enumClassDecl->Definition(); - CreateEnumItemFields(enumDecl, enumClass, enumType); + CreateEnumItemFields(enumDecl, enumClass, TYPE); auto *const namesArrayIdent = CreateEnumNamesArray(enumDecl, enumClass); - auto *const valuesArrayIdent = CreateEnumValuesArray(enumDecl, enumClass); - auto *const stringValuesArrayIdent = CreateEnumStringValuesArray(enumDecl, enumClass); - auto *const itemsArrayIdent = CreateEnumItemsArray(enumDecl, enumClass); - CreateEnumGetNameMethod(enumDecl, enumClass, namesArrayIdent); - - CreateEnumGetValueOfMethod(enumDecl, enumClass, namesArrayIdent, itemsArrayIdent); - - CreateEnumFromValueMethod(enumDecl, enumClass, valuesArrayIdent, itemsArrayIdent, TYPE); - - CreateEnumValueOfMethod(enumDecl, enumClass, valuesArrayIdent, TYPE); - - CreateEnumToStringMethod(enumDecl, enumClass, stringValuesArrayIdent); - - CreateEnumValuesMethod(enumDecl, enumClass, itemsArrayIdent); - - CreateEnumGetOrdinalMethod(enumDecl, enumClass); - - CreateEnumDollarGetMethod(enumDecl, enumClass); - - SetDefaultPositionInUnfilledClassNodes(enumClassDecl, enumDecl); - - enumClassDecl->SetParent(enumDecl->Parent()); - ProcessEnumClassDeclaration(enumDecl, flags, enumClassDecl); - - return enumClassDecl; -} - -template -ir::ClassDeclaration *EnumLoweringPhase::CreateEnumFloatClassFromEnumDeclaration(ir::TSEnumDeclaration *const enumDecl, - const DeclarationFlags flags) -{ - EnumType enumType = EnumType::DOUBLE; - - auto *const enumClassDecl = CreateClass(enumDecl, flags, enumType); - auto *const enumClass = enumClassDecl->Definition(); + ir::Identifier *valuesArrayIdent; + if (TYPE != EnumType::STRING) { + switch (enumType) { + case (ir::PrimitiveType::INT): + valuesArrayIdent = CreateEnumValuesArray(enumDecl, enumClass); + break; + case ir::PrimitiveType::BYTE: + valuesArrayIdent = CreateEnumValuesArray(enumDecl, enumClass); + break; + case ir::PrimitiveType::LONG: + valuesArrayIdent = CreateEnumValuesArray(enumDecl, enumClass); + break; + case ir::PrimitiveType::SHORT: + valuesArrayIdent = CreateEnumValuesArray(enumDecl, enumClass); + break; + case ir::PrimitiveType::FLOAT: + valuesArrayIdent = CreateEnumValuesArray(enumDecl, enumClass); + break; + case ir::PrimitiveType::DOUBLE: + valuesArrayIdent = CreateEnumValuesArray(enumDecl, enumClass); + break; + case ir::PrimitiveType::BOOLEAN: + case ir::PrimitiveType::CHAR: + case ir::PrimitiveType::VOID: + ES2PANDA_UNREACHABLE(); + break; + } + } - CreateEnumItemFields(enumDecl, enumClass, enumType); - auto *const namesArrayIdent = CreateEnumNamesArray(enumDecl, enumClass); - auto *const valuesArrayIdent = CreateEnumValuesArray(enumDecl, enumClass); auto *const stringValuesArrayIdent = CreateEnumStringValuesArray(enumDecl, enumClass); auto *const itemsArrayIdent = CreateEnumItemsArray(enumDecl, enumClass); @@ -552,9 +608,13 @@ ir::ClassDeclaration *EnumLoweringPhase::CreateEnumFloatClassFromEnumDeclaration CreateEnumGetValueOfMethod(enumDecl, enumClass, namesArrayIdent, itemsArrayIdent); - CreateEnumFromValueMethod(enumDecl, enumClass, valuesArrayIdent, itemsArrayIdent, TYPE); - - CreateEnumValueOfMethod(enumDecl, enumClass, valuesArrayIdent, TYPE); + if (TYPE != EnumType::STRING) { + CreateEnumFromValueMethod(enumDecl, enumClass, valuesArrayIdent, itemsArrayIdent, enumType); + CreateEnumValueOfMethod(enumDecl, enumClass, valuesArrayIdent, enumType); + } else { + CreateEnumFromValueMethod(enumDecl, enumClass, stringValuesArrayIdent, itemsArrayIdent, std::nullopt); + CreateEnumValueOfMethod(enumDecl, enumClass, stringValuesArrayIdent, std::nullopt); + } CreateEnumToStringMethod(enumDecl, enumClass, stringValuesArrayIdent); @@ -572,40 +632,6 @@ ir::ClassDeclaration *EnumLoweringPhase::CreateEnumFloatClassFromEnumDeclaration return enumClassDecl; } -ir::ClassDeclaration *EnumLoweringPhase::CreateEnumStringClassFromEnumDeclaration(ir::TSEnumDeclaration *const enumDecl, - const DeclarationFlags flags) -{ - auto *const enumClassDecl = CreateClass(enumDecl, flags, EnumType::STRING); - auto *const enumClass = enumClassDecl->Definition(); - - CreateEnumItemFields(enumDecl, enumClass, EnumType::STRING); - auto *const namesArrayIdent = CreateEnumNamesArray(enumDecl, enumClass); - auto *const stringValuesArrayIdent = CreateEnumStringValuesArray(enumDecl, enumClass); - auto *const itemsArrayIdent = CreateEnumItemsArray(enumDecl, enumClass); - - CreateEnumGetNameMethod(enumDecl, enumClass, namesArrayIdent); - - CreateEnumGetValueOfMethod(enumDecl, enumClass, namesArrayIdent, itemsArrayIdent); - - CreateEnumFromValueMethod(enumDecl, enumClass, stringValuesArrayIdent, itemsArrayIdent, std::nullopt); - - CreateEnumValueOfMethod(enumDecl, enumClass, stringValuesArrayIdent, std::nullopt); - - CreateEnumToStringMethod(enumDecl, enumClass, stringValuesArrayIdent); - - CreateEnumValuesMethod(enumDecl, enumClass, itemsArrayIdent); - - CreateEnumGetOrdinalMethod(enumDecl, enumClass); - - CreateEnumDollarGetMethod(enumDecl, enumClass); - - SetDefaultPositionInUnfilledClassNodes(enumClassDecl, enumDecl); - - enumClassDecl->SetParent(enumDecl->Parent()); - ProcessEnumClassDeclaration(enumDecl, flags, enumClassDecl); - return enumClassDecl; -} - static EnumLoweringPhase::DeclarationFlags GetDeclFlags(ir::TSEnumDeclaration *const enumDecl) { return {enumDecl->Parent() != nullptr && enumDecl->Parent()->IsETSModule() && @@ -615,39 +641,6 @@ static EnumLoweringPhase::DeclarationFlags GetDeclFlags(ir::TSEnumDeclaration *c enumDecl->Parent()->AsClassDefinition()->IsNamespaceTransformed()}; } -checker::AstNodePtr EnumLoweringPhase::TransformAnnotedEnumChildrenRecursively(checker::AstNodePtr &ast) -{ - auto *enumDecl = ast->AsTSEnumDeclaration(); - auto const flags = GetDeclFlags(enumDecl); - if (!flags.IsValid() || enumDecl->Members().empty()) { - return ast; - } - - bool hasLoggedError = false; - bool hasLongLiteral = false; - auto *const itemInit = enumDecl->Members().front()->AsTSEnumMember()->Init(); - ir::TypeNode *typeAnnotation = enumDecl->TypeNodes(); - - ir::PrimitiveType primitiveType = typeAnnotation->AsETSPrimitiveType()->GetPrimitiveType(); - if ((primitiveType == ir::PrimitiveType::INT || primitiveType == ir::PrimitiveType::LONG) && - CheckEnumMemberType(enumDecl->Members(), hasLoggedError, hasLongLiteral)) { - auto res = hasLongLiteral ? CreateEnumIntClassFromEnumDeclaration(enumDecl, flags) - : CreateEnumIntClassFromEnumDeclaration(enumDecl, flags); - return res; - } - - if ((primitiveType == ir::PrimitiveType::DOUBLE) && - CheckEnumMemberType(enumDecl->Members(), hasLoggedError, hasLongLiteral)) { - return CreateEnumFloatClassFromEnumDeclaration(enumDecl, flags); - } - - if (!hasLoggedError) { - LogError(diagnostic::UNSUPPORTED_ENUM_TYPE, {}, itemInit->Start()); - } - - return ast; -} - checker::AstNodePtr EnumLoweringPhase::TransformEnumChildrenRecursively(checker::AstNodePtr &ast) { auto *enumDecl = ast->AsTSEnumDeclaration(); @@ -657,29 +650,44 @@ checker::AstNodePtr EnumLoweringPhase::TransformEnumChildrenRecursively(checker: } if (enumDecl->Members().empty()) { - return CreateEnumIntClassFromEnumDeclaration(enumDecl, flags); + return CreateEnumNumericClassFromEnumDeclaration(enumDecl, flags); } bool hasLoggedError = false; bool hasLongLiteral = false; auto *const itemInit = enumDecl->Members().front()->AsTSEnumMember()->Init(); - if (itemInit->IsNumberLiteral() && - ((itemInit->AsNumberLiteral()->Number().IsInteger() || itemInit->AsNumberLiteral()->Number().IsLong()) && - CheckEnumMemberType(enumDecl->Members(), hasLoggedError, hasLongLiteral))) { - auto res = hasLongLiteral ? CreateEnumIntClassFromEnumDeclaration(enumDecl, flags) - : CreateEnumIntClassFromEnumDeclaration(enumDecl, flags); - return res; - } - if (itemInit->IsNumberLiteral() && - ((itemInit->AsNumberLiteral()->Number().IsDouble() || itemInit->AsNumberLiteral()->Number().IsFloat()) && - CheckEnumMemberType(enumDecl->Members(), hasLoggedError, hasLongLiteral))) { - return CreateEnumFloatClassFromEnumDeclaration(enumDecl, flags); - } + if (itemInit->IsNumberLiteral()) { + if (itemInit->AsNumberLiteral()->Number().IsByte() && + CheckEnumMemberType(enumDecl->Members(), hasLoggedError, hasLongLiteral)) { + return CreateEnumNumericClassFromEnumDeclaration(enumDecl, flags); + } + + if (itemInit->AsNumberLiteral()->Number().IsShort() && + CheckEnumMemberType(enumDecl->Members(), hasLoggedError, hasLongLiteral)) { + return CreateEnumNumericClassFromEnumDeclaration(enumDecl, flags); + } + + if (itemInit->AsNumberLiteral()->Number().IsFloat() && + CheckEnumMemberType(enumDecl->Members(), hasLoggedError, hasLongLiteral)) { + return CreateEnumNumericClassFromEnumDeclaration(enumDecl, flags); + } - if (itemInit->IsStringLiteral() && - CheckEnumMemberType(enumDecl->Members(), hasLoggedError, hasLongLiteral)) { - return CreateEnumStringClassFromEnumDeclaration(enumDecl, flags); + if (itemInit->AsNumberLiteral()->Number().IsDouble() && + CheckEnumMemberType(enumDecl->Members(), hasLoggedError, hasLongLiteral)) { + return CreateEnumNumericClassFromEnumDeclaration(enumDecl, flags); + } + + if (((itemInit->AsNumberLiteral()->Number().IsInteger() || itemInit->AsNumberLiteral()->Number().IsLong()) && + CheckEnumMemberType(enumDecl->Members(), hasLoggedError, hasLongLiteral))) { + auto res = hasLongLiteral ? CreateEnumNumericClassFromEnumDeclaration(enumDecl, flags) + : CreateEnumNumericClassFromEnumDeclaration(enumDecl, flags); + + return res; + } + } else if (itemInit->IsStringLiteral() && + CheckEnumMemberType(enumDecl->Members(), hasLoggedError, hasLongLiteral)) { + return CreateEnumNumericClassFromEnumDeclaration(enumDecl, flags); } if (!hasLoggedError) { @@ -707,12 +715,9 @@ bool EnumLoweringPhase::PerformForModule(public_lib::Context *ctx, parser::Progr program->Ast()->TransformChildrenRecursively( [this](checker::AstNodePtr ast) -> checker::AstNodePtr { if (ast->IsTSEnumDeclaration()) { - ir::TSEnumDeclaration *enumDecl = ast->AsTSEnumDeclaration(); - - if (enumDecl->TypeNodes() != nullptr) { - return TransformAnnotedEnumChildrenRecursively(ast); + if (ast->AsTSEnumDeclaration()->TypeAnnotation() != nullptr) { + ast->AsTSEnumDeclaration()->TypeAnnotation()->SetParent(ast->AsTSEnumDeclaration()); } - return TransformEnumChildrenRecursively(ast); } return ast; @@ -725,10 +730,16 @@ bool EnumLoweringPhase::PerformForModule(public_lib::Context *ctx, parser::Progr } template -ir::Identifier *EnumLoweringPhase::CreateEnumValuesArray(const ir::TSEnumDeclaration *const enumDecl, +ir::Identifier *EnumLoweringPhase::CreateEnumValuesArray(ir::TSEnumDeclaration *const enumDecl, ir::ClassDefinition *const enumClass) { - auto *const type = AllocNode(TYPE, Allocator()); + ir::TypeNode *type; + if (enumDecl->TypeAnnotation() != nullptr) { + type = enumDecl->TypeAnnotation()->Clone(Allocator(), enumClass); + } else { + type = AllocNode(TYPE, Allocator()); + } + auto *const arrayTypeAnnotation = AllocNode(type, Allocator()); // clang-format off return MakeArray(enumDecl, enumClass, VALUES_ARRAY_NAME, arrayTypeAnnotation, @@ -759,13 +770,25 @@ ir::Identifier *EnumLoweringPhase::CreateEnumStringValuesArray(const ir::TSEnumD stringValue = init->AsStringLiteral()->Str(); } else { std::string str {}; - if (init->AsNumberLiteral()->Number().IsInteger()) { + if (init->AsNumberLiteral()->Number().IsByte()){ + std::int8_t res = init->AsNumberLiteral()->Number().GetValue(); + str = std::to_string(res); + } else if (init->AsNumberLiteral()->Number().IsShort()){ + std::int16_t res = init->AsNumberLiteral()->Number().GetValue(); + str = std::to_string(res); + } else if (init->AsNumberLiteral()->Number().IsInteger()) { std::int64_t res = init->AsNumberLiteral()->Number().GetValue(); str = std::to_string(res); - } else { + } else if (init->AsNumberLiteral()->Number().IsFloat()){ + float res = init->AsNumberLiteral()->Number().GetValue(); + str = std::to_string(res); + }else if (init->AsNumberLiteral()->Number().IsDouble()){ double res = init->AsNumberLiteral()->Number().GetValue(); str = std::to_string(res); + } else { + ES2PANDA_UNREACHABLE(); } + stringValue = util::UString(str, Allocator()).View(); } auto *const enumValueStringLiteral = AllocNode(stringValue); @@ -881,7 +904,7 @@ void EnumLoweringPhase::CreateEnumToStringMethod(const ir::TSEnumDeclaration *co MakeMethodDef(context_, enumClass, functionIdent, function); } -void EnumLoweringPhase::CreateEnumValueOfMethod(const ir::TSEnumDeclaration *const enumDecl, +void EnumLoweringPhase::CreateEnumValueOfMethod(ir::TSEnumDeclaration *const enumDecl, ir::ClassDefinition *const enumClass, ir::Identifier *const valuesArrayIdent, std::optional primitiveType) @@ -893,9 +916,18 @@ void EnumLoweringPhase::CreateEnumValueOfMethod(const ir::TSEnumDeclaration *con body.push_back(returnStmt); ArenaVector params(Allocator()->Adapter()); - auto *const typeAnnotation = primitiveType.has_value() - ? AllocNode(primitiveType.value(), Allocator())->AsTypeNode() - : MakeTypeReference(context_, STRING_REFERENCE_TYPE)->AsTypeNode(); + + ir::TypeNode *typeAnnotation; + if (primitiveType.has_value()) { + if (enumDecl->TypeAnnotation() != nullptr) { + typeAnnotation = enumDecl->TypeAnnotation()->Clone(Allocator(), enumClass); + } else { + typeAnnotation = AllocNode(primitiveType.value(), Allocator())->AsTypeNode(); + } + } else { + typeAnnotation = MakeTypeReference(context_, STRING_REFERENCE_TYPE)->AsTypeNode(); + } + auto *const function = MakeFunction({std::move(params), std::move(body), typeAnnotation, enumDecl, ir::ModifierFlags::PUBLIC}); auto *const functionIdent = AllocNode(checker::ETSEnumType::VALUE_OF_METHOD_NAME, Allocator()); @@ -1031,7 +1063,7 @@ void EnumLoweringPhase::CreateEnumGetValueOfMethod(const ir::TSEnumDeclaration * MakeMethodDef(context_, enumClass, functionIdent, function); } -void EnumLoweringPhase::CreateEnumFromValueMethod(ir::TSEnumDeclaration const *const enumDecl, +void EnumLoweringPhase::CreateEnumFromValueMethod(ir::TSEnumDeclaration *const enumDecl, ir::ClassDefinition *const enumClass, ir::Identifier *const valuesArrayIdent, ir::Identifier *const itemsArrayIdent, @@ -1041,9 +1073,18 @@ void EnumLoweringPhase::CreateEnumFromValueMethod(ir::TSEnumDeclaration const *c auto *const forLoopInitVarDecl = CreateForLoopInitVariableDeclaration(context_, forLoopIIdent); auto *const forLoopTest = CreateForLoopTest(context_, enumClass->Ident(), valuesArrayIdent, forLoopIIdent); auto *const forLoopUpdate = CreateForLoopUpdate(context_, forLoopIIdent); - auto *const typeAnnotation = primitiveType.has_value() - ? AllocNode(primitiveType.value(), Allocator())->AsTypeNode() - : MakeTypeReference(context_, STRING_REFERENCE_TYPE)->AsTypeNode(); + + ir::TypeNode *typeAnnotation; + if (primitiveType.has_value()) { + if (enumDecl->TypeAnnotation() != nullptr) { + typeAnnotation = enumDecl->TypeAnnotation()->Clone(Allocator(), enumClass); + } else { + typeAnnotation = AllocNode(primitiveType.value(), Allocator())->AsTypeNode(); + } + } else { + typeAnnotation = MakeTypeReference(context_, STRING_REFERENCE_TYPE)->AsTypeNode(); + } + auto *const inputValueIdent = MakeFunctionParam(context_, PARAM_VALUE, typeAnnotation); auto *const ifStmt = CreateIf(context_, CreateStaticAccessMemberExpression(context_, enumClass->Ident(), valuesArrayIdent), diff --git a/ets2panda/compiler/lowering/ets/enumLowering.h b/ets2panda/compiler/lowering/ets/enumLowering.h index f95443c8ce783deb8a2c3d27d974a2d4dcf85424..06daa8029241a32594845245f51f7ebfd95a0cff 100644 --- a/ets2panda/compiler/lowering/ets/enumLowering.h +++ b/ets2panda/compiler/lowering/ets/enumLowering.h @@ -38,7 +38,7 @@ public: static constexpr std::string_view ORDINAL_NAME {"#ordinal"}; static constexpr auto ORDINAL_TYPE {ir::PrimitiveType::INT}; - enum EnumType { NOT_SPECIFIED = 0, INT = 1, LONG = 2, DOUBLE = 3, STRING = 4 }; + enum EnumType { NOT_SPECIFIED = 0, INT = 1, LONG = 2, DOUBLE = 3, FLOAT = 4, BYTE = 5, SHORT = 6, STRING = 7 }; struct DeclarationFlags { // NOLINTBEGIN(misc-non-private-member-variables-in-classes) @@ -93,17 +93,15 @@ private: ir::ClassProperty *CreateOrdinalField(ir::ClassDefinition *const enumClass); ir::MemberExpression *CreateOrdinalAccessExpression(); void CreateCCtorForEnumClass(ir::ClassDefinition *const enumClass); - void CreateCtorForEnumClass(ir::ClassDefinition *const enumClass, EnumType enumType); - ir::ScriptFunction *CreateFunctionForCtorOfEnumClass(ir::ClassDefinition *const enumClass, EnumType enumType); + void CreateCtorForEnumClass(ir::ClassDefinition *const enumClass, ir::TypeNode *enumType); + ir::ScriptFunction *CreateFunctionForCtorOfEnumClass(ir::ClassDefinition *const enumClass, ir::TypeNode *enumType); void ProcessEnumClassDeclaration(ir::TSEnumDeclaration *const enumDecl, const DeclarationFlags &flags, ir::ClassDeclaration *enumClassDecl); - template - ir::ClassDeclaration *CreateEnumIntClassFromEnumDeclaration(ir::TSEnumDeclaration *const enumDecl, - const DeclarationFlags flags); - template - ir::ClassDeclaration *CreateEnumFloatClassFromEnumDeclaration(ir::TSEnumDeclaration *const enumDecl, - const DeclarationFlags flags); + template + ir::ClassDeclaration *CreateEnumNumericClassFromEnumDeclaration(ir::TSEnumDeclaration *const enumDecl, + const DeclarationFlags flags); + ir::ClassDeclaration *CreateEnumStringClassFromEnumDeclaration(ir::TSEnumDeclaration *const enumDecl, const DeclarationFlags flags); static void AppendParentNames(util::UString &qualifiedName, const ir::AstNode *const node); @@ -115,20 +113,20 @@ private: EnumType enumType); ir::Identifier *CreateEnumNamesArray(const ir::TSEnumDeclaration *const enumDecl, ir::ClassDefinition *enumClass); template - ir::Identifier *CreateEnumValuesArray(const ir::TSEnumDeclaration *const enumDecl, ir::ClassDefinition *enumClass); + ir::Identifier *CreateEnumValuesArray(ir::TSEnumDeclaration *const enumDecl, ir::ClassDefinition *enumClass); ir::Identifier *CreateEnumStringValuesArray(const ir::TSEnumDeclaration *const enumDecl, ir::ClassDefinition *enumClass); ir::Identifier *CreateEnumItemsArray(const ir::TSEnumDeclaration *const enumDecl, ir::ClassDefinition *enumClass); void CreateEnumToStringMethod(ir::TSEnumDeclaration const *const enumDecl, ir::ClassDefinition *const enumClass, ir::Identifier *const stringValuesArrayIdent); - void CreateEnumValueOfMethod(ir::TSEnumDeclaration const *const enumDecl, ir::ClassDefinition *const enumClass, + void CreateEnumValueOfMethod(ir::TSEnumDeclaration *const enumDecl, ir::ClassDefinition *const enumClass, ir::Identifier *const valuesArrayIdent, std::optional primitiveType); void CreateEnumGetNameMethod(ir::TSEnumDeclaration const *const enumDecl, ir::ClassDefinition *const enumClass, ir::Identifier *const namesArrayIdent); void CreateEnumGetValueOfMethod(ir::TSEnumDeclaration const *const enumDecl, ir::ClassDefinition *const enumClass, ir::Identifier *const namesArrayIdent, ir::Identifier *const itemsArrayIdent); - void CreateEnumFromValueMethod(ir::TSEnumDeclaration const *const enumDecl, ir::ClassDefinition *const enumClass, + void CreateEnumFromValueMethod(ir::TSEnumDeclaration *const enumDecl, ir::ClassDefinition *const enumClass, ir::Identifier *const valuesArrayIdent, ir::Identifier *const itemsArrayIdent, std::optional primitiveType); void CreateEnumValuesMethod(ir::TSEnumDeclaration const *const enumDecl, ir::ClassDefinition *const enumClass, @@ -139,7 +137,6 @@ private: ir::TSEnumDeclaration const *const enumDecl); ir::Expression *CheckEnumTypeForItemFields(EnumType enumType, ir::TSEnumMember *const member); checker::AstNodePtr TransformEnumChildrenRecursively(checker::AstNodePtr &ast); - checker::AstNodePtr TransformAnnotedEnumChildrenRecursively(checker::AstNodePtr &ast); ArenaAllocator *Allocator(); template diff --git a/ets2panda/compiler/lowering/ets/enumPostCheckLowering.cpp b/ets2panda/compiler/lowering/ets/enumPostCheckLowering.cpp index ef92dd27aa7b9ad688e9d54434716718bfbad283..4d9ef4f0ec651ff04a31f63ac1023100078de62e 100644 --- a/ets2panda/compiler/lowering/ets/enumPostCheckLowering.cpp +++ b/ets2panda/compiler/lowering/ets/enumPostCheckLowering.cpp @@ -74,10 +74,13 @@ static bool IsValidEnumCasting(checker::Type *type, EnumCastType castType) case EnumCastType::CAST_TO_STRING: { return type->IsETSStringEnumType(); } - case EnumCastType::CAST_TO_INT: { - return type->IsETSIntEnumType(); + case EnumCastType::CAST_TO_INT: + case EnumCastType::CAST_TO_DOUBLE: + case EnumCastType::CAST_TO_BYTE: + case EnumCastType::CAST_TO_SHORT: { + return type->IsETSNumericEnumType(); } - case EnumCastType::CAST_TO_INT_ENUM: + case EnumCastType::CAST_TO_NUMERIC_ENUM: case EnumCastType::CAST_TO_STRING_ENUM: { return true; } @@ -97,9 +100,18 @@ static EnumCastType NeedHandleEnumCasting(ir::TSAsExpression *node) if (type->IsETSStringType()) { castType = EnumCastType::CAST_TO_STRING; } else if (type->HasTypeFlag(checker::TypeFlag::ETS_NUMERIC) || type->IsBuiltinNumeric()) { - castType = EnumCastType::CAST_TO_INT; + if (type->AsETSObjectType()->HasObjectFlag(checker::ETSObjectFlags::BUILTIN_DOUBLE)) { + castType = EnumCastType::CAST_TO_DOUBLE; + } else if (type->AsETSObjectType()->HasObjectFlag(checker::ETSObjectFlags::BUILTIN_INT)) { + castType = EnumCastType::CAST_TO_INT; + } else if (type->AsETSObjectType()->HasObjectFlag(checker::ETSObjectFlags::BUILTIN_BYTE)) { + castType = EnumCastType::CAST_TO_BYTE; + } else if (type->AsETSObjectType()->HasObjectFlag(checker::ETSObjectFlags::BUILTIN_SHORT)) { + castType = EnumCastType::CAST_TO_BYTE; + } } else if (type->IsETSEnumType()) { - castType = type->IsETSIntEnumType() ? EnumCastType::CAST_TO_INT_ENUM : EnumCastType::CAST_TO_STRING_ENUM; + castType = + type->IsETSNumericEnumType() ? EnumCastType::CAST_TO_NUMERIC_ENUM : EnumCastType::CAST_TO_STRING_ENUM; } else { return castType; } @@ -249,8 +261,11 @@ void EnumPostCheckLoweringPhase::CreateStatementForUnionConstituentType(EnumCast } break; } - case EnumCastType::CAST_TO_INT: { - if (type->IsETSIntEnumType()) { + case EnumCastType::CAST_TO_INT: + case EnumCastType::CAST_TO_DOUBLE: + case EnumCastType::CAST_TO_BYTE: + case EnumCastType::CAST_TO_SHORT: { + if (type->IsETSNumericEnumType()) { auto callExpr = CallInstanceEnumMethod(context_, checker::ETSEnumType::VALUE_OF_METHOD_NAME, ident->Clone(context_->Allocator(), nullptr)->AsExpression()); callExpr->SetRange(tsAsExpr->Expr()->Range()); @@ -258,10 +273,18 @@ void EnumPostCheckLoweringPhase::CreateStatementForUnionConstituentType(EnumCast } break; } - case EnumCastType::CAST_TO_INT_ENUM: { + case EnumCastType::CAST_TO_NUMERIC_ENUM: { // int and Boxed Int can be casted to int enum - if (type->IsIntType() || (type->IsETSObjectType() && - type->AsETSObjectType()->HasObjectFlag(checker::ETSObjectFlags::BUILTIN_INT))) { + bool isNumeric = type->IsIntType() || type->IsDoubleType() || type->IsByteType() || type->IsShortType(); + bool isBuiltinNumeric = false; + + if (type->IsETSObjectType()) { + isBuiltinNumeric = type->AsETSObjectType()->HasObjectFlag( + checker::ETSObjectFlags::BUILTIN_INT | checker::ETSObjectFlags::BUILTIN_DOUBLE | + checker::ETSObjectFlags::BUILTIN_BYTE | checker::ETSObjectFlags::BUILTIN_SHORT); + } + + if (isNumeric || isBuiltinNumeric) { auto name = TypeAnnotationToString(tsAsExpr->TypeAnnotation()->AsETSTypeReference(), context_); auto callExpr = GenerateFromValueCall(ident->Clone(context_->Allocator(), nullptr)->AsExpression(), name); @@ -398,7 +421,7 @@ static void RecheckNode(ir::AstNode *node, checker::ETSChecker *checker) node->Check(checker); if (node->IsExpression() && node->AsExpression()->TsType() != nullptr && - !node->AsExpression()->TsType()->IsETSIntEnumType()) { + !node->AsExpression()->TsType()->IsETSNumericEnumType()) { node->RemoveAstNodeFlags(ir::AstNodeFlags::GENERATE_VALUE_OF); } } diff --git a/ets2panda/compiler/lowering/ets/enumPostCheckLowering.h b/ets2panda/compiler/lowering/ets/enumPostCheckLowering.h index 1ce716fe85b21f515640551bfc42b09b63874693..cd46ef71b358f086778cdc2eeef36f25d1e00c16 100644 --- a/ets2panda/compiler/lowering/ets/enumPostCheckLowering.h +++ b/ets2panda/compiler/lowering/ets/enumPostCheckLowering.h @@ -25,7 +25,10 @@ enum class EnumCastType { NONE, CAST_TO_STRING, CAST_TO_INT, - CAST_TO_INT_ENUM, + CAST_TO_DOUBLE, + CAST_TO_BYTE, + CAST_TO_SHORT, + CAST_TO_NUMERIC_ENUM, CAST_TO_STRING_ENUM, }; diff --git a/ets2panda/ir/base/classDefinition.h b/ets2panda/ir/base/classDefinition.h index b1df4a83c3d87e41adca6f6a0de08a2001097695..3daa0dd2aaad82cfa58e7619162eb5dba5ab6fb8 100644 --- a/ets2panda/ir/base/classDefinition.h +++ b/ets2panda/ir/base/classDefinition.h @@ -55,7 +55,7 @@ enum class ClassDefinitionModifiers : uint32_t { CLASSDEFINITION_CHECKED = 1U << 12U, NAMESPACE_TRANSFORMED = 1U << 13U, STRING_ENUM_TRANSFORMED = 1U << 14U, - INT_ENUM_TRANSFORMED = 1U << 15U, + NUMERIC_ENUM_TRANSFORMED = 1U << 15U, FROM_STRUCT = 1U << 16U, FUNCTIONAL_REFERENCE = 1U << 17U, LAZY_IMPORT_OBJECT_CLASS = 1U << 18U, @@ -252,9 +252,9 @@ public: return (Modifiers() & ClassDefinitionModifiers::ANONYMOUS) != 0; } - [[nodiscard]] bool IsIntEnumTransformed() const noexcept + [[nodiscard]] bool IsNumericEnumTransformed() const noexcept { - return (Modifiers() & ClassDefinitionModifiers::INT_ENUM_TRANSFORMED) != 0; + return (Modifiers() & ClassDefinitionModifiers::NUMERIC_ENUM_TRANSFORMED) != 0; } [[nodiscard]] bool IsStringEnumTransformed() const noexcept @@ -264,7 +264,7 @@ public: [[nodiscard]] bool IsEnumTransformed() const noexcept { - return IsIntEnumTransformed() || IsStringEnumTransformed(); + return IsNumericEnumTransformed() || IsStringEnumTransformed(); } [[nodiscard]] bool IsNamespaceTransformed() const noexcept diff --git a/ets2panda/ir/ts/tsEnumDeclaration.cpp b/ets2panda/ir/ts/tsEnumDeclaration.cpp index 93e14b5f32cb50aa76c3e9dd704c6fd3560b2b04..7a18b8c9ea6296be7522cf15a25ee3675a23a644 100644 --- a/ets2panda/ir/ts/tsEnumDeclaration.cpp +++ b/ets2panda/ir/ts/tsEnumDeclaration.cpp @@ -126,6 +126,10 @@ void TSEnumDeclaration::Dump(ir::SrcDumper *dumper) const } dumper->Add("enum "); Key()->Dump(dumper); + if (typeAnnotation_) { + dumper->Add(": "); + dumper->Add(typeAnnotation_->DumpEtsSrc()); + } dumper->Add(" {"); auto const members = Members(); if (!members.empty()) { diff --git a/ets2panda/ir/ts/tsEnumDeclaration.h b/ets2panda/ir/ts/tsEnumDeclaration.h index 2a992d9c3941b05d4b44c541c939fac2c760a609..d4e44d57874d6bb011845c33c753a043c4e2b5c8 100644 --- a/ets2panda/ir/ts/tsEnumDeclaration.h +++ b/ets2panda/ir/ts/tsEnumDeclaration.h @@ -43,7 +43,7 @@ public: : TypedStatement(AstNodeType::TS_ENUM_DECLARATION), decorators_(allocator->Adapter()), key_(key), - typeNode_(nullptr), + typeAnnotation_(nullptr), members_(std::move(members)), isConst_(flags.isConst), lang_(lang) @@ -62,7 +62,7 @@ public: : TypedStatement(AstNodeType::TS_ENUM_DECLARATION), decorators_(allocator->Adapter()), key_(key), - typeNode_(typeNode), + typeAnnotation_(typeNode), members_(std::move(members)), isConst_(flags.isConst), lang_(lang) @@ -82,7 +82,7 @@ public: : TypedStatement(AstNodeType::TS_ENUM_DECLARATION), decorators_(allocator->Adapter()), key_(key), - typeNode_(nullptr), + typeAnnotation_(nullptr), members_(std::move(members)), isConst_(flags.isConst), lang_(lang) @@ -126,11 +126,6 @@ public: return GetHistoryNodeAs()->key_; } - TypeNode *TypeNodes() - { - return typeNode_; - } - Identifier *Key() { return GetHistoryNodeAs()->key_; @@ -181,6 +176,16 @@ public: return GetHistoryNodeAs()->lang_; } + [[nodiscard]] TypeNode *TypeAnnotation() noexcept + { + return GetHistoryNodeAs()->typeAnnotation_; + } + + [[nodiscard]] const TypeNode *TypeAnnotation() const noexcept + { + return GetHistoryNodeAs()->typeAnnotation_; + } + static varbinder::EnumMemberResult EvaluateEnumMember(checker::TSChecker *checker, varbinder::EnumVariable *enumVar, const ir::AstNode *expr); void TransformChildren(const NodeTransformer &cb, std::string_view transformationName) override; @@ -218,7 +223,7 @@ private: varbinder::LocalScope *scope_ {nullptr}; ArenaVector decorators_; Identifier *key_; - ir::TypeNode *typeNode_; + ir::TypeNode *typeAnnotation_; ArenaVector members_; util::StringView internalName_; ir::ClassDefinition *boxedClass_ {nullptr}; diff --git a/ets2panda/parser/ETSparserEnums.cpp b/ets2panda/parser/ETSparserEnums.cpp index 44434862cb24624894067944521b420157710561..43064e3bcbf1db3520e3facb0a8e9a81a1ad0789 100644 --- a/ets2panda/parser/ETSparserEnums.cpp +++ b/ets2panda/parser/ETSparserEnums.cpp @@ -160,22 +160,7 @@ ir::TSEnumDeclaration *ETSParser::ParseEnumMembers(ir::Identifier *const key, co Lexer()->NextToken(); // eat ':' TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::REPORT_ERROR; typeAnnotation = ParseTypeAnnotation(&options); - - // According to a comment on ETSparser.cpp:1598, compiler can't process ": string" correctly. - // ParseTypeAnnotation reads ": string" as literal so it's not supported here for now. - auto startPos = Lexer()->GetToken().Start(); - if (!typeAnnotation->IsETSPrimitiveType()) { - LogError(diagnostic::UNSUPPORTED_ENUM_TYPE, {}, startPos); - typeAnnotation = nullptr; - } else { - ir::PrimitiveType primitiveType = typeAnnotation->AsETSPrimitiveType()->GetPrimitiveType(); - if (primitiveType != ir::PrimitiveType::INT && primitiveType != ir::PrimitiveType::LONG && - primitiveType != ir::PrimitiveType::DOUBLE) { - // Issue: #26024 Numeric support for enum - LogError(diagnostic::UNSUPPORTED_ENUM_TYPE, {}, startPos); - typeAnnotation = nullptr; - } - } + typeAnnotation->SetRange({Lexer()->GetToken().Start(), Lexer()->GetToken().End()}); } Lexer()->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT); // eat '{' diff --git a/ets2panda/test/ast/parser/ets/enumAnnotation.ets b/ets2panda/test/ast/parser/ets/enumAnnotation.ets index 625a12d886895dff4224b374a8202471f5cc53d5..b480191ebc0feb99e4b44b5bf249a8bb1c37141d 100644 --- a/ets2panda/test/ast/parser/ets/enumAnnotation.ets +++ b/ets2panda/test/ast/parser/ets/enumAnnotation.ets @@ -15,5 +15,25 @@ enum Fraction: int { A = 1, - B = 1 + B = 2 +} + +enum Fraction2: double { + A = 1.2, + B = 3.1 +} + +enum Fraction3: string { + A = "A", + B = "B" +} + +enum Fraction4: byte { + A = 0x01, + B = 0x01 +} + +enum Fraction5: short { + A = 1, + B = 2 } diff --git a/ets2panda/test/ast/parser/ets/enumAnnotation2.ets b/ets2panda/test/ast/parser/ets/enumAnnotation2.ets index d790c608a386b3a6eeb2d2f9403b61013fbe9bf5..49b20f1b3b1d7591acfaec55f76ae4b4226f441c 100644 --- a/ets2panda/test/ast/parser/ets/enumAnnotation2.ets +++ b/ets2panda/test/ast/parser/ets/enumAnnotation2.ets @@ -13,7 +13,11 @@ * limitations under the License. */ -enum Fraction: double { - A = 1.2, - B = 3.1 +enum Test1: int { + A = 0x32 } + +enum Test1: short { + A = 0x01 +} + diff --git a/ets2panda/test/ast/parser/ets/enumAnnotation3.ets b/ets2panda/test/ast/parser/ets/enumAnnotation3.ets index 17fc47a361df438e6b9e34a0765f1d222caba8c0..85444d223ee61f105e0a395a7566a5b9e430a424 100644 --- a/ets2panda/test/ast/parser/ets/enumAnnotation3.ets +++ b/ets2panda/test/ast/parser/ets/enumAnnotation3.ets @@ -13,10 +13,10 @@ * limitations under the License. */ -enum Fraction: string { - A = "A", - B = "B" -} +class MyType{ } +let a = MyType() -/* @@? 16:23 Error SyntaxError: Unsupported enum type annotation. Supported enum types are: int, long or double. String is allowed for literal types, not annotations. */ +enum Test: MyType{ + A = a +}; \ No newline at end of file diff --git a/ets2panda/test/ast/parser/ets/enumAnnotation4.ets b/ets2panda/test/ast/parser/ets/enumAnnotation4.ets index 2816b123bbfe215c49f072278a0a92fd70ce361f..f2dddf0a5cd566a80d4f3f30c4688bb322229c50 100644 --- a/ets2panda/test/ast/parser/ets/enumAnnotation4.ets +++ b/ets2panda/test/ast/parser/ets/enumAnnotation4.ets @@ -19,4 +19,4 @@ enum Fraction: customInt { } -/* @@? 16:26 Error SyntaxError: Unsupported enum type annotation. Supported enum types are: int, long or double. String is allowed for literal types, not annotations. */ \ No newline at end of file +/* @@? 16:16 Error TypeError: Cannot find type 'customInt'. */ \ No newline at end of file diff --git a/ets2panda/test/ast/parser/ets/enumAnnotation5.ets b/ets2panda/test/ast/parser/ets/enumAnnotation5.ets index 64ff1a363563cd8cb88b37c7e1ccc12df2f30269..6a78d85a1d9532a46dfa90d2ed7129d18eac2181 100644 --- a/ets2panda/test/ast/parser/ets/enumAnnotation5.ets +++ b/ets2panda/test/ast/parser/ets/enumAnnotation5.ets @@ -18,6 +18,21 @@ enum Fraction: int { B = "B" } +enum Fraction1: double { + A = "A", + B = "B" +} + +enum Fraction2: int { + A = 1.2, + B = 2.2 +} + +enum Fraction: string { + A = 1, + B = 2 +} + /* @@? 17:9 Error TypeError: Enumeration members can be initialized only by compile-time expressions and initializers must be of the same type. */ /* @@? 18:9 Error TypeError: Enumeration members can be initialized only by compile-time expressions and initializers must be of the same type. */ \ No newline at end of file diff --git a/ets2panda/test/ast/parser/ets/enumAnnotation6.ets b/ets2panda/test/ast/parser/ets/enumAnnotation6.ets index b52526a67f952ca270ba61ea16bd1c25d2a59444..2c2b7ea4a6abef9eff107b37f60e75a9035eadc3 100644 --- a/ets2panda/test/ast/parser/ets/enumAnnotation6.ets +++ b/ets2panda/test/ast/parser/ets/enumAnnotation6.ets @@ -13,10 +13,36 @@ * limitations under the License. */ -enum Fraction: byte { - A = 1, - B = 2 +enum Test1: Byte{ + A = 0x1, + B = 0x01 + 1, + C = B, + D = C + 0x02, + E = D - 2, + F = D * C, } +enum Test2: double{ + A = 1.1, + B = 1.2 + 1.3, + C = B, + D = C + 1.5, + E = D - 2.5, + F = D * C, +} + +enum Test3: int{ + A = 1, + B = 2 + 3, + C = B, + D = C + 1, + E = D - 2, + F = D * C, +} -/* @@? 16:21 Error SyntaxError: Unsupported enum type annotation. Supported enum types are: int, long or double. String is allowed for literal types, not annotations. */ +enum Test4: string{ + A = "A", + B = "A" + "B", + C = B, + D = C + "C", +} \ No newline at end of file diff --git a/ets2panda/test/ast/parser/ets/enumAnnotation7.ets b/ets2panda/test/ast/parser/ets/enumAnnotation7.ets index 05c4208c2ccc6d51ac26286e099f25c2cc93d10f..2410e0426be34aa3a5dcf4026d5c180dc95444a6 100644 --- a/ets2panda/test/ast/parser/ets/enumAnnotation7.ets +++ b/ets2panda/test/ast/parser/ets/enumAnnotation7.ets @@ -13,11 +13,21 @@ * limitations under the License. */ -enum E: double{ - A = 1.1, - B = 1.2 + 1.3, - C = B, - D = C + 1.5, - E = D - 2.5, - F = D * C, +const a: int = 1; + +enum Test: int { + A = a, + b = 1 + a +}; + +enum Test2: byte { + A = a, + b = 0x01 + A +} + +const b: string = "name" + +enum Test3: string{ + A = b, + B = A + " test" } \ No newline at end of file diff --git a/ets2panda/test/ast/parser/ets/enumAnnotation8.ets b/ets2panda/test/ast/parser/ets/enumAnnotation8.ets new file mode 100644 index 0000000000000000000000000000000000000000..276e843034684bf16ccf44805f9a282e1ea3615d --- /dev/null +++ b/ets2panda/test/ast/parser/ets/enumAnnotation8.ets @@ -0,0 +1,33 @@ +/* + * 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. + */ + +let a: int = 1; + +enum Test: int { + A = a, + b = 1 + a +}; + +enum Test2: byte { + A = a, + b = 0x01 + A +} + +let b: string = "name" + +enum Test3: string{ + A = b, + B = A + " test" +} \ No newline at end of file diff --git a/ets2panda/test/runtime/ets/Enum8.ets b/ets2panda/test/runtime/ets/Enum8.ets index edebc4ce29a145d3557f9c0ac50610a313b88e64..f5bded1b2f803de8a0dbfcbd369939e3e10d61e8 100644 --- a/ets2panda/test/runtime/ets/Enum8.ets +++ b/ets2panda/test/runtime/ets/Enum8.ets @@ -19,7 +19,7 @@ enum StringEnum { C = "Cherry" } -enum IntEnum { +enum NumericEnum { One = 1, Two = 2, Three = 3, @@ -67,10 +67,10 @@ function main() { arktest.assertTrue(StringEnum.A !== StringEnum.B); arktest.assertTrue(StringEnum.C > StringEnum.A); - arktest.assertEQ(IntEnum.One + IntEnum.Two, 3); - arktest.assertEQ(IntEnum.Three - IntEnum.One, 2); - arktest.assertEQ(IntEnum.Four * IntEnum.Two, 8); - arktest.assertEQ(IntEnum.Four / IntEnum.Two, 2); + arktest.assertEQ(NumericEnum.One + NumericEnum.Two, 3); + arktest.assertEQ(NumericEnum.Three - NumericEnum.One, 2); + arktest.assertEQ(NumericEnum.Four * NumericEnum.Two, 8); + arktest.assertEQ(NumericEnum.Four / NumericEnum.Two, 2); arktest.assertEQ(ColorEnum.Red + ColorEnum.Green, 15); arktest.assertEQ(ColorEnum.Blue - ColorEnum.Green > 0 ? "Greater" : "Smaller", "Greater"); diff --git a/ets2panda/test/runtime/ets/annotation_tests/EnumAnnotationAlias.ets b/ets2panda/test/runtime/ets/annotation_tests/EnumAnnotationAlias.ets index 2f4b6aafbe7b4670be95f7343cee29b1d5774082..9b11eaa12db6812c8d48920eed9add2af4668abb 100644 --- a/ets2panda/test/runtime/ets/annotation_tests/EnumAnnotationAlias.ets +++ b/ets2panda/test/runtime/ets/annotation_tests/EnumAnnotationAlias.ets @@ -13,7 +13,8 @@ * limitations under the License. */ -enum Status { +type intAlias = int +enum Status: intAlias { Pending, InProgress, Complete diff --git a/ets2panda/test/runtime/ets/annotation_tests/EnumAnnotationAlias3.ets b/ets2panda/test/runtime/ets/annotation_tests/EnumAnnotationAlias3.ets new file mode 100644 index 0000000000000000000000000000000000000000..c2d771fa847c4097cb6a4cc91e3694bbbd09286d --- /dev/null +++ b/ets2panda/test/runtime/ets/annotation_tests/EnumAnnotationAlias3.ets @@ -0,0 +1,25 @@ +/* + * 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. + */ + +type myByte = byte; +enum Status: myByte { + Pending = 0x34, + InProgress = 0xAF, + Complete = 0x8F +} + +type StatusType = Status; + +let current: StatusType = Status.InProgress; \ No newline at end of file diff --git a/ets2panda/test/runtime/ets/enum_as_key_of_record.ets b/ets2panda/test/runtime/ets/enum_as_key_of_record.ets index 93d19bb9f681e4ddcdfa5e5659e6c11d1b7c248e..d35836fec64f12067c567ef3030f5782188cf421 100644 --- a/ets2panda/test/runtime/ets/enum_as_key_of_record.ets +++ b/ets2panda/test/runtime/ets/enum_as_key_of_record.ets @@ -18,11 +18,11 @@ up = "1" } - enum IntEnum { + enum NumericEnum { up = 1 } -function foo(val1:Record, val2:Record){ +function foo(val1:Record, val2:Record){ } \ No newline at end of file diff --git a/ets2panda/test/unit/public/ast_verifier_identifier_has_variable_test.cpp b/ets2panda/test/unit/public/ast_verifier_identifier_has_variable_test.cpp index e8a8aabcef379d53bf7469e31aaa935096369571..22da23873f7db04a271f377df4902be6c6573177 100644 --- a/ets2panda/test/unit/public/ast_verifier_identifier_has_variable_test.cpp +++ b/ets2panda/test/unit/public/ast_verifier_identifier_has_variable_test.cpp @@ -184,7 +184,7 @@ TEST_F(ASTVerifierTest, PromiseUndefined) } } -TEST_F(ASTVerifierTest, EnumInts) +TEST_F(ASTVerifierTest, EnumNumerics) { char const *text = R"( enum Color { diff --git a/ets2panda/test/unit/sizeof_node_test.cpp b/ets2panda/test/unit/sizeof_node_test.cpp index 40ed613d568551f2bc679bd4a69cd6fac9458a17..9b888bc8b0d52ecff53ac487ac35912ea1c770b3 100644 --- a/ets2panda/test/unit/sizeof_node_test.cpp +++ b/ets2panda/test/unit/sizeof_node_test.cpp @@ -304,7 +304,7 @@ size_t SizeOfNodeTest::SizeOf() sizeof(node->members_) + sizeof(node->internalName_) + sizeof(node->boxedClass_) + - sizeof(node->typeNode_) + + sizeof(node->typeAnnotation_) + Align(sizeof(node->isConst_)); // clang-format on } diff --git a/ets2panda/util/diagnostic/syntax.yaml b/ets2panda/util/diagnostic/syntax.yaml index 3df686ee44d8b292245941c27ef697760dfa1940..9432225592c477c370ac73a9065c8eb249ce1329 100644 --- a/ets2panda/util/diagnostic/syntax.yaml +++ b/ets2panda/util/diagnostic/syntax.yaml @@ -209,9 +209,9 @@ syntax: id: 36 message: "Invalid enum initialization value" -- name: ENUM_STRING_TYPE_ALL_ITEMS_INIT +- name: ENUM_NON_INT_TYPE_ALL_ITEMS_INIT id: 276 - message: "All items of string-type enumeration should be explicitly initialized." + message: "All items of non-int enumeration should be explicitly initialized." - name: ERROR_ARKTS_NO_AMBIENT_DECLS id: 308 @@ -1269,6 +1269,10 @@ syntax: id: 161 message: "'With' is deprecated and not supported any more." +- name: WRONG_ENUM_TYPE + id: 399 + message: "Member type {} cannot be assigned to enum type {}." + - name: WRONG_LEFT_OF_INSTANCEOF id: 310 message: "The left operand of 'instanceof' operator cannot be a type." @@ -1281,6 +1285,7 @@ syntax: id: 54 message: "Yield is not allowed in generator parameters." + graveyard: - 29 - 37