1 /*
2 * Copyright (c) 2021-2024 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 "etsArrayType.h"
17
18 #include "varbinder/variable.h"
19 #include "checker/ETSchecker.h"
20 #include "checker/ets/conversion.h"
21 #include "checker/types/typeRelation.h"
22
23 namespace ark::es2panda::checker {
ToString(std::stringstream & ss,bool precise) const24 void ETSArrayType::ToString(std::stringstream &ss, bool precise) const
25 {
26 bool needParens = (element_->IsETSUnionType() || element_->IsETSFunctionType());
27 if (needParens) {
28 ss << "(";
29 }
30 element_->ToString(ss, precise);
31 if (needParens) {
32 ss << ")";
33 }
34 ss << "[]";
35 }
36
ToAssemblerType(std::stringstream & ss) const37 void ETSArrayType::ToAssemblerType(std::stringstream &ss) const
38 {
39 element_->ToAssemblerType(ss);
40 }
41
ToAssemblerTypeWithRank(std::stringstream & ss) const42 void ETSArrayType::ToAssemblerTypeWithRank(std::stringstream &ss) const
43 {
44 element_->ToAssemblerType(ss);
45
46 for (uint32_t i = Rank(); i > 0; --i) {
47 ss << "[]";
48 }
49 }
50
ToDebugInfoType(std::stringstream & ss) const51 void ETSArrayType::ToDebugInfoType(std::stringstream &ss) const
52 {
53 ss << "[";
54 element_->ToDebugInfoType(ss);
55 }
56
Rank() const57 uint32_t ETSArrayType::Rank() const
58 {
59 uint32_t rank = 1;
60 auto iter = element_;
61 while (iter->IsETSArrayType()) {
62 iter = iter->AsETSArrayType()->ElementType();
63 rank++;
64 }
65
66 return rank;
67 }
68
Identical(TypeRelation * relation,Type * other)69 void ETSArrayType::Identical(TypeRelation *relation, Type *other)
70 {
71 if (other->IsETSArrayType()) {
72 // will be removed, if wildcard type is assigned to array type, not element type
73 if (element_->IsWildcardType() || other->AsETSArrayType()->ElementType()->IsWildcardType()) {
74 relation->Result(true);
75 return;
76 }
77 relation->IsIdenticalTo(element_, other->AsETSArrayType()->ElementType());
78 }
79 }
80
AssignmentTarget(TypeRelation * relation,Type * source)81 void ETSArrayType::AssignmentTarget(TypeRelation *relation, Type *source)
82 {
83 if (source->IsETSArrayType()) {
84 if (AsETSArrayType()->ElementType()->HasTypeFlag(TypeFlag::ETS_PRIMITIVE) ||
85 source->AsETSArrayType()->ElementType()->HasTypeFlag(TypeFlag::ETS_PRIMITIVE)) {
86 return;
87 }
88 relation->IsAssignableTo(source->AsETSArrayType()->ElementType(), element_);
89 }
90 }
91
Cast(TypeRelation * const relation,Type * const target)92 void ETSArrayType::Cast(TypeRelation *const relation, Type *const target)
93 {
94 if (target->HasTypeFlag(TypeFlag::ETS_ARRAY)) {
95 conversion::Identity(relation, this, target->AsETSArrayType());
96 if (relation->IsTrue()) {
97 return;
98 }
99
100 conversion::WideningReference(relation, this, target->AsETSArrayType());
101 if (relation->IsTrue()) {
102 return;
103 }
104
105 conversion::NarrowingReference(relation, this, target->AsETSArrayType());
106 if (relation->IsTrue()) {
107 return;
108 }
109
110 if (ElementType()->IsETSTypeParameter()) {
111 // unchecked cast!
112 relation->Result(true);
113 return;
114 }
115
116 conversion::Forbidden(relation);
117 return;
118 }
119
120 if (target->HasTypeFlag(TypeFlag::ETS_OBJECT)) {
121 conversion::WideningReference(relation, this, target->AsETSObjectType());
122 if (relation->IsTrue()) {
123 return;
124 }
125
126 conversion::Forbidden(relation);
127 return;
128 }
129
130 conversion::Forbidden(relation);
131 }
132
IsSupertypeOf(TypeRelation * const relation,Type * source)133 void ETSArrayType::IsSupertypeOf(TypeRelation *const relation, Type *source)
134 {
135 relation->Result(false);
136 // 3.8.3 Subtyping among Array Types
137 if (source->IsETSArrayType()) {
138 auto *const sourceElemType = this->AsETSArrayType()->ElementType();
139 auto *const targetElemType = source->AsETSArrayType()->ElementType();
140 if (targetElemType->IsETSReferenceType() && sourceElemType->IsETSReferenceType()) {
141 sourceElemType->IsSupertypeOf(relation, targetElemType);
142 }
143 }
144 }
145
Instantiate(ArenaAllocator * allocator,TypeRelation * relation,GlobalTypesHolder * globalTypes)146 Type *ETSArrayType::Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes)
147 {
148 return relation->GetChecker()->AsETSChecker()->CreateETSArrayType(
149 element_->Instantiate(allocator, relation, globalTypes));
150 }
151
Substitute(TypeRelation * relation,const Substitution * substitution)152 Type *ETSArrayType::Substitute(TypeRelation *relation, const Substitution *substitution)
153 {
154 if (substitution == nullptr || substitution->empty()) {
155 return this;
156 }
157
158 auto *resultElt = element_->Substitute(relation, substitution);
159 return resultElt == element_ ? this : relation->GetChecker()->AsETSChecker()->CreateETSArrayType(resultElt);
160 }
161
162 } // namespace ark::es2panda::checker
163