| // 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. |
| |
| #ifndef SRC_TINT_LANG_WGSL_RESOLVER_SEM_HELPER_H_ |
| #define SRC_TINT_LANG_WGSL_RESOLVER_SEM_HELPER_H_ |
| |
| #include <string> |
| |
| #include "src/tint/lang/core/builtin/builtin_value.h" |
| #include "src/tint/lang/core/builtin/interpolation_sampling.h" |
| #include "src/tint/lang/core/builtin/interpolation_type.h" |
| #include "src/tint/lang/wgsl/program/program_builder.h" |
| #include "src/tint/lang/wgsl/resolver/dependency_graph.h" |
| #include "src/tint/lang/wgsl/sem/builtin_enum_expression.h" |
| #include "src/tint/lang/wgsl/sem/function_expression.h" |
| #include "src/tint/lang/wgsl/sem/type_expression.h" |
| #include "src/tint/utils/containers/map.h" |
| #include "src/tint/utils/diagnostic/diagnostic.h" |
| |
| namespace tint::resolver { |
| |
| /// Helper class to retrieve sem information. |
| class SemHelper { |
| public: |
| /// Constructor |
| /// @param builder the program builder |
| explicit SemHelper(ProgramBuilder* builder); |
| ~SemHelper(); |
| |
| /// Get is a helper for obtaining the semantic node for the given AST node. |
| /// Raises an ICE and returns `nullptr` if there is no semantic node associated with the AST |
| /// node. |
| /// @param ast the ast node to get the sem for |
| /// @returns the sem node for @p ast |
| template <typename SEM = sem::Info::InferFromAST, typename AST = ast::Node> |
| auto* Get(const AST* ast) const { |
| using T = sem::Info::GetResultType<SEM, AST>; |
| auto* sem = builder_->Sem().Get(ast); |
| if (TINT_UNLIKELY(!sem)) { |
| TINT_ICE(Resolver, builder_->Diagnostics()) |
| << "AST node '" << ast->TypeInfo().name << "' had no semantic info\n" |
| << "At: " << ast->source << "\n" |
| << "Pointer: " << ast; |
| } |
| return const_cast<T*>(As<T>(sem)); |
| } |
| |
| /// GetVal is a helper for obtaining the semantic sem::ValueExpression for the given AST node. |
| /// Raises an error diagnostic and returns `nullptr` if the semantic node is not a |
| /// sem::ValueExpression. |
| /// @param ast the ast node to get the sem for |
| /// @returns the sem node for @p ast |
| template <typename AST = ast::Node> |
| auto* GetVal(const AST* ast) const { |
| return AsValueExpression(Get(ast)); |
| } |
| |
| /// @param expr the semantic node |
| /// @returns nullptr if @p expr is nullptr, or @p expr cast to sem::ValueExpression if the cast |
| /// is successful, otherwise an error diagnostic is raised. |
| sem::ValueExpression* AsValueExpression(sem::Expression* expr) const { |
| if (TINT_LIKELY(expr)) { |
| if (auto* val_expr = expr->As<sem::ValueExpression>(); TINT_LIKELY(val_expr)) { |
| return val_expr; |
| } |
| ErrorExpectedValueExpr(expr); |
| } |
| return nullptr; |
| } |
| |
| /// @param expr the semantic node |
| /// @returns nullptr if @p expr is nullptr, or @p expr cast to type::Type if the cast is |
| /// successful, otherwise an error diagnostic is raised. |
| sem::TypeExpression* AsTypeExpression(sem::Expression* expr) const { |
| if (TINT_LIKELY(expr)) { |
| if (auto* ty_expr = expr->As<sem::TypeExpression>(); TINT_LIKELY(ty_expr)) { |
| return ty_expr; |
| } |
| ErrorUnexpectedExprKind(expr, "type"); |
| } |
| return nullptr; |
| } |
| |
| /// @param expr the semantic node |
| /// @returns nullptr if @p expr is nullptr, or @p expr cast to sem::Function if the cast is |
| /// successful, otherwise an error diagnostic is raised. |
| sem::FunctionExpression* AsFunctionExpression(sem::Expression* expr) const { |
| if (TINT_LIKELY(expr)) { |
| auto* fn_expr = expr->As<sem::FunctionExpression>(); |
| if (TINT_LIKELY(fn_expr)) { |
| return fn_expr; |
| } |
| ErrorUnexpectedExprKind(expr, "function"); |
| } |
| return nullptr; |
| } |
| |
| /// @param expr the semantic node |
| /// @returns nullptr if @p expr is nullptr, or @p expr cast to |
| /// sem::BuiltinEnumExpression<builtin::AddressSpace> if the cast is successful, otherwise an |
| /// error diagnostic is raised. |
| sem::BuiltinEnumExpression<builtin::AddressSpace>* AsAddressSpace(sem::Expression* expr) const { |
| if (TINT_LIKELY(expr)) { |
| auto* enum_expr = expr->As<sem::BuiltinEnumExpression<builtin::AddressSpace>>(); |
| if (TINT_LIKELY(enum_expr)) { |
| return enum_expr; |
| } |
| ErrorUnexpectedExprKind(expr, "address space"); |
| } |
| return nullptr; |
| } |
| |
| /// @param expr the semantic node |
| /// @returns nullptr if @p expr is nullptr, or @p expr cast to |
| /// sem::BuiltinEnumExpression<builtin::BuiltinValue> if the cast is successful, otherwise an |
| /// error diagnostic is raised. |
| sem::BuiltinEnumExpression<builtin::BuiltinValue>* AsBuiltinValue(sem::Expression* expr) const { |
| if (TINT_LIKELY(expr)) { |
| auto* enum_expr = expr->As<sem::BuiltinEnumExpression<builtin::BuiltinValue>>(); |
| if (TINT_LIKELY(enum_expr)) { |
| return enum_expr; |
| } |
| ErrorUnexpectedExprKind(expr, "builtin value"); |
| } |
| return nullptr; |
| } |
| |
| /// @param expr the semantic node |
| /// @returns nullptr if @p expr is nullptr, or @p expr cast to |
| /// sem::BuiltinEnumExpression<type::TexelFormat> if the cast is successful, otherwise an error |
| /// diagnostic is raised. |
| sem::BuiltinEnumExpression<builtin::TexelFormat>* AsTexelFormat(sem::Expression* expr) const { |
| if (TINT_LIKELY(expr)) { |
| auto* enum_expr = expr->As<sem::BuiltinEnumExpression<builtin::TexelFormat>>(); |
| if (TINT_LIKELY(enum_expr)) { |
| return enum_expr; |
| } |
| ErrorUnexpectedExprKind(expr, "texel format"); |
| } |
| return nullptr; |
| } |
| |
| /// @param expr the semantic node |
| /// @returns nullptr if @p expr is nullptr, or @p expr cast to |
| /// sem::BuiltinEnumExpression<builtin::Access> if the cast is successful, otherwise an error |
| /// diagnostic is raised. |
| sem::BuiltinEnumExpression<builtin::Access>* AsAccess(sem::Expression* expr) const { |
| if (TINT_LIKELY(expr)) { |
| auto* enum_expr = expr->As<sem::BuiltinEnumExpression<builtin::Access>>(); |
| if (TINT_LIKELY(enum_expr)) { |
| return enum_expr; |
| } |
| ErrorUnexpectedExprKind(expr, "access"); |
| } |
| return nullptr; |
| } |
| |
| /// @param expr the semantic node |
| /// @returns nullptr if @p expr is nullptr, or @p expr cast to |
| /// sem::BuiltinEnumExpression<builtin::InterpolationSampling> if the cast is successful, |
| /// otherwise an error diagnostic is raised. |
| sem::BuiltinEnumExpression<builtin::InterpolationSampling>* AsInterpolationSampling( |
| sem::Expression* expr) const { |
| if (TINT_LIKELY(expr)) { |
| auto* enum_expr = |
| expr->As<sem::BuiltinEnumExpression<builtin::InterpolationSampling>>(); |
| if (TINT_LIKELY(enum_expr)) { |
| return enum_expr; |
| } |
| ErrorUnexpectedExprKind(expr, "interpolation sampling"); |
| } |
| return nullptr; |
| } |
| |
| /// @param expr the semantic node |
| /// @returns nullptr if @p expr is nullptr, or @p expr cast to |
| /// sem::BuiltinEnumExpression<builtin::InterpolationType> if the cast is successful, otherwise |
| /// an error diagnostic is raised. |
| sem::BuiltinEnumExpression<builtin::InterpolationType>* AsInterpolationType( |
| sem::Expression* expr) const { |
| if (TINT_LIKELY(expr)) { |
| auto* enum_expr = expr->As<sem::BuiltinEnumExpression<builtin::InterpolationType>>(); |
| if (TINT_LIKELY(enum_expr)) { |
| return enum_expr; |
| } |
| ErrorUnexpectedExprKind(expr, "interpolation type"); |
| } |
| return nullptr; |
| } |
| |
| /// @returns the resolved type of the ast::Expression @p expr |
| /// @param expr the expression |
| type::Type* TypeOf(const ast::Expression* expr) const; |
| |
| /// @returns the type name of the given semantic type, unwrapping references. |
| /// @param ty the type to look up |
| std::string TypeNameOf(const type::Type* ty) const; |
| |
| /// @returns the type name of the given semantic type, without unwrapping references. |
| /// @param ty the type to look up |
| std::string RawTypeNameOf(const type::Type* ty) const; |
| |
| /// Raises an error diagnostic that the expression @p got was expected to be a |
| /// sem::ValueExpression, but the expression evaluated to something different. |
| /// @param expr the expression |
| void ErrorExpectedValueExpr(const sem::Expression* expr) const; |
| |
| /// Raises an error diagnostic that the expression @p got was not of the kind @p wanted. |
| /// @param expr the expression |
| /// @param wanted the expected expression kind |
| void ErrorUnexpectedExprKind(const sem::Expression* expr, std::string_view wanted) const; |
| |
| /// If @p node is a module-scope type, variable or function declaration, then appends a note |
| /// diagnostic where this declaration was declared, otherwise the function does nothing. |
| /// @param node the AST node. |
| void NoteDeclarationSource(const ast::Node* node) const; |
| |
| /// @param expr the expression to describe |
| /// @return a string that describes @p expr. Useful for diagnostics. |
| std::string Describe(const sem::Expression* expr) const; |
| |
| private: |
| /// Adds the given error message to the diagnostics |
| void AddError(const std::string& msg, const Source& source) const; |
| |
| /// Adds the given warning message to the diagnostics |
| void AddWarning(const std::string& msg, const Source& source) const; |
| |
| /// Adds the given note message to the diagnostics |
| void AddNote(const std::string& msg, const Source& source) const; |
| |
| ProgramBuilder* builder_; |
| }; |
| |
| } // namespace tint::resolver |
| |
| #endif // SRC_TINT_LANG_WGSL_RESOLVER_SEM_HELPER_H_ |