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 "etsTypeParameter.h"
17 #include "ir/expressions/identifier.h"
18 #include "ir/ts/tsTypeParameter.h"
19 #include "checker/ETSchecker.h"
20 #include "checker/ets/conversion.h"
21
22 namespace panda::es2panda::checker {
ToString(std::stringstream & ss) const23 void ETSTypeParameter::ToString(std::stringstream &ss) const
24 {
25 ss << declNode_->Name()->Name();
26
27 if (IsNullish()) {
28 if (ContainsNull()) {
29 ss << "|null";
30 }
31 if (ContainsUndefined()) {
32 ss << "|undefined";
33 }
34 }
35 }
36
Identical(TypeRelation * relation,Type * other)37 void ETSTypeParameter::Identical([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *other)
38 {
39 if ((ContainsNull() != other->ContainsNull()) || (ContainsUndefined() != other->ContainsUndefined())) {
40 return;
41 }
42
43 if (other->IsETSTypeParameter() && other->AsETSTypeParameter()->GetOriginal() == GetOriginal()) {
44 relation->Result(true);
45 }
46 }
47
AssignmentSource(TypeRelation * relation,Type * target)48 bool ETSTypeParameter::AssignmentSource([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *target)
49 {
50 return relation->Result(false);
51 }
52
AssignmentTarget(TypeRelation * relation,Type * source)53 void ETSTypeParameter::AssignmentTarget([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *source)
54 {
55 if (source->IsETSNullType()) {
56 relation->Result(ContainsNull());
57 return;
58 }
59 if (source->IsETSUndefinedType()) {
60 relation->Result(ContainsUndefined());
61 return;
62 }
63
64 if ((source->ContainsNull() && !ContainsNull()) || (source->ContainsUndefined() && !ContainsUndefined())) {
65 relation->Result(false);
66 return;
67 }
68 if (source->IsETSTypeParameter() && source->AsETSTypeParameter()->GetOriginal() == GetOriginal()) {
69 relation->Result(true);
70 return;
71 }
72
73 relation->IsSupertypeOf(this, source);
74 }
75
Cast(TypeRelation * relation,Type * target)76 void ETSTypeParameter::Cast(TypeRelation *relation, Type *target)
77 {
78 if (relation->IsSupertypeOf(target, this)) {
79 relation->RemoveFlags(TypeRelationFlag::UNCHECKED_CAST);
80 return;
81 }
82
83 // NOTE(vpukhov): adjust UNCHECKED_CAST flags
84 if (target->IsETSObjectType()) {
85 relation->RemoveFlags(TypeRelationFlag::UNCHECKED_CAST);
86 }
87 relation->Result(relation->InCastingContext());
88 }
89
CastTarget(TypeRelation * relation,Type * source)90 void ETSTypeParameter::CastTarget(TypeRelation *relation, Type *source)
91 {
92 if (relation->IsSupertypeOf(this, source)) {
93 relation->RemoveFlags(TypeRelationFlag::UNCHECKED_CAST);
94 return;
95 }
96
97 relation->Result(relation->InCastingContext());
98 }
99
IsSupertypeOf(TypeRelation * relation,Type * source)100 void ETSTypeParameter::IsSupertypeOf([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *source)
101 {
102 relation->Result(false);
103 }
104
IsSubtypeOf(TypeRelation * relation,Type * target)105 void ETSTypeParameter::IsSubtypeOf([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *target)
106 {
107 if (relation->IsSupertypeOf(target, GetConstraintType())) {
108 return;
109 }
110
111 relation->Result(false);
112 }
113
Instantiate(ArenaAllocator * allocator,TypeRelation * relation,GlobalTypesHolder * globalTypes)114 Type *ETSTypeParameter::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation,
115 [[maybe_unused]] GlobalTypesHolder *globalTypes)
116 {
117 auto *const checker = relation->GetChecker()->AsETSChecker();
118
119 auto *const copiedType = checker->CreateTypeParameter();
120 copiedType->AddTypeFlag(TypeFlag::GENERIC);
121 copiedType->SetDeclNode(GetDeclNode());
122 copiedType->SetDefaultType(GetDefaultType());
123 copiedType->SetConstraintType(GetConstraintType());
124 copiedType->SetVariable(Variable());
125 return copiedType;
126 }
127
Substitute(TypeRelation * relation,const Substitution * substitution)128 Type *ETSTypeParameter::Substitute(TypeRelation *relation, const Substitution *substitution)
129 {
130 if (substitution == nullptr || substitution->empty()) {
131 return this;
132 }
133 auto *const checker = relation->GetChecker()->AsETSChecker();
134 auto *original = GetOriginal();
135 if (auto repl = substitution->find(original); repl != substitution->end()) {
136 auto *replType = repl->second;
137 /* Any other flags we need to copy? */
138
139 /* The check this != base is a kludge to distinguish bare type parameter T
140 with a nullish constraint (like the default Object?) from explicitly nullish T?
141 */
142 if (this != original && ((ContainsNull() && !replType->ContainsNull()) ||
143 (ContainsUndefined() && !replType->ContainsUndefined()))) {
144 // this type is explicitly marked as nullish
145 ASSERT(ETSChecker::IsReferenceType(replType));
146 auto nullishFlags = TypeFlag(TypeFlags() & TypeFlag::NULLISH);
147 auto *newReplType = checker->CreateNullishType(replType, nullishFlags, checker->Allocator(), relation,
148 checker->GetGlobalTypesHolder());
149 replType = newReplType;
150 }
151 return replType;
152 }
153
154 return this;
155 }
156
ToAssemblerType(std::stringstream & ss) const157 void ETSTypeParameter::ToAssemblerType(std::stringstream &ss) const
158 {
159 GetConstraintType()->ToAssemblerType(ss);
160 }
161
ToDebugInfoType(std::stringstream & ss) const162 void ETSTypeParameter::ToDebugInfoType(std::stringstream &ss) const
163 {
164 GetConstraintType()->ToDebugInfoType(ss);
165 }
166
GetOriginal() const167 ETSTypeParameter *ETSTypeParameter::GetOriginal() const
168 {
169 return GetDeclNode()->Name()->Variable()->TsType()->AsETSTypeParameter();
170 }
171
172 } // namespace panda::es2panda::checker
173