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