• 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 "typeElaborationContext.h"
17 
18 #include <util/helpers.h>
19 #include <binder/scope.h>
20 #include <ir/expressions/identifier.h>
21 #include <ir/expressions/objectExpression.h>
22 #include <ir/expressions/arrayExpression.h>
23 #include <ir/expressions/literals/numberLiteral.h>
24 #include <ir/expressions/literals/stringLiteral.h>
25 #include <ir/base/spreadElement.h>
26 #include <ir/base/property.h>
27 
28 namespace panda::es2panda::checker {
GetBestMatchingType(Type * indexType,const ir::Expression * sourceNode)29 Type *ElaborationContext::GetBestMatchingType(Type *indexType, const ir::Expression *sourceNode)
30 {
31     ArenaVector<Type *> bestMatchingType(checker_->Allocator()->Adapter());
32     Type *sourceType = sourceNode ? checker_->CheckTypeCached(sourceNode) : checker_->GlobalAnyType();
33 
34     for (auto it = potentialTypes_.begin(); it != potentialTypes_.end();) {
35         Type *currentType = checker_->GetPropertyTypeForIndexType(*it, indexType);
36 
37         if (!currentType) {
38             it = potentialTypes_.erase(it);
39             continue;
40         }
41 
42         if (!checker_->IsTypeAssignableTo(sourceType, currentType)) {
43             it = potentialTypes_.erase(it);
44         } else {
45             it++;
46         }
47 
48         bestMatchingType.push_back(currentType);
49     }
50 
51     return checker_->CreateUnionType(std::move(bestMatchingType));
52 }
53 
Start()54 void ArrayElaborationContext::Start()
55 {
56     ASSERT(sourceNode_->IsArrayExpression());
57     RemoveUnnecessaryTypes();
58 
59     for (auto *it : sourceNode_->AsArrayExpression()->Elements()) {
60         if (it->IsOmittedExpression()) {
61             index_++;
62             continue;
63         }
64 
65         util::StringView memberIndex = util::Helpers::ToStringView(checker_->Allocator(), index_);
66 
67         Type *targetElementType = nullptr;
68 
69         if (targetType_->IsUnionType()) {
70             targetElementType = GetBestMatchingType(checker_->CreateStringLiteralType(memberIndex), it);
71         } else {
72             targetElementType =
73                 checker_->GetPropertyTypeForIndexType(targetType_, checker_->CreateStringLiteralType(memberIndex));
74         }
75 
76         if (!targetElementType) {
77             return;
78         }
79 
80         checker_->ElaborateElementwise(targetElementType, it, it->Start());
81         index_++;
82     }
83 }
84 
RemoveUnnecessaryTypes()85 void ArrayElaborationContext::RemoveUnnecessaryTypes()
86 {
87     if (!targetType_->IsUnionType()) {
88         return;
89     }
90 
91     for (auto *it : targetType_->AsUnionType()->ConstituentTypes()) {
92         if (it->IsArrayType() || it->IsObjectType()) {
93             potentialTypes_.push_back(it);
94         }
95     }
96 }
97 
Start()98 void ObjectElaborationContext::Start()
99 {
100     ASSERT(sourceNode_->IsObjectExpression());
101     RemoveUnnecessaryTypes();
102 
103     for (auto *it : sourceNode_->AsObjectExpression()->Properties()) {
104         if (it->IsSpreadElement()) {
105             continue;
106         }
107 
108         const ir::Property *prop = it->AsProperty();
109 
110         Type *propKeyType = nullptr;
111         if (prop->IsComputed()) {
112             propKeyType = checker_->CheckComputedPropertyName(prop->Key());
113         } else {
114             switch (prop->Key()->Type()) {
115                 case ir::AstNodeType::IDENTIFIER: {
116                     propKeyType = checker_->Allocator()->New<StringLiteralType>(prop->Key()->AsIdentifier()->Name());
117                     break;
118                 }
119                 case ir::AstNodeType::NUMBER_LITERAL: {
120                     propKeyType =
121                         checker_->Allocator()->New<NumberLiteralType>(prop->Key()->AsNumberLiteral()->Number());
122                     break;
123                 }
124                 case ir::AstNodeType::STRING_LITERAL: {
125                     propKeyType = checker_->Allocator()->New<StringLiteralType>(prop->Key()->AsStringLiteral()->Str());
126                     break;
127                 }
128                 default: {
129                     UNREACHABLE();
130                     break;
131                 }
132             }
133         }
134 
135         Type *targetElementType = nullptr;
136 
137         if (targetType_->IsUnionType()) {
138             targetElementType = GetBestMatchingType(propKeyType, prop->IsShorthand() ? nullptr : prop->Value());
139         } else {
140             targetElementType = checker_->GetPropertyTypeForIndexType(targetType_, propKeyType);
141         }
142 
143         if (!targetElementType) {
144             if (propKeyType->HasTypeFlag(TypeFlag::LITERAL)) {
145                 checker_->ThrowTypeError({"Object literal may only specify known properties, and ", propKeyType,
146                                           " does not exist in type '", targetType_, "'."},
147                                          it->Start());
148             }
149 
150             return;
151         }
152 
153         if (prop->IsShorthand()) {
154             continue;
155         }
156 
157         checker_->ElaborateElementwise(targetElementType, prop->Value(), it->Start());
158     }
159 }
160 
RemoveUnnecessaryTypes()161 void ObjectElaborationContext::RemoveUnnecessaryTypes()
162 {
163     if (!targetType_->IsUnionType()) {
164         return;
165     }
166 
167     for (auto *it : targetType_->AsUnionType()->ConstituentTypes()) {
168         if (it->IsObjectType()) {
169             potentialTypes_.push_back(it);
170         }
171     }
172 }
173 }  // namespace panda::es2panda::checker
174