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 "unionType.h"
17
18 #include <typescript/types/globalTypesHolder.h>
19
20 namespace panda::es2panda::checker {
21
ToString(std::stringstream & ss) const22 void UnionType::ToString(std::stringstream &ss) const
23 {
24 for (auto it = constituentTypes_.begin(); it != constituentTypes_.end(); it++) {
25 (*it)->ToString(ss);
26 if (std::next(it) != constituentTypes_.end()) {
27 ss << " | ";
28 }
29 }
30 }
31
EachTypeRelatedToSomeType(TypeRelation * relation,UnionType * source,UnionType * target)32 bool UnionType::EachTypeRelatedToSomeType(TypeRelation *relation, UnionType *source, UnionType *target)
33 {
34 return std::all_of(source->constituentTypes_.begin(), source->constituentTypes_.end(),
35 [relation, target](auto *s) { return TypeRelatedToSomeType(relation, s, target); });
36 }
37
TypeRelatedToSomeType(TypeRelation * relation,Type * source,UnionType * target)38 bool UnionType::TypeRelatedToSomeType(TypeRelation *relation, Type *source, UnionType *target)
39 {
40 return std::any_of(target->constituentTypes_.begin(), target->constituentTypes_.end(),
41 [relation, source](auto *t) { return relation->IsIdenticalTo(source, t); });
42 }
43
Identical(TypeRelation * relation,Type * other)44 void UnionType::Identical(TypeRelation *relation, Type *other)
45 {
46 if (other->IsUnionType()) {
47 if (EachTypeRelatedToSomeType(relation, this, other->AsUnionType()) &&
48 EachTypeRelatedToSomeType(relation, other->AsUnionType(), this)) {
49 relation->Result(true);
50 return;
51 }
52 }
53
54 relation->Result(false);
55 }
56
AssignmentSource(TypeRelation * relation,Type * target)57 bool UnionType::AssignmentSource(TypeRelation *relation, Type *target)
58 {
59 for (auto *it : constituentTypes_) {
60 if (!relation->IsAssignableTo(it, target)) {
61 return false;
62 }
63 }
64
65 relation->Result(true);
66 return true;
67 }
68
AssignmentTarget(TypeRelation * relation,Type * source)69 void UnionType::AssignmentTarget(TypeRelation *relation, Type *source)
70 {
71 for (auto *it : constituentTypes_) {
72 if (relation->IsAssignableTo(source, it)) {
73 return;
74 }
75 }
76 }
77
GetTypeFacts() const78 TypeFacts UnionType::GetTypeFacts() const
79 {
80 TypeFacts facts = TypeFacts::NONE;
81
82 for (auto *it : constituentTypes_) {
83 facts |= it->GetTypeFacts();
84 }
85
86 return facts;
87 }
88
RemoveDuplicatedTypes(TypeRelation * relation,ArenaVector<Type * > & constituentTypes)89 void UnionType::RemoveDuplicatedTypes(TypeRelation *relation, ArenaVector<Type *> &constituentTypes)
90 {
91 auto compare = constituentTypes.begin();
92
93 while (compare != constituentTypes.end()) {
94 auto it = compare + 1;
95
96 while (it != constituentTypes.end()) {
97 relation->Result(false);
98
99 (*compare)->Identical(relation, *it);
100
101 if (relation->IsTrue()) {
102 it = constituentTypes.erase(it);
103 } else {
104 it++;
105 }
106 }
107
108 compare++;
109 }
110 }
111
HandleUnionType(UnionType * unionType,GlobalTypesHolder * globalTypesHolder)112 Type *UnionType::HandleUnionType(UnionType *unionType, GlobalTypesHolder *globalTypesHolder)
113 {
114 if (unionType->HasConstituentFlag(TypeFlag::ANY)) {
115 return globalTypesHolder->GlobalAnyType();
116 }
117
118 if (unionType->HasConstituentFlag(TypeFlag::UNKNOWN)) {
119 return globalTypesHolder->GlobalUnknownType();
120 }
121
122 RemoveRedundantLiteralTypesFromUnion(unionType);
123
124 if (unionType->ConstituentTypes().size() == 1) {
125 return unionType->ConstituentTypes()[0];
126 }
127
128 return unionType;
129 }
130
RemoveRedundantLiteralTypesFromUnion(UnionType * type)131 void UnionType::RemoveRedundantLiteralTypesFromUnion(UnionType *type)
132 {
133 bool removeNumberLiterals = false;
134 bool removeStringLiterals = false;
135 bool removeBigintLiterals = false;
136 bool removeBooleanLiterals = false;
137
138 if (type->HasConstituentFlag(TypeFlag::NUMBER) && type->HasConstituentFlag(TypeFlag::NUMBER_LITERAL)) {
139 removeNumberLiterals = true;
140 }
141
142 if (type->HasConstituentFlag(TypeFlag::STRING) && type->HasConstituentFlag(TypeFlag::STRING_LITERAL)) {
143 removeStringLiterals = true;
144 }
145
146 if (type->HasConstituentFlag(TypeFlag::BIGINT) && type->HasConstituentFlag(TypeFlag::BIGINT_LITERAL)) {
147 removeBigintLiterals = true;
148 }
149
150 if (type->HasConstituentFlag(TypeFlag::BOOLEAN) && type->HasConstituentFlag(TypeFlag::BOOLEAN_LITERAL)) {
151 removeBooleanLiterals = true;
152 }
153
154 auto &constituentTypes = type->ConstituentTypes();
155 /* TODO(dbatyai): use std::erase_if */
156 auto it = constituentTypes.begin();
157 while (it != constituentTypes.end()) {
158 if ((removeNumberLiterals && (*it)->IsNumberLiteralType()) ||
159 (removeStringLiterals && (*it)->IsStringLiteralType()) ||
160 (removeBigintLiterals && (*it)->IsBigintLiteralType()) ||
161 (removeBooleanLiterals && (*it)->IsBooleanLiteralType())) {
162 type->RemoveConstituentFlag((*it)->TypeFlags());
163 it = constituentTypes.erase(it);
164 continue;
165 }
166
167 it++;
168 }
169 }
170
Instantiate(ArenaAllocator * allocator,TypeRelation * relation,GlobalTypesHolder * globalTypes)171 Type *UnionType::Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes)
172 {
173 ArenaVector<Type *> copiedConstituents(constituentTypes_.size(), allocator->Adapter());
174
175 for (auto *it : constituentTypes_) {
176 copiedConstituents.push_back(it->Instantiate(allocator, relation, globalTypes));
177 }
178
179 RemoveDuplicatedTypes(relation, copiedConstituents);
180
181 if (copiedConstituents.size() == 1) {
182 return copiedConstituents[0];
183 }
184
185 Type *newUnionType = allocator->New<UnionType>(std::move(copiedConstituents));
186 CHECK_NOT_NULL(newUnionType);
187
188 return HandleUnionType(newUnionType->AsUnionType(), globalTypes);
189 }
190
191 } // namespace panda::es2panda::checker
192