• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2023 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 "etsTupleType.h"
17 #include "checker/ets/conversion.h"
18 
19 namespace panda::es2panda::checker {
ToString(std::stringstream & ss) const20 void ETSTupleType::ToString(std::stringstream &ss) const
21 {
22     ss << "[";
23     for (const auto *const type : typeList_) {
24         type->ToString(ss);
25     }
26 
27     if (spreadType_ != nullptr) {
28         ss << ", ...";
29         spreadType_->ToString(ss);
30         ss << "[]";
31     }
32 
33     ss << "]";
34 }
35 
GetTypeAtIndex(const TupleSizeType index) const36 Type *ETSTupleType::GetTypeAtIndex(const TupleSizeType index) const
37 {
38     return index >= GetTupleSize() ? GetSpreadType() : GetTupleTypesList().at(static_cast<std::size_t>(index));
39 }
40 
Identical(TypeRelation * const relation,Type * const other)41 void ETSTupleType::Identical([[maybe_unused]] TypeRelation *const relation, Type *const other)
42 {
43     if (!other->IsETSTupleType()) {
44         return;
45     }
46 
47     const auto *const otherTuple = other->AsETSTupleType();
48 
49     if (GetMinTupleSize() != otherTuple->GetMinTupleSize()) {
50         return;
51     }
52 
53     for (TupleSizeType idx = 0; idx < GetMinTupleSize(); ++idx) {
54         if (!relation->IsIdenticalTo(GetTypeAtIndex(idx), otherTuple->GetTypeAtIndex(idx))) {
55             relation->Result(false);
56             return;
57         }
58     }
59 
60     if (HasSpreadType() != otherTuple->HasSpreadType()) {
61         relation->Result(false);
62         return;
63     }
64 
65     relation->Result(true);
66 }
67 
AssignmentSource(TypeRelation * const relation,Type * const target)68 bool ETSTupleType::AssignmentSource(TypeRelation *const relation, Type *const target)
69 {
70     if (!(target->IsETSTupleType() || target->IsETSArrayType())) {
71         return false;
72     }
73 
74     if (!target->IsETSTupleType()) {
75         ASSERT(target->IsETSArrayType());
76         auto *const arrayTarget = target->AsETSArrayType();
77 
78         const SavedTypeRelationFlagsContext savedFlagsCtx(
79             relation, TypeRelationFlag::NO_BOXING | TypeRelationFlag::NO_UNBOXING | TypeRelationFlag::NO_WIDENING);
80 
81         relation->Result(relation->IsAssignableTo(ElementType(), arrayTarget->ElementType()));
82     }
83 
84     return relation->IsTrue();
85 }
86 
AssignmentTarget(TypeRelation * const relation,Type * const source)87 void ETSTupleType::AssignmentTarget(TypeRelation *const relation, Type *const source)
88 {
89     if (!(source->IsETSTupleType() || (source->IsETSArrayType() && HasSpreadType()))) {
90         return;
91     }
92 
93     if (!source->IsETSTupleType()) {
94         ASSERT(source->IsETSArrayType());
95         auto *const arraySource = source->AsETSArrayType();
96 
97         const SavedTypeRelationFlagsContext savedFlagsCtx(
98             relation, TypeRelationFlag::NO_BOXING | TypeRelationFlag::NO_UNBOXING | TypeRelationFlag::NO_WIDENING);
99 
100         relation->Result(relation->IsAssignableTo(arraySource->ElementType(), ElementType()));
101         return;
102     }
103 
104     const auto *const tupleSource = source->AsETSTupleType();
105 
106     if (tupleSource->GetMinTupleSize() != GetMinTupleSize()) {
107         return;
108     }
109 
110     for (int32_t idx = 0; idx < GetMinTupleSize(); ++idx) {
111         // because an array assignment to another array simply copies it's memory address, then it's not possible to
112         // make boxing/unboxing/widening for types. Only conversion allowed is reference widening, which won't generate
113         // bytecode for the conversion, same as for arrays.
114 
115         const SavedTypeRelationFlagsContext savedFlagsCtx(
116             relation, TypeRelationFlag::NO_BOXING | TypeRelationFlag::NO_UNBOXING | TypeRelationFlag::NO_WIDENING);
117 
118         if (!relation->IsAssignableTo(tupleSource->GetTypeAtIndex(idx), GetTypeAtIndex(idx))) {
119             relation->Result(false);
120             return;
121         }
122     }
123 
124     if (!HasSpreadType() && tupleSource->HasSpreadType()) {
125         relation->Result(false);
126         return;
127     }
128 
129     relation->Result(true);
130 }
131 
Cast(TypeRelation * const relation,Type * const target)132 void ETSTupleType::Cast(TypeRelation *const relation, Type *const target)
133 {
134     // NOTE(mmartin): Might be not the correct casting rules, as these aren't defined yet
135 
136     if (!(target->IsETSTupleType() || target->IsETSArrayType())) {
137         conversion::Forbidden(relation);
138         return;
139     }
140 
141     if (target->IsETSArrayType() && (!target->IsETSTupleType())) {
142         auto *const arrayTarget = target->AsETSArrayType();
143 
144         if (!arrayTarget->ElementType()->IsETSObjectType()) {
145             conversion::Forbidden(relation);
146             return;
147         }
148 
149         const SavedTypeRelationFlagsContext savedFlagsCtx(
150             relation, TypeRelationFlag::NO_BOXING | TypeRelationFlag::NO_UNBOXING | TypeRelationFlag::NO_WIDENING);
151 
152         const bool elementsAssignable =
153             std::all_of(GetTupleTypesList().begin(), GetTupleTypesList().end(),
154                         [&relation, &arrayTarget](auto *const tupleTypeAtIdx) {
155                             return relation->IsAssignableTo(tupleTypeAtIdx, arrayTarget->ElementType());
156                         });
157 
158         bool spreadAssignable = true;
159         if (HasSpreadType()) {
160             spreadAssignable = relation->IsAssignableTo(GetSpreadType(), arrayTarget->ElementType());
161         }
162 
163         relation->Result(elementsAssignable && spreadAssignable);
164         return;
165     }
166 
167     const auto *const tupleTarget = target->AsETSTupleType();
168 
169     if (tupleTarget->GetTupleSize() != GetTupleSize()) {
170         return;
171     }
172 
173     for (int32_t idx = 0; idx < GetTupleSize(); ++idx) {
174         const SavedTypeRelationFlagsContext savedFlagsCtx(
175             relation, TypeRelationFlag::NO_BOXING | TypeRelationFlag::NO_UNBOXING | TypeRelationFlag::NO_WIDENING);
176 
177         if (!relation->IsAssignableTo(tupleTarget->GetTypeAtIndex(idx), GetTypeAtIndex(idx))) {
178             return;
179         }
180     }
181 
182     relation->Result(true);
183 }
184 
Instantiate(ArenaAllocator * allocator,TypeRelation * relation,GlobalTypesHolder * globalTypes)185 Type *ETSTupleType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation,
186                                 [[maybe_unused]] GlobalTypesHolder *globalTypes)
187 {
188     return this;
189 }
190 
191 }  // namespace panda::es2panda::checker
192