diff --git a/ets2panda/BUILD.gn b/ets2panda/BUILD.gn index ceeeb2ed6c71a7b81fbd3d330cf80ef0ed05e102..084856fb18dcb98074113bd79f3b0a8113bada0d 100644 --- a/ets2panda/BUILD.gn +++ b/ets2panda/BUILD.gn @@ -91,6 +91,7 @@ libes2panda_sources = [ "checker/ets/dynamic.cpp", "checker/ets/etsWarningAnalyzer.cpp", "checker/ets/function.cpp", + "checker/ets/functionHelpers.cpp", "checker/ets/helpers.cpp", "checker/ets/object.cpp", "checker/ets/typeCheckingHelpers.cpp", diff --git a/ets2panda/CMakeLists.txt b/ets2panda/CMakeLists.txt index b37a63a03b022394dbe943a54c8acc39a7fa4249..7bb292d98f5f7fb6df8a98b4731506baabe73e0a 100644 --- a/ets2panda/CMakeLists.txt +++ b/ets2panda/CMakeLists.txt @@ -587,6 +587,7 @@ set(ES2PANDA_LIB_SRC checker/ets/conversion.cpp checker/ets/dynamic.cpp checker/ets/function.cpp + checker/ets/functionHelpers.cpp checker/ets/validateHelpers.cpp checker/ets/typeCheckingHelpers.cpp checker/ets/helpers.cpp diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index 4498536bb1f300d01c8b1a2ba89667e544d50c3f..2c7fbde283741647691d87037aa1619fce3fe1ed 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -156,7 +156,7 @@ checker::Type *ETSAnalyzer::Check(ir::ClassStaticBlock *st) const } auto *func = st->Function(); - checker->BuildFunctionSignature(func); + func->SetSignature(checker->BuildFunctionSignature(func)); if (func->Signature() == nullptr) { st->SetTsType(checker->GlobalTypeError()); @@ -894,39 +894,102 @@ static bool CheckElement(ETSChecker *checker, Type *const preferredType, return true; } -static Type *InferPreferredTypeFromElements(ETSChecker *checker, ir::ArrayExpression *arrayExpr) +static Type *ArrayLikeElementTypeByIndex(ETSChecker *checker, Type *type, size_t ix) { + if (type->IsETSTupleType()) { + return type->AsETSTupleType()->GetTupleTypesList()[ix]; + } + return checker->GetElementTypeOfArray(type); +} + +static Type *NonConstantTypeIfNonConstantPreferred(ETSChecker *checker, Type *tp, Type *preferredTp) +{ + if (checker->GetNonConstantType(preferredTp) == preferredTp) { + return checker->GetNonConstantType(tp); + } + return tp; +} + +static Type *InferTypeFromElements(ETSChecker *checker, ir::ArrayExpression *arrayExpr, Type *preferredType) +{ + if (arrayExpr->Elements().empty()) { + return preferredType; + } + ArenaVector arrayExpressionElementTypes(checker->ProgramAllocator()->Adapter()); - for (auto *const element : arrayExpr->Elements()) { + size_t tupleIndex = 0; // does not matter when we expect an array + for (auto *element : arrayExpr->Elements()) { + auto *expectedType = + preferredType == nullptr ? nullptr : ArrayLikeElementTypeByIndex(checker, preferredType, tupleIndex); + if (!element->IsSpreadElement()) { + element->SetPreferredType(expectedType); + } auto *elementType = *element->Check(checker); + if (element->IsSpreadElement() && elementType->IsETSTupleType()) { for (auto *typeFromTuple : elementType->AsETSTupleType()->GetTupleTypesList()) { arrayExpressionElementTypes.emplace_back(typeFromTuple); + tupleIndex++; } continue; + } else { + tupleIndex++; } if (element->IsSpreadElement() && elementType->IsETSArrayType()) { elementType = elementType->AsETSArrayType()->ElementType(); } - arrayExpressionElementTypes.emplace_back(elementType); - } + auto *nonConstType = checker->GetNonConstantType(elementType); + + // We select expectedType at least in two special cases: + // - when expectedType is a string literal type + // - when there is implicit conversion involved + Type *derivedType = nullptr; + if (expectedType == nullptr) { + derivedType = nonConstType; + } else if (!checker->Relation()->IsSupertypeOf(expectedType, nonConstType)) { + derivedType = expectedType; + } else { + ArenaVector derivedTpars {checker->Allocator()->Adapter()}; + std::copy(checker->TypeParametersBeingDerived().begin(), checker->TypeParametersBeingDerived().end(), + std::back_inserter(derivedTpars)); - // NOTE (smartin): fix union type normalization. Currently for primitive types like a 'char | char' type, it will be - // normalized to 'Char'. However it shouldn't be boxed, and be kept as 'char'. For a quick fix, if all types are - // primitive, then after making the union type, explicitly unbox it. - if (std::all_of(arrayExpressionElementTypes.begin(), arrayExpressionElementTypes.end(), - [](Type *const typeOfElement) { return typeOfElement->IsETSPrimitiveType(); })) { - return checker->CreateETSResizableArrayType(checker->GetNonConstantType( - checker->MaybeUnboxType(checker->CreateETSUnionType(std::move(arrayExpressionElementTypes))))); + Substitution subst {}; + if (checker->EnhanceSubstitutionForType(derivedTpars, expectedType, nonConstType, &subst)) { + derivedType = expectedType->Substitute(checker->Relation(), &subst); + } else { + derivedType = expectedType; + } + } + + arrayExpressionElementTypes.emplace_back(derivedType); } // NOTE (smartin): optimize element access on constant array expressions (note is here, because the constant value // will be present on the type) - return checker->CreateETSResizableArrayType( - checker->GetNonConstantType(checker->CreateETSUnionType(std::move(arrayExpressionElementTypes)))); + if (preferredType == nullptr) { + return checker->CreateETSResizableArrayType( + checker->GetNonConstantType(checker->CreateETSUnionType(std::move(arrayExpressionElementTypes)))); + } else if (preferredType->IsETSResizableArrayType()) { + auto *elemType = NonConstantTypeIfNonConstantPreferred( + checker, checker->CreateETSUnionType(std::move(arrayExpressionElementTypes)), + preferredType->AsETSResizableArrayType()->ElementType()); + return checker->CreateETSResizableArrayType(elemType); + } else if (preferredType->IsETSArrayType()) { + auto *elemType = NonConstantTypeIfNonConstantPreferred( + checker, checker->CreateETSUnionType(std::move(arrayExpressionElementTypes)), + preferredType->AsETSArrayType()->ElementType()); + return checker->CreateETSArrayType(elemType); + } + ES2PANDA_ASSERT(preferredType->IsETSTupleType()); + ES2PANDA_ASSERT(preferredType->AsETSTupleType()->GetTupleSize() == arrayExpressionElementTypes.size()); + for (size_t ix = 0; ix < arrayExpressionElementTypes.size(); ix++) { + arrayExpressionElementTypes[ix] = NonConstantTypeIfNonConstantPreferred( + checker, arrayExpressionElementTypes[ix], preferredType->AsETSTupleType()->GetTypeAtIndex(ix)); + } + return checker->Allocator()->New(checker, arrayExpressionElementTypes); } static bool CheckArrayExpressionElements(ETSChecker *checker, ir::ArrayExpression *arrayExpr) @@ -1052,28 +1115,33 @@ checker::Type *ETSAnalyzer::Check(ir::ArrayExpression *expr) const return expr->TsType(); } - auto *preferredType = GetAppropriatePreferredType(expr->PreferredType(), &Type::IsAnyETSArrayOrTupleType); + auto *preferredType = GetAppropriatePreferredType( + expr->PreferredType(), [checker](Type *tp) { return IsArrayExpressionValidInitializerForType(checker, tp); }); - if (expr->PreferredType() != nullptr && expr->PreferredType()->IsETSUnionType()) { + // NOTE(gogabr): to be subsumed by the general type inference algorithm + if (expr->PreferredType() != nullptr && preferredType == nullptr && expr->PreferredType()->IsETSUnionType()) { if (auto *picked = SelectArrayPreferredTypeForLiteral(checker, expr, expr->PreferredType())) { preferredType = picked; expr->SetPreferredType(preferredType); } } - if (preferredType != nullptr && preferredType->IsETSReadonlyArrayType()) { - const auto elementType = preferredType->AsETSObjectType()->TypeArguments().front(); - preferredType = checker->CreateETSResizableArrayType(elementType); + if (expr->PreferredType() != nullptr && preferredType == nullptr) { + if (!(checker->Relation()->GetTypeRelationFlags() & TypeRelationFlag::NO_THROW)) { + checker->LogError(diagnostic::UNEXPECTED_ARRAY, {expr->PreferredType()}, expr->Start()); + } + return checker->InvalidateType(expr); } - if (!IsArrayExpressionValidInitializerForType(checker, preferredType)) { - checker->LogError(diagnostic::UNEXPECTED_ARRAY, {expr->PreferredType()}, expr->Start()); - return checker->InvalidateType(expr); + if (preferredType != nullptr && preferredType->IsETSObjectType() && + preferredType->AsETSObjectType()->TypeArguments().size() == 1) { + const auto elementType = preferredType->AsETSObjectType()->TypeArguments().front(); + preferredType = checker->CreateETSResizableArrayType(elementType); } if (!expr->Elements().empty()) { if (preferredType == nullptr || preferredType == checker->GlobalETSObjectType()) { - preferredType = InferPreferredTypeFromElements(checker, expr); + preferredType = InferTypeFromElements(checker, expr, nullptr); } expr->SetPreferredType(preferredType); @@ -1088,35 +1156,80 @@ checker::Type *ETSAnalyzer::Check(ir::ArrayExpression *expr) const return checker->InvalidateType(expr); } - expr->SetTsType(preferredType); - if (!preferredType->IsETSResizableArrayType() && !preferredType->IsETSTupleType()) { - ES2PANDA_ASSERT(preferredType->IsETSArrayType()); - const auto *const arrayType = preferredType->AsETSArrayType(); + auto *type = InferTypeFromElements(checker, expr, preferredType); + + expr->SetTsType(type); + if (!type->IsETSResizableArrayType() && !type->IsETSTupleType()) { + ES2PANDA_ASSERT(type->IsETSArrayType()); + const auto *const arrayType = type->AsETSArrayType(); checker->CreateBuiltinArraySignature(arrayType, arrayType->Rank()); } return expr->TsType(); } -void TryInferPreferredType(ir::ArrowFunctionExpression *expr, checker::Type *preferredType, ETSChecker *checker) +Signature *TryInferPreferredSignatureForLambda(ir::ArrowFunctionExpression *expr, checker::Type *preferredType, + ETSChecker *checker) { if (!preferredType->IsETSUnionType()) { if (preferredType->IsETSArrowType() && !preferredType->AsETSFunctionType()->CallSignaturesOfMethodOrArrow().empty()) { - checker->TryInferTypeForLambdaTypeAlias(expr, preferredType->AsETSFunctionType()); - checker->BuildFunctionSignature(expr->Function(), false); + if (!checker->TryInferTypeForLambda(expr, preferredType->AsETSFunctionType())) { + return nullptr; + } + return checker->BuildFunctionSignature(expr->Function(), false); } - return; + return nullptr; } for (auto &ct : preferredType->AsETSUnionType()->ConstituentTypes()) { if (!ct->IsETSArrowType() || ct->AsETSFunctionType()->CallSignaturesOfMethodOrArrow().empty()) { continue; } - checker->TryInferTypeForLambdaTypeAlias(expr, ct->AsETSFunctionType()); - checker->BuildFunctionSignature(expr->Function(), false); - if (expr->Function()->Signature() != nullptr) { + if (!checker->TryInferTypeForLambda(expr, ct->AsETSFunctionType())) { + continue; + } + + auto *signature = checker->BuildFunctionSignature(expr->Function(), false); + if (signature != nullptr) { + return signature; + } + } + return nullptr; +} + +static Type *ComputeReturnType(ETSChecker *checker, ir::ScriptFunction *func) +{ + ArenaVector returnTypes {checker->Allocator()->Adapter()}; + std::function retCheck = [&](ir::AstNode *ast) { + if (ast->IsScriptFunction()) { + return; + } + + ast->Iterate(retCheck); + + if (!ast->IsReturnStatement()) { + return; + } + auto *ret = ast->AsReturnStatement(); + if (ret->Argument() == nullptr) { return; } + // account for possible implicit conversions + auto *expectedPrimitive = GetAppropriatePreferredType(ret->ReturnType(), [](Type *tp) { + return tp->IsETSObjectType() && tp->AsETSObjectType()->IsBoxedPrimitive(); + }); + auto *rtype = + expectedPrimitive != nullptr ? ret->ReturnType() : checker->GetNonConstantType(ret->Argument()->TsType()); + returnTypes.push_back(rtype); + }; + func->Iterate(retCheck); + auto *fullRtype = + returnTypes.empty() ? checker->GlobalVoidType() : checker->CreateETSUnionType(std::move(returnTypes)); + if (func->IsAsyncFunc() && + !GetAppropriatePreferredType(fullRtype, [&](Type *tp) { return checker->IsPromiseType(tp); })) { + return checker->CreatePromiseOf(fullRtype); + } else { + return fullRtype; } } @@ -1174,14 +1287,15 @@ checker::Type *ETSAnalyzer::Check(ir::ArrowFunctionExpression *expr) const checker->AddStatus(checker::CheckerStatus::IN_LAMBDA); checker->Context().SetContainingLambda(expr); - auto preferredType = expr->GetPreferredType(); + auto preferredType = expr->PreferredType(); + Signature *signature = nullptr; if (preferredType != nullptr) { - TryInferPreferredType(expr, preferredType, checker); - } else { - checker->BuildFunctionSignature(expr->Function(), false); + signature = TryInferPreferredSignatureForLambda(expr, preferredType, checker); } - - if (expr->Function()->Signature() == nullptr) { + if (signature == nullptr) { + signature = checker->BuildFunctionSignature(expr->Function(), false); + } + if (signature == nullptr) { return checker->InvalidateType(expr); } @@ -1189,7 +1303,6 @@ checker::Type *ETSAnalyzer::Check(ir::ArrowFunctionExpression *expr) const checker->AddStatus(checker::CheckerStatus::IN_EXTENSION_METHOD); CheckExtensionMethod(checker, expr->Function(), expr); } - auto *signature = expr->Function()->Signature(); checker->Context().SetContainingSignature(signature); expr->Function()->Body()->Check(checker); @@ -1209,6 +1322,13 @@ checker::Type *ETSAnalyzer::Check(ir::ArrowFunctionExpression *expr) const } } + // May need to update signature based on computed return type + if (expr->Function()->ReturnTypeAnnotation() == nullptr) { + signature->SetReturnType(ComputeReturnType(checker, expr->Function())); + expr->Function()->SetSignature(signature); + } + expr->Function()->SetSignature(signature); + auto *funcType = checker->CreateETSArrowType(signature); checker->Context().SetContainingSignature(nullptr); expr->SetTsType(funcType); @@ -1384,8 +1504,6 @@ checker::Type *ETSAnalyzer::Check(ir::AssignmentExpression *const expr) const checker->ValidateUnaryOperatorOperand(expr->target_, expr); } - checker->InferLambdaInAssignmentExpression(expr); - if (auto setterType = GetSetterType(expr->target_, checker); setterType != nullptr) { leftType = setterType; expr->Left()->SetTsType(leftType); @@ -1419,19 +1537,10 @@ static checker::Type *HandleSubstitution(ETSChecker *checker, ir::AssignmentExpr leftType->IsETSTupleType() || leftType->IsETSUnionType(); if (expr->Right()->IsArrayExpression() && possibleInferredTypeOfArray) { checker->ModifyPreferredType(expr->Right()->AsArrayExpression(), leftType); - } else if (expr->Right()->IsArrowFunctionExpression() && - (leftType->IsETSArrowType() || leftType->IsETSUnionType())) { - if (auto *preferredType = GetAppropriatePreferredType(leftType, [](Type *tp) { return tp->IsETSArrowType(); }); - preferredType != nullptr) { - checker->TryInferTypeForLambdaTypeAlias(expr->Right()->AsArrowFunctionExpression(), - preferredType->AsETSFunctionType()); - } - } else if (expr->Right()->IsObjectExpression()) { - expr->Right()->AsObjectExpression()->SetPreferredType(leftType); - } else { - expr->Right()->SetPreferredType(leftType); } + expr->Right()->SetPreferredType(leftType); + return expr->Right()->Check(checker); } @@ -1899,6 +2008,7 @@ checker::Type *ETSAnalyzer::Check(ir::ConditionalExpression *expr) const } auto *consequent = expr->Consequent(); + consequent->SetPreferredType(expr->PreferredType()); Type *consequentType = consequent->Check(checker); SmartCastArray consequentSmartCasts = checker->Context().CloneSmartCasts(); @@ -1911,6 +2021,7 @@ checker::Type *ETSAnalyzer::Check(ir::ConditionalExpression *expr) const } auto *alternate = expr->Alternate(); + alternate->SetPreferredType(expr->PreferredType()); Type *alternateType = alternate->Check(checker); // Here we need to combine types from consequent and alternate if blocks. @@ -2074,8 +2185,9 @@ checker::Type *ETSAnalyzer::ResolveMemberExpressionByBaseType(ETSChecker *checke return expr->SetAndAdjustType(checker, checker->GlobalETSObjectType()); } - if (baseType->IsETSFunctionType()) { - return expr->SetAndAdjustType(checker, checker->GlobalBuiltinFunctionType()); + if (baseType->IsETSArrowType()) { + baseType = + baseType->AsETSFunctionType()->ArrowToFunctionalInterface(checker); // will be processed in the next if } if (baseType->IsETSObjectType()) { @@ -2386,7 +2498,15 @@ static bool AreAllRequiredInterfacePropertiesSatisfied(ir::ObjectExpression *exp checker::ETSObjectType *interfaceType, ETSChecker *checker) { // Get all properties of the interface using GetAllProperties - auto allProperties = interfaceType->GetAllProperties(); + std::vector allProperties {}; + std::function const addProps = [&allProperties, + &addProps](ETSObjectType const *itf) -> void { + auto const &curProps = itf->GetAllProperties(); + std::copy(curProps.begin(), curProps.end(), std::back_inserter(allProperties)); + auto const &superItfs = itf->Interfaces(); + std::for_each(superItfs.begin(), superItfs.end(), addProps); + }; + addProps(interfaceType); // Create a set of property names provided in the object literal std::unordered_set literalProperties; diff --git a/ets2panda/checker/ETSAnalyzerHelpers.cpp b/ets2panda/checker/ETSAnalyzerHelpers.cpp index 7df2adc15cb3d0a2748d41d6fe5004e0b19b16ec..b5f877eeb0894f7f0574cc2a0ca7184e008ea122 100644 --- a/ets2panda/checker/ETSAnalyzerHelpers.cpp +++ b/ets2panda/checker/ETSAnalyzerHelpers.cpp @@ -372,6 +372,7 @@ checker::Signature *ResolveCallExtensionFunction(checker::Type *functionType, ch expr->Arguments().erase(expr->Arguments().begin()); return nullptr; } + // expr->Arguments().erase(expr->Arguments().begin()); SwitchMethodCallToFunctionCall(checker, expr, signature); return signature; @@ -672,12 +673,28 @@ checker::Type *InferReturnType(ETSChecker *checker, ir::ScriptFunction *containi bool IsArrayExpressionValidInitializerForType(ETSChecker *checker, const Type *const arrayExprPreferredType) { - const auto validForTarget = arrayExprPreferredType == nullptr // preferred type will be inferred from elements - || arrayExprPreferredType->IsAnyETSArrayOrTupleType() // valid for array or tuple types + const auto validForTarget = arrayExprPreferredType->IsAnyETSArrayOrTupleType() // valid for array or tuple types || checker->Relation()->IsSupertypeOf(arrayExprPreferredType, // valid for 'Object' checker->GlobalETSObjectType()); + if (validForTarget) { + return true; + } + + if (!arrayExprPreferredType->IsETSObjectType()) { + return false; + } + + auto *preferredObjType = arrayExprPreferredType->AsETSObjectType(); + + // All supertypes of Array have the same type argument + if (preferredObjType->TypeArguments().size() != 1) { + return false; + } + + auto *substitutedResizeableArrayType = checker->GlobalBuiltinETSResizableArrayType()->SubstituteArguments( + checker->Relation(), preferredObjType->TypeArguments()); - return validForTarget; + return checker->Relation()->IsSupertypeOf(preferredObjType, substitutedResizeableArrayType); } void CastPossibleTupleOnRHS(ETSChecker *checker, ir::AssignmentExpression *expr) diff --git a/ets2panda/checker/ETSchecker.h b/ets2panda/checker/ETSchecker.h index 621a001d0b3e89e9c4912388f6d2b08e55743dad..b3d71da8dc2dca3626ba9a2b9805cbcde75b0fbe 100644 --- a/ets2panda/checker/ETSchecker.h +++ b/ets2panda/checker/ETSchecker.h @@ -413,7 +413,7 @@ public: void InferTypesForLambda(ir::ScriptFunction *lambda, ir::ETSFunctionType *calleeType, Signature *maybeSubstitutedFunctionSig = nullptr); void InferTypesForLambda(ir::ScriptFunction *lambda, Signature *signature); - void TryInferTypeForLambdaTypeAlias(ir::ArrowFunctionExpression *expr, ETSFunctionType *calleeType); + bool TryInferTypeForLambda(ir::ArrowFunctionExpression *expr, ETSFunctionType *calleeType); bool ResolveLambdaArgumentType(Signature *signature, ir::Expression *argument, size_t paramPosition, size_t argumentPosition, TypeRelationFlag resolutionFlags); bool TrailingLambdaTypeInference(Signature *signature, const ArenaVector &arguments); @@ -557,7 +557,7 @@ public: SignatureInfo *ComposeSignatureInfo(ir::TSTypeParameterDeclaration *typeParams, ArenaVector const ¶ms); void ValidateMainSignature(ir::ScriptFunction *func); - void BuildFunctionSignature(ir::ScriptFunction *func, bool isConstructSig = false); + Signature *BuildFunctionSignature(ir::ScriptFunction *func, bool isConstructSig = false); ETSFunctionType *BuildMethodType(ir::ScriptFunction *func); Type *BuildMethodSignature(ir::MethodDefinition *method); Signature *CheckEveryAbstractSignatureIsOverridden(ETSFunctionType *target, ETSFunctionType *source); @@ -656,7 +656,6 @@ public: void CheckSinglePropertyAnnotation(ir::AnnotationUsage *st, ir::AnnotationDeclaration *annoDecl); void CheckMultiplePropertiesAnnotation(ir::AnnotationUsage *st, util::StringView const &baseName, ArenaUnorderedMap &fieldMap); - void InferLambdaInAssignmentExpression(ir::AssignmentExpression *const expr); void InferAliasLambdaType(ir::TypeNode *localTypeAnnotation, ir::ArrowFunctionExpression *init); checker::Type *ApplyConditionalOperatorPromotion(checker::ETSChecker *checker, checker::Type *unboxedL, checker::Type *unboxedR); @@ -1004,6 +1003,14 @@ public: // clang-format on } + void AddDerivedTypeParameter(ETSTypeParameter *tp); + void RemoveDerivedTypeParameter(ETSTypeParameter *tp); + [[nodiscard]] bool IsTypeParameterBeingDerived(ETSTypeParameter *tpar); + std::unordered_set const &TypeParametersBeingDerived() + { + return typeParametersBeingDerived_; + } + private: std::pair GetTargetIdentifierAndType(ir::Identifier *ident); void NotResolvedError(ir::Identifier *const ident, const varbinder::Variable *classVar, @@ -1110,6 +1117,7 @@ private: ArenaVector overloadSigContainer_; ArenaSet readdedChecker_; bool permitRelaxedAny_ {false}; + std::unordered_set typeParametersBeingDerived_ {}; }; } // namespace ark::es2panda::checker diff --git a/ets2panda/checker/checker.h b/ets2panda/checker/checker.h index d7466fb0d418ece598f7f6319d2b61f1e64a4e9a..6d50eefe640604df27e3aabd748e7cdfe18ae27d 100644 --- a/ets2panda/checker/checker.h +++ b/ets2panda/checker/checker.h @@ -408,6 +408,8 @@ public: : checker_(checker), prev_(checker->context_) { const bool inExternal = checker->HasStatus(CheckerStatus::IN_EXTERNAL); + newStatus |= + CheckerStatus(prev_.Status() & (CheckerStatus::BUILTINS_INITIALIZED | CheckerStatus::TYPES_ARE_STABLE)); checker_->context_ = CheckerContext(checker, newStatus, containingClass, containingSignature); if (inExternal) { // handled here instead of at call sites to make things more foolproof diff --git a/ets2panda/checker/checkerContext.h b/ets2panda/checker/checkerContext.h index 1c3f8cb59cbc159b26305cd181952b77465ba865..3548226ab45c800c9525b2f8ffa07c1aa1c91565 100644 --- a/ets2panda/checker/checkerContext.h +++ b/ets2panda/checker/checkerContext.h @@ -39,6 +39,7 @@ class Variable; namespace ark::es2panda::checker { class ETSObjectType; +class ETSTypeParameter; class Signature; class Type; class Checker; @@ -59,31 +60,33 @@ enum class CheckerStatus : uint32_t { IN_STATIC_BLOCK = 1U << 9U, INNER_CLASS = 1U << 10U, IN_ENUM = 1U << 11U, - BUILTINS_INITIALIZED = 1U << 12U, - IN_LAMBDA = 1U << 13U, - IGNORE_VISIBILITY = 1U << 14U, - IN_EXTENSION_METHOD = 1U << 15U, - IN_LOCAL_CLASS = 1U << 16U, - IN_INSTANCEOF_CONTEXT = 1U << 17U, - IN_TEST_EXPRESSION = 1U << 18U, - IN_LOOP = 1U << 19U, - MEET_RETURN = 1U << 20U, - MEET_BREAK = 1U << 21U, - MEET_CONTINUE = 1U << 22U, - MEET_THROW = 1U << 23U, - IN_EXTERNAL = 1U << 24U, - IN_BRIDGE_TEST = 1U << 25U, - IN_GETTER = 1U << 26U, - IN_SETTER = 1U << 27U, - IN_EXTENSION_ACCESSOR_CHECK = 1U << 28U, - IN_TYPE_INFER = 1U << 29U, + IN_LAMBDA = 1U << 12U, + IGNORE_VISIBILITY = 1U << 13U, + IN_EXTENSION_METHOD = 1U << 14U, + IN_LOCAL_CLASS = 1U << 15U, + IN_INSTANCEOF_CONTEXT = 1U << 16U, + IN_TEST_EXPRESSION = 1U << 17U, + IN_LOOP = 1U << 18U, + MEET_RETURN = 1U << 19U, + MEET_BREAK = 1U << 20U, + MEET_CONTINUE = 1U << 21U, + MEET_THROW = 1U << 22U, + IN_EXTERNAL = 1U << 23U, + IN_BRIDGE_TEST = 1U << 24U, + IN_GETTER = 1U << 25U, + IN_SETTER = 1U << 26U, + IN_EXTENSION_ACCESSOR_CHECK = 1U << 27U, + IN_TYPE_INFER = 1U << 28U, + + // Should normally only be added, never revoked + BUILTINS_INITIALIZED = 1U << 29U, + TYPES_ARE_STABLE = 1U << 30U, // nodes that already have type will never change it }; } // namespace ark::es2panda::checker template <> -struct enumbitops::IsAllowedType : std::true_type { -}; +struct enumbitops::IsAllowedType : std::true_type {}; namespace ark::es2panda::checker { diff --git a/ets2panda/checker/ets/arithmetic.cpp b/ets2panda/checker/ets/arithmetic.cpp index cc7e14a1bbeb453976419d06e0a851947f1647bc..b36bb4777505de9aa8ab4761d15a92270171e7bf 100644 --- a/ets2panda/checker/ets/arithmetic.cpp +++ b/ets2panda/checker/ets/arithmetic.cpp @@ -1134,12 +1134,6 @@ std::tuple ETSChecker::CheckArithmeticOperations( if (tsType->IsETSPrimitiveType()) { tsType = MaybeBoxType(tsType); } - if (left->TsType()->IsTypeError()) { - left->SetTsType(tsType); - } - if (right->TsType()->IsTypeError()) { - right->SetTsType(tsType); - } return {tsType, tsType}; } @@ -1167,6 +1161,11 @@ std::tuple ETSChecker::CheckBinaryOperator(ir::Expression *left, ir::Expression *expr, lexer::TokenType operationType, lexer::SourcePosition pos, bool forcePromotion) { + if (operationType == lexer::TokenType::PUNCTUATOR_NULLISH_COALESCING && expr->PreferredType() != nullptr) { + left->SetPreferredType(CreateETSUnionType({expr->PreferredType(), GlobalETSUnionUndefinedNull()})); + right->SetPreferredType(expr->PreferredType()); + } + // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) checker::Type *leftType = left->Check(this); diff --git a/ets2panda/checker/ets/function.cpp b/ets2panda/checker/ets/function.cpp index 2643ee7f1b29e25283309e2b118bf9162aa1d565..55d7a7608dd0be638807be63091a7269c886629a 100644 --- a/ets2panda/checker/ets/function.cpp +++ b/ets2panda/checker/ets/function.cpp @@ -22,7 +22,7 @@ #include "ir/astNodeFlags.h" #include "varbinder/ETSBinder.h" #include "checker/ETSchecker.h" -#include "checker/ets/function_helpers.h" +#include "checker/ets/functionHelpers.h" #include "checker/ets/typeRelationContext.h" #include "checker/types/ets/etsAwaitedType.h" #include "checker/types/ets/etsObjectType.h" @@ -208,73 +208,6 @@ bool ETSChecker::ProcessUntypedParameter(ir::AstNode *declNode, size_t paramInde return true; } -static void RemoveInvalidTypeMarkers(ir::AstNode *node) noexcept -{ - std::function doNode = [&](ir::AstNode *nn) { - if (nn->IsTyped() && !(nn->IsExpression() && nn->AsExpression()->IsTypeNode()) && - nn->AsTyped()->TsType() != nullptr && nn->AsTyped()->TsType()->IsTypeError()) { - nn->AsTyped()->SetTsType(nullptr); - } - if (nn->IsIdentifier() && nn->AsIdentifier()->TsType() != nullptr && - nn->AsIdentifier()->TsType()->IsTypeError()) { - nn->AsIdentifier()->SetVariable(nullptr); - } - if (!nn->IsETSTypeReference()) { - nn->Iterate([&](ir::AstNode *child) { doNode(child); }); - } - }; - - doNode(node); -} - -static void ResetInferredTypeInArrowBody(ir::AstNode *body, ETSChecker *checker, - std::unordered_set &inferredVarSet) -{ - std::function doNode = [&](ir::AstNode *node) { - if (node->IsIdentifier()) { - auto *id = node->AsIdentifier(); - if (inferredVarSet.count(id->Variable()) == 0U) { - return; - } - - id->Check(checker); - if (auto *parent = id->Parent(); parent->IsMemberExpression()) { - parent->AsMemberExpression()->Check(checker); - } - } - if (node->IsVariableDeclarator()) { - auto *id = node->AsVariableDeclarator()->Id(); - inferredVarSet.emplace(id->Variable()); - node->Check(checker); - } - }; - body->IterateRecursively(doNode); -} - -static void ResetInferredNode(ETSChecker *checker, std::unordered_set &inferredVarSet) -{ - auto relation = checker->Relation(); - auto resetFuncState = [](ir::ArrowFunctionExpression *expr) { - auto *func = expr->Function(); - func->SetSignature(nullptr); - func->ClearReturnStatements(); - expr->SetTsType(nullptr); - }; - - const bool hasValidNode = relation->GetNode() != nullptr && relation->GetNode()->IsArrowFunctionExpression(); - if (!checker->HasStatus(CheckerStatus::IN_TYPE_INFER) || !hasValidNode) { - return; - } - - auto *arrowFunc = relation->GetNode()->AsArrowFunctionExpression(); - relation->SetNode(nullptr); - - RemoveInvalidTypeMarkers(arrowFunc); - ResetInferredTypeInArrowBody(arrowFunc->Function()->Body(), checker, inferredVarSet); - resetFuncState(arrowFunc); - arrowFunc->Check(checker); -} - bool ETSChecker::EnhanceSubstitutionForNonNullish(const ArenaVector &typeParams, ETSNonNullishType *paramType, Type *argumentType, Substitution *substitution) { @@ -331,8 +264,6 @@ bool ETSChecker::EnhanceSubstitutionForFunction(const ArenaVector &typeP res &= enhance(paramSig->Params()[idx]->TsType(), argSig->Params()[idx]->TsType()); } - ResetInferredNode(this, inferredVarSet); - if (argSig->HasRestParameter() && paramSig->HasRestParameter()) { res &= enhance(paramSig->RestVar()->TsType(), argSig->RestVar()->TsType()); } @@ -572,7 +503,7 @@ bool ETSChecker::ValidateSignatureRequiredParams(Signature *substitutedSig, commonArity = commonArity - 1; } for (size_t index = 0; index < commonArity; ++index) { - auto &argument = arguments[index]; + auto argument = arguments[index]; // #22952: infer optional parameter heuristics auto const paramType = GetNonNullishType(substitutedSig->Params()[index]->TsType()); @@ -629,10 +560,16 @@ bool ETSChecker::ValidateSignatureRequiredParams(Signature *substitutedSig, bool ETSChecker::ValidateSignatureInvocationContext(Signature *substitutedSig, ir::Expression *argument, std::size_t index, TypeRelationFlag flags) { + SavedTypeRelationFlagsContext rctx {Relation(), flags}; Type *targetType = substitutedSig->Params()[index]->TsType(); + argument->SetPreferredType(targetType); // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) Type *argumentType = argument->Check(this); + if (argumentType->IsTypeError()) { + return false; + } + flags |= (TypeRelationFlag::ONLY_CHECK_WIDENING); auto const invocationCtx = @@ -865,7 +802,7 @@ ArenaVector ETSChecker::CollectSignatures(ArenaVector Signature *notVisibleSignature = nullptr; if (signatures.size() > 1) { - resolveFlags |= TypeRelationFlag::OVERLOADING_CONTEXT; + resolveFlags |= TypeRelationFlag::OVERLOADING_CONTEXT | TypeRelationFlag::NO_THROW; } auto collectSignatures = [&](TypeRelationFlag relationFlags) { @@ -878,6 +815,15 @@ ArenaVector ETSChecker::CollectSignatures(ArenaVector // Bridges are never invoked direcly continue; } + if (signatures.size() > 1 && !HasStatus(CheckerStatus::TYPES_ARE_STABLE)) { + for (auto *arg : arguments) { + if (sig->IsExtensionFunction() && arg == arguments.front()) { + // Type of extension receiver is computed before determining which extenstion function to call. + continue; + } + RemoveTypeMarkers(arg); + } + } // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) auto *concreteSig = ValidateSignature(std::make_tuple(sig, typeArguments, relationFlags), arguments, pos, argTypeInferenceRequired, signatures.size() == 1); @@ -1565,8 +1511,9 @@ static bool CollectOverload(checker::ETSChecker *checker, ir::MethodDefinition * ES2PANDA_ASSERT(currentFunc->Function() != nullptr); ES2PANDA_ASSERT(currentFunc->Id() != nullptr); currentFunc->Function()->Id()->SetVariable(currentFunc->Id()->Variable()); - checker->BuildFunctionSignature(currentFunc->Function(), method->IsConstructor()); - if (currentFunc->Function()->Signature() == nullptr) { + auto *overloadSig = checker->BuildFunctionSignature(currentFunc->Function(), method->IsConstructor()); + currentFunc->Function()->SetSignature(overloadSig); + if (overloadSig == nullptr) { auto *methodId = method->Id(); ES2PANDA_ASSERT(methodId != nullptr); methodId->Variable()->SetTsType(checker->GlobalTypeError()); @@ -1582,7 +1529,6 @@ static bool CollectOverload(checker::ETSChecker *checker, ir::MethodDefinition * currentFunc->SetTsType(overloadType); } - auto overloadSig = currentFunc->Function()->Signature(); funcType->AddCallSignature(overloadSig); if (overloadSig->IsExtensionAccessor()) { funcType->GetExtensionAccessorSigs().emplace_back(overloadSig); @@ -1621,8 +1567,9 @@ checker::Type *ETSChecker::BuildMethodSignature(ir::MethodDefinition *method) return methodId->Variable()->SetTsType(GlobalTypeError()); } method->Function()->Id()->SetVariable(methodId->Variable()); - BuildFunctionSignature(method->Function(), method->IsConstructor()); - if (method->Function()->Signature() == nullptr) { + auto *signature = BuildFunctionSignature(method->Function(), method->IsConstructor()); + method->Function()->SetSignature(signature); + if (signature == nullptr) { return methodId->Variable()->SetTsType(GlobalTypeError()); } auto *funcType = BuildMethodType(method->Function()); @@ -1724,7 +1671,7 @@ static varbinder::LocalVariable *SetupSignatureParameter(ir::ETSParameterExpress // Should be moved to original ComposeSignatureInfo after AST fix static bool AppendSignatureInfoParam(ETSChecker *checker, SignatureInfo *sigInfo, ir::ETSParameterExpression *param) { - auto variable = SetupSignatureParameter(param, [checker, param]() { + auto variable = SetupSignatureParameter(param, [checker, param]() -> Type * { if (param->TypeAnnotation() != nullptr) { auto type = param->TypeAnnotation()->GetType(checker); return param->IsOptional() ? checker->CreateETSUnionType({type, checker->GlobalETSUndefinedType()}) : type; @@ -1739,7 +1686,7 @@ static bool AppendSignatureInfoParam(ETSChecker *checker, SignatureInfo *sigInfo return checker->GlobalTypeError(); }()); - if (variable == nullptr) { // #23134 + if (variable == nullptr || variable->TsType()->IsTypeError()) { // #23134 return false; } if (param->IsRestParameter()) { @@ -1775,7 +1722,7 @@ SignatureInfo *ETSChecker::ComposeSignatureInfo(ir::TSTypeParameterDeclaration * for (auto *const p : params) { if (!p->IsETSParameterExpression() || !AppendSignatureInfoParam(this, signatureInfo, p->AsETSParameterExpression())) { // #23134 - ES2PANDA_ASSERT(IsAnyError()); + ES2PANDA_ASSERT(HasStatus(checker::CheckerStatus::IN_TYPE_INFER) || IsAnyError()); return nullptr; } } @@ -1825,20 +1772,20 @@ void ETSChecker::ValidateMainSignature(ir::ScriptFunction *func) } } -void ETSChecker::BuildFunctionSignature(ir::ScriptFunction *func, bool isConstructSig) +Signature *ETSChecker::BuildFunctionSignature(ir::ScriptFunction *func, bool isConstructSig) { ES2PANDA_ASSERT(func != nullptr); bool isArrow = func->IsArrow(); // note(Ekko): For extenal function overload, need to not change ast tree, for arrow type, need perferred type. if (func->Signature() != nullptr && !isArrow) { - return; + return func->Signature(); } auto *nameVar = isArrow ? nullptr : func->Id()->Variable(); auto funcName = nameVar == nullptr ? util::StringView() : nameVar->Name(); if (func->IsConstructor() && func->IsStatic()) { LogError(diagnostic::INVALID_DECORATOR_CONSTRUCTOR, {}, func->Start()); - return; + return nullptr; } if ((func->IsConstructor() || !func->IsStatic()) && !func->IsArrow()) { @@ -1846,17 +1793,19 @@ void ETSChecker::BuildFunctionSignature(ir::ScriptFunction *func, bool isConstru thisVar->SetTsType(Context().ContainingClass()); } auto *signatureInfo = ComposeSignatureInfo(func->TypeParams(), func->Params()); + if (signatureInfo == nullptr) { + ES2PANDA_ASSERT(HasStatus(checker::CheckerStatus::IN_TYPE_INFER) || IsAnyError()); + return nullptr; + } auto *returnType = func->GetPreferredReturnType() != nullptr ? func->GetPreferredReturnType() : ComposeReturnType(func->ReturnTypeAnnotation(), func->IsAsyncFunc()); auto *signature = ComposeSignature(func, signatureInfo, returnType, nameVar); if (signature == nullptr) { // #23134 ES2PANDA_ASSERT(IsAnyError()); - return; + return nullptr; } - func->SetSignature(signature); - if (isConstructSig) { signature->AddSignatureFlag(SignatureFlags::CONSTRUCT); } else { @@ -1871,8 +1820,11 @@ void ETSChecker::BuildFunctionSignature(ir::ScriptFunction *func, bool isConstru ValidateMainSignature(func); } + func->SetSignature(signature); VarBinder()->AsETSBinder()->BuildFunctionName(func); Program()->AddToFunctionScopes(func->Scope()); + + return signature; } checker::ETSFunctionType *ETSChecker::BuildMethodType(ir::ScriptFunction *func) @@ -2133,9 +2085,9 @@ bool ETSChecker::CheckOverride(Signature *signature, ETSObjectType *site) void ETSChecker::CheckOverride(Signature *signature) { - ES2PANDA_ASSERT(signature != nullptr); + ERROR_SANITY_CHECK(this, signature != nullptr, return); auto *owner = signature->Owner(); - ES2PANDA_ASSERT(owner != nullptr); + ERROR_SANITY_CHECK(this, owner != nullptr, return); bool isOverriding = false; if (!owner->HasObjectFlag(ETSObjectFlags::CLASS | ETSObjectFlags::INTERFACE)) { diff --git a/ets2panda/checker/ets/function_helpers.h b/ets2panda/checker/ets/functionHelpers.cpp similarity index 74% rename from ets2panda/checker/ets/function_helpers.h rename to ets2panda/checker/ets/functionHelpers.cpp index 5ed15b1336a4c79b5ed7a65fc168c87745bec14c..74fceb57f71544b093d975ae99f79bc4a278fc52 100644 --- a/ets2panda/checker/ets/function_helpers.h +++ b/ets2panda/checker/ets/functionHelpers.cpp @@ -13,9 +13,7 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_CHECKER_ETS_FUNCTION_HELPERS_H -#define ES2PANDA_COMPILER_CHECKER_ETS_FUNCTION_HELPERS_H - +#include "checker/ets/functionHelpers.h" #include "checker/ETSchecker.h" #include "checker/ets/typeRelationContext.h" #include "checker/types/ets/etsObjectType.h" @@ -42,17 +40,15 @@ #include "parser/program/program.h" #include "libarkbase/utils/arena_containers.h" #include "util/helpers.h" -#include "util/language.h" #include "varbinder/declaration.h" #include "varbinder/ETSBinder.h" #include "varbinder/scope.h" #include "varbinder/varbinder.h" #include "varbinder/variable.h" -#include "varbinder/variableFlags.h" namespace ark::es2panda::checker { -static Type *MaybeBoxedType(ETSChecker *checker, Type *type, ir::Expression *expr) +Type *MaybeBoxedType(ETSChecker *checker, Type *type, ir::Expression *expr) { ES2PANDA_ASSERT(type != nullptr); if (!type->IsETSPrimitiveType()) { @@ -66,8 +62,33 @@ static Type *MaybeBoxedType(ETSChecker *checker, Type *type, ir::Expression *exp return res; } -static void InferUntilFail(Signature const *const signature, const ArenaVector &arguments, - ETSChecker *checker, Substitution *substitution) +void RemoveTypeMarkers(ir::AstNode *node) noexcept +{ + std::function doNode = [&](ir::AstNode *nn) { + if (nn->IsETSTypeReference() || nn->IsOpaqueTypeNode()) { + return; + } + if (nn->IsIdentifier()) { // NOTE(gogabr): subject to smart casts, + // which we cannot reproduce yet. + return; + } + if (nn->IsTyped()) { + nn->AsTyped()->SetTsType(nullptr); + } + if (nn->IsArrowFunctionExpression()) { + auto *func = nn->AsArrowFunctionExpression()->Function(); + func->SetSignature(nullptr); + func->ClearReturnStatements(); + } + + nn->Iterate([&](ir::AstNode *child) { doNode(child); }); + }; + + doNode(node); +} + +void InferUntilFail(Signature const *const signature, const ArenaVector &arguments, + ETSChecker *checker, Substitution *substitution) { auto *sigInfo = signature->GetSignatureInfo(); auto &sigParams = signature->GetSignatureInfo()->typeParams; @@ -79,6 +100,7 @@ static void InferUntilFail(Signature const *const signature, const ArenaVectorAddStatus(checker::CheckerStatus::IN_TYPE_INFER); // some ets lib files require type infer from arg index 0,1,... , not fit to build graph ES2PANDA_ASSERT(substitution != nullptr); + while (anyChange && substitution->size() < sigParams.size()) { anyChange = false; for (size_t ix = 0; ix < arguments.size(); ++ix) { @@ -91,13 +113,24 @@ static void InferUntilFail(Signature const *const signature, const ArenaVectorArgCount()) { + paramType = sigInfo->params[ix]->TsType(); + } else if (sigInfo->restVar != nullptr && arg->IsSpreadElement()) { + paramType = sigInfo->restVar->TsType(); + } else if (sigInfo->restVar != nullptr) { + paramType = checker->GetElementTypeOfArray(sigInfo->restVar->TsType()); + } + if (paramType == nullptr) { + return; // The signature is non-applicable in any case, will fail later. + } + paramType = paramType->Substitute(checker->Relation(), substitution); + arg->SetPreferredType(paramType); + auto *const argType = arg->IsSpreadElement() ? MaybeBoxedType(checker, arg->AsSpreadElement()->Argument()->Check(checker), arg->AsSpreadElement()->Argument()) : MaybeBoxedType(checker, arg->Check(checker), arg); - auto *const paramType = (ix < signature->ArgCount()) ? sigInfo->params[ix]->TsType() - : sigInfo->restVar != nullptr ? sigInfo->restVar->TsType() - : nullptr; if (paramType == nullptr) { continue; @@ -115,18 +148,29 @@ static void InferUntilFail(Signature const *const signature, const ArenaVectorRemoveStatus(checker::CheckerStatus::IN_TYPE_INFER); } -static std::optional BuildImplicitSubstitutionForArguments(ETSChecker *checker, Signature *signature, - const ArenaVector &arguments) +std::optional BuildImplicitSubstitutionForArguments(ETSChecker *checker, Signature *signature, + const ArenaVector &arguments) { auto substitution = Substitution {}; auto *sigInfo = signature->GetSignatureInfo(); auto &sigParams = signature->GetSignatureInfo()->typeParams; + for (auto *param : sigParams) { + ES2PANDA_ASSERT(param->IsETSTypeParameter()); + checker->AddDerivedTypeParameter(param->AsETSTypeParameter()); + } + InferUntilFail(signature, arguments, checker, &substitution); + for (auto *param : sigParams) { + ES2PANDA_ASSERT(param->IsETSTypeParameter()); + checker->RemoveDerivedTypeParameter(param->AsETSTypeParameter()); + } + if (substitution.size() != sigParams.size()) { for (const auto typeParam : sigParams) { auto newTypeParam = typeParam->AsETSTypeParameter(); @@ -151,13 +195,18 @@ static std::optional BuildImplicitSubstitutionForArguments(ETSChec return std::nullopt; } + /* Clean up argument types; they will need to be re-checked with new substituted context */ + for (auto *arg : arguments) { + RemoveTypeMarkers(arg); + } + return substitution; } -static std::optional BuildExplicitSubstitutionForArguments(ETSChecker *checker, Signature *signature, - const ArenaVector ¶ms, - const lexer::SourcePosition &pos, - TypeRelationFlag flags) +std::optional BuildExplicitSubstitutionForArguments(ETSChecker *checker, Signature *signature, + const ArenaVector ¶ms, + const lexer::SourcePosition &pos, + TypeRelationFlag flags) { auto &sigParams = signature->GetSignatureInfo()->typeParams; auto substitution = Substitution {}; @@ -195,13 +244,14 @@ static std::optional BuildExplicitSubstitutionForArguments(ETSChec } checker->EmplaceSubstituted(&substitution, sigParams[ix]->AsETSTypeParameter(), instArgs[ix]); } + return substitution; } -static Signature *MaybeSubstituteTypeParameters(ETSChecker *checker, Signature *signature, - const ir::TSTypeParameterInstantiation *typeArguments, - const ArenaVector &arguments, - const lexer::SourcePosition &pos, TypeRelationFlag flags) +Signature *MaybeSubstituteTypeParameters(ETSChecker *checker, Signature *signature, + const ir::TSTypeParameterInstantiation *typeArguments, + const ArenaVector &arguments, + const lexer::SourcePosition &pos, TypeRelationFlag flags) { if (typeArguments == nullptr && signature->GetSignatureInfo()->typeParams.empty()) { return signature; @@ -215,8 +265,7 @@ static Signature *MaybeSubstituteTypeParameters(ETSChecker *checker, Signature * return (!substitution.has_value()) ? nullptr : signature->Substitute(checker->Relation(), &substitution.value()); } -static bool CheckInterfaceOverride(ETSChecker *const checker, ETSObjectType *const interface, - Signature *const signature) +bool CheckInterfaceOverride(ETSChecker *const checker, ETSObjectType *const interface, Signature *const signature) { bool isOverriding = checker->CheckOverride(signature, interface); @@ -227,7 +276,7 @@ static bool CheckInterfaceOverride(ETSChecker *const checker, ETSObjectType *con return isOverriding; } -static varbinder::Scope *NodeScope(ir::AstNode *ast) +varbinder::Scope *NodeScope(ir::AstNode *ast) { if (ast->IsBlockStatement()) { return ast->AsBlockStatement()->Scope(); @@ -266,5 +315,3 @@ static varbinder::Scope *NodeScope(ir::AstNode *ast) } } // namespace ark::es2panda::checker - -#endif diff --git a/ets2panda/checker/ets/functionHelpers.h b/ets2panda/checker/ets/functionHelpers.h new file mode 100644 index 0000000000000000000000000000000000000000..8a5ed45b503fa77942c1b310d5c549b19f1b2983 --- /dev/null +++ b/ets2panda/checker/ets/functionHelpers.h @@ -0,0 +1,67 @@ +/* + * 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 + * + * 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_ETS_FUNCTION_HELPERS_H +#define ES2PANDA_COMPILER_CHECKER_ETS_FUNCTION_HELPERS_H + +#include "checker/ETSchecker.h" +#include "checker/ets/typeRelationContext.h" +#include "checker/types/ets/etsObjectType.h" +#include "checker/types/type.h" +#include "ir/base/catchClause.h" +#include "ir/base/classDefinition.h" +#include "ir/base/classProperty.h" +#include "ir/base/methodDefinition.h" +#include "ir/base/scriptFunction.h" +#include "ir/expressions/callExpression.h" +#include "ir/expressions/memberExpression.h" +#include "ir/statements/doWhileStatement.h" +#include "ir/statements/expressionStatement.h" +#include "ir/statements/forInStatement.h" +#include "ir/statements/forOfStatement.h" +#include "ir/statements/forUpdateStatement.h" +#include "ir/statements/switchStatement.h" +#include "ir/statements/whileStatement.h" +#include "ir/ts/tsTypeParameterInstantiation.h" +#include "libarkbase/utils/arena_containers.h" +#include "util/helpers.h" +#include "varbinder/declaration.h" +#include "varbinder/ETSBinder.h" +#include "varbinder/scope.h" +#include "varbinder/varbinder.h" +#include "varbinder/variable.h" + +namespace ark::es2panda::checker { + +Type *MaybeBoxedType(ETSChecker *checker, Type *type, ir::Expression *expr); +void RemoveTypeMarkers(ir::AstNode *node) noexcept; +void InferUntilFail(Signature const *const signature, const ArenaVector &arguments, + ETSChecker *checker, Substitution *substitution); +std::optional BuildImplicitSubstitutionForArguments(ETSChecker *checker, Signature *signature, + const ArenaVector &arguments); +std::optional BuildExplicitSubstitutionForArguments(ETSChecker *checker, Signature *signature, + const ArenaVector ¶ms, + const lexer::SourcePosition &pos, + TypeRelationFlag flags); +Signature *MaybeSubstituteTypeParameters(ETSChecker *checker, Signature *signature, + const ir::TSTypeParameterInstantiation *typeArguments, + const ArenaVector &arguments, + const lexer::SourcePosition &pos, TypeRelationFlag flags); +bool CheckInterfaceOverride(ETSChecker *const checker, ETSObjectType *const interface, Signature *const signature); +varbinder::Scope *NodeScope(ir::AstNode *ast); + +} // namespace ark::es2panda::checker + +#endif diff --git a/ets2panda/checker/ets/helpers.cpp b/ets2panda/checker/ets/helpers.cpp index 8f730c9e1ca764f20d13b5f4ec8e5a4ac7ec48ef..d8c5005b163e9e68d510c453dfb21052dd16d24a 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -613,51 +613,6 @@ static void SetTypeforLambdaParamWithoutTypeAnnotation(ir::ETSParameterExpressio lambdaParam->SetTsType(type); } -void ETSChecker::InferLambdaInAssignmentExpression(ir::AssignmentExpression *const expr) -{ - auto *left = expr->Left(); - auto *right = expr->Right(); - - if (!right->IsArrowFunctionExpression()) { - return; - } - - if (left->TsType() == nullptr || !left->TsType()->IsETSFunctionType() || - left->TsType()->AsETSFunctionType()->CallSignaturesOfMethodOrArrow().empty()) { - return; - } - - ArenaVector lambdaParams = right->AsArrowFunctionExpression()->Function()->Params(); - Signature *sig = left->TsType()->AsETSFunctionType()->CallSignaturesOfMethodOrArrow()[0]; - - size_t paramCount = sig->Params().size(); - if (sig->RestVar() != nullptr) { - paramCount++; - } - - if (paramCount != lambdaParams.size()) { - return; - } - - if (std::any_of(lambdaParams.begin(), lambdaParams.end(), - [](auto ¶m) { return !param->IsETSParameterExpression(); })) { - return; - } - - if (sig->RestVar() != nullptr) { - if (!lambdaParams.back()->AsETSParameterExpression()->IsRestParameter()) { - return; - } - SetTypeforLambdaParamWithoutTypeAnnotation(lambdaParams.back()->AsETSParameterExpression(), - sig->RestVar()->TsType()); - paramCount--; - } - for (size_t i = 0; i < paramCount; i++) { - auto *inferredType = sig->Params()[i]->TsType(); - SetTypeforLambdaParamWithoutTypeAnnotation(lambdaParams[i]->AsETSParameterExpression(), inferredType); - } -} - void ETSChecker::InferAliasLambdaType(ir::TypeNode *localTypeAnnotation, ir::ArrowFunctionExpression *init) { ES2PANDA_ASSERT(localTypeAnnotation != nullptr); @@ -734,8 +689,8 @@ checker::Type *PreferredObjectTypeFromAnnotation(checker::Type *annotationType) } // CC-OFFNXT(huge_cyclomatic_complexity, huge_cca_cyclomatic_complexity[C++]) solid logic -static bool SetPreferredTypeForExpression(ETSChecker *checker, ir::Identifier *ident, ir::TypeNode *typeAnnotation, - ir::Expression *init, checker::Type *annotationType) +static bool SetPreferredTypeForExpression(ETSChecker *checker, ir::Identifier *ident, ir::Expression *init, + checker::Type *annotationType) { if (init->IsMemberExpression() && init->AsMemberExpression()->Object()->IsObjectExpression()) { checker->LogError(diagnostic::MEMBER_OF_OBJECT_LIT, {}, ident->Start()); @@ -754,44 +709,9 @@ static bool SetPreferredTypeForExpression(ETSChecker *checker, ir::Identifier *i !checker->IsArrayExprSizeValidForTuple(init->AsArrayExpression(), annotationType->AsETSTupleType())) { return false; } - - init->AsArrayExpression()->SetPreferredType(annotationType); } - if (init->IsObjectExpression() && annotationType != nullptr) { - init->SetPreferredType(PreferredObjectTypeFromAnnotation(annotationType)); - } - - if (init->IsETSNewArrayInstanceExpression() && annotationType != nullptr) { - init->SetPreferredType(annotationType); - } - if (init->IsETSNewMultiDimArrayInstanceExpression() && annotationType != nullptr) { - init->SetPreferredType(annotationType); - } - if (init->IsNumberLiteral() && annotationType != nullptr) { - init->SetPreferredType(annotationType); - } - if (init->IsBinaryExpression() && annotationType != nullptr) { - auto *binExpr = init->AsBinaryExpression(); - if (binExpr->OperatorType() == lexer::TokenType::PUNCTUATOR_NULLISH_COALESCING && - !binExpr->Right()->IsLiteral()) { - binExpr->Right()->SetPreferredType(annotationType); - } - } - if (init->IsConditionalExpression() && annotationType != nullptr) { - auto *conditionalExpr = init->AsConditionalExpression(); - if (!conditionalExpr->Consequent()->IsLiteral()) { - conditionalExpr->Consequent()->SetPreferredType(annotationType); - } - if (!conditionalExpr->Alternate()->IsLiteral()) { - conditionalExpr->Alternate()->SetPreferredType(annotationType); - } - } - - if (typeAnnotation != nullptr && init->IsArrowFunctionExpression()) { - // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - checker->InferAliasLambdaType(typeAnnotation, init->AsArrowFunctionExpression()); - } + init->SetPreferredType(annotationType); return true; } @@ -820,7 +740,7 @@ bool ETSChecker::CheckInit(ir::Identifier *ident, ir::TypeNode *typeAnnotation, bindingVar->SetTsType(annotationType); } } - return SetPreferredTypeForExpression(this, ident, typeAnnotation, init, annotationType); + return SetPreferredTypeForExpression(this, ident, init, annotationType); } void ETSChecker::CheckEnumType(ir::Expression *init, checker::Type *initType, const util::StringView &varName) @@ -1987,11 +1907,13 @@ checker::Type *ETSChecker::GetElementTypeOfArray(checker::Type *type) const if (type->IsETSResizableArrayType()) { return type->AsETSResizableArrayType()->ElementType(); } - if (type->IsETSReadonlyArrayType()) { + /* Some other supertype of array, such as ReadonlyArray or ConcatArray */ + if (type->IsETSObjectType() && type->AsETSObjectType()->TypeArguments().size() == 1) { auto const &typeArgs = type->AsETSObjectType()->TypeArguments(); ES2PANDA_ASSERT(!typeArgs.empty()); return typeArgs.front(); } + ES2PANDA_UNREACHABLE(); } @@ -2716,16 +2638,32 @@ void ETSChecker::InferTypesForLambda(ir::ScriptFunction *lambda, ir::ETSFunction void ETSChecker::InferTypesForLambda(ir::ScriptFunction *lambda, Signature *signature) { - ES2PANDA_ASSERT(signature->Params().size() >= lambda->Params().size()); + [[maybe_unused]] auto nSigParams = signature->Params().size(); + if (lambda->Params().size() > 0 && lambda->Params().back()->IsETSParameterExpression() && + lambda->Params().back()->AsETSParameterExpression()->IsRestParameter()) { + nSigParams++; + } + ES2PANDA_ASSERT(nSigParams >= lambda->Params().size()); + for (size_t i = 0; i < lambda->Params().size(); ++i) { if (!lambda->Params().at(i)->IsETSParameterExpression()) { LogError(diagnostic::INVALID_LAMBDA_PARAMETER, lambda->Params().at(i)->Start()); continue; } - auto *const lambdaParam = lambda->Params().at(i)->AsETSParameterExpression()->Ident(); - if (lambdaParam->TypeAnnotation() == nullptr) { - lambdaParam->Variable()->SetTsType(signature->Params().at(i)->TsType()); - lambdaParam->SetTsType(signature->Params().at(i)->TsType()); + auto *const lambdaParam = lambda->Params().at(i)->AsETSParameterExpression(); + + if (lambdaParam->IsRestParameter()) { + auto *spreadIdent = lambdaParam->Spread()->Argument()->AsIdentifier(); + if (spreadIdent->TypeAnnotation() == nullptr && signature->RestVar() != nullptr) { + spreadIdent->Variable()->SetTsType(signature->RestVar()->TsType()); + spreadIdent->SetTsType(signature->RestVar()->TsType()); + } + } else { + auto *lambdaParamIdent = lambdaParam->Ident(); + if (lambdaParamIdent->TypeAnnotation() == nullptr) { + lambdaParamIdent->Variable()->SetTsType(signature->Params().at(i)->TsType()); + lambdaParamIdent->SetTsType(signature->Params().at(i)->TsType()); + } } } @@ -2747,7 +2685,7 @@ void ETSChecker::ModifyPreferredType(ir::ArrayExpression *const arrayExpr, Type } } -void ETSChecker::TryInferTypeForLambdaTypeAlias(ir::ArrowFunctionExpression *expr, ETSFunctionType *calleeType) +bool ETSChecker::TryInferTypeForLambda(ir::ArrowFunctionExpression *expr, ETSFunctionType *calleeType) { ES2PANDA_ASSERT(expr->IsArrowFunctionExpression()); ES2PANDA_ASSERT(calleeType->IsETSArrowType()); @@ -2755,9 +2693,21 @@ void ETSChecker::TryInferTypeForLambdaTypeAlias(ir::ArrowFunctionExpression *exp ir::ScriptFunction *const lambda = expr->AsArrowFunctionExpression()->Function(); auto *signature = calleeType->CallSignaturesOfMethodOrArrow()[0]; - if (signature->Params().size() >= lambda->Params().size() && NeedTypeInference(lambda)) { + auto nLambdaParams = lambda->Params().size(); + if (nLambdaParams > 0 && lambda->Params().back()->IsETSParameterExpression() && + lambda->Params().back()->AsETSParameterExpression()->IsRestParameter()) { + nLambdaParams--; + } + + if (signature->Params().size() < nLambdaParams) { + return false; + } + + if (NeedTypeInference(lambda)) { InferTypesForLambda(lambda, signature); } + + return true; } bool ETSChecker::IsInLocalClass(const ir::AstNode *node) const @@ -3407,4 +3357,19 @@ checker::ETSFunctionType *ETSChecker::IntersectSignatureSets(const checker::ETSF return CreateETSMethodType(left->Name(), std::move(intersection)); } +void ETSChecker::AddDerivedTypeParameter(ETSTypeParameter *tp) +{ + typeParametersBeingDerived_.insert(tp); +} + +void ETSChecker::RemoveDerivedTypeParameter(ETSTypeParameter *tp) +{ + typeParametersBeingDerived_.erase(tp); +} + +bool ETSChecker::IsTypeParameterBeingDerived(ETSTypeParameter *tp) +{ + return typeParametersBeingDerived_.count(tp) > 0; +} + } // namespace ark::es2panda::checker diff --git a/ets2panda/checker/ets/typeCheckingHelpers.cpp b/ets2panda/checker/ets/typeCheckingHelpers.cpp index a2894f93e9dab21b104b933b552fd15bad16bf04..066ae54b3a0c70fc9baf4d1a27ee321617850fc8 100644 --- a/ets2panda/checker/ets/typeCheckingHelpers.cpp +++ b/ets2panda/checker/ets/typeCheckingHelpers.cpp @@ -1588,6 +1588,7 @@ bool ETSChecker::ResolveLambdaArgumentType(Signature *signature, ir::Expression auto *const param = signature->GetSignatureInfo()->params[paramPosition]->Declaration()->Node()->AsETSParameterExpression(); Type *const parameterType = signature->Params()[paramPosition]->TsType(); + arrowFuncExpr->SetPreferredType(parameterType); // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) bool rc = CheckLambdaTypeAnnotation(param, arrowFuncExpr, parameterType, resolutionFlags); diff --git a/ets2panda/checker/types/ets/etsTypeParameter.cpp b/ets2panda/checker/types/ets/etsTypeParameter.cpp index 53c70fcfcc2cc884654aae6c0b78e1453262d4a5..90682e9f47828923368f6d841e763436aedba49c 100644 --- a/ets2panda/checker/types/ets/etsTypeParameter.cpp +++ b/ets2panda/checker/types/ets/etsTypeParameter.cpp @@ -30,6 +30,11 @@ void ETSTypeParameter::ToString(std::stringstream &ss, bool precise) const void ETSTypeParameter::Identical(TypeRelation *relation, Type *other) { + if (relation->GetChecker()->AsETSChecker()->IsTypeParameterBeingDerived(this)) { + // We are optimistically assuming the needed relation + relation->Result(true); + return; + } relation->Result(false); if (other->IsETSTypeParameter() && other->AsETSTypeParameter()->GetOriginal() == GetOriginal()) { relation->Result(true); @@ -76,11 +81,22 @@ void ETSTypeParameter::CastTarget(TypeRelation *relation, Type *source) void ETSTypeParameter::IsSupertypeOf(TypeRelation *relation, [[maybe_unused]] Type *source) { + if (relation->GetChecker()->AsETSChecker()->IsTypeParameterBeingDerived(this)) { + // We are optimistically assuming the needed relation + relation->Result(true); + return; + } relation->Result(false); } void ETSTypeParameter::IsSubtypeOf(TypeRelation *relation, Type *target) { + if (relation->GetChecker()->AsETSChecker()->IsTypeParameterBeingDerived(this)) { + // We are optimistically assuming the needed relation + relation->Result(true); + return; + } + if (relation->IsSupertypeOf(target, GetConstraintType())) { return; } diff --git a/ets2panda/checker/types/ets/etsUnionType.cpp b/ets2panda/checker/types/ets/etsUnionType.cpp index 1fee41b8f8ec7dcaa9700b3aee19b68f4eb6818d..a3a27e561fb5e2574254b45e9e56d209be6aae60 100644 --- a/ets2panda/checker/types/ets/etsUnionType.cpp +++ b/ets2panda/checker/types/ets/etsUnionType.cpp @@ -18,6 +18,7 @@ #include "etsUnionType.h" #include "checker/ets/conversion.h" #include "checker/types/ets/etsTupleType.h" +#include "checker/types/ets/etsPartialTypeParameter.h" #include "checker/types/globalTypesHolder.h" #include "checker/ETSchecker.h" @@ -251,11 +252,62 @@ void ETSUnionType::CastTarget(TypeRelation *relation, Type *source) RelationTarget(relation, source, relFn); } +static bool ContainsTypeParameterBeingDerived(ETSChecker *checker, Type *tp) +{ + auto const &containsRecCall = [checker](Type *tt) -> bool { + return ContainsTypeParameterBeingDerived(checker, tt); + }; + + if (tp->IsETSTypeParameter()) { + return checker->IsTypeParameterBeingDerived(tp->AsETSTypeParameter()); + } + if (tp->IsETSObjectType()) { + return std::any_of(tp->AsETSObjectType()->TypeArguments().begin(), tp->AsETSObjectType()->TypeArguments().end(), + containsRecCall); + } + if (tp->IsETSUnionType()) { + return tp->AsETSUnionType()->AnyOfConstituentTypes(containsRecCall); + } + if (tp->IsETSArrayType()) { + return ContainsTypeParameterBeingDerived(checker, tp->AsETSArrayType()->ElementType()); + } + if (tp->IsETSResizableArrayType()) { + return ContainsTypeParameterBeingDerived(checker, tp->AsETSResizableArrayType()->ElementType()); + } + if (tp->IsETSFunctionType()) { + ES2PANDA_ASSERT(tp->IsETSArrowType()); + auto *sig = tp->AsETSFunctionType()->ArrowSignature(); + return ContainsTypeParameterBeingDerived(checker, sig->ReturnType()) || + std::any_of(sig->Params().begin(), sig->Params().end(), [checker](varbinder::Variable *v) -> bool { + return v->TsType() != nullptr && ContainsTypeParameterBeingDerived(checker, v->TsType()); + }); + } + if (tp->IsETSNonNullishType()) { + return ContainsTypeParameterBeingDerived(checker, tp->AsETSNonNullishType()->GetUnderlying()); + } + if (tp->IsETSPartialTypeParameter()) { + return ContainsTypeParameterBeingDerived(checker, tp->AsETSPartialTypeParameter()->GetUnderlying()); + } + if (tp->IsETSReadonlyType()) { + return ContainsTypeParameterBeingDerived(checker, tp->AsETSReadonlyType()->GetUnderlying()); + } + if (tp->IsETSTupleType()) { + return std::any_of(tp->AsETSTupleType()->GetTupleTypesList().begin(), + tp->AsETSTupleType()->GetTupleTypesList().end(), containsRecCall); + } + return false; +} + static std::optional TryMergeTypes(TypeRelation *relation, Type *const t1, Type *const t2) { auto *const checker = relation->GetChecker()->AsETSChecker(); auto *const never = checker->GetGlobalTypesHolder()->GlobalETSNeverType(); + if (ContainsTypeParameterBeingDerived(relation->GetChecker()->AsETSChecker(), t1) || + ContainsTypeParameterBeingDerived(relation->GetChecker()->AsETSChecker(), t2)) { + return std::nullopt; + } + if (relation->IsSupertypeOf(t1, t2) || t2 == never) { return t1; } diff --git a/ets2panda/compiler/lowering/checkerPhase.cpp b/ets2panda/compiler/lowering/checkerPhase.cpp index d01f5603ed1dd88bcb7d1f2f4a790bd7eb994062..d746af74ea9873bb1143c3bd251ce783ee27ec82 100644 --- a/ets2panda/compiler/lowering/checkerPhase.cpp +++ b/ets2panda/compiler/lowering/checkerPhase.cpp @@ -52,6 +52,7 @@ bool CheckerPhase::Perform(public_lib::Context *ctx, [[maybe_unused]] parser::Pr if (program->Extension() == ScriptExtension::ETS) { try { ctx->GetChecker()->StartChecker(ctx->parserProgram->VarBinder(), *ctx->config->options); + ctx->GetChecker()->AddStatus(checker::CheckerStatus::TYPES_ARE_STABLE); } catch (std::exception &e) { // nothing to do - just to avoid program crash } diff --git a/ets2panda/compiler/lowering/ets/declareOverloadLowering.cpp b/ets2panda/compiler/lowering/ets/declareOverloadLowering.cpp index ad3cebeced6a13ed458e27f8656c5ab8b21e2295..db4d46f8a5cb20d98f90730b45e6e0cd6dd5a6a8 100644 --- a/ets2panda/compiler/lowering/ets/declareOverloadLowering.cpp +++ b/ets2panda/compiler/lowering/ets/declareOverloadLowering.cpp @@ -98,13 +98,14 @@ void BuildOverloadHelperFunction(public_lib::Context *ctx, ir::MethodDefinition funcScope->BindName(method->Function()->Scope()->Name()); helperOverload->Function()->Id()->SetVariable(helperOverload->Id()->Variable()); - checker->BuildFunctionSignature(helperOverload->Function(), method->IsConstructor()); + auto *signature = checker->BuildFunctionSignature(helperOverload->Function(), method->IsConstructor()); + helperOverload->Function()->SetSignature(signature); auto *const overloadType = checker->BuildMethodType(helperOverload->Function()); helperOverload->SetTsType(overloadType); ES2PANDA_ASSERT(method->TsType()->IsETSFunctionType()); - method->TsType()->AsETSFunctionType()->SetHelperSignature(helperOverload->Function()->Signature()); + method->TsType()->AsETSFunctionType()->SetHelperSignature(signature); } void UpdateCallSignature(public_lib::Context *ctx, ir::CallExpression *expr) diff --git a/ets2panda/compiler/lowering/ets/genericBridgesLowering.cpp b/ets2panda/compiler/lowering/ets/genericBridgesLowering.cpp index 0fa3241d61db19757895a373c2216c0339a7d6bd..8c23d85c2ebdda43d30f58370b1bfbd1daecc243 100644 --- a/ets2panda/compiler/lowering/ets/genericBridgesLowering.cpp +++ b/ets2panda/compiler/lowering/ets/genericBridgesLowering.cpp @@ -222,8 +222,9 @@ void GenericBridgesPhase::AddGenericBridge(ir::ClassDefinition const *const clas // call to `BuildFunctionSignature(...)` breaks it! auto *methodType = methodDefinition->Id()->Variable()->TsType()->AsETSFunctionType(); - checker->BuildFunctionSignature(bridgeMethod->Function()); - bridgeMethod->Function()->Signature()->AddSignatureFlag(checker::SignatureFlags::BRIDGE); + auto *signature = checker->BuildFunctionSignature(bridgeMethod->Function()); + signature->AddSignatureFlag(checker::SignatureFlags::BRIDGE); + bridgeMethod->Function()->SetSignature(signature); auto *const bridgeMethodType = checker->BuildMethodType(bridgeMethod->Function()); checker->CheckIdenticalOverloads(methodType, bridgeMethodType, bridgeMethod, false, diff --git a/ets2panda/compiler/lowering/ets/lambdaLowering.cpp b/ets2panda/compiler/lowering/ets/lambdaLowering.cpp index 100d4e5cfa0d4fa5241f1b16cff4b9f57e8dc108..12a3083c9927fd7093774ac4d5a21cc90e804791 100644 --- a/ets2panda/compiler/lowering/ets/lambdaLowering.cpp +++ b/ets2panda/compiler/lowering/ets/lambdaLowering.cpp @@ -350,7 +350,6 @@ static void ProcessCalleeMethodBody(ir::AstNode *body, checker::ETSChecker *chec auto *id = node->AsIdentifier(); if (auto ref = varMap.find(id->Variable()); ref != varMap.end()) { id->SetVariable(ref->second); - id->Check(checker); } } if (substitution == nullptr) { @@ -1290,7 +1289,6 @@ static ir::AstNode *ConvertLambda(public_lib::Context *ctx, ir::ArrowFunctionExp auto *allocator = ctx->allocator; auto *checker = ctx->GetChecker()->AsETSChecker(); - lambda->Check(checker); ES2PANDA_ASSERT(lambda->TsType()->IsETSFunctionType()); LambdaInfo info; diff --git a/ets2panda/ir/expressions/arrowFunctionExpression.h b/ets2panda/ir/expressions/arrowFunctionExpression.h index 2550cc7e0dac82d24970f05ef9e826aaa79a199a..ff6a756d44669f97954b0f17fe12526725616e96 100644 --- a/ets2panda/ir/expressions/arrowFunctionExpression.h +++ b/ets2panda/ir/expressions/arrowFunctionExpression.h @@ -51,16 +51,6 @@ public: return func_; } - void SetPreferredType(checker::Type *preferredType) noexcept - { - preferredType_ = preferredType; - } - - [[nodiscard]] checker::Type *GetPreferredType() noexcept - { - return preferredType_; - } - [[nodiscard]] ArrowFunctionExpression *Clone(ArenaAllocator *allocator, AstNode *parent) override; void TransformChildren(const NodeTransformer &cb, std::string_view transformationName) override; @@ -82,7 +72,6 @@ public: private: ScriptFunction *func_; - checker::Type *preferredType_ {}; }; } // namespace ark::es2panda::ir diff --git a/ets2panda/ir/expressions/identifier.h b/ets2panda/ir/expressions/identifier.h index bb455f333bc16ddb7b0d64473f5578072563e004..31c8bffcd8bf7dd7127482803bd9f7b3b848ec71 100644 --- a/ets2panda/ir/expressions/identifier.h +++ b/ets2panda/ir/expressions/identifier.h @@ -44,8 +44,7 @@ enum class IdentifierFlags : uint32_t { } // namespace ark::es2panda::ir template <> -struct enumbitops::IsAllowedType : std::true_type { -}; +struct enumbitops::IsAllowedType : std::true_type {}; namespace ark::es2panda::ir { diff --git a/ets2panda/util/nameMangler.cpp b/ets2panda/util/nameMangler.cpp index 70e138917d88ad38c9a6c703565b2e39bf1b6bac..12d296eb0ac8285138b18156b587a6c2e327406e 100644 --- a/ets2panda/util/nameMangler.cpp +++ b/ets2panda/util/nameMangler.cpp @@ -13,6 +13,7 @@ * limitations under the License. */ +#include #include "nameMangler.h" namespace ark::es2panda::util { diff --git a/ets2panda/util/perfMetrics.cpp b/ets2panda/util/perfMetrics.cpp index ae8215df9579393830078801e3cb46a7701520cd..6a4afa464c41ea529352dace765d537faec554ae 100644 --- a/ets2panda/util/perfMetrics.cpp +++ b/ets2panda/util/perfMetrics.cpp @@ -18,6 +18,7 @@ #include "libarkbase/utils/logger.h" #include "libarkbase/utils/type_converter.h" #include "libarkbase/mem/mem.h" +#include #include #include #include