diff --git a/ets2panda/BUILD.gn b/ets2panda/BUILD.gn index 2ef3ae274a71ebe4ad29af07f83652d856c8d81e..e39cc1999232173388f8a53a472b1807e3a1f968 100644 --- a/ets2panda/BUILD.gn +++ b/ets2panda/BUILD.gn @@ -126,8 +126,10 @@ 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/gradualType.cpp", "checker/types/signature.cpp", "checker/types/ts/anyType.cpp", "checker/types/ts/arrayType.cpp", @@ -223,11 +225,13 @@ libes2panda_sources = [ "compiler/lowering/ets/expressionLambdaLowering.cpp", "compiler/lowering/ets/extensionAccessorLowering.cpp", "compiler/lowering/ets/genericBridgesLowering.cpp", + "compiler/lowering/ets/gradualTypeNarrowing.cpp", "compiler/lowering/ets/insertOptionalParametersAnnotation.cpp", "compiler/lowering/ets/interfaceObjectLiteralLowering.cpp", "compiler/lowering/ets/interfacePropertyDeclarations.cpp", "compiler/lowering/ets/lateInitialization.cpp", "compiler/lowering/ets/lambdaLowering.cpp", + "compiler/lowering/ets/lazyImportObject.cpp", "compiler/lowering/ets/localClassLowering.cpp", "compiler/lowering/ets/objectIndexAccess.cpp", "compiler/lowering/ets/objectIterator.cpp", diff --git a/ets2panda/CMakeLists.txt b/ets2panda/CMakeLists.txt index 0857184f54be9013c34c14c7e67067b4d2f9163b..6384b7738bb619f7027bd1c1a80b795c1effb315 100644 --- a/ets2panda/CMakeLists.txt +++ b/ets2panda/CMakeLists.txt @@ -276,6 +276,7 @@ set(ES2PANDA_LIB_SRC compiler/lowering/ets/expressionLambdaLowering.cpp compiler/lowering/ets/extensionAccessorLowering.cpp compiler/lowering/ets/genericBridgesLowering.cpp + compiler/lowering/ets/gradualTypeNarrowing.cpp compiler/lowering/ets/arrayLiteralLowering.cpp compiler/lowering/ets/boxedTypeLowering.cpp compiler/lowering/ets/boxingForLocals.cpp @@ -290,6 +291,7 @@ set(ES2PANDA_LIB_SRC compiler/lowering/ets/exportAnonymousConst.cpp compiler/lowering/ets/lateInitialization.cpp compiler/lowering/ets/lambdaLowering.cpp + compiler/lowering/ets/lazyImportObject.cpp compiler/lowering/ets/restTupleLowering.cpp compiler/lowering/ets/spreadLowering.cpp compiler/lowering/ets/localClassLowering.cpp @@ -575,6 +577,7 @@ set(ES2PANDA_LIB_SRC checker/types/type.cpp checker/types/typeRelation.cpp checker/types/globalTypesHolder.cpp + checker/types/gradualType.cpp checker/types/ets/byteType.cpp checker/types/ets/charType.cpp checker/types/ets/doubleType.cpp @@ -582,6 +585,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..c7be9377da48dd175f4dfef3716d43bdf615782b 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() || IsAnyTypeMemberAccess(); 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) || name.Is(compiler::Signatures::GRADUAL_TYPE_NAME); } bool IsUnionMemberAccess() @@ -88,6 +85,12 @@ private: !inv_->UnionLoweringOccurred(); } + bool IsAnyTypeMemberAccess() + { + return ast_->Parent() != nullptr && ast_->Parent()->IsMemberExpression() && + ast_->Parent()->AsMemberExpression()->Object()->TsType()->IsETSAnyType(); + } + private: const IdentifierHasVariable *inv_ {}; const ir::Identifier *ast_ {}; diff --git a/ets2panda/ast_verifier/invariants/modifierAccessValid.cpp b/ets2panda/ast_verifier/invariants/modifierAccessValid.cpp index 58ce2de70a8439b4446c9198aa3a03bd1de71147..ca18ceb48fbafe542521d60f42b4021c71a85e6e 100644 --- a/ets2panda/ast_verifier/invariants/modifierAccessValid.cpp +++ b/ets2panda/ast_verifier/invariants/modifierAccessValid.cpp @@ -39,7 +39,8 @@ CheckResult ModifierAccessValid::HandleMethodExpression(const ir::AstNode *ast) } const auto *propVar = ast->AsMemberExpression()->PropVar(); if (propVar != nullptr && propVar->HasFlag(varbinder::VariableFlags::PROPERTY) && - !ValidateVariableAccess(propVar, ast->AsMemberExpression())) { + !ValidateVariableAccess(propVar, ast->AsMemberExpression()) && + !ast->AsMemberExpression()->ObjType()->HasObjectFlag(checker::ETSObjectFlags::DECL_MODULE)) { AddCheckMessage("PROPERTY_NOT_VISIBLE_HERE", *ast); return {CheckDecision::INCORRECT, CheckAction::CONTINUE}; } diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index cc87b76f3415a275a203b6ca591e1364e7951a92..89e5014e1a568d8d94d13be0d14bb383c1cbccb0 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -507,32 +507,36 @@ checker::Type *ETSAnalyzer::Check(ir::ETSNewClassInstanceExpression *expr) const return checker->InvalidateType(expr); } auto *calleeObj = calleeType->AsETSObjectType(); - expr->SetTsType(calleeObj); - - if (calleeType->IsETSDynamicType() && !calleeType->AsETSDynamicType()->HasDecl()) { - auto lang = calleeType->AsETSDynamicType()->Language(); - expr->SetSignature(checker->ResolveDynamicCallExpression(expr->GetTypeRef(), expr->GetArguments(), lang, true)); + if (calleeType->IsGradualType()) { + expr->SetTsType(calleeType); } else { - auto *signature = checker->ResolveConstructExpression(calleeObj, expr->GetArguments(), expr->Start()); - - if (signature == nullptr) { - return checker->InvalidateType(expr); - } + expr->SetTsType(calleeObj); + } - checker->CheckObjectLiteralArguments(signature, expr->GetArguments()); + // if (calleeType->IsETSDynamicType() && !calleeType->AsETSDynamicType()->HasDecl()) { + // auto lang = calleeType->AsETSDynamicType()->Language(); + // expr->SetSignature(checker->ResolveDynamicCallExpression(expr->GetTypeRef(), expr->GetArguments(), lang, true)); - checker->ValidateSignatureAccessibility(calleeObj, signature, expr->Start()); + auto *signature = checker->ResolveConstructExpression(calleeObj, expr->GetArguments(), expr->Start()); - if (calleeType->IsETSDynamicType()) { - ES2PANDA_ASSERT(signature->Function()->IsDynamic()); - auto lang = calleeType->AsETSDynamicType()->Language(); - expr->SetSignature( - checker->ResolveDynamicCallExpression(expr->GetTypeRef(), signature->Params(), lang, true)); - } else { - expr->SetSignature(signature); - } + if (signature == nullptr) { + return checker->InvalidateType(expr); } + checker->CheckObjectLiteralArguments(signature, expr->GetArguments()); + + checker->ValidateSignatureAccessibility(calleeObj, signature, expr->Start()); + + // if (calleeType->IsETSDynamicType()) { + // ES2PANDA_ASSERT(signature->Function()->IsDynamic()); + // auto lang = calleeType->AsETSDynamicType()->Language(); + // expr->SetSignature( + // checker->ResolveDynamicCallExpression(expr->GetTypeRef(), signature->Params(), lang, true)); + // } else { + expr->SetSignature(signature); + // } + + return expr->TsType(); } @@ -849,6 +853,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 +865,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 +899,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())) { @@ -1410,13 +1423,13 @@ Type *ETSAnalyzer::GetReturnType(ir::CallExpression *expr, Type *calleeType) con checker->ValidateSignatureAccessibility(calleeObj, signature, expr->Start()); } - if (calleeType->IsETSMethodType() && signature->Function()->IsDynamic()) { - ES2PANDA_ASSERT(signature->Function()->IsDynamic()); - auto lang = signature->Function()->Language(); - expr->SetSignature(checker->ResolveDynamicCallExpression(expr->Callee(), signature->Params(), lang, false)); - } else { - expr->SetSignature(signature); - } + // if (calleeType->IsETSMethodType() && signature->Function()->IsDynamic()) { + // ES2PANDA_ASSERT(signature->Function()->IsDynamic()); + // auto lang = signature->Function()->Language(); + // expr->SetSignature(checker->ResolveDynamicCallExpression(expr->Callee(), signature->Params(), lang, false)); + // } else { + expr->SetSignature(signature); + // } // #22951: this type should not be encoded as a signature flag if (signature->HasSignatureFlag(SignatureFlags::THIS_RETURN_TYPE)) { @@ -1474,13 +1487,18 @@ checker::Type *ETSAnalyzer::GetCallExpressionReturnType(ir::CallExpression *expr { ETSChecker *checker = GetETSChecker(); checker::Type *returnType = nullptr; - if (UNLIKELY(calleeType->IsETSDynamicType() && !calleeType->AsETSDynamicType()->HasDecl())) { + // if (UNLIKELY(calleeType->IsETSDynamicType() && !calleeType->AsETSDynamicType()->HasDecl())) { // Trailing lambda for js function call is not supported, check the correctness of `foo() {}` + // checker->EnsureValidCurlyBrace(expr); + // auto lang = calleeType->AsETSDynamicType()->Language(); + // expr->SetSignature(checker->ResolveDynamicCallExpression(expr->Callee(), expr->Arguments(), lang, false)); + // returnType = expr->Signature()->ReturnType(); + if (calleeType->IsETSAnyType()) { + // Trailing lambda for any function call is not supported, check the correctness of `foo() {}` checker->EnsureValidCurlyBrace(expr); - auto lang = calleeType->AsETSDynamicType()->Language(); - expr->SetSignature(checker->ResolveDynamicCallExpression(expr->Callee(), expr->Arguments(), lang, false)); + expr->SetSignature(checker->ResolveAnyCallExpression(expr, expr->Arguments())); returnType = expr->Signature()->ReturnType(); - } else { + } else { returnType = GetReturnType(expr, calleeType); } @@ -1554,7 +1572,10 @@ 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 if (calleeType->IsETSAnyType()) { + // TODO (daizihan): Don't do anything now, since the return type is assumed to be Any. + // expr->SetUncheckedType() } else { expr->SetUncheckedType(checker->GuaranteedTypeForUncheckedCallReturn(expr->Signature())); } @@ -1733,6 +1754,10 @@ checker::Type *ETSAnalyzer::ResolveMemberExpressionByBaseType(ETSChecker *checke return checker->InvalidateType(expr); } + if (baseType->IsETSAnyType()) { + return expr->AdjustType(checker, checker->GlobalETSAnyType()); + } + if (baseType->IsETSArrayType()) { if (expr->Property()->AsIdentifier()->Name().Is("length")) { return expr->AdjustType(checker, checker->GlobalIntType()); @@ -1813,7 +1838,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; } @@ -2252,9 +2277,9 @@ checker::Type *ETSAnalyzer::Check(ir::ObjectExpression *expr) const return expr->TsType(); } - if (expr->PreferredType()->IsETSDynamicType() && !expr->PreferredType()->AsETSDynamicType()->HasDecl()) { - return CheckDynamic(expr); - } + // if (expr->PreferredType()->IsETSDynamicType() && !expr->PreferredType()->AsETSDynamicType()->HasDecl()) { + // return CheckDynamic(expr); + // } checker::ETSObjectType *objType = ResolveObjectTypeFromPreferredType(checker, expr); @@ -3484,12 +3509,12 @@ checker::Type *ETSAnalyzer::Check(ir::TSAsExpression *expr) const checker->Relation(), diagnostic::INVALID_CAST, {sourceType, targetType}, checker::CastingContext::ConstructorData {expr->Expr(), sourceType, targetType, expr->Expr()->Start()}); - if (sourceType->IsETSDynamicType() && targetType->IsLambdaObject()) { - // NOTE: itrubachev. change targetType to created lambdaobject type. - // Now targetType is not changed, only construct signature is added to it - checker->BuildLambdaObjectClass(targetType->AsETSObjectType(), - expr->TypeAnnotation()->AsETSFunctionType()->ReturnType()); - } + // if (sourceType->IsETSDynamicType() && targetType->IsLambdaObject()) { + // // NOTE: itrubachev. change targetType to created lambdaobject type. + // // Now targetType is not changed, only construct signature is added to it + // checker->BuildLambdaObjectClass(targetType->AsETSObjectType(), + // expr->TypeAnnotation()->AsETSFunctionType()->ReturnType()); + // } expr->isUncheckedCast_ = ctx.UncheckedCast(); // Make sure the array type symbol gets created for the assembler to be able to emit checkcast. diff --git a/ets2panda/checker/ETSAnalyzerHelpers.cpp b/ets2panda/checker/ETSAnalyzerHelpers.cpp index ff4be3487e2d1f5ac6cd8e4aa1a8b2ba08f0120c..bf00645a612fabc5cc6b39a9e9e11caca2272fd2 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 01e68b8bac1558bd1cc48be51c9d1a66d9b08084..188dc2aec6727ad45a736a41ba95ff717d449918 100644 --- a/ets2panda/checker/ETSchecker.cpp +++ b/ets2panda/checker/ETSchecker.cpp @@ -25,6 +25,8 @@ #include "ir/expressions/callExpression.h" #include "ir/ts/tsInterfaceDeclaration.h" #include "ir/statements/blockStatement.h" +#include "types/type.h" +#include "utils/arena_containers.h" #include "varbinder/ETSBinder.h" #include "parser/program/program.h" #include "checker/ets/aliveAnalyzer.h" @@ -297,6 +299,33 @@ void ETSChecker::InitializeBuiltins(varbinder::ETSBinder *varbinder) AddStatus(CheckerStatus::BUILTINS_INITIALIZED); } +void ETSChecker::InitialGradualTypes() +{ + ArenaUnorderedMap etsMap {ProgramAllocator()->Adapter()}; + gradualTypes_.insert({Language(Language::Id::ETS), etsMap}); + ArenaUnorderedMap jsMap {ProgramAllocator()->Adapter()}; + gradualTypes_.insert({Language(Language::Id::JS), jsMap}); + ArenaUnorderedMap tsMap {ProgramAllocator()->Adapter()}; + gradualTypes_.insert({Language(Language::Id::TS), tsMap}); + GetOrCreateGradualType(GlobalETSBooleanBuiltinType()); + GetOrCreateGradualType(GlobalByteBuiltinType()); + GetOrCreateGradualType(GlobalShortBuiltinType()); + GetOrCreateGradualType(GlobalCharBuiltinType()); + GetOrCreateGradualType(GlobalIntBuiltinType()); + GetOrCreateGradualType(GlobalLongBuiltinType()); + GetOrCreateGradualType(GlobalFloatBuiltinType()); + GetOrCreateGradualType(GlobalDoubleBuiltinType()); + GetOrCreateGradualType(GlobalETSBooleanType()); + GetOrCreateGradualType(GlobalByteType()); + GetOrCreateGradualType(GlobalShortType()); + GetOrCreateGradualType(GlobalCharType()); + GetOrCreateGradualType(GlobalIntType()); + GetOrCreateGradualType(GlobalLongType()); + GetOrCreateGradualType(GlobalFloatType()); + GetOrCreateGradualType(GlobalDoubleType()); + GetOrCreateGradualType(GlobalTypeError()); +} + void ETSChecker::InitializeBuiltin(varbinder::Variable *var, const util::StringView &name) { Type *type {nullptr}; @@ -317,6 +346,7 @@ bool ETSChecker::StartChecker(varbinder::VarBinder *varbinder, const util::Optio auto *etsBinder = varbinder->AsETSBinder(); InitializeBuiltins(etsBinder); + InitialGradualTypes(); for (auto &entry : etsBinder->DynamicImportVars()) { auto &data = entry.second; @@ -368,6 +398,21 @@ void ETSChecker::SetDebugInfoPlugin(evaluate::ScopedDebugInfoPlugin *debugInfo) debugInfoPlugin_ = debugInfo; } +void ETSChecker::WrapTypeNode(ir::AstNode *node) +{ + std::function doNode = ([&](ir::AstNode *node) { + if (node->IsTyped() && node->AsTyped()->TsType() != nullptr) { + node->AsTyped()->SetTsType(GetOrCreateGradualType(node->AsTyped()->TsType(), false)); + } + if (node->Variable() != nullptr && node->Variable()->TsType() != nullptr) { + node->Variable()->SetTsType(GetOrCreateGradualType(node->Variable()->TsType(), false)); + } + node->Iterate([&](ir::AstNode *child) { doNode(child); }); + }); + + doNode(node); +} + void ETSChecker::CheckProgram(parser::Program *program, bool runAnalysis) { auto *savedProgram = Program(); @@ -395,6 +440,10 @@ void ETSChecker::CheckProgram(parser::Program *program, bool runAnalysis) AssignAnalyzer(this).Analyze(Program()->Ast()); } + if (program->IsDeclForDynamicStaticInterop()) { + WrapTypeNode(program->Ast()); + } + ES2PANDA_ASSERT(VarBinder()->AsETSBinder()->GetExternalRecordTable().find(program)->second); SetProgram(savedProgram); @@ -423,6 +472,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->GetUnderlyingType()->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 { @@ -524,6 +589,11 @@ Type *ETSChecker::GlobalETSUndefinedType() const return GetGlobalTypesHolder()->GlobalETSUndefinedType(); } +Type *ETSChecker::GlobalETSAnyType() const +{ + return GetGlobalTypesHolder()->GlobalETSAnyType(); +} + Type *ETSChecker::GlobalETSNeverType() const { return GetGlobalTypesHolder()->GlobalETSNeverType(); @@ -549,15 +619,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 bf9cd81c5f6056e58738977b9eb36ddbcbaf4e7c..d4aa82a88e969fc68d560d7726a81bbacba456d9 100644 --- a/ets2panda/checker/ETSchecker.h +++ b/ets2panda/checker/ETSchecker.h @@ -27,6 +27,7 @@ #include "checker/resolveResult.h" #include "ir/visitor/AstVisitor.h" #include "util/helpers.h" +#include "checker/types/gradualType.h" namespace ark::es2panda::varbinder { class VarBinder; @@ -87,6 +88,7 @@ public: // NOLINTNEXTLINE(readability-redundant-member-init) : Checker(allocator, diagnosticEngine, programAllocator), arrayTypes_(Allocator()->Adapter()), + gradualTypes_(Allocator()->Adapter()), pendingConstraintCheckRecords_(Allocator()->Adapter()), objectInstantiationMap_(Allocator()->Adapter()), invokeToArrowSignatures_(Allocator()->Adapter()), @@ -111,15 +113,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; @@ -132,6 +131,7 @@ public: Type *GlobalVoidType() const; Type *GlobalETSNullType() const; Type *GlobalETSUndefinedType() const; + Type *GlobalETSAnyType() const; Type *GlobalETSNeverType() const; Type *GlobalETSStringLiteralType() const; Type *GlobalETSBigIntType() const; @@ -147,8 +147,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; @@ -185,6 +185,7 @@ public: const util::DiagnosticMessageParams &list, const lexer::SourcePosition &at); void InitializeBuiltins(varbinder::ETSBinder *varbinder); + void InitialGradualTypes(); void InitializeBuiltin(varbinder::Variable *var, const util::StringView &name); bool StartChecker([[maybe_unused]] varbinder::VarBinder *varbinder, const util::Options &options) override; Type *CheckTypeCached(ir::Expression *expr) override; @@ -312,6 +313,8 @@ public: ETSResizableArrayType *CreateETSMultiDimResizableArrayType(Type *element, size_t dimSize); ETSResizableArrayType *CreateETSResizableArrayType(Type *element); ETSArrayType *CreateETSArrayType(Type *elementType, bool isCachePolluting = false); + GradualType *GetGlobalGradualType(Type *baseType) const; + GradualType *GetOrCreateGradualType(Type *baseType, bool recursive = true); Type *CreateETSUnionType(Span constituentTypes); template Type *CreateETSUnionType(Type *const (&arr)[N]) // NOLINT(modernize-avoid-c-arrays) @@ -512,6 +515,7 @@ public: Signature *ResolveCallExpressionAndTrailingLambda(ArenaVector &signatures, ir::CallExpression *callExpr, const lexer::SourcePosition &pos, TypeRelationFlag reportFlag = TypeRelationFlag::NONE); + Signature *ResolveAnyCallExpression(const ir::Expression *expr, const ArenaVector &arguments); void UpdateDeclarationFromSignature(ir::CallExpression *expr, checker::Signature *signature); Signature *ResolveConstructExpression(ETSObjectType *type, const ArenaVector &arguments, const lexer::SourcePosition &pos); @@ -572,6 +576,7 @@ public: const util::StringView &importPath); util::StringView FindPropNameForNamespaceImport(const util::StringView &originalName, const util::StringView &importPath); + parser::Program *SelectEntryOrExternalProgram(varbinder::ETSBinder *etsBinder, const util::StringView &importPath); void SetPropertiesForModuleObject(checker::ETSObjectType *moduleObjType, const util::StringView &importPath, ir::ETSImportDeclaration *importDecl = nullptr); void SetrModuleObjectTsType(ir::Identifier *local, checker::ETSObjectType *moduleObjType); @@ -666,6 +671,8 @@ public: Type *MaybeUnboxExpression(ir::Expression *expr); Type *MaybeBoxType(Type *type) const; Type *MaybeUnboxType(Type *type) const; + Type *MaybeGradualType(Type *baseType) const; + Type *MaybeBaseTypeOfGradualType(Type *baseType); Type const *MaybeBoxType(Type const *type) const; Type const *MaybeUnboxType(Type const *type) const; void CheckForSameSwitchCases(ArenaVector const &cases); @@ -928,6 +935,7 @@ public: { Checker::CleanUp(); arrayTypes_.clear(); + gradualTypes_.clear(); pendingConstraintCheckRecords_.clear(); constraintCheckScopesCount_ = 0; globalArraySignatures_.clear(); @@ -1041,6 +1049,7 @@ private: void SetUpTypeParameterConstraint(ir::TSTypeParameter *param); ETSObjectType *UpdateGlobalType(ETSObjectType *objType, util::StringView name); + void WrapTypeNode(ir::AstNode *node); void CheckProgram(parser::Program *program, bool runAnalysis = false); void CheckWarnings(parser::Program *program, const util::Options &options); @@ -1093,6 +1102,7 @@ private: std::unordered_set &typeAliases); ArrayMap arrayTypes_; + ArenaUnorderedMap> gradualTypes_; ArenaVector pendingConstraintCheckRecords_; ObjectInstantiationMap objectInstantiationMap_; FunctionSignatureMap invokeToArrowSignatures_; 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 b0b3e32efd5af3ce71e4525bf4e8fca6e88a970f..775e7884564d4314f560788141a41c531ee5467d 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; } @@ -627,14 +628,14 @@ std::tuple ETSChecker::CheckBinaryOperatorStrictEqual(ir::Expres } tsType = GlobalETSBooleanType(); - if (rightType->IsETSDynamicType() && leftType->IsETSDynamicType()) { - return {tsType, GlobalBuiltinJSValueType()}; - } + // if (rightType->IsETSDynamicType() && leftType->IsETSDynamicType()) { + // return {tsType, GlobalBuiltinJSValueType()}; + // } return {tsType, GlobalETSObjectType()}; } -static Type *CheckOperatorEqualDynamic(ETSChecker *checker, BinaryArithmOperands const &ops) +[[maybe_unused]] static Type *CheckOperatorEqualDynamic(ETSChecker *checker, BinaryArithmOperands const &ops) { auto left = ops.expr->Left(); auto right = ops.expr->Right(); @@ -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) @@ -703,9 +704,9 @@ static Type *CheckBinaryOperatorEqual(ETSChecker *checker, BinaryArithmOperands return checker->GlobalTypeError(); } - if (typeL->IsETSDynamicType() || typeR->IsETSDynamicType()) { - return CheckOperatorEqualDynamic(checker, ops); - } + // if (typeL->IsETSDynamicType() || typeR->IsETSDynamicType()) { + // return CheckOperatorEqualDynamic(checker, ops); + // } if (reducedL->IsETSBooleanType() && reducedR->IsETSBooleanType()) { if (reducedL->IsConstantType() && reducedR->IsConstantType()) { @@ -799,12 +800,13 @@ std::tuple ETSChecker::CheckBinaryOperatorInstanceOf(lexer::Sour return {GlobalETSBooleanType(), leftType}; } - if (rightType->IsETSDynamicType() && !rightType->AsETSDynamicType()->HasDecl()) { - LogError(diagnostic::INSTANCEOF_NOT_TYPE, {}, pos); - return {GlobalETSBooleanType(), leftType}; - } + // if (rightType->IsETSDynamicType() && !rightType->AsETSDynamicType()->HasDecl()) { + // LogError(diagnostic::INSTANCEOF_NOT_TYPE, {}, pos); + // return {GlobalETSBooleanType(), leftType}; + // } - checker::Type *opType = rightType->IsETSDynamicType() ? GlobalBuiltinJSValueType() : GlobalETSObjectType(); + checker::Type *opType = GlobalETSObjectType(); + // checker::Type *opType = rightType->IsETSDynamicType() ? GlobalBuiltinJSValueType() : GlobalETSObjectType(); // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) ComputeApparentType(rightType); RemoveStatus(checker::CheckerStatus::IN_INSTANCEOF_CONTEXT); @@ -1146,6 +1148,8 @@ std::tuple ETSChecker::CheckBinaryOperator(ir::Expression *left, return {leftType, leftType}; } + leftType = leftType->GetUnderlyingType(); + rightType = rightType->GetUnderlyingType(); CheckNeedToGenerateGetValueForBinaryExpression(expr); const bool isLogicalExtendedOperator = (operationType == lexer::TokenType::PUNCTUATOR_LOGICAL_AND) || diff --git a/ets2panda/checker/ets/function.cpp b/ets2panda/checker/ets/function.cpp index 2e33f3143634b478e9dbb21f3113d78fa216bfd7..21eff6f0bd3876ab6cf769eee64e963e1b358e5d 100644 --- a/ets2panda/checker/ets/function.cpp +++ b/ets2panda/checker/ets/function.cpp @@ -348,7 +348,9 @@ bool ETSChecker::EnhanceSubstitutionForResizableArray(const ArenaVector auto *const elementType = argumentType->IsETSResizableArrayType() ? argumentType->AsETSResizableArrayType()->ElementType() : argumentType; - return EnhanceSubstitutionForType(typeParams, paramType->ElementType(), elementType, substitution); + return EnhanceSubstitutionForType(typeParams, + paramType->GetUnderlyingType()->AsETSResizableArrayType()->ElementType(), + elementType, substitution); } Signature *ETSChecker::ValidateParameterlessConstructor(Signature *signature, const lexer::SourcePosition &pos, @@ -1187,6 +1189,21 @@ void ETSChecker::UpdateDeclarationFromSignature(ir::CallExpression *expr, checke callIdentifier->SetVariable(newVar); } +Signature *ETSChecker::ResolveAnyCallExpression(const ir::Expression *expr, const ArenaVector &arguments) +{ + for (auto arg : arguments) { + arg->Check(this); + } + auto *const signatureInfo = CreateSignatureInfo(); + // TODO (daizihan): Replaced to gradual type if it was imported from 1.1. + auto *returnType = GlobalETSAnyType(); + auto *signature = ProgramAllocator()->New(signatureInfo, returnType); + if (expr->IsCallExpression() && expr->AsCallExpression()->Callee()->IsMemberExpression()) { + signature->SetInternalName(expr->AsCallExpression()->Callee()->AsMemberExpression()->Property()->AsIdentifier()->Name()); + } + return signature; +} + Signature *ETSChecker::ResolveCallExpressionAndTrailingLambda(ArenaVector &signatures, ir::CallExpression *callExpr, const lexer::SourcePosition &pos, @@ -1566,12 +1583,12 @@ checker::ETSFunctionType *ETSChecker::BuildMethodType(ir::ScriptFunction *func) ES2PANDA_ASSERT(!func->IsArrow()); auto *nameVar = func->Id()->Variable(); ETSFunctionType *funcType; - if (func->IsDynamic()) { - funcType = CreateETSDynamicMethodType(nameVar->Name(), {{func->Signature()}, ProgramAllocator()->Adapter()}, - func->Language()); - } else { - funcType = CreateETSMethodType(nameVar->Name(), {{func->Signature()}, ProgramAllocator()->Adapter()}); - } + // if (func->IsDynamic()) { + // funcType = CreateETSDynamicMethodType(nameVar->Name(), {{func->Signature()}, ProgramAllocator()->Adapter()}, + // func->Language()); + // } else { + funcType = CreateETSMethodType(nameVar->Name(), {{func->Signature()}, ProgramAllocator()->Adapter()}); + // } funcType->SetVariable(nameVar); return funcType; } diff --git a/ets2panda/checker/ets/helpers.cpp b/ets2panda/checker/ets/helpers.cpp index 82a6fdb2c2b478b9eaf620d12aa8df2c5dc60cd6..2f77912ae6f1acce9dad8a5abb4dd30924ba980b 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -1086,7 +1086,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. @@ -1699,7 +1699,7 @@ util::StringView ETSChecker::FindPropNameForNamespaceImport(const util::StringVi } // Helps to prevent searching for the imported file among external sources if it is the entry program -static parser::Program *SelectEntryOrExternalProgram(varbinder::ETSBinder *etsBinder, +parser::Program *ETSChecker::SelectEntryOrExternalProgram(varbinder::ETSBinder *etsBinder, const util::StringView &importPath) { if (importPath.Is(etsBinder->GetGlobalRecordTable()->Program()->AbsoluteName().Mutf8())) { @@ -3040,7 +3040,12 @@ Type *ETSChecker::GetImportSpecifierObjectType(ir::ETSImportDeclaration *importD parser::Program *program = SelectEntryOrExternalProgram(static_cast(VarBinder()), importPath); if (program == nullptr) { - return GlobalTypeError(); + importPath = importDecl->DeclPath(); + program = + SelectEntryOrExternalProgram(static_cast(VarBinder()), importPath); + if (program == nullptr) { + return GlobalTypeError(); + } } auto const moduleName = program->ModuleName(); diff --git a/ets2panda/checker/ets/object.cpp b/ets2panda/checker/ets/object.cpp index cbf729d09f454287d1086ccf8e384f6ecc21ea42..f23a3b6a03d52e9dac3972aa436128216a20eda5 100644 --- a/ets2panda/checker/ets/object.cpp +++ b/ets2panda/checker/ets/object.cpp @@ -376,7 +376,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) { @@ -401,7 +401,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; @@ -1994,6 +1994,12 @@ PropertySearchFlags ETSChecker::GetSearchFlags(const ir::MemberExpression *const return searchFlag; } + if (targetRef != nullptr && targetRef->TsType()->IsETSObjectType() && + targetRef->TsType()->AsETSObjectType()->HasObjectFlag(checker::ETSObjectFlags::DECL_MODULE)) { + searchFlag |= PropertySearchFlags::SEARCH_STATIC; + return searchFlag; + } + if (targetRef != nullptr && (targetRef->HasFlag(varbinder::VariableFlags::CLASS_OR_INTERFACE_OR_ENUM) || // NOTE (DZ): need to investigate when and why `targetRef->TsType()->Variable()` can be `nullptr` @@ -2190,12 +2196,12 @@ std::vector ETSChecker::ResolveMemberReference(const ir::Member { std::vector resolveRes {}; - if (target->IsETSDynamicType() && !target->AsETSDynamicType()->HasDecl()) { - auto propName = memberExpr->Property()->AsIdentifier()->Name(); - varbinder::LocalVariable *propVar = target->AsETSDynamicType()->GetPropertyDynamic(propName, this); - resolveRes.emplace_back(ProgramAllocator()->New(propVar, ResolvedKind::PROPERTY)); - return resolveRes; - } + // if (target->IsETSDynamicType() && !target->AsETSDynamicType()->HasDecl()) { + // auto propName = memberExpr->Property()->AsIdentifier()->Name(); + // varbinder::LocalVariable *propVar = target->AsETSDynamicType()->GetPropertyDynamic(propName, this); + // resolveRes.emplace_back(ProgramAllocator()->New(propVar, ResolvedKind::PROPERTY)); + // return resolveRes; + // } if (target->GetDeclNode() != nullptr && target->GetDeclNode()->IsClassDefinition() && !target->GetDeclNode()->AsClassDefinition()->IsClassDefinitionChecked()) { @@ -2271,9 +2277,9 @@ void ETSChecker::CheckValidInheritance(ETSObjectType *classType, ir::ClassDefini if (classType->SuperType() == nullptr) { return; } - if (classType->SuperType()->IsETSDynamicType()) { - LogError(diagnostic::EXTEND_DYNAMIC, {classDef->Ident()->Name()}, classDef->Start()); - } + // if (classType->SuperType()->IsETSDynamicType()) { + // LogError(diagnostic::EXTEND_DYNAMIC, {classDef->Ident()->Name()}, classDef->Start()); + // } const auto &allProps = classType->GetAllProperties(); diff --git a/ets2panda/checker/ets/typeCheckingHelpers.cpp b/ets2panda/checker/ets/typeCheckingHelpers.cpp index 1fa0493279befe6b6429cb10983fd5d8b5782f9d..40850a2d72488829f58f4124b7c26394da14c312 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())}; } @@ -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); } @@ -1159,6 +1167,10 @@ Type *ETSChecker::MaybeUnboxInRelation(Type *type) return nullptr; } + if (type->IsGradualType()) { + return MaybeUnboxInRelation(type->GetUnderlyingType()); + } + if (type->IsETSPrimitiveType()) { return type; } @@ -1181,7 +1193,7 @@ Type *ETSChecker::MaybeUnboxConditionalInRelation(Type *const objectType) return objectType; } - if ((objectType == nullptr) || !objectType->IsConditionalExprType()) { + if (objectType == nullptr) { return nullptr; } @@ -1235,6 +1247,23 @@ Type const *ETSChecker::MaybeUnboxType(Type const *type) const return MaybeUnboxType(const_cast(type)); } +Type *ETSChecker::MaybeGradualType(Type *type) const +{ + if (Program()->IsDeclForDynamicStaticInterop()) { + return GetGlobalGradualType(type); + } + return type; +} + +Type *ETSChecker::MaybeBaseTypeOfGradualType(Type *type) +{ + if (!type->IsGradualType()) { + return type; + } + + return type->GetUnderlyingType(); +} + ir::BoxingUnboxingFlags ETSChecker::GetBoxingFlag(Type *const boxingType) { auto typeKind = TypeKind(MaybeUnboxInRelation(boxingType)); @@ -1348,9 +1377,9 @@ void ETSChecker::CheckBoxedSourceTypeAssignable(TypeRelation *relation, Type *so } ES2PANDA_ASSERT(target != nullptr); // Do not box primitive in case of cast to dynamic types - if (target->IsETSDynamicType()) { - return; - } + // if (target->IsETSDynamicType()) { + // return; + // } relation->IsAssignableTo(boxedSourceType, target); if (relation->IsTrue()) { MaybeAddBoxingFlagInRelation(relation, boxedSourceType); 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 53b6838523debd2753639fa0ebed2702c14a6745..9ace5c530a8c99750c4ad03d5c55b4cd52b91ee1 100644 --- a/ets2panda/checker/ets/typeCreation.cpp +++ b/ets2panda/checker/ets/typeCreation.cpp @@ -151,6 +151,62 @@ ETSArrayType *ETSChecker::CreateETSArrayType(Type *elementType, bool isCachePoll return arrayType; } +static Language GetProgramLanguage(parser::Program *program) +{ + Language lang = es2panda::Language(Language::Id::ETS); + switch (program->Extension()) { + case util::gen::extension::Enum::ETS: + lang = es2panda::Language(Language::Id::ETS); + break; + case util::gen::extension::Enum::AS: + lang = es2panda::Language(Language::Id::AS); + break; + case util::gen::extension::Enum::JS: + lang = es2panda::Language(Language::Id::JS); + break; + case util::gen::extension::Enum::TS: + lang = es2panda::Language(Language::Id::TS); + break; + default: + UNREACHABLE(); + } + return lang; +} + +GradualType *ETSChecker::GetGlobalGradualType(Type *baseType) const +{ + auto lang = GetProgramLanguage(Program()); + auto gradualMap = gradualTypes_.find(lang)->second; + auto res = gradualMap.find(baseType); + if (res != gradualMap.end()) { + return res->second; + } + return gradualMap.find(GlobalTypeError())->second; +} + +GradualType *ETSChecker::GetOrCreateGradualType(Type *baseType, bool recursive) +{ + if (!recursive && baseType->IsGradualType()) { + return baseType->AsGradualType(); + } + + auto lang = GetProgramLanguage(Program()); + auto gradualMap = gradualTypes_.find(lang)->second; + + auto res = gradualMap.find(baseType); + if (res != gradualMap.end()) { + return res->second; + } + + auto *gradualType = ProgramAllocator()->New(baseType, lang); + + std::stringstream ss; + gradualType->ToAssemblerTypeWithRank(ss); + + gradualMap.insert({baseType, gradualType}); + return gradualType; +} + Type *ETSChecker::CreateETSUnionType(Span constituentTypes) { if (constituentTypes.empty()) { @@ -261,7 +317,7 @@ SignatureInfo *ETSChecker::CreateSignatureInfo() { return ProgramAllocator()->New(ProgramAllocator()); } - + ETSTypeParameter *ETSChecker::CreateTypeParameter() { return ProgramAllocator()->New(); @@ -307,8 +363,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: { @@ -410,10 +466,10 @@ ETSObjectType *ETSChecker::CreateETSObjectType(ir::AstNode *declNode, ETSObjectF std::make_tuple(declNode, flags, Relation())); } - if (auto [lang, hasDecl] = CheckForDynamicLang(declNode, internalName); lang.IsDynamic()) { - return ProgramAllocator()->New(ProgramAllocator(), std::make_tuple(name, internalName, lang), - std::make_tuple(declNode, flags, Relation()), hasDecl); - } + // if (auto [lang, hasDecl] = CheckForDynamicLang(declNode, internalName); lang.IsDynamic()) { + // return ProgramAllocator()->New(ProgramAllocator(), std::make_tuple(name, internalName, lang), + // std::make_tuple(declNode, flags, Relation()), hasDecl); + // } return ProgramAllocator()->New(ProgramAllocator(), name, internalName, std::make_tuple(declNode, flags, Relation())); diff --git a/ets2panda/checker/ets/unboxingConverter.cpp b/ets2panda/checker/ets/unboxingConverter.cpp index e3b958cf6d07fb6c177e4f1c5d254c80e687d921..2ff7a3c2c2befccd68d80da1cb3e72844ef8e8b3 100644 --- a/ets2panda/checker/ets/unboxingConverter.cpp +++ b/ets2panda/checker/ets/unboxingConverter.cpp @@ -22,7 +22,7 @@ namespace ark::es2panda::checker { checker::Type *UnboxingConverter::Convert(checker::ETSChecker const *checker, ETSObjectType *type) { - switch (type->UnboxableKind()) { + switch (type->GetUnderlyingType()->AsETSObjectType()->UnboxableKind()) { case ETSObjectFlags::BUILTIN_BOOLEAN: return checker->GlobalETSBooleanType(); case ETSObjectFlags::BUILTIN_BYTE: diff --git a/ets2panda/checker/ets/utilityTypeHandlers.cpp b/ets2panda/checker/ets/utilityTypeHandlers.cpp index c77f536455038d1fbfc515fa394857d494d936f1..1a5a6303f1191b98d7ec95c2381f628ad6df61be 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()); } @@ -126,7 +134,7 @@ Type *ETSChecker::CreatePartialType(Type *const typeToBePartial) // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) return CreatePartialTypeClass(typeToBePartial->AsETSObjectType(), - typeToBePartial->Variable()->Declaration()->Node()); + typeToBePartial->AsETSObjectType()->Variable()->Declaration()->Node()); } Type *ETSChecker::CreatePartialTypeParameter(ETSTypeParameter *typeToBePartial) diff --git a/ets2panda/checker/ets/validateHelpers.cpp b/ets2panda/checker/ets/validateHelpers.cpp index f3ad9a385b9c4e0619ab024c454748e9602ecc35..f14319c093e7a9cc31b9c0ae71eefafad3c4ddca 100644 --- a/ets2panda/checker/ets/validateHelpers.cpp +++ b/ets2panda/checker/ets/validateHelpers.cpp @@ -68,7 +68,7 @@ void ETSChecker::ValidateCallExpressionIdentifier(ir::Identifier *const ident, T ident->Variable()->Declaration()->Node()->IsImportNamespaceSpecifier()) { std::ignore = TypeError(ident->Variable(), diagnostic::NAMESPACE_CALL, {ident->ToString()}, ident->Start()); } - if (type->IsETSFunctionType() || type->IsETSDynamicType()) { + if (type->IsETSFunctionType() || type->IsETSAnyType()) { return; } // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) 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 6ee38c66621147d016e917a5dc352869b3df7035..3322cc8ae65989a02cec2f16a46a0af8c6b53f4c 100644 --- a/ets2panda/checker/types/ets/etsFunctionType.cpp +++ b/ets2panda/checker/types/ets/etsFunctionType.cpp @@ -250,14 +250,14 @@ bool ETSFunctionType::AssignmentSource(TypeRelation *relation, Type *target) AssertNoMethodsInFunctionRelation(this, target); // this should be defined by the dynamic type itself - if (target->IsETSDynamicType()) { - ES2PANDA_ASSERT(relation->GetNode() != nullptr); - if (relation->GetNode()->IsArrowFunctionExpression()) { - ES2PANDA_ASSERT(callSignatures_.size() == 1 && ArrowSignature()->HasSignatureFlag(SignatureFlags::CALL)); - return relation->Result(true); - } - return relation->Result(false); - } + // if (target->IsETSDynamicType()) { + // ES2PANDA_ASSERT(relation->GetNode() != nullptr); + // if (relation->GetNode()->IsArrowFunctionExpression()) { + // ES2PANDA_ASSERT(callSignatures_.size() == 1 && ArrowSignature()->HasSignatureFlag(SignatureFlags::CALL)); + // return relation->Result(true); + // } + // return relation->Result(false); + // } return relation->IsSupertypeOf(target, this); } diff --git a/ets2panda/checker/types/ets/etsObjectType.cpp b/ets2panda/checker/types/ets/etsObjectType.cpp index 61a6db0141bf8e1c7eeb777481cebbc09b8bac23..6e3b824e2493e5adcfaa607b5c876ba89db6ed34 100644 --- a/ets2panda/checker/types/ets/etsObjectType.cpp +++ b/ets2panda/checker/types/ets/etsObjectType.cpp @@ -542,9 +542,9 @@ bool ETSObjectType::AssignmentSource(TypeRelation *const relation, [[maybe_unuse bool ETSObjectType::IsBoxedPrimitive() const { - if (this->IsETSDynamicType()) { - return false; - } + // if (this->IsETSDynamicType()) { + // return false; + // } return this->IsETSUnboxableObject(); } diff --git a/ets2panda/checker/types/ets/etsObjectTypeConstants.h b/ets2panda/checker/types/ets/etsObjectTypeConstants.h index 0a51f2f1d6a1393d49d722194d834fdc8992eb7e..d0f52b049c5ae32fc4cc052828b1ba3304534ec6 100644 --- a/ets2panda/checker/types/ets/etsObjectTypeConstants.h +++ b/ets2panda/checker/types/ets/etsObjectTypeConstants.h @@ -60,6 +60,7 @@ enum class ETSObjectFlags : std::uint64_t { EXTENSION_FUNCTION = 1ULL << 34U, FUNCTIONAL_REFERENCE = 1ULL << 35U, + DECL_MODULE = 1ULL << 36U, BUILTIN_NUMERIC = BUILTIN_BYTE | BUILTIN_SHORT | BUILTIN_INT | BUILTIN_LONG | BUILTIN_FLOAT | BUILTIN_DOUBLE, // Complete set includes null|undefined|Object 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/gradualType.cpp b/ets2panda/checker/types/gradualType.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4cad8c227275d0a44d8ded3f58520456c9d86a1f --- /dev/null +++ b/ets2panda/checker/types/gradualType.cpp @@ -0,0 +1,135 @@ +/* + * 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 "gradualType.h" + +#include "checker/ETSchecker.h" +#include "checker/ets/conversion.h" + +namespace ark::es2panda::checker { +void GradualType::Identical(TypeRelation *relation, Type *other) +{ + if (baseType_->IsETSObjectType() && + baseType_->AsETSObjectType()->AssemblerName().Mutf8() == compiler::Signatures::BUILTIN_OBJECT) { + relation->Result(true); + } else { + baseType_->Identical(relation, other); + } +} + +void GradualType::AssignmentTarget(TypeRelation *relation, Type *source) +{ + if (baseType_->IsETSObjectType() && + baseType_->AsETSObjectType()->AssemblerName().Mutf8() == compiler::Signatures::BUILTIN_OBJECT) { + relation->Result(true); + } else { + baseType_->AssignmentTarget(relation, source); + } +} + +bool GradualType::AssignmentSource(TypeRelation *relation, Type *target) +{ + if (baseType_->IsETSObjectType() && + baseType_->AsETSObjectType()->AssemblerName().Mutf8() == compiler::Signatures::BUILTIN_OBJECT) { + relation->Result(true); + return false; + } else { + return baseType_->AssignmentSource(relation, target); + } +} + +void GradualType::Compare(TypeRelation *relation, Type *other) +{ + if (baseType_->IsETSObjectType() && + baseType_->AsETSObjectType()->AssemblerName().Mutf8() == compiler::Signatures::BUILTIN_OBJECT) { + relation->Result(true); + } else { + return baseType_->Compare(relation, other); + } +} + +void GradualType::Cast(TypeRelation *relation, Type *target) +{ + if (baseType_->IsETSObjectType() && + baseType_->AsETSObjectType()->AssemblerName().Mutf8() == compiler::Signatures::BUILTIN_OBJECT) { + relation->Result(true); + } else { + return baseType_->Cast(relation, target); + } +} + +void GradualType::CastTarget(TypeRelation *relation, Type *source) +{ + if (baseType_->IsETSObjectType() && + baseType_->AsETSObjectType()->AssemblerName().Mutf8() == compiler::Signatures::BUILTIN_OBJECT) { + relation->Result(true); + } else { + return baseType_->CastTarget(relation, source); + } +} + +void GradualType::IsSubtypeOf(TypeRelation *relation, Type *target) +{ + if (baseType_->IsETSObjectType() && + baseType_->AsETSObjectType()->AssemblerName().Mutf8() == compiler::Signatures::BUILTIN_OBJECT) { + relation->Result(true); + } else { + return baseType_->IsSubtypeOf(relation, target); + } +} + +void GradualType::IsSupertypeOf(TypeRelation *relation, Type *source) +{ + if (baseType_->IsETSObjectType() && + baseType_->AsETSObjectType()->AssemblerName().Mutf8() == compiler::Signatures::BUILTIN_OBJECT) { + relation->Result(true); + } else { + return baseType_->IsSupertypeOf(relation, source); + } +} + +void GradualType::ToString(std::stringstream &ss, [[maybe_unused]] bool precise) const +{ + ss << "gradual"; + ss << "<"; + baseType_->ToString(ss); + ss << ">"; +} + +Type *GradualType::Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) +{ + return baseType_->Instantiate(allocator, relation, globalTypes); +} + +Type *GradualType::Substitute(TypeRelation *relation, const Substitution *substitution) +{ + return baseType_->Substitute(relation, substitution); +} + +void GradualType::ToAssemblerType(std::stringstream &ss) const +{ + baseType_->ToAssemblerType(ss); +} + +void GradualType::ToDebugInfoType(std::stringstream &ss) const +{ + baseType_->ToDebugInfoType(ss); +} + +void GradualType::ToAssemblerTypeWithRank(std::stringstream &ss) const +{ + baseType_->ToAssemblerTypeWithRank(ss); +} +} // namespace ark::es2panda::checker \ No newline at end of file diff --git a/ets2panda/checker/types/gradualType.h b/ets2panda/checker/types/gradualType.h new file mode 100644 index 0000000000000000000000000000000000000000..47ad7c1c573db32e668cb4e97ed39185ac5c836f --- /dev/null +++ b/ets2panda/checker/types/gradualType.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2024 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_GRADUAL_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_GRADUAL_TYPE_H + +#include "checker/types/type.h" +#include "ir/astNode.h" + +namespace ark::es2panda::checker { +class GradualType : public Type { +public: + GradualType(checker::Type *baseType) + : Type(TypeFlag::GRADUAL_TYPE), baseType_(baseType), lang_(es2panda::Language(Language::Id::ETS)) + { + } + + GradualType(checker::Type *baseType, Language lang) : Type(TypeFlag::GRADUAL_TYPE), baseType_(baseType), lang_(lang) + { + } + + 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(std::stringstream &ss) const override; + void ToAssemblerTypeWithRank(std::stringstream &ss) const override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + Type *Substitute(TypeRelation *relation, const Substitution *substitution) override; + + Type *BaseType() + { + return baseType_; + } + + Type *BaseType() const + { + return baseType_; + } + + Type *GetUnderlyingType() override + { + return baseType_->GetUnderlyingType(); + } + + const Type *GetUnderlyingType() const override + { + return baseType_->GetUnderlyingType(); + } + + es2panda::Language Language() const + { + return lang_; + } + +private: + Type *baseType_; + es2panda::Language lang_; +}; +} // namespace ark::es2panda::checker + +#endif diff --git a/ets2panda/checker/types/type.h b/ets2panda/checker/types/type.h index 1104cada5f540782858ce5ef1b0b7de8f17639d6..fb1786e2f6c21a575457bec11ae51b792b0be40c 100644 --- a/ets2panda/checker/types/type.h +++ b/ets2panda/checker/types/type.h @@ -35,6 +35,7 @@ class ETSChecker; class ETSDynamicFunctionType; class ETSTypeParameter; class ETSEnumType; +class GradualType; // CC-OFFNXT(G.PRE.02) name part // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) @@ -62,31 +63,58 @@ public: virtual ~Type() = default; static std::mutex idLock_; + virtual const Type *GetUnderlyingType() const + { + return const_cast(this); + } + + virtual Type *GetUnderlyingType() + { + return this; + } + + bool IsGradualType() const noexcept + { + return (typeFlags_ & TypeFlag::GRADUAL_TYPE) != 0; + } + + GradualType *AsGradualType() + { + ES2PANDA_ASSERT(IsGradualType()); + return reinterpret_cast(this); + } + + const GradualType *AsGradualType() const + { + ES2PANDA_ASSERT(IsGradualType()); + return reinterpret_cast(this); + } + // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define TYPE_IS_CHECKS(typeFlag, typeName) \ bool Is##typeName() const noexcept \ { \ /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed*/ \ - return HasTypeFlag(typeFlag); \ + return GetUnderlyingType()->HasTypeFlag(typeFlag); \ } TYPE_MAPPING(TYPE_IS_CHECKS) #undef DECLARE_IS_CHECKS /* CC-OFFNXT(G.PRE.06,G.PRE.02) solid logic, name part */ // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define TYPE_AS_CASTS(typeFlag, typeName) \ - /* CC-OFFNXT(G.PRE.02) name part*/ \ - typeName *As##typeName() \ - { \ - ES2PANDA_ASSERT(Is##typeName()); \ - /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed*/ \ - return reinterpret_cast(this); /* CC-OFF(G.PRE.02) name part*/ \ - } \ - const typeName *As##typeName() const \ - { \ - ES2PANDA_ASSERT(Is##typeName()); \ - /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed*/ \ - return reinterpret_cast(this); \ +#define TYPE_AS_CASTS(typeFlag, typeName) \ + /* CC-OFFNXT(G.PRE.02) name part*/ \ + typeName *As##typeName() \ + { \ + ES2PANDA_ASSERT(Is##typeName()); \ + /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed*/ \ + return reinterpret_cast(GetUnderlyingType()); /* CC-OFF(G.PRE.02) name part*/ \ + } \ + const typeName *As##typeName() const \ + { \ + ES2PANDA_ASSERT(Is##typeName()); \ + /* CC-OFFNXT(G.PRE.05) The macro is used to generate a function. Return is needed*/ \ + return reinterpret_cast(GetUnderlyingType()); \ } TYPE_MAPPING(TYPE_AS_CASTS) #undef TYPE_AS_CASTS @@ -189,11 +217,6 @@ public: return reinterpret_cast(this); } - bool IsConditionalExprType() const - { - return HasTypeFlag(TypeFlag::CONDITION_EXPRESSION_TYPE); - } - bool IsConstantType() const { return HasTypeFlag(checker::TypeFlag::CONSTANT); @@ -201,22 +224,22 @@ public: TypeFlag TypeFlags() const { - return typeFlags_; + return GetUnderlyingType()->typeFlags_; } bool HasTypeFlag(TypeFlag typeFlag) const { - return (typeFlags_ & typeFlag) != 0; + return (GetUnderlyingType()->typeFlags_ & typeFlag) != 0; } void AddTypeFlag(TypeFlag typeFlag) { - typeFlags_ |= typeFlag; + GetUnderlyingType()->typeFlags_ |= typeFlag; } void RemoveTypeFlag(TypeFlag typeFlag) { - typeFlags_ &= ~typeFlag; + GetUnderlyingType()->typeFlags_ &= ~typeFlag; } uint64_t Id() const @@ -226,16 +249,25 @@ public: void SetVariable(varbinder::Variable *variable) { + if (IsGradualType()) { + GetUnderlyingType()->SetVariable(variable); + } variable_ = variable; } varbinder::Variable *Variable() { + if (IsGradualType()) { + GetUnderlyingType()->Variable(); + } return variable_; } const varbinder::Variable *Variable() const { + if (IsGradualType()) { + GetUnderlyingType()->Variable(); + } return variable_; } diff --git a/ets2panda/checker/types/typeFlag.h b/ets2panda/checker/types/typeFlag.h index 86e149f3a3d2ce2c4816b00280f55012f2b91548..aa021603dcf4f6e686f7ef7186f4edf9cb3a499c 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[] @@ -70,7 +69,7 @@ enum class TypeFlag : uint64_t { ETS_ARRAY = 1ULL << 41ULL, // ETS array type WILDCARD = 1ULL << 42ULL, // new A() ETS_TYPE_PARAMETER = 1ULL << 43ULL, // ETS type parameter - ETS_TYPE_REFERENCE = 1ULL << 44ULL, // ETS type reference + GRADUAL_TYPE = 1ULL << 44ULL, // gradual Type GENERIC = 1ULL << 45ULL, // ETS Generic ETS_INT_ENUM = 1ULL << 46ULL, // ETS Enum ETS_STRING_ENUM = 1ULL << 47ULL, // ETS string-type Enumeration @@ -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_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/checker/types/typeRelation.cpp b/ets2panda/checker/types/typeRelation.cpp index 965d2172bb0dc4ed33260bd727d8d2f127523260..9a82abc1fe528bc385895ad50def67f1a9a64a44 100644 --- a/ets2panda/checker/types/typeRelation.cpp +++ b/ets2panda/checker/types/typeRelation.cpp @@ -59,7 +59,7 @@ bool TypeRelation::IsIdenticalTo(Type *source, Type *target) return Result(false); } - if (source == target) { + if (source->GetUnderlyingType() == target->GetUnderlyingType()) { return Result(true); } @@ -117,7 +117,7 @@ bool TypeRelation::IsIdenticalTo(IndexInfo *source, IndexInfo *target) // NOTE: applyNarrowing -> flag bool TypeRelation::IsAssignableTo(Type *source, Type *target) { - if (source == target) { + if (source->GetUnderlyingType() == target->GetUnderlyingType()) { return Result(true); } @@ -157,11 +157,11 @@ bool TypeRelation::IsComparableTo(Type *source, Type *target) result_ = CacheLookup(source, target, checker_->ComparableResults(), RelationType::COMPARABLE); // NOTE: vpukhov. reimplement dynamic comparison and remove this check - if (source->IsETSDynamicType() || target->IsETSDynamicType()) { - if (!(source->IsETSDynamicType() && target->IsETSDynamicType())) { - return false; - } - } + // if (source->IsETSDynamicType() || target->IsETSDynamicType()) { + // if (!(source->IsETSDynamicType() && target->IsETSDynamicType())) { + // return false; + // } + // } if (result_ == RelationResult::CACHE_MISS) { if (IsAssignableTo(source, target)) { @@ -236,7 +236,7 @@ bool TypeRelation::IsLegalBoxedPrimitiveConversion(Type *target, Type *source) bool TypeRelation::IsSupertypeOf(Type *super, Type *sub) { - if (super == sub) { + if (super->GetUnderlyingType() == sub->GetUnderlyingType()) { return Result(true); } 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/base/lreference.cpp b/ets2panda/compiler/base/lreference.cpp index 240aa09bd3fbad7c3e11dc67fa5826635b15e745..b2d1e8725fe70e25c22834f4fd4d9584192a4751 100644 --- a/ets2panda/compiler/base/lreference.cpp +++ b/ets2panda/compiler/base/lreference.cpp @@ -183,8 +183,8 @@ ETSLReference::ETSLReference(CodeGen *cg, const ir::AstNode *node, ReferenceKind const auto *memberExpr = Node()->AsMemberExpression(); staticObjRef_ = memberExpr->Object()->TsType(); - if (!memberExpr->IsComputed() && etsg_->Checker()->IsVariableStatic(memberExpr->PropVar()) && - !staticObjRef_->IsETSDynamicType()) { + if (!memberExpr->IsComputed() && memberExpr->PropVar() != nullptr && + etsg_->Checker()->IsVariableStatic(memberExpr->PropVar())) { return; } @@ -197,7 +197,8 @@ ETSLReference::ETSLReference(CodeGen *cg, const ir::AstNode *node, ReferenceKind TargetTypeContext pttctx(etsg_, memberExpr->Property()->TsType()); memberExpr->Property()->Compile(etsg_); etsg_->ApplyConversion(memberExpr->Property()); - ES2PANDA_ASSERT(etsg_->GetAccumulatorType()->HasTypeFlag(checker::TypeFlag::ETS_INTEGRAL)); + ES2PANDA_ASSERT(memberExpr->Object()->TsType()->IsETSAnyType() || + etsg_->GetAccumulatorType()->HasTypeFlag(checker::TypeFlag::ETS_INTEGRAL)); propReg_ = etsg_->AllocReg(); etsg_->StoreAccumulator(node, propReg_); } @@ -281,8 +282,17 @@ void ETSLReference::SetValueComputed(const ir::MemberExpression *memberExpr) con { const auto *const objectType = memberExpr->Object()->TsType(); - if (objectType->IsETSDynamicType()) { - etsg_->StoreElementDynamic(Node(), baseReg_, propReg_); + // if (objectType->IsETSDynamicType()) { + // etsg_->StoreElementDynamic(Node(), baseReg_, propReg_); + // return; + // } + + if (objectType->IsETSAnyType()) { + if (memberExpr->Property()->TsType()->HasTypeFlag(checker::TypeFlag::ETS_NUMERIC)) { + etsg_->StoreByIndexAny(memberExpr, baseReg_, propReg_); + } else { + etsg_->StoreByValueAny(memberExpr, baseReg_, propReg_); + } return; } @@ -327,6 +337,7 @@ void ETSLReference::SetValue() const const auto *const memberExpr = Node()->AsMemberExpression(); const auto *const memberExprTsType = memberExpr->TsType(); + auto const *objectType = memberExpr->Object()->TsType(); if (!memberExpr->IsIgnoreBox()) { etsg_->ApplyConversion(Node(), memberExprTsType); @@ -337,6 +348,11 @@ void ETSLReference::SetValue() const return; } + if (objectType->IsETSAnyType()) { + etsg_->StorePropertyByNameAny(memberExpr, baseReg_, memberExpr->Property()->AsIdentifier()->Name()); + return; + } + if (memberExpr->PropVar()->TsType()->HasTypeFlag(checker::TypeFlag::GETTER_SETTER)) { SetValueGetterSetter(memberExpr); return; @@ -346,21 +362,19 @@ void ETSLReference::SetValue() const if (memberExpr->PropVar()->HasFlag(varbinder::VariableFlags::STATIC)) { const util::StringView fullName = etsg_->FormClassPropReference(staticObjRef_->AsETSObjectType(), propName); - if (staticObjRef_->IsETSDynamicType()) { - etsg_->StorePropertyDynamic(Node(), memberExprTsType, baseReg_, propName); - } else { - etsg_->StoreStaticProperty(Node(), memberExprTsType, fullName); - } + // if (staticObjRef_->IsETSDynamicType()) { + // etsg_->StorePropertyDynamic(Node(), memberExprTsType, baseReg_, propName); + // } else { + etsg_->StoreStaticProperty(Node(), memberExprTsType, fullName); + // } return; } - auto const *objectType = memberExpr->Object()->TsType(); - - if (objectType->IsETSDynamicType()) { - etsg_->StorePropertyDynamic(Node(), memberExprTsType, baseReg_, propName); - return; - } + // if (objectType->IsETSDynamicType()) { + // etsg_->StorePropertyDynamic(Node(), memberExprTsType, baseReg_, propName); + // return; + // } if (objectType->IsETSUnionType()) { etsg_->StorePropertyByName(Node(), baseReg_, diff --git a/ets2panda/compiler/core/ETSCompiler.cpp b/ets2panda/compiler/core/ETSCompiler.cpp index 86ee12f811a1febfbb0dbf9396155fea1018198d..35f67e51b9f066cc1ec0f1ac3932d7611eb54eb7 100644 --- a/ets2panda/compiler/core/ETSCompiler.cpp +++ b/ets2panda/compiler/core/ETSCompiler.cpp @@ -21,6 +21,7 @@ #include "compiler/core/ETSGen-inl.h" #include "compiler/base/lreference.h" #include "compiler/core/switchBuilder.h" +#include "compiler/core/targetTypeContext.h" #include "compiler/function/functionBuilder.h" #include "checker/ETSchecker.h" #include "checker/types/ets/etsDynamicFunctionType.h" @@ -173,8 +174,16 @@ static std::pair LoadDynamicName(compiler::ETSGen *etsg, const ir::A return {qnameStart, qnameLen}; } -static void CreateDynamicObject(const ir::AstNode *node, compiler::ETSGen *etsg, const ir::Expression *typeRef, - checker::Signature *signature, const ArenaVector &arguments) +// [[maybe_unused]] static void CreateAnyObject(const ir::AstNode *node, compiler::ETSGen *etsg, +// const ir::Expression *typeRef, checker::Signature *signature, +// const ArenaVector &arguments) +// { + +// } + +[[maybe_unused]] static void CreateDynamicObject(const ir::AstNode *node, compiler::ETSGen *etsg, + const ir::Expression *typeRef, checker::Signature *signature, + const ArenaVector &arguments) { auto objReg = etsg->AllocReg(); @@ -288,14 +297,18 @@ static void GetSizeInForOf(compiler::ETSGen *etsg, checker::Type const *const ex void ETSCompiler::Compile(const ir::ETSNewClassInstanceExpression *expr) const { ETSGen *etsg = GetETSGen(); - if (expr->TsType()->IsETSDynamicType()) { - compiler::RegScope rs(etsg); - auto *name = expr->GetTypeRef(); - CreateDynamicObject(expr, etsg, name, expr->signature_, expr->GetArguments()); - } else { - ConvertRestArguments(const_cast(etsg->Checker()->AsETSChecker()), expr); - etsg->InitObject(expr, expr->signature_, expr->GetArguments()); - } + // if (expr->TsType()->IsETSDynamicType()) { + // compiler::RegScope rs(etsg); + // auto *name = expr->GetTypeRef(); + // CreateDynamicObject(expr, etsg, name, expr->signature_, expr->GetArguments()); + // } else { + // if (expr->TsType()->IsETSAnyType()) { + // compiler::RegScope rs(etsg); + // auto *name = expr->GetTypeRef(); + // } else { + ConvertRestArguments(const_cast(etsg->Checker()->AsETSChecker()), expr); + etsg->InitObject(expr, expr->signature_, expr->GetArguments()); + // } etsg->SetAccumulatorType(expr->TsType()); } @@ -533,15 +546,15 @@ static void CompileInstanceof(compiler::ETSGen *etsg, const ir::BinaryExpression expr->Left()->Compile(etsg); etsg->ApplyConversionAndStoreAccumulator(expr->Left(), lhs, expr->OperationType()); - if (expr->Left()->TsType()->IsETSDynamicType() || expr->Right()->TsType()->IsETSDynamicType()) { - auto rhs = etsg->AllocReg(); - expr->Right()->Compile(etsg); - etsg->StoreAccumulator(expr, rhs); - etsg->IsInstanceDynamic(expr, lhs, rhs); - } else { - auto target = expr->Right()->TsType(); - etsg->IsInstance(expr, lhs, target); - } + // if (expr->Left()->TsType()->IsETSDynamicType() || expr->Right()->TsType()->IsETSDynamicType()) { + // auto rhs = etsg->AllocReg(); + // expr->Right()->Compile(etsg); + // etsg->StoreAccumulator(expr, rhs); + // etsg->IsInstanceDynamic(expr, lhs, rhs); + // } else { + auto target = expr->Right()->TsType(); + etsg->IsInstance(expr, lhs, target); + // } ES2PANDA_ASSERT(etsg->Checker()->Relation()->IsIdenticalTo(etsg->GetAccumulatorType(), expr->TsType())); } @@ -732,6 +745,25 @@ void ETSCompiler::CompileDynamic(const ir::CallExpression *expr, compiler::VReg } } +void ETSCompiler::CompileAny([[maybe_unused]]const ir::CallExpression *expr, const ir::Expression *callee, [[maybe_unused]]compiler::VReg &calleeReg) const +{ + ETSGen *etsg = GetETSGen(); + checker::Signature *const signature = expr->Signature(); + if (callee->IsMemberExpression()) { + // Emit any.callthis + callee->AsMemberExpression()->Object()->Compile(etsg); + etsg->CallAnyThis(expr, signature, expr->Arguments()); + } else if (callee->IsIdentifier()) { + // Emit any.call + etsg->CallAny(expr, signature, expr->Arguments()); + } else { + ES2PANDA_UNREACHABLE(); + } + + // TODO (daizihan) Emit any.callnew + // TODO (daizihan) Emit any.callsuper +} + void ETSCompiler::EmitCall(const ir::CallExpression *expr, compiler::VReg &calleeReg, checker::Signature *signature) const { @@ -778,6 +810,8 @@ void ETSCompiler::Compile(const ir::CallExpression *expr) const if (callee->TsType()->HasTypeFlag(checker::TypeFlag::ETS_DYNAMIC_FLAG)) { CompileDynamic(expr, calleeReg); + } else if (callee->TsType()->IsETSAnyType()) { + CompileAny(expr, callee, calleeReg); } else if (callee->IsIdentifier()) { if (!isStatic) { etsg->LoadThis(expr); @@ -854,8 +888,8 @@ void ETSCompiler::Compile(const ir::Identifier *expr) const etsg->SetAccumulatorType(smartType); } -static void LoadETSDynamicTypeFromMemberExpr(compiler::ETSGen *etsg, const ir::MemberExpression *expr, - compiler::VReg objReg) +[[maybe_unused]] static void LoadETSDynamicTypeFromMemberExpr(compiler::ETSGen *etsg, const ir::MemberExpression *expr, + compiler::VReg objReg) { if (etsg->Checker()->AsETSChecker()->Relation()->IsSupertypeOf(etsg->Checker()->GlobalBuiltinETSStringType(), expr->Property()->TsType())) { @@ -865,6 +899,16 @@ static void LoadETSDynamicTypeFromMemberExpr(compiler::ETSGen *etsg, const ir::M } } +static void LoadETSAnyTypeFromMemberExpr(compiler::ETSGen *etsg, const ir::MemberExpression *expr, + compiler::VReg objReg) +{ + if (expr->Property()->TsType()->HasTypeFlag(checker::TypeFlag::ETS_NUMERIC)) { + etsg->LoadByIndexAny(expr, objReg); + } else { + etsg->LoadByValueAny(expr, objReg); + } +} + bool ETSCompiler::CompileComputed(compiler::ETSGen *etsg, const ir::MemberExpression *expr) { if (!expr->IsComputed()) { @@ -890,8 +934,8 @@ bool ETSCompiler::CompileComputed(compiler::ETSGen *etsg, const ir::MemberExpres auto indexValue = *expr->GetTupleIndexValue(); auto *tupleElementType = objectType->AsETSTupleType()->GetTypeAtIndex(indexValue); etsg->LoadTupleElement(expr, objReg, tupleElementType, indexValue); - } else if (objectType->IsETSDynamicType()) { - LoadETSDynamicTypeFromMemberExpr(etsg, expr, objReg); + } else if (objectType->IsETSAnyType()) { + LoadETSAnyTypeFromMemberExpr(etsg, expr, objReg); } else { ES2PANDA_ASSERT(objectType->IsETSArrayType()); etsg->LoadArrayElement(expr, objReg); @@ -904,6 +948,23 @@ bool ETSCompiler::CompileComputed(compiler::ETSGen *etsg, const ir::MemberExpres return true; } +bool ETSCompiler::CompileAny(compiler::ETSGen *etsg, const ir::MemberExpression *expr) const +{ + if (!expr->Object()->TsType()->IsETSAnyType()) { + return false; + } + auto ottctx = compiler::TargetTypeContext(etsg, expr->Object()->TsType()); + etsg->CompileAndCheck(expr->Object()); + + compiler::VReg objReg = etsg->AllocReg(); + etsg->StoreAccumulator(expr, objReg); + + auto ttctx = compiler::TargetTypeContext(etsg, expr->TsType()); + etsg->LoadPropertyByNameAny(expr, objReg, expr->Property()->AsIdentifier()->Name()); + + return true; +} + void ETSCompiler::Compile(const ir::MemberExpression *expr) const { ETSGen *etsg = GetETSGen(); @@ -914,6 +975,10 @@ void ETSCompiler::Compile(const ir::MemberExpression *expr) const return; } + if (CompileAny(etsg, expr)) { + return; + } + if (HandleArrayTypeLengthProperty(expr, etsg)) { return; } @@ -941,8 +1006,8 @@ void ETSCompiler::Compile(const ir::MemberExpression *expr) const } else { etsg->CallVirtual(expr, variableType->AsETSFunctionType()->FindGetter(), objReg); } - } else if (objectType->IsETSDynamicType()) { - etsg->LoadPropertyDynamic(expr, expr->TsType(), objReg, propName); + // } else if (objectType->IsETSDynamicType()) { + // etsg->LoadPropertyDynamic(expr, expr->TsType(), objReg, propName); } else if (objectType->IsETSUnionType()) { etsg->LoadPropertyByName(expr, objReg, checker::ETSChecker::FormNamedAccessMetadata(expr->PropVar())); } else { @@ -1004,7 +1069,7 @@ void ETSCompiler::Compile(const ir::ObjectExpression *expr) const compiler::VReg objReg = etsg->AllocReg(); // NOTE: object expressions of dynamic type are not handled in objectLiteralLowering phase - ES2PANDA_ASSERT(expr->TsType()->IsETSDynamicType()); + // ES2PANDA_ASSERT(expr->TsType()->IsETSDynamicType()); auto *signatureInfo = etsg->Allocator()->New(etsg->Allocator()); auto *createObjSig = etsg->Allocator()->New(signatureInfo, nullptr, nullptr); @@ -1033,11 +1098,11 @@ void ETSCompiler::Compile(const ir::ObjectExpression *expr) const value->Compile(etsg); etsg->ApplyConversion(value, key->TsType()); - if (expr->TsType()->IsETSDynamicType()) { - etsg->StorePropertyDynamic(expr, value->TsType(), objReg, pname); - } else { - etsg->StoreProperty(expr, key->TsType(), objReg, pname); - } + // if (expr->TsType()->IsETSDynamicType()) { + // etsg->StorePropertyDynamic(expr, value->TsType(), objReg, pname); + // } else { + etsg->StoreProperty(expr, key->TsType(), objReg, pname); + // } } etsg->LoadAccumulator(expr, objReg); @@ -1664,6 +1729,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/ETSCompiler.h b/ets2panda/compiler/core/ETSCompiler.h index 94cd1e8f35b8cdbe204d965a029984772d864185..8f3d6e111e84fbdd7da0bc02f0cf5d6463ff20fe 100644 --- a/ets2panda/compiler/core/ETSCompiler.h +++ b/ets2panda/compiler/core/ETSCompiler.h @@ -35,6 +35,7 @@ public: private: void GetDynamicNameParts(const ir::CallExpression *expr, ArenaVector &parts) const; + void CompileAny(const ir::CallExpression *expr, const ir::Expression *callee, compiler::VReg &calleeReg) const; void CompileDynamic(const ir::CallExpression *expr, compiler::VReg &calleeReg) const; void CompileCastUnboxable(const ir::TSAsExpression *expr) const; void CompileCastPrimitives(const ir::TSAsExpression *expr) const; @@ -46,6 +47,7 @@ private: void CompileTupleCreation(const ir::ArrayExpression *tupleInitializer) const; static bool CompileComputed(compiler::ETSGen *etsg, const ir::MemberExpression *expr); + bool CompileAny(compiler::ETSGen *etsg, const ir::MemberExpression *expr) const; ETSGen *GetETSGen() const; }; diff --git a/ets2panda/compiler/core/ETSGen.cpp b/ets2panda/compiler/core/ETSGen.cpp index 004427936cbf08ea19c6b7e32214e490ddf3bf18..406f6209c3a1a2c8f5b75025af3d0a3b677f15fd 100644 --- a/ets2panda/compiler/core/ETSGen.cpp +++ b/ets2panda/compiler/core/ETSGen.cpp @@ -16,6 +16,7 @@ #include "ETSGen.h" #include "ETSGen-inl.h" +#include "generated/isa.h" #include "generated/signatures.h" #include "ir/base/scriptFunction.h" #include "ir/base/classDefinition.h" @@ -291,15 +292,15 @@ void ETSGen::LoadDynamicNamespaceVariable(const ir::AstNode *node, varbinder::Va void ETSGen::LoadVar(const ir::Identifier *node, varbinder::Variable const *const var) { - if (VarBinder()->IsDynamicModuleVariable(var)) { - LoadDynamicModuleVariable(node, var); - return; - } - - if (VarBinder()->IsDynamicNamespaceVariable(var)) { - LoadDynamicNamespaceVariable(node, var); - return; - } + // if (VarBinder()->IsDynamicModuleVariable(var)) { + // LoadDynamicModuleVariable(node, var); + // return; + // } + // + // if (VarBinder()->IsDynamicNamespaceVariable(var)) { + // LoadDynamicNamespaceVariable(node, var); + // return; + // } auto *local = var->AsLocalVariable(); @@ -419,6 +420,20 @@ void ETSGen::StoreProperty(const ir::AstNode *const node, const checker::Type *p } } +void ETSGen::StorePropertyByNameAny(const ir::AstNode *const node, const VReg objReg, const util::StringView &fullName) +{ + ES2PANDA_ASSERT(node->IsMemberExpression() && node->AsMemberExpression()->Object()->TsType()->IsETSAnyType()); + Ra().Emit(node, objReg, fullName); + SetAccumulatorType(node->AsMemberExpression()->TsType()); +} + +void ETSGen::LoadPropertyByNameAny(const ir::AstNode *const node, const VReg objReg, const util::StringView &fullName) +{ + ES2PANDA_ASSERT(node->IsMemberExpression() && node->AsMemberExpression()->Object()->TsType()->IsETSAnyType()); + Ra().Emit(node, objReg, fullName); + SetAccumulatorType(node->AsMemberExpression()->TsType()); +} + void ETSGen::LoadProperty(const ir::AstNode *const node, const checker::Type *propType, const VReg objReg, const util::StringView &fullName) { @@ -605,6 +620,48 @@ void ETSGen::LoadElementDynamic(const ir::AstNode *node, VReg objectReg) SetAccumulatorType(Checker()->GlobalBuiltinDynamicType(lang)); } +void ETSGen::StoreByIndexAny(const ir::MemberExpression *node, VReg objectReg, VReg index) +{ + RegScope rs(this); + + // Store property by index + Ra().Emit(node, objectReg, index); + SetAccumulatorType(Checker()->GlobalVoidType()); +} + +void ETSGen::LoadByIndexAny(const ir::MemberExpression *node, VReg objectReg) +{ + RegScope rs(this); + + VReg indexReg = AllocReg(); + StoreAccumulator(node, indexReg); + + // Get property by index + Ra().Emit(node, objectReg); + SetAccumulatorType(node->TsType()); +} + +void ETSGen::StoreByValueAny(const ir::MemberExpression *node, VReg objectReg, VReg value) +{ + RegScope rs(this); + + // Store property by value + Ra().Emit(node, objectReg, value); + SetAccumulatorType(Checker()->GlobalVoidType()); +} + +void ETSGen::LoadByValueAny(const ir::MemberExpression *node, VReg objectReg) +{ + RegScope rs(this); + + VReg valueReg = AllocReg(); + StoreAccumulator(node, valueReg); + + // Get property by value + Ra().Emit(node, objectReg, valueReg); + SetAccumulatorType(node->TsType()); +} + void ETSGen::CallRangeFillUndefined(const ir::AstNode *const node, checker::Signature *const signature, const VReg thisReg) { @@ -692,18 +749,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 +786,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 +843,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 +855,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 +903,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 +930,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 +942,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 +996,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 +1018,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 +1779,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 +1794,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 +1839,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 +2175,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 +2351,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 +2728,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..3e4ff4243d6597325e14b933cee88330df02c6f6 100644 --- a/ets2panda/compiler/core/ETSGen.h +++ b/ets2panda/compiler/core/ETSGen.h @@ -16,6 +16,7 @@ #ifndef ES2PANDA_COMPILER_CORE_ETSGEN_H #define ES2PANDA_COMPILER_CORE_ETSGEN_H +#include "generated/isa.h" #include "ir/astNode.h" #include "compiler/core/codeGen.h" #include "compiler/core/ETSfunction.h" @@ -77,6 +78,15 @@ public: void StoreElementDynamic(const ir::AstNode *node, VReg objectReg, VReg index); void LoadElementDynamic(const ir::AstNode *node, VReg objectReg); + void StoreByIndexAny(const ir::MemberExpression *node, VReg objectReg, VReg index); + void LoadByIndexAny(const ir::MemberExpression *node, VReg objectReg); + + void StoreByValueAny(const ir::MemberExpression *node, VReg objectReg, VReg value); + void LoadByValueAny(const ir::MemberExpression *node, VReg objectReg); + + void StorePropertyByNameAny(const ir::AstNode *const node, const VReg objReg, const util::StringView &fullName); + void LoadPropertyByNameAny(const ir::AstNode *const node, const VReg objReg, const util::StringView &fullName); + void StorePropertyByName(const ir::AstNode *node, VReg objReg, checker::ETSChecker::NamedAccessMeta const &fieldMeta); void LoadPropertyByName(const ir::AstNode *node, VReg objReg, @@ -424,6 +434,18 @@ public: CallDynamicImpl(data, param3, signature, arguments); } + void CallAnyThis(const ir::AstNode *const node, const checker::Signature *signature, + const ArenaVector &arguments) + { + CallAnyImpl(node, signature, arguments); + } + + void CallAny(const ir::AstNode *const node, const checker::Signature *signature, + const ArenaVector &arguments) + { + CallAnyImpl(node, signature, arguments); + } + // until a lowering for implicit super is available void CallRangeFillUndefined(const ir::AstNode *const node, checker::Signature *const signature, const VReg thisReg); @@ -477,6 +499,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) @@ -733,6 +771,50 @@ private: } #undef COMPILE_ARG + +// NOLINTBEGIN(cppcoreguidelines-macro-usage, readability-container-size-empty) +#define COMPILE_ANY_ARG(idx) \ + ES2PANDA_ASSERT((idx) < arguments.size()); \ + auto *param##idx = arguments[idx]; \ + auto *paramType##idx = param##idx->TsType(); \ + auto ttctx##idx = TargetTypeContext(this, paramType##idx); \ + arguments[idx]->Compile(this); \ + VReg arg##idx = AllocReg(); \ + ApplyConversion(arguments[idx], nullptr); \ + ApplyConversionAndStoreAccumulator(arguments[idx], arg##idx, paramType##idx) + + template + void CallAnyImpl(const ir::AstNode *node, checker::Signature const *signature, + const ArenaVector &arguments) + { + ES2PANDA_ASSERT(signature != nullptr); + RegScope rs(this); + + switch (arguments.size()) { + case 0U: { + Ra().Emit(node, signature->InternalName(), dummyReg_, 0); + break; + } + case 1U: { + COMPILE_ANY_ARG(0); + Ra().Emit(node, signature->InternalName(), arg0, 1); + break; + } + default: { + VReg argStart = NextReg(); + + for (size_t idx = 0; idx < arguments.size(); idx++) { + COMPILE_ANY_ARG(idx); + } + + Rra().Emit(node, argStart, arguments.size(), signature->InternalName(), argStart, dummyReg_, + arguments.size()); + break; + } + } + } +#undef COMPILE_ARG + // NOLINTEND(cppcoreguidelines-macro-usage, readability-container-size-empty) void ToBinaryResult(const ir::AstNode *node, Label *ifFalse); diff --git a/ets2panda/compiler/lowering/ets/arrayLiteralLowering.cpp b/ets2panda/compiler/lowering/ets/arrayLiteralLowering.cpp index bf9fea2cc5a6552378dff92248dfff73ac4d9e89..f9dd8d0d64e0e961aa670a9a2c519c0112fb273d 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 c1e53dd59ba2aab22e37dca6f3ef6f470a149af0..4033c033f31f838d865d385b9ebdd4f503e404f9 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 a46a63ea5e6e0036ee0a6a7b29b8da687be252f0..1eb861ff8ab9fbbca68aed96aa7812c605c23139 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/gradualTypeNarrowing.cpp b/ets2panda/compiler/lowering/ets/gradualTypeNarrowing.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e6c3fc1f03604f75b769551acd9ebaa49a8837ae --- /dev/null +++ b/ets2panda/compiler/lowering/ets/gradualTypeNarrowing.cpp @@ -0,0 +1,98 @@ +/* + * 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 "gradualTypeNarrowing.h" + +#include "checker/ETSchecker.h" +#include "es2panda.h" +#include "ir/astNode.h" +#include "ir/opaqueTypeNode.h" +#include "ir/typed.h" +#include "util/language.h" + +namespace ark::es2panda::compiler { + +bool GradualTypeNarrowing::IsETSCommonType(checker::Type *type) +{ + if (!type->IsETSObjectType()) { + return true; + } + auto declNode = type->AsETSObjectType()->GetDeclNode(); + return declNode->IsClassDefinition() && declNode->AsClassDefinition()->Language() == Language::Id::ETS; +} + +void GradualTypeNarrowing::NarrowGradualType(ir::AstNode *node) +{ + auto typedNode = node->AsTyped(); + if (typedNode->TsType() == nullptr || !typedNode->TsType()->IsGradualType()) { + return; + } + auto underlyingType = typedNode->TsType()->GetUnderlyingType(); + if (IsETSCommonType(underlyingType)) { + typedNode->SetTsType(underlyingType); + } else { + typedNode->SetTsType(checker_->GlobalETSAnyType()); + } +} + +ir::AstNode *GradualTypeNarrowing::ProcessGradualTypeNode(ir::ETSTypeReference *node) +{ + auto type = node->GetType(checker_); + if (!type->IsGradualType()) { + return node; + } + + // Only narrow explicit type annotation of gradual to T or to Any + if (!node->Part()->Name()->IsIdentifier() || + !(node->Part()->Name()->AsIdentifier()->Name() == compiler::Signatures::GRADUAL_TYPE_NAME)) { + return node; + } + + auto underlyingType = type->GetUnderlyingType(); + ir::AstNode *loweredNode = nullptr; + if (IsETSCommonType(underlyingType)) { + loweredNode = context_->AllocNode(underlyingType, context_->Allocator()); + } else { + loweredNode = context_->AllocNode(checker_->GlobalETSAnyType(), context_->Allocator()); + } + loweredNode->SetRange(node->Range()); + loweredNode->SetParent(node->Parent()); + loweredNode->Check(checker_); + return loweredNode; +} + +bool GradualTypeNarrowing::PerformForModule(public_lib::Context *ctx, parser::Program *program) +{ + context_ = ctx; + checker_ = ctx->GetChecker()->AsETSChecker(); + + program->Ast()->TransformChildrenRecursively( + // CC-OFFNXT(G.FMT.14-CPP) project code style + [this](ir::AstNode *ast) -> ir::AstNode * { + if (ast->IsETSTypeReference()) { + return ProcessGradualTypeNode(ast->AsETSTypeReference()); + } + return ast; + }, + Name()); + + program->Ast()->IterateRecursively([this](ir::AstNode *ast) { + if (ast->IsTyped()) { + NarrowGradualType(ast); + } + }); + return true; +} +} // namespace ark::es2panda::compiler \ No newline at end of file diff --git a/ets2panda/compiler/lowering/ets/gradualTypeNarrowing.h b/ets2panda/compiler/lowering/ets/gradualTypeNarrowing.h new file mode 100644 index 0000000000000000000000000000000000000000..02fcf6f07e18c26df67eb4533933002d1c0775bc --- /dev/null +++ b/ets2panda/compiler/lowering/ets/gradualTypeNarrowing.h @@ -0,0 +1,43 @@ +/* + * 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_GRADUAL_TYPE_NARROWING_H +#define ES2PANDA_GRADUAL_TYPE_NARROWING_H + +#include "compiler/lowering/phase.h" +#include "ir/typeNode.h" + +namespace ark::es2panda::compiler { + +class GradualTypeNarrowing : public PhaseForBodies { +public: + std::string_view Name() const override + { + return "GradualTypeNarrowing"; + } + + bool PerformForModule(public_lib::Context *ctx, parser::Program *program) override; + +private: + bool IsETSCommonType(checker::Type *type); + void NarrowGradualType(ir::AstNode *node); + ir::AstNode *ProcessGradualTypeNode(ir::ETSTypeReference *node); + + public_lib::Context *context_ {nullptr}; + checker::ETSChecker *checker_ {nullptr}; +}; +} // namespace ark::es2panda::compiler + +#endif \ No newline at end of file diff --git a/ets2panda/compiler/lowering/ets/lambdaLowering.cpp b/ets2panda/compiler/lowering/ets/lambdaLowering.cpp index 782f6e5c102f944c6baafaa142d0360501b3475f..c8eca7b133aa1a1b59199d33356a7d2dd67b75f9 100644 --- a/ets2panda/compiler/lowering/ets/lambdaLowering.cpp +++ b/ets2panda/compiler/lowering/ets/lambdaLowering.cpp @@ -389,7 +389,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; @@ -538,10 +538,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); @@ -558,7 +557,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); } @@ -571,13 +570,12 @@ static void CreateInvokeMethodRestParameter(public_lib::Context *ctx, LambdaClas { auto *allocator = ctx->allocator; auto *checker = ctx->GetChecker()->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 = checker->CreateETSArrayType(checker->GlobalETSAnyType()); auto *typeAnnotation = allocator->New(arr, allocator); spread->SetTsTypeAnnotation(typeAnnotation); @@ -674,7 +672,7 @@ static ir::BlockStatement *CreateLambdaClassInvokeBody(public_lib::Context *ctx, auto *allocator = ctx->allocator; auto *parser = ctx->parser->AsETSParser(); auto *checker = ctx->GetChecker()->AsETSChecker(); - auto *anyType = checker->GlobalETSNullishObjectType(); + auto *anyType = checker->GlobalETSAnyType(); auto *call = CreateCallForLambdaClassInvoke(ctx, info, lciInfo, wrapToObject); auto bodyStmts = CreateRestArgumentsArrayReallocation(ctx, lciInfo); @@ -702,7 +700,7 @@ static void CreateLambdaClassInvokeMethod(public_lib::Context *ctx, LambdaInfo c { auto *allocator = ctx->allocator; auto *checker = ctx->GetChecker()->AsETSChecker(); - auto *anyType = checker->GlobalETSNullishObjectType(); + auto *anyType = checker->GlobalETSAnyType(); auto params = ArenaVector(allocator->Adapter()); for (size_t idx = 0; idx < lciInfo->arity; ++idx) { @@ -1101,7 +1099,8 @@ static bool IsVariableOriginalAccessor(const varbinder::Variable *var) static bool IsFunctionOrMethodCall(checker::ETSChecker *checker, ir::CallExpression const *node) { auto const *callee = node->Callee(); - if (callee->TsType() != nullptr && callee->TsType()->IsETSExtensionFuncHelperType()) { + if (callee->TsType() != nullptr && + (callee->TsType()->IsETSExtensionFuncHelperType() || callee->TsType()->IsETSAnyType())) { return true; } @@ -1138,9 +1137,9 @@ static ir::AstNode *InsertInvokeCall(public_lib::Context *ctx, ir::CallExpressio auto *ifaceType = oldType->IsETSObjectType() ? oldType->AsETSObjectType() : oldType->AsETSFunctionType()->ArrowToFunctionalInterfaceDesiredArity(checker, arity); - if (ifaceType->IsETSDynamicType()) { - return call; - } + // if (ifaceType->IsETSDynamicType()) { + // return call; + // } bool hasRestParam = oldType->IsETSFunctionType() && oldType->AsETSFunctionType()->ArrowSignature()->HasRestParameter(); util::StringView invokeMethodName = diff --git a/ets2panda/compiler/lowering/ets/lazyImportObject.cpp b/ets2panda/compiler/lowering/ets/lazyImportObject.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2e7a0527037e1caa550300484355ac99a5797327 --- /dev/null +++ b/ets2panda/compiler/lowering/ets/lazyImportObject.cpp @@ -0,0 +1,133 @@ +/** + * 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 "lazyImportObject.h" +#include "checker/ETSchecker.h" + +#include "compiler/lowering/util.h" +#include "compiler/lowering/scopesInit/scopesInitPhase.h" + +namespace { +uint32_t g_lazyImportObjectCount = 0; +} // namespace + +namespace ark::es2panda::compiler { + +using AstNodePtr = ir::AstNode *; +static constexpr std::string_view LAZY_IMPORT_OBJECT_SUFFIX = "%%lazyImportObject-"; + +ir::ClassDeclaration *CreateLazyImportObjectClass(ark::ArenaAllocator *allocator) +{ + auto className = + util::UString(std::string {LAZY_IMPORT_OBJECT_SUFFIX} + std::to_string(g_lazyImportObjectCount++), allocator); + auto *ident = allocator->New(className.View(), allocator); + auto *classDef = util::NodeAllocator::ForceSetParent( + allocator, allocator, ident, ir::ClassDefinitionModifiers::CLASS_DECL, ir::ModifierFlags::ABSTRACT, + Language(Language::Id::ETS)); + auto *classDecl = util::NodeAllocator::ForceSetParent(allocator, classDef, allocator); + ArenaVector annotations {allocator->Adapter()}; + return classDecl; +} + +static void BuildLazyImportObject(public_lib::Context *ctx, ir::ETSImportDeclaration *importDecl, + parser::Program *program, + ArenaUnorderedMap &varMap) +{ + auto parser = ctx->parser->AsETSParser(); + auto checker = ctx->GetChecker()->AsETSChecker(); + auto varBinder = checker->VarBinder()->AsETSBinder(); + auto allocator = ctx->GetChecker()->AsETSChecker()->ProgramAllocator(); + + auto delcProgram = checker->SelectEntryOrExternalProgram(varBinder, importDecl->DeclPath()); + if (!delcProgram->IsDeclForDynamicStaticInterop() || delcProgram->IsASTChecked()) { + return; + } + + auto klass = CreateLazyImportObjectClass(allocator); + auto importSpecifiers = importDecl->Specifiers(); + auto *ident = allocator->New(klass->Definition()->Ident()->Name(), allocator); + auto objType = checker->GetImportSpecifierObjectType(importDecl, ident)->AsETSObjectType(); + objType->AddObjectFlag(checker::ETSObjectFlags::DECL_MODULE); + auto moduleType = checker->GetOrCreateGradualType(objType); + auto *typeAnnotation = allocator->New(moduleType, allocator); + auto classProp = parser->CreateFormattedClassFieldDefinition("value: @@T1", typeAnnotation)->AsClassProperty(); + typeAnnotation->SetParent(classProp); + classProp->AddModifier(ir::ModifierFlags::CONST | ir::ModifierFlags::STATIC); + klass->Definition()->EmplaceBody(classProp); + classProp->SetParent(klass->Definition()); + for (auto specifier : importSpecifiers) { + varMap.insert({specifier[0].AsImportSpecifier()->Imported()->Variable(), klass->Definition()}); + } + + program->GlobalClass()->EmplaceBody(klass); + klass->SetParent(program->GlobalClass()); + auto lexScope = varbinder::LexicalScope::Enter(varBinder, program->GlobalClassScope()); + InitScopesPhaseETS::RunExternalNode(klass, varBinder); + varBinder->ResolveReferencesForScopeWithContext(klass, varBinder->TopScope()); + klass->Check(checker); +} + +static AstNodePtr TransformIdentifier(ir::Identifier *ident, public_lib::Context *ctx, + ArenaUnorderedMap &varMap) +{ + if (ident->Parent()->IsImportSpecifier()) { + return ident; + } + + // auto parser = ctx->parser->AsETSParser(); + auto checker = ctx->GetChecker()->AsETSChecker(); + auto varBinder = checker->VarBinder()->AsETSBinder(); + auto allocator = ctx->GetChecker()->AsETSChecker()->ProgramAllocator(); + + auto found = varMap.find(ident->Variable()); + if (found == varMap.end()) { + return ident; + } + + auto parent = ident->Parent(); + auto *object = allocator->New(found->second->Ident()->Name(), allocator); + auto *property = allocator->New("value", allocator); + auto *memberExpr = util::NodeAllocator::ForceSetParent( + allocator, object, property, ir::MemberExpressionKind::NONE, false, false); + + auto *res = util::NodeAllocator::ForceSetParent(allocator, memberExpr, ident, + ir::MemberExpressionKind::NONE, false, false); + res->SetParent(parent); + CheckLoweredNode(varBinder, checker, res); + if (parent->IsCallExpression()) { + ident->SetTsType(nullptr); + } + return res; +} + +bool LazyImportObject::PerformForModule(public_lib::Context *ctx, parser::Program *program) +{ + ArenaUnorderedMap varMap {ctx->Allocator()->Adapter()}; + for (auto *importDecl : program->VarBinder()->AsETSBinder()->DynamicImports()) { + BuildLazyImportObject(ctx, importDecl, program, varMap); + } + + program->Ast()->TransformChildrenRecursively( + [ctx, &varMap](ir::AstNode *node) -> AstNodePtr { + if (node->IsIdentifier() && node->AsIdentifier()->Variable() != nullptr) { + return TransformIdentifier(node->AsIdentifier(), ctx, varMap); + } + return node; + }, + Name()); + + return true; +} +} // namespace ark::es2panda::compiler diff --git a/ets2panda/compiler/lowering/ets/lazyImportObject.h b/ets2panda/compiler/lowering/ets/lazyImportObject.h new file mode 100644 index 0000000000000000000000000000000000000000..95591ff5e7b67278f8bfa1bbef5f18d21700ed78 --- /dev/null +++ b/ets2panda/compiler/lowering/ets/lazyImportObject.h @@ -0,0 +1,35 @@ +/** + * 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_LOWERING_LAZY_IMPORT_OBJECT_H +#define ES2PANDA_COMPILER_LOWERING_LAZY_IMPORT_OBJECT_H + +#include "compiler/lowering/phase.h" +#include "utils/arena_containers.h" + +namespace ark::es2panda::compiler { + +class LazyImportObject : public PhaseForBodies { +public: + std::string_view Name() const override + { + return "LazyImportObject"; + } + + bool PerformForModule(public_lib::Context *ctx, parser::Program *program) override; +}; +} // namespace ark::es2panda::compiler + +#endif // ES2PANDA_COMPILER_LOWERING_TYPE_FOR_LOWERING_H diff --git a/ets2panda/compiler/lowering/ets/optionalArgumentsLowering.cpp b/ets2panda/compiler/lowering/ets/optionalArgumentsLowering.cpp index 94ce1794274081033d3b74167141e6e6fd066f7f..cf1b076b6799f0f6b89013f039c69920fedcc61a 100644 --- a/ets2panda/compiler/lowering/ets/optionalArgumentsLowering.cpp +++ b/ets2panda/compiler/lowering/ets/optionalArgumentsLowering.cpp @@ -70,7 +70,7 @@ bool OptionalArgumentsLowering::PerformForModule(public_lib::Context *ctx, parse program->Ast()->TransformChildrenRecursivelyPreorder( // CC-OFFNXT(G.FMT.14-CPP) project code style [ctx](ir::AstNode *const node) -> ir::AstNode * { - if (node->IsCallExpression()) { + if (node->IsCallExpression() && !node->AsCallExpression()->Callee()->TsType()->IsETSAnyType()) { auto callExpr = node->AsCallExpression(); callExpr->IsTrailingCall() ? TransformArgumentsForTrailingLambda(ctx, callExpr->AsCallExpression(), callExpr->Signature()) diff --git a/ets2panda/compiler/lowering/phase.cpp b/ets2panda/compiler/lowering/phase.cpp index a871d1f962bab02d92219218356f59d30f350f82..da4c1e1d34d0073137f933abcc145c53224b8a32 100644 --- a/ets2panda/compiler/lowering/phase.cpp +++ b/ets2panda/compiler/lowering/phase.cpp @@ -38,10 +38,12 @@ #include "compiler/lowering/ets/expressionLambdaLowering.h" #include "compiler/lowering/ets/extensionAccessorLowering.h" #include "compiler/lowering/ets/genericBridgesLowering.h" +#include "compiler/lowering/ets/gradualTypeNarrowing.h" #include "compiler/lowering/ets/insertOptionalParametersAnnotation.h" #include "compiler/lowering/ets/interfaceObjectLiteralLowering.h" #include "compiler/lowering/ets/interfacePropertyDeclarations.h" #include "compiler/lowering/ets/lambdaLowering.h" +#include "compiler/lowering/ets/lazyImportObject.h" #include "compiler/lowering/ets/localClassLowering.h" #include "compiler/lowering/ets/objectIndexAccess.h" #include "compiler/lowering/ets/objectIterator.h" @@ -121,6 +123,7 @@ std::vector GetETSPhaseList() // pluginsAfterCheck has to go right after checkerPhase, nothing should be between them new PluginPhase {g_pluginsAfterCheck, ES2PANDA_STATE_CHECKED, &util::Plugin::AfterCheck}, new ConvertPrimitiveCastMethodCall, + new LazyImportObject, new DynamicImportLowering, new AsyncMethodLowering, new DeclareOverloadLowering, @@ -149,6 +152,7 @@ std::vector GetETSPhaseList() new OptionalArgumentsLowering, // #22952 could be moved to earlier phase new GenericBridgesPhase, new TypeFromLowering, + new GradualTypeNarrowing, // pluginsAfterLowerings has to come at the very end, nothing should go after it new PluginPhase{g_pluginsAfterLowering, ES2PANDA_STATE_LOWERED, &util::Plugin::AfterLowerings}, diff --git a/ets2panda/compiler/scripts/signatures.yaml b/ets2panda/compiler/scripts/signatures.yaml index 496aa8e961e6aee144f65ee1a300f5aac0366e8d..c9b24e00aad3ae3993a305485d95c9c5d3aa7591 100644 --- a/ets2panda/compiler/scripts/signatures.yaml +++ b/ets2panda/compiler/scripts/signatures.yaml @@ -157,8 +157,12 @@ defines: ref: REQUIRED_TYPE_NAME - name: 'Array' ref: ARRAY + - name: 'gradual' + ref: GRADUAL_TYPE_NAME - name: '' ref: PROPERTY + - name: 'Any' + ref: ANY_TYPE_NAME - name: 'never' ref: NEVER_TYPE_NAME - name: 'SOURCE' @@ -727,8 +731,8 @@ signatures: - callee: BUILTIN_STRING method_name: charAt - params: [PRIMITIVE_INT] - return_type: PRIMITIVE_CHAR + params: [PRIMITIVE_DOUBLE] + return_type: BUILTIN_STRING ref: BUILTIN_STRING_CHAR_AT - callee: BUILTIN_ARRAY diff --git a/ets2panda/ir/base/classDefinition.h b/ets2panda/ir/base/classDefinition.h index 7a8c0ed2ef238c968318e9c9e0bb345364770746..92a67a2f02a316b0b29e0d0285702a71e352e3bc 100644 --- a/ets2panda/ir/base/classDefinition.h +++ b/ets2panda/ir/base/classDefinition.h @@ -59,6 +59,7 @@ enum class ClassDefinitionModifiers : uint32_t { INT_ENUM_TRANSFORMED = 1U << 15U, FROM_STRUCT = 1U << 16U, FUNCTIONAL_REFERENCE = 1U << 17U, + LAZY_IMPORT_OBJECT = 1U << 18U, DECLARATION_ID_REQUIRED = DECLARATION | ID_REQUIRED, ETS_MODULE = NAMESPACE_TRANSFORMED | GLOBAL }; @@ -277,6 +278,11 @@ public: return (Modifiers() & ClassDefinitionModifiers::FROM_STRUCT) != 0; } + [[nodiscard]] bool IsLazyImportObjectClass() const noexcept + { + return (Modifiers() & ClassDefinitionModifiers::LAZY_IMPORT_OBJECT) != 0; + } + [[nodiscard]] bool IsModule() const noexcept { return IsGlobal() || IsNamespaceTransformed(); @@ -317,6 +323,11 @@ public: AddClassModifiers(ClassDefinitionModifiers::FROM_STRUCT); } + void SetLazyImportObjectClass() noexcept + { + AddClassModifiers(ClassDefinitionModifiers::LAZY_IMPORT_OBJECT); + } + [[nodiscard]] ClassDefinitionModifiers Modifiers() const noexcept { return GetHistoryNodeAs()->modifiers_; diff --git a/ets2panda/ir/ets/etsTypeReferencePart.cpp b/ets2panda/ir/ets/etsTypeReferencePart.cpp index befb99668289ac1918700cba32b279fd6426654f..e755216b198a49b73a70455978bc92ee4634ed3d 100644 --- a/ets2panda/ir/ets/etsTypeReferencePart.cpp +++ b/ets2panda/ir/ets/etsTypeReferencePart.cpp @@ -117,12 +117,69 @@ 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::BUILTIN_TYPE_PARAM_ERROR, {compiler::Signatures::FIXED_ARRAY_TYPE_NAME}, + 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; +} + checker::Type *ETSTypeReferencePart::HandleInternalTypes(checker::ETSChecker *const checker) { auto const name = Name(); ES2PANDA_ASSERT(name->IsIdentifier() || name->IsTSQualifiedName()); - Identifier *ident = GetIdent(); + Identifier *const ident = GetIdent(); varbinder::Variable *variable = nullptr; if (name->IsIdentifier()) { @@ -141,29 +198,12 @@ 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 (auto res = CheckPredefinedBuiltinTypes(checker, this); res != nullptr) { + return res; } - 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 (ident->Name() == compiler::Signatures::GRADUAL_TYPE_NAME) { + return HandleGradualType(checker); } if (ident->IsErrorPlaceHolder()) { @@ -173,35 +213,27 @@ checker::Type *ETSTypeReferencePart::HandleInternalTypes(checker::ETSChecker *co return nullptr; } -checker::Type *ETSTypeReferencePart::HandleFixedArrayType(checker::ETSChecker *const checker) +checker::Type *ETSTypeReferencePart::HandleGradualType(checker::ETSChecker *const checker) { - auto const typeParams = TypeParams(); - if (typeParams == nullptr || typeParams->Params().size() != 1) { - checker->LogError(diagnostic::FIXED_ARRAY_PARAM_ERROR, {}, Start()); + if (typeParams_ == nullptr || typeParams_->Params().size() != 1) { + checker->LogError(diagnostic::BUILTIN_TYPE_PARAM_ERROR, {compiler::Signatures::GRADUAL_TYPE_NAME}, Start()); return checker->GlobalTypeError(); } - checker::Type *type = checker->CreateETSArrayType(typeParams->Params()[0]->GetType(checker), IsReadonlyType()); + checker::Type *type = checker->GetOrCreateGradualType(typeParams_->Params()[0]->GetType(checker)); SetTsType(type); return type; } -checker::Type *ETSTypeReferencePart::HandlePartialType(checker::ETSChecker *const checker, - const Identifier *const ident) +checker::Type *ETSTypeReferencePart::HandleFixedArrayType(checker::ETSChecker *const checker) { auto const typeParams = TypeParams(); - 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(); - } - } + if (typeParams_ == nullptr || typeParams_->Params().size() != 1) { + checker->LogError(diagnostic::BUILTIN_TYPE_PARAM_ERROR, {compiler::Signatures::FIXED_ARRAY_TYPE_NAME}, Start()); + return checker->GlobalTypeError(); } - return baseType; + checker::Type *type = checker->CreateETSArrayType(typeParams->Params()[0]->GetType(checker), IsReadonlyType()); + SetTsType(type); + return type; } checker::Type *ETSTypeReferencePart::GetType(checker::ETSChecker *checker) @@ -226,7 +258,11 @@ checker::Type *ETSTypeReferencePart::GetType(checker::ETSChecker *checker) ES2PANDA_ASSERT(baseType != nullptr); if (baseType->IsETSObjectType()) { checker::InstantiationContext ctx(checker, baseType->AsETSObjectType(), TypeParams(), Start()); - SetTsType(ctx.Result()); + if (baseType->IsGradualType()) { + SetTsType(checker->GetOrCreateGradualType(ctx.Result())); + } else { + SetTsType(ctx.Result()); + } } else { SetTsType(baseType); } diff --git a/ets2panda/ir/ets/etsTypeReferencePart.h b/ets2panda/ir/ets/etsTypeReferencePart.h index 54a2156b997be8542d539df7cefeb31dbcc9ceed..8326da161879a8d9e2cdbf46248e72902f933e8f 100644 --- a/ets2panda/ir/ets/etsTypeReferencePart.h +++ b/ets2panda/ir/ets/etsTypeReferencePart.h @@ -109,9 +109,9 @@ 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); + checker::Type *HandleGradualType(checker::ETSChecker *const checker); friend class SizeOfNodeTest; void SetName(ir::Expression *name); diff --git a/ets2panda/ir/expressions/memberExpression.cpp b/ets2panda/ir/expressions/memberExpression.cpp index 9b8569317cbae274a1e8cf89f8419f48c5d45ced..9582c9545538f220d105e0e1b9a2b84af8c5e867 100644 --- a/ets2panda/ir/expressions/memberExpression.cpp +++ b/ets2panda/ir/expressions/memberExpression.cpp @@ -483,11 +483,16 @@ static void CastTupleElementFromClassMemberType(checker::ETSChecker *checker, checker::Type *MemberExpression::CheckComputed(checker::ETSChecker *checker, checker::Type *baseType) { - if (baseType->IsETSDynamicType()) { - if (!property_->Check(checker)->IsETSStringType()) { - checker->ValidateArrayIndex(property_); - } - return checker->GlobalBuiltinDynamicType(baseType->AsETSDynamicType()->Language()); + // if (baseType->IsETSDynamicType()) { + // if (!property_->Check(checker)->IsETSStringType()) { + // checker->ValidateArrayIndex(property_); + // } + // return checker->GlobalBuiltinDynamicType(baseType->AsETSDynamicType()->Language()); + // } + + if (baseType->IsETSAnyType()) { + property_->Check(checker); + return checker->GlobalETSAnyType(); } if (baseType->IsETSArrayType()) { 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/parser/program/program.h b/ets2panda/parser/program/program.h index c29543942cadcf88358a2ac9db0e08e8f34a4169..13762717edb7c183dc3c82117ec2515734cc861f 100644 --- a/ets2panda/parser/program/program.h +++ b/ets2panda/parser/program/program.h @@ -276,6 +276,11 @@ public: return moduleInfo_.kind == util::ModuleKind::PACKAGE; } + bool IsDeclForDynamicStaticInterop() const + { + return moduleInfo_.isDeclForDynamicStaticInterop; + } + void SetFlag(ProgramFlags flag); bool GetFlag(ProgramFlags flag) const; void SetASTChecked(); diff --git a/ets2panda/scripts/arkui.properties b/ets2panda/scripts/arkui.properties index 0cbcc384399ca9b927b8745ddac7de4204957a67..bcd5168bfd0c2865a2a476b72a2234dca141bee1 100644 --- a/ets2panda/scripts/arkui.properties +++ b/ets2panda/scripts/arkui.properties @@ -1,3 +1,3 @@ ARKUI_DEV_REPO=https://gitee.com/rri_opensource/koala_projects.git -ARKUI_DEV_BRANCH=panda_rev_8 +ARKUI_DEV_BRANCH=panda_rev_8_any_2 ARKUI_DEST=koala-sig 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 36718f3d1ed6bfbcaed25e4e62532a2f0bd3c539..6b220807a6026dd6d4dd151721a53b50dc4d4255 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 e61143986bcf695abdb9aa0c4020ed3b1e3d0d43..77d0719cc37f170a33772acea19bcc61362c33bf 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" @@ -1099,9 +1091,9 @@ semantic: id: 276 message: "The `keyof` keyword can only be used for class or interface type." -- name: FIXED_ARRAY_PARAM_ERROR +- name: BUILTIN_TYPE_PARAM_ERROR id: 277 - message: "FixedArray must have only one type parameter." + message: "{} must have only one type parameter." - name: LOCAL_CLASS_NATIVE_METHOD id: 278 diff --git a/ets2panda/util/importPathManager.cpp b/ets2panda/util/importPathManager.cpp index 7cf04669276b7b647c1a6d4a086c986641ad2d86..714111fe702f7335a43cc93b1ebc2e3feb649d8f 100644 --- a/ets2panda/util/importPathManager.cpp +++ b/ets2panda/util/importPathManager.cpp @@ -66,7 +66,7 @@ ImportPathManager::ImportMetadata ImportPathManager::GatherImportMetadata(parser // NOTE(dkofanov): The code below expresses the idea of 'dynamicPaths' defining separated, virtual file system. // Probably, paths of common imports should be isolated from the host fs as well, being resolved by 'ModuleInfo' // instead of 'AbsoluteName'. - isDynamic_ = program->ModuleInfo().isDeclForDynamicStaticInterop; + isDynamic_ = program->IsDeclForDynamicStaticInterop();; auto curModulePath = isDynamic_ ? program->ModuleInfo().moduleName : program->AbsoluteName(); auto [resolvedImportPath, resolvedIsDynamic] = ResolvePath(curModulePath.Utf8(), importPath); if (resolvedImportPath.empty()) { diff --git a/ets2panda/varbinder/ETSBinder.cpp b/ets2panda/varbinder/ETSBinder.cpp index 3c1b368ce7d2fe7a0da0d81285a47f1c0bd200fd..a1c9685baf87a84e623d8659bed1bd7bbbf705ea 100644 --- a/ets2panda/varbinder/ETSBinder.cpp +++ b/ets2panda/varbinder/ETSBinder.cpp @@ -56,9 +56,11 @@ 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 || name == compiler::Signatures::GRADUAL_TYPE_NAME || + name.StartsWith("%%lazyImportObject-"); } bool ETSBinder::HandleDynamicVariables(ir::Identifier *ident, Variable *variable, bool allowDynamicNamespaces)