• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 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 #include "boxingConverter.h"
18 #include "macros.h"
19 #include "varbinder/scope.h"
20 #include "varbinder/variable.h"
21 #include "varbinder/declaration.h"
22 #include "checker/types/ets/etsUnionType.h"
23 #include "ir/expressions/arrayExpression.h"
24 #include "ir/ts/tsTypeParameter.h"
25 
26 namespace ark::es2panda::checker {
ValidateArrayTypeInitializerByElement(TypeRelation * relation,ir::ArrayExpression * node,ETSArrayType * target)27 bool AssignmentContext::ValidateArrayTypeInitializerByElement(TypeRelation *relation, ir::ArrayExpression *node,
28                                                               ETSArrayType *target)
29 {
30     bool ok = true;
31     if (target->IsETSTupleType()) {
32         return true;
33     }
34 
35     for (uint32_t index = 0; index < node->Elements().size(); index++) {
36         ir::Expression *currentArrayElem = node->Elements()[index];
37         auto *const currentArrayElementType = currentArrayElem->Check(relation->GetChecker()->AsETSChecker());
38 
39         if (!AssignmentContext(relation, currentArrayElem,
40                                currentArrayElem->Check(relation->GetChecker()->AsETSChecker()), target->ElementType(),
41                                currentArrayElem->Start(), {}, TypeRelationFlag::NO_THROW)
42                  // CC-OFFNXT(G.FMT.06-CPP,G.FMT.02-CPP) project code style
43                  .IsAssignable()) {
44             relation->GetChecker()->LogTypeError(
45                 {"Array element at index ", index, " with type '", currentArrayElementType,
46                  "' is not compatible with the target array element type '", target->ElementType(), "'"},
47                 currentArrayElem->Start());
48             ok = false;
49         }
50     }
51     return ok;
52 }
53 
ValidateTypeArguments(ETSObjectType * type,ir::TSTypeParameterInstantiation * typeArgs,const lexer::SourcePosition & pos)54 bool InstantiationContext::ValidateTypeArguments(ETSObjectType *type, ir::TSTypeParameterInstantiation *typeArgs,
55                                                  const lexer::SourcePosition &pos)
56 {
57     if (checker_->HasStatus(CheckerStatus::IN_INSTANCEOF_CONTEXT)) {
58         if (typeArgs != nullptr) {
59             checker_->ReportWarning(
60                 {"Type parameter is erased from type '", type->Name(), "' when used in instanceof expression."}, pos);
61         }
62         result_ = type;
63         return true;
64     }
65     if (!checker_->CheckNumberOfTypeArguments(type, typeArgs, pos)) {
66         result_ = checker_->GlobalTypeError();
67         return true;
68         // the return value 'true' of this function let Instantiationcontext constructor return immediately.
69     }
70     if (type->TypeArguments().empty()) {
71         result_ = type;
72         return true;
73     }
74     return false;
75 }
76 
InstantiateType(ETSObjectType * type,ir::TSTypeParameterInstantiation * typeArgs)77 void InstantiationContext::InstantiateType(ETSObjectType *type, ir::TSTypeParameterInstantiation *typeArgs)
78 {
79     ArenaVector<Type *> typeArgTypes(checker_->Allocator()->Adapter());
80     typeArgTypes.reserve(type->TypeArguments().size());
81 
82     if (typeArgs != nullptr) {
83         for (auto *const it : typeArgs->Params()) {
84             auto *paramType = it->GetType(checker_);
85             if (paramType->IsTypeError()) {
86                 result_ = paramType;
87                 return;
88             }
89 
90             if (paramType->IsETSPrimitiveType()) {
91                 checker_->Relation()->SetNode(it);
92 
93                 auto *const boxedTypeArg = checker_->MaybeBoxInRelation(paramType);
94                 ASSERT(boxedTypeArg);
95                 paramType = boxedTypeArg->Instantiate(checker_->Allocator(), checker_->Relation(),
96                                                       checker_->GetGlobalTypesHolder());
97             }
98 
99             typeArgTypes.push_back(paramType);
100         }
101     }
102 
103     while (typeArgTypes.size() < type->TypeArguments().size()) {
104         auto *defaultType = type->TypeArguments().at(typeArgTypes.size())->AsETSTypeParameter()->GetDefaultType();
105         typeArgTypes.push_back(defaultType);
106     }
107 
108     auto pos = (typeArgs == nullptr) ? lexer::SourcePosition() : typeArgs->Range().start;
109     InstantiateType(type, std::move(typeArgTypes), pos);
110     ASSERT(result_->IsETSObjectType());
111     result_->AsETSObjectType()->AddObjectFlag(ETSObjectFlags::NO_OPTS);
112 }
113 
CheckInstantiationConstraints(ETSChecker * checker,ArenaVector<Type * > const & typeParams,const Substitution * substitution,lexer::SourcePosition pos)114 static void CheckInstantiationConstraints(ETSChecker *checker, ArenaVector<Type *> const &typeParams,
115                                           const Substitution *substitution, lexer::SourcePosition pos)
116 {
117     auto relation = checker->Relation();
118 
119     for (auto type : typeParams) {
120         if (!type->IsETSTypeParameter()) {
121             continue;
122         }
123         auto typeParam = type->AsETSTypeParameter();
124         auto typeArg = typeParam->Substitute(relation, substitution);
125         if (typeArg->IsWildcardType()) {
126             continue;
127         }
128         if (typeArg->IsTypeError()) {
129             continue;
130         }
131         // NOTE(vpukhov): #19701 void refactoring
132         ASSERT(typeArg->IsETSReferenceType() || typeArg->IsETSVoidType());
133         auto constraint = typeParam->GetConstraintType()->Substitute(relation, substitution);
134         if (!relation->IsAssignableTo(typeArg, constraint)) {
135             checker->LogTypeError(  // NOTE(vpukhov): refine message
136                 {"Type ", typeArg, " is not assignable to", " constraint type ", constraint}, pos);
137         }
138     }
139 }
140 
TryCheckConstraints()141 void ConstraintCheckScope::TryCheckConstraints()
142 {
143     if (Unlock()) {
144         auto &records = checker_->PendingConstraintCheckRecords();
145         for (auto const &[typeParams, substitution, pos] : records) {
146             CheckInstantiationConstraints(checker_, *typeParams, substitution, pos);
147         }
148         records.clear();
149     }
150 }
151 
InstantiateType(ETSObjectType * type,ArenaVector<Type * > && typeArgTypes,const lexer::SourcePosition & pos)152 void InstantiationContext::InstantiateType(ETSObjectType *type, ArenaVector<Type *> &&typeArgTypes,
153                                            const lexer::SourcePosition &pos)
154 {
155     util::StringView hash = checker_->GetHashFromTypeArguments(typeArgTypes);
156     auto const &typeParams = type->TypeArguments();
157 
158     while (typeArgTypes.size() < typeParams.size()) {
159         typeArgTypes.push_back(typeParams.at(typeArgTypes.size()));
160     }
161 
162     auto *substitution = checker_->NewSubstitution();
163     for (size_t idx = 0; idx < typeParams.size(); idx++) {
164         if (!typeParams[idx]->IsETSTypeParameter()) {
165             continue;
166         }
167         ETSChecker::EmplaceSubstituted(substitution, typeParams[idx]->AsETSTypeParameter(), typeArgTypes[idx]);
168     }
169 
170     ConstraintCheckScope ctScope(checker_);
171     if (!checker_->Relation()->NoThrowGenericTypeAlias()) {
172         checker_->PendingConstraintCheckRecords().push_back({&typeParams, substitution, pos});
173     }
174 
175     result_ = type->Substitute(checker_->Relation(), substitution)->AsETSObjectType();
176     type->GetInstantiationMap().try_emplace(hash, result_->AsETSObjectType());
177     result_->AddTypeFlag(TypeFlag::GENERIC);
178 
179     ctScope.TryCheckConstraints();
180 }
181 
182 }  // namespace ark::es2panda::checker
183