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