• 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 #ifndef ES2PANDA_COMPILER_CHECKER_ETS_TYPE_RELATION_CONTEXT_H
17 #define ES2PANDA_COMPILER_CHECKER_ETS_TYPE_RELATION_CONTEXT_H
18 
19 #include "checker/ETSchecker.h"
20 
21 namespace ark::es2panda::checker {
22 class ETSChecker;
23 
24 class AssignmentContext {
25 public:
26     AssignmentContext(TypeRelation *relation, ir::Expression *node, Type *source, Type *target,
27                       const lexer::SourcePosition &pos, std::initializer_list<TypeErrorMessageElement> list,
28                       TypeRelationFlag flags = TypeRelationFlag::NONE)
29     {
30         flags_ |= ((flags & TypeRelationFlag::NO_BOXING) != 0) ? TypeRelationFlag::NONE : TypeRelationFlag::BOXING;
31         flags_ |= ((flags & TypeRelationFlag::NO_UNBOXING) != 0) ? TypeRelationFlag::NONE : TypeRelationFlag::UNBOXING;
32         flags_ |= ((flags & TypeRelationFlag::NO_WIDENING) != 0) ? TypeRelationFlag::NONE : TypeRelationFlag::WIDENING;
33 
34         auto *const etsChecker = relation->GetChecker()->AsETSChecker();
35 
36         if (target->IsETSArrayType() && node->IsArrayExpression()) {
37             ValidateArrayTypeInitializerByElement(relation, node->AsArrayExpression(), target->AsETSArrayType());
38             return;
39         }
40 
41         flags_ |= flags;
42         relation->SetNode(node);
43 
44         // NOTE (oeotvos) The narrowing flag will be applied here. It means, that the result of "let tmp: int = 1.5"
45         // will be 1, which could cause problems.
46         if (source->HasTypeFlag(TypeFlag::CONSTANT)) {
47             flags_ |= TypeRelationFlag::NARROWING;
48         }
49 
50         relation->SetFlags(flags_);
51 
52         if (!relation->IsAssignableTo(source, target)) {
53             if (((flags_ & TypeRelationFlag::UNBOXING) != 0) && !relation->IsTrue() && source->IsETSObjectType() &&
54                 !target->IsETSObjectType()) {
55                 etsChecker->CheckUnboxedTypesAssignable(relation, source, target);
56             }
57             if (((flags_ & TypeRelationFlag::BOXING) != 0) && target->IsETSObjectType() && !relation->IsTrue()) {
58                 etsChecker->CheckBoxedSourceTypeAssignable(relation, source, target);
59             }
60         }
61 
62         if (!relation->IsTrue() && (flags_ & TypeRelationFlag::NO_THROW) == 0) {
63             relation->RaiseError(list, pos);
64         }
65 
66         relation->SetNode(nullptr);
67         relation->SetFlags(TypeRelationFlag::NONE);
68         assignable_ = relation->IsTrue();
69     }
70 
IsAssignable()71     bool IsAssignable() const
72     {
73         return assignable_;
74     }
75 
76     void ValidateArrayTypeInitializerByElement(TypeRelation *relation, ir::ArrayExpression *node, ETSArrayType *target);
77 
78 private:
79     TypeRelationFlag flags_ = TypeRelationFlag::IN_ASSIGNMENT_CONTEXT;
80     bool assignable_ {false};
81 };
82 
83 class InvocationContext {
84 public:
85     InvocationContext(TypeRelation *relation, ir::Expression *node, Type *source, Type *target,
86                       const lexer::SourcePosition &pos, std::initializer_list<TypeErrorMessageElement> list,
87                       TypeRelationFlag initialFlags = TypeRelationFlag::NONE)
88     {
89         flags_ |=
90             ((initialFlags & TypeRelationFlag::NO_BOXING) != 0) ? TypeRelationFlag::NONE : TypeRelationFlag::BOXING;
91         flags_ |=
92             ((initialFlags & TypeRelationFlag::NO_UNBOXING) != 0) ? TypeRelationFlag::NONE : TypeRelationFlag::UNBOXING;
93 
94         auto *const etsChecker = relation->GetChecker()->AsETSChecker();
95 
96         relation->SetNode(node);
97         relation->SetFlags(flags_ | initialFlags);
98 
99         if (!relation->IsAssignableTo(source, target)) {
100             if (((flags_ & TypeRelationFlag::UNBOXING) != 0U) && !relation->IsTrue() && source->IsETSObjectType() &&
101                 !target->IsETSObjectType()) {
102                 etsChecker->CheckUnboxedSourceTypeWithWideningAssignable(relation, source, target);
103             }
104             if (((flags_ & TypeRelationFlag::BOXING) != 0) && target->IsETSObjectType() && !relation->IsTrue()) {
105                 etsChecker->CheckBoxedSourceTypeAssignable(relation, source, target);
106             }
107         }
108 
109         relation->SetNode(nullptr);
110         relation->SetFlags(TypeRelationFlag::NONE);
111 
112         if (!relation->IsTrue()) {
113             if ((initialFlags & TypeRelationFlag::NO_THROW) == 0) {
114                 relation->RaiseError(list, pos);
115             }
116             return;
117         }
118 
119         invocable_ = true;
120     }
121 
IsInvocable()122     bool IsInvocable() const
123     {
124         return invocable_;
125     }
126 
127 private:
128     TypeRelationFlag flags_ = TypeRelationFlag::NONE;
129     bool invocable_ {false};
130 };
131 
132 class ConstraintCheckScope {
133 public:
ConstraintCheckScope(ETSChecker * checker)134     explicit ConstraintCheckScope(ETSChecker *checker) : checker_(checker), isheld_(true)
135     {
136         size_t &counter = checker_->ConstraintCheckScopesCount();
137         ASSERT(counter != 0 || checker_->PendingConstraintCheckRecords().empty());
138         counter++;
139     }
140 
~ConstraintCheckScope()141     ~ConstraintCheckScope()
142     {
143         if (isheld_) {
144             Unlock();
145         }
146     }
147 
148     void TryCheckConstraints();
149 
150     NO_COPY_SEMANTIC(ConstraintCheckScope);
151     NO_MOVE_SEMANTIC(ConstraintCheckScope);
152 
153 private:
Unlock()154     bool Unlock()
155     {
156         ASSERT(isheld_);
157         isheld_ = false;
158         return --checker_->ConstraintCheckScopesCount() == 0;
159     }
160 
161     ETSChecker *checker_;
162     bool isheld_ {};
163 };
164 
165 class InstantiationContext {
166 public:
InstantiationContext(ETSChecker * checker,ETSObjectType * type,ir::TSTypeParameterInstantiation * typeArgs,const lexer::SourcePosition & pos)167     InstantiationContext(ETSChecker *checker, ETSObjectType *type, ir::TSTypeParameterInstantiation *typeArgs,
168                          const lexer::SourcePosition &pos)
169         : checker_(checker)
170     {
171         if (ValidateTypeArguments(type, typeArgs, pos)) {
172             return;
173         }
174         InstantiateType(type, typeArgs);
175     }
176 
InstantiationContext(ETSChecker * checker,ETSObjectType * type,ArenaVector<Type * > && typeArgs,const lexer::SourcePosition & pos)177     InstantiationContext(ETSChecker *checker, ETSObjectType *type, ArenaVector<Type *> &&typeArgs,
178                          const lexer::SourcePosition &pos)
179         : checker_(checker)
180     {
181         if (type->HasObjectFlag(ETSObjectFlags::ENUM)) {
182             return;
183         }
184         InstantiateType(type, std::move(typeArgs), pos);
185     }
186 
Result()187     ETSObjectType *Result()
188     {
189         return result_;
190     }
191 
192 private:
193     bool ValidateTypeArguments(ETSObjectType *type, ir::TSTypeParameterInstantiation *typeArgs,
194                                const lexer::SourcePosition &pos);
195 
196     void InstantiateType(ETSObjectType *type, ir::TSTypeParameterInstantiation *typeArgs);
197 
198     void InstantiateType(ETSObjectType *type, ArenaVector<Type *> &&typeArgTypes, const lexer::SourcePosition &pos);
199     util::StringView GetHashFromTypeArguments(ArenaVector<Type *> &typeArgTypes);
200 
201     ETSChecker *checker_;
202     ETSObjectType *result_ {};
203 };
204 
205 }  // namespace ark::es2panda::checker
206 
207 #endif
208