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