validation: fix arrayAcceor/memberAccessor error msg and add unit-tests
Bug: tint:1172
Change-Id: Icbc920dbc6adc9a5c78b8ae7d700b527a4fa48f7
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/64100
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Sarah Mashayekhi <sarahmashay@google.com>
diff --git a/src/resolver/array_accessor_test.cc b/src/resolver/array_accessor_test.cc
index 21883cd..a565d0c 100644
--- a/src/resolver/array_accessor_test.cc
+++ b/src/resolver/array_accessor_test.cc
@@ -257,6 +257,59 @@
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
+TEST_F(ResolverArrayAccessorTest, EXpr_Deref_FuncGoodParent) {
+ // fn func(p: ptr<function, vec4<f32>>) -> f32 {
+ // let idx: u32 = u32();
+ // let x: f32 = (*p)[idx];
+ // return x;
+ // }
+ auto* p =
+ Param("p", ty.pointer(ty.vec4<f32>(), ast::StorageClass::kFunction));
+ auto* idx = Const("idx", ty.u32(), Construct(ty.u32()));
+ auto* star_p = Deref(p);
+ auto* accessor_expr = IndexAccessor(Source{{12, 34}}, star_p, idx);
+ auto* x = Var("x", ty.f32(), accessor_expr);
+ Func("func", {p}, ty.f32(), {Decl(idx), Decl(x), Return(x)});
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+}
+
+TEST_F(ResolverArrayAccessorTest, EXpr_Deref_FuncBadParent) {
+ // fn func(p: ptr<function, vec4<f32>>) -> f32 {
+ // let idx: u32 = u32();
+ // let x: f32 = *p[idx];
+ // return x;
+ // }
+ auto* p =
+ Param("p", ty.pointer(ty.vec4<f32>(), ast::StorageClass::kFunction));
+ auto* idx = Const("idx", ty.u32(), Construct(ty.u32()));
+ auto* accessor_expr = IndexAccessor(Source{{12, 34}}, p, idx);
+ auto* star_p = Deref(accessor_expr);
+ auto* x = Var("x", ty.f32(), star_p);
+ Func("func", {p}, ty.f32(), {Decl(idx), Decl(x), Return(x)});
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(),
+ "12:34 error: cannot index type 'ptr<function, vec4<f32>>'");
+}
+
+TEST_F(ResolverArrayAccessorTest, Exr_Deref_BadParent) {
+ // var param: vec4<f32>
+ // let x: f32 = *(¶m)[0];
+ auto* param = Var("param", ty.vec4<f32>());
+ auto* idx = Var("idx", ty.u32(), Construct(ty.u32()));
+ auto* addressOf_expr = AddressOf(param);
+ auto* accessor_expr = IndexAccessor(Source{{12, 34}}, addressOf_expr, idx);
+ auto* star_p = Deref(accessor_expr);
+ auto* x = Var("x", ty.f32(), star_p);
+ WrapInFunction(param, idx, x);
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(
+ r()->error(),
+ "12:34 error: cannot index type 'ptr<function, vec4<f32>, read_write>'");
+}
+
} // namespace
} // namespace resolver
} // namespace tint
diff --git a/src/resolver/resolver.cc b/src/resolver/resolver.cc
index 4abe071..1b26b60 100644
--- a/src/resolver/resolver.cc
+++ b/src/resolver/resolver.cc
@@ -2348,8 +2348,7 @@
} else if (auto* mat = parent_type->As<sem::Matrix>()) {
ret = builder_->create<sem::Vector>(mat->type(), mat->rows());
} else {
- AddError("invalid parent type (" + parent_type->type_name() +
- ") in array accessor",
+ AddError("cannot index type '" + TypeNameOf(expr->array()) + "'",
expr->source());
return false;
}
@@ -3126,9 +3125,10 @@
expr, builder_->create<sem::Swizzle>(expr, ret, current_statement_,
std::move(swizzle)));
} else {
- AddError("invalid use of member accessor on a non-vector/non-struct " +
- TypeNameOf(expr->structure()),
- expr->source());
+ AddError(
+ "invalid member accessor expression. Expected vector or struct, got '" +
+ TypeNameOf(expr->structure()) + "'",
+ expr->structure()->source());
return false;
}
diff --git a/src/resolver/validation_test.cc b/src/resolver/validation_test.cc
index aea2321..06cc2bb 100644
--- a/src/resolver/validation_test.cc
+++ b/src/resolver/validation_test.cc
@@ -451,6 +451,64 @@
EXPECT_EQ(r()->error(), "3:3 error: invalid vector swizzle member");
}
+TEST_F(ResolverValidationTest, Expr_MemberAccessor_BadParent) {
+ // var param: vec4<f32>
+ // let ret: f32 = *(¶m).x;
+ auto* param = Var("param", ty.vec4<f32>());
+ auto* x = create<ast::IdentifierExpression>(
+ Source{{Source::Location{3, 3}, Source::Location{3, 8}}},
+ Symbols().Register("x"));
+
+ auto* addressOf_expr = AddressOf(Source{{12, 34}}, param);
+ auto* accessor_expr = MemberAccessor(addressOf_expr, x);
+ auto* star_p = Deref(accessor_expr);
+ auto* ret = Var("r", ty.f32(), star_p);
+ WrapInFunction(Decl(param), Decl(ret));
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(),
+ "12:34 error: invalid member accessor expression. Expected vector "
+ "or struct, got 'ptr<function, vec4<f32>, read_write>'");
+}
+
+TEST_F(ResolverValidationTest, EXpr_MemberAccessor_FuncGoodParent) {
+ // fn func(p: ptr<function, vec4<f32>>) -> f32 {
+ // let x: f32 = (*p).z;
+ // return x;
+ // }
+ auto* p =
+ Param("p", ty.pointer(ty.vec4<f32>(), ast::StorageClass::kFunction));
+ auto* star_p = Deref(p);
+ auto* z = create<ast::IdentifierExpression>(
+ Source{{Source::Location{3, 3}, Source::Location{3, 8}}},
+ Symbols().Register("z"));
+ auto* accessor_expr = MemberAccessor(star_p, z);
+ auto* x = Var("x", ty.f32(), accessor_expr);
+ Func("func", {p}, ty.f32(), {Decl(x), Return(x)});
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+}
+
+TEST_F(ResolverValidationTest, EXpr_MemberAccessor_FuncBadParent) {
+ // fn func(p: ptr<function, vec4<f32>>) -> f32 {
+ // let x: f32 = *p.z;
+ // return x;
+ // }
+ auto* p =
+ Param("p", ty.pointer(ty.vec4<f32>(), ast::StorageClass::kFunction));
+ auto* z = create<ast::IdentifierExpression>(
+ Source{{Source::Location{3, 3}, Source::Location{3, 8}}},
+ Symbols().Register("z"));
+ auto* accessor_expr = MemberAccessor(p, z);
+ auto* star_p = Deref(accessor_expr);
+ auto* x = Var("x", ty.f32(), star_p);
+ Func("func", {p}, ty.f32(), {Decl(x), Return(x)});
+
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(),
+ "error: invalid member accessor expression. Expected vector or "
+ "struct, got 'ptr<function, vec4<f32>>'");
+}
+
TEST_F(ResolverValidationTest,
Stmt_Loop_ContinueInLoopBodyBeforeDeclAndAfterDecl_UsageInContinuing) {
// loop {