| // Copyright 2022 The Tint Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "src/tint/resolver/sem_helper.h" |
| |
| #include "src/tint/sem/builtin_enum_expression.h" |
| #include "src/tint/sem/function.h" |
| #include "src/tint/sem/function_expression.h" |
| #include "src/tint/sem/type_expression.h" |
| #include "src/tint/sem/value_expression.h" |
| |
| namespace tint::resolver { |
| |
| SemHelper::SemHelper(ProgramBuilder* builder) : builder_(builder) {} |
| |
| SemHelper::~SemHelper() = default; |
| |
| std::string SemHelper::TypeNameOf(const type::Type* ty) const { |
| return RawTypeNameOf(ty->UnwrapRef()); |
| } |
| |
| std::string SemHelper::RawTypeNameOf(const type::Type* ty) const { |
| return ty->FriendlyName(builder_->Symbols()); |
| } |
| |
| type::Type* SemHelper::TypeOf(const ast::Expression* expr) const { |
| auto* sem = GetVal(expr); |
| return sem ? const_cast<type::Type*>(sem->Type()) : nullptr; |
| } |
| |
| void SemHelper::ErrorUnexpectedExprKind(const sem::Expression* expr, |
| std::string_view wanted) const { |
| Switch( |
| expr, // |
| [&](const sem::VariableUser* var_expr) { |
| auto* variable = var_expr->Variable()->Declaration(); |
| auto name = builder_->Symbols().NameFor(variable->name->symbol); |
| std::string kind = Switch( |
| variable, // |
| [&](const ast::Var*) { return "var"; }, // |
| [&](const ast::Const*) { return "const"; }, // |
| [&](const ast::Parameter*) { return "parameter"; }, // |
| [&](const ast::Override*) { return "override"; }, // |
| [&](Default) { return "variable"; }); |
| AddError("cannot use " + kind + " '" + name + "' as " + std::string(wanted), |
| var_expr->Declaration()->source); |
| NoteDeclarationSource(variable); |
| }, |
| [&](const sem::ValueExpression* val_expr) { |
| auto type = val_expr->Type()->FriendlyName(builder_->Symbols()); |
| AddError("cannot use expression of type '" + type + "' as " + std::string(wanted), |
| val_expr->Declaration()->source); |
| }, |
| [&](const sem::TypeExpression* ty_expr) { |
| auto name = ty_expr->Type()->FriendlyName(builder_->Symbols()); |
| AddError("cannot use type '" + name + "' as " + std::string(wanted), |
| ty_expr->Declaration()->source); |
| }, |
| [&](const sem::FunctionExpression* fn_expr) { |
| auto* fn = fn_expr->Function()->Declaration(); |
| auto name = builder_->Symbols().NameFor(fn->name->symbol); |
| AddError("cannot use function '" + name + "' as " + std::string(wanted), |
| fn_expr->Declaration()->source); |
| NoteDeclarationSource(fn); |
| }, |
| [&](const sem::BuiltinEnumExpression<type::Access>* access) { |
| AddError("cannot use access '" + utils::ToString(access->Value()) + "' as " + |
| std::string(wanted), |
| access->Declaration()->source); |
| }, |
| [&](const sem::BuiltinEnumExpression<type::AddressSpace>* addr) { |
| AddError("cannot use address space '" + utils::ToString(addr->Value()) + "' as " + |
| std::string(wanted), |
| addr->Declaration()->source); |
| }, |
| [&](const sem::BuiltinEnumExpression<type::TexelFormat>* fmt) { |
| AddError("cannot use texel format '" + utils::ToString(fmt->Value()) + "' as " + |
| std::string(wanted), |
| fmt->Declaration()->source); |
| }, |
| [&](Default) { |
| TINT_ICE(Resolver, builder_->Diagnostics()) |
| << "unhandled sem::Expression type: " << (expr ? expr->TypeInfo().name : "<null>"); |
| }); |
| } |
| |
| void SemHelper::ErrorExpectedValueExpr(const sem::Expression* expr) const { |
| ErrorUnexpectedExprKind(expr, "value"); |
| if (auto* ty_expr = expr->As<sem::TypeExpression>()) { |
| if (auto* ident = ty_expr->Declaration()->As<ast::IdentifierExpression>()) { |
| AddNote("are you missing '()' for type initializer?", |
| Source{{ident->source.range.end}}); |
| } |
| if (auto* str = ty_expr->Type()->As<type::Struct>()) { |
| AddNote("struct '" + str->FriendlyName(builder_->Symbols()) + "' declared here", |
| str->Source()); |
| } |
| } |
| } |
| |
| void SemHelper::NoteDeclarationSource(const ast::Node* node) const { |
| Switch( |
| node, |
| [&](const ast::Struct* n) { |
| AddNote("struct '" + builder_->Symbols().NameFor(n->name->symbol) + "' declared here", |
| n->source); |
| }, |
| [&](const ast::Alias* n) { |
| AddNote("alias '" + builder_->Symbols().NameFor(n->name->symbol) + "' declared here", |
| n->source); |
| }, |
| [&](const ast::Var* n) { |
| AddNote("var '" + builder_->Symbols().NameFor(n->name->symbol) + "' declared here", |
| n->source); |
| }, |
| [&](const ast::Let* n) { |
| AddNote("let '" + builder_->Symbols().NameFor(n->name->symbol) + "' declared here", |
| n->source); |
| }, |
| [&](const ast::Override* n) { |
| AddNote("override '" + builder_->Symbols().NameFor(n->name->symbol) + "' declared here", |
| n->source); |
| }, |
| [&](const ast::Const* n) { |
| AddNote("const '" + builder_->Symbols().NameFor(n->name->symbol) + "' declared here", |
| n->source); |
| }, |
| [&](const ast::Parameter* n) { |
| AddNote( |
| "parameter '" + builder_->Symbols().NameFor(n->name->symbol) + "' declared here", |
| n->source); |
| }, |
| [&](const ast::Function* n) { |
| AddNote("function '" + builder_->Symbols().NameFor(n->name->symbol) + "' declared here", |
| n->source); |
| }); |
| } |
| |
| void SemHelper::AddError(const std::string& msg, const Source& source) const { |
| builder_->Diagnostics().add_error(diag::System::Resolver, msg, source); |
| } |
| |
| void SemHelper::AddWarning(const std::string& msg, const Source& source) const { |
| builder_->Diagnostics().add_warning(diag::System::Resolver, msg, source); |
| } |
| |
| void SemHelper::AddNote(const std::string& msg, const Source& source) const { |
| builder_->Diagnostics().add_note(diag::System::Resolver, msg, source); |
| } |
| } // namespace tint::resolver |