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