| // 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_RESOLVER_SEM_HELPER_H_ | 
 | #define SRC_TINT_RESOLVER_SEM_HELPER_H_ | 
 |  | 
 | #include <string> | 
 |  | 
 | #include "src/tint/builtin/builtin_value.h" | 
 | #include "src/tint/builtin/interpolation_sampling.h" | 
 | #include "src/tint/builtin/interpolation_type.h" | 
 | #include "src/tint/diagnostic/diagnostic.h" | 
 | #include "src/tint/program_builder.h" | 
 | #include "src/tint/resolver/dependency_graph.h" | 
 | #include "src/tint/sem/builtin_enum_expression.h" | 
 | #include "src/tint/sem/function_expression.h" | 
 | #include "src/tint/sem/type_expression.h" | 
 | #include "src/tint/utils/map.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_RESOLVER_SEM_HELPER_H_ |