1 /**
2 * Copyright (c) 2021 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 <typescript/checker.h>
19 #include <typescript/types/indexInfo.h>
20 #include <typescript/types/signature.h>
21
22 namespace panda::es2panda::checker {
23
GetType() const24 const Type *AsSrc::GetType() const
25 {
26 return type_;
27 }
28
TypeRelation(Checker * checker)29 TypeRelation::TypeRelation(Checker *checker) : checker_(checker), result_(RelationResult::FALSE) {}
30
IsTrue() const31 bool TypeRelation::IsTrue() const
32 {
33 return result_ == RelationResult::TRUE;
34 }
35
GetChecker() const36 const Checker *TypeRelation::GetChecker() const
37 {
38 return checker_;
39 }
40
GetChecker()41 Checker *TypeRelation::GetChecker()
42 {
43 return checker_;
44 }
45
Allocator()46 ArenaAllocator *TypeRelation::Allocator()
47 {
48 return checker_->Allocator();
49 }
50
CacheLookup(const Type * source,const Type * target,const RelationHolder & holder,RelationType type) const51 RelationResult TypeRelation::CacheLookup(const Type *source, const Type *target, const RelationHolder &holder,
52 RelationType type) const
53 {
54 if (result_ == RelationResult::CACHE_MISS) {
55 return result_;
56 }
57
58 CHECK_NOT_NULL(source);
59 CHECK_NOT_NULL(target);
60 RelationKey relationKey {source->Id(), target->Id()};
61 auto res = holder.cached.find(relationKey);
62 if (res == holder.cached.end()) {
63 return RelationResult::CACHE_MISS;
64 }
65
66 if (res->second.type >= type && res->second.result == RelationResult::TRUE) {
67 return RelationResult::TRUE;
68 }
69
70 if (res->second.type <= type && res->second.result == RelationResult::FALSE) {
71 return RelationResult::FALSE;
72 }
73
74 return RelationResult::CACHE_MISS;
75 }
76
IsIdenticalTo(Type * source,Type * target)77 bool TypeRelation::IsIdenticalTo(Type *source, Type *target)
78 {
79 if (source == target) {
80 Result(true);
81 return true;
82 }
83
84 CHECK_NOT_NULL(target);
85 result_ = CacheLookup(source, target, checker_->IdenticalResults(), RelationType::IDENTICAL);
86 if (result_ == RelationResult::CACHE_MISS) {
87 checker_->ResolveStructuredTypeMembers(source);
88 checker_->ResolveStructuredTypeMembers(target);
89 result_ = RelationResult::FALSE;
90 target->Identical(this, source);
91 checker_->IdenticalResults().cached.insert({{source->Id(), target->Id()}, {result_, RelationType::IDENTICAL}});
92 }
93
94 return result_ == RelationResult::TRUE;
95 }
96
IsIdenticalTo(Signature * source,Signature * target)97 bool TypeRelation::IsIdenticalTo(Signature *source, Signature *target)
98 {
99 if (source == target) {
100 Result(true);
101 return true;
102 }
103
104 result_ = RelationResult::FALSE;
105 target->Identical(this, source);
106
107 return result_ == RelationResult::TRUE;
108 }
109
IsIdenticalTo(IndexInfo * source,IndexInfo * target)110 bool TypeRelation::IsIdenticalTo(IndexInfo *source, IndexInfo *target)
111 {
112 if (source == target) {
113 Result(true);
114 return true;
115 }
116
117 result_ = RelationResult::FALSE;
118 target->Identical(this, source);
119
120 return result_ == RelationResult::TRUE;
121 }
122
IsAssignableTo(Type * source,Type * target)123 bool TypeRelation::IsAssignableTo(Type *source, Type *target)
124 {
125 result_ = CacheLookup(source, target, checker_->AssignableResults(), RelationType::ASSIGNABLE);
126 if (result_ == RelationResult::CACHE_MISS) {
127 if (IsIdenticalTo(source, target)) {
128 return true;
129 }
130
131 result_ = RelationResult::FALSE;
132
133 if (!source->AssignmentSource(this, target)) {
134 target->AssignmentTarget(this, source);
135 }
136
137 checker_->AssignableResults().cached.insert(
138 {{source->Id(), target->Id()}, {result_, RelationType::ASSIGNABLE}});
139 }
140
141 return result_ == RelationResult::TRUE;
142 }
143
IsComparableTo(Type * source,Type * target)144 bool TypeRelation::IsComparableTo(Type *source, Type *target)
145 {
146 result_ = CacheLookup(source, target, checker_->ComparableResults(), RelationType::COMPARABLE);
147 if (result_ == RelationResult::CACHE_MISS) {
148 if (IsAssignableTo(source, target)) {
149 return true;
150 }
151
152 result_ = RelationResult::FALSE;
153 CHECK_NOT_NULL(target);
154 target->Compare(this, source);
155 checker_->ComparableResults().cached.insert(
156 {{source->Id(), target->Id()}, {result_, RelationType::COMPARABLE}});
157 }
158
159 return result_ == RelationResult::TRUE;
160 }
161
RaiseError(const std::string & errMsg,const lexer::SourcePosition & loc) const162 void TypeRelation::RaiseError(const std::string &errMsg, const lexer::SourcePosition &loc) const
163 {
164 checker_->ThrowTypeError(errMsg, loc);
165 }
166
RaiseError(std::initializer_list<TypeErrorMessageElement> list,const lexer::SourcePosition & loc) const167 void TypeRelation::RaiseError(std::initializer_list<TypeErrorMessageElement> list,
168 const lexer::SourcePosition &loc) const
169 {
170 checker_->ThrowTypeError(list, loc);
171 }
172
Result(bool res)173 void TypeRelation::Result(bool res)
174 {
175 result_ = res ? RelationResult::TRUE : RelationResult::FALSE;
176 }
177
178 } // namespace panda::es2panda::checker
179