• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "typeRelation.h"
17 
18 #include "checker/checker.h"
19 #include "checker/types/ts/indexInfo.h"
20 #include "checker/types/signature.h"
21 
22 namespace panda::es2panda::checker {
Allocator()23 ArenaAllocator *TypeRelation::Allocator()
24 {
25     return checker_->Allocator();
26 }
27 
CacheLookup(const Type * source,const Type * target,const RelationHolder & holder,RelationType type) const28 RelationResult TypeRelation::CacheLookup(const Type *source, const Type *target, const RelationHolder &holder,
29                                          RelationType type) const
30 {
31     if (result_ == RelationResult::CACHE_MISS) {
32         return result_;
33     }
34 
35     RelationKey relationKey {source->Id(), target->Id()};
36     auto res = holder.cached.find(relationKey);
37     if (res == holder.cached.end()) {
38         return RelationResult::CACHE_MISS;
39     }
40 
41     if (res->second.type >= type && res->second.result == RelationResult::TRUE) {
42         return RelationResult::TRUE;
43     }
44 
45     if (res->second.type <= type && res->second.result == RelationResult::FALSE) {
46         return RelationResult::FALSE;
47     }
48 
49     return RelationResult::CACHE_MISS;
50 }
51 
IsIdenticalTo(Type * source,Type * target)52 bool TypeRelation::IsIdenticalTo(Type *source, Type *target)
53 {
54     if (source == target) {
55         Result(true);
56         return true;
57     }
58 
59     result_ = CacheLookup(source, target, checker_->IdenticalResults(), RelationType::IDENTICAL);
60     if (result_ == RelationResult::CACHE_MISS) {
61         checker_->ResolveStructuredTypeMembers(source);
62         checker_->ResolveStructuredTypeMembers(target);
63         result_ = RelationResult::FALSE;
64         target->Identical(this, source);
65         checker_->IdenticalResults().cached.insert({{source->Id(), target->Id()}, {result_, RelationType::IDENTICAL}});
66     }
67 
68     return result_ == RelationResult::TRUE;
69 }
70 
IsIdenticalTo(Signature * source,Signature * target)71 bool TypeRelation::IsIdenticalTo(Signature *source, Signature *target)
72 {
73     if (source == target) {
74         Result(true);
75         return true;
76     }
77 
78     result_ = RelationResult::FALSE;
79     target->Identical(this, source);
80 
81     return result_ == RelationResult::TRUE;
82 }
83 
IsIdenticalTo(IndexInfo * source,IndexInfo * target)84 bool TypeRelation::IsIdenticalTo(IndexInfo *source, IndexInfo *target)
85 {
86     if (source == target) {
87         Result(true);
88         return true;
89     }
90 
91     result_ = RelationResult::FALSE;
92     target->Identical(this, source);
93 
94     return result_ == RelationResult::TRUE;
95 }
96 
97 // NOTE: applyNarrowing -> flag
IsAssignableTo(Type * source,Type * target)98 bool TypeRelation::IsAssignableTo(Type *source, Type *target)
99 {
100     result_ = CacheLookup(source, target, checker_->AssignableResults(), RelationType::ASSIGNABLE);
101     if (result_ == RelationResult::CACHE_MISS) {
102         if (IsIdenticalTo(source, target)) {
103             return true;
104         }
105 
106         result_ = RelationResult::FALSE;
107 
108         if (!source->AssignmentSource(this, target)) {
109             target->AssignmentTarget(this, source);
110         }
111 
112         if (flags_ == TypeRelationFlag::NONE) {
113             checker_->AssignableResults().cached.insert(
114                 {{source->Id(), target->Id()}, {result_, RelationType::ASSIGNABLE}});
115         }
116     }
117 
118     return result_ == RelationResult::TRUE;
119 }
120 
IsComparableTo(Type * source,Type * target)121 bool TypeRelation::IsComparableTo(Type *source, Type *target)
122 {
123     result_ = CacheLookup(source, target, checker_->ComparableResults(), RelationType::COMPARABLE);
124 
125     // NOTE: vpukhov. reimplement dynamic comparison and remove this check
126     if (source->IsETSDynamicType() || target->IsETSDynamicType()) {
127         if (!(source->IsETSDynamicType() && target->IsETSDynamicType())) {
128             return false;
129         }
130     }
131 
132     if (result_ == RelationResult::CACHE_MISS) {
133         if (IsAssignableTo(source, target)) {
134             return true;
135         }
136 
137         result_ = RelationResult::FALSE;
138         target->Compare(this, source);
139         checker_->ComparableResults().cached.insert(
140             {{source->Id(), target->Id()}, {result_, RelationType::COMPARABLE}});
141     }
142 
143     return result_ == RelationResult::TRUE;
144 }
145 
IsCastableTo(Type * const source,Type * const target)146 bool TypeRelation::IsCastableTo(Type *const source, Type *const target)
147 {
148     result_ = CacheLookup(source, target, checker_->UncheckedCastableResult(), RelationType::UNCHECKED_CASTABLE);
149     if (result_ == RelationResult::CACHE_MISS) {
150         result_ = RelationResult::FALSE;
151         flags_ |= TypeRelationFlag::UNCHECKED_CAST;
152 
153         source->Cast(this, target);
154         if (!IsTrue()) {
155             target->CastTarget(this, source);
156         }
157 
158         if (!IsTrue()) {
159             return false;
160         }
161 
162         // NOTE: Can't cache if the node has BoxingUnboxingFlags. These flags should be stored and restored on the node
163         // on cache hit.
164         if (UncheckedCast() && node_->GetBoxingUnboxingFlags() == ir::BoxingUnboxingFlags::NONE) {
165             checker_->UncheckedCastableResult().cached.insert(
166                 {{source->Id(), target->Id()}, {result_, RelationType::UNCHECKED_CASTABLE}});
167         }
168 
169         return true;
170     }
171 
172     return result_ == RelationResult::TRUE;
173 }
174 
IsSupertypeOf(Type * super,Type * sub)175 bool TypeRelation::IsSupertypeOf(Type *super, Type *sub)
176 {
177     result_ = CacheLookup(super, sub, checker_->SupertypeResults(), RelationType::SUPERTYPE);
178     if (result_ == RelationResult::CACHE_MISS) {
179         if (IsIdenticalTo(super, sub)) {
180             return true;
181         }
182 
183         result_ = RelationResult::FALSE;
184 
185         if (super->IsSupertypeOf(this, sub), !IsTrue()) {
186             sub->IsSubtypeOf(this, super);
187         }
188 
189         if (flags_ == TypeRelationFlag::NONE) {
190             checker_->SupertypeResults().cached.insert({{super->Id(), sub->Id()}, {result_, RelationType::SUPERTYPE}});
191         }
192     }
193 
194     return result_ == RelationResult::TRUE;
195 }
196 
RaiseError(const std::string & errMsg,const lexer::SourcePosition & loc) const197 void TypeRelation::RaiseError(const std::string &errMsg, const lexer::SourcePosition &loc) const
198 {
199     checker_->ThrowTypeError(errMsg, loc);
200 }
201 
RaiseError(std::initializer_list<TypeErrorMessageElement> list,const lexer::SourcePosition & loc) const202 void TypeRelation::RaiseError(std::initializer_list<TypeErrorMessageElement> list,
203                               const lexer::SourcePosition &loc) const
204 {
205     checker_->ThrowTypeError(list, loc);
206 }
207 }  // namespace panda::es2panda::checker
208