diff --git a/ets2panda/BUILD.gn b/ets2panda/BUILD.gn index dec0dc9a48863188dfa0892241c4f7db468f1392..5fd3853ad0627a2262f6e3ccc509d06aa9f6e63b 100644 --- a/ets2panda/BUILD.gn +++ b/ets2panda/BUILD.gn @@ -126,6 +126,7 @@ libes2panda_sources = [ "checker/types/ets/intType.cpp", "checker/types/ets/longType.cpp", "checker/types/ets/shortType.cpp", + "checker/types/ets/etsAnyType.cpp", "checker/types/ets/wildcardType.cpp", "checker/types/globalTypesHolder.cpp", "checker/types/signature.cpp", diff --git a/ets2panda/CMakeLists.txt b/ets2panda/CMakeLists.txt index 10cf792e9428eca26e159cbc97f4d69be8c48b6a..03ff66845f33524fdc18fdf5524b2d6757e92e18 100644 --- a/ets2panda/CMakeLists.txt +++ b/ets2panda/CMakeLists.txt @@ -581,6 +581,7 @@ set(ES2PANDA_LIB_SRC checker/types/ets/intType.cpp checker/types/ets/longType.cpp checker/types/ets/shortType.cpp + checker/types/ets/etsAnyType.cpp checker/types/ets/etsArrayType.cpp checker/types/ets/etsBooleanType.cpp checker/types/ets/etsDynamicType.cpp diff --git a/ets2panda/ast_verifier/invariants/identifierHasVariable.cpp b/ets2panda/ast_verifier/invariants/identifierHasVariable.cpp index 930ac3249abec15f18214163607aa72b5c6a036b..4eae5c316c003fd8e3545f5390611a2bd0418a13 100644 --- a/ets2panda/ast_verifier/invariants/identifierHasVariable.cpp +++ b/ets2panda/ast_verifier/invariants/identifierHasVariable.cpp @@ -25,8 +25,8 @@ public: ExceptionsMatcher(const IdentifierHasVariable *inv, const ir::Identifier *ast) : inv_(inv), ast_(ast) {} bool Match() { - auto res = IsLengthProp() || IsEmptyName() || IsInObjectExpr() || IsInPackageDecl() || IsUtilityType() || - IsUnionMemberAccess() || IsFixedArrayType(); + auto res = IsLengthProp() || IsEmptyName() || IsInObjectExpr() || IsInPackageDecl() || IsBuiltinType() || + IsUnionMemberAccess(); return res; } @@ -69,16 +69,13 @@ private: return false; } - bool IsUtilityType() + bool IsBuiltinType() { + auto name = ast_->Name(); // NOTE(mmartin): find a better solution to handle utility type resolution - return ast_->Name().Is(Signatures::PARTIAL_TYPE_NAME) || ast_->Name().Is(Signatures::REQUIRED_TYPE_NAME) || - ast_->Name().Is(Signatures::READONLY_TYPE_NAME); - } - - bool IsFixedArrayType() - { - return ast_->Name().Is(Signatures::FIXED_ARRAY_TYPE_NAME); + return name.Is(Signatures::PARTIAL_TYPE_NAME) || name.Is(Signatures::REQUIRED_TYPE_NAME) || + name.Is(Signatures::READONLY_TYPE_NAME) || name.Is(Signatures::FIXED_ARRAY_TYPE_NAME) || + name.Is(compiler::Signatures::ANY_TYPE_NAME); } bool IsUnionMemberAccess() diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index 9c5c1c1bdd0b3a79d9e19d010f6261e9d128d59d..19596b245787ab8a9b559e726937ca02f37fc6b1 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -849,6 +849,11 @@ static bool CheckArrayExpressionElements(ETSChecker *checker, ir::ArrayExpressio return allElementsAssignable; } +static bool IsPossibleArrayExpressionType(Type const *type) +{ + return type->IsETSArrayType() || type->IsETSTupleType() || type->IsETSResizableArrayType(); +} + void ETSAnalyzer::GetUnionPreferredType(ir::Expression *expr, Type *originalType) const { if (originalType == nullptr || !originalType->IsETSUnionType()) { @@ -856,7 +861,7 @@ void ETSAnalyzer::GetUnionPreferredType(ir::Expression *expr, Type *originalType } checker::Type *preferredType = nullptr; for (auto &type : originalType->AsETSUnionType()->ConstituentTypes()) { - if (type->IsETSArrayType() || type->IsETSTupleType() || type->IsETSResizableArrayType()) { + if (IsPossibleArrayExpressionType(type)) { if (preferredType != nullptr) { preferredType = nullptr; break; @@ -890,6 +895,10 @@ checker::Type *ETSAnalyzer::Check(ir::ArrayExpression *expr) const if (expr->GetPreferredType()->IsETSUnionType()) { GetUnionPreferredType(expr, expr->GetPreferredType()); } + + if (expr->GetPreferredType() != nullptr && !IsPossibleArrayExpressionType(expr->GetPreferredType())) { + expr->SetPreferredType(nullptr); + } } if (!IsArrayExpressionValidInitializerForType(checker, expr->GetPreferredType())) { @@ -1564,7 +1573,7 @@ checker::Type *ETSAnalyzer::Check(ir::CallExpression *expr) const } if (calleeType->IsETSArrowType()) { expr->SetUncheckedType(checker->GuaranteedTypeForUncheckedCast( - checker->GlobalETSNullishObjectType(), checker->MaybeBoxType(expr->Signature()->ReturnType()))); + checker->GlobalETSAnyType(), checker->MaybeBoxType(expr->Signature()->ReturnType()))); } else { expr->SetUncheckedType(checker->GuaranteedTypeForUncheckedCallReturn(expr->Signature())); } @@ -1826,7 +1835,7 @@ checker::Type *ETSAnalyzer::Check(ir::MemberExpression *expr) const } if (!checker->CheckNonNullish(expr->Object())) { auto *invalidType = checker->HasStatus(checker::CheckerStatus::IN_EXTENSION_ACCESSOR_CHECK) - ? checker->GlobalETSNullishType() + ? checker->GlobalETSUnionUndefinedNull() : checker->InvalidateType(expr); return invalidType; } diff --git a/ets2panda/checker/ETSAnalyzerHelpers.cpp b/ets2panda/checker/ETSAnalyzerHelpers.cpp index f652f68e788bf04c99f3cf5025e85efc5da534f2..de15a13dd997e4472e25de008da1ef6e19dc41a2 100644 --- a/ets2panda/checker/ETSAnalyzerHelpers.cpp +++ b/ets2panda/checker/ETSAnalyzerHelpers.cpp @@ -516,8 +516,7 @@ void ProcessExclamationMark(ETSChecker *checker, ir::UnaryExpression *expr, chec return; } - if (operandType == nullptr || !operandType->IsConditionalExprType()) { - checker->LogError(diagnostic::ASSERT_NOT_LOGICAL, {}, expr->Argument()->Start()); + if (operandType == nullptr || operandType->IsTypeError()) { expr->SetTsType(checker->GlobalTypeError()); return; } diff --git a/ets2panda/checker/ETSchecker.cpp b/ets2panda/checker/ETSchecker.cpp index 227ef1787433fb492bd4752c543ec7fd86cfe94c..9255b39ae7f2fb15105975c8b7766e00ef0f86df 100644 --- a/ets2panda/checker/ETSchecker.cpp +++ b/ets2panda/checker/ETSchecker.cpp @@ -411,6 +411,22 @@ bool ETSChecker::IsClassStaticMethod(checker::ETSObjectType *objType, checker::S signature->HasSignatureFlag(checker::SignatureFlags::STATIC); } +[[nodiscard]] TypeFlag ETSChecker::TypeKind(const Type *const type) noexcept +{ + // These types were not present in the ETS_TYPE list. Some of them are omited intentionally, other are just bugs + static constexpr auto TO_CLEAR = TypeFlag::CONSTANT | TypeFlag::GENERIC | TypeFlag::ETS_INT_ENUM | + TypeFlag::ETS_STRING_ENUM | TypeFlag::READONLY | TypeFlag::BIGINT_LITERAL | + TypeFlag::ETS_TYPE_ALIAS | TypeFlag::TYPE_ERROR; + + // Bugs: these types do not appear as a valid TypeKind, as the TypeKind has more then one bit set + [[maybe_unused]] static constexpr auto NOT_A_TYPE_KIND = TypeFlag::ETS_DYNAMIC_FLAG; + + auto res = static_cast(type->TypeFlags() & ~(TO_CLEAR)); + ES2PANDA_ASSERT_POS(res == TypeFlag::NONE || helpers::math::IsPowerOfTwo(res & ~(NOT_A_TYPE_KIND)), + ark::es2panda::GetPositionForDiagnostic()); + return res; +} + template ETSObjectType *ETSChecker::AsETSObjectType(Type *(GlobalTypesHolder::*typeFunctor)(Args...), Args... args) const { @@ -512,6 +528,11 @@ Type *ETSChecker::GlobalETSUndefinedType() const return GetGlobalTypesHolder()->GlobalETSUndefinedType(); } +Type *ETSChecker::GlobalETSAnyType() const +{ + return GetGlobalTypesHolder()->GlobalETSAnyType(); +} + Type *ETSChecker::GlobalETSNeverType() const { return GetGlobalTypesHolder()->GlobalETSNeverType(); @@ -537,15 +558,15 @@ ETSObjectType *ETSChecker::GlobalETSObjectType() const return AsETSObjectType(&GlobalTypesHolder::GlobalETSObjectType); } -ETSUnionType *ETSChecker::GlobalETSNullishType() const +ETSUnionType *ETSChecker::GlobalETSUnionUndefinedNull() const { - auto *ret = (GetGlobalTypesHolder()->*&GlobalTypesHolder::GlobalETSNullishType)(); + auto *ret = (GetGlobalTypesHolder()->*&GlobalTypesHolder::GlobalETSUnionUndefinedNull)(); return ret != nullptr ? ret->AsETSUnionType() : nullptr; } -ETSUnionType *ETSChecker::GlobalETSNullishObjectType() const +ETSUnionType *ETSChecker::GlobalETSUnionUndefinedNullObject() const { - auto *ret = (GetGlobalTypesHolder()->*&GlobalTypesHolder::GlobalETSNullishObjectType)(); + auto *ret = (GetGlobalTypesHolder()->*&GlobalTypesHolder::GlobalETSUnionUndefinedNullObject)(); return ret != nullptr ? ret->AsETSUnionType() : nullptr; } diff --git a/ets2panda/checker/ETSchecker.h b/ets2panda/checker/ETSchecker.h index 06de9f47df7fc3cd76ba9417daf3c146cc31b52d..da0dc4378956303b6c9e7f5fe0bbe12cb0730191 100644 --- a/ets2panda/checker/ETSchecker.h +++ b/ets2panda/checker/ETSchecker.h @@ -88,15 +88,12 @@ public: NO_COPY_SEMANTIC(ETSChecker); NO_MOVE_SEMANTIC(ETSChecker); - [[nodiscard]] static inline TypeFlag ETSType(const Type *const type) noexcept + [[nodiscard]] static TypeFlag ETSType(const Type *const type) noexcept { - return static_cast(type->TypeFlags() & TypeFlag::ETS_TYPE); + return ETSChecker::TypeKind(type); } - [[nodiscard]] static inline TypeFlag TypeKind(const Type *const type) noexcept - { - return static_cast(type->TypeFlags() & checker::TypeFlag::ETS_TYPE); - } + [[nodiscard]] static TypeFlag TypeKind(const Type *const type) noexcept; Type *GlobalByteType() const; Type *GlobalShortType() const; @@ -109,6 +106,7 @@ public: Type *GlobalVoidType() const; Type *GlobalETSNullType() const; Type *GlobalETSUndefinedType() const; + Type *GlobalETSAnyType() const; Type *GlobalETSNeverType() const; Type *GlobalETSStringLiteralType() const; Type *GlobalETSBigIntType() const; @@ -124,8 +122,8 @@ public: Type *GlobalETSBooleanBuiltinType() const; ETSObjectType *GlobalETSObjectType() const; - ETSUnionType *GlobalETSNullishType() const; - ETSUnionType *GlobalETSNullishObjectType() const; + ETSUnionType *GlobalETSUnionUndefinedNull() const; + ETSUnionType *GlobalETSUnionUndefinedNullObject() const; ETSObjectType *GlobalBuiltinETSResizableArrayType() const; ETSObjectType *GlobalBuiltinETSStringType() const; ETSObjectType *GlobalBuiltinETSBigIntType() const; diff --git a/ets2panda/checker/ets/aliveAnalyzer.cpp b/ets2panda/checker/ets/aliveAnalyzer.cpp index ff2ba27302437785434c2801d9608996fdfe6f70..5714edf7ca2bab62ae9b8767a0b40ed3f901c782 100644 --- a/ets2panda/checker/ets/aliveAnalyzer.cpp +++ b/ets2panda/checker/ets/aliveAnalyzer.cpp @@ -281,7 +281,7 @@ void AliveAnalyzer::AnalyzeDoLoop(const ir::DoWhileStatement *doWhile) AnalyzeStat(doWhile->Body()); status_ = Or(status_, ResolveContinues(doWhile)); AnalyzeNode(doWhile->Test()); - ES2PANDA_ASSERT(doWhile->Test()->TsType() && doWhile->Test()->TsType()->IsConditionalExprType()); + ES2PANDA_ASSERT(doWhile->Test()->TsType()); const auto exprRes = doWhile->Test()->TsType()->ResolveConditionExpr(); status_ = And(status_, static_cast(!std::get<0>(exprRes) || !std::get<1>(exprRes))); status_ = Or(status_, ResolveBreaks(doWhile)); @@ -291,7 +291,7 @@ void AliveAnalyzer::AnalyzeWhileLoop(const ir::WhileStatement *whileStmt) { SetOldPendingExits(PendingExits()); AnalyzeNode(whileStmt->Test()); - ES2PANDA_ASSERT(whileStmt->Test()->TsType() && whileStmt->Test()->TsType()->IsConditionalExprType()); + ES2PANDA_ASSERT(whileStmt->Test()->TsType()); const auto exprRes = whileStmt->Test()->TsType()->ResolveConditionExpr(); status_ = And(status_, static_cast(!std::get<0>(exprRes) || std::get<1>(exprRes))); AnalyzeStat(whileStmt->Body()); @@ -309,7 +309,7 @@ void AliveAnalyzer::AnalyzeForLoop(const ir::ForUpdateStatement *forStmt) if (forStmt->Test() != nullptr) { AnalyzeNode(forStmt->Test()); - ES2PANDA_ASSERT(forStmt->Test()->TsType() && forStmt->Test()->TsType()->IsConditionalExprType()); + ES2PANDA_ASSERT(forStmt->Test()->TsType()); condType = forStmt->Test()->TsType(); std::tie(resolveType, res) = forStmt->Test()->TsType()->ResolveConditionExpr(); status_ = From(!resolveType || res); diff --git a/ets2panda/checker/ets/arithmetic.cpp b/ets2panda/checker/ets/arithmetic.cpp index 7f9007daec83c514d2c16c020d68ae3b9deeb99e..9fe9eee1e418e44606aa3e4f2e4ce83a80e72737 100644 --- a/ets2panda/checker/ets/arithmetic.cpp +++ b/ets2panda/checker/ets/arithmetic.cpp @@ -556,15 +556,16 @@ checker::Type *ETSChecker::CheckBinaryOperatorLogical(ir::Expression *left, ir:: return CreateETSUnionType({MaybeBoxExpression(left), MaybeBoxExpression(right)}); } +// NOTE: code inside this function follows the broken logic bool ETSChecker::CheckValidEqualReferenceType(checker::Type *const leftType, checker::Type *const rightType) { - auto isGlobalObjectType {[](checker::Type *const type) -> bool { - return type->IsETSObjectType() && type->AsETSObjectType()->IsGlobalETSObjectType(); + auto isRelaxedType {[](checker::Type *const type) -> bool { + return (type->IsETSObjectType() && type->AsETSObjectType()->IsGlobalETSObjectType()) || type->IsETSAnyType() || + type->IsETSNullType() || type->IsETSUndefinedType(); }}; - // Equality expression is always allowed for Object, undefined and null - if (isGlobalObjectType(leftType) || isGlobalObjectType(rightType) || leftType->IsETSUndefinedType() || - rightType->IsETSUndefinedType() || leftType->IsETSNullType() || rightType->IsETSNullType()) { + // Equality expression is always allowed for *magic types* + if (isRelaxedType(leftType) || isRelaxedType(rightType)) { return true; } @@ -651,10 +652,10 @@ static Type *CheckOperatorEqualDynamic(ETSChecker *checker, BinaryArithmOperands } if (otherExp->TsType()->IsETSReferenceType()) { // have to prevent casting dyn_exp via ApplyCast without nullish flag - return checker->GlobalETSNullishObjectType(); + return checker->GlobalETSAnyType(); } checker->LogError(diagnostic::BINOP_DYN_UNIMPLEMENTED, {}, ops.expr->Start()); - return checker->GlobalETSNullishObjectType(); + return checker->GlobalETSAnyType(); } static Type *HandelReferenceBinaryEquality(ETSChecker *checker, BinaryArithmOperands const &ops) diff --git a/ets2panda/checker/ets/helpers.cpp b/ets2panda/checker/ets/helpers.cpp index a9b83658ec1a1784c81a34dac4632baec21d12a2..43db915edd0bef65702e397cbc77935590920e53 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -1093,7 +1093,7 @@ std::pair ETSChecker::CheckTestNullishCondition(Type *testedType return {GlobalETSUndefinedType(), RemoveUndefinedType(actualType)}; } - return {GlobalETSNullishType(), GetNonNullishType(actualType)}; + return {GlobalETSUnionUndefinedNull(), GetNonNullishType(actualType)}; } // Auxiliary method to reduce the size of common 'CheckTestSmartCastConditions' function. diff --git a/ets2panda/checker/ets/object.cpp b/ets2panda/checker/ets/object.cpp index c5724a9d7e175efa7d20ad4fda5cfce5b6e2c599..4fc956301c109fcf65c82edc6ef35aaed9faf9a5 100644 --- a/ets2panda/checker/ets/object.cpp +++ b/ets2panda/checker/ets/object.cpp @@ -374,7 +374,7 @@ void ETSChecker::SetUpTypeParameterConstraint(ir::TSTypeParameter *const param) traverseReferenced(param->Constraint()); paramType->SetConstraintType(param->Constraint()->GetType(this)); } else { - paramType->SetConstraintType(GlobalETSNullishObjectType()); + paramType->SetConstraintType(GlobalETSAnyType()); } if (param->DefaultType() != nullptr) { @@ -399,7 +399,7 @@ ETSTypeParameter *ETSChecker::SetUpParameterType(ir::TSTypeParameter *const para paramType->SetDeclNode(param); paramType->SetVariable(param->Variable()); // NOTE: #15026 recursive type parameter workaround - paramType->SetConstraintType(GlobalETSNullishObjectType()); + paramType->SetConstraintType(GlobalETSAnyType()); var->SetTsType(paramType); return paramType; diff --git a/ets2panda/checker/ets/typeCheckingHelpers.cpp b/ets2panda/checker/ets/typeCheckingHelpers.cpp index 2848d1fa2be24bd6f480f0ac6f30e86b1fa86f8b..2f70b2d7b0d67151d18baa0d26439da0d7527169 100644 --- a/ets2panda/checker/ets/typeCheckingHelpers.cpp +++ b/ets2panda/checker/ets/typeCheckingHelpers.cpp @@ -55,8 +55,7 @@ void ETSChecker::CheckTruthinessOfType(ir::Expression *expr) expr->SetTsType(conditionType); - if (conditionType == nullptr || (!conditionType->IsTypeError() && !conditionType->IsConditionalExprType())) { - LogError(diagnostic::NOT_COND_TYPE, {}, expr->Start()); + if (conditionType == nullptr) { return; } @@ -94,6 +93,9 @@ Type *ETSChecker::GetNonNullishType(Type *type) if (type->DefinitelyNotETSNullish()) { return type; } + if (type->IsETSAnyType()) { + return type; + } if (type->IsETSTypeParameter()) { return ProgramAllocator()->New(type->AsETSTypeParameter()); } @@ -116,7 +118,7 @@ Type *ETSChecker::GetNonNullishType(Type *type) Type *ETSChecker::RemoveNullType(Type *const type) { - if (type->DefinitelyNotETSNullish() || type->IsETSUndefinedType()) { + if (type->IsETSAnyType() || type->DefinitelyNotETSNullish() || type->IsETSUndefinedType()) { return type; } @@ -144,7 +146,7 @@ Type *ETSChecker::RemoveNullType(Type *const type) Type *ETSChecker::RemoveUndefinedType(Type *const type) { - if (type->DefinitelyNotETSNullish() || type->IsETSNullType()) { + if (type->IsETSAnyType() || type->DefinitelyNotETSNullish() || type->IsETSNullType()) { return type; } @@ -176,8 +178,12 @@ std::pair ETSChecker::RemoveNullishTypes(Type *type) return {GetGlobalTypesHolder()->GlobalETSNeverType(), type}; } + if (type->IsETSAnyType()) { + return {type, type}; + } + if (type->IsETSTypeParameter()) { - return {GetGlobalTypesHolder()->GlobalETSNullishType(), + return {GetGlobalTypesHolder()->GlobalETSUnionUndefinedNull(), ProgramAllocator()->New(type->AsETSTypeParameter())}; } @@ -251,21 +257,21 @@ static bool MatchConstituentOrConstraint(const Type *type, Pred const &pred) bool Type::PossiblyETSNull() const { return MatchConstituentOrConstraint( - this, [](const Type *t) { return t->IsETSNullType(); }, + this, [](const Type *t) { return t->IsETSAnyType() || t->IsETSNullType(); }, [](const Type *t) { return !t->IsETSNonNullishType(); }); } bool Type::PossiblyETSUndefined() const { return MatchConstituentOrConstraint( - this, [](const Type *t) { return t->IsETSUndefinedType(); }, + this, [](const Type *t) { return t->IsETSAnyType() || t->IsETSUndefinedType(); }, [](const Type *t) { return !t->IsETSNonNullishType(); }); } bool Type::PossiblyETSNullish() const { return MatchConstituentOrConstraint( - this, [](const Type *t) { return t->IsETSNullType() || t->IsETSUndefinedType(); }, + this, [](const Type *t) { return t->IsETSAnyType() || t->IsETSNullType() || t->IsETSUndefinedType(); }, [](const Type *t) { return !t->IsETSNonNullishType(); }); } @@ -287,7 +293,8 @@ bool Type::DefinitelyNotETSNullish() const bool Type::PossiblyETSString() const { return MatchConstituentOrConstraint(this, [](const Type *t) { - return t->IsETSStringType() || (t->IsETSObjectType() && t->AsETSObjectType()->IsGlobalETSObjectType()); + return t->IsETSAnyType() || t->IsETSStringType() || + (t->IsETSObjectType() && t->AsETSObjectType()->IsGlobalETSObjectType()); }); } @@ -308,7 +315,8 @@ bool Type::PossiblyETSValueTyped() const bool Type::PossiblyETSValueTypedExceptNullish() const { return MatchConstituentOrConstraint(this, [](const Type *t) { - return t->IsETSFunctionType() || (t->IsETSObjectType() && IsValueTypedObjectType(t->AsETSObjectType())); + return t->IsETSAnyType() || t->IsETSFunctionType() || + (t->IsETSObjectType() && IsValueTypedObjectType(t->AsETSObjectType())); }); } @@ -328,9 +336,9 @@ bool Type::IsETSMethodType() const static constexpr TypeFlag ETS_SANE_REFERENCE_TYPE = TypeFlag::TYPE_ERROR | TypeFlag::ETS_NULL | TypeFlag::ETS_UNDEFINED | TypeFlag::ETS_OBJECT | TypeFlag::ETS_TYPE_PARAMETER | TypeFlag::WILDCARD | TypeFlag::ETS_NONNULLISH | - TypeFlag::ETS_REQUIRED_TYPE_PARAMETER | TypeFlag::ETS_NEVER | TypeFlag::ETS_UNION | TypeFlag::ETS_ARRAY | - TypeFlag::FUNCTION | TypeFlag::ETS_PARTIAL_TYPE_PARAMETER | TypeFlag::ETS_TUPLE | TypeFlag::ETS_ENUM | - TypeFlag::ETS_READONLY; + TypeFlag::ETS_REQUIRED_TYPE_PARAMETER | TypeFlag::ETS_ANY | TypeFlag::ETS_NEVER | TypeFlag::ETS_UNION | + TypeFlag::ETS_ARRAY | TypeFlag::FUNCTION | TypeFlag::ETS_PARTIAL_TYPE_PARAMETER | TypeFlag::ETS_TUPLE | + TypeFlag::ETS_ENUM | TypeFlag::ETS_READONLY; // Issues if (type->IsETSVoidType()) { // NOTE(vpukhov): #19701 void refactoring @@ -340,7 +348,7 @@ bool Type::IsETSMethodType() const return true; } if (type->IsNeverType()) { // NOTE(vpukhov): #20562 We use ets/never and ts/never simultaneously - return true; + ES2PANDA_UNREACHABLE(); } return type->HasTypeFlag(ETS_SANE_REFERENCE_TYPE); } @@ -1184,7 +1192,7 @@ Type *ETSChecker::MaybeUnboxConditionalInRelation(Type *const objectType) return objectType; } - if ((objectType == nullptr) || !objectType->IsConditionalExprType()) { + if (objectType == nullptr) { return nullptr; } diff --git a/ets2panda/checker/ets/typeConverter.h b/ets2panda/checker/ets/typeConverter.h index 2d0bd3db6ce4eecd8838166e27c22b1fb93d0ca7..46635fdc5d66f58cfaa086f6b093a378a749bac2 100644 --- a/ets2panda/checker/ets/typeConverter.h +++ b/ets2panda/checker/ets/typeConverter.h @@ -62,7 +62,7 @@ public: template static Type *ConvertConstantType(Type *source, ArenaAllocator *allocator) { - switch (static_cast(source->TypeFlags() & TypeFlag::ETS_TYPE)) { + switch (static_cast(source->TypeFlags() & (TypeFlag::ETS_NUMERIC | TypeFlag::CHAR))) { case TypeFlag::INT: return ConvertConstant(source->AsIntType(), allocator); @@ -95,7 +95,7 @@ public: { ES2PANDA_ASSERT(source->IsETSPrimitiveType() && target->IsETSPrimitiveType() && source->IsConstantType()); - switch (static_cast(target->TypeFlags() & TypeFlag::ETS_TYPE)) { + switch (static_cast(target->TypeFlags() & (TypeFlag::ETS_NUMERIC | TypeFlag::CHAR))) { case TypeFlag::INT: return ConvertConstantType(source, allocator); diff --git a/ets2panda/checker/ets/typeCreation.cpp b/ets2panda/checker/ets/typeCreation.cpp index 4c35d829af3a26b73da9834501dd945f6dccaad4..509630ade7603528b07a4724d1e73a30882b3dc7 100644 --- a/ets2panda/checker/ets/typeCreation.cpp +++ b/ets2panda/checker/ets/typeCreation.cpp @@ -305,8 +305,8 @@ static ETSObjectType *InitializeGlobalBuiltinObjectType(ETSChecker *checker, Glo auto *objType = setType(GlobalTypeId::ETS_OBJECT_BUILTIN, create())->AsETSObjectType(); auto null = checker->GlobalETSNullType(); auto undef = checker->GlobalETSUndefinedType(); - setType(GlobalTypeId::ETS_NULLISH_OBJECT, checker->CreateETSUnionType({objType, null, undef})); - setType(GlobalTypeId::ETS_NULLISH_TYPE, checker->CreateETSUnionType({null, undef})); + setType(GlobalTypeId::ETS_UNION_UNDEFINED_NULL_OBJECT, checker->CreateETSUnionType({objType, null, undef})); + setType(GlobalTypeId::ETS_UNION_UNDEFINED_NULL, checker->CreateETSUnionType({null, undef})); return objType; } case GlobalTypeId::ETS_STRING_BUILTIN: { diff --git a/ets2panda/checker/ets/utilityTypeHandlers.cpp b/ets2panda/checker/ets/utilityTypeHandlers.cpp index d9e630189d243cb885cff4441381ba66f7eeb067..11d256dedbe959b12d5c8b74904dbe7435d405e8 100644 --- a/ets2panda/checker/ets/utilityTypeHandlers.cpp +++ b/ets2panda/checker/ets/utilityTypeHandlers.cpp @@ -59,6 +59,10 @@ Type *ETSChecker::HandleUtilityTypeParameterNode(const ir::TSTypeParameterInstan return GlobalTypeError(); } + if (baseType->IsETSAnyType()) { + return baseType; + } + if (utilityType == compiler::Signatures::PARTIAL_TYPE_NAME) { // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) return CreatePartialType(baseType); @@ -115,6 +119,10 @@ Type *ETSChecker::CreatePartialType(Type *const typeToBePartial) { ES2PANDA_ASSERT(typeToBePartial->IsETSReferenceType()); + if (typeToBePartial->IsETSAnyType()) { + return typeToBePartial; + } + if (typeToBePartial->IsETSTypeParameter()) { return CreatePartialTypeParameter(typeToBePartial->AsETSTypeParameter()); } diff --git a/ets2panda/checker/types/ets/etsAnyType.cpp b/ets2panda/checker/types/ets/etsAnyType.cpp new file mode 100644 index 0000000000000000000000000000000000000000..811705455b8d6f9b88ff1d5b3624ce67a0aa2d46 --- /dev/null +++ b/ets2panda/checker/types/ets/etsAnyType.cpp @@ -0,0 +1,112 @@ +/* + * 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. + */ + +#include "etsAnyType.h" + +#include "checker/ETSchecker.h" +#include "checker/ets/conversion.h" +#include "etsTypeParameter.h" + +namespace ark::es2panda::checker { +void ETSAnyType::Identical(TypeRelation *relation, Type *other) +{ + relation->Result(other->IsAnyType()); +} + +void ETSAnyType::AssignmentTarget(TypeRelation *relation, Type *source) +{ + if (!source->IsETSPrimitiveType()) { + relation->Result(true); + return; + } + + if (relation->ApplyBoxing()) { + auto checker = relation->GetChecker()->AsETSChecker(); + relation->GetNode()->AddBoxingUnboxingFlags(checker->GetBoxingFlag(checker->MaybeBoxType(source))); + relation->Result(true); + } +} + +bool ETSAnyType::AssignmentSource(TypeRelation *relation, Type *target) +{ + Identical(relation, target); + return relation->IsTrue(); +} + +void ETSAnyType::Compare([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *other) +{ + ES2PANDA_UNREACHABLE(); +} + +void ETSAnyType::Cast(TypeRelation *relation, Type *target) +{ + if (!relation->InCastingContext()) { + Identical(relation, target); + return; + } + + if (!target->IsETSPrimitiveType()) { + relation->Result(true); + return; + } + + if (relation->ApplyUnboxing()) { + auto *const boxedTarget = relation->GetChecker()->AsETSChecker()->MaybeBoxInRelation(target); + conversion::Unboxing(relation, boxedTarget->AsETSObjectType()); + relation->Result(true); + } +} + +void ETSAnyType::CastTarget(TypeRelation *relation, [[maybe_unused]] Type *source) +{ + AssignmentTarget(relation, source); +} + +void ETSAnyType::IsSubtypeOf(TypeRelation *relation, Type *target) +{ + Identical(relation, target); +} + +void ETSAnyType::IsSupertypeOf(TypeRelation *relation, Type *source) +{ + relation->Result(!source->IsETSPrimitiveType()); +} + +void ETSAnyType::ToString(std::stringstream &ss, [[maybe_unused]] bool precise) const +{ + ss << compiler::Signatures::ANY_TYPE_NAME; +} + +void ETSAnyType::ToAssemblerType(std::stringstream &ss) const +{ + ss << compiler::Signatures::BUILTIN_OBJECT; +} + +TypeFacts ETSAnyType::GetTypeFacts() const +{ + return TypeFacts::NONE; +} + +void ETSAnyType::ToDebugInfoType(std::stringstream &ss) const +{ + ss << ETSObjectType::NameToDescriptor(compiler::Signatures::BUILTIN_OBJECT); +} + +Type *ETSAnyType::Instantiate(ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, + [[maybe_unused]] GlobalTypesHolder *globalTypes) +{ + return allocator->New(); +} +} // namespace ark::es2panda::checker \ No newline at end of file diff --git a/ets2panda/checker/types/ets/etsAnyType.h b/ets2panda/checker/types/ets/etsAnyType.h new file mode 100644 index 0000000000000000000000000000000000000000..3dbca0c808e843261e5c8ecd42ef2b6e0b43f280 --- /dev/null +++ b/ets2panda/checker/types/ets/etsAnyType.h @@ -0,0 +1,49 @@ +/* + * 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. + */ +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_ETS_ANY_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_ETS_ANY_TYPE_H + +#include "checker/types/type.h" +#include "ir/astNode.h" + +namespace ark::es2panda::checker { +class ETSAnyType : public Type { +public: + ETSAnyType() : Type(TypeFlag::ETS_ANY) {} + + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + bool AssignmentSource(TypeRelation *relation, Type *target) override; + void Compare(TypeRelation *relation, Type *other) override; + void Cast(TypeRelation *relation, Type *target) override; + void CastTarget(TypeRelation *relation, Type *source) override; + void IsSubtypeOf(TypeRelation *relation, Type *target) override; + void IsSupertypeOf(TypeRelation *relation, Type *source) override; + void ToString(std::stringstream &ss, bool precise) const override; + void ToAssemblerType(std::stringstream &ss) const override; + void ToDebugInfoType([[maybe_unused]] std::stringstream &ss) const override; + + TypeFacts GetTypeFacts() const override; + + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + + std::tuple ResolveConditionExpr() const override + { + return {IsConstantType(), false}; + } +}; +} // namespace ark::es2panda::checker + +#endif diff --git a/ets2panda/checker/types/ets/etsFunctionType.cpp b/ets2panda/checker/types/ets/etsFunctionType.cpp index 1df9fd28eac9bc6271cff13c4bf63277ce2ae0d8..288967ac2a8cf5bad249a34048c918d08ca19258 100644 --- a/ets2panda/checker/types/ets/etsFunctionType.cpp +++ b/ets2panda/checker/types/ets/etsFunctionType.cpp @@ -73,7 +73,9 @@ static ETSObjectType *FunctionTypeToFunctionalInterfaceType(ETSChecker *checker, if (signature->RestVar() != nullptr) { auto *functionN = checker->GlobalBuiltinFunctionType(arity, true)->AsETSObjectType(); auto *substitution = checker->NewSubstitution(); - auto *elementType = checker->GetElementTypeOfArray(signature->RestVar()->TsType()); + auto *elementType = !signature->RestVar()->TsType()->IsETSTupleType() + ? checker->GetElementTypeOfArray(signature->RestVar()->TsType()) + : checker->GlobalETSAnyType(); substitution->emplace(functionN->TypeArguments()[0]->AsETSTypeParameter(), checker->MaybeBoxType(elementType)); return functionN->Substitute(checker->Relation(), substitution, true, isExtensionHack); } diff --git a/ets2panda/checker/types/ets/types.h b/ets2panda/checker/types/ets/types.h index 89d59b801ed6bc0f632dd6dd7f7adf08473c41f8..68b9f0079e01979ddefd35e89163c968e3b2077c 100644 --- a/ets2panda/checker/types/ets/types.h +++ b/ets2panda/checker/types/ets/types.h @@ -40,6 +40,7 @@ #include "etsNullishTypes.h" #include "checker/types/signature.h" #include "etsReadonlyType.h" +#include "etsAnyType.h" #include "etsNeverType.h" #endif /* TYPES_H */ diff --git a/ets2panda/checker/types/globalTypesHolder.cpp b/ets2panda/checker/types/globalTypesHolder.cpp index 784aa977a409c2561d3418a1ec74d7eb7821fb44..300e9b3fbf2d5ffe883189398111f9a2634f32c5 100644 --- a/ets2panda/checker/types/globalTypesHolder.cpp +++ b/ets2panda/checker/types/globalTypesHolder.cpp @@ -48,6 +48,7 @@ #include "checker/types/ets/etsNullishTypes.h" #include "checker/types/ets/etsObjectType.h" #include "checker/types/ets/wildcardType.h" +#include "checker/types/ets/etsAnyType.h" #include "checker/types/ets/etsNeverType.h" #include "util/helpers.h" @@ -148,11 +149,13 @@ void GlobalTypesHolder::AddEtsSpecificTypes(ArenaAllocator *allocator) globalTypes_[static_cast(GlobalTypeId::ETS_UNDEFINED)] = allocator->New(); globalTypes_[static_cast(GlobalTypeId::ETS_WILDCARD)] = allocator->New(); globalTypes_[static_cast(GlobalTypeId::TYPE_ERROR)] = allocator->New(); + globalTypes_[static_cast(GlobalTypeId::ETS_ANY)] = allocator->New(); globalTypes_[static_cast(GlobalTypeId::ETS_NEVER)] = allocator->New(); } void GlobalTypesHolder::AddEtsSpecificBuiltinTypes() { + builtinNameMappings_.emplace("Any", GlobalTypeId::ETS_ANY); builtinNameMappings_.emplace("Boolean", GlobalTypeId::ETS_BOOLEAN_BUILTIN); builtinNameMappings_.emplace("Byte", GlobalTypeId::ETS_BYTE_BUILTIN); builtinNameMappings_.emplace("Char", GlobalTypeId::ETS_CHAR_BUILTIN); @@ -403,19 +406,24 @@ Type *GlobalTypesHolder::GlobalETSUndefinedType() return globalTypes_.at(static_cast(GlobalTypeId::ETS_UNDEFINED)); } +Type *GlobalTypesHolder::GlobalETSAnyType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_ANY)); +} + Type *GlobalTypesHolder::GlobalETSNeverType() { return globalTypes_.at(static_cast(GlobalTypeId::ETS_NEVER)); } -Type *GlobalTypesHolder::GlobalETSNullishObjectType() +Type *GlobalTypesHolder::GlobalETSUnionUndefinedNullObject() { - return globalTypes_.at(static_cast(GlobalTypeId::ETS_NULLISH_OBJECT)); + return globalTypes_.at(static_cast(GlobalTypeId::ETS_UNION_UNDEFINED_NULL_OBJECT)); } -Type *GlobalTypesHolder::GlobalETSNullishType() +Type *GlobalTypesHolder::GlobalETSUnionUndefinedNull() { - return globalTypes_.at(static_cast(GlobalTypeId::ETS_NULLISH_TYPE)); + return globalTypes_.at(static_cast(GlobalTypeId::ETS_UNION_UNDEFINED_NULL)); } Type *GlobalTypesHolder::GlobalWildcardType() diff --git a/ets2panda/checker/types/globalTypesHolder.h b/ets2panda/checker/types/globalTypesHolder.h index 2242097f8d854483c454b3d2ab6f24672ae1840c..635c8b080e5aed24f6ad9827b259a2d41b5f180c 100644 --- a/ets2panda/checker/types/globalTypesHolder.h +++ b/ets2panda/checker/types/globalTypesHolder.h @@ -57,9 +57,10 @@ enum class GlobalTypeId : std::size_t { ETS_OBJECT_BUILTIN, ETS_NULL, ETS_UNDEFINED, - ETS_NULLISH_TYPE, + ETS_UNION_UNDEFINED_NULL, + ETS_ANY, ETS_NEVER, - ETS_NULLISH_OBJECT, + ETS_UNION_UNDEFINED_NULL_OBJECT, ETS_WILDCARD, ETS_BOOLEAN_BUILTIN, ETS_BYTE_BUILTIN, @@ -267,9 +268,10 @@ public: Type *GlobalETSObjectType(); Type *GlobalETSNullType(); Type *GlobalETSUndefinedType(); + Type *GlobalETSAnyType(); Type *GlobalETSNeverType(); - Type *GlobalETSNullishType(); - Type *GlobalETSNullishObjectType(); + Type *GlobalETSUnionUndefinedNull(); + Type *GlobalETSUnionUndefinedNullObject(); Type *GlobalWildcardType(); Type *GlobalETSBooleanBuiltinType(); Type *GlobalByteBuiltinType(); diff --git a/ets2panda/checker/types/type.h b/ets2panda/checker/types/type.h index 1a0895b37a62d2824bab0b9fbf52314c9f7a80e5..d6d1fb2f7dc9444b1b81ae6e0e5f29c6c4af3e01 100644 --- a/ets2panda/checker/types/type.h +++ b/ets2panda/checker/types/type.h @@ -186,11 +186,6 @@ public: return reinterpret_cast(this); } - bool IsConditionalExprType() const - { - return HasTypeFlag(TypeFlag::CONDITION_EXPRESSION_TYPE); - } - bool IsConstantType() const { return HasTypeFlag(checker::TypeFlag::CONSTANT); diff --git a/ets2panda/checker/types/typeFlag.h b/ets2panda/checker/types/typeFlag.h index 86e149f3a3d2ce2c4816b00280f55012f2b91548..feea58ce1294a994cceccb60c8811fb08999593c 100644 --- a/ets2panda/checker/types/typeFlag.h +++ b/ets2panda/checker/types/typeFlag.h @@ -48,7 +48,6 @@ enum class TypeFlag : uint64_t { INTERSECTION = 1ULL << 19ULL, // x: a & b INDEX = 1ULL << 20ULL, // keyof x INDEX_ACCESS = 1ULL << 21ULL, // x[a] - CONDITIONAL = 1ULL << 22ULL, // x extends a ? b : c TEMPLATE_LITERAL = 1ULL << 23ULL, // x: `hello ${World}` ANY = 1ULL << 24ULL, // x: any ARRAY = 1ULL << 25ULL, // x: number[] @@ -88,14 +87,11 @@ enum class TypeFlag : uint64_t { ETS_PARTIAL_TYPE_PARAMETER = 1ULL << 59ULL, // ETS Partial type parameter TYPE_ERROR = 1ULL << 60ULL, // type error ETS_TYPE_ALIAS = 1ULL << 61ULL, // ETS Type alias + ETS_ANY = 1ULL << 22ULL, // ETS any, the value was *stolen* from the CONDITIONAL type kind ETS_NEVER = 1ULL << 62ULL, // ETS never ETS_METHOD = 1ULL << 63ULL, // ETS method (or function in module) (possibly overloaded) ETS_DYNAMIC_TYPE = ETS_OBJECT | ETS_DYNAMIC_FLAG, ETS_DYNAMIC_FUNCTION_TYPE = FUNCTION | ETS_DYNAMIC_FLAG, - ETS_TYPE = BYTE | SHORT | INT | LONG | FLOAT | DOUBLE | CHAR | ETS_BOOLEAN | ETS_VOID | ETS_OBJECT | ETS_ARRAY | - FUNCTION | WILDCARD | ETS_TYPE_PARAMETER | ETS_DYNAMIC_TYPE | ETS_UNION | ETS_NULL | ETS_UNDEFINED | - ETS_NONNULLISH | ETS_READONLY | ETS_REQUIRED_TYPE_PARAMETER | ETS_PARTIAL_TYPE_PARAMETER | ETS_NEVER | - ETS_TUPLE, ETS_INTEGRAL_NUMERIC = BYTE | SHORT | INT | LONG, ETS_FLOATING_POINT = FLOAT | DOUBLE, ETS_NUMERIC = ETS_INTEGRAL_NUMERIC | ETS_FLOATING_POINT, @@ -123,9 +119,6 @@ enum class TypeFlag : uint64_t { VALID_ARITHMETIC_TYPE = ANY | NUMBER_LIKE | BIGINT_LIKE | ENUM, UNIT = LITERAL | UNDEFINED | NULL_TYPE, GETTER_SETTER = GETTER | SETTER, - CONDITION_EXPRESSION_TYPE = ETS_NULL | ETS_UNDEFINED | ETS_OBJECT | ETS_ARRAY | ETS_UNION | CONSTANT | BYTE | CHAR | - SHORT | INT | LONG | FLOAT | DOUBLE | ETS_BOOLEAN | ETS_INT_ENUM | ETS_STRING_ENUM | - FUNCTION | ETS_TUPLE, }; } // namespace ark::es2panda::checker diff --git a/ets2panda/checker/types/typeMapping.h b/ets2panda/checker/types/typeMapping.h index 4964190828798d93cc53c3a26e0c5e4aabd8f83e..a856a49bdbc8561f4e98e87e5be6a1b936804281 100644 --- a/ets2panda/checker/types/typeMapping.h +++ b/ets2panda/checker/types/typeMapping.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2021-2024 Huawei Device Co., Ltd. + * Copyright (c) 2021-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 @@ -53,6 +53,7 @@ _(TypeFlag::ETS_VOID, ETSVoidType) \ _(TypeFlag::ETS_NULL, ETSNullType) \ _(TypeFlag::ETS_UNDEFINED, ETSUndefinedType) \ + _(TypeFlag::ETS_ANY, ETSAnyType) \ _(TypeFlag::ETS_NEVER, ETSNeverType) \ _(TypeFlag::FUNCTION, ETSFunctionType) \ _(TypeFlag::ETS_OBJECT, ETSObjectType) \ diff --git a/ets2panda/compiler/base/condition.cpp b/ets2panda/compiler/base/condition.cpp index c8a7d0de4dbbc06d728f934d25c777bec1edc21a..dc0b40e8dcf4da57ec0d3704d5ef263e206e8a11 100644 --- a/ets2panda/compiler/base/condition.cpp +++ b/ets2panda/compiler/base/condition.cpp @@ -235,7 +235,6 @@ void Condition::Compile(ETSGen *etsg, const ir::Expression *expr, Label *falseLa etsg->BranchIfTrue(expr, falseLabel); return; } - ES2PANDA_ASSERT(expr->TsType()->IsConditionalExprType()); expr->Compile(etsg); etsg->ApplyConversion(expr, etsg->Checker()->GlobalETSBooleanType()); etsg->ResolveConditionalResultIfFalse(expr, falseLabel); diff --git a/ets2panda/compiler/core/ETSCompiler.cpp b/ets2panda/compiler/core/ETSCompiler.cpp index 76dc7e8bdf242dafd6d446983f30a8cf3945072a..c7bf4dca5f63a7d010622ae830669b1ba27b313a 100644 --- a/ets2panda/compiler/core/ETSCompiler.cpp +++ b/ets2panda/compiler/core/ETSCompiler.cpp @@ -1665,6 +1665,7 @@ void ETSCompiler::CompileCast(const ir::TSAsExpression *expr) const case checker::TypeFlag::ETS_NONNULLISH: case checker::TypeFlag::ETS_PARTIAL_TYPE_PARAMETER: case checker::TypeFlag::ETS_UNION: + case checker::TypeFlag::ETS_ANY: case checker::TypeFlag::ETS_NULL: case checker::TypeFlag::ETS_UNDEFINED: { etsg->CastToReftype(expr, targetType, expr->isUncheckedCast_); diff --git a/ets2panda/compiler/core/ETSGen.cpp b/ets2panda/compiler/core/ETSGen.cpp index e539dffc831402c382dcc99a5fcb1be9960bf545..84960c75e6084deb1f4011ae274f9a3c1a5b2c5f 100644 --- a/ets2panda/compiler/core/ETSGen.cpp +++ b/ets2panda/compiler/core/ETSGen.cpp @@ -692,18 +692,6 @@ void ETSGen::ReturnAcc(const ir::AstNode *node) } } -static bool IsAnyReferenceSupertype(checker::Type const *type) -{ - if (!type->IsETSUnionType()) { - return false; - } - auto const &constituent = type->AsETSUnionType()->ConstituentTypes(); - return constituent.size() == 3U && std::all_of(constituent.begin(), constituent.end(), [](checker::Type *t) { - return t->IsETSUndefinedType() || t->IsETSNullType() || - (t->IsETSObjectType() && t->AsETSObjectType()->IsGlobalETSObjectType()); - }); // CC-OFF(G.FMT.02) project code style -} - static bool IsNullUnsafeObjectType(checker::Type const *type) { return type->IsETSObjectType() && type->AsETSObjectType()->IsGlobalETSObjectType(); @@ -741,10 +729,10 @@ void ETSGen::IsInstanceDynamic(const ir::BinaryExpression *const node, const VRe Language lang = rhsType->AsETSDynamicType()->Language(); VReg dynTypeReg = MoveAccToReg(node); LoadAccumulator(node, srcReg); - Sa().Emit(node, Checker()->GlobalBuiltinDynamicType(lang)->AssemblerName()); + EmitIsInstance(node, Checker()->GlobalBuiltinDynamicType(lang)->AssemblerName()); BranchIfFalse(node, ifFalse); LoadAccumulator(node, srcReg); - Sa().Emit(node, Checker()->GlobalBuiltinDynamicType(lang)->AssemblerName()); + EmitCheckCast(node, Checker()->GlobalBuiltinDynamicType(lang)->AssemblerName()); CallExact(node, Signatures::BUILTIN_JSRUNTIME_INSTANCE_OF_DYNAMIC, srcReg, dynTypeReg); SetLabel(node, ifFalse); } else { @@ -798,7 +786,7 @@ void ETSGen::TestIsInstanceConstituent(const ir::AstNode *const node, std::tuple break; case checker::TypeFlag::ETS_OBJECT: if (!IsNullUnsafeObjectType(target)) { - Sa().Emit(node, ToAssemblerType(target)); + EmitIsInstance(node, ToAssemblerType(target)); BranchIfTrue(node, ifTrue); break; } @@ -810,7 +798,7 @@ void ETSGen::TestIsInstanceConstituent(const ir::AstNode *const node, std::tuple case checker::TypeFlag::ETS_ARRAY: case checker::TypeFlag::ETS_TUPLE: case checker::TypeFlag::FUNCTION: { - Sa().Emit(node, ToAssemblerType(target)); + EmitIsInstance(node, ToAssemblerType(target)); BranchIfTrue(node, ifTrue); break; } @@ -858,7 +846,7 @@ void ETSGen::IsInstance(const ir::AstNode *const node, const VReg srcReg, const target = Checker()->GetApparentType(target); ES2PANDA_ASSERT(target->IsETSReferenceType()); - if (IsAnyReferenceSupertype(target)) { // should be IsSupertypeOf(target, source) + if (target->IsETSAnyType()) { // should be IsSupertypeOf(target, source) LoadAccumulatorBoolean(node, true); return; } @@ -885,7 +873,7 @@ void ETSGen::InternalIsInstance(const ir::AstNode *node, const es2panda::checker { ES2PANDA_ASSERT(target->IsETSObjectType() || target->IsETSArrayType()); if (!IsNullUnsafeObjectType(target)) { - Sa().Emit(node, ToAssemblerType(target)); + EmitIsInstance(node, ToAssemblerType(target)); SetAccumulatorType(Checker()->GlobalETSBooleanType()); } else { LoadAccumulatorBoolean(node, true); @@ -897,7 +885,7 @@ void ETSGen::InternalCheckCast(const ir::AstNode *node, const es2panda::checker: { ES2PANDA_ASSERT(target->IsETSObjectType() || target->IsETSArrayType() || target->IsETSTupleType()); if (!IsNullUnsafeObjectType(target)) { - Sa().Emit(node, ToAssemblerType(target)); + EmitCheckCast(node, ToAssemblerType(target)); } SetAccumulatorType(target); } @@ -951,7 +939,7 @@ void ETSGen::CheckedReferenceNarrowing(const ir::AstNode *node, const checker::T target = Checker()->GetApparentType(target); ES2PANDA_ASSERT(target->IsETSReferenceType()); - if (IsAnyReferenceSupertype(target)) { // should be IsSupertypeOf(target, source) + if (target->IsETSAnyType()) { // should be IsSupertypeOf(target, source) SetAccumulatorType(target); return; } @@ -973,7 +961,7 @@ void ETSGen::CheckedReferenceNarrowing(const ir::AstNode *node, const checker::T SetLabel(node, ifTrue); LoadAccumulator(node, srcReg); // Verifier can't infer type if isinstance met, help him - Sa().Emit(node, ToAssemblerType(target)); + EmitCheckCast(node, ToAssemblerType(target)); SetAccumulatorType(target); } @@ -1734,7 +1722,7 @@ void ETSGen::CastDynamicToObject(const ir::AstNode *node, const checker::Type *t // and this function will need to be refactored in the future. if (targetType->IsETSArrayType() || targetType->IsETSObjectType() || targetType->IsETSTypeParameter() || targetType->IsETSUnionType() || targetType->IsETSFunctionType() || targetType->DefinitelyETSNullish() || - targetType->IsETSTupleType()) { + targetType->IsETSTupleType() || targetType->IsETSAnyType()) { auto lang = GetAccumulatorType()->AsETSDynamicType()->Language(); auto methodName = compiler::Signatures::Dynamic::GetObjectBuiltin(lang); @@ -1749,7 +1737,7 @@ void ETSGen::CastDynamicToObject(const ir::AstNode *node, const checker::Type *t StoreAccumulator(node, typeReg); Ra().Emit(node, methodName, dynObjReg, typeReg); - Sa().Emit(node, assemblerType); // trick verifier + EmitCheckCast(node, assemblerType); // trick verifier SetAccumulatorType(targetType); return; } @@ -1794,6 +1782,7 @@ void ETSGen::CastToDynamic(const ir::AstNode *node, const checker::ETSDynamicTyp case checker::TypeFlag::ETS_NONNULLISH: case checker::TypeFlag::ETS_PARTIAL_TYPE_PARAMETER: case checker::TypeFlag::ETS_UNION: // NOTE(vpukhov): refine dynamic type cast rules + case checker::TypeFlag::ETS_ANY: if (GetAccumulatorType()->IsETSStringType()) { methodName = compiler::Signatures::Dynamic::NewStringBuiltin(type->Language()); break; @@ -2129,7 +2118,7 @@ void ETSGen::ResolveConditionalResultReference(const ir::AstNode *node) compiler::VReg objReg = AllocReg(); StoreAccumulator(node, objReg); - Sa().Emit(node, Checker()->GlobalBuiltinETSStringType()->AssemblerName()); + EmitIsInstance(node, Checker()->GlobalBuiltinETSStringType()->AssemblerName()); BranchIfTrue(node, isString); Sa().Emit(node, 1); Branch(node, end); @@ -2305,10 +2294,9 @@ void ETSGen::BranchIfNotNullish(const ir::AstNode *node, Label *ifNotNullish) void ETSGen::AssumeNonNullish(const ir::AstNode *node, checker::Type const *targetType) { auto const *nullishType = GetAccumulatorType(); - if (nullishType->PossiblyETSNull() && - ToAssemblerType(targetType) != ToAssemblerType(Checker()->GlobalETSObjectType())) { + if (nullishType->PossiblyETSNull()) { // clear 'null' dataflow - Sa().Emit(node, ToAssemblerType(targetType)); + EmitCheckCast(node, ToAssemblerType(targetType)); } SetAccumulatorType(targetType); } @@ -2683,7 +2671,6 @@ void ETSGen::Negate(const ir::AstNode *node) void ETSGen::LogicalNot(const ir::AstNode *node) { - ES2PANDA_ASSERT(GetAccumulatorType()->IsConditionalExprType()); ResolveConditionalResultIfFalse(node); Sa().Emit(node, 1); SetAccumulatorType(Checker()->GlobalETSBooleanType()); diff --git a/ets2panda/compiler/core/ETSGen.h b/ets2panda/compiler/core/ETSGen.h index dcc6d78ab118ad0acfe31e3fc9a1ea93bed7b8a8..6b3400e02c0f73128399fe6316fecc1c2fef8696 100644 --- a/ets2panda/compiler/core/ETSGen.h +++ b/ets2panda/compiler/core/ETSGen.h @@ -477,6 +477,22 @@ private: #endif // PANDA_WITH_ETS } + void EmitCheckCast(const ir::AstNode *node, util::StringView target) + { + if (target != Signatures::BUILTIN_OBJECT) { + Sa().Emit(node, target); + } + } + + void EmitIsInstance(const ir::AstNode *node, util::StringView target) + { + if (target != Signatures::BUILTIN_OBJECT) { + Sa().Emit(node, target); + } else { + LoadAccumulatorBoolean(node, true); + } + } + template void EmitEtsEquals([[maybe_unused]] const ir::AstNode *node, [[maybe_unused]] const VReg lhs, [[maybe_unused]] const VReg rhs) diff --git a/ets2panda/compiler/lowering/ets/arrayLiteralLowering.cpp b/ets2panda/compiler/lowering/ets/arrayLiteralLowering.cpp index a9aa187de82ac2c266206b969e1b8ef6a7812535..a933800ade97be80116563d4964a61c3a3b3550b 100644 --- a/ets2panda/compiler/lowering/ets/arrayLiteralLowering.cpp +++ b/ets2panda/compiler/lowering/ets/arrayLiteralLowering.cpp @@ -40,7 +40,7 @@ ArenaVector ArrayLiteralLowering::GenerateDefaultCallToConstruc { std::stringstream ss; std::vector newStmts; - if (!eleType->IsETSUnionType()) { + if (!eleType->IsETSUnionType() && !eleType->IsETSAnyType()) { auto *indexSymbol = Gensym(Allocator()); auto *lengthSymbol = Gensym(Allocator()); auto *typeNode = checker_->AllocNode(eleType, Allocator()); diff --git a/ets2panda/compiler/lowering/ets/declareOverloadLowering.cpp b/ets2panda/compiler/lowering/ets/declareOverloadLowering.cpp index 613fcf10d239657b8c98836c6c3e3fda9bf9e6a2..b9679b253f8dcd51869f1a189de9c34bd38d28c9 100644 --- a/ets2panda/compiler/lowering/ets/declareOverloadLowering.cpp +++ b/ets2panda/compiler/lowering/ets/declareOverloadLowering.cpp @@ -30,7 +30,7 @@ void GenerateOverloadHelperParams(public_lib::Context *ctx, uint32_t minArg, siz if (!hasRestVar) { for (size_t idx = 0; idx < maxArg; ++idx) { auto *id = Gensym(allocator); - auto *typeAnnotation = ctx->AllocNode(checker->GlobalETSNullishObjectType(), allocator); + auto *typeAnnotation = ctx->AllocNode(checker->GlobalETSAnyType(), allocator); id->SetTsTypeAnnotation(typeAnnotation); typeAnnotation->SetParent(id); auto *param = ctx->AllocNode(id, false, allocator); @@ -42,7 +42,7 @@ void GenerateOverloadHelperParams(public_lib::Context *ctx, uint32_t minArg, siz auto *restIdent = Gensym(allocator); auto *spread = ctx->AllocNode(ir::AstNodeType::REST_ELEMENT, allocator, restIdent); - auto *arr = checker->CreateETSArrayType(checker->GlobalETSNullishObjectType(), false); + auto *arr = checker->CreateETSArrayType(checker->GlobalETSAnyType(), false); auto *typeAnnotation = ctx->AllocNode(arr, allocator); spread->SetTsTypeAnnotation(typeAnnotation); @@ -68,7 +68,7 @@ void BuildOverloadHelperFunction(public_lib::Context *ctx, ir::MethodDefinition auto params = ArenaVector(allocator->Adapter()); GenerateOverloadHelperParams(ctx, minArg, maxArg, hasRestVar, params); - auto *returnType = returnVoid ? checker->GlobalVoidType() : checker->GlobalETSNullishObjectType(); + auto *returnType = returnVoid ? checker->GlobalVoidType() : checker->GlobalETSAnyType(); auto *returnAnno = ctx->AllocNode(returnType, allocator); ir::ScriptFunctionFlags functionFlag = method->Function()->Flags(); diff --git a/ets2panda/compiler/lowering/ets/enumPostCheckLowering.cpp b/ets2panda/compiler/lowering/ets/enumPostCheckLowering.cpp index 6e555c258c7b6d94031b4f892ce8b29bf21334c3..c21054995595e29100e34d8da091510c840cf2b3 100644 --- a/ets2panda/compiler/lowering/ets/enumPostCheckLowering.cpp +++ b/ets2panda/compiler/lowering/ets/enumPostCheckLowering.cpp @@ -209,7 +209,7 @@ ir::Expression *EnumPostCheckLoweringPhase::HandleEnumTypeCasting(checker::Type // Generate fromValue call; if (type->IsETSEnumType()) { auto exprType = expr->TsType(); - if (exprType->IsETSEnumType() || + if (exprType->IsETSEnumType() || exprType->IsETSAnyType() || (exprType->IsETSObjectType() && exprType->AsETSObjectType()->IsGlobalETSObjectType())) { return expr; } diff --git a/ets2panda/compiler/lowering/ets/lambdaLowering.cpp b/ets2panda/compiler/lowering/ets/lambdaLowering.cpp index df7f1a1a0bf972437c3d2b7e367bc1c0c40bc889..b34f08ab1ca61dbb090c143f792b523ab96a4a00 100644 --- a/ets2panda/compiler/lowering/ets/lambdaLowering.cpp +++ b/ets2panda/compiler/lowering/ets/lambdaLowering.cpp @@ -387,7 +387,7 @@ static ir::MethodDefinition *CreateCallee(public_lib::Context *ctx, ir::ArrowFun auto calleeName = lambda->Function()->IsAsyncFunc() ? (util::UString {checker::ETSChecker::GetAsyncImplName(info->name), allocator}).View() : info->name; - auto *forcedReturnType = lambda->Function()->IsAsyncFunc() ? checker->GlobalETSNullishObjectType() : nullptr; + auto *forcedReturnType = lambda->Function()->IsAsyncFunc() ? checker->GlobalETSAnyType() : nullptr; CalleeMethodInfo cmInfo; cmInfo.calleeName = calleeName; @@ -536,10 +536,9 @@ static ArenaVector CreateRestArgumentsArrayReall << "}"; args = parser->CreateFormattedStatement( statements.str(), restParameterIndex, tmpArray, elementType, elementType, lciInfo->restParameterIdentifier, - lciInfo->restArgumentIdentifier, tmpArray, elementType, spreadArrIterator, - checker->GlobalETSNullishObjectType(), lciInfo->restParameterIdentifier, lciInfo->restArgumentIdentifier, - restParameterIndex, spreadArrIterator, checker->MaybeBoxType(elementType), elementType, restParameterIndex, - restParameterIndex); + lciInfo->restArgumentIdentifier, tmpArray, elementType, spreadArrIterator, checker->GlobalETSAnyType(), + lciInfo->restParameterIdentifier, lciInfo->restArgumentIdentifier, restParameterIndex, spreadArrIterator, + checker->MaybeBoxType(elementType), elementType, restParameterIndex, restParameterIndex); } else { auto *typeNode = allocator->New( checker->GetElementTypeOfArray(lciInfo->lambdaSignature->RestVar()->TsType()), allocator); @@ -556,7 +555,7 @@ static ArenaVector CreateRestArgumentsArrayReall << "}"; args = parser->CreateFormattedStatement( statements.str(), restParameterIndex, lciInfo->restArgumentIdentifier, typeNode, - lciInfo->restParameterIdentifier, spreadArrIterator, checker->GlobalETSNullishObjectType(), + lciInfo->restParameterIdentifier, spreadArrIterator, checker->GlobalETSAnyType(), lciInfo->restParameterIdentifier, lciInfo->restArgumentIdentifier, restParameterIndex, spreadArrIterator, checker->MaybeBoxType(elementType), restParameterIndex, restParameterIndex); } @@ -569,13 +568,14 @@ static void CreateInvokeMethodRestParameter(public_lib::Context *ctx, LambdaClas { auto *allocator = ctx->allocator; auto *checker = ctx->checker->AsETSChecker(); - auto *anyType = checker->GlobalETSNullishObjectType(); auto *restIdent = Gensym(allocator); lciInfo->restParameterIdentifier = restIdent->Name(); lciInfo->restArgumentIdentifier = GenName(allocator).View(); auto *spread = allocator->New(ir::AstNodeType::REST_ELEMENT, allocator, restIdent); - auto *arr = checker->CreateETSArrayType(anyType); + auto *arr = lciInfo->lambdaSignature->RestVar()->TsType()->IsETSTupleType() + ? lciInfo->lambdaSignature->RestVar()->TsType() + : checker->CreateETSArrayType(checker->GlobalETSAnyType()); auto *typeAnnotation = allocator->New(arr, allocator); spread->SetTsTypeAnnotation(typeAnnotation); @@ -672,7 +672,7 @@ static ir::BlockStatement *CreateLambdaClassInvokeBody(public_lib::Context *ctx, auto *allocator = ctx->allocator; auto *parser = ctx->parser->AsETSParser(); auto *checker = ctx->checker->AsETSChecker(); - auto *anyType = checker->GlobalETSNullishObjectType(); + auto *anyType = checker->GlobalETSAnyType(); auto *call = CreateCallForLambdaClassInvoke(ctx, info, lciInfo, wrapToObject); auto bodyStmts = CreateRestArgumentsArrayReallocation(ctx, lciInfo); @@ -700,7 +700,7 @@ static void CreateLambdaClassInvokeMethod(public_lib::Context *ctx, LambdaInfo c { auto *allocator = ctx->allocator; auto *checker = ctx->checker->AsETSChecker(); - auto *anyType = checker->GlobalETSNullishObjectType(); + auto *anyType = checker->GlobalETSAnyType(); auto params = ArenaVector(allocator->Adapter()); for (size_t idx = 0; idx < lciInfo->arity; ++idx) { diff --git a/ets2panda/compiler/scripts/signatures.yaml b/ets2panda/compiler/scripts/signatures.yaml index 496aa8e961e6aee144f65ee1a300f5aac0366e8d..c6bfa42dbc96f6aecbc514132437513f95734339 100644 --- a/ets2panda/compiler/scripts/signatures.yaml +++ b/ets2panda/compiler/scripts/signatures.yaml @@ -159,6 +159,8 @@ defines: ref: ARRAY - name: '' ref: PROPERTY + - name: 'Any' + ref: ANY_TYPE_NAME - name: 'never' ref: NEVER_TYPE_NAME - name: 'SOURCE' diff --git a/ets2panda/ir/ets/etsTypeReferencePart.cpp b/ets2panda/ir/ets/etsTypeReferencePart.cpp index 3c7089b10f5d1f33e88d8b90a5a052bc7857f3cb..5c951356deae58962bf2022ed7b012815e4b81cc 100644 --- a/ets2panda/ir/ets/etsTypeReferencePart.cpp +++ b/ets2panda/ir/ets/etsTypeReferencePart.cpp @@ -93,6 +93,62 @@ checker::VerifiedType ETSTypeReferencePart::Check(checker::ETSChecker *checker) return {this, checker->GetAnalyzer()->Check(this)}; } +static checker::Type *HandleFixedArrayType(checker::ETSChecker *const checker, ETSTypeReferencePart *ref) +{ + auto typeParams = ref->TypeParams(); + if (typeParams == nullptr || typeParams->Params().size() != 1) { + checker->LogError(diagnostic::FIXED_ARRAY_PARAM_ERROR, {}, ref->Start()); + return checker->GlobalTypeError(); + } + return checker->CreateETSArrayType(typeParams->Params()[0]->GetType(checker), ref->IsReadonlyType()); +} + +static checker::Type *HandlePartialType(checker::ETSChecker *const checker, ETSTypeReferencePart *ref) +{ + auto *baseType = checker->HandleUtilityTypeParameterNode(ref->TypeParams(), ref->GetIdent()); + if (baseType != nullptr && baseType->IsETSObjectType() && !baseType->AsETSObjectType()->TypeArguments().empty()) { + // we treat Partial> class as a different copy from A now, + // but not a generic type param for Partial<> + if (ref->TypeParams() != nullptr) { + for (auto &typeRef : ref->TypeParams()->Params()) { + checker::InstantiationContext ctx(checker, baseType->AsETSObjectType(), + typeRef->AsETSTypeReference()->Part()->TypeParams(), ref->Start()); + baseType = ctx.Result(); + } + } + } + return baseType; +} + +static checker::Type *CheckPredefinedBuiltinTypes(checker::ETSChecker *const checker, ETSTypeReferencePart *ref) +{ + auto const ident = ref->GetIdent(); + if (ident->Name() == compiler::Signatures::ANY_TYPE_NAME) { + return checker->GlobalETSAnyType(); + } + if (ident->Name() == compiler::Signatures::UNDEFINED) { + return checker->GlobalETSUndefinedType(); + } + if (ident->Name() == compiler::Signatures::NULL_LITERAL) { + return checker->GlobalETSNullType(); + } + if (ident->Name() == compiler::Signatures::NEVER_TYPE_NAME) { + return checker->GlobalETSNeverType(); + } + + if (ident->Name() == compiler::Signatures::READONLY_TYPE_NAME || + ident->Name() == compiler::Signatures::REQUIRED_TYPE_NAME) { + return checker->HandleUtilityTypeParameterNode(ref->TypeParams(), ident); + } + if (ident->Name() == compiler::Signatures::PARTIAL_TYPE_NAME) { + return HandlePartialType(checker, ref); + } + if (ident->Name() == compiler::Signatures::FIXED_ARRAY_TYPE_NAME) { + return HandleFixedArrayType(checker, ref); + } + return nullptr; +} + [[maybe_unused]] static bool CheckTypeAliaLoop(ETSTypeReferencePart *ref, varbinder::Variable *variable) { auto typeAliasDecl = variable->Declaration()->Node()->AsTSTypeAliasDeclaration(); @@ -120,7 +176,7 @@ checker::Type *ETSTypeReferencePart::HandleInternalTypes(checker::ETSChecker *co { ES2PANDA_ASSERT(name_->IsIdentifier() || name_->IsTSQualifiedName()); - Identifier *ident = GetIdent(); + Identifier *const ident = GetIdent(); varbinder::Variable *variable = nullptr; if (name_->IsIdentifier()) { @@ -143,29 +199,8 @@ checker::Type *ETSTypeReferencePart::HandleInternalTypes(checker::ETSChecker *co variable->Declaration()->AsTypeAliasDecl()->Node()->AsTSTypeAliasDeclaration()); } - if (ident->Name() == compiler::Signatures::UNDEFINED) { - return checker->GlobalETSUndefinedType(); - } - - if (ident->Name() == compiler::Signatures::NULL_LITERAL) { - return checker->GlobalETSNullType(); - } - - if (ident->Name() == compiler::Signatures::NEVER_TYPE_NAME) { - return checker->GlobalETSNeverType(); - } - - if (ident->Name() == compiler::Signatures::READONLY_TYPE_NAME || - ident->Name() == compiler::Signatures::REQUIRED_TYPE_NAME) { - return checker->HandleUtilityTypeParameterNode(typeParams_, ident); - } - - if (ident->Name() == compiler::Signatures::PARTIAL_TYPE_NAME) { - return HandlePartialType(checker, ident); - } - - if (ident->Name() == compiler::Signatures::FIXED_ARRAY_TYPE_NAME) { - return HandleFixedArrayType(checker); + if (auto res = CheckPredefinedBuiltinTypes(checker, this); res != nullptr) { + return res; } if (ident->IsErrorPlaceHolder()) { @@ -175,35 +210,6 @@ checker::Type *ETSTypeReferencePart::HandleInternalTypes(checker::ETSChecker *co return nullptr; } -checker::Type *ETSTypeReferencePart::HandleFixedArrayType(checker::ETSChecker *const checker) -{ - if (typeParams_ == nullptr || typeParams_->Params().size() != 1) { - checker->LogError(diagnostic::FIXED_ARRAY_PARAM_ERROR, {}, Start()); - return checker->GlobalTypeError(); - } - checker::Type *type = checker->CreateETSArrayType(typeParams_->Params()[0]->GetType(checker), IsReadonlyType()); - SetTsType(type); - return type; -} - -checker::Type *ETSTypeReferencePart::HandlePartialType(checker::ETSChecker *const checker, - const Identifier *const ident) -{ - auto *baseType = checker->HandleUtilityTypeParameterNode(typeParams_, ident); - if (baseType != nullptr && baseType->IsETSObjectType() && !baseType->AsETSObjectType()->TypeArguments().empty()) { - // we treat Partial> class as a different copy from A now, - // but not a generic type param for Partial<> - if (typeParams_ != nullptr) { - for (auto &typeRef : typeParams_->Params()) { - checker::InstantiationContext ctx(checker, baseType->AsETSObjectType(), - typeRef->AsETSTypeReference()->Part()->typeParams_, Start()); - baseType = ctx.Result(); - } - } - } - return baseType; -} - checker::Type *ETSTypeReferencePart::GetType(checker::ETSChecker *checker) { if (TypeParams() != nullptr) { diff --git a/ets2panda/ir/ets/etsTypeReferencePart.h b/ets2panda/ir/ets/etsTypeReferencePart.h index 4b1e6aba373dae5440ecf75c7f3606d47b884a2e..8286b312fc8a3b6daf08c488db7373260b2473fe 100644 --- a/ets2panda/ir/ets/etsTypeReferencePart.h +++ b/ets2panda/ir/ets/etsTypeReferencePart.h @@ -80,9 +80,7 @@ public: void CopyTo(AstNode *other) const override; private: - checker::Type *HandlePartialType(checker::ETSChecker *const checker, const Identifier *const ident); checker::Type *HandleInternalTypes(checker::ETSChecker *checker); - checker::Type *HandleFixedArrayType(checker::ETSChecker *const checker); friend class SizeOfNodeTest; ir::Expression *name_; diff --git a/ets2panda/lexer/scripts/keywords.yaml b/ets2panda/lexer/scripts/keywords.yaml index a3dc0855ad37d14eb158297de2be98e5d2a43960..3ed7f5ff79b968f79653accfe1985b6313fa2988 100644 --- a/ets2panda/lexer/scripts/keywords.yaml +++ b/ets2panda/lexer/scripts/keywords.yaml @@ -32,6 +32,11 @@ keywords: keyword_like: [ts] flags: [reserved_type_name] + - name: 'Any' + token: KEYW_BUILTIN_ANY + keyword_like: [ets] + flags: [predefined_type] + - name: 'anyref' token: KEYW_ANYREF keyword_like: [as] diff --git a/ets2panda/test/ast/parser/ets/FixedArray/FunctionalTypeAsArrayElement.ets b/ets2panda/test/ast/parser/ets/FixedArray/FunctionalTypeAsArrayElement.ets index e6559e42e9ff6ba90dee5124c1222bc67a0ecfd8..5a026a628857da2820a46aa5f40c2d6a48323b73 100644 --- a/ets2panda/test/ast/parser/ets/FixedArray/FunctionalTypeAsArrayElement.ets +++ b/ets2panda/test/ast/parser/ets/FixedArray/FunctionalTypeAsArrayElement.ets @@ -19,4 +19,4 @@ function main(){ ] } -/* @@? 17:48 Error TypeError: Expected type for array literal should be an array type, got () => FixedArray */ +/* @@? 17:48 Error TypeError: Type 'Array<() => Int>' cannot be assigned to type '() => FixedArray' */ diff --git a/ets2panda/test/ast/parser/ets/FunctionalTypeAsArrayElement.ets b/ets2panda/test/ast/parser/ets/FunctionalTypeAsArrayElement.ets index 4e6298318b225a5247e2ccc51396fddc999dd435..d31642e769b87be22eb93ac64b491232cfce12f0 100644 --- a/ets2panda/test/ast/parser/ets/FunctionalTypeAsArrayElement.ets +++ b/ets2panda/test/ast/parser/ets/FunctionalTypeAsArrayElement.ets @@ -19,4 +19,4 @@ function main(){ ] } -/* @@? 17:38 Error TypeError: Expected type for array literal should be an array type, got () => Array */ +/* @@? 17:38 Error TypeError: Type 'Array<() => Int>' cannot be assigned to type '() => Array' */ diff --git a/ets2panda/test/ast/parser/ets/annotations_tests/annotationDecl_bad_initializer03.ets b/ets2panda/test/ast/parser/ets/annotations_tests/annotationDecl_bad_initializer03.ets index 956e26b9c611beb309229a95dd0cc94a7eab0783..6d9b6522bd51b0dff2714bdf880f314c3a696073 100644 --- a/ets2panda/test/ast/parser/ets/annotations_tests/annotationDecl_bad_initializer03.ets +++ b/ets2panda/test/ast/parser/ets/annotations_tests/annotationDecl_bad_initializer03.ets @@ -14,8 +14,8 @@ */ @interface MyAnno { - testProperty1: string = /* @@ label */[1,2,a] + testProperty1: string = [1,2,/* @@ label */a] } -/* @@@ label Error TypeError: Expected type for array literal should be an array type, got String */ +/* @@@ label Error TypeError: Unresolved reference a */ diff --git a/ets2panda/test/ast/parser/ets/annotations_tests/annotationUsage_bad_param04.ets b/ets2panda/test/ast/parser/ets/annotations_tests/annotationUsage_bad_param04.ets index cd104710cf1c2bf5fb4186fb4da86ff654bd321a..8dd647720d7b61077d14390d6d14f468c9e708c6 100644 --- a/ets2panda/test/ast/parser/ets/annotations_tests/annotationUsage_bad_param04.ets +++ b/ets2panda/test/ast/parser/ets/annotations_tests/annotationUsage_bad_param04.ets @@ -21,4 +21,4 @@ @MyAnno({testProperty1: "1", testProperty2: [1, 2, a]}) class B{} -/* @@? 21:45 Error TypeError: Expected type for array literal should be an array type, got double */ +/* @@? 21:52 Error TypeError: Unresolved reference a */ 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..4fd228987dd3e7d8fdd3f96a96ea31f2d76daf98 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 @@ -19,4 +19,3 @@ /* @@@ 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. */ diff --git a/ets2panda/test/ast/parser/ets/type_from_utility_type.ets b/ets2panda/test/ast/parser/ets/type_from_utility_type.ets index f36c443a76ca1e9882d3669e1b5650f38e48502c..a41765f81a5b41c0e9649b74a769a36dd1519378 100644 --- a/ets2panda/test/ast/parser/ets/type_from_utility_type.ets +++ b/ets2panda/test/ast/parser/ets/type_from_utility_type.ets @@ -31,7 +31,6 @@ let recordarrA = Type.from,Array>>(); let recordarrT = Type.from,Array>>(); } - /* @@? 17:20 Error TypeError: No matching call signature */ /* @@? 30:19 Error TypeError: Bad operand type, the types of the operands must be numeric, same enumeration, or boolean type. */ /* @@? 30:29 Error TypeError: No static $_invoke method and static $_instantiate method in Record. Record() is not allowed. */ /* @@? 30:29 Error TypeError: Type 'Record' has no call signatures. */ diff --git a/ets2panda/test/runtime/ets/AnyType.ets b/ets2panda/test/runtime/ets/AnyType.ets new file mode 100644 index 0000000000000000000000000000000000000000..5b84855f12a58cb2195c2efd6043972303d62481 --- /dev/null +++ b/ets2panda/test/runtime/ets/AnyType.ets @@ -0,0 +1,41 @@ +/* + * 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: Any + +a = undefined +a = new Object() +a = null +a = 1 + +a = undefined as Any +a = new Object() as Any +a = null as Any +a = 1 as Any + +function asgn(a: T): Any { return a } + +assertTrue(asgn(null) === null) +assertTrue(asgn(undefined) === undefined) +assertTrue(asgn("a") === "a") +assertTrue(asgn(1) === 1) + +class C {} + +asgn>(new C()) +asgn>(new C()) +asgn>(new C()) +asgn>(new C()) +asgn>(new C()) diff --git a/ets2panda/test/runtime/ets/Function.ets b/ets2panda/test/runtime/ets/Function.ets index 45406aca33491c2a45baf0bab1c77e344cf5850c..5889ad5f607595a940b8d6bfc9ef912988b54328 100644 --- a/ets2panda/test/runtime/ets/Function.ets +++ b/ets2panda/test/runtime/ets/Function.ets @@ -24,9 +24,7 @@ class B extends A { } } -type __T = object | null | undefined - -function test(f: Function, action: (f: Function) => __T, v: __T) { +function test(f: Function, action: (f: Function) => Any, v: Any) { assertEQ(action(f), v) } diff --git a/ets2panda/test/runtime/ets/NoConstraint.ets b/ets2panda/test/runtime/ets/NoConstraint.ets index 16189c1b13041b33497973255f70ba69880fe865..e0736e76968d63794f1089cd3f8ab884e4dcd70a 100644 --- a/ets2panda/test/runtime/ets/NoConstraint.ets +++ b/ets2panda/test/runtime/ets/NoConstraint.ets @@ -13,13 +13,11 @@ * limitations under the License. */ -type NullishFoo = Object | null | undefined; - -function foo(x: T): NullishFoo { +function foo(x: T): Any { return x; } -function bar(x: T): NullishFoo { +function bar(x: T): Any { return x; } diff --git a/ets2panda/test/runtime/ets/defaultLocalInitializers.ets b/ets2panda/test/runtime/ets/defaultLocalInitializers.ets index 9aa08962a2e711fef15a73a921e58bb4a1c5d9e8..96cb2300f101d8bb7ea4982916b7d2721dc0f994 100644 --- a/ets2panda/test/runtime/ets/defaultLocalInitializers.ets +++ b/ets2panda/test/runtime/ets/defaultLocalInitializers.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -function erase(v: T): object | null | undefined { return v } +function erase(v: T): Any { return v } assertTrue(erase((() => { let r: boolean | undefined; diff --git a/ets2panda/test/runtime/ets/stringComparision.ets b/ets2panda/test/runtime/ets/stringComparision.ets index e1d40eabf18ef357386c4523a80f119a45808eaf..0af50e17f8e178da3b14c5fe5c34d27d644d285d 100644 --- a/ets2panda/test/runtime/ets/stringComparision.ets +++ b/ets2panda/test/runtime/ets/stringComparision.ets @@ -14,7 +14,7 @@ */ function foo(p: T, q: U): T|U { - return p!.toString() > q!.toString() ? p : q + return (p! as object).toString() > (q! as object).toString() ? p : q } function main() { diff --git a/ets2panda/util/diagnostic/semantic.yaml b/ets2panda/util/diagnostic/semantic.yaml index ba0191e4ad3dca36bac8ec8513b9cf73622f5dc8..f78c0aaa838192c073dbef194dbdddc8f31d0c8e 100644 --- a/ets2panda/util/diagnostic/semantic.yaml +++ b/ets2panda/util/diagnostic/semantic.yaml @@ -40,10 +40,6 @@ semantic: id: 7 message: Cannot use array creation expression with type parameter. -- name: NOT_COND_TYPE - id: 8 - message: "Condition must be of possible condition type" - - name: VOID_IN_LOGIC id: 9 message: "An expression of type 'void' cannot be tested for truthiness" @@ -124,10 +120,6 @@ semantic: id: 28 message: "Invalid string template expression" -- name: ASSERT_NOT_LOGICAL - id: 29 - message: "Bad operand type, the type of the operand must be boolean type." - - name: ASSERT_MESSAGE_NOT_STRING id: 30 message: "Assert message must be string" diff --git a/ets2panda/varbinder/ETSBinder.cpp b/ets2panda/varbinder/ETSBinder.cpp index 0f9ae6db10eb045584fc07219f3d5e52f561d4bc..a57a93f26dfd3d200f204042397a77da76d42157 100644 --- a/ets2panda/varbinder/ETSBinder.cpp +++ b/ets2panda/varbinder/ETSBinder.cpp @@ -56,9 +56,10 @@ void ETSBinder::LookupTypeArgumentReferences(ir::ETSTypeReference *typeRef) static bool IsSpecialName(const util::StringView &name) { - return name == compiler::Signatures::UNDEFINED || name == compiler::Signatures::NULL_LITERAL || - name == compiler::Signatures::READONLY_TYPE_NAME || name == compiler::Signatures::PARTIAL_TYPE_NAME || - name == compiler::Signatures::REQUIRED_TYPE_NAME || name == compiler::Signatures::FIXED_ARRAY_TYPE_NAME; + return name == compiler::Signatures::ANY_TYPE_NAME || name == compiler::Signatures::UNDEFINED || + name == compiler::Signatures::NULL_LITERAL || name == compiler::Signatures::READONLY_TYPE_NAME || + name == compiler::Signatures::PARTIAL_TYPE_NAME || name == compiler::Signatures::REQUIRED_TYPE_NAME || + name == compiler::Signatures::FIXED_ARRAY_TYPE_NAME; } bool ETSBinder::HandleDynamicVariables(ir::Identifier *ident, Variable *variable, bool allowDynamicNamespaces)