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