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 "memberExpression.h"
17
18 #include <compiler/core/pandagen.h>
19 #include <typescript/checker.h>
20 #include <ir/astDump.h>
21 #include <ir/expressions/identifier.h>
22 #include <ir/expressions/privateIdentifier.h>
23 #include <ir/expressions/literals/numberLiteral.h>
24 #include <ir/expressions/literals/stringLiteral.h>
25
26 namespace panda::es2panda::ir {
27
Iterate(const NodeTraverser & cb) const28 void MemberExpression::Iterate(const NodeTraverser &cb) const
29 {
30 cb(object_);
31 cb(property_);
32 }
33
Dump(ir::AstDumper * dumper) const34 void MemberExpression::Dump(ir::AstDumper *dumper) const
35 {
36 dumper->Add({{"type", "MemberExpression"},
37 {"object", object_},
38 {"property", property_},
39 {"computed", computed_},
40 {"optional", optional_}});
41 }
42
CompileObject(compiler::PandaGen * pg,compiler::VReg dest) const43 void MemberExpression::CompileObject(compiler::PandaGen *pg, compiler::VReg dest) const
44 {
45 object_->Compile(pg);
46 pg->StoreAccumulator(this, dest);
47 pg->GetOptionalChain()->CheckNullish(optional_, dest);
48 }
49
CompileKey(compiler::PandaGen * pg) const50 compiler::Operand MemberExpression::CompileKey(compiler::PandaGen *pg) const
51 {
52 return pg->ToPropertyKey(property_, computed_);
53 }
54
Compile(compiler::PandaGen * pg) const55 void MemberExpression::Compile(compiler::PandaGen *pg) const
56 {
57 compiler::RegScope rs(pg);
58 compiler::VReg objReg = pg->AllocReg();
59 Compile(pg, objReg);
60 }
61
Compile(compiler::PandaGen * pg,compiler::VReg objReg) const62 void MemberExpression::Compile(compiler::PandaGen *pg, compiler::VReg objReg) const
63 {
64 CompileObject(pg, objReg);
65 if (AccessPrivateProperty()) {
66 auto name = property_->AsPrivateIdentifier()->Name();
67 auto result = pg->Scope()->FindPrivateName(name);
68 if (!result.result.isMethod) {
69 pg->LoadAccumulator(this, objReg);
70 pg->LoadPrivateProperty(this, result.lexLevel, result.result.slot);
71 return;
72 }
73 if (result.result.isSetter) {
74 pg->ThrowTypeError(this, "Property is not defined with Getter");
75 }
76 if (result.result.isStatic) {
77 pg->LoadLexicalVar(this, result.lexLevel, result.result.validateMethodSlot);
78 pg->Equal(this, objReg);
79 pg->ThrowTypeErrorIfFalse(this, "Object does not have private property");
80 } else {
81 pg->LoadAccumulator(this, objReg);
82 pg->LoadPrivateProperty(this, result.lexLevel, result.result.validateMethodSlot);
83 }
84
85 if (result.result.isGetter) {
86 pg->LoadAccumulator(this, objReg);
87 pg->LoadPrivateProperty(this, result.lexLevel, result.result.slot);
88 return;
89 }
90 pg->LoadLexicalVar(this, result.lexLevel, result.result.slot);
91 return;
92 }
93 compiler::Operand prop = CompileKey(pg);
94
95 if (object_->IsSuperExpression()) {
96 pg->LoadSuperProperty(property_, objReg, prop);
97 } else {
98 pg->LoadObjProperty(property_, objReg, prop);
99 }
100 }
101
Check(checker::Checker * checker) const102 checker::Type *MemberExpression::Check(checker::Checker *checker) const
103 {
104 checker::Type *baseType = checker->CheckNonNullType(object_->Check(checker), object_->Start());
105
106 if (computed_) {
107 checker::Type *indexType = property_->Check(checker);
108 checker::Type *indexedAccessType = checker->GetPropertyTypeForIndexType(baseType, indexType);
109
110 if (indexedAccessType) {
111 return indexedAccessType;
112 }
113
114 if (!indexType->HasTypeFlag(checker::TypeFlag::STRING_LIKE | checker::TypeFlag::NUMBER_LIKE)) {
115 checker->ThrowTypeError({"Type ", indexType, " cannot be used as index type"}, property_->Start());
116 }
117
118 if (indexType->IsNumberType()) {
119 checker->ThrowTypeError("No index signature with a parameter of type 'string' was found on type this type",
120 Start());
121 }
122
123 if (indexType->IsStringType()) {
124 checker->ThrowTypeError("No index signature with a parameter of type 'number' was found on type this type",
125 Start());
126 }
127
128 switch (property_->Type()) {
129 case ir::AstNodeType::IDENTIFIER: {
130 checker->ThrowTypeError(
131 {"Property ", property_->AsIdentifier()->Name(), " does not exist on this type."},
132 property_->Start());
133 }
134 case ir::AstNodeType::NUMBER_LITERAL: {
135 checker->ThrowTypeError(
136 {"Property ", property_->AsNumberLiteral()->Str(), " does not exist on this type."},
137 property_->Start());
138 }
139 case ir::AstNodeType::STRING_LITERAL: {
140 checker->ThrowTypeError(
141 {"Property ", property_->AsStringLiteral()->Str(), " does not exist on this type."},
142 property_->Start());
143 }
144 default: {
145 UNREACHABLE();
146 }
147 }
148 }
149
150 binder::Variable *prop = checker->GetPropertyOfType(baseType, property_->AsIdentifier()->Name());
151
152 if (prop) {
153 checker::Type *propType = checker->GetTypeOfVariable(prop);
154 if (prop->HasFlag(binder::VariableFlags::READONLY)) {
155 propType->AddTypeFlag(checker::TypeFlag::READONLY);
156 }
157
158 return propType;
159 }
160
161 if (baseType->IsObjectType()) {
162 checker::ObjectType *objType = baseType->AsObjectType();
163
164 if (objType->StringIndexInfo()) {
165 checker::Type *indexType = objType->StringIndexInfo()->GetType();
166 if (objType->StringIndexInfo()->Readonly()) {
167 indexType->AddTypeFlag(checker::TypeFlag::READONLY);
168 }
169
170 return indexType;
171 }
172 }
173
174 checker->ThrowTypeError({"Property ", property_->AsIdentifier()->Name(), " does not exist on this type."},
175 property_->Start());
176 return nullptr;
177 }
178
UpdateSelf(const NodeUpdater & cb,binder::Binder * binder)179 void MemberExpression::UpdateSelf(const NodeUpdater &cb, [[maybe_unused]] binder::Binder *binder)
180 {
181 object_ = std::get<ir::AstNode *>(cb(object_))->AsExpression();
182 property_ = std::get<ir::AstNode *>(cb(property_))->AsExpression();
183 }
184
185 } // namespace panda::es2panda::ir
186