• 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_CHECKER_CHECKER_H
17 #define ES2PANDA_CHECKER_CHECKER_H
18 
19 #include "varbinder/enumMemberResult.h"
20 #include "checker/checkerContext.h"
21 #include "checker/SemanticAnalyzer.h"
22 #include "checker/types/typeRelation.h"
23 #include "util/enumbitops.h"
24 #include "util/ustring.h"
25 #include "es2panda.h"
26 
27 #include "macros.h"
28 
29 #include <cstdint>
30 #include <initializer_list>
31 #include <unordered_map>
32 #include <unordered_set>
33 
34 namespace panda::es2panda::parser {
35 class Program;
36 }  // namespace panda::es2panda::parser
37 
38 namespace panda::es2panda::ir {
39 class AstNode;
40 class Expression;
41 class BlockStatement;
42 enum class AstNodeType;
43 }  // namespace panda::es2panda::ir
44 
45 namespace panda::es2panda::varbinder {
46 class VarBinder;
47 class Decl;
48 class EnumVariable;
49 class FunctionDecl;
50 class LocalVariable;
51 class Scope;
52 class Variable;
53 }  // namespace panda::es2panda::varbinder
54 
55 namespace panda::es2panda::checker {
56 class ETSChecker;
57 class InterfaceType;
58 class GlobalTypesHolder;
59 
60 using StringLiteralPool = std::unordered_map<util::StringView, Type *>;
61 using NumberLiteralPool = std::unordered_map<double, Type *>;
62 using FunctionParamsResolveResult = std::variant<std::vector<varbinder::LocalVariable *> &, bool>;
63 using InterfacePropertyMap =
64     std::unordered_map<util::StringView, std::pair<varbinder::LocalVariable *, InterfaceType *>>;
65 using TypeOrNode = std::variant<Type *, ir::AstNode *>;
66 using IndexInfoTypePair = std::pair<Type *, Type *>;
67 using PropertyMap = std::unordered_map<util::StringView, varbinder::LocalVariable *>;
68 using ArgRange = std::pair<uint32_t, uint32_t>;
69 
70 class Checker {
71 public:
72     explicit Checker();
73     virtual ~Checker() = default;
74     NO_COPY_SEMANTIC(Checker);
75     NO_MOVE_SEMANTIC(Checker);
76 
Allocator()77     ArenaAllocator *Allocator()
78     {
79         return &allocator_;
80     }
81 
Scope()82     varbinder::Scope *Scope() const
83     {
84         return scope_;
85     }
86 
Context()87     CheckerContext &Context()
88     {
89         return context_;
90     }
91 
HasStatus(CheckerStatus status)92     bool HasStatus(CheckerStatus status)
93     {
94         return (context_.Status() & status) != 0;
95     }
96 
RemoveStatus(CheckerStatus status)97     void RemoveStatus(CheckerStatus status)
98     {
99         context_.Status() &= ~status;
100     }
101 
AddStatus(CheckerStatus status)102     void AddStatus(CheckerStatus status)
103     {
104         context_.Status() |= status;
105     }
106 
Relation()107     TypeRelation *Relation() const
108     {
109         return relation_;
110     }
111 
GetGlobalTypesHolder()112     GlobalTypesHolder *GetGlobalTypesHolder() const
113     {
114         return globalTypes_;
115     }
116 
IdenticalResults()117     RelationHolder &IdenticalResults()
118     {
119         return identicalResults_;
120     }
121 
AssignableResults()122     RelationHolder &AssignableResults()
123     {
124         return assignableResults_;
125     }
126 
ComparableResults()127     RelationHolder &ComparableResults()
128     {
129         return comparableResults_;
130     }
131 
UncheckedCastableResult()132     [[nodiscard]] RelationHolder &UncheckedCastableResult() noexcept
133     {
134         return uncheckedCastableResults_;
135     }
136 
SupertypeResults()137     RelationHolder &SupertypeResults()
138     {
139         return supertypeResults_;
140     }
141 
TypeStack()142     std::unordered_set<const void *> &TypeStack()
143     {
144         return typeStack_;
145     }
146 
IsETSChecker()147     virtual bool IsETSChecker()
148     {
149         return false;
150     }
151 
AsETSChecker()152     ETSChecker *AsETSChecker()
153     {
154         return reinterpret_cast<ETSChecker *>(this);
155     }
156 
AsETSChecker()157     const ETSChecker *AsETSChecker() const
158     {
159         return reinterpret_cast<const ETSChecker *>(this);
160     }
161 
162     virtual bool StartChecker([[maybe_unused]] varbinder::VarBinder *varbinder, const CompilerOptions &options) = 0;
163     virtual Type *CheckTypeCached(ir::Expression *expr) = 0;
164     virtual Type *GetTypeOfVariable(varbinder::Variable *var) = 0;
165     virtual void ResolveStructuredTypeMembers(Type *type) = 0;
166 
167     std::string FormatMsg(std::initializer_list<TypeErrorMessageElement> list);
168     [[noreturn]] void ThrowTypeError(std::string_view message, const lexer::SourcePosition &pos);
169     [[noreturn]] void ThrowTypeError(std::initializer_list<TypeErrorMessageElement> list,
170                                      const lexer::SourcePosition &pos);
171     void Warning(std::string_view message, const lexer::SourcePosition &pos) const;
172     void ReportWarning(std::initializer_list<TypeErrorMessageElement> list, const lexer::SourcePosition &pos);
173 
174     bool IsTypeIdenticalTo(Type *source, Type *target);
175     bool IsTypeIdenticalTo(Type *source, Type *target, const std::string &errMsg, const lexer::SourcePosition &errPos);
176     bool IsTypeIdenticalTo(Type *source, Type *target, std::initializer_list<TypeErrorMessageElement> list,
177                            const lexer::SourcePosition &errPos);
178     bool IsTypeAssignableTo(Type *source, Type *target);
179     bool IsTypeAssignableTo(Type *source, Type *target, const std::string &errMsg, const lexer::SourcePosition &errPos);
180     bool IsTypeAssignableTo(Type *source, Type *target, std::initializer_list<TypeErrorMessageElement> list,
181                             const lexer::SourcePosition &errPos);
182     bool IsTypeComparableTo(Type *source, Type *target);
183     bool IsTypeComparableTo(Type *source, Type *target, const std::string &errMsg, const lexer::SourcePosition &errPos);
184     bool IsTypeComparableTo(Type *source, Type *target, std::initializer_list<TypeErrorMessageElement> list,
185                             const lexer::SourcePosition &errPos);
186     bool AreTypesComparable(Type *source, Type *target);
187     bool IsTypeEqualityComparableTo(Type *source, Type *target);
188     bool IsAllTypesAssignableTo(Type *source, Type *target);
189     void SetAnalyzer(SemanticAnalyzer *analyzer);
190     checker::SemanticAnalyzer *GetAnalyzer() const;
191 
192     friend class ScopeContext;
193     friend class TypeStackElement;
194     friend class SavedCheckerContext;
195 
196     varbinder::VarBinder *VarBinder() const;
197 
198 protected:
199     void Initialize(varbinder::VarBinder *varbinder);
200     parser::Program *Program() const;
201     void SetProgram(parser::Program *program);
202 
203 private:
204     ArenaAllocator allocator_;
205     CheckerContext context_;
206     GlobalTypesHolder *globalTypes_;
207     TypeRelation *relation_;
208     SemanticAnalyzer *analyzer_ {};
209     varbinder::VarBinder *varbinder_ {};
210     parser::Program *program_ {};
211     varbinder::Scope *scope_ {};
212 
213     RelationHolder identicalResults_;
214     RelationHolder assignableResults_;
215     RelationHolder comparableResults_;
216     RelationHolder uncheckedCastableResults_;
217     RelationHolder supertypeResults_;
218 
219     std::unordered_set<const void *> typeStack_;
220 };
221 
222 class TypeStackElement {
223 public:
TypeStackElement(Checker * checker,void * element,std::initializer_list<TypeErrorMessageElement> list,const lexer::SourcePosition & pos)224     explicit TypeStackElement(Checker *checker, void *element, std::initializer_list<TypeErrorMessageElement> list,
225                               const lexer::SourcePosition &pos)
226         : checker_(checker), element_(element)
227     {
228         if (!checker->typeStack_.insert(element).second) {
229             checker_->ThrowTypeError(list, pos);
230         }
231     }
232 
TypeStackElement(Checker * checker,void * element,std::string_view err,const lexer::SourcePosition & pos)233     explicit TypeStackElement(Checker *checker, void *element, std::string_view err, const lexer::SourcePosition &pos)
234         : checker_(checker), element_(element)
235     {
236         if (!checker->typeStack_.insert(element).second) {
237             checker_->ThrowTypeError(err, pos);
238         }
239     }
240 
~TypeStackElement()241     ~TypeStackElement()
242     {
243         checker_->typeStack_.erase(element_);
244     }
245 
246     NO_COPY_SEMANTIC(TypeStackElement);
247     NO_MOVE_SEMANTIC(TypeStackElement);
248 
249 private:
250     Checker *checker_;
251     void *element_;
252 };
253 
254 class ScopeContext {
255 public:
ScopeContext(Checker * checker,varbinder::Scope * newScope)256     explicit ScopeContext(Checker *checker, varbinder::Scope *newScope)
257         : checker_(checker), prevScope_(checker_->scope_)
258     {
259         checker_->scope_ = newScope;
260     }
261 
~ScopeContext()262     ~ScopeContext()
263     {
264         checker_->scope_ = prevScope_;
265     }
266 
267     NO_COPY_SEMANTIC(ScopeContext);
268     NO_MOVE_SEMANTIC(ScopeContext);
269 
270 private:
271     Checker *checker_;
272     varbinder::Scope *prevScope_;
273 };
274 
275 class SavedCheckerContext {
276 public:
SavedCheckerContext(Checker * checker,CheckerStatus newStatus)277     explicit SavedCheckerContext(Checker *checker, CheckerStatus newStatus)
278         : SavedCheckerContext(checker, newStatus, nullptr)
279     {
280     }
281 
SavedCheckerContext(Checker * checker,CheckerStatus newStatus,ETSObjectType * containingClass)282     explicit SavedCheckerContext(Checker *checker, CheckerStatus newStatus, ETSObjectType *containingClass)
283         : SavedCheckerContext(checker, newStatus, containingClass, nullptr)
284     {
285     }
286 
SavedCheckerContext(Checker * checker,CheckerStatus newStatus,ETSObjectType * containingClass,Signature * containingSignature)287     explicit SavedCheckerContext(Checker *checker, CheckerStatus newStatus, ETSObjectType *containingClass,
288                                  Signature *containingSignature)
289         : checker_(checker), prev_(checker->context_)
290     {
291         checker_->context_ = CheckerContext(checker->Allocator(), newStatus, containingClass, containingSignature);
292     }
293 
294     NO_COPY_SEMANTIC(SavedCheckerContext);
295     DEFAULT_MOVE_SEMANTIC(SavedCheckerContext);
296 
~SavedCheckerContext()297     ~SavedCheckerContext()
298     {
299         checker_->context_ = prev_;
300     }
301 
302 private:
303     Checker *checker_;
304     CheckerContext prev_;
305 };
306 
307 }  // namespace panda::es2panda::checker
308 
309 #endif /* CHECKER_H */
310