• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "typeRelationContext.h"
17 
18 namespace ark::es2panda::checker {
ValidateArrayTypeInitializerByElement(TypeRelation * relation,ir::ArrayExpression * node,ETSArrayType * target)19 bool AssignmentContext::ValidateArrayTypeInitializerByElement(TypeRelation *relation, ir::ArrayExpression *node,
20                                                               ETSArrayType *target)
21 {
22     bool ok = true;
23     ES2PANDA_ASSERT(node != nullptr);
24     ES2PANDA_ASSERT(target != nullptr);
25     if (target->IsETSTupleType()) {
26         return true;
27     }
28 
29     for (uint32_t index = 0; index < node->Elements().size(); index++) {
30         ir::Expression *currentArrayElem = node->Elements()[index];
31         auto const currentArrayElementType = currentArrayElem->Check(relation->GetChecker()->AsETSChecker());
32 
33         if (!AssignmentContext(relation, currentArrayElem,
34                                currentArrayElem->Check(relation->GetChecker()->AsETSChecker()), target->ElementType(),
35                                currentArrayElem->Start(), std::nullopt, TypeRelationFlag::NO_THROW)
36                  // CC-OFFNXT(G.FMT.06-CPP,G.FMT.02-CPP) project code style
37                  .IsAssignable()) {
38             relation->GetChecker()->LogError(diagnostic::ARRAY_ELEMENT_INIT_TYPE_INCOMPAT,
39                                              {index, currentArrayElementType, target->ElementType()},
40                                              currentArrayElem->Start());
41             ok = false;
42         }
43     }
44     return ok;
45 }
46 
ValidateTypeArguments(ETSObjectType * type,ir::TSTypeParameterInstantiation * typeArgs,const lexer::SourcePosition & pos)47 bool InstantiationContext::ValidateTypeArguments(ETSObjectType *type, ir::TSTypeParameterInstantiation *typeArgs,
48                                                  const lexer::SourcePosition &pos)
49 {
50     if (checker_->HasStatus(CheckerStatus::IN_INSTANCEOF_CONTEXT)) {
51         if (typeArgs != nullptr) {
52             checker_->LogDiagnostic(diagnostic::INSTANCEOF_ERASED, {type->Name()}, pos);
53         }
54         result_ = type;
55         return true;
56     }
57     if (!checker_->CheckNumberOfTypeArguments(type, typeArgs, pos)) {
58         result_ = checker_->GlobalTypeError();
59         return true;
60         // the return value 'true' of this function let Instantiationcontext constructor return immediately.
61     }
62     if (type->TypeArguments().empty()) {
63         result_ = type;
64         return true;
65     }
66     return false;
67 }
68 
69 // CC-OFFNXT(huge_depth[C++]) solid logic
InstantiateType(ETSObjectType * type,ir::TSTypeParameterInstantiation * typeArgs)70 void InstantiationContext::InstantiateType(ETSObjectType *type, ir::TSTypeParameterInstantiation *typeArgs)
71 {
72     ArenaVector<Type *> typeArgTypes(checker_->Allocator()->Adapter());
73     typeArgTypes.reserve(type->TypeArguments().size());
74 
75     if (typeArgs != nullptr) {
76         for (auto *const it : typeArgs->Params()) {
77             auto *paramType = it->GetType(checker_);
78             ES2PANDA_ASSERT(paramType != nullptr);
79             if (paramType->IsTypeError()) {
80                 result_ = paramType;
81                 return;
82             }
83 
84             if (paramType->IsETSPrimitiveType()) {
85                 checker_->Relation()->SetNode(it);
86 
87                 auto *const boxedTypeArg = checker_->MaybeBoxInRelation(paramType);
88                 if (boxedTypeArg != nullptr) {
89                     paramType = boxedTypeArg->Instantiate(checker_->Allocator(), checker_->Relation(),
90                                                           checker_->GetGlobalTypesHolder());
91                 } else {
92                     ES2PANDA_UNREACHABLE();
93                 }
94             }
95 
96             typeArgTypes.push_back(paramType);
97         }
98     }
99 
100     while (typeArgTypes.size() < type->TypeArguments().size()) {
101         Type *defaultType = nullptr;
102 
103         if (type->TypeArguments().at(typeArgTypes.size())->IsETSTypeParameter()) {
104             defaultType = type->TypeArguments().at(typeArgTypes.size())->AsETSTypeParameter()->GetDefaultType();
105         } else {
106             defaultType = type->TypeArguments().at(typeArgTypes.size());
107         }
108 
109         if (defaultType != nullptr && !defaultType->IsTypeError()) {
110             typeArgTypes.emplace_back(defaultType);
111         } else {
112             ES2PANDA_ASSERT(checker_->IsAnyError());
113             typeArgTypes.emplace_back(checker_->GlobalETSObjectType());
114         }
115     }
116 
117     auto pos = (typeArgs == nullptr) ? lexer::SourcePosition() : typeArgs->Range().start;
118     InstantiateType(type, std::move(typeArgTypes), pos);
119     ES2PANDA_ASSERT(result_->IsETSObjectType());
120     result_->AsETSObjectType()->AddObjectFlag(ETSObjectFlags::NO_OPTS);
121 }
122 
CheckInstantiationConstraints(ETSChecker * checker,ArenaVector<Type * > const & typeParams,const Substitution * substitution,lexer::SourcePosition pos)123 static void CheckInstantiationConstraints(ETSChecker *checker, ArenaVector<Type *> const &typeParams,
124                                           const Substitution *substitution, lexer::SourcePosition pos)
125 {
126     auto relation = checker->Relation();
127 
128     for (auto type : typeParams) {
129         if (!type->IsETSTypeParameter()) {
130             continue;
131         }
132         auto typeParam = type->AsETSTypeParameter();
133         auto typeArg = typeParam->Substitute(relation, substitution);
134         if (typeArg->IsWildcardType()) {
135             continue;
136         }
137         if (typeArg->IsTypeError()) {
138             continue;
139         }
140         // NOTE(vpukhov): #19701 void refactoring
141         ES2PANDA_ASSERT(typeArg->IsETSReferenceType() || typeArg->IsETSVoidType());
142         auto constraint = typeParam->GetConstraintType()->Substitute(relation, substitution);
143         if (!relation->IsAssignableTo(typeArg, constraint)) {
144             // NOTE(vpukhov): refine message
145             checker->LogError(diagnostic::INIT_NOT_ASSIGNABLE, {typeArg, constraint}, pos);
146         }
147     }
148 }
149 
TryCheckConstraints()150 void ConstraintCheckScope::TryCheckConstraints()
151 {
152     if (Unlock()) {
153         auto &records = checker_->PendingConstraintCheckRecords();
154         for (auto const &[typeParams, substitution, pos] : records) {
155             CheckInstantiationConstraints(checker_, *typeParams, substitution, pos);
156         }
157         records.clear();
158     }
159 }
160 
InstantiateType(ETSObjectType * type,ArenaVector<Type * > && typeArgTypes,const lexer::SourcePosition & pos)161 void InstantiationContext::InstantiateType(ETSObjectType *type, ArenaVector<Type *> &&typeArgTypes,
162                                            const lexer::SourcePosition &pos)
163 {
164     util::StringView hash = checker_->GetHashFromTypeArguments(typeArgTypes);
165     auto const &typeParams = type->TypeArguments();
166 
167     while (typeArgTypes.size() < typeParams.size()) {
168         typeArgTypes.push_back(typeParams.at(typeArgTypes.size()));
169     }
170 
171     auto *substitution = checker_->NewSubstitution();
172     for (size_t idx = 0; idx < typeParams.size(); idx++) {
173         if (!typeParams[idx]->IsETSTypeParameter()) {
174             continue;
175         }
176         checker_->EmplaceSubstituted(substitution, typeParams[idx]->AsETSTypeParameter(), typeArgTypes[idx]);
177     }
178 
179     ConstraintCheckScope ctScope(checker_);
180     if (!checker_->Relation()->NoThrowGenericTypeAlias()) {
181         checker_->PendingConstraintCheckRecords().push_back({&typeParams, substitution, pos});
182     }
183 
184     result_ = type->Substitute(checker_->Relation(), substitution)->AsETSObjectType();
185     type->GetInstantiationMap().try_emplace(hash, result_->AsETSObjectType());
186     result_->AddTypeFlag(TypeFlag::GENERIC);
187 
188     ctScope.TryCheckConstraints();
189 }
190 
191 }  // namespace ark::es2panda::checker
192