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_TS_DESTRUCTURING_CONTEXT_H
17 #define ES2PANDA_CHECKER_TS_DESTRUCTURING_CONTEXT_H
18 
19 #include "checker/TSchecker.h"
20 #include "ir/expression.h"
21 
22 #include <macros.h>
23 
24 namespace ark::es2panda::ir {
25 class Expression;
26 class SpreadElement;
27 }  // namespace ark::es2panda::ir
28 
29 namespace ark::es2panda::checker {
30 class Type;
31 
32 class DestructuringContext {
33 public:
34     // Struct to reduce number of constructor arguments to pass code checker
35     struct DestructuringContextArguments {
36         TSChecker *checker;
37         ir::Expression *id;
38         bool inAssignment;
39         bool convertTupleToArray;
40         ir::TypeNode *typeAnnotation;
41         ir::Expression *initializer;
42     };
43 
DestructuringContext(const DestructuringContextArguments &data)44     explicit DestructuringContext(const DestructuringContextArguments &data)
45         : checker_(data.checker),
46           id_(data.id),
47           inAssignment_(data.inAssignment),
48           convertTupleToArray_(data.convertTupleToArray)
49     {
50         Prepare(data.typeAnnotation, data.initializer, data.id->Start());
51     }
52 
SetInferredType(Type *type)53     void SetInferredType(Type *type)
54     {
55         inferredType_ = type;
56     }
57 
SetSignatureInfo(SignatureInfo *info)58     void SetSignatureInfo(SignatureInfo *info)
59     {
60         signatureInfo_ = info;
61     }
62 
InferredType()63     Type *InferredType()
64     {
65         return inferredType_;
66     }
67 
68     void ValidateObjectLiteralType(ObjectType *objType, ir::ObjectExpression *objPattern);
69     void HandleDestructuringAssignment(ir::Identifier *ident, Type *inferredType, Type *defaultType);
70     void HandleAssignmentPattern(ir::AssignmentExpression *assignmentPattern, Type *inferredType, bool validateDefault);
71     void HandleAssignmentPatternArrayPattern(ir::AssignmentExpression *assignmentPattern, Type *inferredType);
72     void HandleAssignmentPatternIdentifier(ir::AssignmentExpression *assignmentPattern, Type *defaultType,
73                                            Type *inferredType);
74     void SetInferredTypeForVariable(varbinder::Variable *var, Type *inferredType, const lexer::SourcePosition &loc);
75     void Prepare(ir::TypeNode *typeAnnotation, ir::Expression *initializer, const lexer::SourcePosition &loc);
76 
77     DEFAULT_COPY_SEMANTIC(DestructuringContext);
78     DEFAULT_MOVE_SEMANTIC(DestructuringContext);
79     virtual ~DestructuringContext() = default;
80 
81     virtual void Start() = 0;
82     virtual void ValidateInferredType() = 0;
83     virtual Type *NextInferredType([[maybe_unused]] const util::StringView &searchName, bool throwError) = 0;
84     virtual void HandleRest(ir::SpreadElement *rest) = 0;
85     virtual Type *GetRestType([[maybe_unused]] const lexer::SourcePosition &loc) = 0;
86     virtual Type *ConvertTupleTypeToArrayTypeIfNecessary(ir::AstNode *node, Type *type) = 0;
87 
88 protected:
89     // NOLINTBEGIN(misc-non-private-member-variables-in-classes)
90     TSChecker *checker_;
91     ir::Expression *id_;
92     bool inAssignment_;
93     bool convertTupleToArray_;
94     Type *inferredType_ {};
95     SignatureInfo *signatureInfo_ {};
96     bool validateObjectPatternInitializer_ {true};
97     bool validateTypeAnnotation_ {};
98     // NOLINTEND(misc-non-private-member-variables-in-classes)
99 };
100 
101 class ArrayDestructuringContext : public DestructuringContext {
102 public:
ArrayDestructuringContext(const DestructuringContextArguments &data)103     explicit ArrayDestructuringContext(const DestructuringContextArguments &data) : DestructuringContext(data) {}
104 
105     Type *GetTypeFromTupleByIndex(TupleType *tuple);
106     Type *CreateArrayTypeForRest(UnionType *inferredType);
107     Type *CreateTupleTypeForRest(TupleType *tuple);
108     void SetRemainingParameterTypes();
109 
110     void Start() override;
111     void HandleElement(ir::Expression *element, Type *nextInferredType);
112     void ValidateInferredType() override;
113     Type *NextInferredType([[maybe_unused]] const util::StringView &searchName, bool throwError) override;
114     void HandleRest(ir::SpreadElement *rest) override;
115     Type *GetRestType([[maybe_unused]] const lexer::SourcePosition &loc) override;
116     Type *ConvertTupleTypeToArrayTypeIfNecessary(ir::AstNode *node, Type *type) override;
117 
118 private:
119     uint32_t index_ {0};
120 };
121 
122 class ObjectDestructuringContext : public DestructuringContext {
123 public:
ObjectDestructuringContext(const DestructuringContextArguments &data)124     explicit ObjectDestructuringContext(const DestructuringContextArguments &data) : DestructuringContext(data) {}
125 
126     Type *CreateObjectTypeForRest(ObjectType *objType);
127 
128     void Start() override;
129     void ValidateInferredType() override;
130     Type *NextInferredType([[maybe_unused]] const util::StringView &searchName, bool throwError) override;
131     void HandleRest(ir::SpreadElement *rest) override;
132     Type *GetRestType([[maybe_unused]] const lexer::SourcePosition &loc) override;
133     Type *ConvertTupleTypeToArrayTypeIfNecessary(ir::AstNode *node, Type *type) override;
134 };
135 }  // namespace ark::es2panda::checker
136 
137 #endif
138