1 /**
2 * Copyright (c) 2021 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 #include "assignmentExpression.h"
17
18 #include <compiler/base/lreference.h>
19 #include <compiler/core/pandagen.h>
20 #include <compiler/core/regScope.h>
21 #include <typescript/checker.h>
22 #include <typescript/core/destructuringContext.h>
23 #include <ir/astDump.h>
24 #include <ir/base/spreadElement.h>
25 #include <ir/expressions/arrayExpression.h>
26 #include <ir/expressions/objectExpression.h>
27 #include <ir/expressions/identifier.h>
28
29 namespace panda::es2panda::ir {
30
ConvertibleToAssignmentPattern(bool mustBePattern)31 bool AssignmentExpression::ConvertibleToAssignmentPattern(bool mustBePattern)
32 {
33 bool convResult = true;
34
35 switch (left_->Type()) {
36 case AstNodeType::ARRAY_EXPRESSION: {
37 convResult = left_->AsArrayExpression()->ConvertibleToArrayPattern();
38 break;
39 }
40 case AstNodeType::SPREAD_ELEMENT: {
41 convResult = mustBePattern && left_->AsSpreadElement()->ConvertibleToRest(false);
42 break;
43 }
44 case AstNodeType::OBJECT_EXPRESSION: {
45 convResult = left_->AsObjectExpression()->ConvertibleToObjectPattern();
46 break;
47 }
48 case AstNodeType::ASSIGNMENT_EXPRESSION: {
49 convResult = left_->AsAssignmentExpression()->ConvertibleToAssignmentPattern(mustBePattern);
50 break;
51 }
52 case AstNodeType::META_PROPERTY_EXPRESSION:
53 case AstNodeType::CHAIN_EXPRESSION: {
54 convResult = false;
55 break;
56 }
57 default: {
58 break;
59 }
60 }
61
62 if (mustBePattern) {
63 SetType(AstNodeType::ASSIGNMENT_PATTERN);
64 }
65
66 if (!right_->IsAssignmentExpression()) {
67 return convResult;
68 }
69
70 switch (right_->Type()) {
71 case AstNodeType::ARRAY_EXPRESSION: {
72 convResult = right_->AsArrayExpression()->ConvertibleToArrayPattern();
73 break;
74 }
75 case AstNodeType::CHAIN_EXPRESSION:
76 case AstNodeType::SPREAD_ELEMENT: {
77 convResult = false;
78 break;
79 }
80 case AstNodeType::OBJECT_EXPRESSION: {
81 convResult = right_->AsObjectExpression()->ConvertibleToObjectPattern();
82 break;
83 }
84 case AstNodeType::ASSIGNMENT_EXPRESSION: {
85 convResult = right_->AsAssignmentExpression()->ConvertibleToAssignmentPattern(false);
86 break;
87 }
88 default: {
89 break;
90 }
91 }
92
93 return convResult;
94 }
95
Iterate(const NodeTraverser & cb) const96 void AssignmentExpression::Iterate(const NodeTraverser &cb) const
97 {
98 cb(left_);
99 cb(right_);
100 }
101
Dump(ir::AstDumper * dumper) const102 void AssignmentExpression::Dump(ir::AstDumper *dumper) const
103 {
104 if (type_ == AstNodeType::ASSIGNMENT_EXPRESSION) {
105 dumper->Add({{"type", "AssignmentExpression"}, {"operator", operator_}, {"left", left_}, {"right", right_}});
106 } else {
107 dumper->Add({{"type", "AssignmentPattern"}, {"left", left_}, {"right", right_}});
108 }
109 }
110
Compile(compiler::PandaGen * pg) const111 void AssignmentExpression::Compile(compiler::PandaGen *pg) const
112 {
113 compiler::RegScope rs(pg);
114 compiler::LReference lref = compiler::LReference::CreateLRef(pg, left_, false);
115
116 if (operator_ == lexer::TokenType::PUNCTUATOR_LOGICAL_AND_EQUAL ||
117 operator_ == lexer::TokenType::PUNCTUATOR_LOGICAL_OR_EQUAL ||
118 operator_ == lexer::TokenType::PUNCTUATOR_LOGICAL_NULLISH_EQUAL) {
119 auto *skipRight = pg->AllocLabel();
120 auto *endLabel = pg->AllocLabel();
121 compiler::VReg lhsReg = pg->AllocReg();
122
123 lref.GetValue();
124 pg->StoreAccumulator(left_, lhsReg);
125 if (operator_ == lexer::TokenType::PUNCTUATOR_LOGICAL_AND_EQUAL) {
126 pg->BranchIfFalse(left_, skipRight);
127 } else if (operator_ == lexer::TokenType::PUNCTUATOR_LOGICAL_OR_EQUAL) {
128 pg->BranchIfTrue(left_, skipRight);
129 } else {
130 ASSERT(operator_ == lexer::TokenType::PUNCTUATOR_LOGICAL_NULLISH_EQUAL);
131 auto *nullish = pg->AllocLabel();
132 pg->BranchIfStrictNull(left_, nullish);
133 pg->LoadAccumulator(left_, lhsReg);
134 pg->BranchIfStrictNotUndefined(this, skipRight);
135 pg->SetLabel(left_, nullish);
136 }
137 // left = right
138 right_->Compile(pg);
139 lref.SetValue();
140 pg->Branch(this, endLabel);
141 // skip right part
142 pg->SetLabel(this, skipRight);
143 pg->LoadAccumulator(this, lhsReg);
144 pg->SetLabel(this, endLabel);
145 return;
146 } else if (operator_ != lexer::TokenType::PUNCTUATOR_SUBSTITUTION) {
147 compiler::VReg lhsReg = pg->AllocReg();
148
149 lref.GetValue();
150 pg->StoreAccumulator(left_, lhsReg);
151 right_->Compile(pg);
152 pg->Binary(this, operator_, lhsReg);
153 } else {
154 right_->Compile(pg);
155 }
156
157 lref.SetValue();
158 }
159
CompilePattern(compiler::PandaGen * pg) const160 void AssignmentExpression::CompilePattern(compiler::PandaGen *pg) const
161 {
162 compiler::RegScope rs(pg);
163 compiler::LReference lref = compiler::LReference::CreateLRef(pg, left_, false);
164 right_->Compile(pg);
165 lref.SetValue();
166 }
167
Check(checker::Checker * checker) const168 checker::Type *AssignmentExpression::Check(checker::Checker *checker) const
169 {
170 if (left_->IsArrayPattern()) {
171 auto savedContext = checker::SavedCheckerContext(checker, checker::CheckerStatus::FORCE_TUPLE);
172 auto destructuringContext = checker::ArrayDestructuringContext(checker, left_, true, true, nullptr, right_);
173 destructuringContext.Start();
174 return destructuringContext.InferedType();
175 }
176
177 if (left_->IsObjectPattern()) {
178 auto savedContext = checker::SavedCheckerContext(checker, checker::CheckerStatus::FORCE_TUPLE);
179 auto destructuringContext = checker::ObjectDestructuringContext(checker, left_, true, true, nullptr, right_);
180 destructuringContext.Start();
181 return destructuringContext.InferedType();
182 }
183
184 if (left_->IsIdentifier() && left_->AsIdentifier()->Variable() &&
185 left_->AsIdentifier()->Variable()->Declaration()->IsConstDecl()) {
186 checker->ThrowTypeError({"Cannot assign to ", left_->AsIdentifier()->Name(), " because it is a constant."},
187 left_->Start());
188 }
189
190 auto *leftType = left_->Check(checker);
191
192 if (leftType->HasTypeFlag(checker::TypeFlag::READONLY)) {
193 checker->ThrowTypeError("Cannot assign to this property because it is readonly.", left_->Start());
194 }
195
196 if (operator_ == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) {
197 checker->ElaborateElementwise(leftType, right_, left_->Start());
198 return checker->CheckTypeCached(right_);
199 }
200
201 auto *rightType = right_->Check(checker);
202
203 switch (operator_) {
204 case lexer::TokenType::PUNCTUATOR_MULTIPLY_EQUAL:
205 case lexer::TokenType::PUNCTUATOR_EXPONENTIATION_EQUAL:
206 case lexer::TokenType::PUNCTUATOR_DIVIDE_EQUAL:
207 case lexer::TokenType::PUNCTUATOR_MOD_EQUAL:
208 case lexer::TokenType::PUNCTUATOR_MINUS_EQUAL:
209 case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT_EQUAL:
210 case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT_EQUAL:
211 case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT_EQUAL:
212 case lexer::TokenType::PUNCTUATOR_BITWISE_AND_EQUAL:
213 case lexer::TokenType::PUNCTUATOR_BITWISE_XOR_EQUAL:
214 case lexer::TokenType::PUNCTUATOR_BITWISE_OR_EQUAL: {
215 return checker->CheckBinaryOperator(leftType, rightType, left_, right_, this, operator_);
216 }
217 case lexer::TokenType::PUNCTUATOR_PLUS_EQUAL: {
218 return checker->CheckPlusOperator(leftType, rightType, left_, right_, this, operator_);
219 }
220 case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL:
221 case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: {
222 return checker->CheckCompareOperator(leftType, rightType, left_, right_, this, operator_);
223 }
224 case lexer::TokenType::PUNCTUATOR_SUBSTITUTION: {
225 checker->CheckAssignmentOperator(operator_, left_, leftType, rightType);
226 return rightType;
227 }
228 default: {
229 UNREACHABLE();
230 break;
231 }
232 }
233
234 return nullptr;
235 }
236
UpdateSelf(const NodeUpdater & cb,binder::Binder * binder)237 void AssignmentExpression::UpdateSelf(const NodeUpdater &cb, [[maybe_unused]] binder::Binder *binder)
238 {
239 left_ = std::get<ir::AstNode *>(cb(left_))->AsExpression();
240 right_ = std::get<ir::AstNode *>(cb(right_))->AsExpression();
241 }
242
243 } // namespace panda::es2panda::ir
244