1 // Copyright 2021 The Tint Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "src/resolver/resolver.h"
16
17 #include "gmock/gmock.h"
18 #include "src/ast/call_statement.h"
19 #include "src/resolver/resolver_test_helper.h"
20
21 namespace tint {
22 namespace resolver {
23 namespace {
24
25 using ResolverCallValidationTest = ResolverTest;
26
TEST_F(ResolverCallValidationTest, TooFewArgs)27 TEST_F(ResolverCallValidationTest, TooFewArgs) {
28 Func("foo", {Param(Sym(), ty.i32()), Param(Sym(), ty.f32())}, ty.void_(),
29 {Return()});
30 auto* call = Call(Source{{12, 34}}, "foo", 1);
31 WrapInFunction(call);
32
33 EXPECT_FALSE(r()->Resolve());
34 EXPECT_EQ(
35 r()->error(),
36 "12:34 error: too few arguments in call to 'foo', expected 2, got 1");
37 }
38
TEST_F(ResolverCallValidationTest, TooManyArgs)39 TEST_F(ResolverCallValidationTest, TooManyArgs) {
40 Func("foo", {Param(Sym(), ty.i32()), Param(Sym(), ty.f32())}, ty.void_(),
41 {Return()});
42 auto* call = Call(Source{{12, 34}}, "foo", 1, 1.0f, 1.0f);
43 WrapInFunction(call);
44
45 EXPECT_FALSE(r()->Resolve());
46 EXPECT_EQ(
47 r()->error(),
48 "12:34 error: too many arguments in call to 'foo', expected 2, got 3");
49 }
50
TEST_F(ResolverCallValidationTest, MismatchedArgs)51 TEST_F(ResolverCallValidationTest, MismatchedArgs) {
52 Func("foo", {Param(Sym(), ty.i32()), Param(Sym(), ty.f32())}, ty.void_(),
53 {Return()});
54 auto* call = Call("foo", Expr(Source{{12, 34}}, true), 1.0f);
55 WrapInFunction(call);
56
57 EXPECT_FALSE(r()->Resolve());
58 EXPECT_EQ(r()->error(),
59 "12:34 error: type mismatch for argument 1 in call to 'foo', "
60 "expected 'i32', got 'bool'");
61 }
62
TEST_F(ResolverCallValidationTest, UnusedRetval)63 TEST_F(ResolverCallValidationTest, UnusedRetval) {
64 // fn func() -> f32 { return 1.0; }
65 // fn main() {func(); return; }
66
67 Func("func", {}, ty.f32(), {Return(Expr(1.0f))}, {});
68
69 Func("main", {}, ty.void_(),
70 {
71 CallStmt(Source{{12, 34}}, Call("func")),
72 Return(),
73 });
74
75 EXPECT_TRUE(r()->Resolve()) << r()->error();
76 }
77
TEST_F(ResolverCallValidationTest, PointerArgument_VariableIdentExpr)78 TEST_F(ResolverCallValidationTest, PointerArgument_VariableIdentExpr) {
79 // fn foo(p: ptr<function, i32>) {}
80 // fn main() {
81 // var z: i32 = 1;
82 // foo(&z);
83 // }
84 auto* param = Param("p", ty.pointer<i32>(ast::StorageClass::kFunction));
85 Func("foo", {param}, ty.void_(), {});
86 Func("main", {}, ty.void_(),
87 {
88 Decl(Var("z", ty.i32(), Expr(1))),
89 CallStmt(Call("foo", AddressOf(Source{{12, 34}}, Expr("z")))),
90 });
91
92 EXPECT_TRUE(r()->Resolve()) << r()->error();
93 }
94
TEST_F(ResolverCallValidationTest, PointerArgument_ConstIdentExpr)95 TEST_F(ResolverCallValidationTest, PointerArgument_ConstIdentExpr) {
96 // fn foo(p: ptr<function, i32>) {}
97 // fn main() {
98 // let z: i32 = 1;
99 // foo(&z);
100 // }
101 auto* param = Param("p", ty.pointer<i32>(ast::StorageClass::kFunction));
102 Func("foo", {param}, ty.void_(), {});
103 Func("main", {}, ty.void_(),
104 {
105 Decl(Const("z", ty.i32(), Expr(1))),
106 CallStmt(Call("foo", AddressOf(Expr(Source{{12, 34}}, "z")))),
107 });
108
109 EXPECT_FALSE(r()->Resolve());
110 EXPECT_EQ(r()->error(), "12:34 error: cannot take the address of expression");
111 }
112
TEST_F(ResolverCallValidationTest, PointerArgument_NotIdentExprVar)113 TEST_F(ResolverCallValidationTest, PointerArgument_NotIdentExprVar) {
114 // struct S { m: i32; };
115 // fn foo(p: ptr<function, i32>) {}
116 // fn main() {
117 // var v: S;
118 // foo(&v.m);
119 // }
120 auto* S = Structure("S", {Member("m", ty.i32())});
121 auto* param = Param("p", ty.pointer<i32>(ast::StorageClass::kFunction));
122 Func("foo", {param}, ty.void_(), {});
123 Func("main", {}, ty.void_(),
124 {
125 Decl(Var("v", ty.Of(S))),
126 CallStmt(Call(
127 "foo", AddressOf(Source{{12, 34}}, MemberAccessor("v", "m")))),
128 });
129
130 EXPECT_FALSE(r()->Resolve());
131 EXPECT_EQ(r()->error(),
132 "12:34 error: expected an address-of expression of a variable "
133 "identifier expression or a function parameter");
134 }
135
TEST_F(ResolverCallValidationTest, PointerArgument_AddressOfMemberAccessor)136 TEST_F(ResolverCallValidationTest, PointerArgument_AddressOfMemberAccessor) {
137 // struct S { m: i32; };
138 // fn foo(p: ptr<function, i32>) {}
139 // fn main() {
140 // let v: S = S();
141 // foo(&v.m);
142 // }
143 auto* S = Structure("S", {Member("m", ty.i32())});
144 auto* param = Param("p", ty.pointer<i32>(ast::StorageClass::kFunction));
145 Func("foo", {param}, ty.void_(), {});
146 Func("main", {}, ty.void_(),
147 {
148 Decl(Const("v", ty.Of(S), Construct(ty.Of(S)))),
149 CallStmt(Call("foo", AddressOf(Expr(Source{{12, 34}},
150 MemberAccessor("v", "m"))))),
151 });
152
153 EXPECT_FALSE(r()->Resolve());
154 EXPECT_EQ(r()->error(), "12:34 error: cannot take the address of expression");
155 }
156
TEST_F(ResolverCallValidationTest, PointerArgument_FunctionParam)157 TEST_F(ResolverCallValidationTest, PointerArgument_FunctionParam) {
158 // fn foo(p: ptr<function, i32>) {}
159 // fn bar(p: ptr<function, i32>) {
160 // foo(p);
161 // }
162 Func("foo", {Param("p", ty.pointer<i32>(ast::StorageClass::kFunction))},
163 ty.void_(), {});
164 Func("bar", {Param("p", ty.pointer<i32>(ast::StorageClass::kFunction))},
165 ty.void_(), ast::StatementList{CallStmt(Call("foo", Expr("p")))});
166
167 EXPECT_TRUE(r()->Resolve()) << r()->error();
168 }
169
TEST_F(ResolverCallValidationTest, PointerArgument_FunctionParamWithMain)170 TEST_F(ResolverCallValidationTest, PointerArgument_FunctionParamWithMain) {
171 // fn foo(p: ptr<function, i32>) {}
172 // fn bar(p: ptr<function, i32>) {
173 // foo(p);
174 // }
175 // [[stage(fragment)]]
176 // fn main() {
177 // var v: i32;
178 // bar(&v);
179 // }
180 Func("foo", {Param("p", ty.pointer<i32>(ast::StorageClass::kFunction))},
181 ty.void_(), {});
182 Func("bar", {Param("p", ty.pointer<i32>(ast::StorageClass::kFunction))},
183 ty.void_(), ast::StatementList{CallStmt(Call("foo", Expr("p")))});
184 Func("main", ast::VariableList{}, ty.void_(),
185 {
186 Decl(Var("v", ty.i32(), Expr(1))),
187 CallStmt(Call("foo", AddressOf(Expr("v")))),
188 },
189 {
190 Stage(ast::PipelineStage::kFragment),
191 });
192
193 EXPECT_TRUE(r()->Resolve()) << r()->error();
194 }
195
TEST_F(ResolverCallValidationTest, LetPointer)196 TEST_F(ResolverCallValidationTest, LetPointer) {
197 // fn x(p : ptr<function, i32>) -> i32 {}
198 // [[stage(fragment)]]
199 // fn main() {
200 // var v: i32;
201 // let p: ptr<function, i32> = &v;
202 // var c: i32 = x(p);
203 // }
204 Func("x", {Param("p", ty.pointer<i32>(ast::StorageClass::kFunction))},
205 ty.void_(), {});
206 auto* v = Var("v", ty.i32());
207 auto* p = Const("p", ty.pointer(ty.i32(), ast::StorageClass::kFunction),
208 AddressOf(v));
209 auto* c = Var("c", ty.i32(), ast::StorageClass::kNone,
210 Call("x", Expr(Source{{12, 34}}, p)));
211 Func("main", ast::VariableList{}, ty.void_(),
212 {
213 Decl(v),
214 Decl(p),
215 Decl(c),
216 },
217 {
218 Stage(ast::PipelineStage::kFragment),
219 });
220 EXPECT_FALSE(r()->Resolve());
221 EXPECT_EQ(r()->error(),
222 "12:34 error: expected an address-of expression of a variable "
223 "identifier expression or a function parameter");
224 }
225
TEST_F(ResolverCallValidationTest, LetPointerPrivate)226 TEST_F(ResolverCallValidationTest, LetPointerPrivate) {
227 // let p: ptr<private, i32> = &v;
228 // fn foo(p : ptr<private, i32>) -> i32 {}
229 // var v: i32;
230 // [[stage(fragment)]]
231 // fn main() {
232 // var c: i32 = foo(p);
233 // }
234 Func("foo", {Param("p", ty.pointer<i32>(ast::StorageClass::kPrivate))},
235 ty.void_(), {});
236 auto* v = Global("v", ty.i32(), ast::StorageClass::kPrivate);
237 auto* p = Const("p", ty.pointer(ty.i32(), ast::StorageClass::kPrivate),
238 AddressOf(v));
239 auto* c = Var("c", ty.i32(), ast::StorageClass::kNone,
240 Call("foo", Expr(Source{{12, 34}}, p)));
241 Func("main", ast::VariableList{}, ty.void_(),
242 {
243 Decl(p),
244 Decl(c),
245 },
246 {
247 Stage(ast::PipelineStage::kFragment),
248 });
249 EXPECT_FALSE(r()->Resolve());
250 EXPECT_EQ(r()->error(),
251 "12:34 error: expected an address-of expression of a variable "
252 "identifier expression or a function parameter");
253 }
254
255 } // namespace
256 } // namespace resolver
257 } // namespace tint
258