Add semantic::Statement

Add Stmt() accessor on all semantic::Expressions so the owning statement can be retrieved.

Change-Id: I5d584335a6d137fdeab0b8d74a161fcae9b46080
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/41545
Reviewed-by: James Price <jrprice@google.com>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Auto-Submit: Ben Clayton <bclayton@google.com>
This commit is contained in:
Ben Clayton 2021-02-16 18:45:45 +00:00 committed by Commit Bot service account
parent e7dab3c9ea
commit f97b9c9310
15 changed files with 258 additions and 70 deletions

View File

@ -391,6 +391,7 @@ source_set("libtint_core_src") {
"src/semantic/sem_intrinsic.cc",
"src/semantic/sem_member_accessor_expression.cc",
"src/semantic/sem_node.cc",
"src/semantic/sem_statement.cc",
"src/semantic/sem_variable.cc",
"src/semantic/type_mappings.h",
"src/source.cc",

View File

@ -205,6 +205,7 @@ set(TINT_LIB_SRCS
semantic/sem_info.cc
semantic/sem_intrinsic.cc
semantic/sem_node.cc
semantic/sem_statement.cc
semantic/sem_variable.cc
semantic/type_mappings.h
source.cc

View File

@ -27,7 +27,8 @@ class Call : public Castable<Call, Expression> {
public:
/// Constructor
/// @param target the call target
explicit Call(const CallTarget* target);
/// @param statement the statement that owns this expression
explicit Call(const CallTarget* target, Statement* statement);
/// Destructor
~Call() override;

View File

@ -20,10 +20,11 @@
namespace tint {
// Forward declarations
namespace semantic {
class Statement;
} // namespace semantic
namespace type {
class Type;
} // namespace type
namespace semantic {
@ -33,13 +34,18 @@ class Expression : public Castable<Expression, Node> {
public:
/// Constructor
/// @param type the resolved type of the expression
explicit Expression(type::Type* type);
/// @param statement the statement that owns this expression
explicit Expression(type::Type* type, Statement* statement);
/// @return the resolved type of the expression
type::Type* Type() const { return type_; }
/// @return the statement that owns this expression
Statement* Stmt() const { return statement_; }
private:
type::Type* const type_;
Statement* const statement_;
};
} // namespace semantic

View File

@ -27,8 +27,11 @@ class MemberAccessorExpression
public:
/// Constructor
/// @param type the resolved type of the expression
/// @param statement the statement that owns this expression
/// @param is_swizzle true if this member access is for a vector swizzle
MemberAccessorExpression(type::Type* type, bool is_swizzle);
MemberAccessorExpression(type::Type* type,
Statement* statement,
bool is_swizzle);
/// @return true if this member access is for a vector swizzle
bool IsSwizzle() const { return is_swizzle_; }

View File

@ -19,8 +19,8 @@ TINT_INSTANTIATE_CLASS_ID(tint::semantic::Call);
namespace tint {
namespace semantic {
Call::Call(const CallTarget* target)
: Base(target->ReturnType()), target_(target) {}
Call::Call(const CallTarget* target, Statement* statement)
: Base(target->ReturnType(), statement), target_(target) {}
Call::~Call() = default;

View File

@ -21,7 +21,8 @@ TINT_INSTANTIATE_CLASS_ID(tint::semantic::Expression);
namespace tint {
namespace semantic {
Expression::Expression(type::Type* type) : type_(type->UnwrapIfNeeded()) {}
Expression::Expression(type::Type* type, Statement* statement)
: type_(type->UnwrapIfNeeded()), statement_(statement) {}
} // namespace semantic
} // namespace tint

View File

@ -20,8 +20,9 @@ namespace tint {
namespace semantic {
MemberAccessorExpression::MemberAccessorExpression(type::Type* type,
Statement* statement,
bool is_swizzle)
: Base(type), is_swizzle_(is_swizzle) {}
: Base(type, statement), is_swizzle_(is_swizzle) {}
} // namespace semantic
} // namespace tint

View File

@ -0,0 +1,27 @@
// Copyright 2021 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/semantic/statement.h"
#include "src/type/type.h"
TINT_INSTANTIATE_CLASS_ID(tint::semantic::Statement);
namespace tint {
namespace semantic {
Statement::Statement(ast::Statement* declaration) : declaration_(declaration) {}
} // namespace semantic
} // namespace tint

46
src/semantic/statement.h Normal file
View File

@ -0,0 +1,46 @@
// Copyright 2021 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_SEMANTIC_STATEMENT_H_
#define SRC_SEMANTIC_STATEMENT_H_
#include "src/semantic/node.h"
namespace tint {
// Forward declarations
namespace ast {
class Statement;
} // namespace ast
namespace semantic {
/// Statement holds the semantic information for a statement.
class Statement : public Castable<Statement, Node> {
public:
/// Constructor
/// @param declaration the AST node for this statement
explicit Statement(ast::Statement* declaration);
/// @return the AST node for this statement
ast::Statement* Declaration() const { return declaration_; }
private:
ast::Statement* const declaration_;
};
} // namespace semantic
} // namespace tint
#endif // SRC_SEMANTIC_STATEMENT_H_

View File

@ -47,6 +47,7 @@
#include "src/semantic/function.h"
#include "src/semantic/intrinsic.h"
#include "src/semantic/member_accessor_expression.h"
#include "src/semantic/statement.h"
#include "src/semantic/variable.h"
#include "src/type/array_type.h"
#include "src/type/bool_type.h"
@ -69,6 +70,23 @@ namespace {
using IntrinsicType = tint::semantic::IntrinsicType;
// Helper class that temporarily assigns a value to a reference for the scope of
// the object. Once the ScopedAssignment is destructed, the original value is
// restored.
template <typename T>
class ScopedAssignment {
public:
ScopedAssignment(T& ref, T val) : ref_(ref) {
old_value_ = ref;
ref = val;
}
~ScopedAssignment() { ref_ = old_value_; }
private:
T& ref_;
T old_value_;
};
} // namespace
TypeDeterminer::TypeDeterminer(ProgramBuilder* builder)
@ -171,9 +189,11 @@ bool TypeDeterminer::DetermineFunctions(const ast::FunctionList& funcs) {
}
bool TypeDeterminer::DetermineFunction(ast::Function* func) {
current_function_ = function_infos_.Create<FunctionInfo>(func);
symbol_to_function_[func->symbol()] = current_function_;
function_to_info_.emplace(func, current_function_);
auto* func_info = function_infos_.Create<FunctionInfo>(func);
symbol_to_function_[func->symbol()] = func_info;
function_to_info_.emplace(func, func_info);
ScopedAssignment<FunctionInfo*> sa(current_function_, func_info);
variable_stack_.push_scope();
for (auto* param : func->params()) {
@ -185,8 +205,6 @@ bool TypeDeterminer::DetermineFunction(ast::Function* func) {
}
variable_stack_.pop_scope();
current_function_ = nullptr;
return true;
}
@ -234,6 +252,10 @@ bool TypeDeterminer::DetermineVariableStorageClass(ast::Statement* stmt) {
}
bool TypeDeterminer::DetermineResultType(ast::Statement* stmt) {
auto* sem_statement = builder_->create<semantic::Statement>(stmt);
ScopedAssignment<semantic::Statement*> sa(current_statement_, sem_statement);
if (auto* a = stmt->As<ast::AssignmentStatement>()) {
return DetermineResultType(a->lhs()) && DetermineResultType(a->rhs());
}
@ -451,7 +473,8 @@ bool TypeDeterminer::DetermineCall(ast::CallExpression* call) {
}
auto* function = iter->second;
function_calls_.emplace(call, function);
function_calls_.emplace(call,
FunctionCallInfo{function, current_statement_});
SetType(call, function->declaration->return_type());
}
@ -501,12 +524,14 @@ bool TypeDeterminer::DetermineIntrinsicCall(
}
auto* intrinsic = builder_->create<semantic::Intrinsic>(intrinsic_type,
ret_ty, parameters);
builder_->Sem().Add(call, builder_->create<semantic::Call>(intrinsic));
builder_->Sem().Add(
call, builder_->create<semantic::Call>(intrinsic, current_statement_));
SetType(call, ret_ty);
return false;
}
builder_->Sem().Add(call, builder_->create<semantic::Call>(result.intrinsic));
builder_->Sem().Add(call, builder_->create<semantic::Call>(
result.intrinsic, current_statement_));
SetType(call, result.intrinsic->ReturnType());
return true;
}
@ -791,9 +816,9 @@ bool TypeDeterminer::DetermineMemberAccessor(
return false;
}
builder_->Sem().Add(
expr,
builder_->create<semantic::MemberAccessorExpression>(ret, is_swizzle));
builder_->Sem().Add(expr,
builder_->create<semantic::MemberAccessorExpression>(
ret, current_statement_, is_swizzle));
SetType(expr, ret);
return true;
@ -890,16 +915,16 @@ TypeDeterminer::VariableInfo* TypeDeterminer::CreateVariableInfo(
}
type::Type* TypeDeterminer::TypeOf(ast::Expression* expr) {
auto it = expr_types_.find(expr);
if (it != expr_types_.end()) {
return it->second;
auto it = expr_info_.find(expr);
if (it != expr_info_.end()) {
return it->second.type;
}
return nullptr;
}
void TypeDeterminer::SetType(ast::Expression* expr, type::Type* type) {
assert(expr_types_.count(expr) == 0);
expr_types_.emplace(expr, type);
assert(expr_info_.count(expr) == 0);
expr_info_.emplace(expr, ExpressionInfo{type, current_statement_});
}
void TypeDeterminer::CreateSemanticNodes() const {
@ -938,20 +963,21 @@ void TypeDeterminer::CreateSemanticNodes() const {
// Create semantic nodes for all ast::CallExpressions
for (auto it : function_calls_) {
auto* call = it.first;
auto* func_info = it.second;
auto* sem_func = func_info_to_sem_func.at(func_info);
sem.Add(call, builder_->create<semantic::Call>(sem_func));
auto info = it.second;
auto* sem_func = func_info_to_sem_func.at(info.function);
sem.Add(call, builder_->create<semantic::Call>(sem_func, info.statement));
}
// Create semantic nodes for all remaining expression types
for (auto it : expr_types_) {
for (auto it : expr_info_) {
auto* expr = it.first;
auto* type = it.second;
auto& info = it.second;
if (sem.Get(expr)) {
// Expression has already been assigned a semantic node
continue;
}
sem.Add(expr, builder_->create<semantic::Expression>(type));
sem.Add(expr,
builder_->create<semantic::Expression>(info.type, info.statement));
}
}

View File

@ -30,8 +30,9 @@
#include "src/type/storage_texture_type.h"
namespace tint {
namespace ast {
// Forward declarations
namespace ast {
class ArrayAccessorExpression;
class BinaryExpression;
class BitcastExpression;
@ -42,8 +43,10 @@ class IdentifierExpression;
class MemberAccessorExpression;
class UnaryOpExpression;
class Variable;
} // namespace ast
namespace semantic {
class Statement;
} // namespace semantic
/// Determines types for all items in the given tint program
class TypeDeterminer {
@ -95,7 +98,7 @@ class TypeDeterminer {
std::unordered_set<T> set;
};
/// Structure holding semantic information about a function.
/// Structure holding semantic information about a variable.
/// Used to build the semantic::Function nodes at the end of resolving.
struct VariableInfo {
explicit VariableInfo(ast::Variable* decl);
@ -117,6 +120,21 @@ class TypeDeterminer {
UniqueVector<Symbol> ancestor_entry_points;
};
/// Structure holding semantic information about an expression.
/// Used to build the semantic::Expression nodes at the end of resolving.
struct ExpressionInfo {
type::Type* type;
semantic::Statement* statement;
};
/// Structure holding semantic information about a call expression to an
/// ast::Function.
/// Used to build the semantic::Call nodes at the end of resolving.
struct FunctionCallInfo {
FunctionInfo* function;
semantic::Statement* statement;
};
/// Determines type information for the program, without creating final the
/// semantic nodes.
/// @returns true if the determination was successful
@ -203,9 +221,10 @@ class TypeDeterminer {
std::unordered_map<Symbol, FunctionInfo*> symbol_to_function_;
std::unordered_map<ast::Function*, FunctionInfo*> function_to_info_;
std::unordered_map<ast::Variable*, VariableInfo*> variable_to_info_;
std::unordered_map<ast::CallExpression*, FunctionInfo*> function_calls_;
std::unordered_map<ast::Expression*, type::Type*> expr_types_;
std::unordered_map<ast::CallExpression*, FunctionCallInfo> function_calls_;
std::unordered_map<ast::Expression*, ExpressionInfo> expr_info_;
FunctionInfo* current_function_ = nullptr;
semantic::Statement* current_statement_ = nullptr;
BlockAllocator<VariableInfo> variable_infos_;
BlockAllocator<FunctionInfo> function_infos_;

View File

@ -55,6 +55,7 @@
#include "src/semantic/call.h"
#include "src/semantic/expression.h"
#include "src/semantic/function.h"
#include "src/semantic/statement.h"
#include "src/semantic/variable.h"
#include "src/type/access_control_type.h"
#include "src/type/alias_type.h"
@ -105,6 +106,11 @@ class TypeDeterminerHelper : public ProgramBuilder {
TypeDeterminer* td() const { return td_.get(); }
ast::Statement* StmtOf(ast::Expression* expr) {
auto* sem_stmt = Sem().Get(expr)->Stmt();
return sem_stmt ? sem_stmt->Declaration() : nullptr;
}
private:
std::unique_ptr<TypeDeterminer> td_;
};
@ -149,14 +155,17 @@ TEST_F(TypeDeterminerTest, Stmt_Assign) {
EXPECT_TRUE(TypeOf(lhs)->Is<type::I32>());
EXPECT_TRUE(TypeOf(rhs)->Is<type::F32>());
EXPECT_EQ(StmtOf(lhs), assign);
EXPECT_EQ(StmtOf(rhs), assign);
}
TEST_F(TypeDeterminerTest, Stmt_Case) {
auto* lhs = Expr(2);
auto* rhs = Expr(2.3f);
auto* assign = create<ast::AssignmentStatement>(lhs, rhs);
auto* body = create<ast::BlockStatement>(ast::StatementList{
create<ast::AssignmentStatement>(lhs, rhs),
assign,
});
ast::CaseSelectorList lit;
lit.push_back(create<ast::SintLiteral>(ty.i32(), 3));
@ -169,14 +178,17 @@ TEST_F(TypeDeterminerTest, Stmt_Case) {
ASSERT_NE(TypeOf(rhs), nullptr);
EXPECT_TRUE(TypeOf(lhs)->Is<type::I32>());
EXPECT_TRUE(TypeOf(rhs)->Is<type::F32>());
EXPECT_EQ(StmtOf(lhs), assign);
EXPECT_EQ(StmtOf(rhs), assign);
}
TEST_F(TypeDeterminerTest, Stmt_Block) {
auto* lhs = Expr(2);
auto* rhs = Expr(2.3f);
auto* assign = create<ast::AssignmentStatement>(lhs, rhs);
auto* block = create<ast::BlockStatement>(ast::StatementList{
create<ast::AssignmentStatement>(lhs, rhs),
assign,
});
WrapInFunction(block);
@ -186,16 +198,20 @@ TEST_F(TypeDeterminerTest, Stmt_Block) {
ASSERT_NE(TypeOf(rhs), nullptr);
EXPECT_TRUE(TypeOf(lhs)->Is<type::I32>());
EXPECT_TRUE(TypeOf(rhs)->Is<type::F32>());
EXPECT_EQ(StmtOf(lhs), assign);
EXPECT_EQ(StmtOf(rhs), assign);
}
TEST_F(TypeDeterminerTest, Stmt_Else) {
auto* lhs = Expr(2);
auto* rhs = Expr(2.3f);
auto* assign = create<ast::AssignmentStatement>(lhs, rhs);
auto* body = create<ast::BlockStatement>(ast::StatementList{
create<ast::AssignmentStatement>(lhs, rhs),
assign,
});
auto* stmt = create<ast::ElseStatement>(Expr(3), body);
auto* cond = Expr(3);
auto* stmt = create<ast::ElseStatement>(cond, body);
WrapInFunction(stmt);
EXPECT_TRUE(td()->Determine()) << td()->error();
@ -206,6 +222,9 @@ TEST_F(TypeDeterminerTest, Stmt_Else) {
EXPECT_TRUE(TypeOf(stmt->condition())->Is<type::I32>());
EXPECT_TRUE(TypeOf(lhs)->Is<type::I32>());
EXPECT_TRUE(TypeOf(rhs)->Is<type::F32>());
EXPECT_EQ(StmtOf(lhs), assign);
EXPECT_EQ(StmtOf(rhs), assign);
EXPECT_EQ(StmtOf(cond), stmt);
}
TEST_F(TypeDeterminerTest, Stmt_If) {
@ -216,16 +235,17 @@ TEST_F(TypeDeterminerTest, Stmt_If) {
create<ast::AssignmentStatement>(else_lhs, else_rhs),
});
auto* else_stmt = create<ast::ElseStatement>(Expr(3), else_body);
auto* else_cond = Expr(3);
auto* else_stmt = create<ast::ElseStatement>(else_cond, else_body);
auto* lhs = Expr(2);
auto* rhs = Expr(2.3f);
auto* body = create<ast::BlockStatement>(ast::StatementList{
create<ast::AssignmentStatement>(lhs, rhs),
});
auto* stmt = create<ast::IfStatement>(Expr(3), body,
ast::ElseStatementList{else_stmt});
auto* assign = create<ast::AssignmentStatement>(lhs, rhs);
auto* body = create<ast::BlockStatement>(ast::StatementList{assign});
auto* cond = Expr(3);
auto* stmt =
create<ast::IfStatement>(cond, body, ast::ElseStatementList{else_stmt});
WrapInFunction(stmt);
EXPECT_TRUE(td()->Determine()) << td()->error();
@ -240,6 +260,10 @@ TEST_F(TypeDeterminerTest, Stmt_If) {
EXPECT_TRUE(TypeOf(else_rhs)->Is<type::F32>());
EXPECT_TRUE(TypeOf(lhs)->Is<type::I32>());
EXPECT_TRUE(TypeOf(rhs)->Is<type::F32>());
EXPECT_EQ(StmtOf(lhs), assign);
EXPECT_EQ(StmtOf(rhs), assign);
EXPECT_EQ(StmtOf(cond), stmt);
EXPECT_EQ(StmtOf(else_cond), else_stmt);
}
TEST_F(TypeDeterminerTest, Stmt_Loop) {
@ -332,6 +356,7 @@ TEST_F(TypeDeterminerTest, Stmt_Call) {
ASSERT_NE(TypeOf(expr), nullptr);
EXPECT_TRUE(TypeOf(expr)->Is<type::F32>());
EXPECT_EQ(StmtOf(expr), call);
}
TEST_F(TypeDeterminerTest, Stmt_Call_undeclared) {
@ -376,14 +401,15 @@ TEST_F(TypeDeterminerTest, Stmt_VariableDecl) {
}
TEST_F(TypeDeterminerTest, Stmt_VariableDecl_ModuleScope) {
auto* var = Global("my_var", ast::StorageClass::kNone, ty.i32(), Expr(2),
ast::VariableDecorationList{});
auto* init = var->constructor();
auto* init = Expr(2);
Global("my_var", ast::StorageClass::kNone, ty.i32(), init,
ast::VariableDecorationList{});
EXPECT_TRUE(td()->Determine()) << td()->error();
ASSERT_NE(TypeOf(init), nullptr);
EXPECT_TRUE(TypeOf(init)->Is<type::I32>());
EXPECT_EQ(StmtOf(init), nullptr);
}
TEST_F(TypeDeterminerTest, Stmt_VariableDecl_OuterScopeAfterInnerScope) {
@ -438,6 +464,10 @@ TEST_F(TypeDeterminerTest, Stmt_VariableDecl_OuterScopeAfterInnerScope) {
EXPECT_TRUE(TypeOf(bar_i32_init)->UnwrapAll()->Is<type::I32>());
ASSERT_NE(TypeOf(bar_f32_init), nullptr);
EXPECT_TRUE(TypeOf(bar_f32_init)->UnwrapAll()->Is<type::F32>());
EXPECT_EQ(StmtOf(foo_i32_init), foo_i32_decl);
EXPECT_EQ(StmtOf(bar_i32_init), bar_i32_decl);
EXPECT_EQ(StmtOf(foo_f32_init), foo_f32_decl);
EXPECT_EQ(StmtOf(bar_f32_init), bar_f32_decl);
}
TEST_F(TypeDeterminerTest, Stmt_VariableDecl_ModuleScopeAfterFunctionScope) {
@ -480,6 +510,9 @@ TEST_F(TypeDeterminerTest, Stmt_VariableDecl_ModuleScopeAfterFunctionScope) {
EXPECT_TRUE(TypeOf(fn_i32_init)->Is<type::I32>());
ASSERT_NE(TypeOf(fn_f32_init), nullptr);
EXPECT_TRUE(TypeOf(fn_f32_init)->UnwrapAll()->Is<type::F32>());
EXPECT_EQ(StmtOf(fn_i32_init), fn_i32_decl);
EXPECT_EQ(StmtOf(mod_init), nullptr);
EXPECT_EQ(StmtOf(fn_f32_init), fn_f32_decl);
}
TEST_F(TypeDeterminerTest, Expr_Error_Unknown) {
@ -708,59 +741,77 @@ TEST_F(TypeDeterminerTest, Expr_Identifier_GlobalConstant) {
}
TEST_F(TypeDeterminerTest, Expr_Identifier_FunctionVariable_Const) {
auto* my_var = Expr("my_var");
auto* my_var_a = Expr("my_var");
auto* my_var_b = Expr("my_var");
auto* var = Const("my_var", ast::StorageClass::kNone, ty.f32());
auto* assign = create<ast::AssignmentStatement>(my_var_a, my_var_b);
Func("my_func", ast::VariableList{}, ty.f32(),
ast::StatementList{
create<ast::VariableDeclStatement>(var),
create<ast::AssignmentStatement>(my_var, Expr("my_var")),
assign,
},
ast::FunctionDecorationList{});
EXPECT_TRUE(td()->Determine()) << td()->error();
ASSERT_NE(TypeOf(my_var), nullptr);
EXPECT_TRUE(TypeOf(my_var)->Is<type::F32>());
ASSERT_NE(TypeOf(my_var_a), nullptr);
EXPECT_TRUE(TypeOf(my_var_a)->Is<type::F32>());
EXPECT_EQ(StmtOf(my_var_a), assign);
ASSERT_NE(TypeOf(my_var_b), nullptr);
EXPECT_TRUE(TypeOf(my_var_b)->Is<type::F32>());
EXPECT_EQ(StmtOf(my_var_b), assign);
}
TEST_F(TypeDeterminerTest, Expr_Identifier_FunctionVariable) {
auto* my_var = Expr("my_var");
auto* my_var_a = Expr("my_var");
auto* my_var_b = Expr("my_var");
auto* assign = create<ast::AssignmentStatement>(my_var_a, my_var_b);
Func("my_func", ast::VariableList{}, ty.f32(),
ast::StatementList{
create<ast::VariableDeclStatement>(
Var("my_var", ast::StorageClass::kNone, ty.f32())),
create<ast::AssignmentStatement>(my_var, Expr("my_var")),
assign,
},
ast::FunctionDecorationList{});
EXPECT_TRUE(td()->Determine()) << td()->error();
ASSERT_NE(TypeOf(my_var), nullptr);
EXPECT_TRUE(TypeOf(my_var)->Is<type::Pointer>());
EXPECT_TRUE(TypeOf(my_var)->As<type::Pointer>()->type()->Is<type::F32>());
ASSERT_NE(TypeOf(my_var_a), nullptr);
EXPECT_TRUE(TypeOf(my_var_a)->Is<type::Pointer>());
EXPECT_TRUE(TypeOf(my_var_a)->As<type::Pointer>()->type()->Is<type::F32>());
EXPECT_EQ(StmtOf(my_var_a), assign);
ASSERT_NE(TypeOf(my_var_b), nullptr);
EXPECT_TRUE(TypeOf(my_var_b)->Is<type::Pointer>());
EXPECT_TRUE(TypeOf(my_var_b)->As<type::Pointer>()->type()->Is<type::F32>());
EXPECT_EQ(StmtOf(my_var_b), assign);
}
TEST_F(TypeDeterminerTest, Expr_Identifier_Function_Ptr) {
type::Pointer ptr(ty.f32(), ast::StorageClass::kFunction);
auto* my_var = Expr("my_var");
auto* my_var_a = Expr("my_var");
auto* my_var_b = Expr("my_var");
auto* assign = create<ast::AssignmentStatement>(my_var_a, my_var_b);
Func("my_func", ast::VariableList{}, ty.f32(),
ast::StatementList{
create<ast::VariableDeclStatement>(
Var("my_var", ast::StorageClass::kNone, &ptr)),
create<ast::AssignmentStatement>(my_var, Expr("my_var")),
Var("my_var", ast::StorageClass::kNone,
ty.pointer<f32>(ast::StorageClass::kFunction))),
assign,
},
ast::FunctionDecorationList{});
EXPECT_TRUE(td()->Determine()) << td()->error();
ASSERT_NE(TypeOf(my_var), nullptr);
EXPECT_TRUE(TypeOf(my_var)->Is<type::Pointer>());
EXPECT_TRUE(TypeOf(my_var)->As<type::Pointer>()->type()->Is<type::F32>());
ASSERT_NE(TypeOf(my_var_a), nullptr);
EXPECT_TRUE(TypeOf(my_var_a)->Is<type::Pointer>());
EXPECT_TRUE(TypeOf(my_var_a)->As<type::Pointer>()->type()->Is<type::F32>());
EXPECT_EQ(StmtOf(my_var_a), assign);
ASSERT_NE(TypeOf(my_var_b), nullptr);
EXPECT_TRUE(TypeOf(my_var_b)->Is<type::Pointer>());
EXPECT_TRUE(TypeOf(my_var_b)->As<type::Pointer>()->type()->Is<type::F32>());
EXPECT_EQ(StmtOf(my_var_b), assign);
}
TEST_F(TypeDeterminerTest, Expr_Call_Function) {

View File

@ -52,9 +52,12 @@ ast::TypeConstructorExpression* AppendVector(ProgramBuilder* b,
packed_el_ty = vector_sem->Type();
}
auto* statement = vector_sem->Stmt();
// Cast scalar to the vector element type
auto* scalar_cast = b->Construct(packed_el_ty, scalar);
b->Sem().Add(scalar_cast, b->create<semantic::Expression>(packed_el_ty));
b->Sem().Add(scalar_cast,
b->create<semantic::Expression>(packed_el_ty, statement));
auto* packed_ty = b->create<type::Vector>(packed_el_ty, packed_size);
@ -73,7 +76,8 @@ ast::TypeConstructorExpression* AppendVector(ProgramBuilder* b,
}
auto* constructor = b->Construct(packed_ty, std::move(packed));
b->Sem().Add(constructor, b->create<semantic::Expression>(packed_ty));
b->Sem().Add(constructor,
b->create<semantic::Expression>(packed_ty, statement));
return constructor;
}

View File

@ -984,7 +984,8 @@ bool GeneratorImpl::EmitTextureCall(std::ostream& pre,
auto emit_vector_appended_with_i32_zero = [&](tint::ast::Expression* vector) {
auto* i32 = builder_.create<type::I32>();
auto* zero = builder_.Expr(0);
builder_.Sem().Add(zero, builder_.create<semantic::Expression>(i32));
auto* stmt = builder_.Sem().Get(vector)->Stmt();
builder_.Sem().Add(zero, builder_.create<semantic::Expression>(i32, stmt));
auto* packed = AppendVector(&builder_, vector, zero);
return EmitExpression(pre, out, packed);
};