• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/literals/numberLiteral.h>
23 #include <ir/expressions/literals/stringLiteral.h>
24 
25 namespace panda::es2panda::ir {
26 
Iterate(const NodeTraverser & cb) const27 void MemberExpression::Iterate(const NodeTraverser &cb) const
28 {
29     cb(object_);
30     cb(property_);
31 }
32 
Dump(ir::AstDumper * dumper) const33 void MemberExpression::Dump(ir::AstDumper *dumper) const
34 {
35     dumper->Add({{"type", "MemberExpression"},
36                  {"object", object_},
37                  {"property", property_},
38                  {"computed", computed_},
39                  {"optional", optional_}});
40 }
41 
CompileObject(compiler::PandaGen * pg,compiler::VReg dest) const42 void MemberExpression::CompileObject(compiler::PandaGen *pg, compiler::VReg dest) const
43 {
44     object_->Compile(pg);
45     pg->StoreAccumulator(this, dest);
46     pg->GetOptionalChain()->CheckNullish(optional_, dest);
47 }
48 
CompileKey(compiler::PandaGen * pg) const49 compiler::Operand MemberExpression::CompileKey(compiler::PandaGen *pg) const
50 {
51     return pg->ToPropertyKey(property_, computed_);
52 }
53 
Compile(compiler::PandaGen * pg) const54 void MemberExpression::Compile(compiler::PandaGen *pg) const
55 {
56     compiler::RegScope rs(pg);
57     compiler::VReg objReg = pg->AllocReg();
58     Compile(pg, objReg);
59 }
60 
Compile(compiler::PandaGen * pg,compiler::VReg objReg) const61 void MemberExpression::Compile(compiler::PandaGen *pg, compiler::VReg objReg) const
62 {
63     CompileObject(pg, objReg);
64     compiler::Operand prop = CompileKey(pg);
65 
66     if (object_->IsSuperExpression()) {
67         pg->LoadSuperProperty(this, objReg, prop);
68     } else {
69         pg->LoadObjProperty(this, objReg, prop);
70     }
71 }
72 
Check(checker::Checker * checker) const73 checker::Type *MemberExpression::Check(checker::Checker *checker) const
74 {
75     checker::Type *baseType = checker->CheckNonNullType(object_->Check(checker), object_->Start());
76 
77     if (computed_) {
78         checker::Type *indexType = property_->Check(checker);
79         checker::Type *indexedAccessType = checker->GetPropertyTypeForIndexType(baseType, indexType);
80 
81         if (indexedAccessType) {
82             return indexedAccessType;
83         }
84 
85         if (!indexType->HasTypeFlag(checker::TypeFlag::STRING_LIKE | checker::TypeFlag::NUMBER_LIKE)) {
86             checker->ThrowTypeError({"Type ", indexType, " cannot be used as index type"}, property_->Start());
87         }
88 
89         if (indexType->IsNumberType()) {
90             checker->ThrowTypeError("No index signature with a parameter of type 'string' was found on type this type",
91                                     Start());
92         }
93 
94         if (indexType->IsStringType()) {
95             checker->ThrowTypeError("No index signature with a parameter of type 'number' was found on type this type",
96                                     Start());
97         }
98 
99         switch (property_->Type()) {
100             case ir::AstNodeType::IDENTIFIER: {
101                 checker->ThrowTypeError(
102                     {"Property ", property_->AsIdentifier()->Name(), " does not exist on this type."},
103                     property_->Start());
104             }
105             case ir::AstNodeType::NUMBER_LITERAL: {
106                 checker->ThrowTypeError(
107                     {"Property ", property_->AsNumberLiteral()->Str(), " does not exist on this type."},
108                     property_->Start());
109             }
110             case ir::AstNodeType::STRING_LITERAL: {
111                 checker->ThrowTypeError(
112                     {"Property ", property_->AsStringLiteral()->Str(), " does not exist on this type."},
113                     property_->Start());
114             }
115             default: {
116                 UNREACHABLE();
117             }
118         }
119     }
120 
121     binder::Variable *prop = checker->GetPropertyOfType(baseType, property_->AsIdentifier()->Name());
122 
123     if (prop) {
124         checker::Type *propType = checker->GetTypeOfVariable(prop);
125         if (prop->HasFlag(binder::VariableFlags::READONLY)) {
126             propType->AddTypeFlag(checker::TypeFlag::READONLY);
127         }
128 
129         return propType;
130     }
131 
132     if (baseType->IsObjectType()) {
133         checker::ObjectType *objType = baseType->AsObjectType();
134 
135         if (objType->StringIndexInfo()) {
136             checker::Type *indexType = objType->StringIndexInfo()->GetType();
137             if (objType->StringIndexInfo()->Readonly()) {
138                 indexType->AddTypeFlag(checker::TypeFlag::READONLY);
139             }
140 
141             return indexType;
142         }
143     }
144 
145     checker->ThrowTypeError({"Property ", property_->AsIdentifier()->Name(), " does not exist on this type."},
146                             property_->Start());
147     return nullptr;
148 }
149 
UpdateSelf(const NodeUpdater & cb,binder::Binder * binder)150 void MemberExpression::UpdateSelf(const NodeUpdater &cb, [[maybe_unused]] binder::Binder *binder)
151 {
152     object_ = std::get<ir::AstNode *>(cb(object_))->AsExpression();
153     property_ = std::get<ir::AstNode *>(cb(property_))->AsExpression();
154 }
155 
156 }  // namespace panda::es2panda::ir
157