diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index 97bbfddfb71b518b491c79ea70af03c4c3e2fad1..ac558c3634171a66c97c9156b57ab1ab351ad5ba 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -2548,7 +2548,7 @@ checker::Type *ETSAnalyzer::Check(ir::UnaryExpression *expr) const auto argType = expr->argument_->Check(checker); const auto isCondExpr = expr->OperatorType() == lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK; - checker::Type *operandType = checker->ApplyUnaryOperatorPromotion(argType, true, true, isCondExpr); + checker::Type *operandType = checker->ApplyUnaryOperatorPromotion(expr->argument_, argType, isCondExpr); auto unboxedOperandType = isCondExpr ? checker->MaybeUnboxConditionalInRelation(argType) : checker->MaybeUnboxInRelation(argType); diff --git a/ets2panda/checker/ETSAnalyzerHelpers.cpp b/ets2panda/checker/ETSAnalyzerHelpers.cpp index f652f68e788bf04c99f3cf5025e85efc5da534f2..76a994b155c1f1804b33d0060fd07ca90ebff16b 100644 --- a/ets2panda/checker/ETSAnalyzerHelpers.cpp +++ b/ets2panda/checker/ETSAnalyzerHelpers.cpp @@ -558,8 +558,10 @@ void SetTsTypeForUnaryExpression(ETSChecker *checker, ir::UnaryExpression *expr, expr->SetTsType(checker->GlobalTypeError()); break; } - - expr->Argument()->SetTsType(expr->SetTsType(checker->SelectGlobalIntegerTypeForNumeric(operandType))); + auto exprType = expr->SetTsType(checker->SelectGlobalIntegerTypeForNumeric(operandType)); + if (!expr->Argument()->TsType()->IsETSIntEnumType()) { + expr->Argument()->SetTsType(exprType); + } break; } case lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK: { diff --git a/ets2panda/checker/ETSchecker.h b/ets2panda/checker/ETSchecker.h index 06de9f47df7fc3cd76ba9417daf3c146cc31b52d..0b6c686f56dd7037db7dcdad201bc183d4c0375e 100644 --- a/ets2panda/checker/ETSchecker.h +++ b/ets2panda/checker/ETSchecker.h @@ -594,8 +594,7 @@ public: void InferAliasLambdaType(ir::TypeNode *localTypeAnnotation, ir::ArrowFunctionExpression *init); checker::Type *ApplyConditionalOperatorPromotion(checker::ETSChecker *checker, checker::Type *unboxedL, checker::Type *unboxedR); - Type *ApplyUnaryOperatorPromotion(Type *type, bool createConst = true, bool doPromotion = true, - bool isCondExpr = false); + Type *ApplyUnaryOperatorPromotion(ir::Expression *expr, Type *type, bool isCondExpr = false); Type *HandleBooleanLogicalOperators(Type *leftType, Type *rightType, lexer::TokenType tokenType); bool HandleLogicalPotentialResult(ir::Expression *left, ir::Expression *right, ir::BinaryExpression *expr, diff --git a/ets2panda/checker/ets/helpers.cpp b/ets2panda/checker/ets/helpers.cpp index a9b83658ec1a1784c81a34dac4632baec21d12a2..dcd9c9ebbbddbbf6e82da37f90d47cf15447fb42 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -16,6 +16,7 @@ #include "checker/ETSchecker.h" #include "checker/types/globalTypesHolder.h" +#include "checker/types/ets/etsEnumType.h" #include "checker/types/ets/etsTupleType.h" #include "checker/ets/typeRelationContext.h" #include "checker/ets/typeConverter.h" @@ -372,31 +373,34 @@ checker::Type *ETSChecker::ApplyConditionalOperatorPromotion(checker::ETSChecker ES2PANDA_UNREACHABLE(); } -Type *ETSChecker::ApplyUnaryOperatorPromotion(Type *type, const bool createConst, const bool doPromotion, - const bool isCondExpr) +Type *ETSChecker::ApplyUnaryOperatorPromotion(ir::Expression *expr, Type *type, const bool isCondExpr) { Type *unboxedType = isCondExpr ? MaybeUnboxConditionalInRelation(type) : MaybeUnboxInRelation(type); + if (type != nullptr && type->IsETSIntEnumType()) { + expr->AddAstNodeFlags(ir::AstNodeFlags::GENERATE_VALUE_OF); + unboxedType = type->AsETSEnumType()->GetBaseEnumElementType(this); + } + if (unboxedType == nullptr) { return nullptr; } - if (doPromotion) { - switch (ETSType(unboxedType)) { - case TypeFlag::BYTE: - case TypeFlag::SHORT: - case TypeFlag::CHAR: { - if (!createConst) { - return GlobalIntType(); - } - return CreateIntTypeFromType(unboxedType); - } - default: { - break; - } - } + switch (ETSType(unboxedType)) { + case TypeFlag::BYTE: + [[fallthrough]]; + case TypeFlag::SHORT: + [[fallthrough]]; + case TypeFlag::CHAR: + [[fallthrough]]; + case TypeFlag::INT: + return GlobalIntBuiltinType(); + + default: + break; } - return unboxedType; + + return type; } bool ETSChecker::IsNullLikeOrVoidExpression(const ir::Expression *expr) const diff --git a/ets2panda/checker/types/ets/etsEnumType.cpp b/ets2panda/checker/types/ets/etsEnumType.cpp index 61d23b7cbf94ef87d12a88cce69cb24207f4cb97..872b611f881aab69e3cc094adb1b340c7f159bca 100644 --- a/ets2panda/checker/types/ets/etsEnumType.cpp +++ b/ets2panda/checker/types/ets/etsEnumType.cpp @@ -15,11 +15,17 @@ #include "etsEnumType.h" +#include "checker/ETSchecker.h" #include "checker/ets/conversion.h" #include "checker/types/ets/etsUnionType.h" namespace ark::es2panda::checker { +Type *ETSEnumType::GetBaseEnumElementType(ETSChecker *checker) +{ + return checker->MaybeUnboxType(SuperType()->TypeArguments()[0]); +} + bool ETSStringEnumType::AssignmentSource(TypeRelation *relation, Type *target) { bool result = false; diff --git a/ets2panda/checker/types/ets/etsEnumType.h b/ets2panda/checker/types/ets/etsEnumType.h index a5c6bdf33d7a3e767413365b6105f75f9114285b..90265cc3704cf6050badc04f8686bd96e122e34e 100644 --- a/ets2panda/checker/types/ets/etsEnumType.h +++ b/ets2panda/checker/types/ets/etsEnumType.h @@ -45,6 +45,8 @@ public: static constexpr std::string_view const VALUES_METHOD_NAME {"values"}; static constexpr std::string_view const GET_ORDINAL_METHOD_NAME {"getOrdinal"}; static constexpr std::string_view const DOLLAR_GET_METHOD_NAME {"$_get"}; + + Type *GetBaseEnumElementType(ETSChecker *checker); }; class ETSIntEnumType : public ETSEnumType { diff --git a/ets2panda/test/ast/compiler/ets/string_enum_unary.ets b/ets2panda/test/ast/compiler/ets/string_enum_unary.ets new file mode 100644 index 0000000000000000000000000000000000000000..68ca4eb5fadf8a2c1d71f6484bf4833801b8e4cc --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/string_enum_unary.ets @@ -0,0 +1,29 @@ +/* + * 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 {Red = "10"} + + +function main() { + arktest.assertEQ(~/* @@ label */Color.Red, ~10) + arktest.assertEQ(+/* @@ label1 */Color.Red, 10) + arktest.assertEQ(-/* @@ label2 */Color.Red, -10) + // This was allowed because enum is in extended conditional expression which is expected. + arktest.assertEQ(!Color.Red, !10) +} + +/* @@@ label Error TypeError: Bad operand type, the type of the operand must be numeric type. */ +/* @@@ label1 Error TypeError: Bad operand type, the type of the operand must be numeric type. */ +/* @@@ label2 Error TypeError: Bad operand type, the type of the operand must be numeric type. */ diff --git a/ets2panda/test/ast/parser/ets/increment-on-nullish-type-undefined-invalid.ets b/ets2panda/test/ast/parser/ets/increment-on-nullish-type-undefined-invalid.ets index e3b52ed7aeb2e461a67468b93781a1b56ce68a38..76b9878b1c36fbd27e2062fd1970415712d7794a 100644 --- a/ets2panda/test/ast/parser/ets/increment-on-nullish-type-undefined-invalid.ets +++ b/ets2panda/test/ast/parser/ets/increment-on-nullish-type-undefined-invalid.ets @@ -14,9 +14,8 @@ */ function main(){ let a = 1; - a/* @@ label */~/* @@ label1 */!/* @@ label2 */; + a/* @@ label */~/* @@ label2 */!/* @@ label3 */; } /* @@@ label Error SyntaxError: Unexpected token '~'. */ -/* @@@ label1 Error TypeError: Bad operand type, the type of the operand must be numeric type. */ -/* @@@ label2 Error SyntaxError: Unexpected token ';'. */ -/* @@@ label2 Error TypeError: Bad operand type, the type of the operand must be boolean type. */ +/* @@@ label2 Error TypeError: Bad operand type, the type of the operand must be numeric type. */ +/* @@@ label3 Error SyntaxError: Unexpected token ';'. */ diff --git a/ets2panda/test/runtime/ets/unary_enum.ets b/ets2panda/test/runtime/ets/unary_enum.ets new file mode 100644 index 0000000000000000000000000000000000000000..de029ba5fc11d6ea1c0a852e437f0dc2e2ccf930 --- /dev/null +++ b/ets2panda/test/runtime/ets/unary_enum.ets @@ -0,0 +1,23 @@ +/* + * 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 {Red = 10} + +function main() { + arktest.assertEQ(~Color.Red, ~10) + arktest.assertEQ(+Color.Red, 10) + arktest.assertEQ(-Color.Red, -10) + arktest.assertEQ(!Color.Red, !10) +} \ No newline at end of file