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