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 if (HasTypeFlag(TypeFlag::READONLY)) {
27 ss << "readonly ";
28 }
29 bool needParens = (element_->IsETSUnionType() || element_->IsETSFunctionType());
30 if (needParens) {
31 ss << "(";
32 }
33 element_->ToString(ss, precise);
34 if (needParens) {
35 ss << ")";
36 }
37 ss << "[]";
38 }
39
ToAssemblerType(std::stringstream & ss) const40 void ETSArrayType::ToAssemblerType(std::stringstream &ss) const
41 {
42 element_->ToAssemblerType(ss);
43 }
44
ToAssemblerTypeWithRank(std::stringstream & ss) const45 void ETSArrayType::ToAssemblerTypeWithRank(std::stringstream &ss) const
46 {
47 element_->ToAssemblerType(ss);
48
49 for (uint32_t i = Rank(); i > 0; --i) {
50 ss << "[]";
51 }
52 }
53
ToDebugInfoType(std::stringstream & ss) const54 void ETSArrayType::ToDebugInfoType(std::stringstream &ss) const
55 {
56 ss << "[";
57 element_->ToDebugInfoType(ss);
58 }
59
Rank() const60 uint32_t ETSArrayType::Rank() const
61 {
62 uint32_t rank = 1;
63 auto iter = element_;
64 while (iter->IsETSArrayType() && iter->AsETSArrayType()->ElementType() != iter) {
65 iter = iter->AsETSArrayType()->ElementType();
66 rank++;
67 }
68
69 return rank;
70 }
71
Identical(TypeRelation * relation,Type * other)72 void ETSArrayType::Identical(TypeRelation *relation, Type *other)
73 {
74 if (other->IsETSArrayType()) {
75 // will be removed, if wildcard type is assigned to array type, not element type
76 if (element_->IsWildcardType() || other->AsETSArrayType()->ElementType()->IsWildcardType()) {
77 relation->Result(true);
78 return;
79 }
80 relation->IsIdenticalTo(element_, other->AsETSArrayType()->ElementType());
81 }
82 }
83
AssignmentTarget(TypeRelation * relation,Type * source)84 void ETSArrayType::AssignmentTarget(TypeRelation *relation, Type *source)
85 {
86 if (source->HasTypeFlag(TypeFlag::READONLY)) {
87 relation->Result(false);
88 return;
89 }
90 if (source->IsETSArrayType()) {
91 if (AsETSArrayType()->ElementType()->IsETSPrimitiveType() ||
92 source->AsETSArrayType()->ElementType()->IsETSPrimitiveType()) {
93 return;
94 }
95 relation->IsAssignableTo(source->AsETSArrayType()->ElementType(), element_);
96 }
97 }
98
Cast(TypeRelation * const relation,Type * const target)99 void ETSArrayType::Cast(TypeRelation *const relation, Type *const target)
100 {
101 if (target->HasTypeFlag(TypeFlag::ETS_ARRAY)) {
102 conversion::Identity(relation, this, target->AsETSArrayType());
103 if (relation->IsTrue()) {
104 return;
105 }
106
107 conversion::WideningReference(relation, this, target->AsETSArrayType());
108 if (relation->IsTrue()) {
109 return;
110 }
111
112 conversion::NarrowingReference(relation, this, target->AsETSArrayType());
113 if (relation->IsTrue()) {
114 return;
115 }
116
117 if (ElementType()->IsETSTypeParameter()) {
118 // unchecked cast!
119 relation->Result(true);
120 return;
121 }
122
123 conversion::Forbidden(relation);
124 return;
125 }
126
127 if (target->HasTypeFlag(TypeFlag::ETS_OBJECT)) {
128 conversion::WideningReference(relation, this, target->AsETSObjectType());
129 if (relation->IsTrue()) {
130 return;
131 }
132
133 conversion::Forbidden(relation);
134 return;
135 }
136
137 conversion::Forbidden(relation);
138 }
139
IsSupertypeOf(TypeRelation * const relation,Type * source)140 void ETSArrayType::IsSupertypeOf(TypeRelation *const relation, Type *source)
141 {
142 relation->Result(false);
143 // 3.8.3 Subtyping among Array Types
144 if (source->IsETSArrayType()) {
145 auto *const sourceElemType = this->AsETSArrayType()->ElementType();
146 auto *const targetElemType = source->AsETSArrayType()->ElementType();
147 if (targetElemType->IsETSReferenceType() && sourceElemType->IsETSReferenceType()) {
148 sourceElemType->IsSupertypeOf(relation, targetElemType);
149 }
150 }
151 }
152
Instantiate(ArenaAllocator * allocator,TypeRelation * relation,GlobalTypesHolder * globalTypes)153 Type *ETSArrayType::Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes)
154 {
155 auto *elementType = element_->Instantiate(allocator, relation, globalTypes);
156 bool needAllocator = HasTypeFlag(TypeFlag::READONLY);
157 ETSArrayType *arrayType = needAllocator ? relation->GetChecker()->Allocator()->New<ETSArrayType>(elementType)
158 : relation->GetChecker()->AsETSChecker()->CreateETSArrayType(elementType);
159 arrayType->typeFlags_ = typeFlags_;
160 return arrayType;
161 }
162
Substitute(TypeRelation * relation,const Substitution * substitution)163 Type *ETSArrayType::Substitute(TypeRelation *relation, const Substitution *substitution)
164 {
165 if (substitution == nullptr || substitution->empty()) {
166 return this;
167 }
168
169 auto *resultElt = element_->Substitute(relation, substitution);
170
171 if (resultElt == element_) {
172 return this;
173 }
174
175 ETSArrayType *result = relation->GetChecker()->AsETSChecker()->CreateETSArrayType(resultElt);
176 result->typeFlags_ = typeFlags_;
177 return result;
178 }
179
180 } // namespace ark::es2panda::checker
181