• 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 "checker.h"
17 
18 #include "checker/types/type.h"
19 #include "ir/expression.h"
20 #include "ir/statements/blockStatement.h"
21 #include "parser/program/program.h"
22 #include "util/helpers.h"
23 #include "varbinder/varbinder.h"
24 #include "varbinder/scope.h"
25 #include "varbinder/variable.h"
26 #include "es2panda.h"
27 #include "checker/types/globalTypesHolder.h"
28 #include "checker/types/ts/unionType.h"
29 #include "checker/types/signature.h"
30 
31 #include <cstdint>
32 #include <initializer_list>
33 #include <memory>
34 
35 namespace ark::es2panda::checker {
Checker()36 Checker::Checker()
37     : allocator_(SpaceType::SPACE_TYPE_COMPILER, nullptr, true),
38       context_(this, CheckerStatus::NO_OPTS),
39       globalTypes_(allocator_.New<GlobalTypesHolder>(&allocator_)),
40       relation_(allocator_.New<TypeRelation>(this))
41 {
42 }
43 
Initialize(varbinder::VarBinder * varbinder)44 void Checker::Initialize(varbinder::VarBinder *varbinder)
45 {
46     varbinder_ = varbinder;
47     scope_ = varbinder_->TopScope();
48     program_ = varbinder_->Program();
49 }
50 
FormatMsg(std::initializer_list<TypeErrorMessageElement> list)51 std::string Checker::FormatMsg(std::initializer_list<TypeErrorMessageElement> list)
52 {
53     std::stringstream ss;
54 
55     for (const auto &it : list) {
56         if (std::holds_alternative<char *>(it)) {
57             ss << std::get<char *>(it);
58         } else if (std::holds_alternative<util::StringView>(it)) {
59             ss << std::get<util::StringView>(it);
60         } else if (std::holds_alternative<lexer::TokenType>(it)) {
61             ss << TokenToString(std::get<lexer::TokenType>(it));
62         } else if (std::holds_alternative<const Type *>(it)) {
63             std::get<const Type *>(it)->ToString(ss);
64         } else if (std::holds_alternative<AsSrc>(it)) {
65             std::get<AsSrc>(it).GetType()->ToStringAsSrc(ss);
66         } else if (std::holds_alternative<size_t>(it)) {
67             ss << std::to_string(std::get<size_t>(it));
68         } else if (std::holds_alternative<const Signature *>(it)) {
69             std::get<const Signature *>(it)->ToString(ss, nullptr, true);
70         } else {
71             UNREACHABLE();
72         }
73     }
74 
75     return ss.str();
76 }
77 
ThrowTypeError(std::initializer_list<TypeErrorMessageElement> list,const lexer::SourcePosition & pos)78 void Checker::ThrowTypeError(std::initializer_list<TypeErrorMessageElement> list, const lexer::SourcePosition &pos)
79 {
80     ThrowTypeError(FormatMsg(list), pos);
81 }
82 
ThrowTypeError(std::string_view message,const lexer::SourcePosition & pos)83 void Checker::ThrowTypeError(std::string_view message, const lexer::SourcePosition &pos)
84 {
85     lexer::LineIndex index(program_->SourceCode());
86     lexer::SourceLocation loc = index.GetLocation(pos);
87 
88     throw Error {ErrorType::TYPE, program_->SourceFilePath().Utf8(), message, loc.line, loc.col};
89 }
90 
LogTypeError(std::initializer_list<TypeErrorMessageElement> list,const lexer::SourcePosition & pos)91 void Checker::LogTypeError(std::initializer_list<TypeErrorMessageElement> list, const lexer::SourcePosition &pos)
92 {
93     LogTypeError(FormatMsg(list), pos);
94 }
95 
LogTypeError(std::string_view message,const lexer::SourcePosition & pos)96 void Checker::LogTypeError(std::string_view message, const lexer::SourcePosition &pos)
97 {
98     lexer::LineIndex index(program_->SourceCode());
99     lexer::SourceLocation loc = index.GetLocation(pos);
100 
101     errorLogger_.WriteLog(Error {ErrorType::TYPE, program_->SourceFilePath().Utf8(), message, loc.line, loc.col});
102 }
103 
Warning(const std::string_view message,const lexer::SourcePosition & pos) const104 void Checker::Warning(const std::string_view message, const lexer::SourcePosition &pos) const
105 {
106     lexer::LineIndex index(program_->SourceCode());
107     lexer::SourceLocation loc = index.GetLocation(pos);
108 
109     // NOTE: This should go to stderr but currently the test system does not handle stderr messages
110     auto fileName = program_->SourceFilePath().Utf8();
111     fileName = fileName.substr(fileName.find_last_of(ark::os::file::File::GetPathDelim()) + 1);
112     std::cout << "Warning: " << message << " [" << fileName << ":" << loc.line << ":" << loc.col << "]" << std::endl;
113 }
114 
ReportWarning(std::initializer_list<TypeErrorMessageElement> list,const lexer::SourcePosition & pos)115 void Checker::ReportWarning(std::initializer_list<TypeErrorMessageElement> list, const lexer::SourcePosition &pos)
116 {
117     Warning(FormatMsg(list), pos);
118 }
119 
IsAllTypesAssignableTo(Type * source,Type * target)120 bool Checker::IsAllTypesAssignableTo(Type *source, Type *target)
121 {
122     if (source->TypeFlags() == TypeFlag::UNION) {
123         auto &types = source->AsUnionType()->ConstituentTypes();
124 
125         return std::all_of(types.begin(), types.end(),
126                            [this, target](auto *it) { return IsAllTypesAssignableTo(it, target); });
127     }
128 
129     return relation_->IsAssignableTo(source, target);
130 }
131 
IsTypeIdenticalTo(Type * source,Type * target)132 bool Checker::IsTypeIdenticalTo(Type *source, Type *target)
133 {
134     return relation_->IsIdenticalTo(source, target);
135 }
136 
IsTypeIdenticalTo(Type * source,Type * target,const std::string & errMsg,const lexer::SourcePosition & errPos)137 bool Checker::IsTypeIdenticalTo(Type *source, Type *target, const std::string &errMsg,
138                                 const lexer::SourcePosition &errPos)
139 {
140     if (!IsTypeIdenticalTo(source, target)) {
141         relation_->RaiseError(errMsg, errPos);
142     }
143 
144     return true;
145 }
146 
IsTypeIdenticalTo(Type * source,Type * target,std::initializer_list<TypeErrorMessageElement> list,const lexer::SourcePosition & errPos)147 bool Checker::IsTypeIdenticalTo(Type *source, Type *target, std::initializer_list<TypeErrorMessageElement> list,
148                                 const lexer::SourcePosition &errPos)
149 {
150     if (!IsTypeIdenticalTo(source, target)) {
151         relation_->RaiseError(list, errPos);
152     }
153 
154     return true;
155 }
156 
IsTypeAssignableTo(Type * source,Type * target)157 bool Checker::IsTypeAssignableTo(Type *source, Type *target)
158 {
159     return relation_->IsAssignableTo(source, target);
160 }
161 
IsTypeAssignableTo(Type * source,Type * target,const std::string & errMsg,const lexer::SourcePosition & errPos)162 bool Checker::IsTypeAssignableTo(Type *source, Type *target, const std::string &errMsg,
163                                  const lexer::SourcePosition &errPos)
164 {
165     if (!IsTypeAssignableTo(source, target)) {
166         relation_->RaiseError(errMsg, errPos);
167     }
168 
169     return true;
170 }
171 
IsTypeAssignableTo(Type * source,Type * target,std::initializer_list<TypeErrorMessageElement> list,const lexer::SourcePosition & errPos)172 bool Checker::IsTypeAssignableTo(Type *source, Type *target, std::initializer_list<TypeErrorMessageElement> list,
173                                  const lexer::SourcePosition &errPos)
174 {
175     if (!IsTypeAssignableTo(source, target)) {
176         relation_->RaiseError(list, errPos);
177     }
178 
179     return true;
180 }
181 
IsTypeComparableTo(Type * source,Type * target)182 bool Checker::IsTypeComparableTo(Type *source, Type *target)
183 {
184     return relation_->IsComparableTo(source, target);
185 }
186 
IsTypeComparableTo(Type * source,Type * target,const std::string & errMsg,const lexer::SourcePosition & errPos)187 bool Checker::IsTypeComparableTo(Type *source, Type *target, const std::string &errMsg,
188                                  const lexer::SourcePosition &errPos)
189 {
190     if (!IsTypeComparableTo(source, target)) {
191         relation_->RaiseError(errMsg, errPos);
192     }
193 
194     return true;
195 }
196 
IsTypeComparableTo(Type * source,Type * target,std::initializer_list<TypeErrorMessageElement> list,const lexer::SourcePosition & errPos)197 bool Checker::IsTypeComparableTo(Type *source, Type *target, std::initializer_list<TypeErrorMessageElement> list,
198                                  const lexer::SourcePosition &errPos)
199 {
200     if (!IsTypeComparableTo(source, target)) {
201         relation_->RaiseError(list, errPos);
202     }
203 
204     return true;
205 }
206 
AreTypesComparable(Type * source,Type * target)207 bool Checker::AreTypesComparable(Type *source, Type *target)
208 {
209     return IsTypeComparableTo(source, target) || IsTypeComparableTo(target, source);
210 }
211 
IsTypeEqualityComparableTo(Type * source,Type * target)212 bool Checker::IsTypeEqualityComparableTo(Type *source, Type *target)
213 {
214     return IsTypeComparableTo(source, target);
215 }
216 
Program() const217 parser::Program *Checker::Program() const
218 {
219     return program_;
220 }
221 
SetProgram(parser::Program * program)222 void Checker::SetProgram(parser::Program *program)
223 {
224     program_ = program;
225 }
226 
VarBinder() const227 varbinder::VarBinder *Checker::VarBinder() const
228 {
229     return varbinder_;
230 }
231 
SetAnalyzer(SemanticAnalyzer * analyzer)232 void Checker::SetAnalyzer(SemanticAnalyzer *analyzer)
233 {
234     analyzer_ = analyzer;
235 }
236 
GetAnalyzer() const237 checker::SemanticAnalyzer *Checker::GetAnalyzer() const
238 {
239     return analyzer_;
240 }
241 
242 }  // namespace ark::es2panda::checker
243