13af6ab5fSopenharmony_ci/** 23af6ab5fSopenharmony_ci * Copyright (c) 2021-2024 Huawei Device Co., Ltd. 33af6ab5fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 43af6ab5fSopenharmony_ci * you may not use this file except in compliance with the License. 53af6ab5fSopenharmony_ci * You may obtain a copy of the License at 63af6ab5fSopenharmony_ci * 73af6ab5fSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 83af6ab5fSopenharmony_ci * 93af6ab5fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 103af6ab5fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 113af6ab5fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 123af6ab5fSopenharmony_ci * See the License for the specific language governing permissions and 133af6ab5fSopenharmony_ci * limitations under the License. 143af6ab5fSopenharmony_ci */ 153af6ab5fSopenharmony_ci 163af6ab5fSopenharmony_ci#include "util/helpers.h" 173af6ab5fSopenharmony_ci#include "macros.h" 183af6ab5fSopenharmony_ci#include "varbinder/ETSBinder.h" 193af6ab5fSopenharmony_ci#include "parser/ETSparser.h" 203af6ab5fSopenharmony_ci 213af6ab5fSopenharmony_ci#include "checker/types/ets/etsTupleType.h" 223af6ab5fSopenharmony_ci#include "checker/types/ets/etsReadonlyType.h" 233af6ab5fSopenharmony_ci#include "checker/ets/typeRelationContext.h" 243af6ab5fSopenharmony_ci#include "checker/ETSchecker.h" 253af6ab5fSopenharmony_ci#include "checker/types/globalTypesHolder.h" 263af6ab5fSopenharmony_ci#include "evaluate/scopedDebugInfoPlugin.h" 273af6ab5fSopenharmony_ci 283af6ab5fSopenharmony_ci#include "compiler/lowering/scopesInit/scopesInitPhase.h" 293af6ab5fSopenharmony_ci#include "generated/signatures.h" 303af6ab5fSopenharmony_ci 313af6ab5fSopenharmony_cinamespace ark::es2panda::checker { 323af6ab5fSopenharmony_civarbinder::Variable *ETSChecker::FindVariableInFunctionScope(const util::StringView name, 333af6ab5fSopenharmony_ci const varbinder::ResolveBindingOptions options) 343af6ab5fSopenharmony_ci{ 353af6ab5fSopenharmony_ci return Scope()->FindInFunctionScope(name, options).variable; 363af6ab5fSopenharmony_ci} 373af6ab5fSopenharmony_ci 383af6ab5fSopenharmony_cistd::pair<varbinder::Variable *, const ETSObjectType *> ETSChecker::FindVariableInClassOrEnclosing( 393af6ab5fSopenharmony_ci const util::StringView name, const ETSObjectType *classType) 403af6ab5fSopenharmony_ci{ 413af6ab5fSopenharmony_ci const auto searchFlags = PropertySearchFlags::SEARCH_ALL | PropertySearchFlags::SEARCH_IN_BASE | 423af6ab5fSopenharmony_ci PropertySearchFlags::SEARCH_IN_INTERFACES; 433af6ab5fSopenharmony_ci auto *resolved = classType->GetProperty(name, searchFlags); 443af6ab5fSopenharmony_ci while (classType->EnclosingType() != nullptr && resolved == nullptr) { 453af6ab5fSopenharmony_ci classType = classType->EnclosingType(); 463af6ab5fSopenharmony_ci resolved = classType->GetProperty(name, searchFlags); 473af6ab5fSopenharmony_ci } 483af6ab5fSopenharmony_ci 493af6ab5fSopenharmony_ci return {resolved, classType}; 503af6ab5fSopenharmony_ci} 513af6ab5fSopenharmony_ci 523af6ab5fSopenharmony_civarbinder::Variable *ETSChecker::FindVariableInGlobal(const ir::Identifier *const identifier, 533af6ab5fSopenharmony_ci const varbinder::ResolveBindingOptions options) 543af6ab5fSopenharmony_ci{ 553af6ab5fSopenharmony_ci return Scope()->FindInGlobal(identifier->Name(), options).variable; 563af6ab5fSopenharmony_ci} 573af6ab5fSopenharmony_ci 583af6ab5fSopenharmony_cibool ETSChecker::IsVariableStatic(const varbinder::Variable *var) 593af6ab5fSopenharmony_ci{ 603af6ab5fSopenharmony_ci if (var->HasFlag(varbinder::VariableFlags::METHOD)) { 613af6ab5fSopenharmony_ci return var->TsType()->AsETSFunctionType()->CallSignatures()[0]->HasSignatureFlag(SignatureFlags::STATIC); 623af6ab5fSopenharmony_ci } 633af6ab5fSopenharmony_ci return var->HasFlag(varbinder::VariableFlags::STATIC); 643af6ab5fSopenharmony_ci} 653af6ab5fSopenharmony_ci 663af6ab5fSopenharmony_cibool ETSChecker::IsVariableGetterSetter(const varbinder::Variable *var) 673af6ab5fSopenharmony_ci{ 683af6ab5fSopenharmony_ci return var->TsTypeOrError() != nullptr && var->TsTypeOrError()->HasTypeFlag(TypeFlag::GETTER_SETTER); 693af6ab5fSopenharmony_ci} 703af6ab5fSopenharmony_ci 713af6ab5fSopenharmony_civoid ETSChecker::LogUnResolvedError(ir::Identifier *const ident) 723af6ab5fSopenharmony_ci{ 733af6ab5fSopenharmony_ci LogTypeError({"Unresolved reference ", ident->Name()}, ident->Start()); 743af6ab5fSopenharmony_ci} 753af6ab5fSopenharmony_ci 763af6ab5fSopenharmony_civoid ETSChecker::WrongContextErrorClassifyByType(ir::Identifier *ident, varbinder::Variable *const resolved) 773af6ab5fSopenharmony_ci{ 783af6ab5fSopenharmony_ci std::string identCategoryName; 793af6ab5fSopenharmony_ci switch (static_cast<varbinder::VariableFlags>( 803af6ab5fSopenharmony_ci resolved->Flags() & 813af6ab5fSopenharmony_ci (varbinder::VariableFlags::CLASS_OR_INTERFACE_OR_ENUM | varbinder::VariableFlags::METHOD))) { 823af6ab5fSopenharmony_ci case varbinder::VariableFlags::CLASS: { 833af6ab5fSopenharmony_ci identCategoryName = "Class"; 843af6ab5fSopenharmony_ci break; 853af6ab5fSopenharmony_ci } 863af6ab5fSopenharmony_ci case varbinder::VariableFlags::METHOD: { 873af6ab5fSopenharmony_ci identCategoryName = "Function"; 883af6ab5fSopenharmony_ci break; 893af6ab5fSopenharmony_ci } 903af6ab5fSopenharmony_ci case varbinder::VariableFlags::INTERFACE: { 913af6ab5fSopenharmony_ci identCategoryName = "Interface"; 923af6ab5fSopenharmony_ci break; 933af6ab5fSopenharmony_ci } 943af6ab5fSopenharmony_ci case varbinder::VariableFlags::ENUM_LITERAL: { 953af6ab5fSopenharmony_ci identCategoryName = "Enum"; 963af6ab5fSopenharmony_ci break; 973af6ab5fSopenharmony_ci } 983af6ab5fSopenharmony_ci default: { 993af6ab5fSopenharmony_ci LogUnResolvedError(ident); 1003af6ab5fSopenharmony_ci return; 1013af6ab5fSopenharmony_ci } 1023af6ab5fSopenharmony_ci } 1033af6ab5fSopenharmony_ci LogTypeError({identCategoryName.c_str(), " name \"", ident->Name(), "\" used in the wrong context"}, 1043af6ab5fSopenharmony_ci ident->Start()); 1053af6ab5fSopenharmony_ci} 1063af6ab5fSopenharmony_ci 1073af6ab5fSopenharmony_civoid ETSChecker::NotResolvedError(ir::Identifier *const ident, const varbinder::Variable *classVar, 1083af6ab5fSopenharmony_ci const ETSObjectType *classType) 1093af6ab5fSopenharmony_ci{ 1103af6ab5fSopenharmony_ci if (classVar == nullptr) { 1113af6ab5fSopenharmony_ci LogUnResolvedError(ident); 1123af6ab5fSopenharmony_ci return; 1133af6ab5fSopenharmony_ci } 1143af6ab5fSopenharmony_ci 1153af6ab5fSopenharmony_ci if (IsVariableStatic(classVar)) { 1163af6ab5fSopenharmony_ci LogTypeError( 1173af6ab5fSopenharmony_ci {"Static property '", ident->Name(), "' must be accessed through it's class '", classType->Name(), "'"}, 1183af6ab5fSopenharmony_ci ident->Start()); 1193af6ab5fSopenharmony_ci } else { 1203af6ab5fSopenharmony_ci LogTypeError({"Property '", ident->Name(), "' must be accessed through 'this'"}, ident->Start()); 1213af6ab5fSopenharmony_ci } 1223af6ab5fSopenharmony_ci} 1233af6ab5fSopenharmony_ci 1243af6ab5fSopenharmony_cistd::pair<const ir::Identifier *, ir::TypeNode *> ETSChecker::GetTargetIdentifierAndType(ir::Identifier *const ident) 1253af6ab5fSopenharmony_ci{ 1263af6ab5fSopenharmony_ci if (ident->Parent()->IsClassProperty()) { 1273af6ab5fSopenharmony_ci const auto *const classProp = ident->Parent()->AsClassProperty(); 1283af6ab5fSopenharmony_ci ASSERT(classProp->Value() && classProp->Value() == ident); 1293af6ab5fSopenharmony_ci return std::make_pair(classProp->Key()->AsIdentifier(), classProp->TypeAnnotation()); 1303af6ab5fSopenharmony_ci } 1313af6ab5fSopenharmony_ci const auto *const variableDecl = ident->Parent()->AsVariableDeclarator(); 1323af6ab5fSopenharmony_ci ASSERT(variableDecl->Init() && variableDecl->Init() == ident); 1333af6ab5fSopenharmony_ci return std::make_pair(variableDecl->Id()->AsIdentifier(), variableDecl->Id()->AsIdentifier()->TypeAnnotation()); 1343af6ab5fSopenharmony_ci} 1353af6ab5fSopenharmony_ci 1363af6ab5fSopenharmony_civarbinder::Variable *ETSChecker::ExtraCheckForResolvedError(ir::Identifier *const ident) 1373af6ab5fSopenharmony_ci{ 1383af6ab5fSopenharmony_ci const auto [class_var, class_type] = FindVariableInClassOrEnclosing(ident->Name(), Context().ContainingClass()); 1393af6ab5fSopenharmony_ci auto *parentClass = FindAncestorGivenByType(ident, ir::AstNodeType::CLASS_DEFINITION); 1403af6ab5fSopenharmony_ci if (parentClass != nullptr && parentClass->AsClassDefinition()->IsLocal()) { 1413af6ab5fSopenharmony_ci if (parentClass != class_type->GetDeclNode()) { 1423af6ab5fSopenharmony_ci LogTypeError({"Property '", ident->Name(), "' of enclosing class '", class_type->Name(), 1433af6ab5fSopenharmony_ci "' is not allowed to be captured from the local class '", 1443af6ab5fSopenharmony_ci parentClass->AsClassDefinition()->Ident()->Name(), "'"}, 1453af6ab5fSopenharmony_ci ident->Start()); 1463af6ab5fSopenharmony_ci } 1473af6ab5fSopenharmony_ci } 1483af6ab5fSopenharmony_ci NotResolvedError(ident, class_var, class_type); 1493af6ab5fSopenharmony_ci return class_var; 1503af6ab5fSopenharmony_ci} 1513af6ab5fSopenharmony_ci 1523af6ab5fSopenharmony_cibool ETSChecker::SaveCapturedVariableInLocalClass(varbinder::Variable *const var, ir::Identifier *ident) 1533af6ab5fSopenharmony_ci{ 1543af6ab5fSopenharmony_ci const auto &pos = ident->Start(); 1553af6ab5fSopenharmony_ci 1563af6ab5fSopenharmony_ci if (!HasStatus(CheckerStatus::IN_LOCAL_CLASS)) { 1573af6ab5fSopenharmony_ci return false; 1583af6ab5fSopenharmony_ci } 1593af6ab5fSopenharmony_ci 1603af6ab5fSopenharmony_ci if (!var->HasFlag(varbinder::VariableFlags::LOCAL)) { 1613af6ab5fSopenharmony_ci return false; 1623af6ab5fSopenharmony_ci } 1633af6ab5fSopenharmony_ci 1643af6ab5fSopenharmony_ci LOG(DEBUG, ES2PANDA) << "Checking variable (line:" << pos.line << "): " << var->Name(); 1653af6ab5fSopenharmony_ci auto *scopeIter = Scope(); 1663af6ab5fSopenharmony_ci bool inStaticMethod = false; 1673af6ab5fSopenharmony_ci 1683af6ab5fSopenharmony_ci auto captureVariable = [this, var, ident, &scopeIter, &inStaticMethod, &pos]() { 1693af6ab5fSopenharmony_ci if (inStaticMethod) { 1703af6ab5fSopenharmony_ci LogTypeError({"Not allowed to capture variable '", var->Name(), "' in static method"}, pos); 1713af6ab5fSopenharmony_ci return false; 1723af6ab5fSopenharmony_ci } 1733af6ab5fSopenharmony_ci if (scopeIter->Node()->AsClassDefinition()->CaptureVariable(var)) { 1743af6ab5fSopenharmony_ci LOG(DEBUG, ES2PANDA) << " Captured in class:" << scopeIter->Node()->AsClassDefinition()->Ident()->Name(); 1753af6ab5fSopenharmony_ci } 1763af6ab5fSopenharmony_ci 1773af6ab5fSopenharmony_ci auto *parent = ident->Parent(); 1783af6ab5fSopenharmony_ci 1793af6ab5fSopenharmony_ci if (parent->IsVariableDeclarator()) { 1803af6ab5fSopenharmony_ci parent = parent->Parent()->Parent(); 1813af6ab5fSopenharmony_ci } 1823af6ab5fSopenharmony_ci 1833af6ab5fSopenharmony_ci if (!(parent->IsUpdateExpression() || 1843af6ab5fSopenharmony_ci (parent->IsAssignmentExpression() && parent->AsAssignmentExpression()->Left() == ident)) || 1853af6ab5fSopenharmony_ci var->Declaration() == nullptr) { 1863af6ab5fSopenharmony_ci return false; 1873af6ab5fSopenharmony_ci } 1883af6ab5fSopenharmony_ci 1893af6ab5fSopenharmony_ci if (var->Declaration()->IsParameterDecl()) { 1903af6ab5fSopenharmony_ci LOG(DEBUG, ES2PANDA) << " - Modified parameter "; 1913af6ab5fSopenharmony_ci scopeIter->Node()->AsClassDefinition()->AddToLocalVariableIsNeeded(var); 1923af6ab5fSopenharmony_ci } 1933af6ab5fSopenharmony_ci return true; 1943af6ab5fSopenharmony_ci }; 1953af6ab5fSopenharmony_ci 1963af6ab5fSopenharmony_ci while (scopeIter != var->GetScope()) { 1973af6ab5fSopenharmony_ci if (scopeIter->Node() != nullptr) { 1983af6ab5fSopenharmony_ci if (scopeIter->Node()->IsScriptFunction() && scopeIter->Node()->AsScriptFunction()->IsStatic()) { 1993af6ab5fSopenharmony_ci inStaticMethod = true; 2003af6ab5fSopenharmony_ci } 2013af6ab5fSopenharmony_ci 2023af6ab5fSopenharmony_ci if (scopeIter->Node()->IsClassDefinition()) { 2033af6ab5fSopenharmony_ci captureVariable(); 2043af6ab5fSopenharmony_ci return true; 2053af6ab5fSopenharmony_ci } 2063af6ab5fSopenharmony_ci } 2073af6ab5fSopenharmony_ci scopeIter = scopeIter->Parent(); 2083af6ab5fSopenharmony_ci } 2093af6ab5fSopenharmony_ci 2103af6ab5fSopenharmony_ci return false; 2113af6ab5fSopenharmony_ci} 2123af6ab5fSopenharmony_ci 2133af6ab5fSopenharmony_civoid ETSChecker::SaveCapturedVariable(varbinder::Variable *const var, ir::Identifier *ident) 2143af6ab5fSopenharmony_ci{ 2153af6ab5fSopenharmony_ci const auto &pos = ident->Start(); 2163af6ab5fSopenharmony_ci 2173af6ab5fSopenharmony_ci if (!HasStatus(CheckerStatus::IN_LAMBDA)) { 2183af6ab5fSopenharmony_ci return; 2193af6ab5fSopenharmony_ci } 2203af6ab5fSopenharmony_ci 2213af6ab5fSopenharmony_ci if (var->HasFlag(varbinder::VariableFlags::PROPERTY)) { 2223af6ab5fSopenharmony_ci Context().AddCapturedVar(var, pos); 2233af6ab5fSopenharmony_ci return; 2243af6ab5fSopenharmony_ci } 2253af6ab5fSopenharmony_ci 2263af6ab5fSopenharmony_ci if ((!var->HasFlag(varbinder::VariableFlags::LOCAL) && !var->HasFlag(varbinder::VariableFlags::METHOD)) || 2273af6ab5fSopenharmony_ci Context().ContainingLambda()->IsVarFromSubscope(var)) { 2283af6ab5fSopenharmony_ci return; 2293af6ab5fSopenharmony_ci } 2303af6ab5fSopenharmony_ci 2313af6ab5fSopenharmony_ci const auto *scopeIter = Scope(); 2323af6ab5fSopenharmony_ci while (scopeIter != var->GetScope()) { 2333af6ab5fSopenharmony_ci if (scopeIter->IsFunctionScope()) { 2343af6ab5fSopenharmony_ci Context().AddCapturedVar(var, pos); 2353af6ab5fSopenharmony_ci return; 2363af6ab5fSopenharmony_ci } 2373af6ab5fSopenharmony_ci scopeIter = scopeIter->Parent(); 2383af6ab5fSopenharmony_ci } 2393af6ab5fSopenharmony_ci} 2403af6ab5fSopenharmony_ci 2413af6ab5fSopenharmony_ciType *ETSChecker::ResolveIdentifier(ir::Identifier *ident) 2423af6ab5fSopenharmony_ci{ 2433af6ab5fSopenharmony_ci if (ident->Variable() != nullptr) { 2443af6ab5fSopenharmony_ci auto *const resolved = ident->Variable(); 2453af6ab5fSopenharmony_ci SaveCapturedVariable(resolved, ident); 2463af6ab5fSopenharmony_ci return GetTypeOfVariable(resolved); 2473af6ab5fSopenharmony_ci } 2483af6ab5fSopenharmony_ci 2493af6ab5fSopenharmony_ci auto options = ident->Parent()->IsTSTypeAliasDeclaration() ? varbinder::ResolveBindingOptions::TYPE_ALIASES 2503af6ab5fSopenharmony_ci : varbinder::ResolveBindingOptions::ALL_NON_TYPE; 2513af6ab5fSopenharmony_ci 2523af6ab5fSopenharmony_ci auto *resolved = FindVariableInFunctionScope(ident->Name(), options); 2533af6ab5fSopenharmony_ci if (resolved == nullptr) { 2543af6ab5fSopenharmony_ci // If the reference is not found already in the current class, then it is not bound to the class, so we have to 2553af6ab5fSopenharmony_ci // find the reference in the global class first, then in the global scope 2563af6ab5fSopenharmony_ci resolved = FindVariableInGlobal(ident, options); 2573af6ab5fSopenharmony_ci if (UNLIKELY(resolved == nullptr && debugInfoPlugin_ != nullptr)) { 2583af6ab5fSopenharmony_ci resolved = debugInfoPlugin_->FindIdentifier(ident); 2593af6ab5fSopenharmony_ci } 2603af6ab5fSopenharmony_ci } 2613af6ab5fSopenharmony_ci 2623af6ab5fSopenharmony_ci if (resolved == nullptr) { 2633af6ab5fSopenharmony_ci resolved = ExtraCheckForResolvedError(ident); 2643af6ab5fSopenharmony_ci ident->SetVariable(resolved); 2653af6ab5fSopenharmony_ci if (resolved == nullptr) { 2663af6ab5fSopenharmony_ci return GlobalTypeError(); 2673af6ab5fSopenharmony_ci } 2683af6ab5fSopenharmony_ci return GetTypeOfVariable(resolved); 2693af6ab5fSopenharmony_ci } 2703af6ab5fSopenharmony_ci 2713af6ab5fSopenharmony_ci ident->SetVariable(resolved); 2723af6ab5fSopenharmony_ci // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) 2733af6ab5fSopenharmony_ci ValidateResolvedIdentifier(ident, resolved); 2743af6ab5fSopenharmony_ci 2753af6ab5fSopenharmony_ci ValidatePropertyAccess(resolved, Context().ContainingClass(), ident->Start()); 2763af6ab5fSopenharmony_ci SaveCapturedVariable(resolved, ident); 2773af6ab5fSopenharmony_ci 2783af6ab5fSopenharmony_ci return GetTypeOfVariable(resolved); 2793af6ab5fSopenharmony_ci} 2803af6ab5fSopenharmony_ci 2813af6ab5fSopenharmony_cistd::tuple<Type *, bool> ETSChecker::ApplyBinaryOperatorPromotion(Type *left, Type *right, TypeFlag test, 2823af6ab5fSopenharmony_ci bool const doPromotion) 2833af6ab5fSopenharmony_ci{ 2843af6ab5fSopenharmony_ci Type *const unboxedL = ETSBuiltinTypeAsPrimitiveType(left); 2853af6ab5fSopenharmony_ci Type *const unboxedR = ETSBuiltinTypeAsPrimitiveType(right); 2863af6ab5fSopenharmony_ci 2873af6ab5fSopenharmony_ci if (unboxedL == nullptr || unboxedR == nullptr) { 2883af6ab5fSopenharmony_ci return {nullptr, false}; 2893af6ab5fSopenharmony_ci } 2903af6ab5fSopenharmony_ci 2913af6ab5fSopenharmony_ci if (!unboxedL->HasTypeFlag(test) || !unboxedR->HasTypeFlag(test)) { 2923af6ab5fSopenharmony_ci return {nullptr, false}; 2933af6ab5fSopenharmony_ci } 2943af6ab5fSopenharmony_ci 2953af6ab5fSopenharmony_ci bool const bothConst = unboxedL->HasTypeFlag(TypeFlag::CONSTANT) && unboxedR->HasTypeFlag(TypeFlag::CONSTANT); 2963af6ab5fSopenharmony_ci 2973af6ab5fSopenharmony_ci // extract just to reduce nested levels 2983af6ab5fSopenharmony_ci auto const numericPromotion = [this, unboxedL, unboxedR, bothConst]() -> std::tuple<checker::Type *, bool> { 2993af6ab5fSopenharmony_ci if (unboxedL->IsDoubleType() || unboxedR->IsDoubleType()) { 3003af6ab5fSopenharmony_ci return {GlobalDoubleType(), bothConst}; 3013af6ab5fSopenharmony_ci } 3023af6ab5fSopenharmony_ci 3033af6ab5fSopenharmony_ci if (unboxedL->IsFloatType() || unboxedR->IsFloatType()) { 3043af6ab5fSopenharmony_ci return {GlobalFloatType(), bothConst}; 3053af6ab5fSopenharmony_ci } 3063af6ab5fSopenharmony_ci 3073af6ab5fSopenharmony_ci if (unboxedL->IsLongType() || unboxedR->IsLongType()) { 3083af6ab5fSopenharmony_ci return {GlobalLongType(), bothConst}; 3093af6ab5fSopenharmony_ci } 3103af6ab5fSopenharmony_ci 3113af6ab5fSopenharmony_ci if (unboxedL->IsCharType() && unboxedR->IsCharType()) { 3123af6ab5fSopenharmony_ci return {GlobalCharType(), bothConst}; 3133af6ab5fSopenharmony_ci } 3143af6ab5fSopenharmony_ci 3153af6ab5fSopenharmony_ci return {GlobalIntType(), bothConst}; 3163af6ab5fSopenharmony_ci }; 3173af6ab5fSopenharmony_ci 3183af6ab5fSopenharmony_ci if (doPromotion) { 3193af6ab5fSopenharmony_ci if (unboxedL->HasTypeFlag(TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC) && 3203af6ab5fSopenharmony_ci unboxedR->HasTypeFlag(TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC)) { 3213af6ab5fSopenharmony_ci return numericPromotion(); 3223af6ab5fSopenharmony_ci } 3233af6ab5fSopenharmony_ci 3243af6ab5fSopenharmony_ci if (IsTypeIdenticalTo(unboxedL, unboxedR)) { 3253af6ab5fSopenharmony_ci return {unboxedL, bothConst}; 3263af6ab5fSopenharmony_ci } 3273af6ab5fSopenharmony_ci } 3283af6ab5fSopenharmony_ci 3293af6ab5fSopenharmony_ci return {unboxedR, bothConst}; 3303af6ab5fSopenharmony_ci} 3313af6ab5fSopenharmony_ci 3323af6ab5fSopenharmony_cistd::optional<checker::Type *> CheckLeftRightType(checker::ETSChecker *checker, checker::Type *unboxedL, 3333af6ab5fSopenharmony_ci checker::Type *unboxedR) 3343af6ab5fSopenharmony_ci{ 3353af6ab5fSopenharmony_ci if (unboxedL->IsDoubleType() || unboxedR->IsDoubleType()) { 3363af6ab5fSopenharmony_ci return checker->GlobalDoubleType(); 3373af6ab5fSopenharmony_ci } 3383af6ab5fSopenharmony_ci if (unboxedL->IsFloatType() || unboxedR->IsFloatType()) { 3393af6ab5fSopenharmony_ci return checker->GlobalFloatType(); 3403af6ab5fSopenharmony_ci } 3413af6ab5fSopenharmony_ci if (unboxedL->IsLongType() || unboxedR->IsLongType()) { 3423af6ab5fSopenharmony_ci return checker->GlobalLongType(); 3433af6ab5fSopenharmony_ci } 3443af6ab5fSopenharmony_ci if (unboxedL->IsIntType() || unboxedR->IsIntType() || unboxedL->IsCharType() || unboxedR->IsCharType()) { 3453af6ab5fSopenharmony_ci return checker->GlobalIntType(); 3463af6ab5fSopenharmony_ci } 3473af6ab5fSopenharmony_ci if (unboxedL->IsShortType() || unboxedR->IsShortType()) { 3483af6ab5fSopenharmony_ci return checker->GlobalShortType(); 3493af6ab5fSopenharmony_ci } 3503af6ab5fSopenharmony_ci if (unboxedL->IsByteType() || unboxedR->IsByteType()) { 3513af6ab5fSopenharmony_ci return checker->GlobalByteType(); 3523af6ab5fSopenharmony_ci } 3533af6ab5fSopenharmony_ci return std::nullopt; 3543af6ab5fSopenharmony_ci} 3553af6ab5fSopenharmony_cichecker::Type *ETSChecker::ApplyConditionalOperatorPromotion(checker::ETSChecker *checker, checker::Type *unboxedL, 3563af6ab5fSopenharmony_ci checker::Type *unboxedR) 3573af6ab5fSopenharmony_ci{ 3583af6ab5fSopenharmony_ci if ((unboxedL->HasTypeFlag(checker::TypeFlag::CONSTANT) && unboxedL->IsIntType()) || 3593af6ab5fSopenharmony_ci (unboxedR->HasTypeFlag(checker::TypeFlag::CONSTANT) && unboxedR->IsIntType())) { 3603af6ab5fSopenharmony_ci int value = unboxedL->IsIntType() ? unboxedL->AsIntType()->GetValue() : unboxedR->AsIntType()->GetValue(); 3613af6ab5fSopenharmony_ci checker::Type *otherType = !unboxedL->IsIntType() ? unboxedL : unboxedR; 3623af6ab5fSopenharmony_ci 3633af6ab5fSopenharmony_ci switch (checker::ETSChecker::ETSType(otherType)) { 3643af6ab5fSopenharmony_ci case checker::TypeFlag::BYTE: 3653af6ab5fSopenharmony_ci case checker::TypeFlag::CHAR: { 3663af6ab5fSopenharmony_ci if (value <= static_cast<int>(std::numeric_limits<char>::max()) && 3673af6ab5fSopenharmony_ci value >= static_cast<int>(std::numeric_limits<char>::min())) { 3683af6ab5fSopenharmony_ci return checker->GetNonConstantType(otherType); 3693af6ab5fSopenharmony_ci } 3703af6ab5fSopenharmony_ci break; 3713af6ab5fSopenharmony_ci } 3723af6ab5fSopenharmony_ci case checker::TypeFlag::SHORT: { 3733af6ab5fSopenharmony_ci if (value <= std::numeric_limits<int16_t>::max() && value >= std::numeric_limits<int16_t>::min()) { 3743af6ab5fSopenharmony_ci return checker->GlobalShortType(); 3753af6ab5fSopenharmony_ci } 3763af6ab5fSopenharmony_ci break; 3773af6ab5fSopenharmony_ci } 3783af6ab5fSopenharmony_ci default: { 3793af6ab5fSopenharmony_ci return otherType; 3803af6ab5fSopenharmony_ci } 3813af6ab5fSopenharmony_ci } 3823af6ab5fSopenharmony_ci return checker->GlobalIntType(); 3833af6ab5fSopenharmony_ci } 3843af6ab5fSopenharmony_ci 3853af6ab5fSopenharmony_ci auto checkLeftRight = CheckLeftRightType(checker, unboxedL, unboxedR); 3863af6ab5fSopenharmony_ci if (checkLeftRight.has_value()) { 3873af6ab5fSopenharmony_ci return checkLeftRight.value(); 3883af6ab5fSopenharmony_ci } 3893af6ab5fSopenharmony_ci UNREACHABLE(); 3903af6ab5fSopenharmony_ci} 3913af6ab5fSopenharmony_ci 3923af6ab5fSopenharmony_ciType *ETSChecker::ApplyUnaryOperatorPromotion(Type *type, const bool createConst, const bool doPromotion, 3933af6ab5fSopenharmony_ci const bool isCondExpr) 3943af6ab5fSopenharmony_ci{ 3953af6ab5fSopenharmony_ci Type *unboxedType = isCondExpr ? ETSBuiltinTypeAsConditionalType(type) : ETSBuiltinTypeAsPrimitiveType(type); 3963af6ab5fSopenharmony_ci 3973af6ab5fSopenharmony_ci if (unboxedType == nullptr) { 3983af6ab5fSopenharmony_ci return nullptr; 3993af6ab5fSopenharmony_ci } 4003af6ab5fSopenharmony_ci if (doPromotion) { 4013af6ab5fSopenharmony_ci switch (ETSType(unboxedType)) { 4023af6ab5fSopenharmony_ci case TypeFlag::BYTE: 4033af6ab5fSopenharmony_ci case TypeFlag::SHORT: 4043af6ab5fSopenharmony_ci case TypeFlag::CHAR: { 4053af6ab5fSopenharmony_ci if (!createConst) { 4063af6ab5fSopenharmony_ci return GlobalIntType(); 4073af6ab5fSopenharmony_ci } 4083af6ab5fSopenharmony_ci 4093af6ab5fSopenharmony_ci return CreateIntTypeFromType(unboxedType); 4103af6ab5fSopenharmony_ci } 4113af6ab5fSopenharmony_ci default: { 4123af6ab5fSopenharmony_ci break; 4133af6ab5fSopenharmony_ci } 4143af6ab5fSopenharmony_ci } 4153af6ab5fSopenharmony_ci } 4163af6ab5fSopenharmony_ci return unboxedType; 4173af6ab5fSopenharmony_ci} 4183af6ab5fSopenharmony_ci 4193af6ab5fSopenharmony_cibool ETSChecker::IsNullLikeOrVoidExpression(const ir::Expression *expr) const 4203af6ab5fSopenharmony_ci{ 4213af6ab5fSopenharmony_ci return expr->TsType()->DefinitelyETSNullish() || expr->TsType()->IsETSVoidType(); 4223af6ab5fSopenharmony_ci} 4233af6ab5fSopenharmony_ci 4243af6ab5fSopenharmony_cistd::tuple<bool, bool> ETSChecker::IsResolvedAndValue(const ir::Expression *expr, Type *type) const 4253af6ab5fSopenharmony_ci{ 4263af6ab5fSopenharmony_ci auto [isResolve, isValue] = 4273af6ab5fSopenharmony_ci IsNullLikeOrVoidExpression(expr) ? std::make_tuple(true, false) : type->ResolveConditionExpr(); 4283af6ab5fSopenharmony_ci 4293af6ab5fSopenharmony_ci const Type *tsType = expr->TsType(); 4303af6ab5fSopenharmony_ci if (tsType->DefinitelyNotETSNullish() && !type->HasTypeFlag(TypeFlag::ETS_PRIMITIVE)) { 4313af6ab5fSopenharmony_ci isResolve = true; 4323af6ab5fSopenharmony_ci isValue = true; 4333af6ab5fSopenharmony_ci } 4343af6ab5fSopenharmony_ci return std::make_tuple(isResolve, isValue); 4353af6ab5fSopenharmony_ci} 4363af6ab5fSopenharmony_ci 4373af6ab5fSopenharmony_ciType *ETSChecker::HandleBooleanLogicalOperatorsExtended(Type *leftType, Type *rightType, ir::BinaryExpression *expr) 4383af6ab5fSopenharmony_ci{ 4393af6ab5fSopenharmony_ci ASSERT(leftType->IsConditionalExprType() && rightType->IsConditionalExprType()); 4403af6ab5fSopenharmony_ci 4413af6ab5fSopenharmony_ci auto [resolveLeft, leftValue] = IsResolvedAndValue(expr->Left(), leftType); 4423af6ab5fSopenharmony_ci auto [resolveRight, rightValue] = IsResolvedAndValue(expr->Right(), rightType); 4433af6ab5fSopenharmony_ci 4443af6ab5fSopenharmony_ci if (!resolveLeft && !resolveRight && IsTypeIdenticalTo(leftType, rightType)) { 4453af6ab5fSopenharmony_ci return leftType; 4463af6ab5fSopenharmony_ci } 4473af6ab5fSopenharmony_ci 4483af6ab5fSopenharmony_ci switch (expr->OperatorType()) { 4493af6ab5fSopenharmony_ci case lexer::TokenType::PUNCTUATOR_LOGICAL_OR: { 4503af6ab5fSopenharmony_ci if (leftValue) { 4513af6ab5fSopenharmony_ci expr->SetResult(expr->Left()); 4523af6ab5fSopenharmony_ci return leftType->IsETSBooleanType() ? CreateETSBooleanType(true) : leftType; 4533af6ab5fSopenharmony_ci } 4543af6ab5fSopenharmony_ci 4553af6ab5fSopenharmony_ci expr->SetResult(expr->Right()); 4563af6ab5fSopenharmony_ci return rightType->IsETSBooleanType() && resolveRight ? CreateETSBooleanType(rightValue) : rightType; 4573af6ab5fSopenharmony_ci } 4583af6ab5fSopenharmony_ci case lexer::TokenType::PUNCTUATOR_LOGICAL_AND: { 4593af6ab5fSopenharmony_ci if (leftValue) { 4603af6ab5fSopenharmony_ci expr->SetResult(expr->Right()); 4613af6ab5fSopenharmony_ci return rightType->IsETSBooleanType() && resolveRight ? CreateETSBooleanType(rightValue) : rightType; 4623af6ab5fSopenharmony_ci } 4633af6ab5fSopenharmony_ci 4643af6ab5fSopenharmony_ci expr->SetResult(expr->Left()); 4653af6ab5fSopenharmony_ci return leftType->IsETSBooleanType() ? CreateETSBooleanType(false) : leftType; 4663af6ab5fSopenharmony_ci } 4673af6ab5fSopenharmony_ci default: { 4683af6ab5fSopenharmony_ci break; 4693af6ab5fSopenharmony_ci } 4703af6ab5fSopenharmony_ci } 4713af6ab5fSopenharmony_ci 4723af6ab5fSopenharmony_ci UNREACHABLE(); 4733af6ab5fSopenharmony_ci} 4743af6ab5fSopenharmony_ci 4753af6ab5fSopenharmony_ciType *ETSChecker::HandleBooleanLogicalOperators(Type *leftType, Type *rightType, lexer::TokenType tokenType) 4763af6ab5fSopenharmony_ci{ 4773af6ab5fSopenharmony_ci using UType = typename ETSBooleanType::UType; 4783af6ab5fSopenharmony_ci ASSERT(leftType->IsETSBooleanType() && rightType->IsETSBooleanType()); 4793af6ab5fSopenharmony_ci 4803af6ab5fSopenharmony_ci if (!leftType->HasTypeFlag(checker::TypeFlag::CONSTANT) || !rightType->HasTypeFlag(checker::TypeFlag::CONSTANT)) { 4813af6ab5fSopenharmony_ci return GlobalETSBooleanType(); 4823af6ab5fSopenharmony_ci } 4833af6ab5fSopenharmony_ci 4843af6ab5fSopenharmony_ci UType leftValue = leftType->AsETSBooleanType()->GetValue(); 4853af6ab5fSopenharmony_ci UType rightValue = rightType->AsETSBooleanType()->GetValue(); 4863af6ab5fSopenharmony_ci 4873af6ab5fSopenharmony_ci switch (tokenType) { 4883af6ab5fSopenharmony_ci case lexer::TokenType::PUNCTUATOR_BITWISE_XOR: { 4893af6ab5fSopenharmony_ci return CreateETSBooleanType(leftValue ^ rightValue); 4903af6ab5fSopenharmony_ci } 4913af6ab5fSopenharmony_ci case lexer::TokenType::PUNCTUATOR_BITWISE_AND: { 4923af6ab5fSopenharmony_ci return CreateETSBooleanType((static_cast<uint8_t>(leftValue) & static_cast<uint8_t>(rightValue)) != 0); 4933af6ab5fSopenharmony_ci } 4943af6ab5fSopenharmony_ci case lexer::TokenType::PUNCTUATOR_BITWISE_OR: { 4953af6ab5fSopenharmony_ci return CreateETSBooleanType((static_cast<uint8_t>(leftValue) | static_cast<uint8_t>(rightValue)) != 0); 4963af6ab5fSopenharmony_ci } 4973af6ab5fSopenharmony_ci case lexer::TokenType::PUNCTUATOR_LOGICAL_OR: { 4983af6ab5fSopenharmony_ci return CreateETSBooleanType(leftValue || rightValue); 4993af6ab5fSopenharmony_ci } 5003af6ab5fSopenharmony_ci case lexer::TokenType::PUNCTUATOR_LOGICAL_AND: { 5013af6ab5fSopenharmony_ci return CreateETSBooleanType(leftValue && rightValue); 5023af6ab5fSopenharmony_ci } 5033af6ab5fSopenharmony_ci default: { 5043af6ab5fSopenharmony_ci break; 5053af6ab5fSopenharmony_ci } 5063af6ab5fSopenharmony_ci } 5073af6ab5fSopenharmony_ci 5083af6ab5fSopenharmony_ci UNREACHABLE(); 5093af6ab5fSopenharmony_ci return nullptr; 5103af6ab5fSopenharmony_ci} 5113af6ab5fSopenharmony_ci 5123af6ab5fSopenharmony_civoid ETSChecker::ResolveReturnStatement(checker::Type *funcReturnType, checker::Type *argumentType, 5133af6ab5fSopenharmony_ci ir::ScriptFunction *containingFunc, ir::ReturnStatement *st) 5143af6ab5fSopenharmony_ci{ 5153af6ab5fSopenharmony_ci if (funcReturnType->IsETSReferenceType() || argumentType->IsETSReferenceType()) { 5163af6ab5fSopenharmony_ci // function return type should be of reference (object) type 5173af6ab5fSopenharmony_ci Relation()->SetFlags(checker::TypeRelationFlag::NONE); 5183af6ab5fSopenharmony_ci 5193af6ab5fSopenharmony_ci if (!argumentType->IsETSReferenceType()) { 5203af6ab5fSopenharmony_ci argumentType = PrimitiveTypeAsETSBuiltinType(argumentType); 5213af6ab5fSopenharmony_ci if (argumentType == nullptr) { 5223af6ab5fSopenharmony_ci LogTypeError("Invalid return statement expression", st->Argument()->Start()); 5233af6ab5fSopenharmony_ci } else { 5243af6ab5fSopenharmony_ci st->Argument()->AddBoxingUnboxingFlags(GetBoxingFlag(argumentType)); 5253af6ab5fSopenharmony_ci } 5263af6ab5fSopenharmony_ci } 5273af6ab5fSopenharmony_ci 5283af6ab5fSopenharmony_ci if (!funcReturnType->IsETSReferenceType()) { 5293af6ab5fSopenharmony_ci funcReturnType = PrimitiveTypeAsETSBuiltinType(funcReturnType); 5303af6ab5fSopenharmony_ci if (funcReturnType == nullptr) { 5313af6ab5fSopenharmony_ci LogTypeError("Invalid return function expression", st->Start()); 5323af6ab5fSopenharmony_ci } 5333af6ab5fSopenharmony_ci } 5343af6ab5fSopenharmony_ci if (argumentType != nullptr && funcReturnType != nullptr) { 5353af6ab5fSopenharmony_ci funcReturnType = CreateETSUnionType({funcReturnType, argumentType}); 5363af6ab5fSopenharmony_ci containingFunc->Signature()->SetReturnType(funcReturnType); 5373af6ab5fSopenharmony_ci containingFunc->Signature()->AddSignatureFlag(checker::SignatureFlags::INFERRED_RETURN_TYPE); 5383af6ab5fSopenharmony_ci } 5393af6ab5fSopenharmony_ci } else if (funcReturnType->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE_RETURN) && 5403af6ab5fSopenharmony_ci argumentType->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE_RETURN)) { 5413af6ab5fSopenharmony_ci // function return type is of primitive type (including enums): 5423af6ab5fSopenharmony_ci Relation()->SetFlags(checker::TypeRelationFlag::DIRECT_RETURN | 5433af6ab5fSopenharmony_ci checker::TypeRelationFlag::IN_ASSIGNMENT_CONTEXT | 5443af6ab5fSopenharmony_ci checker::TypeRelationFlag::ASSIGNMENT_CONTEXT); 5453af6ab5fSopenharmony_ci if (Relation()->IsAssignableTo(funcReturnType, argumentType)) { 5463af6ab5fSopenharmony_ci funcReturnType = argumentType; 5473af6ab5fSopenharmony_ci containingFunc->Signature()->SetReturnType(funcReturnType); 5483af6ab5fSopenharmony_ci containingFunc->Signature()->AddSignatureFlag(checker::SignatureFlags::INFERRED_RETURN_TYPE); 5493af6ab5fSopenharmony_ci } else if (!Relation()->IsAssignableTo(argumentType, funcReturnType)) { 5503af6ab5fSopenharmony_ci const Type *targetType = TryGettingFunctionTypeFromInvokeFunction(funcReturnType); 5513af6ab5fSopenharmony_ci const Type *sourceType = TryGettingFunctionTypeFromInvokeFunction(argumentType); 5523af6ab5fSopenharmony_ci 5533af6ab5fSopenharmony_ci LogTypeError({"Function cannot have different primitive return types, require '", targetType, "', found '", 5543af6ab5fSopenharmony_ci sourceType, "'"}, 5553af6ab5fSopenharmony_ci st->Argument()->Start()); 5563af6ab5fSopenharmony_ci } 5573af6ab5fSopenharmony_ci } else { 5583af6ab5fSopenharmony_ci // Should never in this branch. 5593af6ab5fSopenharmony_ci UNREACHABLE(); 5603af6ab5fSopenharmony_ci return; 5613af6ab5fSopenharmony_ci } 5623af6ab5fSopenharmony_ci} 5633af6ab5fSopenharmony_ci 5643af6ab5fSopenharmony_cichecker::Type *ETSChecker::CheckArrayElements(ir::ArrayExpression *init) 5653af6ab5fSopenharmony_ci{ 5663af6ab5fSopenharmony_ci ArenaVector<checker::Type *> elementTypes(Allocator()->Adapter()); 5673af6ab5fSopenharmony_ci for (auto e : init->AsArrayExpression()->Elements()) { 5683af6ab5fSopenharmony_ci elementTypes.push_back(GetNonConstantType(e->Check(this))); 5693af6ab5fSopenharmony_ci } 5703af6ab5fSopenharmony_ci 5713af6ab5fSopenharmony_ci if (elementTypes.empty()) { 5723af6ab5fSopenharmony_ci // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) 5733af6ab5fSopenharmony_ci return Allocator()->New<ETSArrayType>(GlobalETSObjectType()); 5743af6ab5fSopenharmony_ci } 5753af6ab5fSopenharmony_ci auto const isNumeric = [](checker::Type *ct) { return ct->HasTypeFlag(TypeFlag::ETS_CONVERTIBLE_TO_NUMERIC); }; 5763af6ab5fSopenharmony_ci auto const elementType = std::all_of(elementTypes.begin(), elementTypes.end(), isNumeric) 5773af6ab5fSopenharmony_ci ? GlobalDoubleType() 5783af6ab5fSopenharmony_ci : CreateETSUnionType(std::move(elementTypes)); 5793af6ab5fSopenharmony_ci 5803af6ab5fSopenharmony_ci // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) 5813af6ab5fSopenharmony_ci return Allocator()->New<ETSArrayType>(elementType); 5823af6ab5fSopenharmony_ci} 5833af6ab5fSopenharmony_ci 5843af6ab5fSopenharmony_civoid ETSChecker::InferAliasLambdaType(ir::TypeNode *localTypeAnnotation, ir::ArrowFunctionExpression *init) 5853af6ab5fSopenharmony_ci{ 5863af6ab5fSopenharmony_ci ASSERT(localTypeAnnotation != nullptr); 5873af6ab5fSopenharmony_ci 5883af6ab5fSopenharmony_ci if (localTypeAnnotation->IsETSTypeReference()) { 5893af6ab5fSopenharmony_ci bool isAnnotationTypeAlias = true; 5903af6ab5fSopenharmony_ci while (localTypeAnnotation->IsETSTypeReference() && isAnnotationTypeAlias) { 5913af6ab5fSopenharmony_ci auto *nodeVar = localTypeAnnotation->AsETSTypeReference()->Part()->Name()->AsIdentifier()->Variable(); 5923af6ab5fSopenharmony_ci if (nodeVar == nullptr) { 5933af6ab5fSopenharmony_ci break; 5943af6ab5fSopenharmony_ci } 5953af6ab5fSopenharmony_ci 5963af6ab5fSopenharmony_ci auto *node = nodeVar->Declaration()->Node(); 5973af6ab5fSopenharmony_ci 5983af6ab5fSopenharmony_ci isAnnotationTypeAlias = node->IsTSTypeAliasDeclaration(); 5993af6ab5fSopenharmony_ci if (isAnnotationTypeAlias) { 6003af6ab5fSopenharmony_ci localTypeAnnotation = node->AsTSTypeAliasDeclaration()->TypeAnnotation(); 6013af6ab5fSopenharmony_ci } 6023af6ab5fSopenharmony_ci } 6033af6ab5fSopenharmony_ci } 6043af6ab5fSopenharmony_ci 6053af6ab5fSopenharmony_ci if (localTypeAnnotation->IsETSFunctionType()) { 6063af6ab5fSopenharmony_ci auto *const arrowFuncExpr = init; 6073af6ab5fSopenharmony_ci ir::ScriptFunction *const lambda = arrowFuncExpr->Function(); 6083af6ab5fSopenharmony_ci if (lambda->Params().size() == localTypeAnnotation->AsETSFunctionType()->Params().size() && 6093af6ab5fSopenharmony_ci NeedTypeInference(lambda)) { 6103af6ab5fSopenharmony_ci InferTypesForLambda(lambda, localTypeAnnotation->AsETSFunctionType()); 6113af6ab5fSopenharmony_ci } 6123af6ab5fSopenharmony_ci } 6133af6ab5fSopenharmony_ci} 6143af6ab5fSopenharmony_ci 6153af6ab5fSopenharmony_cichecker::Type *ETSChecker::FixOptionalVariableType(varbinder::Variable *const bindingVar, ir::ModifierFlags flags, 6163af6ab5fSopenharmony_ci ir::Expression *init) 6173af6ab5fSopenharmony_ci{ 6183af6ab5fSopenharmony_ci if ((flags & ir::ModifierFlags::OPTIONAL) != 0) { 6193af6ab5fSopenharmony_ci auto type = bindingVar->TsTypeOrError(); 6203af6ab5fSopenharmony_ci if (init != nullptr && init->TsType()->IsETSEnumType()) { 6213af6ab5fSopenharmony_ci init->SetBoxingUnboxingFlags(ir::BoxingUnboxingFlags::BOX_TO_ENUM); 6223af6ab5fSopenharmony_ci } 6233af6ab5fSopenharmony_ci if (type->IsETSEnumType()) { 6243af6ab5fSopenharmony_ci type = type->AsETSEnumType()->GetDecl()->BoxedClass()->TsType(); 6253af6ab5fSopenharmony_ci } 6263af6ab5fSopenharmony_ci if (type->IsETSUnionType()) { 6273af6ab5fSopenharmony_ci auto constituentTypes = type->AsETSUnionType()->ConstituentTypes(); 6283af6ab5fSopenharmony_ci constituentTypes.push_back(GlobalETSUndefinedType()); 6293af6ab5fSopenharmony_ci type = CreateETSUnionType(std::move(constituentTypes)); 6303af6ab5fSopenharmony_ci } else { 6313af6ab5fSopenharmony_ci type = CreateETSUnionType({GlobalETSUndefinedType(), type}); 6323af6ab5fSopenharmony_ci } 6333af6ab5fSopenharmony_ci bindingVar->SetTsType(type); 6343af6ab5fSopenharmony_ci } 6353af6ab5fSopenharmony_ci return bindingVar->TsTypeOrError(); 6363af6ab5fSopenharmony_ci} 6373af6ab5fSopenharmony_ci 6383af6ab5fSopenharmony_cichecker::Type *PreferredObjectTypeFromAnnotation(checker::Type *annotationType) 6393af6ab5fSopenharmony_ci{ 6403af6ab5fSopenharmony_ci if (!annotationType->IsETSUnionType()) { 6413af6ab5fSopenharmony_ci return annotationType; 6423af6ab5fSopenharmony_ci } 6433af6ab5fSopenharmony_ci 6443af6ab5fSopenharmony_ci checker::Type *resolvedType = nullptr; 6453af6ab5fSopenharmony_ci for (auto constituentType : annotationType->AsETSUnionType()->ConstituentTypes()) { 6463af6ab5fSopenharmony_ci if (constituentType->IsETSObjectType()) { 6473af6ab5fSopenharmony_ci if (resolvedType != nullptr) { 6483af6ab5fSopenharmony_ci return nullptr; 6493af6ab5fSopenharmony_ci } 6503af6ab5fSopenharmony_ci resolvedType = constituentType; 6513af6ab5fSopenharmony_ci } 6523af6ab5fSopenharmony_ci } 6533af6ab5fSopenharmony_ci 6543af6ab5fSopenharmony_ci return resolvedType; 6553af6ab5fSopenharmony_ci} 6563af6ab5fSopenharmony_ci 6573af6ab5fSopenharmony_cibool ETSChecker::CheckInit(ir::Identifier *ident, ir::TypeNode *typeAnnotation, ir::Expression *init, 6583af6ab5fSopenharmony_ci checker::Type *annotationType, varbinder::Variable *const bindingVar) 6593af6ab5fSopenharmony_ci{ 6603af6ab5fSopenharmony_ci if (typeAnnotation == nullptr) { 6613af6ab5fSopenharmony_ci if (init->IsArrayExpression()) { 6623af6ab5fSopenharmony_ci annotationType = CheckArrayElements(init->AsArrayExpression()); 6633af6ab5fSopenharmony_ci bindingVar->SetTsType(annotationType); 6643af6ab5fSopenharmony_ci } 6653af6ab5fSopenharmony_ci 6663af6ab5fSopenharmony_ci if (init->IsObjectExpression()) { 6673af6ab5fSopenharmony_ci LogTypeError( 6683af6ab5fSopenharmony_ci {"Cannot infer type for ", ident->Name(), " because class composite needs an explicit target type"}, 6693af6ab5fSopenharmony_ci ident->Start()); 6703af6ab5fSopenharmony_ci return false; 6713af6ab5fSopenharmony_ci } 6723af6ab5fSopenharmony_ci } 6733af6ab5fSopenharmony_ci 6743af6ab5fSopenharmony_ci if (init->IsMemberExpression() && init->AsMemberExpression()->Object()->IsObjectExpression()) { 6753af6ab5fSopenharmony_ci LogTypeError({"Class composite must be constructed separately before referring their members."}, 6763af6ab5fSopenharmony_ci ident->Start()); 6773af6ab5fSopenharmony_ci } 6783af6ab5fSopenharmony_ci 6793af6ab5fSopenharmony_ci if ((init->IsMemberExpression()) && (annotationType != nullptr)) { 6803af6ab5fSopenharmony_ci SetArrayPreferredTypeForNestedMemberExpressions(init->AsMemberExpression(), annotationType); 6813af6ab5fSopenharmony_ci } 6823af6ab5fSopenharmony_ci 6833af6ab5fSopenharmony_ci if (init->IsArrayExpression() && (annotationType != nullptr) && annotationType->IsETSArrayType()) { 6843af6ab5fSopenharmony_ci if (annotationType->IsETSTupleType()) { 6853af6ab5fSopenharmony_ci if (!ValidateTupleMinElementSize(init->AsArrayExpression(), annotationType->AsETSTupleType())) { 6863af6ab5fSopenharmony_ci return false; 6873af6ab5fSopenharmony_ci } 6883af6ab5fSopenharmony_ci } 6893af6ab5fSopenharmony_ci 6903af6ab5fSopenharmony_ci init->AsArrayExpression()->SetPreferredType(annotationType); 6913af6ab5fSopenharmony_ci } 6923af6ab5fSopenharmony_ci 6933af6ab5fSopenharmony_ci if (init->IsObjectExpression()) { 6943af6ab5fSopenharmony_ci init->AsObjectExpression()->SetPreferredType(PreferredObjectTypeFromAnnotation(annotationType)); 6953af6ab5fSopenharmony_ci } 6963af6ab5fSopenharmony_ci 6973af6ab5fSopenharmony_ci if (typeAnnotation != nullptr && init->IsArrowFunctionExpression()) { 6983af6ab5fSopenharmony_ci InferAliasLambdaType(typeAnnotation, init->AsArrowFunctionExpression()); 6993af6ab5fSopenharmony_ci } 7003af6ab5fSopenharmony_ci return true; 7013af6ab5fSopenharmony_ci} 7023af6ab5fSopenharmony_civoid ETSChecker::CheckEnumType(ir::Expression *init, checker::Type *initType, const util::StringView &varName) 7033af6ab5fSopenharmony_ci{ 7043af6ab5fSopenharmony_ci if (initType->IsETSObjectType() && initType->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::ENUM) && 7053af6ab5fSopenharmony_ci !init->IsMemberExpression()) { 7063af6ab5fSopenharmony_ci LogTypeError({"Cannot assign type '", initType->AsETSObjectType()->Name(), "' for variable ", varName, "."}, 7073af6ab5fSopenharmony_ci init->Start()); 7083af6ab5fSopenharmony_ci } 7093af6ab5fSopenharmony_ci} 7103af6ab5fSopenharmony_ci 7113af6ab5fSopenharmony_cistatic bool NeedWideningBasedOnInitializerHeuristics(ir::Expression *e) 7123af6ab5fSopenharmony_ci{ 7133af6ab5fSopenharmony_ci // NOTE: need to be done by smart casts. Return true if we need to infer wider type. 7143af6ab5fSopenharmony_ci if (e->IsUnaryExpression()) { 7153af6ab5fSopenharmony_ci return NeedWideningBasedOnInitializerHeuristics(e->AsUnaryExpression()->Argument()); 7163af6ab5fSopenharmony_ci } 7173af6ab5fSopenharmony_ci const bool isConstInit = e->IsIdentifier() && e->Variable()->Declaration()->IsConstDecl(); 7183af6ab5fSopenharmony_ci return e->IsConditionalExpression() || e->IsLiteral() || isConstInit; 7193af6ab5fSopenharmony_ci} 7203af6ab5fSopenharmony_ci 7213af6ab5fSopenharmony_cichecker::Type *ETSChecker::CheckVariableDeclaration(ir::Identifier *ident, ir::TypeNode *typeAnnotation, 7223af6ab5fSopenharmony_ci ir::Expression *init, ir::ModifierFlags const flags) 7233af6ab5fSopenharmony_ci{ 7243af6ab5fSopenharmony_ci const util::StringView &varName = ident->Name(); 7253af6ab5fSopenharmony_ci ASSERT(ident->Variable()); 7263af6ab5fSopenharmony_ci varbinder::Variable *const bindingVar = ident->Variable(); 7273af6ab5fSopenharmony_ci checker::Type *annotationType = nullptr; 7283af6ab5fSopenharmony_ci 7293af6ab5fSopenharmony_ci const bool isConst = (flags & ir::ModifierFlags::CONST) != 0; 7303af6ab5fSopenharmony_ci const bool isReadonly = (flags & ir::ModifierFlags::READONLY) != 0; 7313af6ab5fSopenharmony_ci const bool isStatic = (flags & ir::ModifierFlags::STATIC) != 0; 7323af6ab5fSopenharmony_ci // Note(lujiahui): It should be checked if the readonly function parameter and readonly number[] parameters 7333af6ab5fSopenharmony_ci // are assigned with CONSTANT, which would not be correct. (After feature supported) 7343af6ab5fSopenharmony_ci const bool omitInitConstness = isConst || (isReadonly && isStatic); 7353af6ab5fSopenharmony_ci 7363af6ab5fSopenharmony_ci if (typeAnnotation != nullptr) { 7373af6ab5fSopenharmony_ci annotationType = typeAnnotation->GetType(this); 7383af6ab5fSopenharmony_ci bindingVar->SetTsType(annotationType); 7393af6ab5fSopenharmony_ci } 7403af6ab5fSopenharmony_ci 7413af6ab5fSopenharmony_ci if (init == nullptr) { 7423af6ab5fSopenharmony_ci return FixOptionalVariableType(bindingVar, flags, init); 7433af6ab5fSopenharmony_ci } 7443af6ab5fSopenharmony_ci 7453af6ab5fSopenharmony_ci if (!CheckInit(ident, typeAnnotation, init, annotationType, bindingVar)) { 7463af6ab5fSopenharmony_ci return GlobalTypeError(); 7473af6ab5fSopenharmony_ci } 7483af6ab5fSopenharmony_ci 7493af6ab5fSopenharmony_ci checker::Type *initType = init->Check(this); 7503af6ab5fSopenharmony_ci 7513af6ab5fSopenharmony_ci if (initType == nullptr) { 7523af6ab5fSopenharmony_ci LogTypeError("Cannot get the expression type", init->Start()); 7533af6ab5fSopenharmony_ci return GlobalTypeError(); 7543af6ab5fSopenharmony_ci } 7553af6ab5fSopenharmony_ci 7563af6ab5fSopenharmony_ci if (typeAnnotation == nullptr && initType->IsETSFunctionType()) { 7573af6ab5fSopenharmony_ci if (!init->IsArrowFunctionExpression() && (initType->AsETSFunctionType()->CallSignatures().size() != 1)) { 7583af6ab5fSopenharmony_ci ThrowTypeError("Ambiguous function initialization because of multiple overloads", init->Start()); 7593af6ab5fSopenharmony_ci } 7603af6ab5fSopenharmony_ci 7613af6ab5fSopenharmony_ci annotationType = 7623af6ab5fSopenharmony_ci initType->AsETSFunctionType()->FunctionalInterface() == nullptr 7633af6ab5fSopenharmony_ci ? FunctionTypeToFunctionalInterfaceType(initType->AsETSFunctionType()->CallSignatures().front()) 7643af6ab5fSopenharmony_ci : initType->AsETSFunctionType()->FunctionalInterface(); 7653af6ab5fSopenharmony_ci bindingVar->SetTsType(annotationType); 7663af6ab5fSopenharmony_ci } 7673af6ab5fSopenharmony_ci 7683af6ab5fSopenharmony_ci if (annotationType != nullptr) { 7693af6ab5fSopenharmony_ci CheckAnnotationTypeForVariableDeclaration(annotationType, annotationType->IsETSUnionType(), init, initType); 7703af6ab5fSopenharmony_ci 7713af6ab5fSopenharmony_ci if (omitInitConstness && 7723af6ab5fSopenharmony_ci ((initType->HasTypeFlag(TypeFlag::ETS_PRIMITIVE) && annotationType->HasTypeFlag(TypeFlag::ETS_PRIMITIVE)) || 7733af6ab5fSopenharmony_ci (initType->IsETSStringType() && annotationType->IsETSStringType()))) { 7743af6ab5fSopenharmony_ci bindingVar->SetTsType(init->TsType()); 7753af6ab5fSopenharmony_ci } 7763af6ab5fSopenharmony_ci return FixOptionalVariableType(bindingVar, flags, init); 7773af6ab5fSopenharmony_ci } 7783af6ab5fSopenharmony_ci 7793af6ab5fSopenharmony_ci CheckEnumType(init, initType, varName); 7803af6ab5fSopenharmony_ci 7813af6ab5fSopenharmony_ci // NOTE: need to be done by smart casts 7823af6ab5fSopenharmony_ci const bool needWidening = 7833af6ab5fSopenharmony_ci !omitInitConstness && typeAnnotation == nullptr && NeedWideningBasedOnInitializerHeuristics(init); 7843af6ab5fSopenharmony_ci bindingVar->SetTsType(needWidening ? GetNonConstantType(initType) : initType); 7853af6ab5fSopenharmony_ci 7863af6ab5fSopenharmony_ci return FixOptionalVariableType(bindingVar, flags, init); 7873af6ab5fSopenharmony_ci} 7883af6ab5fSopenharmony_ci 7893af6ab5fSopenharmony_civoid ETSChecker::CheckAnnotationTypeForVariableDeclaration(checker::Type *annotationType, bool isUnionFunction, 7903af6ab5fSopenharmony_ci ir::Expression *init, checker::Type *initType) 7913af6ab5fSopenharmony_ci{ 7923af6ab5fSopenharmony_ci Type *sourceType = TryGettingFunctionTypeFromInvokeFunction(initType); 7933af6ab5fSopenharmony_ci 7943af6ab5fSopenharmony_ci if (!isUnionFunction && annotationType->IsETSUnionType()) { 7953af6ab5fSopenharmony_ci for (auto it : annotationType->AsETSUnionType()->ConstituentTypes()) { 7963af6ab5fSopenharmony_ci if (it->IsETSFunctionType() || 7973af6ab5fSopenharmony_ci (it->IsETSObjectType() && it->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::FUNCTIONAL))) { 7983af6ab5fSopenharmony_ci isUnionFunction = true; 7993af6ab5fSopenharmony_ci break; 8003af6ab5fSopenharmony_ci } 8013af6ab5fSopenharmony_ci } 8023af6ab5fSopenharmony_ci } 8033af6ab5fSopenharmony_ci 8043af6ab5fSopenharmony_ci if (isUnionFunction) { 8053af6ab5fSopenharmony_ci if (!AssignmentContext(Relation(), init, initType, annotationType, init->Start(), {}, 8063af6ab5fSopenharmony_ci TypeRelationFlag::NO_THROW) 8073af6ab5fSopenharmony_ci .IsAssignable()) { 8083af6ab5fSopenharmony_ci LogTypeError({"Type '", sourceType, "' cannot be assigned to type '", annotationType, "'"}, init->Start()); 8093af6ab5fSopenharmony_ci } 8103af6ab5fSopenharmony_ci } else { 8113af6ab5fSopenharmony_ci if (!AssignmentContext(Relation(), init, initType, annotationType, init->Start(), {}, 8123af6ab5fSopenharmony_ci TypeRelationFlag::NO_THROW) 8133af6ab5fSopenharmony_ci .IsAssignable()) { 8143af6ab5fSopenharmony_ci LogTypeError({"Type '", sourceType, "' cannot be assigned to type '", 8153af6ab5fSopenharmony_ci TryGettingFunctionTypeFromInvokeFunction(annotationType), "'"}, 8163af6ab5fSopenharmony_ci init->Start()); 8173af6ab5fSopenharmony_ci } 8183af6ab5fSopenharmony_ci } 8193af6ab5fSopenharmony_ci} 8203af6ab5fSopenharmony_ci 8213af6ab5fSopenharmony_ci//==============================================================================// 8223af6ab5fSopenharmony_ci// Smart cast support 8233af6ab5fSopenharmony_ci//==============================================================================// 8243af6ab5fSopenharmony_ci 8253af6ab5fSopenharmony_cichecker::Type *ETSChecker::ResolveSmartType(checker::Type *sourceType, checker::Type *targetType) 8263af6ab5fSopenharmony_ci{ 8273af6ab5fSopenharmony_ci // For left-hand variable of primitive type leave it as is. 8283af6ab5fSopenharmony_ci if (targetType->HasTypeFlag(TypeFlag::ETS_PRIMITIVE_RETURN)) { 8293af6ab5fSopenharmony_ci return targetType; 8303af6ab5fSopenharmony_ci } 8313af6ab5fSopenharmony_ci 8323af6ab5fSopenharmony_ci // For left-hand variable of tuple type leave it as is. 8333af6ab5fSopenharmony_ci if (targetType->IsETSTupleType()) { 8343af6ab5fSopenharmony_ci return targetType; 8353af6ab5fSopenharmony_ci } 8363af6ab5fSopenharmony_ci 8373af6ab5fSopenharmony_ci // For left-hand variable of builtin type leave it as is. 8383af6ab5fSopenharmony_ci if (targetType->IsETSObjectType() && targetType->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::BUILTIN_TYPE)) { 8393af6ab5fSopenharmony_ci return targetType; 8403af6ab5fSopenharmony_ci } 8413af6ab5fSopenharmony_ci 8423af6ab5fSopenharmony_ci // For the Function source or target types leave the target type as is 8433af6ab5fSopenharmony_ci // until we will be able to create the functional interface type from the source. 8443af6ab5fSopenharmony_ci if (targetType->HasTypeFlag(TypeFlag::FUNCTION) || sourceType->HasTypeFlag(TypeFlag::FUNCTION)) { 8453af6ab5fSopenharmony_ci return targetType; 8463af6ab5fSopenharmony_ci } 8473af6ab5fSopenharmony_ci 8483af6ab5fSopenharmony_ci // Nothing to do with identical types: 8493af6ab5fSopenharmony_ci auto *nonConstSourceType = GetNonConstantType(sourceType); 8503af6ab5fSopenharmony_ci auto *nonConstTargetType = GetNonConstantType(targetType); 8513af6ab5fSopenharmony_ci 8523af6ab5fSopenharmony_ci if (Relation()->IsIdenticalTo(nonConstSourceType, nonConstTargetType) || 8533af6ab5fSopenharmony_ci Relation()->IsIdenticalTo(GlobalBuiltinJSValueType(), nonConstTargetType)) { 8543af6ab5fSopenharmony_ci return targetType; 8553af6ab5fSopenharmony_ci } 8563af6ab5fSopenharmony_ci 8573af6ab5fSopenharmony_ci // For type parameter, null or undefined source type return it as is. 8583af6ab5fSopenharmony_ci if (sourceType->IsETSTypeParameter() || sourceType->DefinitelyETSNullish()) { 8593af6ab5fSopenharmony_ci return sourceType; 8603af6ab5fSopenharmony_ci } 8613af6ab5fSopenharmony_ci 8623af6ab5fSopenharmony_ci // In case of Union left-hand type we have to select the proper type from the Union 8633af6ab5fSopenharmony_ci // NOTE: it always exists at this point! 8643af6ab5fSopenharmony_ci if (targetType->IsETSUnionType()) { 8653af6ab5fSopenharmony_ci sourceType = targetType->AsETSUnionType()->GetAssignableType(this, sourceType); 8663af6ab5fSopenharmony_ci ASSERT(sourceType != nullptr); 8673af6ab5fSopenharmony_ci return sourceType; 8683af6ab5fSopenharmony_ci } 8693af6ab5fSopenharmony_ci 8703af6ab5fSopenharmony_ci // If source is reference type, set it as the current and use it for identifier smart cast 8713af6ab5fSopenharmony_ci if (sourceType->IsETSReferenceType()) { 8723af6ab5fSopenharmony_ci return sourceType; 8733af6ab5fSopenharmony_ci } 8743af6ab5fSopenharmony_ci 8753af6ab5fSopenharmony_ci // For right-hand variable of primitive type apply boxing conversion (case: 'let x: Object = 5', then x => Int). 8763af6ab5fSopenharmony_ci if (sourceType->HasTypeFlag(TypeFlag::ETS_PRIMITIVE) && !sourceType->IsETSVoidType() && 8773af6ab5fSopenharmony_ci targetType->IsETSObjectType()) { 8783af6ab5fSopenharmony_ci return PrimitiveTypeAsETSBuiltinType(sourceType); 8793af6ab5fSopenharmony_ci } 8803af6ab5fSopenharmony_ci 8813af6ab5fSopenharmony_ci // NOTE - it seems that all the other possible cases are assignments like: 8823af6ab5fSopenharmony_ci // 'Object = ObjectLiteral' or smth similar ??? 8833af6ab5fSopenharmony_ci // thus for such cases also leave the target type as is. 8843af6ab5fSopenharmony_ci // Possible errors in tests should clarify this hypothesis sooner or later :) 8853af6ab5fSopenharmony_ci return targetType; 8863af6ab5fSopenharmony_ci} 8873af6ab5fSopenharmony_ci 8883af6ab5fSopenharmony_ci// Auxiliary method to reduce the size of common 'CheckTestSmartCastConditions' function. 8893af6ab5fSopenharmony_cistd::pair<Type *, Type *> ETSChecker::CheckTestNullishCondition(Type *testedType, Type *actualType, bool const strict) 8903af6ab5fSopenharmony_ci{ 8913af6ab5fSopenharmony_ci if (!strict) { 8923af6ab5fSopenharmony_ci return RemoveNullishTypes(actualType); 8933af6ab5fSopenharmony_ci } 8943af6ab5fSopenharmony_ci 8953af6ab5fSopenharmony_ci if (testedType->IsETSNullType()) { 8963af6ab5fSopenharmony_ci return {GlobalETSNullType(), RemoveNullType(actualType)}; 8973af6ab5fSopenharmony_ci } 8983af6ab5fSopenharmony_ci 8993af6ab5fSopenharmony_ci if (testedType->IsETSUndefinedType()) { 9003af6ab5fSopenharmony_ci return {GlobalETSUndefinedType(), RemoveUndefinedType(actualType)}; 9013af6ab5fSopenharmony_ci } 9023af6ab5fSopenharmony_ci 9033af6ab5fSopenharmony_ci return {GlobalETSNullishType(), GetNonNullishType(actualType)}; 9043af6ab5fSopenharmony_ci} 9053af6ab5fSopenharmony_ci 9063af6ab5fSopenharmony_ci// Auxiliary method to reduce the size of common 'CheckTestSmartCastConditions' function. 9073af6ab5fSopenharmony_cistd::pair<Type *, Type *> ETSChecker::CheckTestObjectCondition(ETSArrayType *testedType, Type *actualType) 9083af6ab5fSopenharmony_ci{ 9093af6ab5fSopenharmony_ci if (actualType->IsETSUnionType()) { 9103af6ab5fSopenharmony_ci return actualType->AsETSUnionType()->GetComplimentaryType(this, testedType); 9113af6ab5fSopenharmony_ci } 9123af6ab5fSopenharmony_ci 9133af6ab5fSopenharmony_ci // Both testing and actual (smart) types are arrays. Set types according to their relation. 9143af6ab5fSopenharmony_ci // NOTE: probably the rules of type extraction should be modified later on! 9153af6ab5fSopenharmony_ci if (actualType->IsETSArrayType()) { 9163af6ab5fSopenharmony_ci auto *const arrayType = actualType->AsETSArrayType(); 9173af6ab5fSopenharmony_ci 9183af6ab5fSopenharmony_ci if (Relation()->IsIdenticalTo(arrayType, testedType) || 9193af6ab5fSopenharmony_ci arrayType->AssemblerName() == testedType->AssemblerName()) { 9203af6ab5fSopenharmony_ci return {testedType, GetGlobalTypesHolder()->GlobalNeverType()}; 9213af6ab5fSopenharmony_ci } 9223af6ab5fSopenharmony_ci 9233af6ab5fSopenharmony_ci if (Relation()->IsSupertypeOf(arrayType, testedType)) { 9243af6ab5fSopenharmony_ci return {testedType, actualType}; 9253af6ab5fSopenharmony_ci } 9263af6ab5fSopenharmony_ci 9273af6ab5fSopenharmony_ci if (Relation()->IsSupertypeOf(testedType, arrayType)) { 9283af6ab5fSopenharmony_ci return {testedType, actualType}; 9293af6ab5fSopenharmony_ci } 9303af6ab5fSopenharmony_ci } else if (actualType->IsETSObjectType() && actualType->AsETSObjectType()->IsGlobalETSObjectType()) { 9313af6ab5fSopenharmony_ci return {testedType, actualType}; 9323af6ab5fSopenharmony_ci } 9333af6ab5fSopenharmony_ci 9343af6ab5fSopenharmony_ci return {GetGlobalTypesHolder()->GlobalNeverType(), actualType}; 9353af6ab5fSopenharmony_ci} 9363af6ab5fSopenharmony_ci 9373af6ab5fSopenharmony_ci// Auxiliary method to reduce the size of common 'CheckTestSmartCastConditions' function. 9383af6ab5fSopenharmony_cistd::pair<Type *, Type *> ETSChecker::CheckTestObjectCondition(ETSObjectType *testedType, Type *actualType, 9393af6ab5fSopenharmony_ci bool const strict) 9403af6ab5fSopenharmony_ci{ 9413af6ab5fSopenharmony_ci if (actualType->IsETSUnionType()) { 9423af6ab5fSopenharmony_ci return actualType->AsETSUnionType()->GetComplimentaryType(this, testedType); 9433af6ab5fSopenharmony_ci } 9443af6ab5fSopenharmony_ci 9453af6ab5fSopenharmony_ci // Both testing and actual (smart) types are objects. Set types according to their relation. 9463af6ab5fSopenharmony_ci // NOTE: probably the rules of type extraction should be modified later on! 9473af6ab5fSopenharmony_ci if (actualType->IsETSObjectType()) { 9483af6ab5fSopenharmony_ci auto *const objectType = actualType->AsETSObjectType(); 9493af6ab5fSopenharmony_ci 9503af6ab5fSopenharmony_ci if (Relation()->IsIdenticalTo(objectType, testedType) || 9513af6ab5fSopenharmony_ci objectType->AssemblerName() == testedType->AssemblerName()) { 9523af6ab5fSopenharmony_ci return {testedType, strict ? GetGlobalTypesHolder()->GlobalNeverType() : actualType}; 9533af6ab5fSopenharmony_ci } 9543af6ab5fSopenharmony_ci 9553af6ab5fSopenharmony_ci if (Relation()->IsSupertypeOf(objectType, testedType)) { 9563af6ab5fSopenharmony_ci return {testedType, actualType}; 9573af6ab5fSopenharmony_ci } 9583af6ab5fSopenharmony_ci 9593af6ab5fSopenharmony_ci if (Relation()->IsSupertypeOf(testedType, objectType)) { 9603af6ab5fSopenharmony_ci return {testedType, actualType}; 9613af6ab5fSopenharmony_ci } 9623af6ab5fSopenharmony_ci 9633af6ab5fSopenharmony_ci return {GetGlobalTypesHolder()->GlobalNeverType(), actualType}; 9643af6ab5fSopenharmony_ci } 9653af6ab5fSopenharmony_ci 9663af6ab5fSopenharmony_ci // NOTE: other cases (for example with functional types) will be implemented later on 9673af6ab5fSopenharmony_ci return {testedType, actualType}; 9683af6ab5fSopenharmony_ci} 9693af6ab5fSopenharmony_ci 9703af6ab5fSopenharmony_cistatic constexpr std::size_t const VARIABLE_POSITION = 0UL; 9713af6ab5fSopenharmony_cistatic constexpr std::size_t const CONSEQUENT_TYPE_POSITION = 1UL; 9723af6ab5fSopenharmony_cistatic constexpr std::size_t const ALTERNATE_TYPE_POSITION = 2UL; 9733af6ab5fSopenharmony_ci 9743af6ab5fSopenharmony_civoid CheckerContext::CheckTestSmartCastCondition(lexer::TokenType operatorType) 9753af6ab5fSopenharmony_ci{ 9763af6ab5fSopenharmony_ci if (operatorType != lexer::TokenType::EOS && operatorType != lexer::TokenType::PUNCTUATOR_LOGICAL_AND && 9773af6ab5fSopenharmony_ci operatorType != lexer::TokenType::PUNCTUATOR_LOGICAL_OR) { 9783af6ab5fSopenharmony_ci return; 9793af6ab5fSopenharmony_ci } 9803af6ab5fSopenharmony_ci 9813af6ab5fSopenharmony_ci auto types = ResolveSmartCastTypes(); 9823af6ab5fSopenharmony_ci 9833af6ab5fSopenharmony_ci if (operatorType_ == lexer::TokenType::PUNCTUATOR_LOGICAL_AND) { 9843af6ab5fSopenharmony_ci if (types.has_value()) { 9853af6ab5fSopenharmony_ci auto const &variable = std::get<VARIABLE_POSITION>(*types); 9863af6ab5fSopenharmony_ci // NOTE: now we support only cases like 'if (x != null && y == null)' but don't support different type 9873af6ab5fSopenharmony_ci // checks for a single variable (like 'if (x != null && x instanceof string)'), because it seems that 9883af6ab5fSopenharmony_ci // it doesn't make much sense. 9893af6ab5fSopenharmony_ci // Can be implemented later on if the need arises. 9903af6ab5fSopenharmony_ci if (auto [_, inserted] = 9913af6ab5fSopenharmony_ci testSmartCasts_.emplace(variable, std::make_pair(std::get<CONSEQUENT_TYPE_POSITION>(*types), 9923af6ab5fSopenharmony_ci std::get<ALTERNATE_TYPE_POSITION>(*types))); 9933af6ab5fSopenharmony_ci !inserted) { 9943af6ab5fSopenharmony_ci testSmartCasts_[variable] = {nullptr, nullptr}; 9953af6ab5fSopenharmony_ci } 9963af6ab5fSopenharmony_ci } 9973af6ab5fSopenharmony_ci // Clear alternate types, because now they become indefinite 9983af6ab5fSopenharmony_ci for (auto &smartCast : testSmartCasts_) { 9993af6ab5fSopenharmony_ci smartCast.second.second = nullptr; 10003af6ab5fSopenharmony_ci } 10013af6ab5fSopenharmony_ci } else if (operatorType_ == lexer::TokenType::PUNCTUATOR_LOGICAL_OR) { 10023af6ab5fSopenharmony_ci if (bool const cleanConsequent = types.has_value() ? CheckTestOrSmartCastCondition(*types) : true; 10033af6ab5fSopenharmony_ci cleanConsequent) { 10043af6ab5fSopenharmony_ci // Clear consequent types, because now they become indefinite 10053af6ab5fSopenharmony_ci for (auto &smartCast : testSmartCasts_) { 10063af6ab5fSopenharmony_ci smartCast.second.first = nullptr; 10073af6ab5fSopenharmony_ci } 10083af6ab5fSopenharmony_ci } 10093af6ab5fSopenharmony_ci } else if (types.has_value()) { 10103af6ab5fSopenharmony_ci testSmartCasts_.emplace( 10113af6ab5fSopenharmony_ci std::get<VARIABLE_POSITION>(*types), 10123af6ab5fSopenharmony_ci std::make_pair(std::get<CONSEQUENT_TYPE_POSITION>(*types), std::get<ALTERNATE_TYPE_POSITION>(*types))); 10133af6ab5fSopenharmony_ci } 10143af6ab5fSopenharmony_ci 10153af6ab5fSopenharmony_ci testCondition_ = {}; 10163af6ab5fSopenharmony_ci operatorType_ = operatorType; 10173af6ab5fSopenharmony_ci} 10183af6ab5fSopenharmony_ci 10193af6ab5fSopenharmony_cistd::optional<SmartCastTuple> CheckerContext::ResolveSmartCastTypes() 10203af6ab5fSopenharmony_ci{ 10213af6ab5fSopenharmony_ci if (testCondition_.variable == nullptr) { 10223af6ab5fSopenharmony_ci return std::nullopt; 10233af6ab5fSopenharmony_ci } 10243af6ab5fSopenharmony_ci 10253af6ab5fSopenharmony_ci // Exclude processing of global variables and those captured in lambdas and modified there 10263af6ab5fSopenharmony_ci auto const *const variableScope = testCondition_.variable->GetScope(); 10273af6ab5fSopenharmony_ci auto const topLevelVariable = 10283af6ab5fSopenharmony_ci variableScope != nullptr ? variableScope->IsGlobalScope() || 10293af6ab5fSopenharmony_ci (variableScope->Parent() != nullptr && variableScope->Parent()->IsGlobalScope()) 10303af6ab5fSopenharmony_ci : false; 10313af6ab5fSopenharmony_ci if (topLevelVariable) { 10323af6ab5fSopenharmony_ci return std::nullopt; 10333af6ab5fSopenharmony_ci } 10343af6ab5fSopenharmony_ci 10353af6ab5fSopenharmony_ci ASSERT(testCondition_.testedType != nullptr); 10363af6ab5fSopenharmony_ci // NOTE: functional types are not supported now 10373af6ab5fSopenharmony_ci if (!testCondition_.testedType->IsETSReferenceType() || 10383af6ab5fSopenharmony_ci testCondition_.testedType->HasTypeFlag(TypeFlag::FUNCTION)) { 10393af6ab5fSopenharmony_ci return std::nullopt; 10403af6ab5fSopenharmony_ci } 10413af6ab5fSopenharmony_ci 10423af6ab5fSopenharmony_ci auto *smartType = GetSmartCast(testCondition_.variable); 10433af6ab5fSopenharmony_ci if (smartType == nullptr) { 10443af6ab5fSopenharmony_ci smartType = testCondition_.variable->TsType(); 10453af6ab5fSopenharmony_ci } 10463af6ab5fSopenharmony_ci 10473af6ab5fSopenharmony_ci auto *const checker = parent_->AsETSChecker(); 10483af6ab5fSopenharmony_ci Type *consequentType = nullptr; 10493af6ab5fSopenharmony_ci Type *alternateType = nullptr; 10503af6ab5fSopenharmony_ci 10513af6ab5fSopenharmony_ci if (testCondition_.testedType->DefinitelyETSNullish()) { 10523af6ab5fSopenharmony_ci // In case of testing for 'null' and/or 'undefined' remove corresponding null-like types. 10533af6ab5fSopenharmony_ci std::tie(consequentType, alternateType) = 10543af6ab5fSopenharmony_ci checker->CheckTestNullishCondition(testCondition_.testedType, smartType, testCondition_.strict); 10553af6ab5fSopenharmony_ci } else { 10563af6ab5fSopenharmony_ci if (testCondition_.testedType->IsETSObjectType()) { 10573af6ab5fSopenharmony_ci auto *const testedType = testCondition_.testedType->AsETSObjectType(); 10583af6ab5fSopenharmony_ci std::tie(consequentType, alternateType) = 10593af6ab5fSopenharmony_ci checker->CheckTestObjectCondition(testedType, smartType, testCondition_.strict); 10603af6ab5fSopenharmony_ci } else if (testCondition_.testedType->IsETSArrayType()) { 10613af6ab5fSopenharmony_ci auto *const testedType = testCondition_.testedType->AsETSArrayType(); 10623af6ab5fSopenharmony_ci std::tie(consequentType, alternateType) = checker->CheckTestObjectCondition(testedType, smartType); 10633af6ab5fSopenharmony_ci } else if (testCondition_.testedType->IsETSUnionType()) { 10643af6ab5fSopenharmony_ci // NOTE: now we don't support 'instanceof' operation for union types? 10653af6ab5fSopenharmony_ci UNREACHABLE(); 10663af6ab5fSopenharmony_ci } else { 10673af6ab5fSopenharmony_ci // NOTE: it seems that no more cases are possible here! :) 10683af6ab5fSopenharmony_ci UNREACHABLE(); 10693af6ab5fSopenharmony_ci } 10703af6ab5fSopenharmony_ci } 10713af6ab5fSopenharmony_ci 10723af6ab5fSopenharmony_ci return !testCondition_.negate 10733af6ab5fSopenharmony_ci ? std::make_optional(std::make_tuple(testCondition_.variable, consequentType, alternateType)) 10743af6ab5fSopenharmony_ci : std::make_optional(std::make_tuple(testCondition_.variable, alternateType, consequentType)); 10753af6ab5fSopenharmony_ci} 10763af6ab5fSopenharmony_cibool ETSChecker::CheckVoidAnnotation(const ir::ETSPrimitiveType *typeAnnotation) 10773af6ab5fSopenharmony_ci{ 10783af6ab5fSopenharmony_ci // Void annotation is valid only when used as 'return type' , 'type parameter instantiation', 'default type'. 10793af6ab5fSopenharmony_ci if (typeAnnotation->GetPrimitiveType() != ir::PrimitiveType::VOID) { 10803af6ab5fSopenharmony_ci return true; 10813af6ab5fSopenharmony_ci } 10823af6ab5fSopenharmony_ci 10833af6ab5fSopenharmony_ci auto parent = typeAnnotation->Parent(); 10843af6ab5fSopenharmony_ci if (parent->IsScriptFunction() && parent->AsScriptFunction()->ReturnTypeAnnotation() == typeAnnotation) { 10853af6ab5fSopenharmony_ci return true; 10863af6ab5fSopenharmony_ci } 10873af6ab5fSopenharmony_ci if (parent->IsETSFunctionType() && parent->AsETSFunctionType()->ReturnType() == typeAnnotation) { 10883af6ab5fSopenharmony_ci return true; 10893af6ab5fSopenharmony_ci } 10903af6ab5fSopenharmony_ci if (parent->IsTSTypeParameterInstantiation() || parent->IsTSTypeParameter()) { 10913af6ab5fSopenharmony_ci return true; 10923af6ab5fSopenharmony_ci } 10933af6ab5fSopenharmony_ci LogTypeError({"'void' used as type annotation."}, typeAnnotation->Start()); 10943af6ab5fSopenharmony_ci return false; 10953af6ab5fSopenharmony_ci} 10963af6ab5fSopenharmony_civoid ETSChecker::ApplySmartCast(varbinder::Variable const *const variable, checker::Type *const smartType) noexcept 10973af6ab5fSopenharmony_ci{ 10983af6ab5fSopenharmony_ci ASSERT(variable != nullptr); 10993af6ab5fSopenharmony_ci if (smartType != nullptr) { 11003af6ab5fSopenharmony_ci auto *variableType = variable->TsType(); 11013af6ab5fSopenharmony_ci 11023af6ab5fSopenharmony_ci if (Relation()->IsIdenticalTo(variableType, smartType)) { 11033af6ab5fSopenharmony_ci Context().RemoveSmartCast(variable); 11043af6ab5fSopenharmony_ci } else { 11053af6ab5fSopenharmony_ci Context().SetSmartCast(variable, smartType); 11063af6ab5fSopenharmony_ci } 11073af6ab5fSopenharmony_ci } 11083af6ab5fSopenharmony_ci} 11093af6ab5fSopenharmony_ci 11103af6ab5fSopenharmony_cibool CheckerContext::CheckTestOrSmartCastCondition(SmartCastTuple const &types) 11113af6ab5fSopenharmony_ci{ 11123af6ab5fSopenharmony_ci auto *const &variable = std::get<VARIABLE_POSITION>(types); 11133af6ab5fSopenharmony_ci auto *const &consequentTypeNew = std::get<CONSEQUENT_TYPE_POSITION>(types); 11143af6ab5fSopenharmony_ci auto *const &alternateTypeNew = std::get<ALTERNATE_TYPE_POSITION>(types); 11153af6ab5fSopenharmony_ci 11163af6ab5fSopenharmony_ci if (auto const it = testSmartCasts_.find(variable); it != testSmartCasts_.end()) { 11173af6ab5fSopenharmony_ci auto *const consequentTypeOld = it->second.first; 11183af6ab5fSopenharmony_ci if (consequentTypeOld == nullptr) { 11193af6ab5fSopenharmony_ci return true; 11203af6ab5fSopenharmony_ci } 11213af6ab5fSopenharmony_ci 11223af6ab5fSopenharmony_ci if (consequentTypeNew != nullptr && !parent_->Relation()->IsIdenticalTo(consequentTypeOld, consequentTypeNew)) { 11233af6ab5fSopenharmony_ci it->second.first = parent_->AsETSChecker()->CreateETSUnionType({consequentTypeOld, consequentTypeNew}); 11243af6ab5fSopenharmony_ci } 11253af6ab5fSopenharmony_ci 11263af6ab5fSopenharmony_ci if (auto *const alternateTypeOld = it->second.second; alternateTypeOld != nullptr) { 11273af6ab5fSopenharmony_ci if (alternateTypeNew != nullptr && 11283af6ab5fSopenharmony_ci !parent_->Relation()->IsIdenticalTo(alternateTypeOld, alternateTypeNew)) { 11293af6ab5fSopenharmony_ci it->second.second = parent_->AsETSChecker()->CreateETSUnionType({alternateTypeOld, alternateTypeNew}); 11303af6ab5fSopenharmony_ci } 11313af6ab5fSopenharmony_ci } else { 11323af6ab5fSopenharmony_ci it->second.second = alternateTypeNew; 11333af6ab5fSopenharmony_ci } 11343af6ab5fSopenharmony_ci 11353af6ab5fSopenharmony_ci return false; 11363af6ab5fSopenharmony_ci } 11373af6ab5fSopenharmony_ci 11383af6ab5fSopenharmony_ci // NOTE: now we support only cases like 'if (x != null || y != null)' or 'if (x instanceof A || x instanceof B)' 11393af6ab5fSopenharmony_ci // although it seems that the resulting variable type in the second case isn't used in subsequent code directly. 11403af6ab5fSopenharmony_ci // More complex conditions can be implemented later on if the need arises. 11413af6ab5fSopenharmony_ci testSmartCasts_.emplace(variable, std::make_pair(consequentTypeNew, alternateTypeNew)); 11423af6ab5fSopenharmony_ci return true; 11433af6ab5fSopenharmony_ci} 11443af6ab5fSopenharmony_ci 11453af6ab5fSopenharmony_ci//==============================================================================// 11463af6ab5fSopenharmony_ci 11473af6ab5fSopenharmony_civoid ETSChecker::SetArrayPreferredTypeForNestedMemberExpressions(ir::MemberExpression *expr, Type *annotationType) 11483af6ab5fSopenharmony_ci{ 11493af6ab5fSopenharmony_ci if ((expr == nullptr) || (annotationType == nullptr)) { 11503af6ab5fSopenharmony_ci return; 11513af6ab5fSopenharmony_ci } 11523af6ab5fSopenharmony_ci 11533af6ab5fSopenharmony_ci if (expr->Kind() != ir::MemberExpressionKind::ELEMENT_ACCESS) { 11543af6ab5fSopenharmony_ci return; 11553af6ab5fSopenharmony_ci } 11563af6ab5fSopenharmony_ci 11573af6ab5fSopenharmony_ci // Expand all member expressions 11583af6ab5fSopenharmony_ci Type *elementType = annotationType; 11593af6ab5fSopenharmony_ci ir::Expression *object = expr->Object(); 11603af6ab5fSopenharmony_ci while ((object != nullptr) && (object->IsMemberExpression())) { 11613af6ab5fSopenharmony_ci ir::MemberExpression *memberExpr = object->AsMemberExpression(); 11623af6ab5fSopenharmony_ci if (memberExpr->Kind() != ir::MemberExpressionKind::ELEMENT_ACCESS) { 11633af6ab5fSopenharmony_ci return; 11643af6ab5fSopenharmony_ci } 11653af6ab5fSopenharmony_ci 11663af6ab5fSopenharmony_ci object = memberExpr->Object(); 11673af6ab5fSopenharmony_ci elementType = CreateETSArrayType(elementType); 11683af6ab5fSopenharmony_ci } 11693af6ab5fSopenharmony_ci 11703af6ab5fSopenharmony_ci // Set explicit target type for array 11713af6ab5fSopenharmony_ci if ((object != nullptr) && (object->IsArrayExpression())) { 11723af6ab5fSopenharmony_ci ir::ArrayExpression *array = object->AsArrayExpression(); 11733af6ab5fSopenharmony_ci array->SetPreferredType(CreateETSArrayType(elementType)); 11743af6ab5fSopenharmony_ci } 11753af6ab5fSopenharmony_ci} 11763af6ab5fSopenharmony_ci 11773af6ab5fSopenharmony_cistatic void CheckExpandedType(Type *expandedAliasType, std::set<util::StringView> ¶metersNeedToBeBoxed, 11783af6ab5fSopenharmony_ci bool needToBeBoxed) 11793af6ab5fSopenharmony_ci{ 11803af6ab5fSopenharmony_ci if (expandedAliasType->IsETSTypeParameter()) { 11813af6ab5fSopenharmony_ci auto paramName = expandedAliasType->AsETSTypeParameter()->GetDeclNode()->Name()->Name(); 11823af6ab5fSopenharmony_ci if (needToBeBoxed) { 11833af6ab5fSopenharmony_ci parametersNeedToBeBoxed.insert(paramName); 11843af6ab5fSopenharmony_ci } 11853af6ab5fSopenharmony_ci } else if (expandedAliasType->IsETSObjectType()) { 11863af6ab5fSopenharmony_ci auto objectType = expandedAliasType->AsETSObjectType(); 11873af6ab5fSopenharmony_ci needToBeBoxed = 11883af6ab5fSopenharmony_ci objectType->GetDeclNode()->IsClassDefinition() || objectType->GetDeclNode()->IsTSInterfaceDeclaration(); 11893af6ab5fSopenharmony_ci for (const auto typeArgument : objectType->TypeArguments()) { 11903af6ab5fSopenharmony_ci CheckExpandedType(typeArgument, parametersNeedToBeBoxed, needToBeBoxed); 11913af6ab5fSopenharmony_ci } 11923af6ab5fSopenharmony_ci } else if (expandedAliasType->IsETSTupleType()) { 11933af6ab5fSopenharmony_ci auto tupleType = expandedAliasType->AsETSTupleType(); 11943af6ab5fSopenharmony_ci needToBeBoxed = false; 11953af6ab5fSopenharmony_ci for (auto type : tupleType->GetTupleTypesList()) { 11963af6ab5fSopenharmony_ci CheckExpandedType(type, parametersNeedToBeBoxed, needToBeBoxed); 11973af6ab5fSopenharmony_ci } 11983af6ab5fSopenharmony_ci } else if (expandedAliasType->IsETSArrayType()) { 11993af6ab5fSopenharmony_ci auto arrayType = expandedAliasType->AsETSArrayType(); 12003af6ab5fSopenharmony_ci needToBeBoxed = false; 12013af6ab5fSopenharmony_ci auto elementType = arrayType->ElementType(); 12023af6ab5fSopenharmony_ci CheckExpandedType(elementType, parametersNeedToBeBoxed, needToBeBoxed); 12033af6ab5fSopenharmony_ci } else if (expandedAliasType->IsETSUnionType()) { 12043af6ab5fSopenharmony_ci auto unionType = expandedAliasType->AsETSUnionType(); 12053af6ab5fSopenharmony_ci needToBeBoxed = false; 12063af6ab5fSopenharmony_ci for (auto type : unionType->ConstituentTypes()) { 12073af6ab5fSopenharmony_ci CheckExpandedType(type, parametersNeedToBeBoxed, needToBeBoxed); 12083af6ab5fSopenharmony_ci } 12093af6ab5fSopenharmony_ci } 12103af6ab5fSopenharmony_ci} 12113af6ab5fSopenharmony_ci 12123af6ab5fSopenharmony_ciType *ETSChecker::HandleTypeAlias(ir::Expression *const name, const ir::TSTypeParameterInstantiation *const typeParams) 12133af6ab5fSopenharmony_ci{ 12143af6ab5fSopenharmony_ci ASSERT(name->IsIdentifier() && name->AsIdentifier()->Variable() && 12153af6ab5fSopenharmony_ci name->AsIdentifier()->Variable()->Declaration()->IsTypeAliasDecl()); 12163af6ab5fSopenharmony_ci 12173af6ab5fSopenharmony_ci auto *const typeAliasNode = 12183af6ab5fSopenharmony_ci name->AsIdentifier()->Variable()->Declaration()->AsTypeAliasDecl()->Node()->AsTSTypeAliasDeclaration(); 12193af6ab5fSopenharmony_ci 12203af6ab5fSopenharmony_ci // NOTE (mmartin): modify for default params 12213af6ab5fSopenharmony_ci if ((typeParams == nullptr) != (typeAliasNode->TypeParams() == nullptr)) { 12223af6ab5fSopenharmony_ci if (typeParams == nullptr) { 12233af6ab5fSopenharmony_ci LogTypeError("Type alias declaration is generic, but no type parameters were provided", name->Start()); 12243af6ab5fSopenharmony_ci return GlobalTypeError(); 12253af6ab5fSopenharmony_ci } 12263af6ab5fSopenharmony_ci 12273af6ab5fSopenharmony_ci LogTypeError("Type alias declaration is not generic, but type parameters were provided", typeParams->Start()); 12283af6ab5fSopenharmony_ci return GlobalTypeError(); 12293af6ab5fSopenharmony_ci } 12303af6ab5fSopenharmony_ci 12313af6ab5fSopenharmony_ci if (typeParams == nullptr) { 12323af6ab5fSopenharmony_ci // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) 12333af6ab5fSopenharmony_ci return GetReferencedTypeBase(name); 12343af6ab5fSopenharmony_ci } 12353af6ab5fSopenharmony_ci 12363af6ab5fSopenharmony_ci for (auto *const origTypeParam : typeParams->Params()) { 12373af6ab5fSopenharmony_ci origTypeParam->Check(this); 12383af6ab5fSopenharmony_ci } 12393af6ab5fSopenharmony_ci 12403af6ab5fSopenharmony_ci // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) 12413af6ab5fSopenharmony_ci Type *const aliasType = GetReferencedTypeBase(name); 12423af6ab5fSopenharmony_ci auto *aliasSub = NewSubstitution(); 12433af6ab5fSopenharmony_ci if (typeAliasNode->TypeParams()->Params().size() != typeParams->Params().size()) { 12443af6ab5fSopenharmony_ci LogTypeError("Wrong number of type parameters for generic type alias", typeParams->Start()); 12453af6ab5fSopenharmony_ci return GlobalTypeError(); 12463af6ab5fSopenharmony_ci } 12473af6ab5fSopenharmony_ci 12483af6ab5fSopenharmony_ci std::set<util::StringView> parametersNeedToBeBoxed; 12493af6ab5fSopenharmony_ci auto expandedAliasType = aliasType->Substitute(Relation(), aliasSub); 12503af6ab5fSopenharmony_ci CheckExpandedType(expandedAliasType, parametersNeedToBeBoxed, false); 12513af6ab5fSopenharmony_ci 12523af6ab5fSopenharmony_ci for (std::size_t idx = 0; idx < typeAliasNode->TypeParams()->Params().size(); ++idx) { 12533af6ab5fSopenharmony_ci auto *typeAliasTypeName = typeAliasNode->TypeParams()->Params().at(idx)->Name(); 12543af6ab5fSopenharmony_ci auto *typeAliasType = typeAliasTypeName->Variable()->TsType(); 12553af6ab5fSopenharmony_ci if (!typeAliasType->IsETSTypeParameter()) { 12563af6ab5fSopenharmony_ci continue; 12573af6ab5fSopenharmony_ci } 12583af6ab5fSopenharmony_ci auto paramType = typeParams->Params().at(idx)->TsType(); 12593af6ab5fSopenharmony_ci if (parametersNeedToBeBoxed.find(typeAliasTypeName->Name()) != parametersNeedToBeBoxed.end()) { 12603af6ab5fSopenharmony_ci auto boxedType = PrimitiveTypeAsETSBuiltinType(typeParams->Params().at(idx)->GetType(this)); 12613af6ab5fSopenharmony_ci if (boxedType != nullptr) { 12623af6ab5fSopenharmony_ci paramType = boxedType; 12633af6ab5fSopenharmony_ci } 12643af6ab5fSopenharmony_ci } 12653af6ab5fSopenharmony_ci aliasSub->insert({typeAliasType->AsETSTypeParameter(), paramType}); 12663af6ab5fSopenharmony_ci } 12673af6ab5fSopenharmony_ci 12683af6ab5fSopenharmony_ci // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) 12693af6ab5fSopenharmony_ci ValidateGenericTypeAliasForClonedNode(typeAliasNode->AsTSTypeAliasDeclaration(), typeParams); 12703af6ab5fSopenharmony_ci 12713af6ab5fSopenharmony_ci return aliasType->Substitute(Relation(), aliasSub); 12723af6ab5fSopenharmony_ci} 12733af6ab5fSopenharmony_ci 12743af6ab5fSopenharmony_cistd::vector<util::StringView> ETSChecker::GetNameForSynteticObjectType(const util::StringView &source) 12753af6ab5fSopenharmony_ci{ 12763af6ab5fSopenharmony_ci const std::string str = source.Mutf8(); 12773af6ab5fSopenharmony_ci std::istringstream ss {str}; 12783af6ab5fSopenharmony_ci const char delimiter = '.'; 12793af6ab5fSopenharmony_ci std::string token; 12803af6ab5fSopenharmony_ci 12813af6ab5fSopenharmony_ci std::vector<util::StringView> syntheticName {}; 12823af6ab5fSopenharmony_ci 12833af6ab5fSopenharmony_ci while (std::getline(ss, token, delimiter)) { 12843af6ab5fSopenharmony_ci if (!token.empty()) { 12853af6ab5fSopenharmony_ci util::UString sV(token, Allocator()); 12863af6ab5fSopenharmony_ci syntheticName.emplace_back(sV.View()); 12873af6ab5fSopenharmony_ci } 12883af6ab5fSopenharmony_ci } 12893af6ab5fSopenharmony_ci 12903af6ab5fSopenharmony_ci return syntheticName; 12913af6ab5fSopenharmony_ci} 12923af6ab5fSopenharmony_ci 12933af6ab5fSopenharmony_cistd::pair<bool, util::StringView> FindSpecifierForModuleObject(ir::ETSImportDeclaration *importDecl, 12943af6ab5fSopenharmony_ci util::StringView const &name) 12953af6ab5fSopenharmony_ci{ 12963af6ab5fSopenharmony_ci if (importDecl == nullptr) { 12973af6ab5fSopenharmony_ci return std::make_pair(true, util::StringView()); 12983af6ab5fSopenharmony_ci } 12993af6ab5fSopenharmony_ci 13003af6ab5fSopenharmony_ci for (auto item : importDecl->Specifiers()) { 13013af6ab5fSopenharmony_ci if (item->IsImportSpecifier() && item->AsImportSpecifier()->Imported()->Name().Is(name.Mutf8())) { 13023af6ab5fSopenharmony_ci if (!item->AsImportSpecifier()->Imported()->Name().Is(item->AsImportSpecifier()->Local()->Name().Mutf8())) { 13033af6ab5fSopenharmony_ci return std::make_pair(true, item->AsImportSpecifier()->Local()->Name()); 13043af6ab5fSopenharmony_ci } 13053af6ab5fSopenharmony_ci return std::make_pair(true, util::StringView()); 13063af6ab5fSopenharmony_ci } 13073af6ab5fSopenharmony_ci } 13083af6ab5fSopenharmony_ci return std::make_pair(false, util::StringView()); 13093af6ab5fSopenharmony_ci} 13103af6ab5fSopenharmony_ci 13113af6ab5fSopenharmony_citemplate <checker::PropertyType TYPE> 13123af6ab5fSopenharmony_civoid ETSChecker::BindingsModuleObjectAddProperty(checker::ETSObjectType *moduleObjType, 13133af6ab5fSopenharmony_ci ir::ETSImportDeclaration *importDecl, 13143af6ab5fSopenharmony_ci const varbinder::Scope::VariableMap &bindings) 13153af6ab5fSopenharmony_ci{ 13163af6ab5fSopenharmony_ci for (auto [_, var] : bindings) { 13173af6ab5fSopenharmony_ci (void)_; 13183af6ab5fSopenharmony_ci auto [found, aliasedName] = FindSpecifierForModuleObject(importDecl, var->AsLocalVariable()->Name()); 13193af6ab5fSopenharmony_ci if ((var->AsLocalVariable()->Declaration()->Node()->IsExported() || 13203af6ab5fSopenharmony_ci var->AsLocalVariable()->Declaration()->Node()->IsExportedType()) && 13213af6ab5fSopenharmony_ci found) { 13223af6ab5fSopenharmony_ci if (!aliasedName.Empty()) { 13233af6ab5fSopenharmony_ci moduleObjType->AddReExportAlias(var->Declaration()->Name(), aliasedName); 13243af6ab5fSopenharmony_ci } 13253af6ab5fSopenharmony_ci moduleObjType->AddProperty<TYPE>(var->AsLocalVariable(), 13263af6ab5fSopenharmony_ci FindPropNameForNamespaceImport(var->AsLocalVariable()->Name())); 13273af6ab5fSopenharmony_ci } 13283af6ab5fSopenharmony_ci } 13293af6ab5fSopenharmony_ci} 13303af6ab5fSopenharmony_ci 13313af6ab5fSopenharmony_ciutil::StringView ETSChecker::FindPropNameForNamespaceImport(const util::StringView &originalName) 13323af6ab5fSopenharmony_ci{ 13333af6ab5fSopenharmony_ci if (auto relatedMapItem = 13343af6ab5fSopenharmony_ci VarBinder()->AsETSBinder()->GetSelectiveExportAliasMultimap().find(Program()->SourceFilePath()); 13353af6ab5fSopenharmony_ci relatedMapItem != VarBinder()->AsETSBinder()->GetSelectiveExportAliasMultimap().end()) { 13363af6ab5fSopenharmony_ci if (auto result = std::find_if(relatedMapItem->second.begin(), relatedMapItem->second.end(), 13373af6ab5fSopenharmony_ci [originalName](const auto &item) { return item.second == originalName; }); 13383af6ab5fSopenharmony_ci result != relatedMapItem->second.end()) { 13393af6ab5fSopenharmony_ci return result->first; 13403af6ab5fSopenharmony_ci } 13413af6ab5fSopenharmony_ci } 13423af6ab5fSopenharmony_ci 13433af6ab5fSopenharmony_ci return originalName; 13443af6ab5fSopenharmony_ci} 13453af6ab5fSopenharmony_ci 13463af6ab5fSopenharmony_ci// Helps to prevent searching for the imported file among external sources if it is the entry program 13473af6ab5fSopenharmony_cistatic parser::Program *SelectEntryOrExternalProgram(varbinder::ETSBinder *etsBinder, 13483af6ab5fSopenharmony_ci const util::StringView &importPath) 13493af6ab5fSopenharmony_ci{ 13503af6ab5fSopenharmony_ci if (importPath.Is(etsBinder->GetGlobalRecordTable()->Program()->AbsoluteName().Mutf8())) { 13513af6ab5fSopenharmony_ci return etsBinder->GetGlobalRecordTable()->Program(); 13523af6ab5fSopenharmony_ci } 13533af6ab5fSopenharmony_ci 13543af6ab5fSopenharmony_ci auto programList = etsBinder->GetProgramList(importPath); 13553af6ab5fSopenharmony_ci ASSERT(!programList.empty()); 13563af6ab5fSopenharmony_ci return programList.front(); 13573af6ab5fSopenharmony_ci} 13583af6ab5fSopenharmony_ci 13593af6ab5fSopenharmony_civoid ETSChecker::SetPropertiesForModuleObject(checker::ETSObjectType *moduleObjType, const util::StringView &importPath, 13603af6ab5fSopenharmony_ci ir::ETSImportDeclaration *importDecl) 13613af6ab5fSopenharmony_ci{ 13623af6ab5fSopenharmony_ci parser::Program *program = 13633af6ab5fSopenharmony_ci SelectEntryOrExternalProgram(static_cast<varbinder::ETSBinder *>(VarBinder()), importPath); 13643af6ab5fSopenharmony_ci // Check imported properties before assigning them to module object 13653af6ab5fSopenharmony_ci if (!program->IsASTChecked()) { 13663af6ab5fSopenharmony_ci // NOTE: helps to avoid endless loop in case of recursive imports that uses all bindings 13673af6ab5fSopenharmony_ci program->MarkASTAsChecked(); 13683af6ab5fSopenharmony_ci program->Ast()->Check(this); 13693af6ab5fSopenharmony_ci } 13703af6ab5fSopenharmony_ci 13713af6ab5fSopenharmony_ci BindingsModuleObjectAddProperty<checker::PropertyType::STATIC_FIELD>( 13723af6ab5fSopenharmony_ci moduleObjType, importDecl, program->GlobalClassScope()->StaticFieldScope()->Bindings()); 13733af6ab5fSopenharmony_ci 13743af6ab5fSopenharmony_ci BindingsModuleObjectAddProperty<checker::PropertyType::STATIC_METHOD>( 13753af6ab5fSopenharmony_ci moduleObjType, importDecl, program->GlobalClassScope()->StaticMethodScope()->Bindings()); 13763af6ab5fSopenharmony_ci 13773af6ab5fSopenharmony_ci BindingsModuleObjectAddProperty<checker::PropertyType::STATIC_DECL>( 13783af6ab5fSopenharmony_ci moduleObjType, importDecl, program->GlobalClassScope()->StaticDeclScope()->Bindings()); 13793af6ab5fSopenharmony_ci 13803af6ab5fSopenharmony_ci BindingsModuleObjectAddProperty<checker::PropertyType::STATIC_DECL>( 13813af6ab5fSopenharmony_ci moduleObjType, importDecl, program->GlobalClassScope()->InstanceDeclScope()->Bindings()); 13823af6ab5fSopenharmony_ci 13833af6ab5fSopenharmony_ci BindingsModuleObjectAddProperty<checker::PropertyType::STATIC_DECL>( 13843af6ab5fSopenharmony_ci moduleObjType, importDecl, program->GlobalClassScope()->TypeAliasScope()->Bindings()); 13853af6ab5fSopenharmony_ci} 13863af6ab5fSopenharmony_ci 13873af6ab5fSopenharmony_civoid ETSChecker::SetrModuleObjectTsType(ir::Identifier *local, checker::ETSObjectType *moduleObjType) 13883af6ab5fSopenharmony_ci{ 13893af6ab5fSopenharmony_ci auto *etsBinder = static_cast<varbinder::ETSBinder *>(VarBinder()); 13903af6ab5fSopenharmony_ci 13913af6ab5fSopenharmony_ci for (auto [bindingName, var] : etsBinder->TopScope()->Bindings()) { 13923af6ab5fSopenharmony_ci if (bindingName.Is(local->Name().Mutf8())) { 13933af6ab5fSopenharmony_ci var->SetTsType(moduleObjType); 13943af6ab5fSopenharmony_ci } 13953af6ab5fSopenharmony_ci } 13963af6ab5fSopenharmony_ci} 13973af6ab5fSopenharmony_ci 13983af6ab5fSopenharmony_ciType *ETSChecker::GetReferencedTypeFromBase([[maybe_unused]] Type *baseType, [[maybe_unused]] ir::Expression *name) 13993af6ab5fSopenharmony_ci{ 14003af6ab5fSopenharmony_ci LogTypeError("Invalid type reference.", name->Start()); 14013af6ab5fSopenharmony_ci name->SetTsType(GlobalTypeError()); 14023af6ab5fSopenharmony_ci return name->TsTypeOrError(); 14033af6ab5fSopenharmony_ci} 14043af6ab5fSopenharmony_ci 14053af6ab5fSopenharmony_ciType *ETSChecker::GetReferencedTypeBase(ir::Expression *name) 14063af6ab5fSopenharmony_ci{ 14073af6ab5fSopenharmony_ci if (name->IsTSQualifiedName()) { 14083af6ab5fSopenharmony_ci return name->Check(this); 14093af6ab5fSopenharmony_ci } 14103af6ab5fSopenharmony_ci 14113af6ab5fSopenharmony_ci ASSERT(name->IsIdentifier() && name->AsIdentifier()->Variable() != nullptr); 14123af6ab5fSopenharmony_ci 14133af6ab5fSopenharmony_ci // NOTE: kbaladurin. forbid usage imported entities as types without declarations 14143af6ab5fSopenharmony_ci auto *importData = VarBinder()->AsETSBinder()->DynamicImportDataForVar(name->AsIdentifier()->Variable()); 14153af6ab5fSopenharmony_ci if (importData != nullptr && importData->import->IsPureDynamic()) { 14163af6ab5fSopenharmony_ci name->SetTsType(GlobalBuiltinDynamicType(importData->import->Language())); 14173af6ab5fSopenharmony_ci return name->TsType(); 14183af6ab5fSopenharmony_ci } 14193af6ab5fSopenharmony_ci 14203af6ab5fSopenharmony_ci auto *refVar = name->AsIdentifier()->Variable()->AsLocalVariable(); 14213af6ab5fSopenharmony_ci 14223af6ab5fSopenharmony_ci checker::Type *tsType = nullptr; 14233af6ab5fSopenharmony_ci switch (refVar->Declaration()->Node()->Type()) { 14243af6ab5fSopenharmony_ci case ir::AstNodeType::TS_INTERFACE_DECLARATION: { 14253af6ab5fSopenharmony_ci tsType = GetTypeFromInterfaceReference(refVar); 14263af6ab5fSopenharmony_ci break; 14273af6ab5fSopenharmony_ci } 14283af6ab5fSopenharmony_ci case ir::AstNodeType::CLASS_DECLARATION: 14293af6ab5fSopenharmony_ci case ir::AstNodeType::STRUCT_DECLARATION: 14303af6ab5fSopenharmony_ci case ir::AstNodeType::CLASS_DEFINITION: { 14313af6ab5fSopenharmony_ci tsType = GetTypeFromClassReference(refVar); 14323af6ab5fSopenharmony_ci break; 14333af6ab5fSopenharmony_ci } 14343af6ab5fSopenharmony_ci case ir::AstNodeType::TS_ENUM_DECLARATION: { 14353af6ab5fSopenharmony_ci // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) 14363af6ab5fSopenharmony_ci tsType = GetTypeFromEnumReference(refVar); 14373af6ab5fSopenharmony_ci break; 14383af6ab5fSopenharmony_ci } 14393af6ab5fSopenharmony_ci case ir::AstNodeType::TS_TYPE_PARAMETER: { 14403af6ab5fSopenharmony_ci tsType = GetTypeFromTypeParameterReference(refVar, name->Start()); 14413af6ab5fSopenharmony_ci break; 14423af6ab5fSopenharmony_ci } 14433af6ab5fSopenharmony_ci case ir::AstNodeType::TS_TYPE_ALIAS_DECLARATION: { 14443af6ab5fSopenharmony_ci tsType = GetTypeFromTypeAliasReference(refVar); 14453af6ab5fSopenharmony_ci break; 14463af6ab5fSopenharmony_ci } 14473af6ab5fSopenharmony_ci default: { 14483af6ab5fSopenharmony_ci UNREACHABLE(); 14493af6ab5fSopenharmony_ci } 14503af6ab5fSopenharmony_ci } 14513af6ab5fSopenharmony_ci name->SetTsType(tsType); 14523af6ab5fSopenharmony_ci return tsType; 14533af6ab5fSopenharmony_ci} 14543af6ab5fSopenharmony_ci 14553af6ab5fSopenharmony_civoid ETSChecker::ConcatConstantString(util::UString &target, Type *type) 14563af6ab5fSopenharmony_ci{ 14573af6ab5fSopenharmony_ci switch (ETSType(type)) { 14583af6ab5fSopenharmony_ci case TypeFlag::ETS_OBJECT: { 14593af6ab5fSopenharmony_ci ASSERT(type->IsETSStringType()); 14603af6ab5fSopenharmony_ci target.Append(type->AsETSStringType()->GetValue()); 14613af6ab5fSopenharmony_ci break; 14623af6ab5fSopenharmony_ci } 14633af6ab5fSopenharmony_ci case TypeFlag::ETS_BOOLEAN: { 14643af6ab5fSopenharmony_ci target.Append(type->AsETSBooleanType()->GetValue() ? "true" : "false"); 14653af6ab5fSopenharmony_ci break; 14663af6ab5fSopenharmony_ci } 14673af6ab5fSopenharmony_ci case TypeFlag::BYTE: { 14683af6ab5fSopenharmony_ci target.Append(std::to_string(type->AsByteType()->GetValue())); 14693af6ab5fSopenharmony_ci break; 14703af6ab5fSopenharmony_ci } 14713af6ab5fSopenharmony_ci case TypeFlag::CHAR: { 14723af6ab5fSopenharmony_ci std::string s(1, type->AsCharType()->GetValue()); 14733af6ab5fSopenharmony_ci target.Append(s); 14743af6ab5fSopenharmony_ci break; 14753af6ab5fSopenharmony_ci } 14763af6ab5fSopenharmony_ci case TypeFlag::SHORT: { 14773af6ab5fSopenharmony_ci target.Append(std::to_string(type->AsShortType()->GetValue())); 14783af6ab5fSopenharmony_ci break; 14793af6ab5fSopenharmony_ci } 14803af6ab5fSopenharmony_ci case TypeFlag::INT: { 14813af6ab5fSopenharmony_ci target.Append(std::to_string(type->AsIntType()->GetValue())); 14823af6ab5fSopenharmony_ci break; 14833af6ab5fSopenharmony_ci } 14843af6ab5fSopenharmony_ci case TypeFlag::LONG: { 14853af6ab5fSopenharmony_ci target.Append(std::to_string(type->AsLongType()->GetValue())); 14863af6ab5fSopenharmony_ci break; 14873af6ab5fSopenharmony_ci } 14883af6ab5fSopenharmony_ci case TypeFlag::FLOAT: { 14893af6ab5fSopenharmony_ci target.Append(std::to_string(type->AsFloatType()->GetValue())); 14903af6ab5fSopenharmony_ci break; 14913af6ab5fSopenharmony_ci } 14923af6ab5fSopenharmony_ci case TypeFlag::DOUBLE: { 14933af6ab5fSopenharmony_ci target.Append(std::to_string(type->AsDoubleType()->GetValue())); 14943af6ab5fSopenharmony_ci break; 14953af6ab5fSopenharmony_ci } 14963af6ab5fSopenharmony_ci default: { 14973af6ab5fSopenharmony_ci UNREACHABLE(); 14983af6ab5fSopenharmony_ci } 14993af6ab5fSopenharmony_ci } 15003af6ab5fSopenharmony_ci} 15013af6ab5fSopenharmony_ci 15023af6ab5fSopenharmony_ciType *ETSChecker::HandleStringConcatenation(Type *leftType, Type *rightType) 15033af6ab5fSopenharmony_ci{ 15043af6ab5fSopenharmony_ci ASSERT(leftType->IsETSStringType() || rightType->IsETSStringType()); 15053af6ab5fSopenharmony_ci 15063af6ab5fSopenharmony_ci if (!leftType->HasTypeFlag(checker::TypeFlag::CONSTANT) || !rightType->HasTypeFlag(checker::TypeFlag::CONSTANT) || 15073af6ab5fSopenharmony_ci leftType->IsETSBigIntType() || rightType->IsETSBigIntType()) { 15083af6ab5fSopenharmony_ci return GlobalETSStringLiteralType(); 15093af6ab5fSopenharmony_ci } 15103af6ab5fSopenharmony_ci 15113af6ab5fSopenharmony_ci util::UString concatenated(Allocator()); 15123af6ab5fSopenharmony_ci ConcatConstantString(concatenated, leftType); 15133af6ab5fSopenharmony_ci ConcatConstantString(concatenated, rightType); 15143af6ab5fSopenharmony_ci 15153af6ab5fSopenharmony_ci return CreateETSStringLiteralType(concatenated.View()); 15163af6ab5fSopenharmony_ci} 15173af6ab5fSopenharmony_ci 15183af6ab5fSopenharmony_cichecker::ETSFunctionType *ETSChecker::FindFunctionInVectorGivenByName(util::StringView name, 15193af6ab5fSopenharmony_ci ArenaVector<checker::ETSFunctionType *> &list) 15203af6ab5fSopenharmony_ci{ 15213af6ab5fSopenharmony_ci for (auto *it : list) { 15223af6ab5fSopenharmony_ci if (it->Name() == name) { 15233af6ab5fSopenharmony_ci return it; 15243af6ab5fSopenharmony_ci } 15253af6ab5fSopenharmony_ci } 15263af6ab5fSopenharmony_ci 15273af6ab5fSopenharmony_ci return nullptr; 15283af6ab5fSopenharmony_ci} 15293af6ab5fSopenharmony_ci 15303af6ab5fSopenharmony_cibool ETSChecker::IsFunctionContainsSignature(checker::ETSFunctionType *funcType, Signature *signature) 15313af6ab5fSopenharmony_ci{ 15323af6ab5fSopenharmony_ci for (auto *it : funcType->CallSignatures()) { 15333af6ab5fSopenharmony_ci Relation()->IsCompatibleTo(it, signature); 15343af6ab5fSopenharmony_ci if (Relation()->IsTrue()) { 15353af6ab5fSopenharmony_ci return true; 15363af6ab5fSopenharmony_ci } 15373af6ab5fSopenharmony_ci } 15383af6ab5fSopenharmony_ci 15393af6ab5fSopenharmony_ci return false; 15403af6ab5fSopenharmony_ci} 15413af6ab5fSopenharmony_ci 15423af6ab5fSopenharmony_cibool ETSChecker::CheckFunctionContainsClashingSignature(const checker::ETSFunctionType *funcType, Signature *signature) 15433af6ab5fSopenharmony_ci{ 15443af6ab5fSopenharmony_ci for (auto *it : funcType->CallSignatures()) { 15453af6ab5fSopenharmony_ci SavedTypeRelationFlagsContext strfCtx(Relation(), TypeRelationFlag::NONE); 15463af6ab5fSopenharmony_ci Relation()->IsCompatibleTo(it, signature); 15473af6ab5fSopenharmony_ci if (Relation()->IsTrue() && it->Function()->Id()->Name() == signature->Function()->Id()->Name()) { 15483af6ab5fSopenharmony_ci std::stringstream ss; 15493af6ab5fSopenharmony_ci it->ToString(ss, nullptr, true); 15503af6ab5fSopenharmony_ci auto sigStr1 = ss.str(); 15513af6ab5fSopenharmony_ci ss.str(std::string {}); // Clear buffer 15523af6ab5fSopenharmony_ci signature->ToString(ss, nullptr, true); 15533af6ab5fSopenharmony_ci auto sigStr2 = ss.str(); 15543af6ab5fSopenharmony_ci LogTypeError({"Function '", it->Function()->Id()->Name(), sigStr1.c_str(), 15553af6ab5fSopenharmony_ci "' is redeclared with different signature '", signature->Function()->Id()->Name(), 15563af6ab5fSopenharmony_ci sigStr2.c_str(), "'"}, 15573af6ab5fSopenharmony_ci signature->Function()->ReturnTypeAnnotation()->Start()); 15583af6ab5fSopenharmony_ci return false; 15593af6ab5fSopenharmony_ci } 15603af6ab5fSopenharmony_ci } 15613af6ab5fSopenharmony_ci return true; 15623af6ab5fSopenharmony_ci} 15633af6ab5fSopenharmony_ci 15643af6ab5fSopenharmony_civoid ETSChecker::MergeSignatures(checker::ETSFunctionType *target, checker::ETSFunctionType *source) 15653af6ab5fSopenharmony_ci{ 15663af6ab5fSopenharmony_ci for (auto *s : source->CallSignatures()) { 15673af6ab5fSopenharmony_ci if (IsFunctionContainsSignature(target, s)) { 15683af6ab5fSopenharmony_ci continue; 15693af6ab5fSopenharmony_ci } 15703af6ab5fSopenharmony_ci 15713af6ab5fSopenharmony_ci if (!CheckFunctionContainsClashingSignature(target, s)) { 15723af6ab5fSopenharmony_ci continue; 15733af6ab5fSopenharmony_ci } 15743af6ab5fSopenharmony_ci target->AddCallSignature(s); 15753af6ab5fSopenharmony_ci } 15763af6ab5fSopenharmony_ci} 15773af6ab5fSopenharmony_ci 15783af6ab5fSopenharmony_civoid ETSChecker::MergeComputedAbstracts(ArenaVector<checker::ETSFunctionType *> &merged, 15793af6ab5fSopenharmony_ci ArenaVector<checker::ETSFunctionType *> ¤t) 15803af6ab5fSopenharmony_ci{ 15813af6ab5fSopenharmony_ci for (auto *curr : current) { 15823af6ab5fSopenharmony_ci auto name = curr->Name(); 15833af6ab5fSopenharmony_ci auto *found = FindFunctionInVectorGivenByName(name, merged); 15843af6ab5fSopenharmony_ci if (found != nullptr) { 15853af6ab5fSopenharmony_ci MergeSignatures(found, curr); 15863af6ab5fSopenharmony_ci continue; 15873af6ab5fSopenharmony_ci } 15883af6ab5fSopenharmony_ci 15893af6ab5fSopenharmony_ci merged.push_back(curr); 15903af6ab5fSopenharmony_ci } 15913af6ab5fSopenharmony_ci} 15923af6ab5fSopenharmony_ci 15933af6ab5fSopenharmony_ciir::AstNode *ETSChecker::FindAncestorGivenByType(ir::AstNode *node, ir::AstNodeType type, const ir::AstNode *endNode) 15943af6ab5fSopenharmony_ci{ 15953af6ab5fSopenharmony_ci auto *iter = node->Parent(); 15963af6ab5fSopenharmony_ci 15973af6ab5fSopenharmony_ci while (iter != endNode) { 15983af6ab5fSopenharmony_ci if (iter->Type() == type) { 15993af6ab5fSopenharmony_ci return iter; 16003af6ab5fSopenharmony_ci } 16013af6ab5fSopenharmony_ci 16023af6ab5fSopenharmony_ci iter = iter->Parent(); 16033af6ab5fSopenharmony_ci } 16043af6ab5fSopenharmony_ci 16053af6ab5fSopenharmony_ci return nullptr; 16063af6ab5fSopenharmony_ci} 16073af6ab5fSopenharmony_ci 16083af6ab5fSopenharmony_ciutil::StringView ETSChecker::GetContainingObjectNameFromSignature(Signature *signature) 16093af6ab5fSopenharmony_ci{ 16103af6ab5fSopenharmony_ci ASSERT(signature->Function()); 16113af6ab5fSopenharmony_ci auto *iter = signature->Function()->Parent(); 16123af6ab5fSopenharmony_ci 16133af6ab5fSopenharmony_ci while (iter != nullptr) { 16143af6ab5fSopenharmony_ci if (iter->IsClassDefinition()) { 16153af6ab5fSopenharmony_ci return iter->AsClassDefinition()->Ident()->Name(); 16163af6ab5fSopenharmony_ci } 16173af6ab5fSopenharmony_ci 16183af6ab5fSopenharmony_ci if (iter->IsTSInterfaceDeclaration()) { 16193af6ab5fSopenharmony_ci return iter->AsTSInterfaceDeclaration()->Id()->Name(); 16203af6ab5fSopenharmony_ci } 16213af6ab5fSopenharmony_ci 16223af6ab5fSopenharmony_ci iter = iter->Parent(); 16233af6ab5fSopenharmony_ci } 16243af6ab5fSopenharmony_ci 16253af6ab5fSopenharmony_ci UNREACHABLE(); 16263af6ab5fSopenharmony_ci return {""}; 16273af6ab5fSopenharmony_ci} 16283af6ab5fSopenharmony_ci 16293af6ab5fSopenharmony_cistd::optional<const ir::AstNode *> ETSChecker::FindJumpTarget(ir::AstNode *node) 16303af6ab5fSopenharmony_ci{ 16313af6ab5fSopenharmony_ci ASSERT(node->IsBreakStatement() || node->IsContinueStatement()); 16323af6ab5fSopenharmony_ci 16333af6ab5fSopenharmony_ci bool const isContinue = node->IsContinueStatement(); 16343af6ab5fSopenharmony_ci 16353af6ab5fSopenharmony_ci // Look for label 16363af6ab5fSopenharmony_ci auto label = isContinue ? node->AsContinueStatement()->Ident() : node->AsBreakStatement()->Ident(); 16373af6ab5fSopenharmony_ci if (label != nullptr) { 16383af6ab5fSopenharmony_ci auto var = label->Variable(); 16393af6ab5fSopenharmony_ci if (var != nullptr && var->Declaration()->IsLabelDecl()) { 16403af6ab5fSopenharmony_ci return var->Declaration()->Node(); 16413af6ab5fSopenharmony_ci } 16423af6ab5fSopenharmony_ci 16433af6ab5fSopenharmony_ci // Failed to resolve variable for label 16443af6ab5fSopenharmony_ci LogUnResolvedError(label); 16453af6ab5fSopenharmony_ci return {}; 16463af6ab5fSopenharmony_ci } 16473af6ab5fSopenharmony_ci 16483af6ab5fSopenharmony_ci // No label, find the nearest loop or switch statement 16493af6ab5fSopenharmony_ci const auto *iter = node->Parent(); 16503af6ab5fSopenharmony_ci while (iter != nullptr) { 16513af6ab5fSopenharmony_ci switch (iter->Type()) { 16523af6ab5fSopenharmony_ci case ir::AstNodeType::DO_WHILE_STATEMENT: 16533af6ab5fSopenharmony_ci case ir::AstNodeType::WHILE_STATEMENT: 16543af6ab5fSopenharmony_ci case ir::AstNodeType::FOR_UPDATE_STATEMENT: 16553af6ab5fSopenharmony_ci case ir::AstNodeType::FOR_OF_STATEMENT: 16563af6ab5fSopenharmony_ci case ir::AstNodeType::SWITCH_STATEMENT: { 16573af6ab5fSopenharmony_ci return iter; 16583af6ab5fSopenharmony_ci } 16593af6ab5fSopenharmony_ci default: { 16603af6ab5fSopenharmony_ci break; 16613af6ab5fSopenharmony_ci } 16623af6ab5fSopenharmony_ci } 16633af6ab5fSopenharmony_ci 16643af6ab5fSopenharmony_ci iter = iter->Parent(); 16653af6ab5fSopenharmony_ci } 16663af6ab5fSopenharmony_ci 16673af6ab5fSopenharmony_ci UNREACHABLE(); 16683af6ab5fSopenharmony_ci} 16693af6ab5fSopenharmony_ci 16703af6ab5fSopenharmony_civarbinder::VariableFlags ETSChecker::GetAccessFlagFromNode(const ir::AstNode *node) 16713af6ab5fSopenharmony_ci{ 16723af6ab5fSopenharmony_ci if (node->IsPrivate()) { 16733af6ab5fSopenharmony_ci return varbinder::VariableFlags::PRIVATE; 16743af6ab5fSopenharmony_ci } 16753af6ab5fSopenharmony_ci 16763af6ab5fSopenharmony_ci if (node->IsProtected()) { 16773af6ab5fSopenharmony_ci return varbinder::VariableFlags::PROTECTED; 16783af6ab5fSopenharmony_ci } 16793af6ab5fSopenharmony_ci 16803af6ab5fSopenharmony_ci return varbinder::VariableFlags::PUBLIC; 16813af6ab5fSopenharmony_ci} 16823af6ab5fSopenharmony_ci 16833af6ab5fSopenharmony_ciType *ETSChecker::CheckSwitchDiscriminant(ir::Expression *discriminant) 16843af6ab5fSopenharmony_ci{ 16853af6ab5fSopenharmony_ci discriminant->Check(this); 16863af6ab5fSopenharmony_ci auto *discriminantType = GetNonConstantType(MaybeUnboxExpression(discriminant)); 16873af6ab5fSopenharmony_ci if (!discriminantType->HasTypeFlag(TypeFlag::VALID_SWITCH_TYPE)) { 16883af6ab5fSopenharmony_ci if (!(discriminantType->IsETSObjectType() && 16893af6ab5fSopenharmony_ci discriminantType->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::BUILTIN_STRING | 16903af6ab5fSopenharmony_ci ETSObjectFlags::STRING | ETSObjectFlags::ENUM))) { 16913af6ab5fSopenharmony_ci LogTypeError({"Incompatible types. Found: ", discriminantType, 16923af6ab5fSopenharmony_ci ", required: char , byte , short , int, long , Char , Byte , Short , Int, Long , String " 16933af6ab5fSopenharmony_ci "or an enum type"}, 16943af6ab5fSopenharmony_ci discriminant->Start()); 16953af6ab5fSopenharmony_ci } 16963af6ab5fSopenharmony_ci } 16973af6ab5fSopenharmony_ci 16983af6ab5fSopenharmony_ci return discriminantType; 16993af6ab5fSopenharmony_ci} 17003af6ab5fSopenharmony_ci 17013af6ab5fSopenharmony_civoid ETSChecker::AddBoxingUnboxingFlagsToNode(ir::AstNode *node, Type *boxingUnboxingType) 17023af6ab5fSopenharmony_ci{ 17033af6ab5fSopenharmony_ci if (boxingUnboxingType->IsETSObjectType()) { 17043af6ab5fSopenharmony_ci node->AddBoxingUnboxingFlags(GetBoxingFlag(boxingUnboxingType)); 17053af6ab5fSopenharmony_ci } else if (!boxingUnboxingType->IsETSUnionType()) { 17063af6ab5fSopenharmony_ci node->AddBoxingUnboxingFlags(GetUnboxingFlag(boxingUnboxingType)); 17073af6ab5fSopenharmony_ci } 17083af6ab5fSopenharmony_ci} 17093af6ab5fSopenharmony_ci 17103af6ab5fSopenharmony_ciType *ETSChecker::MaybeBoxExpression(ir::Expression *expr) 17113af6ab5fSopenharmony_ci{ 17123af6ab5fSopenharmony_ci auto *promoted = MaybePromotedBuiltinType(expr->TsTypeOrError()); 17133af6ab5fSopenharmony_ci if (promoted != expr->TsTypeOrError()) { 17143af6ab5fSopenharmony_ci expr->AddBoxingUnboxingFlags(GetBoxingFlag(promoted)); 17153af6ab5fSopenharmony_ci } 17163af6ab5fSopenharmony_ci return promoted; 17173af6ab5fSopenharmony_ci} 17183af6ab5fSopenharmony_ci 17193af6ab5fSopenharmony_ciType *ETSChecker::MaybeUnboxExpression(ir::Expression *expr) 17203af6ab5fSopenharmony_ci{ 17213af6ab5fSopenharmony_ci auto *primitive = MaybePrimitiveBuiltinType(expr->TsType()); 17223af6ab5fSopenharmony_ci if (primitive != expr->TsType()) { 17233af6ab5fSopenharmony_ci expr->AddBoxingUnboxingFlags(GetUnboxingFlag(primitive)); 17243af6ab5fSopenharmony_ci } 17253af6ab5fSopenharmony_ci return primitive; 17263af6ab5fSopenharmony_ci} 17273af6ab5fSopenharmony_ci 17283af6ab5fSopenharmony_civoid ETSChecker::CheckForSameSwitchCases(ArenaVector<ir::SwitchCaseStatement *> const &cases) 17293af6ab5fSopenharmony_ci{ 17303af6ab5fSopenharmony_ci CheckItemCasesConstant(cases); 17313af6ab5fSopenharmony_ci CheckItemCasesDuplicate(cases); 17323af6ab5fSopenharmony_ci} 17333af6ab5fSopenharmony_ci 17343af6ab5fSopenharmony_cistd::string ETSChecker::GetStringFromIdentifierValue(checker::Type *caseType) const 17353af6ab5fSopenharmony_ci{ 17363af6ab5fSopenharmony_ci const auto identifierTypeKind = ETSChecker::TypeKind(caseType); 17373af6ab5fSopenharmony_ci switch (identifierTypeKind) { 17383af6ab5fSopenharmony_ci case TypeFlag::BYTE: { 17393af6ab5fSopenharmony_ci return std::to_string(caseType->AsByteType()->GetValue()); 17403af6ab5fSopenharmony_ci } 17413af6ab5fSopenharmony_ci case TypeFlag::SHORT: { 17423af6ab5fSopenharmony_ci return std::to_string(caseType->AsShortType()->GetValue()); 17433af6ab5fSopenharmony_ci } 17443af6ab5fSopenharmony_ci case TypeFlag::CHAR: { 17453af6ab5fSopenharmony_ci return std::to_string(caseType->AsCharType()->GetValue()); 17463af6ab5fSopenharmony_ci } 17473af6ab5fSopenharmony_ci case TypeFlag::INT: { 17483af6ab5fSopenharmony_ci return std::to_string(caseType->AsIntType()->GetValue()); 17493af6ab5fSopenharmony_ci } 17503af6ab5fSopenharmony_ci case TypeFlag::LONG: { 17513af6ab5fSopenharmony_ci return std::to_string(caseType->AsLongType()->GetValue()); 17523af6ab5fSopenharmony_ci } 17533af6ab5fSopenharmony_ci case TypeFlag::ETS_OBJECT: { 17543af6ab5fSopenharmony_ci VarBinder()->ThrowError(caseType->AsETSObjectType()->Variable()->Declaration()->Node()->Start(), 17553af6ab5fSopenharmony_ci "not implemented"); 17563af6ab5fSopenharmony_ci } 17573af6ab5fSopenharmony_ci default: { 17583af6ab5fSopenharmony_ci UNREACHABLE(); 17593af6ab5fSopenharmony_ci } 17603af6ab5fSopenharmony_ci } 17613af6ab5fSopenharmony_ci} 17623af6ab5fSopenharmony_ci 17633af6ab5fSopenharmony_cibool IsConstantMemberOrIdentifierExpression(ir::Expression *expression) 17643af6ab5fSopenharmony_ci{ 17653af6ab5fSopenharmony_ci if (expression->IsMemberExpression()) { 17663af6ab5fSopenharmony_ci auto *var = expression->AsMemberExpression()->PropVar(); 17673af6ab5fSopenharmony_ci return var->Declaration()->IsConstDecl() || 17683af6ab5fSopenharmony_ci (var->Declaration()->IsReadonlyDecl() && var->HasFlag(varbinder::VariableFlags::STATIC)); 17693af6ab5fSopenharmony_ci } 17703af6ab5fSopenharmony_ci 17713af6ab5fSopenharmony_ci if (expression->IsIdentifier()) { 17723af6ab5fSopenharmony_ci auto *var = expression->AsIdentifier()->Variable(); 17733af6ab5fSopenharmony_ci return var->Declaration()->IsConstDecl() || 17743af6ab5fSopenharmony_ci (var->Declaration()->IsReadonlyDecl() && var->HasFlag(varbinder::VariableFlags::STATIC)); 17753af6ab5fSopenharmony_ci } 17763af6ab5fSopenharmony_ci 17773af6ab5fSopenharmony_ci return false; 17783af6ab5fSopenharmony_ci} 17793af6ab5fSopenharmony_ci 17803af6ab5fSopenharmony_civoid ETSChecker::CheckItemCasesConstant(ArenaVector<ir::SwitchCaseStatement *> const &cases) 17813af6ab5fSopenharmony_ci{ 17823af6ab5fSopenharmony_ci for (auto &it : cases) { 17833af6ab5fSopenharmony_ci auto *caseTest = it->Test(); 17843af6ab5fSopenharmony_ci if (caseTest == nullptr) { 17853af6ab5fSopenharmony_ci continue; 17863af6ab5fSopenharmony_ci } 17873af6ab5fSopenharmony_ci auto *caseType = caseTest->TsType(); 17883af6ab5fSopenharmony_ci if (caseTest->TsType()->IsETSIntEnumType() || caseTest->TsType()->IsETSStringEnumType()) { 17893af6ab5fSopenharmony_ci continue; 17903af6ab5fSopenharmony_ci } 17913af6ab5fSopenharmony_ci 17923af6ab5fSopenharmony_ci if (caseTest->IsIdentifier() || caseTest->IsMemberExpression()) { 17933af6ab5fSopenharmony_ci if (!IsConstantMemberOrIdentifierExpression(caseTest)) { 17943af6ab5fSopenharmony_ci LogTypeError("Constant expression required", it->Start()); 17953af6ab5fSopenharmony_ci continue; 17963af6ab5fSopenharmony_ci } 17973af6ab5fSopenharmony_ci 17983af6ab5fSopenharmony_ci if (!caseType->HasTypeFlag(checker::TypeFlag::VALID_SWITCH_TYPE)) { 17993af6ab5fSopenharmony_ci LogTypeError("Unexpected type " + caseType->ToString(), it->Start()); 18003af6ab5fSopenharmony_ci continue; 18013af6ab5fSopenharmony_ci } 18023af6ab5fSopenharmony_ci continue; 18033af6ab5fSopenharmony_ci } 18043af6ab5fSopenharmony_ci } 18053af6ab5fSopenharmony_ci} 18063af6ab5fSopenharmony_ci 18073af6ab5fSopenharmony_civoid CheckItemEnumType(ir::Expression const *const caseTest, ETSChecker *checker, ETSIntEnumType const *const type, 18083af6ab5fSopenharmony_ci bool &isDup) 18093af6ab5fSopenharmony_ci{ 18103af6ab5fSopenharmony_ci if (caseTest->TsType()->AsETSIntEnumType()->IsSameEnumLiteralType(type)) { 18113af6ab5fSopenharmony_ci isDup = true; 18123af6ab5fSopenharmony_ci checker->LogTypeError("Case duplicate", caseTest->Start()); 18133af6ab5fSopenharmony_ci } 18143af6ab5fSopenharmony_ci} 18153af6ab5fSopenharmony_ci 18163af6ab5fSopenharmony_civoid CheckItemStringEnumType(ir::Expression const *const caseTest, ETSChecker *checker, 18173af6ab5fSopenharmony_ci ETSStringEnumType const *const type, bool &isDup) 18183af6ab5fSopenharmony_ci{ 18193af6ab5fSopenharmony_ci if (caseTest->TsType()->AsETSStringEnumType()->IsSameEnumLiteralType(type)) { 18203af6ab5fSopenharmony_ci isDup = true; 18213af6ab5fSopenharmony_ci checker->LogTypeError("Case duplicate", caseTest->Start()); 18223af6ab5fSopenharmony_ci } 18233af6ab5fSopenharmony_ci} 18243af6ab5fSopenharmony_ci 18253af6ab5fSopenharmony_civoid ETSChecker::CheckItemCasesDuplicate(ArenaVector<ir::SwitchCaseStatement *> const &cases) 18263af6ab5fSopenharmony_ci{ 18273af6ab5fSopenharmony_ci for (size_t caseNum = 0; caseNum < cases.size(); caseNum++) { 18283af6ab5fSopenharmony_ci bool isItemDuplicate = false; 18293af6ab5fSopenharmony_ci for (size_t compareCase = caseNum + 1; compareCase < cases.size(); compareCase++) { 18303af6ab5fSopenharmony_ci auto *caseTest = cases.at(caseNum)->Test(); 18313af6ab5fSopenharmony_ci auto *compareCaseTest = cases.at(compareCase)->Test(); 18323af6ab5fSopenharmony_ci 18333af6ab5fSopenharmony_ci if (caseTest == nullptr || compareCaseTest == nullptr) { 18343af6ab5fSopenharmony_ci continue; 18353af6ab5fSopenharmony_ci } 18363af6ab5fSopenharmony_ci 18373af6ab5fSopenharmony_ci if (caseTest->TsType()->IsETSIntEnumType()) { 18383af6ab5fSopenharmony_ci CheckItemEnumType(caseTest, this, compareCaseTest->TsType()->AsETSIntEnumType(), isItemDuplicate); 18393af6ab5fSopenharmony_ci continue; 18403af6ab5fSopenharmony_ci } 18413af6ab5fSopenharmony_ci 18423af6ab5fSopenharmony_ci if (caseTest->TsType()->IsETSStringEnumType()) { 18433af6ab5fSopenharmony_ci CheckItemStringEnumType(caseTest, this, compareCaseTest->TsType()->AsETSStringEnumType(), 18443af6ab5fSopenharmony_ci isItemDuplicate); 18453af6ab5fSopenharmony_ci continue; 18463af6ab5fSopenharmony_ci } 18473af6ab5fSopenharmony_ci 18483af6ab5fSopenharmony_ci if (caseTest->IsIdentifier() || caseTest->IsMemberExpression()) { 18493af6ab5fSopenharmony_ci CheckIdentifierSwitchCase(caseTest, compareCaseTest, cases.at(caseNum)->Start()); 18503af6ab5fSopenharmony_ci continue; 18513af6ab5fSopenharmony_ci } 18523af6ab5fSopenharmony_ci 18533af6ab5fSopenharmony_ci if (compareCaseTest->IsIdentifier() || compareCaseTest->IsMemberExpression()) { 18543af6ab5fSopenharmony_ci CheckIdentifierSwitchCase(compareCaseTest, caseTest, cases.at(compareCase)->Start()); 18553af6ab5fSopenharmony_ci continue; 18563af6ab5fSopenharmony_ci } 18573af6ab5fSopenharmony_ci 18583af6ab5fSopenharmony_ci if (caseTest->IsLiteral() && compareCaseTest->IsLiteral() && 18593af6ab5fSopenharmony_ci GetStringFromLiteral(caseTest) != GetStringFromLiteral(compareCaseTest)) { 18603af6ab5fSopenharmony_ci continue; 18613af6ab5fSopenharmony_ci } 18623af6ab5fSopenharmony_ci 18633af6ab5fSopenharmony_ci if (!(IsConstantExpression(caseTest, caseTest->TsType()) || caseTest->IsLiteral()) || 18643af6ab5fSopenharmony_ci !(IsConstantExpression(compareCaseTest, compareCaseTest->TsType()) || compareCaseTest->IsLiteral())) { 18653af6ab5fSopenharmony_ci continue; 18663af6ab5fSopenharmony_ci } 18673af6ab5fSopenharmony_ci 18683af6ab5fSopenharmony_ci if (!isItemDuplicate) { 18693af6ab5fSopenharmony_ci isItemDuplicate = true; 18703af6ab5fSopenharmony_ci LogTypeError("Case duplicate", cases.at(compareCase)->Start()); 18713af6ab5fSopenharmony_ci } 18723af6ab5fSopenharmony_ci } 18733af6ab5fSopenharmony_ci } 18743af6ab5fSopenharmony_ci} 18753af6ab5fSopenharmony_ci 18763af6ab5fSopenharmony_cibool ETSChecker::CompareIdentifiersValuesAreDifferent(ir::Expression *compareValue, const std::string &caseValue) 18773af6ab5fSopenharmony_ci{ 18783af6ab5fSopenharmony_ci if (IsConstantMemberOrIdentifierExpression(compareValue)) { 18793af6ab5fSopenharmony_ci checker::Type *compareCaseType = compareValue->TsType(); 18803af6ab5fSopenharmony_ci 18813af6ab5fSopenharmony_ci const auto compareCaseValue = GetStringFromIdentifierValue(compareCaseType); 18823af6ab5fSopenharmony_ci return caseValue != compareCaseValue; 18833af6ab5fSopenharmony_ci } 18843af6ab5fSopenharmony_ci 18853af6ab5fSopenharmony_ci return caseValue != GetStringFromLiteral(compareValue); 18863af6ab5fSopenharmony_ci} 18873af6ab5fSopenharmony_ci 18883af6ab5fSopenharmony_civoid ETSChecker::CheckIdentifierSwitchCase(ir::Expression *currentCase, ir::Expression *compareCase, 18893af6ab5fSopenharmony_ci const lexer::SourcePosition &pos) 18903af6ab5fSopenharmony_ci{ 18913af6ab5fSopenharmony_ci currentCase->Check(this); 18923af6ab5fSopenharmony_ci 18933af6ab5fSopenharmony_ci if (!IsConstantMemberOrIdentifierExpression(currentCase)) { 18943af6ab5fSopenharmony_ci return; 18953af6ab5fSopenharmony_ci } 18963af6ab5fSopenharmony_ci 18973af6ab5fSopenharmony_ci checker::Type *caseType = currentCase->TsType(); 18983af6ab5fSopenharmony_ci 18993af6ab5fSopenharmony_ci if (!caseType->HasTypeFlag(checker::TypeFlag::VALID_SWITCH_TYPE)) { 19003af6ab5fSopenharmony_ci return; 19013af6ab5fSopenharmony_ci } 19023af6ab5fSopenharmony_ci 19033af6ab5fSopenharmony_ci if (!CompareIdentifiersValuesAreDifferent(compareCase, GetStringFromIdentifierValue(caseType))) { 19043af6ab5fSopenharmony_ci LogTypeError("Variable has same value with another switch case", pos); 19053af6ab5fSopenharmony_ci return; 19063af6ab5fSopenharmony_ci } 19073af6ab5fSopenharmony_ci} 19083af6ab5fSopenharmony_ci 19093af6ab5fSopenharmony_cistd::string ETSChecker::GetStringFromLiteral(ir::Expression *caseTest) const 19103af6ab5fSopenharmony_ci{ 19113af6ab5fSopenharmony_ci switch (caseTest->Type()) { 19123af6ab5fSopenharmony_ci case ir::AstNodeType::CHAR_LITERAL: { 19133af6ab5fSopenharmony_ci return std::to_string(caseTest->AsCharLiteral()->Char()); 19143af6ab5fSopenharmony_ci } 19153af6ab5fSopenharmony_ci case ir::AstNodeType::STRING_LITERAL: 19163af6ab5fSopenharmony_ci case ir::AstNodeType::NUMBER_LITERAL: { 19173af6ab5fSopenharmony_ci return util::Helpers::LiteralToPropName(caseTest).Mutf8(); 19183af6ab5fSopenharmony_ci } 19193af6ab5fSopenharmony_ci default: 19203af6ab5fSopenharmony_ci UNREACHABLE(); 19213af6ab5fSopenharmony_ci } 19223af6ab5fSopenharmony_ci} 19233af6ab5fSopenharmony_ci 19243af6ab5fSopenharmony_cibool ETSChecker::IsSameDeclarationType(varbinder::LocalVariable *target, varbinder::LocalVariable *compare) 19253af6ab5fSopenharmony_ci{ 19263af6ab5fSopenharmony_ci return target->Declaration()->Type() == compare->Declaration()->Type(); 19273af6ab5fSopenharmony_ci} 19283af6ab5fSopenharmony_ci 19293af6ab5fSopenharmony_cibool ETSChecker::CheckRethrowingParams(const ir::AstNode *ancestorFunction, const ir::AstNode *node) 19303af6ab5fSopenharmony_ci{ 19313af6ab5fSopenharmony_ci for (const auto param : ancestorFunction->AsScriptFunction()->Signature()->Function()->Params()) { 19323af6ab5fSopenharmony_ci if (node->AsCallExpression()->Callee()->AsIdentifier()->Name().Is( 19333af6ab5fSopenharmony_ci param->AsETSParameterExpression()->Ident()->Name().Mutf8())) { 19343af6ab5fSopenharmony_ci return true; 19353af6ab5fSopenharmony_ci } 19363af6ab5fSopenharmony_ci } 19373af6ab5fSopenharmony_ci return false; 19383af6ab5fSopenharmony_ci} 19393af6ab5fSopenharmony_ci 19403af6ab5fSopenharmony_civoid ETSChecker::CheckThrowingStatements(ir::AstNode *node) 19413af6ab5fSopenharmony_ci{ 19423af6ab5fSopenharmony_ci ir::AstNode *ancestorFunction = FindAncestorGivenByType(node, ir::AstNodeType::SCRIPT_FUNCTION); 19433af6ab5fSopenharmony_ci 19443af6ab5fSopenharmony_ci if (ancestorFunction == nullptr) { 19453af6ab5fSopenharmony_ci LogTypeError( 19463af6ab5fSopenharmony_ci "This statement can cause an exception, therefore it must be enclosed in a try statement with a default " 19473af6ab5fSopenharmony_ci "catch clause", 19483af6ab5fSopenharmony_ci node->Start()); 19493af6ab5fSopenharmony_ci return; 19503af6ab5fSopenharmony_ci } 19513af6ab5fSopenharmony_ci 19523af6ab5fSopenharmony_ci if (ancestorFunction->AsScriptFunction()->IsThrowing() || 19533af6ab5fSopenharmony_ci (ancestorFunction->AsScriptFunction()->IsRethrowing() && 19543af6ab5fSopenharmony_ci (!node->IsThrowStatement() && CheckRethrowingParams(ancestorFunction, node)))) { 19553af6ab5fSopenharmony_ci return; 19563af6ab5fSopenharmony_ci } 19573af6ab5fSopenharmony_ci 19583af6ab5fSopenharmony_ci if (!CheckThrowingPlacement(node, ancestorFunction)) { 19593af6ab5fSopenharmony_ci if (ancestorFunction->AsScriptFunction()->IsRethrowing() && !node->IsThrowStatement()) { 19603af6ab5fSopenharmony_ci LogTypeError( 19613af6ab5fSopenharmony_ci "This statement can cause an exception, re-throwing functions can throw exception only by their " 19623af6ab5fSopenharmony_ci "parameters.", 19633af6ab5fSopenharmony_ci node->Start()); 19643af6ab5fSopenharmony_ci return; 19653af6ab5fSopenharmony_ci } 19663af6ab5fSopenharmony_ci 19673af6ab5fSopenharmony_ci if (auto interfaces = 19683af6ab5fSopenharmony_ci ancestorFunction->AsScriptFunction()->Signature()->Owner()->AsETSObjectType()->Interfaces(); 19693af6ab5fSopenharmony_ci !(!interfaces.empty() && 19703af6ab5fSopenharmony_ci interfaces[0]->AsETSObjectType()->HasObjectFlag(checker::ETSObjectFlags::FUNCTIONAL_INTERFACE))) { 19713af6ab5fSopenharmony_ci LogTypeError( 19723af6ab5fSopenharmony_ci "This statement can cause an exception, therefore it must be enclosed in a try statement with a " 19733af6ab5fSopenharmony_ci "default " 19743af6ab5fSopenharmony_ci "catch clause", 19753af6ab5fSopenharmony_ci node->Start()); 19763af6ab5fSopenharmony_ci return; 19773af6ab5fSopenharmony_ci } 19783af6ab5fSopenharmony_ci } 19793af6ab5fSopenharmony_ci} 19803af6ab5fSopenharmony_ci 19813af6ab5fSopenharmony_cibool ETSChecker::CheckThrowingPlacement(ir::AstNode *node, const ir::AstNode *ancestorFunction) 19823af6ab5fSopenharmony_ci{ 19833af6ab5fSopenharmony_ci ir::AstNode *startPoint = node; 19843af6ab5fSopenharmony_ci ir::AstNode *enclosingCatchClause = nullptr; 19853af6ab5fSopenharmony_ci ir::BlockStatement *enclosingFinallyBlock = nullptr; 19863af6ab5fSopenharmony_ci ir::AstNode *p = startPoint->Parent(); 19873af6ab5fSopenharmony_ci 19883af6ab5fSopenharmony_ci bool isHandled = false; 19893af6ab5fSopenharmony_ci const auto predicateFunc = [&enclosingCatchClause](ir::CatchClause *clause) { 19903af6ab5fSopenharmony_ci return clause == enclosingCatchClause; 19913af6ab5fSopenharmony_ci }; 19923af6ab5fSopenharmony_ci 19933af6ab5fSopenharmony_ci do { 19943af6ab5fSopenharmony_ci if (p->IsTryStatement() && p->AsTryStatement()->HasDefaultCatchClause()) { 19953af6ab5fSopenharmony_ci enclosingCatchClause = FindAncestorGivenByType(startPoint, ir::AstNodeType::CATCH_CLAUSE, p); 19963af6ab5fSopenharmony_ci enclosingFinallyBlock = FindFinalizerOfTryStatement(startPoint, p); 19973af6ab5fSopenharmony_ci const auto catches = p->AsTryStatement()->CatchClauses(); 19983af6ab5fSopenharmony_ci if (std::any_of(catches.begin(), catches.end(), predicateFunc)) { 19993af6ab5fSopenharmony_ci startPoint = enclosingCatchClause; 20003af6ab5fSopenharmony_ci } else if (enclosingFinallyBlock != nullptr && 20013af6ab5fSopenharmony_ci enclosingFinallyBlock == p->AsTryStatement()->FinallyBlock()) { 20023af6ab5fSopenharmony_ci startPoint = enclosingFinallyBlock; 20033af6ab5fSopenharmony_ci } else { 20043af6ab5fSopenharmony_ci isHandled = true; 20053af6ab5fSopenharmony_ci break; 20063af6ab5fSopenharmony_ci } 20073af6ab5fSopenharmony_ci } 20083af6ab5fSopenharmony_ci 20093af6ab5fSopenharmony_ci p = p->Parent(); 20103af6ab5fSopenharmony_ci } while (p != ancestorFunction); 20113af6ab5fSopenharmony_ci 20123af6ab5fSopenharmony_ci return isHandled; 20133af6ab5fSopenharmony_ci} 20143af6ab5fSopenharmony_ci 20153af6ab5fSopenharmony_ciir::BlockStatement *ETSChecker::FindFinalizerOfTryStatement(ir::AstNode *startFrom, const ir::AstNode *p) 20163af6ab5fSopenharmony_ci{ 20173af6ab5fSopenharmony_ci auto *iter = startFrom->Parent(); 20183af6ab5fSopenharmony_ci 20193af6ab5fSopenharmony_ci do { 20203af6ab5fSopenharmony_ci if (iter->IsBlockStatement()) { 20213af6ab5fSopenharmony_ci ir::BlockStatement *finallyBlock = iter->AsBlockStatement(); 20223af6ab5fSopenharmony_ci 20233af6ab5fSopenharmony_ci if (finallyBlock == p->AsTryStatement()->FinallyBlock()) { 20243af6ab5fSopenharmony_ci return finallyBlock; 20253af6ab5fSopenharmony_ci } 20263af6ab5fSopenharmony_ci } 20273af6ab5fSopenharmony_ci 20283af6ab5fSopenharmony_ci iter = iter->Parent(); 20293af6ab5fSopenharmony_ci } while (iter != p); 20303af6ab5fSopenharmony_ci 20313af6ab5fSopenharmony_ci return nullptr; 20323af6ab5fSopenharmony_ci} 20333af6ab5fSopenharmony_ci 20343af6ab5fSopenharmony_civoid ETSChecker::CheckRethrowingFunction(ir::ScriptFunction *func) 20353af6ab5fSopenharmony_ci{ 20363af6ab5fSopenharmony_ci if (func->Signature()->Owner()->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::FUNCTIONAL_INTERFACE)) { 20373af6ab5fSopenharmony_ci return; 20383af6ab5fSopenharmony_ci } 20393af6ab5fSopenharmony_ci 20403af6ab5fSopenharmony_ci bool foundThrowingParam = false; 20413af6ab5fSopenharmony_ci 20423af6ab5fSopenharmony_ci // It doesn't support lambdas yet. 20433af6ab5fSopenharmony_ci for (auto item : func->Params()) { 20443af6ab5fSopenharmony_ci auto const *type = item->AsETSParameterExpression()->Ident()->TypeAnnotation(); 20453af6ab5fSopenharmony_ci 20463af6ab5fSopenharmony_ci if (type->IsETSTypeReference()) { 20473af6ab5fSopenharmony_ci auto *typeDecl = type->AsETSTypeReference()->Part()->Name()->AsIdentifier()->Variable()->Declaration(); 20483af6ab5fSopenharmony_ci if (typeDecl->IsTypeAliasDecl()) { 20493af6ab5fSopenharmony_ci type = typeDecl->Node()->AsTSTypeAliasDeclaration()->TypeAnnotation(); 20503af6ab5fSopenharmony_ci } 20513af6ab5fSopenharmony_ci } 20523af6ab5fSopenharmony_ci 20533af6ab5fSopenharmony_ci if (type->IsETSFunctionType() && type->AsETSFunctionType()->IsThrowing()) { 20543af6ab5fSopenharmony_ci foundThrowingParam = true; 20553af6ab5fSopenharmony_ci break; 20563af6ab5fSopenharmony_ci } 20573af6ab5fSopenharmony_ci } 20583af6ab5fSopenharmony_ci 20593af6ab5fSopenharmony_ci if (!foundThrowingParam) { 20603af6ab5fSopenharmony_ci LogTypeError("A rethrowing function must have a throwing function parameter", func->Start()); 20613af6ab5fSopenharmony_ci } 20623af6ab5fSopenharmony_ci} 20633af6ab5fSopenharmony_ci 20643af6ab5fSopenharmony_ciETSObjectType *ETSChecker::GetRelevantArgumentedTypeFromChild(ETSObjectType *const child, ETSObjectType *const target) 20653af6ab5fSopenharmony_ci{ 20663af6ab5fSopenharmony_ci if (child->GetDeclNode() == target->GetDeclNode()) { 20673af6ab5fSopenharmony_ci auto *relevantType = CreateNewETSObjectType(child->Name(), child->GetDeclNode(), child->ObjectFlags()); 20683af6ab5fSopenharmony_ci 20693af6ab5fSopenharmony_ci ArenaVector<Type *> params = child->TypeArguments(); 20703af6ab5fSopenharmony_ci 20713af6ab5fSopenharmony_ci relevantType->SetTypeArguments(std::move(params)); 20723af6ab5fSopenharmony_ci relevantType->SetEnclosingType(child->EnclosingType()); 20733af6ab5fSopenharmony_ci relevantType->SetSuperType(child->SuperType()); 20743af6ab5fSopenharmony_ci 20753af6ab5fSopenharmony_ci return relevantType; 20763af6ab5fSopenharmony_ci } 20773af6ab5fSopenharmony_ci 20783af6ab5fSopenharmony_ci ASSERT(child->SuperType() != nullptr); 20793af6ab5fSopenharmony_ci 20803af6ab5fSopenharmony_ci return GetRelevantArgumentedTypeFromChild(child->SuperType(), target); 20813af6ab5fSopenharmony_ci} 20823af6ab5fSopenharmony_ci 20833af6ab5fSopenharmony_civoid ETSChecker::EmplaceSubstituted(Substitution *substitution, ETSTypeParameter *tparam, Type *typeArg) 20843af6ab5fSopenharmony_ci{ 20853af6ab5fSopenharmony_ci substitution->emplace(tparam, typeArg); 20863af6ab5fSopenharmony_ci} 20873af6ab5fSopenharmony_ci 20883af6ab5fSopenharmony_ciutil::StringView ETSChecker::GetHashFromTypeArguments(const ArenaVector<Type *> &typeArgTypes) 20893af6ab5fSopenharmony_ci{ 20903af6ab5fSopenharmony_ci std::stringstream ss; 20913af6ab5fSopenharmony_ci 20923af6ab5fSopenharmony_ci for (auto *it : typeArgTypes) { 20933af6ab5fSopenharmony_ci it->ToString(ss, true); 20943af6ab5fSopenharmony_ci ss << compiler::Signatures::MANGLE_SEPARATOR; 20953af6ab5fSopenharmony_ci 20963af6ab5fSopenharmony_ci // In case of ETSTypeParameters storing the name might not be sufficient as there can 20973af6ab5fSopenharmony_ci // be multiple different type parameters with the same name. For those we test identity based 20983af6ab5fSopenharmony_ci // on their memory address equality, so we store them in the hash to keep it unique. 20993af6ab5fSopenharmony_ci // To make it consistent we store it for every type. 21003af6ab5fSopenharmony_ci // NOTE (mmartin): change bare address to something more appropriate unique representation 21013af6ab5fSopenharmony_ci ss << it << compiler::Signatures::MANGLE_SEPARATOR; 21023af6ab5fSopenharmony_ci } 21033af6ab5fSopenharmony_ci 21043af6ab5fSopenharmony_ci return util::UString(ss.str(), Allocator()).View(); 21053af6ab5fSopenharmony_ci} 21063af6ab5fSopenharmony_ci 21073af6ab5fSopenharmony_ciutil::StringView ETSChecker::GetHashFromSubstitution(const Substitution *substitution) 21083af6ab5fSopenharmony_ci{ 21093af6ab5fSopenharmony_ci std::vector<std::string> fields; 21103af6ab5fSopenharmony_ci for (auto [k, v] : *substitution) { 21113af6ab5fSopenharmony_ci std::stringstream ss; 21123af6ab5fSopenharmony_ci k->ToString(ss, true); 21133af6ab5fSopenharmony_ci ss << ":"; 21143af6ab5fSopenharmony_ci v->ToString(ss, true); 21153af6ab5fSopenharmony_ci // NOTE (mmartin): change bare address to something more appropriate unique representation 21163af6ab5fSopenharmony_ci ss << ":" << k << ":" << v; 21173af6ab5fSopenharmony_ci fields.push_back(ss.str()); 21183af6ab5fSopenharmony_ci } 21193af6ab5fSopenharmony_ci std::sort(fields.begin(), fields.end()); 21203af6ab5fSopenharmony_ci 21213af6ab5fSopenharmony_ci std::stringstream ss; 21223af6ab5fSopenharmony_ci for (auto &fstr : fields) { 21233af6ab5fSopenharmony_ci ss << fstr; 21243af6ab5fSopenharmony_ci ss << ";"; 21253af6ab5fSopenharmony_ci } 21263af6ab5fSopenharmony_ci return util::UString(ss.str(), Allocator()).View(); 21273af6ab5fSopenharmony_ci} 21283af6ab5fSopenharmony_ci 21293af6ab5fSopenharmony_ciutil::StringView ETSChecker::GetHashFromFunctionType(ir::ETSFunctionType *type) 21303af6ab5fSopenharmony_ci{ 21313af6ab5fSopenharmony_ci std::stringstream ss; 21323af6ab5fSopenharmony_ci for (auto *p : type->Params()) { 21333af6ab5fSopenharmony_ci auto *const param = p->AsETSParameterExpression(); 21343af6ab5fSopenharmony_ci param->TypeAnnotation()->GetType(this)->ToString(ss, true); 21353af6ab5fSopenharmony_ci ss << ";"; 21363af6ab5fSopenharmony_ci } 21373af6ab5fSopenharmony_ci 21383af6ab5fSopenharmony_ci type->ReturnType()->GetType(this)->ToString(ss, true); 21393af6ab5fSopenharmony_ci ss << ";"; 21403af6ab5fSopenharmony_ci 21413af6ab5fSopenharmony_ci if (type->IsThrowing()) { 21423af6ab5fSopenharmony_ci ss << "throws;"; 21433af6ab5fSopenharmony_ci } 21443af6ab5fSopenharmony_ci 21453af6ab5fSopenharmony_ci if (type->IsRethrowing()) { 21463af6ab5fSopenharmony_ci ss << "rethrows;"; 21473af6ab5fSopenharmony_ci } 21483af6ab5fSopenharmony_ci 21493af6ab5fSopenharmony_ci return util::UString(ss.str(), Allocator()).View(); 21503af6ab5fSopenharmony_ci} 21513af6ab5fSopenharmony_ci 21523af6ab5fSopenharmony_ciETSObjectType *ETSChecker::GetOriginalBaseType(Type *const object) 21533af6ab5fSopenharmony_ci{ 21543af6ab5fSopenharmony_ci if (object == nullptr || !object->IsETSObjectType()) { 21553af6ab5fSopenharmony_ci return nullptr; 21563af6ab5fSopenharmony_ci } 21573af6ab5fSopenharmony_ci 21583af6ab5fSopenharmony_ci return object->AsETSObjectType()->GetOriginalBaseType(); 21593af6ab5fSopenharmony_ci} 21603af6ab5fSopenharmony_ci 21613af6ab5fSopenharmony_civoid ETSChecker::CheckValidGenericTypeParameter(Type *const argType, const lexer::SourcePosition &pos) 21623af6ab5fSopenharmony_ci{ 21633af6ab5fSopenharmony_ci if (!argType->IsETSEnumType()) { 21643af6ab5fSopenharmony_ci return; 21653af6ab5fSopenharmony_ci } 21663af6ab5fSopenharmony_ci std::stringstream ss; 21673af6ab5fSopenharmony_ci argType->ToString(ss); 21683af6ab5fSopenharmony_ci LogTypeError("Type '" + ss.str() + "' is not valid for generic type arguments", pos); 21693af6ab5fSopenharmony_ci} 21703af6ab5fSopenharmony_ci 21713af6ab5fSopenharmony_cibool ETSChecker::CheckNumberOfTypeArguments(ETSObjectType *const type, ir::TSTypeParameterInstantiation *const typeArgs, 21723af6ab5fSopenharmony_ci const lexer::SourcePosition &pos) 21733af6ab5fSopenharmony_ci{ 21743af6ab5fSopenharmony_ci auto const &typeParams = type->TypeArguments(); 21753af6ab5fSopenharmony_ci if (typeParams.empty()) { 21763af6ab5fSopenharmony_ci if (typeArgs != nullptr) { 21773af6ab5fSopenharmony_ci LogTypeError({"Type '", type, "' is not generic."}, pos); 21783af6ab5fSopenharmony_ci return false; 21793af6ab5fSopenharmony_ci } 21803af6ab5fSopenharmony_ci return true; 21813af6ab5fSopenharmony_ci } 21823af6ab5fSopenharmony_ci 21833af6ab5fSopenharmony_ci size_t minimumTypeArgs = std::count_if(typeParams.begin(), typeParams.end(), [](Type *param) { 21843af6ab5fSopenharmony_ci return param->AsETSTypeParameter()->GetDefaultType() == nullptr; 21853af6ab5fSopenharmony_ci }); 21863af6ab5fSopenharmony_ci if (typeArgs == nullptr && minimumTypeArgs > 0) { 21873af6ab5fSopenharmony_ci LogTypeError({"Type '", type, "' is generic but type argument were not provided."}, pos); 21883af6ab5fSopenharmony_ci return false; 21893af6ab5fSopenharmony_ci } 21903af6ab5fSopenharmony_ci 21913af6ab5fSopenharmony_ci if (typeArgs != nullptr && 21923af6ab5fSopenharmony_ci ((minimumTypeArgs > typeArgs->Params().size()) || (typeParams.size() < typeArgs->Params().size()))) { 21933af6ab5fSopenharmony_ci LogTypeError({"Type '", type, "' has ", minimumTypeArgs, " number of type parameters, but ", 21943af6ab5fSopenharmony_ci typeArgs->Params().size(), " type arguments were provided."}, 21953af6ab5fSopenharmony_ci pos); 21963af6ab5fSopenharmony_ci return false; 21973af6ab5fSopenharmony_ci } 21983af6ab5fSopenharmony_ci return true; 21993af6ab5fSopenharmony_ci} 22003af6ab5fSopenharmony_ci 22013af6ab5fSopenharmony_cibool ETSChecker::NeedTypeInference(const ir::ScriptFunction *lambda) 22023af6ab5fSopenharmony_ci{ 22033af6ab5fSopenharmony_ci if (lambda->ReturnTypeAnnotation() == nullptr) { 22043af6ab5fSopenharmony_ci return true; 22053af6ab5fSopenharmony_ci } 22063af6ab5fSopenharmony_ci for (auto *const param : lambda->Params()) { 22073af6ab5fSopenharmony_ci const auto *const lambdaParam = param->AsETSParameterExpression()->Ident(); 22083af6ab5fSopenharmony_ci if (lambdaParam->TypeAnnotation() == nullptr) { 22093af6ab5fSopenharmony_ci return true; 22103af6ab5fSopenharmony_ci } 22113af6ab5fSopenharmony_ci } 22123af6ab5fSopenharmony_ci return false; 22133af6ab5fSopenharmony_ci} 22143af6ab5fSopenharmony_ci 22153af6ab5fSopenharmony_cistd::vector<bool> ETSChecker::FindTypeInferenceArguments(const ArenaVector<ir::Expression *> &arguments) 22163af6ab5fSopenharmony_ci{ 22173af6ab5fSopenharmony_ci std::vector<bool> argTypeInferenceRequired(arguments.size()); 22183af6ab5fSopenharmony_ci size_t index = 0; 22193af6ab5fSopenharmony_ci for (ir::Expression *arg : arguments) { 22203af6ab5fSopenharmony_ci if (arg->IsArrowFunctionExpression()) { 22213af6ab5fSopenharmony_ci ir::ScriptFunction *const lambda = arg->AsArrowFunctionExpression()->Function(); 22223af6ab5fSopenharmony_ci if (NeedTypeInference(lambda)) { 22233af6ab5fSopenharmony_ci argTypeInferenceRequired[index] = true; 22243af6ab5fSopenharmony_ci } 22253af6ab5fSopenharmony_ci } 22263af6ab5fSopenharmony_ci ++index; 22273af6ab5fSopenharmony_ci } 22283af6ab5fSopenharmony_ci return argTypeInferenceRequired; 22293af6ab5fSopenharmony_ci} 22303af6ab5fSopenharmony_ci 22313af6ab5fSopenharmony_cibool ETSChecker::CheckLambdaAssignableUnion(ir::AstNode *typeAnn, ir::ScriptFunction *lambda) 22323af6ab5fSopenharmony_ci{ 22333af6ab5fSopenharmony_ci for (auto *type : typeAnn->AsETSUnionType()->Types()) { 22343af6ab5fSopenharmony_ci if (type->IsETSFunctionType()) { 22353af6ab5fSopenharmony_ci return lambda->Params().size() == type->AsETSFunctionType()->Params().size(); 22363af6ab5fSopenharmony_ci } 22373af6ab5fSopenharmony_ci } 22383af6ab5fSopenharmony_ci 22393af6ab5fSopenharmony_ci return false; 22403af6ab5fSopenharmony_ci} 22413af6ab5fSopenharmony_ci 22423af6ab5fSopenharmony_civoid ETSChecker::InferTypesForLambda(ir::ScriptFunction *lambda, ir::ETSFunctionType *calleeType, 22433af6ab5fSopenharmony_ci Signature *maybeSubstitutedFunctionSig) 22443af6ab5fSopenharmony_ci{ 22453af6ab5fSopenharmony_ci for (size_t i = 0; i < calleeType->Params().size(); ++i) { 22463af6ab5fSopenharmony_ci const auto *const calleeParam = calleeType->Params()[i]->AsETSParameterExpression()->Ident(); 22473af6ab5fSopenharmony_ci auto *const lambdaParam = lambda->Params()[i]->AsETSParameterExpression()->Ident(); 22483af6ab5fSopenharmony_ci if (lambdaParam->TypeAnnotation() == nullptr) { 22493af6ab5fSopenharmony_ci auto *const typeAnnotation = calleeParam->TypeAnnotation()->Clone(Allocator(), lambdaParam); 22503af6ab5fSopenharmony_ci if (maybeSubstitutedFunctionSig != nullptr) { 22513af6ab5fSopenharmony_ci ASSERT(maybeSubstitutedFunctionSig->Params().size() == calleeType->Params().size()); 22523af6ab5fSopenharmony_ci typeAnnotation->SetTsType(maybeSubstitutedFunctionSig->Params()[i]->TsType()); 22533af6ab5fSopenharmony_ci } 22543af6ab5fSopenharmony_ci lambdaParam->SetTsTypeAnnotation(typeAnnotation); 22553af6ab5fSopenharmony_ci typeAnnotation->SetParent(lambdaParam); 22563af6ab5fSopenharmony_ci } 22573af6ab5fSopenharmony_ci } 22583af6ab5fSopenharmony_ci if (lambda->ReturnTypeAnnotation() == nullptr) { 22593af6ab5fSopenharmony_ci auto *const returnTypeAnnotation = calleeType->ReturnType()->Clone(Allocator(), lambda); 22603af6ab5fSopenharmony_ci if (maybeSubstitutedFunctionSig != nullptr) { 22613af6ab5fSopenharmony_ci returnTypeAnnotation->SetTsType(maybeSubstitutedFunctionSig->ReturnType()); 22623af6ab5fSopenharmony_ci } 22633af6ab5fSopenharmony_ci lambda->SetReturnTypeAnnotation(returnTypeAnnotation); 22643af6ab5fSopenharmony_ci } 22653af6ab5fSopenharmony_ci} 22663af6ab5fSopenharmony_ci 22673af6ab5fSopenharmony_civoid ETSChecker::ModifyPreferredType(ir::ArrayExpression *const arrayExpr, Type *const newPreferredType) 22683af6ab5fSopenharmony_ci{ 22693af6ab5fSopenharmony_ci // After modifying the preferred type of an array expression, it needs to be rechecked at the call site 22703af6ab5fSopenharmony_ci arrayExpr->SetPreferredType(newPreferredType); 22713af6ab5fSopenharmony_ci arrayExpr->SetTsType(nullptr); 22723af6ab5fSopenharmony_ci 22733af6ab5fSopenharmony_ci for (auto *const element : arrayExpr->Elements()) { 22743af6ab5fSopenharmony_ci if (element->IsArrayExpression()) { 22753af6ab5fSopenharmony_ci ModifyPreferredType(element->AsArrayExpression(), nullptr); 22763af6ab5fSopenharmony_ci } 22773af6ab5fSopenharmony_ci } 22783af6ab5fSopenharmony_ci} 22793af6ab5fSopenharmony_ci 22803af6ab5fSopenharmony_cibool ETSChecker::IsInLocalClass(const ir::AstNode *node) const 22813af6ab5fSopenharmony_ci{ 22823af6ab5fSopenharmony_ci while (node != nullptr) { 22833af6ab5fSopenharmony_ci if (node->Type() == ir::AstNodeType::CLASS_DEFINITION) { 22843af6ab5fSopenharmony_ci return node->AsClassDefinition()->IsLocal(); 22853af6ab5fSopenharmony_ci } 22863af6ab5fSopenharmony_ci node = node->Parent(); 22873af6ab5fSopenharmony_ci } 22883af6ab5fSopenharmony_ci 22893af6ab5fSopenharmony_ci return false; 22903af6ab5fSopenharmony_ci} 22913af6ab5fSopenharmony_ci 22923af6ab5fSopenharmony_ciir::Expression *ETSChecker::GenerateImplicitInstantiateArg(varbinder::LocalVariable *instantiateMethod, 22933af6ab5fSopenharmony_ci const std::string &className) 22943af6ab5fSopenharmony_ci{ 22953af6ab5fSopenharmony_ci auto callSignatures = instantiateMethod->TsType()->AsETSFunctionType()->CallSignatures(); 22963af6ab5fSopenharmony_ci ASSERT(!callSignatures.empty()); 22973af6ab5fSopenharmony_ci auto methodOwner = std::string(callSignatures[0]->Owner()->Name()); 22983af6ab5fSopenharmony_ci std::string implicitInstantiateArgument = "()=>{return new " + className + "()"; 22993af6ab5fSopenharmony_ci if (methodOwner != className) { 23003af6ab5fSopenharmony_ci implicitInstantiateArgument.append(" as " + methodOwner); 23013af6ab5fSopenharmony_ci } 23023af6ab5fSopenharmony_ci implicitInstantiateArgument.append("}"); 23033af6ab5fSopenharmony_ci 23043af6ab5fSopenharmony_ci parser::Program program(Allocator(), VarBinder()); 23053af6ab5fSopenharmony_ci es2panda::CompilerOptions options; 23063af6ab5fSopenharmony_ci auto parser = parser::ETSParser(&program, options, parser::ParserStatus::NO_OPTS); 23073af6ab5fSopenharmony_ci auto *argExpr = parser.CreateExpression(implicitInstantiateArgument); 23083af6ab5fSopenharmony_ci compiler::InitScopesPhaseETS::RunExternalNode(argExpr, &program); 23093af6ab5fSopenharmony_ci 23103af6ab5fSopenharmony_ci return argExpr; 23113af6ab5fSopenharmony_ci} 23123af6ab5fSopenharmony_ci 23133af6ab5fSopenharmony_ciir::ClassProperty *ETSChecker::ClassPropToImplementationProp(ir::ClassProperty *classProp, varbinder::ClassScope *scope) 23143af6ab5fSopenharmony_ci{ 23153af6ab5fSopenharmony_ci classProp->Key()->AsIdentifier()->SetName( 23163af6ab5fSopenharmony_ci util::UString(std::string(compiler::Signatures::PROPERTY) + classProp->Key()->AsIdentifier()->Name().Mutf8(), 23173af6ab5fSopenharmony_ci Allocator()) 23183af6ab5fSopenharmony_ci .View()); 23193af6ab5fSopenharmony_ci classProp->AddModifier(ir::ModifierFlags::PRIVATE); 23203af6ab5fSopenharmony_ci 23213af6ab5fSopenharmony_ci auto *fieldDecl = Allocator()->New<varbinder::LetDecl>(classProp->Key()->AsIdentifier()->Name()); 23223af6ab5fSopenharmony_ci fieldDecl->BindNode(classProp); 23233af6ab5fSopenharmony_ci 23243af6ab5fSopenharmony_ci auto fieldVar = scope->InstanceFieldScope()->AddDecl(Allocator(), fieldDecl, ScriptExtension::ETS); 23253af6ab5fSopenharmony_ci fieldVar->AddFlag(varbinder::VariableFlags::PROPERTY); 23263af6ab5fSopenharmony_ci 23273af6ab5fSopenharmony_ci classProp->Key()->SetVariable(fieldVar); 23283af6ab5fSopenharmony_ci classProp->Key()->AsIdentifier()->SetVariable(fieldVar); 23293af6ab5fSopenharmony_ci fieldVar->SetTsType(classProp->TsType()); 23303af6ab5fSopenharmony_ci 23313af6ab5fSopenharmony_ci return classProp; 23323af6ab5fSopenharmony_ci} 23333af6ab5fSopenharmony_ci 23343af6ab5fSopenharmony_civoid ETSChecker::GenerateGetterSetterBody(ArenaVector<ir::Statement *> &stmts, ArenaVector<ir::Expression *> ¶ms, 23353af6ab5fSopenharmony_ci ir::ClassProperty *const field, varbinder::FunctionParamScope *paramScope, 23363af6ab5fSopenharmony_ci bool isSetter) 23373af6ab5fSopenharmony_ci{ 23383af6ab5fSopenharmony_ci auto *classDef = field->Parent()->AsClassDefinition(); 23393af6ab5fSopenharmony_ci 23403af6ab5fSopenharmony_ci ir::Expression *baseExpression; 23413af6ab5fSopenharmony_ci if ((field->Modifiers() & ir::ModifierFlags::SUPER_OWNER) != 0U) { 23423af6ab5fSopenharmony_ci baseExpression = Allocator()->New<ir::SuperExpression>(); 23433af6ab5fSopenharmony_ci } else { 23443af6ab5fSopenharmony_ci baseExpression = Allocator()->New<ir::ThisExpression>(); 23453af6ab5fSopenharmony_ci } 23463af6ab5fSopenharmony_ci baseExpression->SetParent(classDef); 23473af6ab5fSopenharmony_ci baseExpression->SetTsType(classDef->TsType()); 23483af6ab5fSopenharmony_ci 23493af6ab5fSopenharmony_ci auto *memberExpression = 23503af6ab5fSopenharmony_ci AllocNode<ir::MemberExpression>(baseExpression, field->Key()->AsIdentifier()->Clone(Allocator(), nullptr), 23513af6ab5fSopenharmony_ci ir::MemberExpressionKind::PROPERTY_ACCESS, false, false); 23523af6ab5fSopenharmony_ci memberExpression->SetTsType(field->TsType()); 23533af6ab5fSopenharmony_ci memberExpression->SetPropVar(field->Key()->Variable()->AsLocalVariable()); 23543af6ab5fSopenharmony_ci memberExpression->SetRange(classDef->Range()); 23553af6ab5fSopenharmony_ci if (memberExpression->ObjType() == nullptr && classDef->TsType() != nullptr) { 23563af6ab5fSopenharmony_ci memberExpression->SetObjectType(classDef->TsType()->AsETSObjectType()); 23573af6ab5fSopenharmony_ci } 23583af6ab5fSopenharmony_ci 23593af6ab5fSopenharmony_ci if (!isSetter) { 23603af6ab5fSopenharmony_ci stmts.push_back(AllocNode<ir::ReturnStatement>(memberExpression)); 23613af6ab5fSopenharmony_ci return; 23623af6ab5fSopenharmony_ci } 23633af6ab5fSopenharmony_ci 23643af6ab5fSopenharmony_ci auto *paramIdent = field->Key()->AsIdentifier()->Clone(Allocator(), nullptr); 23653af6ab5fSopenharmony_ci if (field->TypeAnnotation() != nullptr) { 23663af6ab5fSopenharmony_ci auto *const typeAnnotation = field->TypeAnnotation()->Clone(Allocator(), paramIdent); 23673af6ab5fSopenharmony_ci paramIdent->SetTsTypeAnnotation(typeAnnotation); 23683af6ab5fSopenharmony_ci } else { 23693af6ab5fSopenharmony_ci paramIdent->SetTsType(field->TsType()); 23703af6ab5fSopenharmony_ci } 23713af6ab5fSopenharmony_ci 23723af6ab5fSopenharmony_ci auto *paramExpression = AllocNode<ir::ETSParameterExpression>(paramIdent, nullptr); 23733af6ab5fSopenharmony_ci paramExpression->SetRange(paramIdent->Range()); 23743af6ab5fSopenharmony_ci auto *const paramVar = std::get<2>(paramScope->AddParamDecl(Allocator(), paramExpression)); 23753af6ab5fSopenharmony_ci paramExpression->SetVariable(paramVar); 23763af6ab5fSopenharmony_ci 23773af6ab5fSopenharmony_ci params.push_back(paramExpression); 23783af6ab5fSopenharmony_ci 23793af6ab5fSopenharmony_ci auto *assignmentExpression = AllocNode<ir::AssignmentExpression>( 23803af6ab5fSopenharmony_ci memberExpression, paramExpression->Clone(Allocator(), nullptr), lexer::TokenType::PUNCTUATOR_SUBSTITUTION); 23813af6ab5fSopenharmony_ci assignmentExpression->SetTsType(paramVar->TsType()); 23823af6ab5fSopenharmony_ci 23833af6ab5fSopenharmony_ci assignmentExpression->SetRange({field->Start(), field->End()}); 23843af6ab5fSopenharmony_ci // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) 23853af6ab5fSopenharmony_ci stmts.push_back(AllocNode<ir::ExpressionStatement>(assignmentExpression)); 23863af6ab5fSopenharmony_ci // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) 23873af6ab5fSopenharmony_ci stmts.push_back(Allocator()->New<ir::ReturnStatement>(nullptr)); 23883af6ab5fSopenharmony_ci} 23893af6ab5fSopenharmony_ci 23903af6ab5fSopenharmony_ciir::MethodDefinition *ETSChecker::GenerateDefaultGetterSetter(ir::ClassProperty *const property, 23913af6ab5fSopenharmony_ci ir::ClassProperty *const field, 23923af6ab5fSopenharmony_ci varbinder::ClassScope *classScope, bool isSetter, 23933af6ab5fSopenharmony_ci ETSChecker *checker) 23943af6ab5fSopenharmony_ci{ 23953af6ab5fSopenharmony_ci auto *paramScope = checker->Allocator()->New<varbinder::FunctionParamScope>(checker->Allocator(), classScope); 23963af6ab5fSopenharmony_ci auto *functionScope = checker->Allocator()->New<varbinder::FunctionScope>(checker->Allocator(), paramScope); 23973af6ab5fSopenharmony_ci 23983af6ab5fSopenharmony_ci functionScope->BindParamScope(paramScope); 23993af6ab5fSopenharmony_ci paramScope->BindFunctionScope(functionScope); 24003af6ab5fSopenharmony_ci 24013af6ab5fSopenharmony_ci ArenaVector<ir::Expression *> params(checker->Allocator()->Adapter()); 24023af6ab5fSopenharmony_ci ArenaVector<ir::Statement *> stmts(checker->Allocator()->Adapter()); 24033af6ab5fSopenharmony_ci checker->GenerateGetterSetterBody(stmts, params, field, paramScope, isSetter); 24043af6ab5fSopenharmony_ci // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) 24053af6ab5fSopenharmony_ci auto *body = checker->AllocNode<ir::BlockStatement>(checker->Allocator(), std::move(stmts)); 24063af6ab5fSopenharmony_ci auto funcFlags = isSetter ? ir::ScriptFunctionFlags::SETTER : ir::ScriptFunctionFlags::GETTER; 24073af6ab5fSopenharmony_ci auto *const returnTypeAnn = isSetter || field->TypeAnnotation() == nullptr 24083af6ab5fSopenharmony_ci ? nullptr 24093af6ab5fSopenharmony_ci : field->TypeAnnotation()->Clone(checker->Allocator(), nullptr); 24103af6ab5fSopenharmony_ci // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) 24113af6ab5fSopenharmony_ci auto *func = checker->AllocNode<ir::ScriptFunction>( 24123af6ab5fSopenharmony_ci checker->Allocator(), 24133af6ab5fSopenharmony_ci ir::ScriptFunction::ScriptFunctionData {body, ir::FunctionSignature(nullptr, std::move(params), returnTypeAnn), 24143af6ab5fSopenharmony_ci funcFlags, ir::ModifierFlags::PUBLIC, true}); 24153af6ab5fSopenharmony_ci 24163af6ab5fSopenharmony_ci if (!isSetter) { 24173af6ab5fSopenharmony_ci func->AddFlag(ir::ScriptFunctionFlags::HAS_RETURN); 24183af6ab5fSopenharmony_ci } 24193af6ab5fSopenharmony_ci func->SetRange(field->Range()); 24203af6ab5fSopenharmony_ci func->SetScope(functionScope); 24213af6ab5fSopenharmony_ci body->SetScope(functionScope); 24223af6ab5fSopenharmony_ci // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) 24233af6ab5fSopenharmony_ci auto *methodIdent = property->Key()->AsIdentifier()->Clone(checker->Allocator(), nullptr); 24243af6ab5fSopenharmony_ci // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) 24253af6ab5fSopenharmony_ci auto *funcExpr = checker->AllocNode<ir::FunctionExpression>(func); 24263af6ab5fSopenharmony_ci funcExpr->SetRange(func->Range()); 24273af6ab5fSopenharmony_ci func->AddFlag(ir::ScriptFunctionFlags::METHOD); 24283af6ab5fSopenharmony_ci // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) 24293af6ab5fSopenharmony_ci auto *method = checker->AllocNode<ir::MethodDefinition>(ir::MethodDefinitionKind::METHOD, methodIdent, funcExpr, 24303af6ab5fSopenharmony_ci ir::ModifierFlags::PUBLIC, checker->Allocator(), false); 24313af6ab5fSopenharmony_ci 24323af6ab5fSopenharmony_ci auto *decl = checker->Allocator()->New<varbinder::FunctionDecl>(checker->Allocator(), 24333af6ab5fSopenharmony_ci property->Key()->AsIdentifier()->Name(), method); 24343af6ab5fSopenharmony_ci auto *var = checker->Allocator()->New<varbinder::LocalVariable>(decl, varbinder::VariableFlags::VAR); 24353af6ab5fSopenharmony_ci var->AddFlag(varbinder::VariableFlags::METHOD); 24363af6ab5fSopenharmony_ci 24373af6ab5fSopenharmony_ci methodIdent->SetVariable(var); 24383af6ab5fSopenharmony_ci 24393af6ab5fSopenharmony_ci method->Id()->SetMutator(); 24403af6ab5fSopenharmony_ci method->SetRange(field->Range()); 24413af6ab5fSopenharmony_ci method->Function()->SetIdent(method->Id()->Clone(checker->Allocator(), nullptr)); 24423af6ab5fSopenharmony_ci method->Function()->AddModifier(method->Modifiers()); 24433af6ab5fSopenharmony_ci method->SetVariable(var); 24443af6ab5fSopenharmony_ci method->SetParent(field->Parent()); 24453af6ab5fSopenharmony_ci 24463af6ab5fSopenharmony_ci paramScope->BindNode(func); 24473af6ab5fSopenharmony_ci functionScope->BindNode(func); 24483af6ab5fSopenharmony_ci 24493af6ab5fSopenharmony_ci auto classCtx = varbinder::LexicalScope<varbinder::ClassScope>::Enter(checker->VarBinder(), classScope); 24503af6ab5fSopenharmony_ci checker->VarBinder()->AsETSBinder()->ResolveMethodDefinition(method); 24513af6ab5fSopenharmony_ci 24523af6ab5fSopenharmony_ci functionScope->BindName(classScope->Node()->AsClassDefinition()->InternalName()); 24533af6ab5fSopenharmony_ci method->Check(checker); 24543af6ab5fSopenharmony_ci 24553af6ab5fSopenharmony_ci return method; 24563af6ab5fSopenharmony_ci} 24573af6ab5fSopenharmony_ci 24583af6ab5fSopenharmony_ciir::ClassProperty *GetImplementationClassProp(ETSChecker *checker, ir::ClassProperty *interfaceProp, 24593af6ab5fSopenharmony_ci ir::ClassProperty *originalProp, ETSObjectType *classType) 24603af6ab5fSopenharmony_ci{ 24613af6ab5fSopenharmony_ci bool isSuperOwner = ((originalProp->Modifiers() & ir::ModifierFlags::SUPER_OWNER) != 0U); 24623af6ab5fSopenharmony_ci if (!isSuperOwner) { 24633af6ab5fSopenharmony_ci auto *const classDef = classType->GetDeclNode()->AsClassDefinition(); 24643af6ab5fSopenharmony_ci auto *const scope = checker->Scope()->AsClassScope(); 24653af6ab5fSopenharmony_ci auto *const classProp = checker->ClassPropToImplementationProp( 24663af6ab5fSopenharmony_ci interfaceProp->Clone(checker->Allocator(), originalProp->Parent()), scope); 24673af6ab5fSopenharmony_ci classType->AddProperty<PropertyType::INSTANCE_FIELD>(classProp->Key()->Variable()->AsLocalVariable()); 24683af6ab5fSopenharmony_ci classDef->Body().push_back(classProp); 24693af6ab5fSopenharmony_ci return classProp; 24703af6ab5fSopenharmony_ci } 24713af6ab5fSopenharmony_ci 24723af6ab5fSopenharmony_ci auto *const classProp = classType 24733af6ab5fSopenharmony_ci ->GetProperty(interfaceProp->Key()->AsIdentifier()->Name(), 24743af6ab5fSopenharmony_ci PropertySearchFlags::SEARCH_ALL | PropertySearchFlags::SEARCH_IN_BASE) 24753af6ab5fSopenharmony_ci ->Declaration() 24763af6ab5fSopenharmony_ci ->Node() 24773af6ab5fSopenharmony_ci ->AsClassProperty(); 24783af6ab5fSopenharmony_ci classProp->AddModifier(ir::ModifierFlags::SUPER_OWNER); 24793af6ab5fSopenharmony_ci return classProp; 24803af6ab5fSopenharmony_ci} 24813af6ab5fSopenharmony_ci 24823af6ab5fSopenharmony_cistatic void SetupGetterSetterFlags(ir::ClassProperty *originalProp, ETSObjectType *classType, 24833af6ab5fSopenharmony_ci ir::MethodDefinition *getter, ir::MethodDefinition *setter, const bool inExternal) 24843af6ab5fSopenharmony_ci{ 24853af6ab5fSopenharmony_ci auto *const classDef = classType->GetDeclNode()->AsClassDefinition(); 24863af6ab5fSopenharmony_ci for (auto &method : {getter, setter}) { 24873af6ab5fSopenharmony_ci if (method == nullptr) { 24883af6ab5fSopenharmony_ci continue; 24893af6ab5fSopenharmony_ci } 24903af6ab5fSopenharmony_ci 24913af6ab5fSopenharmony_ci const auto mflag = method == getter ? ir::ModifierFlags::GETTER : ir::ModifierFlags::SETTER; 24923af6ab5fSopenharmony_ci const auto tflag = method == getter ? TypeFlag::GETTER : TypeFlag::SETTER; 24933af6ab5fSopenharmony_ci 24943af6ab5fSopenharmony_ci method->TsType()->AddTypeFlag(tflag); 24953af6ab5fSopenharmony_ci method->Variable()->SetTsType(method->TsType()); 24963af6ab5fSopenharmony_ci if (((originalProp->Modifiers() & mflag) != 0U)) { 24973af6ab5fSopenharmony_ci method->Function()->AddModifier(ir::ModifierFlags::OVERRIDE); 24983af6ab5fSopenharmony_ci } 24993af6ab5fSopenharmony_ci 25003af6ab5fSopenharmony_ci if (inExternal) { 25013af6ab5fSopenharmony_ci method->Function()->AddFlag(ir::ScriptFunctionFlags::EXTERNAL); 25023af6ab5fSopenharmony_ci } 25033af6ab5fSopenharmony_ci method->SetParent(classDef); 25043af6ab5fSopenharmony_ci classType->AddProperty<checker::PropertyType::INSTANCE_METHOD>(method->Variable()->AsLocalVariable()); 25053af6ab5fSopenharmony_ci } 25063af6ab5fSopenharmony_ci} 25073af6ab5fSopenharmony_ci 25083af6ab5fSopenharmony_civoid ETSChecker::GenerateGetterSetterPropertyAndMethod(ir::ClassProperty *originalProp, ETSObjectType *classType) 25093af6ab5fSopenharmony_ci{ 25103af6ab5fSopenharmony_ci auto *const classDef = classType->GetDeclNode()->AsClassDefinition(); 25113af6ab5fSopenharmony_ci auto *interfaceProp = originalProp->Clone(Allocator(), originalProp->Parent()); 25123af6ab5fSopenharmony_ci interfaceProp->ClearModifier(ir::ModifierFlags::GETTER_SETTER); 25133af6ab5fSopenharmony_ci 25143af6ab5fSopenharmony_ci auto *const scope = Scope()->AsClassScope(); 25153af6ab5fSopenharmony_ci scope->InstanceFieldScope()->EraseBinding(interfaceProp->Key()->AsIdentifier()->Name()); 25163af6ab5fSopenharmony_ci interfaceProp->SetRange(originalProp->Range()); 25173af6ab5fSopenharmony_ci 25183af6ab5fSopenharmony_ci auto *const classProp = GetImplementationClassProp(this, interfaceProp, originalProp, classType); 25193af6ab5fSopenharmony_ci 25203af6ab5fSopenharmony_ci // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) 25213af6ab5fSopenharmony_ci ir::MethodDefinition *getter = GenerateDefaultGetterSetter(interfaceProp, classProp, scope, false, this); 25223af6ab5fSopenharmony_ci classDef->Body().push_back(getter); 25233af6ab5fSopenharmony_ci 25243af6ab5fSopenharmony_ci const auto &name = getter->Key()->AsIdentifier()->Name(); 25253af6ab5fSopenharmony_ci 25263af6ab5fSopenharmony_ci ir::MethodDefinition *setter = 25273af6ab5fSopenharmony_ci !classProp->IsConst() 25283af6ab5fSopenharmony_ci ? GenerateDefaultGetterSetter(interfaceProp, classProp, Scope()->AsClassScope(), true, this) 25293af6ab5fSopenharmony_ci : nullptr; 25303af6ab5fSopenharmony_ci 25313af6ab5fSopenharmony_ci auto *const methodScope = scope->InstanceMethodScope(); 25323af6ab5fSopenharmony_ci auto *const decl = Allocator()->New<varbinder::FunctionDecl>(Allocator(), name, getter); 25333af6ab5fSopenharmony_ci auto *var = methodScope->AddDecl(Allocator(), decl, ScriptExtension::ETS); 25343af6ab5fSopenharmony_ci 25353af6ab5fSopenharmony_ci if (var == nullptr) { 25363af6ab5fSopenharmony_ci auto *const prevDecl = methodScope->FindDecl(name); 25373af6ab5fSopenharmony_ci for (const auto &method : {getter, setter}) { 25383af6ab5fSopenharmony_ci if (method != nullptr) { 25393af6ab5fSopenharmony_ci prevDecl->Node()->AsMethodDefinition()->AddOverload(method); 25403af6ab5fSopenharmony_ci } 25413af6ab5fSopenharmony_ci } 25423af6ab5fSopenharmony_ci var = methodScope->FindLocal(name, varbinder::ResolveBindingOptions::BINDINGS); 25433af6ab5fSopenharmony_ci } 25443af6ab5fSopenharmony_ci var->AddFlag(varbinder::VariableFlags::METHOD); 25453af6ab5fSopenharmony_ci 25463af6ab5fSopenharmony_ci SetupGetterSetterFlags(originalProp, classType, getter, setter, HasStatus(CheckerStatus::IN_EXTERNAL)); 25473af6ab5fSopenharmony_ci 25483af6ab5fSopenharmony_ci if (setter != nullptr) { 25493af6ab5fSopenharmony_ci getter->Variable()->TsType()->AsETSFunctionType()->AddCallSignature( 25503af6ab5fSopenharmony_ci setter->TsType()->AsETSFunctionType()->CallSignatures()[0]); 25513af6ab5fSopenharmony_ci } 25523af6ab5fSopenharmony_ci 25533af6ab5fSopenharmony_ci getter->Function()->Id()->SetVariable(var); 25543af6ab5fSopenharmony_ci if (setter != nullptr) { 25553af6ab5fSopenharmony_ci getter->AddOverload(setter); 25563af6ab5fSopenharmony_ci } 25573af6ab5fSopenharmony_ci} 25583af6ab5fSopenharmony_ci 25593af6ab5fSopenharmony_ciType *ETSChecker::TryGettingFunctionTypeFromInvokeFunction(Type *type) 25603af6ab5fSopenharmony_ci{ 25613af6ab5fSopenharmony_ci if (type->IsETSObjectType() && type->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::FUNCTIONAL)) { 25623af6ab5fSopenharmony_ci auto const propInvoke = type->AsETSObjectType()->GetProperty(FUNCTIONAL_INTERFACE_INVOKE_METHOD_NAME, 25633af6ab5fSopenharmony_ci PropertySearchFlags::SEARCH_INSTANCE_METHOD); 25643af6ab5fSopenharmony_ci ASSERT(propInvoke != nullptr); 25653af6ab5fSopenharmony_ci 25663af6ab5fSopenharmony_ci return propInvoke->TsType(); 25673af6ab5fSopenharmony_ci } 25683af6ab5fSopenharmony_ci 25693af6ab5fSopenharmony_ci return type; 25703af6ab5fSopenharmony_ci} 25713af6ab5fSopenharmony_ci 25723af6ab5fSopenharmony_cibool ETSChecker::TryTransformingToStaticInvoke(ir::Identifier *const ident, const Type *resolvedType) 25733af6ab5fSopenharmony_ci{ 25743af6ab5fSopenharmony_ci ASSERT(ident->Parent()->IsCallExpression()); 25753af6ab5fSopenharmony_ci ASSERT(ident->Parent()->AsCallExpression()->Callee() == ident); 25763af6ab5fSopenharmony_ci 25773af6ab5fSopenharmony_ci if (!resolvedType->IsETSObjectType()) { 25783af6ab5fSopenharmony_ci return false; 25793af6ab5fSopenharmony_ci } 25803af6ab5fSopenharmony_ci 25813af6ab5fSopenharmony_ci auto className = ident->Name(); 25823af6ab5fSopenharmony_ci std::string_view propertyName; 25833af6ab5fSopenharmony_ci 25843af6ab5fSopenharmony_ci PropertySearchFlags searchFlag = PropertySearchFlags::SEARCH_IN_INTERFACES | PropertySearchFlags::SEARCH_IN_BASE | 25853af6ab5fSopenharmony_ci PropertySearchFlags::SEARCH_STATIC_METHOD; 25863af6ab5fSopenharmony_ci auto *instantiateMethod = 25873af6ab5fSopenharmony_ci resolvedType->AsETSObjectType()->GetProperty(compiler::Signatures::STATIC_INSTANTIATE_METHOD, searchFlag); 25883af6ab5fSopenharmony_ci auto *invokeMethod = 25893af6ab5fSopenharmony_ci resolvedType->AsETSObjectType()->GetProperty(compiler::Signatures::STATIC_INVOKE_METHOD, searchFlag); 25903af6ab5fSopenharmony_ci if (instantiateMethod != nullptr) { 25913af6ab5fSopenharmony_ci propertyName = compiler::Signatures::STATIC_INSTANTIATE_METHOD; 25923af6ab5fSopenharmony_ci } else if (invokeMethod != nullptr) { 25933af6ab5fSopenharmony_ci propertyName = compiler::Signatures::STATIC_INVOKE_METHOD; 25943af6ab5fSopenharmony_ci } else { 25953af6ab5fSopenharmony_ci LogTypeError({"No static ", compiler::Signatures::STATIC_INVOKE_METHOD, " method and static ", 25963af6ab5fSopenharmony_ci compiler::Signatures::STATIC_INSTANTIATE_METHOD, " method in ", className, ". ", className, 25973af6ab5fSopenharmony_ci "() is not allowed."}, 25983af6ab5fSopenharmony_ci ident->Start()); 25993af6ab5fSopenharmony_ci return true; 26003af6ab5fSopenharmony_ci } 26013af6ab5fSopenharmony_ci // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) 26023af6ab5fSopenharmony_ci auto *classId = AllocNode<ir::Identifier>(className, Allocator()); 26033af6ab5fSopenharmony_ci // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) 26043af6ab5fSopenharmony_ci auto *methodId = AllocNode<ir::Identifier>(propertyName, Allocator()); 26053af6ab5fSopenharmony_ci if (propertyName == compiler::Signatures::STATIC_INSTANTIATE_METHOD) { 26063af6ab5fSopenharmony_ci methodId->SetVariable(instantiateMethod); 26073af6ab5fSopenharmony_ci } else if (propertyName == compiler::Signatures::STATIC_INVOKE_METHOD) { 26083af6ab5fSopenharmony_ci methodId->SetVariable(invokeMethod); 26093af6ab5fSopenharmony_ci } 26103af6ab5fSopenharmony_ci 26113af6ab5fSopenharmony_ci auto *transformedCallee = 26123af6ab5fSopenharmony_ci // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) 26133af6ab5fSopenharmony_ci AllocNode<ir::MemberExpression>(classId, methodId, ir::MemberExpressionKind::PROPERTY_ACCESS, false, false); 26143af6ab5fSopenharmony_ci 26153af6ab5fSopenharmony_ci classId->SetRange(ident->Range()); 26163af6ab5fSopenharmony_ci methodId->SetRange(ident->Range()); 26173af6ab5fSopenharmony_ci transformedCallee->SetRange(ident->Range()); 26183af6ab5fSopenharmony_ci 26193af6ab5fSopenharmony_ci auto *callExpr = ident->Parent()->AsCallExpression(); 26203af6ab5fSopenharmony_ci transformedCallee->SetParent(callExpr); 26213af6ab5fSopenharmony_ci callExpr->SetCallee(transformedCallee); 26223af6ab5fSopenharmony_ci 26233af6ab5fSopenharmony_ci if (instantiateMethod != nullptr) { 26243af6ab5fSopenharmony_ci // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) 26253af6ab5fSopenharmony_ci auto *argExpr = GenerateImplicitInstantiateArg(instantiateMethod, std::string(className)); 26263af6ab5fSopenharmony_ci 26273af6ab5fSopenharmony_ci argExpr->SetParent(callExpr); 26283af6ab5fSopenharmony_ci argExpr->SetRange(ident->Range()); 26293af6ab5fSopenharmony_ci 26303af6ab5fSopenharmony_ci VarBinder()->AsETSBinder()->HandleCustomNodes(argExpr); 26313af6ab5fSopenharmony_ci 26323af6ab5fSopenharmony_ci auto &arguments = callExpr->Arguments(); 26333af6ab5fSopenharmony_ci arguments.insert(arguments.begin(), argExpr); 26343af6ab5fSopenharmony_ci } 26353af6ab5fSopenharmony_ci 26363af6ab5fSopenharmony_ci return true; 26373af6ab5fSopenharmony_ci} 26383af6ab5fSopenharmony_ci 26393af6ab5fSopenharmony_cichecker::ETSObjectType *ETSChecker::CreateSyntheticType(util::StringView const &syntheticName, 26403af6ab5fSopenharmony_ci checker::ETSObjectType *lastObjectType, ir::Identifier *id) 26413af6ab5fSopenharmony_ci{ 26423af6ab5fSopenharmony_ci auto *syntheticObjType = Allocator()->New<checker::ETSObjectType>(Allocator(), syntheticName, syntheticName, id, 26433af6ab5fSopenharmony_ci checker::ETSObjectFlags::NO_OPTS); 26443af6ab5fSopenharmony_ci 26453af6ab5fSopenharmony_ci auto *classDecl = Allocator()->New<varbinder::ClassDecl>(syntheticName); 26463af6ab5fSopenharmony_ci varbinder::LocalVariable *var = 26473af6ab5fSopenharmony_ci Allocator()->New<varbinder::LocalVariable>(classDecl, varbinder::VariableFlags::CLASS); 26483af6ab5fSopenharmony_ci var->SetTsType(syntheticObjType); 26493af6ab5fSopenharmony_ci lastObjectType->AddProperty<checker::PropertyType::STATIC_FIELD>(var); 26503af6ab5fSopenharmony_ci syntheticObjType->SetEnclosingType(lastObjectType); 26513af6ab5fSopenharmony_ci return syntheticObjType; 26523af6ab5fSopenharmony_ci} 26533af6ab5fSopenharmony_ci 26543af6ab5fSopenharmony_civoid ETSChecker::ImportNamespaceObjectTypeAddReExportType(ir::ETSImportDeclaration *importDecl, 26553af6ab5fSopenharmony_ci checker::ETSObjectType *lastObjectType, ir::Identifier *ident) 26563af6ab5fSopenharmony_ci{ 26573af6ab5fSopenharmony_ci for (auto item : VarBinder()->AsETSBinder()->ReExportImports()) { 26583af6ab5fSopenharmony_ci if (!importDecl->ResolvedSource()->Str().Is(item->GetProgramPath().Mutf8())) { 26593af6ab5fSopenharmony_ci continue; 26603af6ab5fSopenharmony_ci } 26613af6ab5fSopenharmony_ci auto *reExportType = GetImportSpecifierObjectType(item->GetETSImportDeclarations(), ident); 26623af6ab5fSopenharmony_ci lastObjectType->AddReExports(reExportType); 26633af6ab5fSopenharmony_ci for (auto node : importDecl->Specifiers()) { 26643af6ab5fSopenharmony_ci if (node->IsImportSpecifier()) { 26653af6ab5fSopenharmony_ci auto specifier = node->AsImportSpecifier(); 26663af6ab5fSopenharmony_ci lastObjectType->AddReExportAlias(specifier->Imported()->Name(), specifier->Local()->Name()); 26673af6ab5fSopenharmony_ci } 26683af6ab5fSopenharmony_ci } 26693af6ab5fSopenharmony_ci } 26703af6ab5fSopenharmony_ci} 26713af6ab5fSopenharmony_ci 26723af6ab5fSopenharmony_ciETSObjectType *ETSChecker::GetImportSpecifierObjectType(ir::ETSImportDeclaration *importDecl, ir::Identifier *ident) 26733af6ab5fSopenharmony_ci{ 26743af6ab5fSopenharmony_ci auto importPath = importDecl->ResolvedSource()->Str(); 26753af6ab5fSopenharmony_ci parser::Program *program = 26763af6ab5fSopenharmony_ci SelectEntryOrExternalProgram(static_cast<varbinder::ETSBinder *>(VarBinder()), importPath); 26773af6ab5fSopenharmony_ci std::vector<util::StringView> syntheticNames = GetNameForSynteticObjectType(program->ModuleName()); 26783af6ab5fSopenharmony_ci ASSERT(!syntheticNames.empty()); 26793af6ab5fSopenharmony_ci auto assemblerName = syntheticNames[0]; 26803af6ab5fSopenharmony_ci 26813af6ab5fSopenharmony_ci if (!program->OmitModuleName()) { 26823af6ab5fSopenharmony_ci assemblerName = util::UString(assemblerName.Mutf8() 26833af6ab5fSopenharmony_ci .append(compiler::Signatures::METHOD_SEPARATOR) 26843af6ab5fSopenharmony_ci .append(compiler::Signatures::ETS_GLOBAL), 26853af6ab5fSopenharmony_ci Allocator()) 26863af6ab5fSopenharmony_ci .View(); 26873af6ab5fSopenharmony_ci } 26883af6ab5fSopenharmony_ci 26893af6ab5fSopenharmony_ci auto *moduleObjectType = 26903af6ab5fSopenharmony_ci Allocator()->New<checker::ETSObjectType>(Allocator(), syntheticNames[0], assemblerName, 26913af6ab5fSopenharmony_ci std::make_tuple(ident, checker::ETSObjectFlags::CLASS, Relation())); 26923af6ab5fSopenharmony_ci 26933af6ab5fSopenharmony_ci auto *rootDecl = Allocator()->New<varbinder::ClassDecl>(syntheticNames[0]); 26943af6ab5fSopenharmony_ci varbinder::LocalVariable *rootVar = 26953af6ab5fSopenharmony_ci Allocator()->New<varbinder::LocalVariable>(rootDecl, varbinder::VariableFlags::NONE); 26963af6ab5fSopenharmony_ci rootVar->SetTsType(moduleObjectType); 26973af6ab5fSopenharmony_ci 26983af6ab5fSopenharmony_ci syntheticNames.erase(syntheticNames.begin()); 26993af6ab5fSopenharmony_ci checker::ETSObjectType *lastObjectType(moduleObjectType); 27003af6ab5fSopenharmony_ci 27013af6ab5fSopenharmony_ci for (const auto &syntheticName : syntheticNames) { 27023af6ab5fSopenharmony_ci lastObjectType = CreateSyntheticType(syntheticName, lastObjectType, ident); 27033af6ab5fSopenharmony_ci } 27043af6ab5fSopenharmony_ci 27053af6ab5fSopenharmony_ci ImportNamespaceObjectTypeAddReExportType(importDecl, lastObjectType, ident); 27063af6ab5fSopenharmony_ci SetPropertiesForModuleObject(lastObjectType, importPath, 27073af6ab5fSopenharmony_ci importDecl->Specifiers()[0]->IsImportNamespaceSpecifier() ? nullptr : importDecl); 27083af6ab5fSopenharmony_ci SetrModuleObjectTsType(ident, lastObjectType); 27093af6ab5fSopenharmony_ci 27103af6ab5fSopenharmony_ci return moduleObjectType; 27113af6ab5fSopenharmony_ci} 27123af6ab5fSopenharmony_ci} // namespace ark::es2panda::checker 2713