diff --git a/ets2panda/BUILD.gn b/ets2panda/BUILD.gn index 056ee80391bc85bc0f60d4201ce6f901c42404d4..34a391ee35402ea79496e8e73a0e1d8ff13ba874 100644 --- a/ets2panda/BUILD.gn +++ b/ets2panda/BUILD.gn @@ -258,6 +258,7 @@ libes2panda_sources = [ "compiler/lowering/ets/primitiveConversionPhase.cpp", "compiler/lowering/ets/promiseVoid.cpp", "compiler/lowering/ets/recordLowering.cpp", + "compiler/lowering/ets/relaxedAnyLowering.cpp", "compiler/lowering/ets/resizableArrayLowering.cpp", "compiler/lowering/ets/restArgsLowering.cpp", "compiler/lowering/ets/restTupleLowering.cpp", diff --git a/ets2panda/CMakeLists.txt b/ets2panda/CMakeLists.txt index 5715dc5301447922b154e413319008abe6417f55..d2c13967594bc1c796eebdd2ff5e8a70f9df6187 100644 --- a/ets2panda/CMakeLists.txt +++ b/ets2panda/CMakeLists.txt @@ -315,6 +315,7 @@ set(ES2PANDA_LIB_SRC compiler/lowering/ets/asyncMethodLowering.cpp compiler/lowering/ets/bigintLowering.cpp compiler/lowering/ets/recordLowering.cpp + compiler/lowering/ets/relaxedAnyLowering.cpp compiler/lowering/ets/resizableArrayLowering.cpp compiler/lowering/ets/restArgsLowering.cpp compiler/lowering/ets/unionLowering.cpp @@ -446,6 +447,7 @@ set(ES2PANDA_LIB_SRC ir/ets/etsClassLiteral.cpp ir/ets/etsIntrinsicNode.cpp ir/ets/etsFunctionType.cpp + ir/ets/etsIntrinsicNode.cpp ir/ets/etsKeyofType.cpp ir/ets/etsNewArrayInstanceExpression.cpp ir/ets/etsNewClassInstanceExpression.cpp diff --git a/ets2panda/ast_verifier/invariants/identifierHasVariable.cpp b/ets2panda/ast_verifier/invariants/identifierHasVariable.cpp index bdc95f22b1a8476b96dd07bc08d62f0acac1c37c..10042ab5850ec5998e00bb0a90ea580d5ba03d09 100644 --- a/ets2panda/ast_verifier/invariants/identifierHasVariable.cpp +++ b/ets2panda/ast_verifier/invariants/identifierHasVariable.cpp @@ -17,6 +17,7 @@ #include "ir/base/scriptFunction.h" #include "ir/expressions/memberExpression.h" #include "ir/ts/tsEnumDeclaration.h" +#include "checker/types/ets/etsAnyType.h" namespace ark::es2panda::compiler::ast_verifier { @@ -25,8 +26,8 @@ public: ExceptionsMatcher(const IdentifierHasVariable *inv, const ir::Identifier *ast) : inv_(inv), ast_(ast) {} bool Match() { - auto res = IsLengthProp() || IsEmptyName() || IsInObjectExpr() || IsInPackageDecl() || IsBuiltinType() || - IsUnionMemberAccess(); + auto res = IsLengthProp() || IsAnyProp() || IsEmptyName() || IsInObjectExpr() || IsInPackageDecl() || + IsBuiltinType() || IsUnionMemberAccess(); return res; } @@ -36,6 +37,13 @@ private: return ast_->Parent() != nullptr && ast_->Parent()->IsMemberExpression() && ast_->Name().Is("length"); } + bool IsAnyProp() + { + return ast_->Parent() != nullptr && ast_->Parent()->IsMemberExpression() && + ast_->Parent()->AsMemberExpression()->Object()->TsType()->IsETSAnyType() && + ast_->Parent()->AsMemberExpression()->Object()->TsType()->AsETSAnyType()->IsRelaxed(); + } + bool IsEmptyName() { // NOTE(kkonkuznetsov): some identifiers have empty names @@ -75,7 +83,8 @@ private: // NOTE(mmartin): find a better solution to handle utility type resolution 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::AWAITED_TYPE_NAME); + name.Is(compiler::Signatures::ANY_TYPE_NAME) || name.Is(Signatures::ANY) || + name.Is(compiler::Signatures::AWAITED_TYPE_NAME); } bool IsUnionMemberAccess() diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index 2f25b810ce2225aa2257658888f6fd72608f761f..d121f52519a61957173e57dc045f529096f63a44 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -467,6 +467,11 @@ checker::Type *ETSAnalyzer::Check(ir::ETSClassLiteral *expr) const return expr->TsType(); } +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ETSIntrinsicNode *node) const +{ + ES2PANDA_UNREACHABLE(); +} + checker::Type *ETSAnalyzer::Check(ir::ETSFunctionType *node) const { if (node->TsType() != nullptr) { @@ -1474,8 +1479,22 @@ static bool OverloadDeclaration(ir::Expression *expr) return false; } -checker::Signature *ETSAnalyzer::ResolveSignature(ETSChecker *checker, ir::CallExpression *expr, - checker::Type *calleeType) const +static Signature *CreateRelaxedAnySyntheticCallSignature(ETSChecker *checker) +{ + std::stringstream ss; + auto *info = checker->CreateSignatureInfo(); + info->minArgCount = 0; + + auto *paramVar = + varbinder::Scope::CreateVar(checker->ProgramAllocator(), "args", varbinder::VariableFlags::NONE, nullptr); + paramVar->SetTsType(checker->CreateETSArrayType(checker->GlobalETSRelaxedAnyType())); + info->restVar = paramVar; + // owner is not set + + return checker->CreateSignature(info, checker->GlobalETSRelaxedAnyType(), ir::ScriptFunctionFlags::NONE, false); +} + +static checker::Signature *ResolveSignature(ETSChecker *checker, ir::CallExpression *expr, checker::Type *calleeType) { if (calleeType->IsETSFunctionType() && calleeType->AsETSFunctionType()->HasHelperSignature() && expr->Signature() != nullptr) { @@ -1494,7 +1513,7 @@ checker::Signature *ETSAnalyzer::ResolveSignature(ETSChecker *checker, ir::CallE if (calleeType->IsETSExtensionFuncHelperType()) { auto *signature = ResolveCallForETSExtensionFuncHelperType(calleeType->AsETSExtensionFuncHelperType(), checker, expr); - GetChecker()->AsETSChecker()->UpdateDeclarationFromSignature(expr, signature); + checker->AsETSChecker()->UpdateDeclarationFromSignature(expr, signature); return signature; } @@ -1509,8 +1528,16 @@ checker::Signature *ETSAnalyzer::ResolveSignature(ETSChecker *checker, ir::CallE } return signature; } + + auto noSignatures = ArenaVector {checker->Allocator()->Adapter()}; + if (calleeType->IsETSRelaxedAnyType()) { + noSignatures.push_back(CreateRelaxedAnySyntheticCallSignature(checker)); + } + auto &signatures = expr->IsETSConstructorCall() ? calleeType->AsETSObjectType()->ConstructSignatures() - : calleeType->AsETSFunctionType()->CallSignaturesOfMethodOrArrow(); + : calleeType->IsETSRelaxedAnyType() + ? noSignatures + : calleeType->AsETSFunctionType()->CallSignaturesOfMethodOrArrow(); return checker->ResolveCallExpressionAndTrailingLambda(signatures, expr, expr->Start()); } @@ -1528,16 +1555,14 @@ static ETSObjectType *GetCallExpressionCalleeObject(ETSChecker *checker, ir::Cal return checker->Context().ContainingClass(); } -Type *ETSAnalyzer::GetReturnType(ir::CallExpression *expr, Type *calleeType) const +static Type *GetReturnType(ETSChecker *checker, ir::CallExpression *expr, Type *calleeType) { - ETSChecker *checker = GetETSChecker(); - if (calleeType->IsTypeError()) { return checker->GlobalTypeError(); } if (!calleeType->IsETSFunctionType() && !expr->IsETSConstructorCall() && - !calleeType->IsETSExtensionFuncHelperType()) { + !calleeType->IsETSExtensionFuncHelperType() && !calleeType->IsETSRelaxedAnyType()) { checker->LogError(diagnostic::NO_CALL_SIGNATURE, {calleeType}, expr->Start()); return checker->GlobalTypeError(); } @@ -1614,10 +1639,10 @@ static checker::SavedCheckerContext ReconstructOwnerClassContext(ETSChecker *che return SavedCheckerContext(checker, status, owner); } -checker::Type *ETSAnalyzer::GetCallExpressionReturnType(ir::CallExpression *expr, checker::Type *calleeType) const +static checker::Type *GetCallExpressionReturnType(ETSChecker *checker, ir::CallExpression *expr, + checker::Type *calleeType) { - ETSChecker *checker = GetETSChecker(); - checker::Type *returnType = GetReturnType(expr, calleeType); + checker::Type *returnType = GetReturnType(checker, expr, calleeType); if (returnType->IsTypeError()) { return checker->GlobalTypeError(); @@ -1708,13 +1733,12 @@ checker::Type *ETSAnalyzer::Check(ir::CallExpression *expr) const checker::TypeStackElement tse(checker, expr, {{diagnostic::CYCLIC_CALLEE, {}}}, expr->Start()); ERROR_SANITY_CHECK(checker, !tse.HasTypeError(), return expr->SetTsType(checker->GlobalTypeError())); - checker::Type *const returnType = GetCallExpressionReturnType(expr, calleeType); + checker::Type *const returnType = GetCallExpressionReturnType(checker, expr, calleeType); expr->SetTsType(returnType); if (returnType->IsTypeError()) { return returnType; } - - if (calleeType->IsETSArrowType()) { + if (calleeType->IsETSArrowType() || calleeType->IsETSRelaxedAnyType()) { expr->SetUncheckedType(checker->GuaranteedTypeForUncheckedCast( checker->GlobalETSAnyType(), checker->MaybeBoxType(expr->Signature()->ReturnType()))); } else { @@ -1946,6 +1970,10 @@ checker::Type *ETSAnalyzer::ResolveMemberExpressionByBaseType(ETSChecker *checke return checker->InvalidateType(expr); } + if (baseType->IsETSRelaxedAnyType()) { + return expr->AdjustType(checker, checker->GlobalETSRelaxedAnyType()); + } + if (baseType->IsGradualType()) { return ResolveMemberExpressionByBaseType(checker, baseType->AsGradualType()->GetBaseType(), expr); } @@ -1979,15 +2007,9 @@ checker::Type *ETSAnalyzer::ResolveMemberExpressionByBaseType(ETSChecker *checke // NOTE(mshimenkov): temporary workaround to deliver 'primitives refactoring' patch // To be removed after complete refactoring if (baseType->IsETSPrimitiveType()) { - static std::array castMethods {{ - "toChar", - "toByte", - "toShort", - "toInt", - "toLong", - "toFloat", - "toDouble", - }}; + static std::array castMethods { + "toChar", "toByte", "toShort", "toInt", "toLong", "toFloat", "toDouble", + }; auto res = std::find(castMethods.begin(), castMethods.end(), expr->Property()->AsIdentifier()->Name().Utf8()); if (res != castMethods.end()) { auto type = checker->MaybeBoxType(baseType); @@ -3010,25 +3032,6 @@ checker::Type *ETSAnalyzer::Check(ir::StringLiteral *expr) const return expr->TsType(); } -checker::Type *ETSAnalyzer::Check(ir::ETSIntrinsicNode *node) const -{ - ETSChecker *checker = GetETSChecker(); - for (auto *arg : node->Arguments()) { - arg->Check(checker); - } - // Note (daizihan): #27074, make it more scalable when IntrinsicNodeType is extended. - if (node->Type() == ir::IntrinsicNodeType::TYPE_REFERENCE) { - auto type = checker->GlobalBuiltinClassType()->Clone(checker); - // Since std.core.Class initialize() is instance method, need to remove the variable flag. - auto newVar = type->Variable()->AsLocalVariable()->Copy(checker->Allocator(), type->Variable()->Declaration()); - newVar->RemoveFlag(varbinder::VariableFlags::CLASS_OR_INTERFACE); - type->SetVariable(newVar); - return node->SetTsType(type); - } - ES2PANDA_UNREACHABLE(); - return checker->GlobalTypeError(); -} - checker::Type *ETSAnalyzer::Check(ir::ImportDeclaration *st) const { ETSChecker *checker = GetETSChecker(); diff --git a/ets2panda/checker/ETSAnalyzer.h b/ets2panda/checker/ETSAnalyzer.h index 4b2adeea2a4297fdbe5194dbfd39ac799ba7c8fc..1bce5564565e5e9518f01d26d5c4490051ed2128 100644 --- a/ets2panda/checker/ETSAnalyzer.h +++ b/ets2panda/checker/ETSAnalyzer.h @@ -54,11 +54,7 @@ private: ETSChecker *GetETSChecker() const; void CheckInstantatedClass(ir::ETSNewClassInstanceExpression *expr, ETSObjectType *&calleeObj) const; void CheckMethodModifiers(ir::MethodDefinition *node) const; - checker::Signature *ResolveSignature(ETSChecker *checker, ir::CallExpression *expr, - checker::Type *calleeType) const; - checker::Type *GetReturnType(ir::CallExpression *expr, checker::Type *calleeType) const; checker::Type *GetFunctionReturnType(ir::ReturnStatement *st, ir::ScriptFunction *containingFunc) const; - checker::Type *GetCallExpressionReturnType(ir::CallExpression *expr, checker::Type *calleeType) const; checker::Type *UnwrapPromiseType(checker::Type *type) const; checker::Type *GetSmartType(ir::AssignmentExpression *expr, checker::Type *leftType, checker::Type *rightType) const; diff --git a/ets2panda/checker/ETSchecker.cpp b/ets2panda/checker/ETSchecker.cpp index 88a71002f8b233850bcbf3444e179df12e41f060..7ba999f0075caf0532df1cf4bda506101eca0a9a 100644 --- a/ets2panda/checker/ETSchecker.cpp +++ b/ets2panda/checker/ETSchecker.cpp @@ -641,16 +641,6 @@ ETSObjectType *ETSChecker::GlobalBuiltinFunctionType() const return AsETSObjectType(&GlobalTypesHolder::GlobalFunctionBuiltinType); } -ETSObjectType *ETSChecker::GlobalBuiltinJSRuntimeType() const -{ - return AsETSObjectType(&GlobalTypesHolder::GlobalJSRuntimeBuiltinType); -} - -ETSObjectType *ETSChecker::GlobalBuiltinJSValueType() const -{ - return AsETSObjectType(&GlobalTypesHolder::GlobalJSValueBuiltinType); -} - ETSObjectType *ETSChecker::GlobalBuiltinFunctionType(size_t nargs, bool hasRest) const { return AsETSObjectType(&GlobalTypesHolder::GlobalFunctionBuiltinType, nargs, hasRest); @@ -671,14 +661,6 @@ size_t ETSChecker::GlobalBuiltinFunctionTypeVariadicThreshold() const return GetGlobalTypesHolder()->VariadicFunctionTypeThreshold(); } -ETSObjectType *ETSChecker::GlobalBuiltinDynamicType(Language lang) const -{ - if (lang.GetId() == Language::Id::JS) { - return GlobalBuiltinJSValueType(); - } - return nullptr; -} - ETSObjectType *ETSChecker::GlobalBuiltinBoxType(Type *contents) { ES2PANDA_ASSERT(contents->IsETSReferenceType()); diff --git a/ets2panda/checker/ETSchecker.h b/ets2panda/checker/ETSchecker.h index 97e8a6d3c36ae60d6301f02d74652d2f363797c1..a3efc0fee992d0510c35ad7e859c3c0ad4a218bd 100644 --- a/ets2panda/checker/ETSchecker.h +++ b/ets2panda/checker/ETSchecker.h @@ -67,14 +67,10 @@ using ComputedAbstracts = using ArrayMap = ArenaUnorderedMap, ETSArrayType *, PairHash>; using ObjectInstantiationMap = ArenaUnorderedMap>; using GlobalArraySignatureMap = ArenaUnorderedMap; -using DynamicCallIntrinsicsMap = ArenaUnorderedMap>; using FunctionSignatureMap = ArenaUnorderedMap; using FunctionInterfaceMap = ArenaUnorderedMap; -using DynamicClassIntrinsicsMap = ArenaUnorderedMap; -using DynamicLambdaObjectSignatureMap = ArenaUnorderedMap; using FunctionalInterfaceMap = ArenaUnorderedMap; using TypeMapping = ArenaUnorderedMap; -using DynamicCallNamesMap = ArenaMap, uint32_t>; using ConstraintCheckRecord = std::tuple *, const Substitution, lexer::SourcePosition>; // can't use util::DiagnosticWithParams because std::optional can't contain references using MaybeDiagnosticInfo = @@ -94,15 +90,8 @@ public: arrowToFuncInterfaces_(Allocator()->Adapter()), globalArraySignatures_(Allocator()->Adapter()), unionAssemblerTypes_(Allocator()->Adapter()), - dynamicIntrinsics_ {DynamicCallIntrinsicsMap {Allocator()->Adapter()}, - DynamicCallIntrinsicsMap {Allocator()->Adapter()}}, - dynamicClasses_ {DynamicClassIntrinsicsMap(Allocator()->Adapter()), - DynamicClassIntrinsicsMap(Allocator()->Adapter())}, - dynamicLambdaSignatureCache_(Allocator()->Adapter()), functionalInterfaceCache_(Allocator()->Adapter()), apparentTypes_(Allocator()->Adapter()), - dynamicCallNames_ { - {DynamicCallNamesMap(Allocator()->Adapter()), DynamicCallNamesMap(Allocator()->Adapter())}}, overloadSigContainer_(Allocator()->Adapter()), readdedChecker_(Allocator()->Adapter()) { @@ -160,8 +149,6 @@ public: ETSObjectType *GlobalStringBuilderBuiltinType() const; ETSObjectType *GlobalBuiltinPromiseType() const; ETSObjectType *GlobalBuiltinFunctionType() const; - ETSObjectType *GlobalBuiltinJSRuntimeType() const; - ETSObjectType *GlobalBuiltinJSValueType() const; ETSObjectType *GlobalBuiltinBoxType(Type *contents); ETSObjectType *GlobalBuiltinFunctionType(size_t nargs, bool hasRest) const; @@ -170,8 +157,6 @@ public: ETSObjectType *GlobalBuiltinTupleType(size_t nargs) const; - ETSObjectType *GlobalBuiltinDynamicType(Language lang) const; - GlobalArraySignatureMap &GlobalArrayTypes(); const GlobalArraySignatureMap &GlobalArrayTypes() const; @@ -871,16 +856,6 @@ public: void ResolveReturnStatement(checker::Type *funcReturnType, checker::Type *argumentType, ir::ScriptFunction *containingFunc, ir::ReturnStatement *st); - auto *DynamicCallNames(bool isConstruct) - { - return &dynamicCallNames_[static_cast(isConstruct)]; - } - - const auto *DynamicCallNames(bool isConstruct) const - { - return &dynamicCallNames_[static_cast(isConstruct)]; - } - std::recursive_mutex *Mutex() { return &mtx_; @@ -975,19 +950,8 @@ public: globalArraySignatures_.clear(); unionAssemblerTypes_.clear(); GetCachedComputedAbstracts()->clear(); - for (auto &dynamicCallIntrinsicsMap : dynamicIntrinsics_) { - dynamicCallIntrinsicsMap.clear(); - } - - for (auto &dynamicClassIntrinsicsMap : dynamicClasses_) { - dynamicClassIntrinsicsMap.clear(); - } - dynamicLambdaSignatureCache_.clear(); functionalInterfaceCache_.clear(); apparentTypes_.clear(); - for (auto &dynamicCallNamesMap : dynamicCallNames_) { - dynamicCallNamesMap.clear(); - } elementStack_.clear(); overloadSigContainer_.clear(); } @@ -1055,26 +1019,6 @@ private: ClassInitializerBuilder const &builder); std::pair CreateScriptFunction(ClassInitializerBuilder const &builder); - template - ir::MethodDefinition *CreateDynamicCallIntrinsic(ir::Expression *callee, const ArenaVector &arguments, - Language lang); - ir::ClassStaticBlock *CreateDynamicCallClassInitializer(Language lang, bool isConstruct); - ir::ClassStaticBlock *CreateDynamicModuleClassInitializer(const std::vector &imports); - ir::MethodDefinition *CreateDynamicModuleClassInitMethod(); - - ir::MethodDefinition *CreateLambdaObjectClassInitializer(ETSObjectType *functionalInterface); - - ir::MethodDefinition *CreateLambdaObjectClassInvokeMethod(Signature *invokeSignature, - ir::TypeNode *retTypeAnnotation); - - void EmitDynamicModuleClassInitCall(); - DynamicCallIntrinsicsMap *DynamicCallIntrinsics(bool isConstruct) - { - return &dynamicIntrinsics_[static_cast(isConstruct)]; - } - - ir::ClassDeclaration *GetDynamicClass(Language lang, bool isConstruct); - using Type2TypeMap = std::unordered_map; using TypeSet = std::unordered_set; bool CheckTypeParameterConstraint(ir::TSTypeParameter *param, Type2TypeMap &extends); @@ -1134,13 +1078,8 @@ private: GlobalArraySignatureMap globalArraySignatures_; ArenaSet unionAssemblerTypes_; ComputedAbstracts *cachedComputedAbstracts_ {nullptr}; - // NOTE(aleksisch): Extract dynamic from checker to separate class - std::array dynamicIntrinsics_; - std::array dynamicClasses_; - DynamicLambdaObjectSignatureMap dynamicLambdaSignatureCache_; FunctionalInterfaceMap functionalInterfaceCache_; TypeMapping apparentTypes_; - std::array dynamicCallNames_; std::recursive_mutex mtx_; evaluate::ScopedDebugInfoPlugin *debugInfoPlugin_ {nullptr}; std::unordered_set elementStack_; diff --git a/ets2panda/checker/ets/typeCheckingHelpers.cpp b/ets2panda/checker/ets/typeCheckingHelpers.cpp index f3bd5643d6be10787ec0d4a1f94c5d914dc6c140..b8cf31d49213fc976ce0edd83606ec2ca18907d6 100644 --- a/ets2panda/checker/ets/typeCheckingHelpers.cpp +++ b/ets2panda/checker/ets/typeCheckingHelpers.cpp @@ -74,7 +74,7 @@ void ETSChecker::CheckTruthinessOfType(ir::Expression *expr) bool ETSChecker::CheckNonNullish(ir::Expression const *expr) { - if (!expr->TsType()->PossiblyETSNullish()) { + if (!expr->TsType()->PossiblyETSNullish() || expr->TsType()->IsETSRelaxedAnyType()) { return true; } @@ -378,6 +378,11 @@ bool Type::IsETSMethodType() const return HasTypeFlag(TypeFlag::ETS_METHOD); } +bool Type::IsETSRelaxedAnyType() const +{ + return IsETSAnyType() && AsETSAnyType()->IsRelaxed(); +} + [[maybe_unused]] static bool IsSaneETSReferenceType(Type const *type) { static constexpr TypeFlag ETS_SANE_REFERENCE_TYPE = diff --git a/ets2panda/checker/ets/validateHelpers.cpp b/ets2panda/checker/ets/validateHelpers.cpp index 47363ca0566fd62d80b35580629c1d9dc110ae0e..430b137c12b60389f7aa467905420111f0cd5c25 100644 --- a/ets2panda/checker/ets/validateHelpers.cpp +++ b/ets2panda/checker/ets/validateHelpers.cpp @@ -107,7 +107,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()) { + if (type->IsETSFunctionType() || type->IsETSRelaxedAnyType()) { return; } // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) diff --git a/ets2panda/checker/types/ets/etsAnyType.cpp b/ets2panda/checker/types/ets/etsAnyType.cpp index ea399276063cd735fb696ab45e416260bd38d9f9..c1e5307545c902a90b0062e2aa9fa97ff2b5abda 100644 --- a/ets2panda/checker/types/ets/etsAnyType.cpp +++ b/ets2panda/checker/types/ets/etsAnyType.cpp @@ -86,7 +86,7 @@ void ETSAnyType::IsSupertypeOf(TypeRelation *relation, Type *source) void ETSAnyType::ToString(std::stringstream &ss, [[maybe_unused]] bool precise) const { - ss << compiler::Signatures::ANY_TYPE_NAME; + ss << (IsRelaxed() ? compiler::Signatures::ANY : compiler::Signatures::ANY_TYPE_NAME); } void ETSAnyType::ToAssemblerType(std::stringstream &ss) const @@ -107,6 +107,6 @@ void ETSAnyType::ToDebugInfoType(std::stringstream &ss) const Type *ETSAnyType::Instantiate(ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, [[maybe_unused]] GlobalTypesHolder *globalTypes) { - return isRelaxedAny_ ? allocator->New(true) : allocator->New(); + return allocator->New(isRelaxed_); } } // namespace ark::es2panda::checker diff --git a/ets2panda/checker/types/ets/etsAnyType.h b/ets2panda/checker/types/ets/etsAnyType.h index 7d12b6a004e77c58e9e50f6f0b2b2a2691dd5668..8e111f75ed5379e3b2af66cc71c9b420ba06bcd3 100644 --- a/ets2panda/checker/types/ets/etsAnyType.h +++ b/ets2panda/checker/types/ets/etsAnyType.h @@ -21,8 +21,12 @@ namespace ark::es2panda::checker { class ETSAnyType : public Type { public: - ETSAnyType() : Type(TypeFlag::ETS_ANY) {} - explicit ETSAnyType(bool isRelaxedAny) : Type(TypeFlag::ETS_ANY), isRelaxedAny_(isRelaxedAny) {} + explicit ETSAnyType(bool isRelaxed) : Type(TypeFlag::ETS_ANY), isRelaxed_(isRelaxed) {} + + bool IsRelaxed() const + { + return isRelaxed_; + } void Identical(TypeRelation *relation, Type *other) override; void AssignmentTarget(TypeRelation *relation, Type *source) override; @@ -40,13 +44,8 @@ public: Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; - bool IsRelaxedAny() const - { - return isRelaxedAny_; - } - private: - bool isRelaxedAny_ = false; + bool isRelaxed_; }; } // namespace ark::es2panda::checker diff --git a/ets2panda/checker/types/ets/etsPartialTypeParameter.cpp b/ets2panda/checker/types/ets/etsPartialTypeParameter.cpp index fc451fd0707596091c2f81d0c8fb6beb8ce54b6b..9333d54633a9c357e64dde7d9bbdc270b617ec4d 100644 --- a/ets2panda/checker/types/ets/etsPartialTypeParameter.cpp +++ b/ets2panda/checker/types/ets/etsPartialTypeParameter.cpp @@ -76,6 +76,8 @@ void ETSPartialTypeParameter::IsSubtypeOf(TypeRelation *relation, Type *target) relation->Result(false); if (target->IsETSPartialTypeParameter()) { relation->IsSupertypeOf(target->AsETSPartialTypeParameter()->GetUnderlying(), GetUnderlying()); + } else if (target->IsETSObjectType() && target->AsETSObjectType()->IsGlobalETSObjectType()) { + relation->IsSupertypeOf(target, GetUnderlying()); } } diff --git a/ets2panda/checker/types/globalTypesHolder.cpp b/ets2panda/checker/types/globalTypesHolder.cpp index 4bf67257acbf5114f924961e48c1706fdf6dca53..7219b11fdbbba992576e2827c85c178aae4e1b62 100644 --- a/ets2panda/checker/types/globalTypesHolder.cpp +++ b/ets2panda/checker/types/globalTypesHolder.cpp @@ -150,7 +150,7 @@ 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_ANY)] = allocator->New(false); globalTypes_[static_cast(GlobalTypeId::ETS_RELAXED_ANY)] = allocator->New(true); globalTypes_[static_cast(GlobalTypeId::ETS_NEVER)] = allocator->New(); } @@ -224,10 +224,6 @@ GlobalTypesHolder::GlobalTypesHolder(ArenaAllocator *allocator) // Tuple types AddTupleTypes(allocator); - - // ETS interop js specific types - builtinNameMappings_.emplace("JSRuntime", GlobalTypeId::ETS_INTEROP_JSRUNTIME_BUILTIN); - builtinNameMappings_.emplace("JSValue", GlobalTypeId::ETS_INTEROP_JSVALUE_BUILTIN); } Type *GlobalTypesHolder::GlobalNumberType() @@ -645,16 +641,6 @@ Type *GlobalTypesHolder::GlobalBoxBuiltinType() return globalTypes_.at(static_cast(GlobalTypeId::ETS_BOX_BUILTIN)); } -Type *GlobalTypesHolder::GlobalJSRuntimeBuiltinType() -{ - return globalTypes_.at(static_cast(GlobalTypeId::ETS_INTEROP_JSRUNTIME_BUILTIN)); -} - -Type *GlobalTypesHolder::GlobalJSValueBuiltinType() -{ - return globalTypes_.at(static_cast(GlobalTypeId::ETS_INTEROP_JSVALUE_BUILTIN)); -} - Type *GlobalTypesHolder::GlobalBooleanBoxBuiltinType() { return globalTypes_.at(static_cast(GlobalTypeId::ETS_BOOLEAN_BOX_BUILTIN)); diff --git a/ets2panda/checker/types/globalTypesHolder.h b/ets2panda/checker/types/globalTypesHolder.h index 14e5a384237cd6756970b9da46172f960cf98ef3..d2392cf099b9b1168796c7f39ae233af63f974a4 100644 --- a/ets2panda/checker/types/globalTypesHolder.h +++ b/ets2panda/checker/types/globalTypesHolder.h @@ -101,8 +101,6 @@ enum class GlobalTypeId : std::size_t { ETS_FUNCTION_BUILTIN, ETS_REGEXP_BUILTIN, ETS_ARRAY_BUILTIN, - ETS_INTEROP_JSRUNTIME_BUILTIN, - ETS_INTEROP_JSVALUE_BUILTIN, ETS_BOX_BUILTIN, ETS_BOOLEAN_BOX_BUILTIN, ETS_BYTE_BOX_BUILTIN, @@ -338,10 +336,6 @@ public: Type *GlobalRegExpBuiltinType(); Type *GlobalSetBuiltinType(); - // JS specific types - Type *GlobalJSRuntimeBuiltinType(); - Type *GlobalJSValueBuiltinType(); - Type *GlobalTypeError(); void InitializeBuiltin(util::StringView name, Type *type); diff --git a/ets2panda/checker/types/type.h b/ets2panda/checker/types/type.h index b0565a97d768a97e48fe6ff99f1413f9df69d67a..91fceb516e6fed3db6a04cde2737cab1ce3eb8ac 100644 --- a/ets2panda/checker/types/type.h +++ b/ets2panda/checker/types/type.h @@ -107,6 +107,7 @@ public: bool IsETSBigIntType() const; bool IsETSArrowType() const; bool IsETSMethodType() const; + bool IsETSRelaxedAnyType() const; bool IsETSPrimitiveType() const; bool IsETSReferenceType() const; bool IsETSAsyncFuncReturnType() const; diff --git a/ets2panda/compiler/core/ETSCompiler.cpp b/ets2panda/compiler/core/ETSCompiler.cpp index 9afe0f1b7126508fe8c55ca3b13f5bd1d0d46fbc..1c4e655ae3bb5316c324b1147343ca87351be691 100644 --- a/ets2panda/compiler/core/ETSCompiler.cpp +++ b/ets2panda/compiler/core/ETSCompiler.cpp @@ -97,6 +97,11 @@ void ETSCompiler::Compile(const ir::ETSClassLiteral *expr) const ES2PANDA_ASSERT(etsg->Checker()->Relation()->IsIdenticalTo(etsg->GetAccumulatorType(), expr->TsType())); } +void ETSCompiler::Compile([[maybe_unused]] const ir::ETSIntrinsicNode *node) const +{ + ES2PANDA_UNREACHABLE(); +} + void ETSCompiler::Compile(const ir::ETSFunctionType *node) const { ETSGen *etsg = GetETSGen(); @@ -255,7 +260,7 @@ void ETSCompiler::Compile(const ir::ETSNewClassInstanceExpression *expr) const auto objReg = etsg->AllocReg(); expr->GetTypeRef()->Compile(etsg); etsg->StoreAccumulator(expr->GetTypeRef(), objReg); - etsg->CallAnyNew(expr, expr->GetArguments(), objReg); + etsg->CallAnyNew(expr, Span(expr->GetArguments()), objReg); } else { ConvertRestArguments(const_cast(etsg->Checker()->AsETSChecker()), expr); etsg->InitObject(expr, expr->signature_, expr->GetArguments()); @@ -388,9 +393,7 @@ void ETSCompiler::Compile(const ir::AssignmentExpression *expr) const etsg->CreateBigIntObject(expr, value, Signatures::BUILTIN_BIGINT_CTOR_BIGINT); } - ES2PANDA_ASSERT(etsg->Checker()->Relation()->IsIdenticalTo(etsg->GetAccumulatorType(), exprType) || - etsg->Checker()->Relation()->IsIdenticalTo(etsg->GetAccumulatorType(), - etsg->Checker()->GlobalBuiltinJSValueType())); + ES2PANDA_ASSERT(etsg->Checker()->Relation()->IsIdenticalTo(etsg->GetAccumulatorType(), exprType)); lref.SetValue(); } @@ -498,7 +501,7 @@ static void CompileAnyInstanceOf(compiler::ETSGen *etsg, const VReg lhs, const i expr->Compile(etsg); etsg->StoreAccumulator(expr, objReg); etsg->LoadAccumulator(expr, lhs); - etsg->EmitAnyIsInstance(expr, objReg); + etsg->EmitAnyIsinstance(expr, objReg); etsg->SetAccumulatorType(etsg->Checker()->GlobalETSBooleanType()); } @@ -513,7 +516,7 @@ static void CompileInstanceof(compiler::ETSGen *etsg, const ir::BinaryExpression etsg->ApplyConversionAndStoreAccumulator(expr->Left(), lhs, expr->OperationType()); auto target = expr->Right()->TsType(); - if (target->IsETSAnyType() && target->AsETSAnyType()->IsRelaxedAny()) { + if (target->IsETSAnyType() && target->AsETSAnyType()->IsRelaxed()) { CompileAnyInstanceOf(etsg, lhs, expr->Right()); } else { etsg->IsInstance(expr, lhs, target); @@ -705,9 +708,11 @@ void ETSCompiler::CompileAny(const ir::CallExpression *expr, const ir::Expressio if (expr->Signature()->Function() != nullptr && expr->Signature()->Function()->IsStatic()) { etsg->LoadPropertyByNameAny(memberExpr, objReg, memberExpr->Property()->AsIdentifier()->Name()); etsg->StoreAccumulator(expr, calleeReg); - etsg->CallAny(callee->AsMemberExpression()->Object(), expr->Arguments(), calleeReg); + etsg->CallAny(callee->AsMemberExpression()->Object(), Span(expr->Arguments()), + calleeReg); } else { - etsg->CallAnyThis(expr, memberExpr->Property()->AsIdentifier(), expr->Arguments(), objReg); + etsg->CallAnyThis(expr, memberExpr->Property()->AsIdentifier()->Name(), + Span(expr->Arguments()), objReg); } etsg->EmitAnyCheckCast(expr, expr->TsType()); } @@ -1021,19 +1026,6 @@ bool ETSCompiler::HandleStaticProperties(const ir::MemberExpression *expr, ETSGe return false; } -void ETSCompiler::Compile(const ir::ETSIntrinsicNode *expr) const -{ - ETSGen *etsg = GetETSGen(); - // Note (daizihan): #27074, make it more scalable when IntrinsicNodeType is extended. - if (expr->Type() == ir::IntrinsicNodeType::TYPE_REFERENCE) { - // Note (daizihan): #27086, we should not use stringLiteral as argument in ETSIntrinsicNode, should be TypeNode. - etsg->EmitLdaType(expr, expr->Arguments()[0]->AsStringLiteral()->Str()); - etsg->SetAccumulatorType(expr->TsType()); - return; - } - ES2PANDA_UNREACHABLE(); -} - void ETSCompiler::Compile(const ir::ObjectExpression *expr) const { ETSGen *etsg = GetETSGen(); diff --git a/ets2panda/compiler/core/ETSGen.cpp b/ets2panda/compiler/core/ETSGen.cpp index 0b745c71f6e340640bcc5b0ca54712b0cb9c4a29..a1232f67ef649bdbcd820fdc751b53453cd7f6e9 100644 --- a/ets2panda/compiler/core/ETSGen.cpp +++ b/ets2panda/compiler/core/ETSGen.cpp @@ -514,13 +514,6 @@ void ETSGen::CallRangeFillUndefined(const ir::AstNode *const node, checker::Sign Rra().Emit(node, argStart, signature->ArgCount() + 1, signature->InternalName(), argStart); } -void ETSGen::LoadUndefinedDynamic(const ir::AstNode *node, Language lang) -{ - RegScope rs(this); - Ra().Emit(node, Signatures::Dynamic::GetUndefinedBuiltin(lang), dummyReg_, dummyReg_); - SetAccumulatorType(Checker()->GlobalBuiltinDynamicType(lang)); -} - void ETSGen::LoadThis(const ir::AstNode *node) { LoadAccumulator(node, GetThisReg()); diff --git a/ets2panda/compiler/core/ETSGen.h b/ets2panda/compiler/core/ETSGen.h index 4b306cccb2659231a1f06fa6f9dd783fe9a40d51..72d720e5216e98efc35aa57cdd3f60289616e6b5 100644 --- a/ets2panda/compiler/core/ETSGen.h +++ b/ets2panda/compiler/core/ETSGen.h @@ -84,8 +84,6 @@ public: void LoadPropertyByName(const ir::AstNode *node, VReg objReg, checker::ETSChecker::NamedAccessMeta const &fieldMeta); - void LoadUndefinedDynamic(const ir::AstNode *node, Language lang); - void LoadThis(const ir::AstNode *node); [[nodiscard]] VReg GetThisReg() const; @@ -325,7 +323,38 @@ public: #endif // PANDA_WITH_ETS } - void EmitAnyIsInstance(const ir::AstNode *node, VReg objReg) + void EmitAnyLdbyname(const ir::AstNode *const node, const VReg objReg, const util::StringView &prop) + { + Ra().Emit(node, objReg, prop); + } + + void EmitAnyStbyname(const ir::AstNode *const node, const VReg objReg, const util::StringView &prop) + { + Ra().Emit(node, objReg, prop); + } + + void EmitAnyLdbyidx(const ir::AstNode *node, VReg objectReg, VReg propReg) + { + LoadAccumulator(node, propReg); // a simplification for the instruction format handling + Ra().Emit(node, objectReg); + } + + void EmitAnyStbyidx(const ir::AstNode *node, VReg objectReg, VReg propReg) + { + Ra().Emit(node, objectReg, propReg); + } + + void EmitAnyLdbyval(const ir::AstNode *node, VReg objectReg, VReg propReg) + { + Ra().Emit(node, objectReg, propReg); + } + + void EmitAnyStbyval(const ir::AstNode *node, VReg objectReg, VReg propReg) + { + Ra().Emit(node, objectReg, propReg); + } + + void EmitAnyIsinstance(const ir::AstNode *node, VReg objReg) { Sa().Emit(node, objReg); } @@ -433,18 +462,18 @@ public: CallDynamicImpl(data, param3, signature, arguments); } - void CallAnyNew(const ir::AstNode *const node, const ArenaVector &arguments, const VReg athis) + void CallAnyNew(const ir::AstNode *const node, const Span arguments, const VReg athis) { CallAnyImpl(node, arguments, athis); } - void CallAnyThis(const ir::AstNode *const node, const ir::Identifier *ident, - const ArenaVector &arguments, const VReg athis) + void CallAnyThis(const ir::AstNode *const node, util::StringView prop, + const Span arguments, const VReg athis) { - CallAnyImpl(node, ident, arguments, athis); + CallAnyImpl(node, prop, arguments, athis); } - void CallAny(const ir::AstNode *const node, const ArenaVector &arguments, const VReg athis) + void CallAny(const ir::AstNode *const node, const Span arguments, const VReg athis) { CallAnyImpl(node, arguments, athis); } @@ -792,20 +821,19 @@ private: ApplyConversionAndStoreAccumulator(arguments[idx], arg##idx, paramType##idx) template - void CallAnyImpl(const ir::AstNode *node, const ir::Identifier *ident, - const ArenaVector &arguments, const VReg athis) + void CallAnyImpl(const ir::AstNode *node, util::StringView prop, const Span arguments, + const VReg athis) { - ES2PANDA_ASSERT(ident != nullptr); RegScope rs(this); switch (arguments.size()) { case 0U: { - Ra().Emit(node, ident->Name(), athis); + Ra().Emit(node, prop, athis); break; } case 1U: { COMPILE_ANY_ARG(0); - Ra().Emit(node, ident->Name(), athis, arg0); + Ra().Emit(node, prop, athis, arg0); break; } default: { @@ -814,13 +842,13 @@ private: COMPILE_ANY_ARG(idx); } - Rra().Emit(node, argStart, arguments.size(), ident->Name(), athis, argStart, arguments.size()); + Rra().Emit(node, argStart, arguments.size(), prop, athis, argStart, arguments.size()); } } } template - void CallAnyImpl(const ir::AstNode *node, const ArenaVector &arguments, const VReg athis) + void CallAnyImpl(const ir::AstNode *node, const Span arguments, const VReg athis) { RegScope rs(this); diff --git a/ets2panda/compiler/core/ETSemitter.cpp b/ets2panda/compiler/core/ETSemitter.cpp index 1151febda86663cf246872e802c7f7cee77ad1ef..0372b8d349afb3b36f002339fe9da4a855cb7305 100644 --- a/ets2panda/compiler/core/ETSemitter.cpp +++ b/ets2panda/compiler/core/ETSemitter.cpp @@ -575,13 +575,6 @@ std::vector ETSEmitter::GenAnnotations(const ir::ClassD parent = parent->Parent(); } - auto classIdent = classDef->Ident()->Name().Mutf8(); - bool isConstruct = classIdent == Signatures::JSNEW_CLASS; - if (isConstruct || classIdent == Signatures::JSCALL_CLASS) { - auto *callNames = Context()->GetChecker()->AsETSChecker()->DynamicCallNames(isConstruct); - annotations.push_back(GenAnnotationDynamicCall(*callNames)); - } - if (std::any_of(classDef->Body().begin(), classDef->Body().end(), [](const ir::AstNode *node) { return node->IsOverloadDeclaration(); })) { annotations.push_back(GenAnnotationFunctionOverload(classDef->Body())); @@ -1149,24 +1142,6 @@ pandasm::AnnotationData ETSEmitter::GenAnnotationAsync(ir::ScriptFunction *scrip return ann; } -pandasm::AnnotationData ETSEmitter::GenAnnotationDynamicCall(DynamicCallNamesMap &callNames) -{ - GenAnnotationRecord(Signatures::ETS_ANNOTATION_DYNAMIC_CALL); - pandasm::AnnotationData dynamicCallSig(Signatures::ETS_ANNOTATION_DYNAMIC_CALL); - std::vector allParts {}; - for (auto &[parts, startIdx] : callNames) { - startIdx = allParts.size(); - for (const auto &str : parts) { - allParts.emplace_back(pandasm::ScalarValue::Create(str.Utf8())); - } - } - pandasm::AnnotationElement value( - Signatures::ANNOTATION_KEY_VALUE, - std::make_unique(pandasm::Value::Type::STRING, std::move(allParts))); - dynamicCallSig.AddElement(std::move(value)); - return dynamicCallSig; -} - void ETSEmitter::GenAnnotationRecord(std::string_view recordNameView, bool isRuntime, bool isType) { const std::string recordName(recordNameView); diff --git a/ets2panda/compiler/core/ETSemitter.h b/ets2panda/compiler/core/ETSemitter.h index 084964321b2986866214b96a02f85535201b31db..98b9dc10751143745b4b0c7afaa99f9c0a1e0648 100644 --- a/ets2panda/compiler/core/ETSemitter.h +++ b/ets2panda/compiler/core/ETSemitter.h @@ -83,8 +83,6 @@ public: const ArenaVector &annotationUsages, const std::string &baseName); private: - using DynamicCallNamesMap = ArenaMap, uint32_t>; - void GenExternalRecord(varbinder::RecordTable *recordTable, const parser::Program *extProg); void GenGlobalArrayRecord(const checker::ETSArrayType *arrayType, checker::Signature *signature); std::vector GenAnnotations(const ir::ClassDefinition *classDef); @@ -116,7 +114,6 @@ private: pandasm::AnnotationData GenAnnotationFunctionalReference(const ir::ClassDefinition *classDef); pandasm::AnnotationData GenAnnotationInnerClass(const ir::ClassDefinition *classDef, const ir::AstNode *parent); pandasm::AnnotationData GenAnnotationAsync(ir::ScriptFunction *scriptFunc); - pandasm::AnnotationData GenAnnotationDynamicCall(DynamicCallNamesMap &callNames); ir::MethodDefinition *FindAsyncImpl(ir::ScriptFunction *asyncFunc); void ProcessArrayExpression(std::string &baseName, LiteralArrayVector &result, std::vector &literals, const ir::Expression *elem); diff --git a/ets2panda/compiler/lowering/ets/relaxedAnyLowering.cpp b/ets2panda/compiler/lowering/ets/relaxedAnyLowering.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3f91acb3dff7ef9de19c8b9fcb32061087af5910 --- /dev/null +++ b/ets2panda/compiler/lowering/ets/relaxedAnyLowering.cpp @@ -0,0 +1,149 @@ +/* + * 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 "relaxedAnyLowering.h" +#include "ir/expressions/memberExpression.h" + +namespace ark::es2panda::compiler { + +static bool IsLoweringCandidate(checker::ETSChecker *checker, checker::Type *type) +{ + if (type->IsTypeError()) { // #29049: type errors should not appear here + return false; + } + if (type->IsETSMethodType() || type->IsETSExtensionFuncHelperType()) { + return false; // synthetic types don't represent values + } + if (type->IsGradualType()) { + return false; // should be removed after Gradual type refactoring + } + + return type->IsETSAnyType() || + !checker->Relation()->IsSupertypeOf(checker->GlobalETSUnionUndefinedNullObject(), type); +} + +static ir::Expression *CreateIntrin(public_lib::Context *ctx, std::string_view id, checker::Type *type, + ArenaVector &&args) +{ + auto checker = ctx->GetChecker()->AsETSChecker(); + auto allocator = ctx->Allocator(); + ir::Expression *result = util::NodeAllocator::ForceSetParent(allocator, id, std::move(args)); + if (type != nullptr && !type->IsTypeError() && // #29049: type errors should not appear here + !checker->Relation()->IsIdenticalTo(type, checker->GlobalETSAnyType())) { + result = util::NodeAllocator::ForceSetParent( + allocator, result, allocator->New(type, allocator), false); + } + result->Check(checker); + return result; +} + +template +static ir::Expression *CreateIntrin(public_lib::Context *ctx, std::string_view id, checker::Type *type, Args &&...args) +{ + return CreateIntrin(ctx, id, type, ArenaVector({args...}, ctx->Allocator()->Adapter())); +} + +static ir::StringLiteral *IdentifierToLiteral(public_lib::Context *ctx, ir::Identifier *id) +{ + return ctx->Allocator()->New(id->Name()); +} + +static ir::AstNode *TransformMemberExpression(public_lib::Context *ctx, ir::MemberExpression *node) +{ + auto checker = ctx->GetChecker()->AsETSChecker(); + if (!IsLoweringCandidate(checker, node->Object()->TsType())) { + return node; + } + + if (!node->IsComputed()) { + auto prop = IdentifierToLiteral(ctx, node->Property()->AsIdentifier()); + return CreateIntrin(ctx, "anyldbyname", node->TsType(), node->Object(), prop); + } + return CreateIntrin(ctx, node->Property()->TsType()->IsBuiltinNumeric() ? "anyldbyidx" : "anyldbyval", + node->TsType(), node->Object(), node->Property()); +} + +static ir::AstNode *TransformStorePattern(public_lib::Context *ctx, ir::AssignmentExpression *node) +{ + auto checker = ctx->GetChecker()->AsETSChecker(); + + auto me = node->Left()->AsMemberExpression(); + if (!IsLoweringCandidate(checker, me->Object()->TsType())) { + return node; + } + + if (!me->IsComputed()) { + auto prop = IdentifierToLiteral(ctx, me->Property()->AsIdentifier()); + return CreateIntrin(ctx, "anystbyname", node->TsType(), me->Object(), prop, node->Right()); + } + return CreateIntrin(ctx, me->Property()->TsType()->IsBuiltinNumeric() ? "anystbyidx" : "anystbyval", node->TsType(), + me->Object(), me->Property(), node->Right()); +} + +static ir::AstNode *TransformCallExpression(public_lib::Context *ctx, ir::CallExpression *node) +{ + auto checker = ctx->GetChecker()->AsETSChecker(); + + auto const callee = node->Callee(); + if (!IsLoweringCandidate(checker, callee->TsType())) { + return node; + } + + auto args = ArenaVector({}, ctx->Allocator()->Adapter()); + args.reserve(node->Arguments().size() + 2U); + + if (callee->IsMemberExpression()) { + auto prop = callee->AsMemberExpression()->Property(); + prop = callee->AsMemberExpression()->IsComputed() ? prop : IdentifierToLiteral(ctx, prop->AsIdentifier()); + args.insert(args.end(), {callee->AsMemberExpression()->Object(), prop}); + args.insert(args.end(), node->Arguments().begin(), node->Arguments().end()); + return CreateIntrin(ctx, "anycallthis", node->TsType(), std::move(args)); + } + + args.insert(args.begin(), callee); + args.insert(args.end(), node->Arguments().begin(), node->Arguments().end()); + return CreateIntrin(ctx, "anycall", node->TsType(), std::move(args)); +} + +static ir::AstNode *LowerOperationIfNeeded(public_lib::Context *ctx, ir::AstNode *node) +{ + auto const setParent = [node](ir::AstNode *res) { + if (res != node) { + res->SetParent(node->Parent()); + } + return res; + }; + + if (node->IsCallExpression()) { + return setParent(TransformCallExpression(ctx, node->AsCallExpression())); + } + if (node->IsAssignmentExpression() && node->AsAssignmentExpression()->Left()->IsMemberExpression()) { + return setParent(TransformStorePattern(ctx, node->AsAssignmentExpression())); + } + if (node->IsMemberExpression()) { + return setParent(TransformMemberExpression(ctx, node->AsMemberExpression())); + } + return node; +} + +bool RelaxedAnyLoweringPhase::PerformForModule(public_lib::Context *ctx, parser::Program *program) +{ + program->Ast()->TransformChildrenRecursivelyPreorder( + [ctx](ir::AstNode *node) { return LowerOperationIfNeeded(ctx, node); }, Name()); + + return true; +} + +} // namespace ark::es2panda::compiler diff --git a/ets2panda/compiler/lowering/ets/relaxedAnyLowering.h b/ets2panda/compiler/lowering/ets/relaxedAnyLowering.h new file mode 100644 index 0000000000000000000000000000000000000000..b0b7ef66198d8eaf161d9dcd9f044c81ec529e5c --- /dev/null +++ b/ets2panda/compiler/lowering/ets/relaxedAnyLowering.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_RELAXED_ANY_LOWERING_H +#define ES2PANDA_COMPILER_RELAXED_ANY_LOWERING_H + +#include "compiler/lowering/phase.h" + +namespace ark::es2panda::compiler { + +class RelaxedAnyLoweringPhase : public PhaseForBodies { +public: + std::string_view Name() const override + { + return "RelaxedAnyLowering"; + } + + bool PerformForModule(public_lib::Context *ctx, parser::Program *program) override; +}; + +} // namespace ark::es2panda::compiler + +#endif // ES2PANDA_COMPILER_RELAXED_ANY_LOWERING_H diff --git a/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp b/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp index d8c68fb76d773b4e536779daa39b3b284e468c5f..c29879557100a542832c25dc23e219f79b7b3346 100644 --- a/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp +++ b/ets2panda/compiler/lowering/ets/topLevelStmts/globalClassHandler.cpp @@ -589,8 +589,7 @@ void GlobalClassHandler::FormDependentInitTriggers(ArenaVector auto moduleName = NodeAllocator::Alloc(allocator_, moduleStr.View()); params.emplace_back(moduleName); // Note (daizihan): #27086, we should not use stringLiteral as argument in ETSIntrinsicNode, should be TypeNode. - auto moduleNode = NodeAllocator::Alloc(allocator_, ir::IntrinsicNodeType::TYPE_REFERENCE, - std::move(params)); + auto moduleNode = NodeAllocator::Alloc(allocator_, "typereference", std::move(params)); auto initIdent = NodeAllocator::Alloc(allocator_, compiler::Signatures::CLASS_INITIALIZE_METHOD, allocator_); auto *callee = NodeAllocator::Alloc( diff --git a/ets2panda/compiler/lowering/ets/unboxLowering.cpp b/ets2panda/compiler/lowering/ets/unboxLowering.cpp index 3d97acae289e59b3908657466042bc35b32c07b1..f97cab8884efddc8f89ebc1e8175935f70f7bf7d 100644 --- a/ets2panda/compiler/lowering/ets/unboxLowering.cpp +++ b/ets2panda/compiler/lowering/ets/unboxLowering.cpp @@ -925,6 +925,21 @@ struct UnboxVisitor : public ir::visitor::EmptyAstVisitor { call->SetTsType(call->GetTypeRef()->TsType()); } + void VisitETSIntrinsicNode(ir::ETSIntrinsicNode *intrin) override + { + for (size_t i = 0; i < intrin->Arguments().size(); i++) { + auto arg = intrin->Arguments()[i]; + + auto expectedType = intrin->ExpectedTypeAt(uctx_->checker, i); + expectedType = expectedType == nullptr ? uctx_->checker->GlobalETSAnyType() : expectedType; + if (expectedType->IsETSPrimitiveType()) { + intrin->Arguments()[i] = AdjustType(uctx_, arg, expectedType); + } else { + intrin->Arguments()[i] = AdjustType(uctx_, arg, expectedType); + } + } + } + void VisitSpreadElement(ir::SpreadElement *spread) override { spread->SetTsType(spread->Argument()->TsType()); diff --git a/ets2panda/compiler/lowering/phase.cpp b/ets2panda/compiler/lowering/phase.cpp index 47a89ade9ea2b820e11e190bceda1dd19e01aed6..51d059d9564a73d062bc036d3e175779f9d8952b 100644 --- a/ets2panda/compiler/lowering/phase.cpp +++ b/ets2panda/compiler/lowering/phase.cpp @@ -59,6 +59,7 @@ #include "compiler/lowering/ets/primitiveConversionPhase.h" #include "compiler/lowering/ets/promiseVoid.h" #include "compiler/lowering/ets/recordLowering.h" +#include "compiler/lowering/ets/relaxedAnyLowering.h" #include "compiler/lowering/ets/resizableArrayLowering.h" #include "compiler/lowering/ets/lateInitialization.h" #include "compiler/lowering/ets/restArgsLowering.h" @@ -132,6 +133,7 @@ std::vector GetETSPhaseList() new PluginPhase {g_pluginsAfterCheck, ES2PANDA_STATE_CHECKED, &util::Plugin::AfterCheck}, // new ConvertPrimitiveCastMethodCall, new DynamicImport, + new RelaxedAnyLoweringPhase, new AnnotationCopyPostLowering, new AsyncMethodLowering, new DeclareOverloadLowering, diff --git a/ets2panda/compiler/lowering/util.cpp b/ets2panda/compiler/lowering/util.cpp index 84e9ccb559117e1aae09adbe17912d061a0cd87c..7e229e83187846a2cd77f164b5b9efdbb82d684a 100644 --- a/ets2panda/compiler/lowering/util.cpp +++ b/ets2panda/compiler/lowering/util.cpp @@ -165,16 +165,6 @@ static bool IsGeneratedForUtilityType(ir::AstNode const *ast) return false; } -static bool IsGeneratedDynamicClass(ir::AstNode const *ast) -{ - if (ast->IsClassDeclaration()) { - auto &name = ast->AsClassDeclaration()->Definition()->Ident()->Name(); - return name.Is(Signatures::JSNEW_CLASS) || name.Is(Signatures::JSCALL_CLASS); - } - - return false; -} - static void ClearHelper(parser::Program *prog) { ResetGlobalClass(prog); @@ -184,7 +174,7 @@ static void ClearHelper(parser::Program *prog) stmts.erase(std::remove_if(stmts.begin(), stmts.end(), [](ir::AstNode *ast) -> bool { return !ast->HasAstNodeFlags(ir::AstNodeFlags::NOCLEANUP) || - IsGeneratedForUtilityType(ast) || IsGeneratedDynamicClass(ast); + IsGeneratedForUtilityType(ast); }), stmts.end()); // clang-format on diff --git a/ets2panda/declgen_ets2ts/declgenEts2Ts.cpp b/ets2panda/declgen_ets2ts/declgenEts2Ts.cpp index e685df218f6891aecc7572668937e0e09e754313..d3fe024a5e2d5eb5db9c697d06c024d2d52ed970 100644 --- a/ets2panda/declgen_ets2ts/declgenEts2Ts.cpp +++ b/ets2panda/declgen_ets2ts/declgenEts2Ts.cpp @@ -1959,8 +1959,7 @@ void TSDeclGen::PrepareClassDeclaration(const ir::ClassDefinition *classDef) bool TSDeclGen::ShouldSkipClassDeclaration(const std::string_view &className) const { - return className == compiler::Signatures::DYNAMIC_MODULE_CLASS || className == compiler::Signatures::JSNEW_CLASS || - className == compiler::Signatures::JSCALL_CLASS || (className.find("$partial") != std::string::npos); + return className.find("$partial") != std::string::npos; } void TSDeclGen::EmitDeclarationPrefix(const ir::ClassDefinition *classDef, const std::string &typeName, diff --git a/ets2panda/ir/ets/etsIntrinsicNode.cpp b/ets2panda/ir/ets/etsIntrinsicNode.cpp index 6e542459c289d5041931c72b88d28857ff9e8a7c..9024106ab3d9fe693127fbfa675a62341b23a60b 100644 --- a/ets2panda/ir/ets/etsIntrinsicNode.cpp +++ b/ets2panda/ir/ets/etsIntrinsicNode.cpp @@ -20,57 +20,151 @@ namespace ark::es2panda::ir { -ETSIntrinsicNode::ETSIntrinsicNode(ETSIntrinsicNode const &other, ArenaAllocator *const allocator) - : Expression(static_cast(other)), arguments_(allocator->Adapter()) +void ETSIntrinsicNode::Iterate(const NodeTraverser &cb) const { - type_ = other.type_; - for (auto *const arg : other.arguments_) { - arguments_.emplace_back(arg->Clone(allocator, this)->AsExpression()); + for (auto *arg : arguments_) { + cb(arg); } } -void ETSIntrinsicNode::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName) +void ETSIntrinsicNode::Dump(ir::AstDumper *dumper) const { - for (auto *&args : arguments_) { - if (auto *transformedNode = cb(args); args != transformedNode) { - args->SetTransformedNode(transformationName, transformedNode); - args = static_cast(transformedNode); + dumper->Add({{"type", "ETSIntrinsicNode"}, {"arguments", arguments_}}); +} + +void ETSIntrinsicNode::Dump([[maybe_unused]] ir::SrcDumper *dumper) const +{ + dumper->Add("%%intrin%%"); + dumper->Add(Id().Mutf8()); + dumper->Add("("); + for (auto arg : arguments_) { + arg->Dump(dumper); + if (arg != arguments_.back()) { + dumper->Add(", "); } } + dumper->Add(")"); } -void ETSIntrinsicNode::Iterate(const NodeTraverser &cb) const +EtsIntrinsicInfo const *GetIntrinsicInfoFor(ETSIntrinsicNode const *node) { - for (auto *arg : arguments_) { - cb(arg); + return node->info_; +} + +class EtsIntrinsicInfo { +public: + static EtsIntrinsicInfo const *For(util::StringView id) + { + if (auto it = infos_.find(id); it != infos_.end()) { + return it->second.get(); + } + return nullptr; + } + + static EtsIntrinsicInfo const *For(ETSIntrinsicNode const *intrin) + { + return GetIntrinsicInfoFor(intrin); + } + + virtual util::StringView Name() const = 0; + + virtual checker::Type *Check(checker::ETSChecker *checker, ETSIntrinsicNode *intrin) const = 0; + + virtual checker::Type *ExpectedTypeAt([[maybe_unused]] checker::ETSChecker *checker, + [[maybe_unused]] size_t idx) const + { + return nullptr; + } + + void Compile(compiler::ETSGen *etsg, ETSIntrinsicNode const *intrin) const + { + CompileImpl(etsg, intrin); + etsg->SetAccumulatorType(intrin->TsType()); + } + + EtsIntrinsicInfo() = default; + virtual ~EtsIntrinsicInfo() = default; + +protected: + virtual void CompileImpl(compiler::ETSGen *etsg, ETSIntrinsicNode const *intrin) const = 0; + + bool CheckParams(checker::ETSChecker *checker, ETSIntrinsicNode *intrin) const + { + bool hasError = false; + for (size_t idx = 0; idx < intrin->Arguments().size(); ++idx) { + auto &arg = intrin->Arguments()[idx]; + arg->SetPreferredType(ExpectedTypeAt(checker, idx)); + hasError |= arg->Check(checker)->IsTypeError(); + } + return !hasError; + } + + checker::Type *InvalidateIntrinsic(checker::ETSChecker *checker, ETSIntrinsicNode *intrin) const + { + checker->LogError(diagnostic::INVALID_INTRINSIC, {}, intrin->Start()); + return intrin->SetTsType(checker->GlobalTypeError()); + } + + template + std::array const &Args(ETSIntrinsicNode const *intrin) const + { + ES2PANDA_ASSERT(intrin->Arguments().size() >= ARGS); + return *reinterpret_cast const *>(intrin->Arguments().data()); + } + +private: + using InfosMap = std::unordered_map>; + + static InfosMap InitIntrinsicInfos(); + static const InfosMap infos_; +}; + +void ETSIntrinsicNode::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} + +void ETSIntrinsicNode::Compile(compiler::ETSGen *etsg) const +{ + if (auto info = GetIntrinsicInfoFor(this); LIKELY(info != nullptr)) { + return info->Compile(etsg, this); } + ES2PANDA_UNREACHABLE(); } -void ETSIntrinsicNode::Dump(ir::AstDumper *dumper) const +ETSIntrinsicNode::ETSIntrinsicNode(ETSIntrinsicNode const &other, ArenaAllocator *const allocator) + : Expression(static_cast(other)), info_(other.info_), arguments_(allocator->Adapter()) { - dumper->Add({{"type", "ETSIntrinsicNode"}, {"arguments", arguments_}}); + for (auto *const arg : other.arguments_) { + arguments_.emplace_back(arg->Clone(allocator, this)->AsExpression()); + } } -void ETSIntrinsicNode::Dump([[maybe_unused]] ir::SrcDumper *dumper) const +ETSIntrinsicNode::ETSIntrinsicNode(util::StringView id, ArenaVector &&arguments) + : Expression(AstNodeType::ETS_INTRINSIC_NODE_TYPE), + info_(EtsIntrinsicInfo::For(id)), + arguments_(std::move(arguments)) +{ +} + +void ETSIntrinsicNode::TransformChildren(const NodeTransformer &cb, std::string_view const transformationName) { - // Note (daizihan): #27074, make it more scalable when IntrinsicNodeType is extended. - if (type_ == IntrinsicNodeType::TYPE_REFERENCE) { - dumper->Add("__intrin_type_reference("); - for (auto arg : arguments_) { - arg->Dump(dumper); - if (arg != arguments_.back()) { - dumper->Add(", "); - } + for (auto *&args : arguments_) { + if (auto *transformedNode = cb(args); args != transformedNode) { + args->SetTransformedNode(transformationName, transformedNode); + args = static_cast(transformedNode); } - dumper->Add(")"); } } -void ETSIntrinsicNode::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +util::StringView ETSIntrinsicNode::Id() const +{ + return info_ == nullptr ? "invalid" : info_->Name(); +} -void ETSIntrinsicNode::Compile(compiler::ETSGen *etsg) const +checker::Type *ETSIntrinsicNode::ExpectedTypeAt(checker::ETSChecker *checker, size_t idx) const { - etsg->GetAstCompiler()->Compile(this); + if (auto info = GetIntrinsicInfoFor(this); LIKELY(info != nullptr)) { + return info->ExpectedTypeAt(checker, idx); + } + return nullptr; } checker::Type *ETSIntrinsicNode::Check([[maybe_unused]] checker::TSChecker *checker) @@ -80,17 +174,385 @@ checker::Type *ETSIntrinsicNode::Check([[maybe_unused]] checker::TSChecker *chec checker::VerifiedType ETSIntrinsicNode::Check([[maybe_unused]] checker::ETSChecker *checker) { - return {this, checker->GetAnalyzer()->Check(this)}; + if (auto info = GetIntrinsicInfoFor(this); LIKELY(info != nullptr)) { + return {this, info->Check(checker, this)}; + } + checker->LogError(diagnostic::INVALID_INTRINSIC, {}, Start()); + return {this, SetTsType(checker->GlobalTypeError())}; } ETSIntrinsicNode *ETSIntrinsicNode::Clone(ArenaAllocator *const allocator, AstNode *const parent) { - ETSIntrinsicNode *clone = allocator->New(allocator); - clone->type_ = type_; + ETSIntrinsicNode *clone = allocator->New(*this, allocator); if (parent != nullptr) { clone->SetParent(parent); } clone->SetRange(Range()); return clone; } -} // namespace ark::es2panda::ir \ No newline at end of file + +class ETSIntrinsicTypeReference final : public EtsIntrinsicInfo { +public: + util::StringView Name() const override + { + return "typereference"; + } + + checker::Type *Check(checker::ETSChecker *checker, ETSIntrinsicNode *intrin) const override + { + CheckParams(checker, intrin); + if (intrin->Arguments().size() != 1 || !intrin->Arguments()[0]->IsStringLiteral()) { + return InvalidateIntrinsic(checker, intrin); + } + return intrin->SetTsType(checker->GlobalBuiltinClassType()); + } + + void CompileImpl(compiler::ETSGen *etsg, ETSIntrinsicNode const *intrin) const override + { + etsg->EmitLdaType(intrin, intrin->Arguments()[0]->AsStringLiteral()->Str()); + } +}; + +class ETSIntrinsicAnyLdByVal final : public EtsIntrinsicInfo { +public: + util::StringView Name() const override + { + return "anyldbyval"; + } + + checker::Type *Check(checker::ETSChecker *checker, ETSIntrinsicNode *intrin) const override + { + CheckParams(checker, intrin); + if (intrin->Arguments().size() != 2U) { + return InvalidateIntrinsic(checker, intrin); + } + return intrin->SetTsType(checker->GlobalETSAnyType()); + } + + void CompileImpl(compiler::ETSGen *etsg, ETSIntrinsicNode const *intrin) const override + { + auto const [obj, prop] = Args<2U>(intrin); + + compiler::RegScope rs(etsg); + auto const objReg = etsg->AllocReg(); + auto const propReg = etsg->AllocReg(); + + obj->Compile(etsg); + etsg->StoreAccumulator(intrin, objReg); + + prop->Compile(etsg); + etsg->StoreAccumulator(intrin, propReg); + + etsg->EmitAnyLdbyval(intrin, objReg, propReg); + } +}; + +class ETSIntrinsicAnyStByVal final : public EtsIntrinsicInfo { +public: + util::StringView Name() const override + { + return "anystbyval"; + } + + checker::Type *Check(checker::ETSChecker *checker, ETSIntrinsicNode *intrin) const override + { + CheckParams(checker, intrin); + if (intrin->Arguments().size() != 3U) { + return InvalidateIntrinsic(checker, intrin); + } + return intrin->SetTsType(intrin->Arguments()[2U]->TsType()); + } + + void CompileImpl(compiler::ETSGen *etsg, ETSIntrinsicNode const *intrin) const override + { + auto const [obj, prop, propVal] = Args<3U>(intrin); + + compiler::RegScope rs(etsg); + auto const objReg = etsg->AllocReg(); + auto const propReg = etsg->AllocReg(); + + obj->Compile(etsg); + etsg->StoreAccumulator(intrin, objReg); + + prop->Compile(etsg); + etsg->StoreAccumulator(intrin, propReg); + + propVal->Compile(etsg); + + etsg->EmitAnyStbyval(intrin, objReg, propReg); + } +}; + +class ETSIntrinsicAnyLdByIdx final : public EtsIntrinsicInfo { +public: + util::StringView Name() const override + { + return "anyldbyidx"; + } + + virtual checker::Type *ExpectedTypeAt(checker::ETSChecker *checker, [[maybe_unused]] size_t idx) const override + { + if (idx == 1U) { + return checker->GlobalDoubleType(); + } + return nullptr; + } + + checker::Type *Check(checker::ETSChecker *checker, ETSIntrinsicNode *intrin) const override + { + CheckParams(checker, intrin); + if (intrin->Arguments().size() != 2U) { + return InvalidateIntrinsic(checker, intrin); + } + return intrin->SetTsType(checker->GlobalETSAnyType()); + } + + void CompileImpl(compiler::ETSGen *etsg, ETSIntrinsicNode const *intrin) const override + { + auto const [obj, prop] = Args<2U>(intrin); + + compiler::RegScope rs(etsg); + auto const objReg = etsg->AllocReg(); + auto const propReg = etsg->AllocReg(); + + obj->Compile(etsg); + etsg->StoreAccumulator(intrin, objReg); + + prop->Compile(etsg); + etsg->StoreAccumulator(intrin, propReg); + + etsg->EmitAnyLdbyidx(intrin, objReg, propReg); + } +}; + +class ETSIntrinsicAnyStByIdx final : public EtsIntrinsicInfo { +public: + util::StringView Name() const override + { + return "anystbyidx"; + } + + virtual checker::Type *ExpectedTypeAt(checker::ETSChecker *checker, [[maybe_unused]] size_t idx) const override + { + if (idx == 1U) { + return checker->GlobalDoubleType(); + } + return nullptr; + } + + checker::Type *Check(checker::ETSChecker *checker, ETSIntrinsicNode *intrin) const override + { + CheckParams(checker, intrin); + if (intrin->Arguments().size() != 3U) { + return InvalidateIntrinsic(checker, intrin); + } + return intrin->SetTsType(intrin->Arguments()[2U]->TsType()); + } + + void CompileImpl(compiler::ETSGen *etsg, ETSIntrinsicNode const *intrin) const override + { + auto const [obj, prop, propVal] = Args<3U>(intrin); + + compiler::RegScope rs(etsg); + auto const objReg = etsg->AllocReg(); + auto const propReg = etsg->AllocReg(); + + obj->Compile(etsg); + etsg->StoreAccumulator(intrin, objReg); + + prop->Compile(etsg); + etsg->StoreAccumulator(intrin, propReg); + + propVal->Compile(etsg); + + etsg->EmitAnyStbyidx(intrin, objReg, propReg); + } +}; + +class ETSIntrinsicAnyLdByName final : public EtsIntrinsicInfo { +public: + util::StringView Name() const override + { + return "anyldbyname"; + } + + checker::Type *Check(checker::ETSChecker *checker, ETSIntrinsicNode *intrin) const override + { + CheckParams(checker, intrin); + if (intrin->Arguments().size() != 2U) { + return InvalidateIntrinsic(checker, intrin); + } + if (!intrin->Arguments()[1]->IsStringLiteral()) { + return InvalidateIntrinsic(checker, intrin); + } + return intrin->SetTsType(checker->GlobalETSAnyType()); + } + + void CompileImpl(compiler::ETSGen *etsg, ETSIntrinsicNode const *intrin) const override + { + auto const [obj, prop] = Args<2U>(intrin); + + compiler::RegScope rs(etsg); + auto const objReg = etsg->AllocReg(); + + obj->Compile(etsg); + etsg->StoreAccumulator(intrin, objReg); + etsg->EmitAnyLdbyname(intrin, objReg, prop->AsStringLiteral()->Str()); + } +}; + +class ETSIntrinsicAnyStByName final : public EtsIntrinsicInfo { +public: + util::StringView Name() const override + { + return "anystbyname"; + } + + checker::Type *Check(checker::ETSChecker *checker, ETSIntrinsicNode *intrin) const override + { + CheckParams(checker, intrin); + if (intrin->Arguments().size() != 3U) { + return InvalidateIntrinsic(checker, intrin); + } + if (!intrin->Arguments()[1]->IsStringLiteral()) { + return InvalidateIntrinsic(checker, intrin); + } + return intrin->SetTsType(intrin->Arguments()[2U]->TsType()); + } + + void CompileImpl(compiler::ETSGen *etsg, ETSIntrinsicNode const *intrin) const override + { + auto const [obj, prop, propVal] = Args<3U>(intrin); + + compiler::RegScope rs(etsg); + auto const objReg = etsg->AllocReg(); + + obj->Compile(etsg); + etsg->StoreAccumulator(intrin, objReg); + + propVal->Compile(etsg); + + etsg->EmitAnyStbyname(intrin, objReg, prop->AsStringLiteral()->Str()); + } +}; + +class ETSIntrinsicAnyCall final : public EtsIntrinsicInfo { +public: + util::StringView Name() const override + { + return "anycall"; + } + + checker::Type *Check(checker::ETSChecker *checker, ETSIntrinsicNode *intrin) const override + { + CheckParams(checker, intrin); + if (intrin->Arguments().size() < 1U) { + return InvalidateIntrinsic(checker, intrin); + } + return intrin->SetTsType(checker->GlobalETSAnyType()); + } + + void CompileImpl(compiler::ETSGen *etsg, ETSIntrinsicNode const *intrin) const override + { + auto const [callee] = Args<1U>(intrin); + auto args = + Span {intrin->Arguments().data(), intrin->Arguments().size()}.SubSpan(1); + + compiler::RegScope rs(etsg); + auto const calleeReg = etsg->AllocReg(); + + callee->Compile(etsg); + etsg->StoreAccumulator(intrin, calleeReg); + + etsg->CallAny(intrin, args, calleeReg); + } +}; + +class ETSIntrinsicAnyCallThis final : public EtsIntrinsicInfo { +public: + util::StringView Name() const override + { + return "anycallthis"; + } + + checker::Type *Check(checker::ETSChecker *checker, ETSIntrinsicNode *intrin) const override + { + CheckParams(checker, intrin); + if (intrin->Arguments().size() < 2U || !intrin->Arguments()[1]->IsStringLiteral()) { + return InvalidateIntrinsic(checker, intrin); + } + return intrin->SetTsType(checker->GlobalETSAnyType()); + } + + void CompileImpl(compiler::ETSGen *etsg, ETSIntrinsicNode const *intrin) const override + { + auto const [callee, prop] = Args<2U>(intrin); + auto args = + Span {intrin->Arguments().data(), intrin->Arguments().size()}.SubSpan(2); + + compiler::RegScope rs(etsg); + auto const calleeReg = etsg->AllocReg(); + + callee->Compile(etsg); + etsg->StoreAccumulator(intrin, calleeReg); + + etsg->CallAnyThis(intrin, prop->AsStringLiteral()->Str(), args, calleeReg); + } +}; + +class ETSIntrinsicAnyIsinstance final : public EtsIntrinsicInfo { +public: + util::StringView Name() const override + { + return "anyisinstance"; + } + + checker::Type *Check(checker::ETSChecker *checker, ETSIntrinsicNode *intrin) const override + { + CheckParams(checker, intrin); + if (intrin->Arguments().size() != 2U) { + return InvalidateIntrinsic(checker, intrin); + } + return intrin->SetTsType(checker->GlobalETSBooleanType()); + } + + void CompileImpl(compiler::ETSGen *etsg, ETSIntrinsicNode const *intrin) const override + { + auto const [obj, type] = Args<2U>(intrin); + + compiler::RegScope rs(etsg); + auto const objReg = etsg->AllocReg(); + + obj->Compile(etsg); + etsg->StoreAccumulator(intrin, objReg); + + type->Compile(etsg); + etsg->EmitAnyIsinstance(intrin, objReg); + } +}; + +const EtsIntrinsicInfo::InfosMap EtsIntrinsicInfo::infos_ = EtsIntrinsicInfo::InitIntrinsicInfos(); + +EtsIntrinsicInfo::InfosMap EtsIntrinsicInfo::InitIntrinsicInfos() +{ + EtsIntrinsicInfo::InfosMap infos; + auto const registerIntrin = [&infos](std::unique_ptr &&data) { + auto name = data->Name(); + [[maybe_unused]] auto res = infos.emplace(name, std::move(data)); + ES2PANDA_ASSERT(res.second); + }; + + registerIntrin(std::make_unique()); + registerIntrin(std::make_unique()); + registerIntrin(std::make_unique()); + registerIntrin(std::make_unique()); + registerIntrin(std::make_unique()); + registerIntrin(std::make_unique()); + registerIntrin(std::make_unique()); + registerIntrin(std::make_unique()); + registerIntrin(std::make_unique()); + registerIntrin(std::make_unique()); + return infos; +} + +} // namespace ark::es2panda::ir diff --git a/ets2panda/ir/ets/etsIntrinsicNode.h b/ets2panda/ir/ets/etsIntrinsicNode.h index d13a914c2fbe7bf6d0ad0eb32654209ce27846dc..946b9e6b7317507d21c2f9ec9cbe19fd8dea4437 100644 --- a/ets2panda/ir/ets/etsIntrinsicNode.h +++ b/ets2panda/ir/ets/etsIntrinsicNode.h @@ -22,7 +22,8 @@ namespace ark::es2panda::ir { -enum class IntrinsicNodeType : uint8_t { NONE = 0, TYPE_REFERENCE = 1 }; +class EtsIntrinsicInfo; +extern EtsIntrinsicInfo const *GetIntrinsicInfoFor(ETSIntrinsicNode const *node); class ETSIntrinsicNode : public Expression { public: @@ -32,26 +33,18 @@ public: NO_COPY_SEMANTIC(ETSIntrinsicNode); NO_MOVE_SEMANTIC(ETSIntrinsicNode); - explicit ETSIntrinsicNode(ArenaAllocator *const allocator) - : Expression(AstNodeType::ETS_INTRINSIC_NODE_TYPE), - type_(IntrinsicNodeType::NONE), - arguments_(allocator->Adapter()) - { - } - explicit ETSIntrinsicNode(ETSIntrinsicNode const &other, ArenaAllocator *const allocator); + explicit ETSIntrinsicNode(util::StringView id, ArenaVector &&arguments); - explicit ETSIntrinsicNode(IntrinsicNodeType type, ArenaVector &&arguments) - : Expression(AstNodeType::ETS_INTRINSIC_NODE_TYPE), type_(type), arguments_(std::move(arguments)) - { - } + util::StringView Id() const; + checker::Type *ExpectedTypeAt(checker::ETSChecker *checker, size_t idx) const; - IntrinsicNodeType Type() const + ArenaVector const &Arguments() const { - return type_; + return arguments_; } - ArenaVector Arguments() const + ArenaVector &Arguments() { return arguments_; } @@ -73,7 +66,9 @@ public: [[nodiscard]] ETSIntrinsicNode *Clone(ArenaAllocator *allocator, AstNode *parent) override; private: - IntrinsicNodeType type_; + friend EtsIntrinsicInfo const *GetIntrinsicInfoFor(ETSIntrinsicNode const *node); + + EtsIntrinsicInfo const *info_; ArenaVector arguments_; }; } // namespace ark::es2panda::ir diff --git a/ets2panda/ir/ets/etsTypeReferencePart.cpp b/ets2panda/ir/ets/etsTypeReferencePart.cpp index 2491ba33fda5854c1505dce6e970fb93a687accb..fc87aa8c0de9100218f782a092fa031ee16f582d 100644 --- a/ets2panda/ir/ets/etsTypeReferencePart.cpp +++ b/ets2panda/ir/ets/etsTypeReferencePart.cpp @@ -150,6 +150,9 @@ static checker::Type *CheckPredefinedBuiltinTypes(checker::ETSChecker *const che if (ident->Name() == compiler::Signatures::ANY_TYPE_NAME) { return checker->GlobalETSAnyType(); } + if (ident->Name() == compiler::Signatures::ANY) { + return checker->GetGlobalTypesHolder()->GlobalETSRelaxedAnyType(); + } if (ident->Name() == compiler::Signatures::UNDEFINED) { return checker->GlobalETSUndefinedType(); } diff --git a/ets2panda/ir/expressions/memberExpression.cpp b/ets2panda/ir/expressions/memberExpression.cpp index 0137fb8c31ad11e8050c74926352c52cccd298eb..fc3f03a2a88c716ec5eb3b8f334adcbbb35b12a8 100644 --- a/ets2panda/ir/expressions/memberExpression.cpp +++ b/ets2panda/ir/expressions/memberExpression.cpp @@ -503,12 +503,18 @@ checker::Type *MemberExpression::HandleComputedInGradualType(checker::ETSChecker checker::Type *MemberExpression::CheckComputed(checker::ETSChecker *checker, checker::Type *baseType) { + if (baseType->IsETSRelaxedAnyType()) { + Property()->Check(checker); + return checker->GlobalETSRelaxedAnyType(); + } + if (baseType->IsETSObjectType() && baseType->AsETSObjectType()->GetDeclNode() != nullptr && baseType->AsETSObjectType()->GetDeclNode()->AsTyped()->TsType() != nullptr && baseType->AsETSObjectType()->GetDeclNode()->AsTyped()->TsType()->IsGradualType()) { SetObjectType(baseType->AsETSObjectType()); return HandleComputedInGradualType(checker, baseType); } + if (baseType->IsETSArrayType()) { auto *dflt = baseType->AsETSArrayType()->ElementType(); if (!checker->ValidateArrayIndex(property_)) { diff --git a/ets2panda/lexer/scripts/keywords.yaml b/ets2panda/lexer/scripts/keywords.yaml index 08ae6869c9a8bf14d83b52ab027894a69cad3149..5e53a6b6ef51d5511d0d4eb3d47ce1f87028ee18 100644 --- a/ets2panda/lexer/scripts/keywords.yaml +++ b/ets2panda/lexer/scripts/keywords.yaml @@ -29,8 +29,8 @@ keywords: - name: 'any' token: KEYW_ANY - keyword_like: [ts] - flags: [reserved_type_name] + keyword_like: [ts, ets] + flags: [reserved_type_name, definable_type_name] - name: 'Any' token: KEYW_BUILTIN_ANY diff --git a/ets2panda/parser/ETSparser.cpp b/ets2panda/parser/ETSparser.cpp index 1c9fe98ea1e18eee9a8f0f6e877e2625057ed7f8..48d445eb8e1756e948de31d528e54a17ace71b45 100644 --- a/ets2panda/parser/ETSparser.cpp +++ b/ets2panda/parser/ETSparser.cpp @@ -1449,6 +1449,7 @@ bool TypedParser::IsPrimitiveType(const lexer::TokenType &tokenType) case lexer::TokenType::KEYW_LONG: case lexer::TokenType::KEYW_SHORT: case lexer::TokenType::KEYW_VOID: + case lexer::TokenType::KEYW_ANY: return true; default: return false; diff --git a/ets2panda/test/ast/compiler/ets/utility_type_can_not_found_etsobjecttype.ets b/ets2panda/test/ast/compiler/ets/utility_type_can_not_found_etsobjecttype.ets index dacc830f5d11bc033b978db592a19c6cc8dd35c9..d92b4f5bde2f8ccf9086d89fd25a971b111e6f17 100644 --- a/ets2panda/test/ast/compiler/ets/utility_type_can_not_found_etsobjecttype.ets +++ b/ets2panda/test/ast/compiler/ets/utility_type_can_not_found_etsobjecttype.ets @@ -13,7 +13,7 @@ * limitations under the License. */ -type BaseObject = Record; +type BaseObject = Record; class X { x: T; @@ -25,6 +25,6 @@ class X { } } -/* @@? 16:34 Error TypeError: Cannot find type 'any'. */ +/* @@? 16:34 Error TypeError: Cannot find type 'xny'. */ /* @@? 21:29 Error TypeError: T in Partial must be a class or an interface type. */ /* @@? 23:14 Error TypeError: Target type for class composite needs to be an object type, found 'T' */ diff --git a/ets2panda/test/ast/parser/ets/constructor_type_inference_crash.ets b/ets2panda/test/ast/parser/ets/constructor_type_inference_crash.ets index d31d7c3e7a9b63085039b91a46b9988c1aaa4024..6b09631bfbdf4398522d75642ca940451999740a 100644 --- a/ets2panda/test/ast/parser/ets/constructor_type_inference_crash.ets +++ b/ets2panda/test/ast/parser/ets/constructor_type_inference_crash.ets @@ -16,12 +16,12 @@ class C { constructor(x: number, y: string); constructor(s: string); - constructor(xs: any, y?: any) {} + constructor(xs: xny, y?: xny) {} } let c = new C(10, 'foo'); /* @@? 17:14 Error TypeError: Only abstract or native methods can't have body. */ /* @@? 19:3 Error TypeError: No matching call signature for constructor */ -/* @@? 19:19 Error TypeError: Cannot find type 'any'. */ -/* @@? 19:28 Error TypeError: Cannot find type 'any'. */ +/* @@? 19:19 Error TypeError: Cannot find type 'xny'. */ +/* @@? 19:28 Error TypeError: Cannot find type 'xny'. */ diff --git a/ets2panda/test/ast/parser/ets/typenode_clone_brokentype.ets b/ets2panda/test/ast/parser/ets/typenode_clone_brokentype.ets index 3e8e77e5b8fbc7cde66c9be1a67e642743645bf5..fe8f7863b73df4a4f792977e2cb8fb7ac5b987de 100644 --- a/ets2panda/test/ast/parser/ets/typenode_clone_brokentype.ets +++ b/ets2panda/test/ast/parser/ets/typenode_clone_brokentype.ets @@ -36,8 +36,8 @@ type NestedBroken = { type BrokenFunc = (param: T) => void; // Test instantiation to trigger ValidateGenericTypeAliasForClonedNode -declare const broken1: BrokenType; -declare const broken2: AnotherBroken; +declare const broken1: BrokenType; +declare const broken2: AnotherBroken; /* @@? 21:33 Error TypeError: Cannot find type 'UndefinedMap'. */ /* @@? 21:45 Error TypeError: The `keyof` keyword can only be used for class or interface type. */ @@ -51,5 +51,5 @@ declare const broken2: AnotherBroken; /* @@? 32:26 Error SyntaxError: Unexpected token ']'. */ /* @@? 32:27 Error SyntaxError: Unexpected token ']'. */ /* @@? 36:27 Error TypeError: Cannot find type 'UndefinedInterface'. */ -/* @@? 39:35 Error TypeError: Cannot find type 'any'. */ -/* @@? 40:38 Error TypeError: Cannot find type 'any'. */ +/* @@? 39:35 Error TypeError: Cannot find type 'xny'. */ +/* @@? 40:38 Error TypeError: Cannot find type 'xny'. */ diff --git a/ets2panda/test/runtime/ets/RelaxedAnyType.ets b/ets2panda/test/runtime/ets/RelaxedAnyType.ets new file mode 100644 index 0000000000000000000000000000000000000000..0fcdd76544c36212a7b450c047fc0e6e4ebf4fe9 --- /dev/null +++ b/ets2panda/test/runtime/ets/RelaxedAnyType.ets @@ -0,0 +1,88 @@ +/* + * 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. + */ + +function xassert(v: boolean) { arktest.assertTrue(v) } + +function expectError(action: () => void) { + try { action() } catch (e) { return } + throw new Error("Error expected, but nothing was thrown") +} + +class X { + prop: string = "ooooooo" + foo() { return this.prop } + bar(a: string) { return this.prop + a } +} + +function testldstname() { + let x = new X(); + ((a: any) => a.prop = "ttt")(x); + xassert(((a: any) => a.prop)(x) == "ttt"); + + // expectError(() => { ((a: any) => a.prop = 1)(x) }); // exception is not thrown + expectError(() => { ((a: any) => a.nope)(x) }); + expectError(() => { ((a: any) => a.nope = 1)(x) }); +} + +function testldstval() { + let x = new X(); + ((a: any) => a["prop"] = "uuu")(x); + xassert(((a: any) => a["prop"])(x) == "uuu"); + + // expectError(() => { ((a: any) => a["prop"] = 1)(x) }); // exception is not thrown + expectError(() => { ((a: any) => a["nope"])(x) }); + expectError(() => { ((a: any) => a["nope"] = 1)(x) }); +} + +function testldstidx() { + let x: Array = [undefined, 21, "ay"]; + ((a: any) => a[1] = "aaa")(x); + xassert(((a: any) => a[1])(x) == "aaa"); + + expectError(() => { ((a: any) => a[-1])(x) }); + expectError(() => { ((a: any) => a[-1] = "aaa")(x) }); + // expectError(() => { ((a: any) => a[1.5])(x) }); // nothing happens +} + +function testcallthis() { + let x = new X(); + ((a: any) => a["prop"] = "ya")(x); + xassert(((a: any) => a.foo())(x) == "ya"); + xassert(((a: any) => a.bar("ee"))(x) == "yaee"); +} + +function testcall() { + xassert(((a: any) => a())(() => "aaa") == "aaa"); + xassert(((a: any) => a("bbb"))((v: string) => v) == "bbb"); + xassert(((a: any) => a(123.0))((v: number) => v) == 123.0); + + expectError(() => { ((a: any) => a(1))((s: string) => s) }); +} + +function testcasts() { + let x = new X() + xassert(((a: any) => a as X)(x) == x) + xassert(((a: any) => a instanceof X)(x) == true) +} + +function test() { + testldstval(); + testldstidx(); + testldstname(); + testcall(); + // testcallthis(); // does not work + testcasts(); +} +test() diff --git a/ets2panda/test/runtime/ets/RelaxedAnyType.ets.expected.err b/ets2panda/test/runtime/ets/RelaxedAnyType.ets.expected.err new file mode 100644 index 0000000000000000000000000000000000000000..546cc6bcde35b2fcf6509bfb26799c6f0210316a --- /dev/null +++ b/ets2panda/test/runtime/ets/RelaxedAnyType.ets.expected.err @@ -0,0 +1,33 @@ +# +# Copyright (c) 2025 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +E/bytecode_optimizer: Optimizing RelaxedAnyType.ETSGLOBAL.lambda_invoke-0:std.core.Object;std.core.Object;: IR builder failed! +E/bytecode_optimizer: Optimizing RelaxedAnyType.ETSGLOBAL.lambda_invoke-1:std.core.Object;std.core.Object;: IR builder failed! +E/bytecode_optimizer: Optimizing RelaxedAnyType.ETSGLOBAL.lambda_invoke-2:std.core.Object;std.core.Object;: IR builder failed! +E/bytecode_optimizer: Optimizing RelaxedAnyType.ETSGLOBAL.lambda_invoke-4:std.core.Object;std.core.Object;: IR builder failed! +E/bytecode_optimizer: Optimizing RelaxedAnyType.ETSGLOBAL.lambda_invoke-6:std.core.Object;std.core.Object;: IR builder failed! +E/bytecode_optimizer: Optimizing RelaxedAnyType.ETSGLOBAL.lambda_invoke-7:std.core.Object;std.core.Object;: IR builder failed! +E/bytecode_optimizer: Optimizing RelaxedAnyType.ETSGLOBAL.lambda_invoke-8:std.core.Object;std.core.Object;: IR builder failed! +E/bytecode_optimizer: Optimizing RelaxedAnyType.ETSGLOBAL.lambda_invoke-10:std.core.Object;std.core.Object;: IR builder failed! +E/bytecode_optimizer: Optimizing RelaxedAnyType.ETSGLOBAL.lambda_invoke-12:std.core.Object;std.core.Object;: IR builder failed! +E/bytecode_optimizer: Optimizing RelaxedAnyType.ETSGLOBAL.lambda_invoke-13:std.core.Object;std.core.Object;: IR builder failed! +E/bytecode_optimizer: Optimizing RelaxedAnyType.ETSGLOBAL.lambda_invoke-14:std.core.Object;std.core.Object;: IR builder failed! +E/bytecode_optimizer: Optimizing RelaxedAnyType.ETSGLOBAL.lambda_invoke-16:std.core.Object;std.core.Object;: IR builder failed! +E/bytecode_optimizer: Optimizing RelaxedAnyType.ETSGLOBAL.lambda_invoke-18:std.core.Object;std.core.Object;: IR builder failed! +E/bytecode_optimizer: Optimizing RelaxedAnyType.ETSGLOBAL.lambda_invoke-19:std.core.Object;std.core.Object;: IR builder failed! +E/bytecode_optimizer: Optimizing RelaxedAnyType.ETSGLOBAL.lambda_invoke-20:std.core.Object;std.core.Object;: IR builder failed! +E/bytecode_optimizer: Optimizing RelaxedAnyType.ETSGLOBAL.lambda_invoke-21:std.core.Object;std.core.Object;: IR builder failed! +E/bytecode_optimizer: Optimizing RelaxedAnyType.ETSGLOBAL.lambda_invoke-23:std.core.Object;std.core.Object;: IR builder failed! +E/bytecode_optimizer: Optimizing RelaxedAnyType.ETSGLOBAL.lambda_invoke-25:std.core.Object;std.core.Object;: IR builder failed! +E/bytecode_optimizer: Optimizing RelaxedAnyType.ETSGLOBAL.lambda_invoke-27:std.core.Object;std.core.Object;: IR builder failed! \ No newline at end of file diff --git a/ets2panda/test/test-lists/ets-runtime/ets-runtime-ignored-AOT-PGO.txt b/ets2panda/test/test-lists/ets-runtime/ets-runtime-ignored-AOT-PGO.txt index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..64b784951dd79ee6c05377f162f21be5b0dacbeb 100644 --- a/ets2panda/test/test-lists/ets-runtime/ets-runtime-ignored-AOT-PGO.txt +++ b/ets2panda/test/test-lists/ets-runtime/ets-runtime-ignored-AOT-PGO.txt @@ -0,0 +1,2 @@ +#29044 +RelaxedAnyType.ets \ No newline at end of file diff --git a/ets2panda/test/test-lists/ets-runtime/ets-runtime-ignored-AOT.txt b/ets2panda/test/test-lists/ets-runtime/ets-runtime-ignored-AOT.txt index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..64b784951dd79ee6c05377f162f21be5b0dacbeb 100644 --- a/ets2panda/test/test-lists/ets-runtime/ets-runtime-ignored-AOT.txt +++ b/ets2panda/test/test-lists/ets-runtime/ets-runtime-ignored-AOT.txt @@ -0,0 +1,2 @@ +#29044 +RelaxedAnyType.ets \ No newline at end of file diff --git a/ets2panda/test/test-lists/ets-runtime/ets-runtime-ignored-JIT-REPEATS.txt b/ets2panda/test/test-lists/ets-runtime/ets-runtime-ignored-JIT-REPEATS.txt index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..64b784951dd79ee6c05377f162f21be5b0dacbeb 100644 --- a/ets2panda/test/test-lists/ets-runtime/ets-runtime-ignored-JIT-REPEATS.txt +++ b/ets2panda/test/test-lists/ets-runtime/ets-runtime-ignored-JIT-REPEATS.txt @@ -0,0 +1,2 @@ +#29044 +RelaxedAnyType.ets \ No newline at end of file diff --git a/ets2panda/test/unit/plugin/CMakeLists.txt b/ets2panda/test/unit/plugin/CMakeLists.txt index 655ccb4560cc3dd77cb2d499b9042b67471e6f98..9022be18358f0e6048a8a4adf4ccc53d103b8f10 100644 --- a/ets2panda/test/unit/plugin/CMakeLists.txt +++ b/ets2panda/test/unit/plugin/CMakeLists.txt @@ -97,7 +97,6 @@ set(PLUGIN_TESTS "plugin_proceed_to_state_create_import compile.ets ${COMPILE_MODE} cpp ${EXECUTABLE_PLUGIN}" "plugin_proceed_to_state_set_from_struct_modifier compile.ets ${COMPILE_MODE} cpp ${EXECUTABLE_PLUGIN}" "plugin_proceed_to_state_default_access_modifier compile.ets ${COMPILE_MODE} cpp ${EXECUTABLE_PLUGIN}" - "plugin_proceed_to_state_dynamic_class_recheck compile.ets ${COMPILE_MODE} cpp ${EXECUTABLE_PLUGIN}" "plugin_proceed_to_state_assignment_expression_set_result compile.ets ${COMPILE_MODE} cpp ${EXECUTABLE_PLUGIN}" "plugin_proceed_to_state_create_diagnostic_kind compile.ets ${COMPILE_MODE} cpp ${EXECUTABLE_PLUGIN}" "plugin_proceed_to_state_is_optional_declaration compile.ets ${COMPILE_MODE} cpp ${EXECUTABLE_PLUGIN}" diff --git a/ets2panda/test/unit/plugin/plugin_proceed_to_state_dynamic_class_recheck.cpp b/ets2panda/test/unit/plugin/plugin_proceed_to_state_dynamic_class_recheck.cpp deleted file mode 100644 index 4355b52e6417937e0cfaff909ce291fa500662e2..0000000000000000000000000000000000000000 --- a/ets2panda/test/unit/plugin/plugin_proceed_to_state_dynamic_class_recheck.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/** - * 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 -#include -#include -#include -#include - -#include "os/library_loader.h" - -#include "public/es2panda_lib.h" -#include "util.h" - -// NOLINTBEGIN -static std::string source = R"( -class $jscall {} -class $jsnew {} -)"; - -static es2panda_Impl *impl = nullptr; -es2panda_Context *context = nullptr; -static es2panda_AstNode *targetAfterCheck = nullptr; -static es2panda_AstNode *targetAfterReCheck = nullptr; - -static void SetTargetClass(es2panda_AstNode *ast, void *inputCtx) -{ - auto ctx = reinterpret_cast(inputCtx); - if (!impl->IsClassDeclaration(ast)) { - return; - } - - auto *def = impl->ClassDeclarationDefinition(ctx, ast); - if (def == nullptr) { - return; - } - - auto *ident = impl->ClassDefinitionIdent(ctx, def); - if (ident == nullptr) { - return; - } - auto name = impl->IdentifierName(ctx, ident); - if (std::string(name) == "$jscall") { - if (targetAfterCheck == nullptr) { - targetAfterCheck = ast; - return; - } - targetAfterReCheck = ast; - } -} - -int main(int argc, char **argv) -{ - if (argc < MIN_ARGC) { - return INVALID_ARGC_ERROR_CODE; - } - - if (GetImpl() == nullptr) { - return NULLPTR_IMPL_ERROR_CODE; - } - impl = GetImpl(); - std::cout << "LOAD SUCCESS" << std::endl; - - const char **args = const_cast(&(argv[1])); - auto config = impl->CreateConfig(argc - 1, args); - context = impl->CreateContextFromString(config, source.data(), argv[argc - 1]); - if (context == nullptr) { - std::cerr << "FAILED TO CREATE CONTEXT" << std::endl; - return NULLPTR_CONTEXT_ERROR_CODE; - } - - impl->ProceedToState(context, ES2PANDA_STATE_CHECKED); - auto *program = impl->ContextProgram(context); - auto *ast = impl->ProgramAst(context, program); - impl->AstNodeForEach(ast, SetTargetClass, context); - if (targetAfterCheck == nullptr) { - std::cerr << "FAILED TO GET NODE" << std::endl; - return NULLPTR_CONTEXT_ERROR_CODE; - } - size_t len; - auto **stmts = impl->BlockStatementStatements(context, ast, &len); - auto *newStmts = static_cast(impl->AllocMemory(context, len + 1, sizeof(es2panda_AstNode *))); - for (size_t idx = 0; idx < len; ++idx) { - if (stmts[idx] != targetAfterCheck) { - newStmts[idx] = stmts[idx]; - continue; - } - - auto *def = impl->ClassDeclarationDefinition(context, targetAfterCheck); - targetAfterCheck = impl->UpdateClassDeclaration(context, targetAfterCheck, def); - newStmts[idx] = targetAfterCheck; - } - impl->BlockStatementSetStatements(context, ast, newStmts, len); - - impl->AstNodeRecheck(context, ast); - impl->AstNodeForEach(ast, SetTargetClass, context); - // the orignal class declaration named "jscall" or "jsnew" should be removed. - int res = targetAfterReCheck == nullptr ? 0 : TEST_ERROR_CODE; - impl->DestroyConfig(config); - - return res; -} - -// NOLINTEND diff --git a/ets2panda/util/diagnostic/semantic.yaml b/ets2panda/util/diagnostic/semantic.yaml index d9295dba3c87130819074312737f3d9a1d845b63..5a859270a22bfc4b53952608884e3a6b06ea8780 100644 --- a/ets2panda/util/diagnostic/semantic.yaml +++ b/ets2panda/util/diagnostic/semantic.yaml @@ -689,6 +689,10 @@ semantic: id: 236 message: "Type '{}' cannot be used as an index type. Only primitive or unboxable integral types can be used as index." +- name: INVALID_INTRINSIC + id: 402 + message: "Invalid internal intrinsic expression" + - name: INVALID_LAMBDA_PARAMETER id: 395 message: "Invalid lambda parameter. Expected: 'identifier(: type)?', 'identifier?(: type)?' or '...identifier(: type)?'." diff --git a/ets2panda/util/helpers.cpp b/ets2panda/util/helpers.cpp index 51c7b324e479e55b5e3ec6808d1c71f4e2a8e7b6..fd6665bd0a9f9414f41101b8d35c0cb9fcf3e084 100644 --- a/ets2panda/util/helpers.cpp +++ b/ets2panda/util/helpers.cpp @@ -825,7 +825,9 @@ ir::AstNode *Helpers::DerefETSTypeReference(ir::AstNode *node) return node; } auto *var = name->AsIdentifier()->Variable(); - ES2PANDA_ASSERT(var != nullptr); + if (var == nullptr) { + return node; + } auto *declNode = var->Declaration()->Node(); if (!declNode->IsTSTypeAliasDeclaration()) { return declNode; diff --git a/ets2panda/varbinder/ETSBinder.cpp b/ets2panda/varbinder/ETSBinder.cpp index af93aaed1cc5f9b77e95ce29a3e9d57eb5704f27..a122f0bbe9508508ba98e60ad2c388a631322bf7 100644 --- a/ets2panda/varbinder/ETSBinder.cpp +++ b/ets2panda/varbinder/ETSBinder.cpp @@ -57,10 +57,16 @@ void ETSBinder::LookupTypeArgumentReferences(ir::ETSTypeReference *typeRef) bool ETSBinder::IsSpecialName(const util::StringView &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::AWAITED_TYPE_NAME; + constexpr std::array specialKeywords = {compiler::Signatures::ANY_TYPE_NAME, compiler::Signatures::ANY, + compiler::Signatures::UNDEFINED, compiler::Signatures::NULL_LITERAL}; + + constexpr std::array utilityTypes = { + compiler::Signatures::READONLY_TYPE_NAME, compiler::Signatures::PARTIAL_TYPE_NAME, + compiler::Signatures::REQUIRED_TYPE_NAME, compiler::Signatures::FIXED_ARRAY_TYPE_NAME, + compiler::Signatures::AWAITED_TYPE_NAME}; + + return std::find(specialKeywords.begin(), specialKeywords.end(), name.Utf8()) != specialKeywords.end() || + std::find(utilityTypes.begin(), utilityTypes.end(), name.Utf8()) != utilityTypes.end(); } bool ETSBinder::LookupInDebugInfoPlugin(ir::Identifier *ident)