• 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 
LogTypeError(std::initializer_list<TypeErrorMessageElement> list,const lexer::SourcePosition & pos)78 void Checker::LogTypeError(std::initializer_list<TypeErrorMessageElement> list, const lexer::SourcePosition &pos)
79 {
80     LogTypeError(FormatMsg(list), pos);
81 }
82 
LogTypeError(std::string_view message,const lexer::SourcePosition & pos)83 void Checker::LogTypeError(std::string_view message, const lexer::SourcePosition &pos)
84 {
85     lexer::LineIndex index(program_->SourceCode());
86     lexer::SourceLocation loc = index.GetLocation(pos);
87 
88     errorLogger_.WriteLog(Error {ErrorType::TYPE, program_->SourceFilePath().Utf8(), message, loc.line, loc.col});
89 }
90 
Warning(const std::string_view message,const lexer::SourcePosition & pos) const91 void Checker::Warning(const std::string_view message, const lexer::SourcePosition &pos) const
92 {
93     lexer::LineIndex index(program_->SourceCode());
94     lexer::SourceLocation loc = index.GetLocation(pos);
95 
96     // NOTE: This should go to stderr but currently the test system does not handle stderr messages
97     auto fileName = program_->SourceFilePath().Utf8();
98     fileName = fileName.substr(fileName.find_last_of(ark::os::file::File::GetPathDelim()) + 1);
99     std::cout << "Warning: " << message << " [" << fileName << ":" << loc.line << ":" << loc.col << "]" << std::endl;
100 }
101 
ReportWarning(std::initializer_list<TypeErrorMessageElement> list,const lexer::SourcePosition & pos)102 void Checker::ReportWarning(std::initializer_list<TypeErrorMessageElement> list, const lexer::SourcePosition &pos)
103 {
104     Warning(FormatMsg(list), pos);
105 }
106 
IsAllTypesAssignableTo(Type * source,Type * target)107 bool Checker::IsAllTypesAssignableTo(Type *source, Type *target)
108 {
109     if (source->TypeFlags() == TypeFlag::UNION) {
110         auto &types = source->AsUnionType()->ConstituentTypes();
111 
112         return std::all_of(types.begin(), types.end(),
113                            [this, target](auto *it) { return IsAllTypesAssignableTo(it, target); });
114     }
115 
116     return relation_->IsAssignableTo(source, target);
117 }
118 
IsTypeIdenticalTo(Type * source,Type * target)119 bool Checker::IsTypeIdenticalTo(Type *source, Type *target)
120 {
121     return relation_->IsIdenticalTo(source, target);
122 }
123 
IsTypeIdenticalTo(Type * source,Type * target,const std::string & errMsg,const lexer::SourcePosition & errPos)124 bool Checker::IsTypeIdenticalTo(Type *source, Type *target, const std::string &errMsg,
125                                 const lexer::SourcePosition &errPos)
126 {
127     if (!IsTypeIdenticalTo(source, target)) {
128         relation_->RaiseError(errMsg, errPos);
129     }
130 
131     return true;
132 }
133 
IsTypeIdenticalTo(Type * source,Type * target,std::initializer_list<TypeErrorMessageElement> list,const lexer::SourcePosition & errPos)134 bool Checker::IsTypeIdenticalTo(Type *source, Type *target, std::initializer_list<TypeErrorMessageElement> list,
135                                 const lexer::SourcePosition &errPos)
136 {
137     if (!IsTypeIdenticalTo(source, target)) {
138         relation_->RaiseError(list, errPos);
139     }
140 
141     return true;
142 }
143 
IsTypeAssignableTo(Type * source,Type * target)144 bool Checker::IsTypeAssignableTo(Type *source, Type *target)
145 {
146     return relation_->IsAssignableTo(source, target);
147 }
148 
IsTypeAssignableTo(Type * source,Type * target,const std::string & errMsg,const lexer::SourcePosition & errPos)149 bool Checker::IsTypeAssignableTo(Type *source, Type *target, const std::string &errMsg,
150                                  const lexer::SourcePosition &errPos)
151 {
152     if (!IsTypeAssignableTo(source, target)) {
153         relation_->RaiseError(errMsg, errPos);
154     }
155 
156     return true;
157 }
158 
IsTypeAssignableTo(Type * source,Type * target,std::initializer_list<TypeErrorMessageElement> list,const lexer::SourcePosition & errPos)159 bool Checker::IsTypeAssignableTo(Type *source, Type *target, std::initializer_list<TypeErrorMessageElement> list,
160                                  const lexer::SourcePosition &errPos)
161 {
162     if (!IsTypeAssignableTo(source, target)) {
163         relation_->RaiseError(list, errPos);
164     }
165 
166     return true;
167 }
168 
IsTypeComparableTo(Type * source,Type * target)169 bool Checker::IsTypeComparableTo(Type *source, Type *target)
170 {
171     return relation_->IsComparableTo(source, target);
172 }
173 
IsTypeComparableTo(Type * source,Type * target,const std::string & errMsg,const lexer::SourcePosition & errPos)174 bool Checker::IsTypeComparableTo(Type *source, Type *target, const std::string &errMsg,
175                                  const lexer::SourcePosition &errPos)
176 {
177     if (!IsTypeComparableTo(source, target)) {
178         relation_->RaiseError(errMsg, errPos);
179     }
180 
181     return true;
182 }
183 
IsTypeComparableTo(Type * source,Type * target,std::initializer_list<TypeErrorMessageElement> list,const lexer::SourcePosition & errPos)184 bool Checker::IsTypeComparableTo(Type *source, Type *target, std::initializer_list<TypeErrorMessageElement> list,
185                                  const lexer::SourcePosition &errPos)
186 {
187     if (!IsTypeComparableTo(source, target)) {
188         relation_->RaiseError(list, errPos);
189     }
190 
191     return true;
192 }
193 
AreTypesComparable(Type * source,Type * target)194 bool Checker::AreTypesComparable(Type *source, Type *target)
195 {
196     return IsTypeComparableTo(source, target) || IsTypeComparableTo(target, source);
197 }
198 
IsTypeEqualityComparableTo(Type * source,Type * target)199 bool Checker::IsTypeEqualityComparableTo(Type *source, Type *target)
200 {
201     return IsTypeComparableTo(source, target);
202 }
203 
Program() const204 parser::Program *Checker::Program() const
205 {
206     return program_;
207 }
208 
SetProgram(parser::Program * program)209 void Checker::SetProgram(parser::Program *program)
210 {
211     program_ = program;
212 }
213 
VarBinder() const214 varbinder::VarBinder *Checker::VarBinder() const
215 {
216     return varbinder_;
217 }
218 
SetAnalyzer(SemanticAnalyzer * analyzer)219 void Checker::SetAnalyzer(SemanticAnalyzer *analyzer)
220 {
221     analyzer_ = analyzer;
222 }
223 
GetAnalyzer() const224 checker::SemanticAnalyzer *Checker::GetAnalyzer() const
225 {
226     return analyzer_;
227 }
228 
229 }  // namespace ark::es2panda::checker
230