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