• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2025 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 "checker/types/globalTypesHolder.h"
20 
21 namespace ark::es2panda::checker {
ToString(std::stringstream & ss,bool precise) const22 void UnionType::ToString(std::stringstream &ss, bool precise) const
23 {
24     for (auto it = constituentTypes_.begin(); it != constituentTypes_.end(); it++) {
25         (*it)->ToString(ss, precise);
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     ES2PANDA_ASSERT(unionType != nullptr);
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     /* NOTE: 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>(allocator, std::move(copiedConstituents));
187 
188     ES2PANDA_ASSERT(newUnionType != nullptr);
189     return HandleUnionType(newUnionType->AsUnionType(), globalTypes);
190 }
191 }  // namespace ark::es2panda::checker
192