Branch data Line data Source code
1 : : // Copyright (C) 2020-2025 Free Software Foundation, Inc.
2 : :
3 : : // This file is part of GCC.
4 : :
5 : : // GCC is free software; you can redistribute it and/or modify it under
6 : : // the terms of the GNU General Public License as published by the Free
7 : : // Software Foundation; either version 3, or (at your option) any later
8 : : // version.
9 : :
10 : : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11 : : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 : : // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 : : // for more details.
14 : :
15 : : // You should have received a copy of the GNU General Public License
16 : : // along with GCC; see the file COPYING3. If not see
17 : : // <http://www.gnu.org/licenses/>.
18 : :
19 : : #include "rust-tyty-call.h"
20 : : #include "rust-hir-type-check-expr.h"
21 : : #include "rust-type-util.h"
22 : :
23 : : namespace Rust {
24 : : namespace TyTy {
25 : :
26 : : void
27 : 8 : emit_unexpected_argument_error (location_t loc,
28 : : unsigned long unexpected_arg_count,
29 : : unsigned long expected_arg_count)
30 : : {
31 : : // https://doc.rust-lang.org/error_codes/E0061.html
32 : : // rustc treats 1 as singular and others as plural
33 : 8 : std::string err_msg = "this function takes %lu ";
34 : 8 : if (expected_arg_count == 1)
35 : : {
36 : 2 : err_msg += "argument";
37 : : }
38 : : else
39 : : {
40 : 6 : err_msg += "arguments";
41 : : }
42 : :
43 : 8 : if (unexpected_arg_count == 1)
44 : : {
45 : 2 : err_msg += " but %lu argument was supplied";
46 : : }
47 : : else
48 : : {
49 : 6 : err_msg += " but %lu arguments were supplied";
50 : : }
51 : 8 : rust_error_at (loc, ErrorCode::E0061, err_msg.c_str (), expected_arg_count,
52 : : unexpected_arg_count);
53 : 8 : }
54 : :
55 : : void
56 : 1406 : TypeCheckCallExpr::visit (ADTType &type)
57 : : {
58 : 1406 : rust_assert (!variant.is_error ());
59 : 1406 : if (variant.get_variant_type () != TyTy::VariantDef::VariantType::TUPLE)
60 : : {
61 : 6 : rust_error_at (
62 : 6 : call.get_locus (), ErrorCode::E0423,
63 : : "expected function, tuple struct or tuple variant, found struct %qs",
64 : 6 : type.get_name ().c_str ());
65 : 6 : return;
66 : : }
67 : :
68 : 1400 : if (call.num_params () != variant.num_fields ())
69 : : {
70 : 4 : emit_unexpected_argument_error (call.get_locus (),
71 : 2 : (unsigned long) call.num_params (),
72 : 2 : (unsigned long) variant.num_fields ());
73 : 2 : return;
74 : : }
75 : :
76 : 1398 : size_t i = 0;
77 : 3305 : for (auto &argument : call.get_arguments ())
78 : : {
79 : 1909 : StructFieldType *field = variant.get_field_at_index (i);
80 : 1909 : BaseType *field_tyty = field->get_field_type ();
81 : 1909 : location_t arg_locus = argument->get_locus ();
82 : :
83 : 1909 : BaseType *arg = Resolver::TypeCheckExpr::Resolve (*argument);
84 : 1909 : if (arg->get_kind () == TyTy::TypeKind::ERROR)
85 : : {
86 : 0 : rust_error_at (argument->get_locus (),
87 : : "failed to resolve argument type");
88 : 0 : return;
89 : : }
90 : :
91 : 1909 : HirId coercion_side_id = argument->get_mappings ().get_hirid ();
92 : 3818 : auto res = Resolver::coercion_site (coercion_side_id,
93 : 1909 : TyWithLocation (field_tyty),
94 : 1909 : TyWithLocation (arg, arg_locus),
95 : 1909 : argument->get_locus ());
96 : 1909 : if (res->get_kind () == TyTy::TypeKind::ERROR)
97 : : {
98 : : return;
99 : : }
100 : :
101 : 1907 : i++;
102 : : }
103 : :
104 : 1396 : if (i != call.num_params ())
105 : : {
106 : 0 : emit_unexpected_argument_error (call.get_locus (), (unsigned long) i,
107 : 0 : (unsigned long) call.num_params ());
108 : 0 : return;
109 : : }
110 : :
111 : 1396 : resolved = type.clone ();
112 : : }
113 : :
114 : : void
115 : 8514 : TypeCheckCallExpr::visit (FnType &type)
116 : : {
117 : 8514 : if (call.num_params () != type.num_params ())
118 : : {
119 : 732 : if (type.is_variadic ())
120 : : {
121 : 726 : if (call.num_params () < type.num_params ())
122 : : {
123 : 0 : emit_unexpected_argument_error (
124 : 0 : call.get_locus (), (unsigned long) call.num_params (),
125 : 0 : (unsigned long) type.num_params ());
126 : 0 : return;
127 : : }
128 : : }
129 : : else
130 : : {
131 : 6 : emit_unexpected_argument_error (call.get_locus (),
132 : 6 : (unsigned long) call.num_params (),
133 : 6 : (unsigned long) type.num_params ());
134 : 6 : return;
135 : : }
136 : : }
137 : :
138 : : size_t i = 0;
139 : 18202 : for (auto &argument : call.get_arguments ())
140 : : {
141 : 9714 : location_t arg_locus = argument->get_locus ();
142 : 9714 : auto argument_expr_tyty = Resolver::TypeCheckExpr::Resolve (*argument);
143 : 9714 : if (argument_expr_tyty->is<TyTy::ErrorType> ())
144 : 8514 : return;
145 : :
146 : : // it might be a variadic function
147 : 9710 : if (i < type.num_params ())
148 : : {
149 : 8935 : auto &fnparam = type.param_at (i);
150 : 8935 : BaseType *param_ty = fnparam.get_type ();
151 : 8935 : location_t param_locus
152 : 8935 : = fnparam.has_pattern ()
153 : 8935 : ? fnparam.get_pattern ().get_locus ()
154 : 0 : : mappings.lookup_location (param_ty->get_ref ());
155 : :
156 : 8935 : HirId coercion_side_id = argument->get_mappings ().get_hirid ();
157 : 8935 : auto resolved_argument_type
158 : 8935 : = Resolver::coercion_site (coercion_side_id,
159 : 8935 : TyWithLocation (param_ty, param_locus),
160 : : TyWithLocation (argument_expr_tyty,
161 : 8935 : arg_locus),
162 : 8935 : argument->get_locus ());
163 : 8935 : if (resolved_argument_type->get_kind () == TyTy::TypeKind::ERROR)
164 : : {
165 : : return;
166 : : }
167 : : }
168 : : else
169 : : {
170 : 775 : switch (argument_expr_tyty->get_kind ())
171 : : {
172 : : case TyTy::TypeKind::ERROR:
173 : : return;
174 : 454 : case TyTy::TypeKind::INT: {
175 : 454 : auto &int_ty
176 : : = static_cast<TyTy::IntType &> (*argument_expr_tyty);
177 : 454 : if ((int_ty.get_int_kind () == TyTy::IntType::IntKind::I8)
178 : 454 : || (int_ty.get_int_kind () == TyTy::IntType::IntKind::I16))
179 : : {
180 : 2 : rich_location richloc (line_table, arg_locus);
181 : 2 : richloc.add_fixit_replace (
182 : : "cast the value to c_int: as c_int");
183 : 2 : rust_error_at (richloc, ErrorCode::E0617,
184 : : "expected %<c_int%> variadic argument");
185 : 2 : return;
186 : 2 : }
187 : : break;
188 : : }
189 : 72 : case TyTy::TypeKind::UINT: {
190 : 72 : auto &uint_ty
191 : : = static_cast<TyTy::UintType &> (*argument_expr_tyty);
192 : 72 : if ((uint_ty.get_uint_kind () == TyTy::UintType::UintKind::U8)
193 : 72 : || (uint_ty.get_uint_kind ()
194 : : == TyTy::UintType::UintKind::U16))
195 : : {
196 : 2 : rich_location richloc (line_table, arg_locus);
197 : 2 : richloc.add_fixit_replace (
198 : : "cast the value to c_uint: as c_uint");
199 : 2 : rust_error_at (richloc, ErrorCode::E0617,
200 : : "expected %<c_uint%> variadic argument");
201 : 2 : return;
202 : 2 : }
203 : : break;
204 : : }
205 : 2 : case TyTy::TypeKind::FLOAT: {
206 : 2 : if (static_cast<TyTy::FloatType &> (*argument_expr_tyty)
207 : 2 : .get_float_kind ()
208 : : == TyTy::FloatType::FloatKind::F32)
209 : : {
210 : 2 : rich_location richloc (line_table, arg_locus);
211 : 2 : richloc.add_fixit_replace (
212 : : "cast the value to c_double: as c_double");
213 : 2 : rust_error_at (richloc, ErrorCode::E0617,
214 : : "expected %<c_double%> variadic argument");
215 : 2 : return;
216 : 2 : }
217 : : break;
218 : : }
219 : 0 : case TyTy::TypeKind::BOOL: {
220 : 0 : rich_location richloc (line_table, arg_locus);
221 : 0 : richloc.add_fixit_replace ("cast the value to c_int: as c_int");
222 : 0 : rust_error_at (arg_locus, ErrorCode::E0617,
223 : : "expected %<c_int%> variadic argument");
224 : 0 : return;
225 : 0 : }
226 : 0 : case TyTy::TypeKind::FNDEF: {
227 : 0 : rust_error_at (
228 : : arg_locus, ErrorCode::E0617,
229 : : "unexpected function definition type as variadic "
230 : : "argument - cast to function pointer");
231 : : }
232 : 0 : return;
233 : : default:
234 : : break;
235 : : }
236 : : }
237 : :
238 : 9694 : i++;
239 : : }
240 : :
241 : 8488 : if (i < call.num_params ())
242 : : {
243 : 0 : emit_unexpected_argument_error (call.get_locus (), (unsigned long) i,
244 : 0 : (unsigned long) call.num_params ());
245 : 0 : return;
246 : : }
247 : :
248 : 8488 : type.monomorphize ();
249 : 8488 : resolved = type.get_return_type ()->clone ();
250 : : }
251 : :
252 : : void
253 : 34 : TypeCheckCallExpr::visit (FnPtr &type)
254 : : {
255 : 34 : if (call.num_params () != type.num_params ())
256 : : {
257 : 0 : emit_unexpected_argument_error (call.get_locus (),
258 : 0 : (unsigned long) call.num_params (),
259 : 0 : (unsigned long) type.num_params ());
260 : 0 : return;
261 : : }
262 : :
263 : : size_t i = 0;
264 : 66 : for (auto &argument : call.get_arguments ())
265 : : {
266 : 34 : location_t arg_locus = argument->get_locus ();
267 : 34 : BaseType *fnparam = type.get_param_type_at (i);
268 : 34 : auto argument_expr_tyty = Resolver::TypeCheckExpr::Resolve (*argument);
269 : 34 : if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR)
270 : : {
271 : 0 : rust_error_at (
272 : 0 : argument->get_locus (),
273 : : "failed to resolve type for argument expr in CallExpr");
274 : 0 : return;
275 : : }
276 : :
277 : 68 : auto resolved_argument_type = Resolver::coercion_site (
278 : 34 : argument->get_mappings ().get_hirid (), TyWithLocation (fnparam),
279 : 34 : TyWithLocation (argument_expr_tyty, arg_locus), argument->get_locus ());
280 : 34 : if (resolved_argument_type->get_kind () == TyTy::TypeKind::ERROR)
281 : : {
282 : : return;
283 : : }
284 : :
285 : 32 : i++;
286 : : }
287 : :
288 : 32 : if (i != call.num_params ())
289 : : {
290 : 0 : emit_unexpected_argument_error (call.get_locus (), (unsigned long) i,
291 : 0 : (unsigned long) call.num_params ());
292 : 0 : return;
293 : : }
294 : :
295 : 32 : resolved = type.get_return_type ()->monomorphized_clone ();
296 : : }
297 : :
298 : : // method call checker
299 : :
300 : 1609 : TypeCheckMethodCallExpr::TypeCheckMethodCallExpr (
301 : : Analysis::NodeMapping call_mappings, std::vector<Argument> &args,
302 : : location_t call_locus, location_t receiver_locus,
303 : 1609 : TyTy::BaseType *adjusted_self, Resolver::TypeCheckContext *context)
304 : 1609 : : call_mappings (call_mappings), arguments (args), call_locus (call_locus),
305 : 1609 : receiver_locus (receiver_locus), adjusted_self (adjusted_self),
306 : 1609 : context (context), mappings (Analysis::Mappings::get ())
307 : 1609 : {}
308 : :
309 : : BaseType *
310 : 1542 : TypeCheckMethodCallExpr::go (FnType *ref, HIR::MethodCallExpr &call,
311 : : TyTy::BaseType *adjusted_self,
312 : : Resolver::TypeCheckContext *context)
313 : : {
314 : 1542 : std::vector<Argument> args;
315 : 2257 : for (auto &arg : call.get_arguments ())
316 : : {
317 : 715 : BaseType *argument_expr_tyty = Resolver::TypeCheckExpr::Resolve (*arg);
318 : 715 : if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR)
319 : : {
320 : 0 : rust_error_at (arg->get_locus (),
321 : : "failed to resolve type for argument");
322 : 0 : return new ErrorType (ref->get_ref ());
323 : : }
324 : :
325 : 715 : Argument a (arg->get_mappings (), argument_expr_tyty, arg->get_locus ());
326 : 715 : args.push_back (std::move (a));
327 : : }
328 : :
329 : 1542 : TypeCheckMethodCallExpr checker (call.get_mappings (), args,
330 : : call.get_locus (),
331 : 1542 : call.get_receiver ().get_locus (),
332 : 1542 : adjusted_self, context);
333 : 1542 : return checker.check (*ref);
334 : 1542 : }
335 : :
336 : : BaseType *
337 : 67 : TypeCheckMethodCallExpr::go (FnType *ref, Analysis::NodeMapping call_mappings,
338 : : std::vector<Argument> &args, location_t call_locus,
339 : : location_t receiver_locus,
340 : : TyTy::BaseType *adjusted_self,
341 : : Resolver::TypeCheckContext *context)
342 : : {
343 : 67 : TypeCheckMethodCallExpr checker (call_mappings, args, call_locus,
344 : 67 : receiver_locus, adjusted_self, context);
345 : 67 : return checker.check (*ref);
346 : : }
347 : :
348 : : BaseType *
349 : 1609 : TypeCheckMethodCallExpr::check (FnType &type)
350 : : {
351 : 1609 : Resolver::unify_site (call_mappings.get_hirid (),
352 : 1609 : TyWithLocation (type.get_self_type ()),
353 : 1609 : TyWithLocation (adjusted_self, receiver_locus),
354 : : call_locus);
355 : :
356 : : // +1 for the receiver self
357 : 1609 : size_t num_args_to_call = arguments.size () + 1;
358 : 1609 : if (num_args_to_call != type.num_params ())
359 : : {
360 : 0 : emit_unexpected_argument_error (call_locus,
361 : : (unsigned long) num_args_to_call,
362 : 0 : (unsigned long) type.num_params ());
363 : 0 : return new ErrorType (type.get_ref ());
364 : : }
365 : :
366 : : size_t i = 1;
367 : 2391 : for (auto &argument : arguments)
368 : : {
369 : 782 : location_t arg_locus = argument.get_locus ();
370 : :
371 : 782 : auto &fnparam = type.param_at (i);
372 : 782 : BaseType *param_ty = fnparam.get_type ();
373 : 782 : location_t param_locus
374 : 782 : = fnparam.has_pattern ()
375 : 782 : ? fnparam.get_pattern ().get_locus ()
376 : 0 : : mappings.lookup_location (param_ty->get_ref ());
377 : :
378 : 782 : auto argument_expr_tyty = argument.get_argument_type ();
379 : 782 : HirId coercion_side_id = argument.get_mappings ().get_hirid ();
380 : 782 : auto resolved_argument_type = Resolver::coercion_site (
381 : 782 : coercion_side_id, TyWithLocation (param_ty, param_locus),
382 : 782 : TyWithLocation (argument_expr_tyty, arg_locus), arg_locus);
383 : 782 : if (resolved_argument_type->get_kind () == TyTy::TypeKind::ERROR)
384 : : {
385 : 0 : return new ErrorType (type.get_ref ());
386 : : }
387 : :
388 : 782 : i++;
389 : : }
390 : :
391 : 1609 : if (i != num_args_to_call)
392 : : {
393 : 0 : emit_unexpected_argument_error (call_locus, (unsigned long) i,
394 : 0 : (unsigned long) arguments.size ());
395 : 0 : return new ErrorType (type.get_ref ());
396 : : }
397 : :
398 : 1609 : type.monomorphize ();
399 : :
400 : 1609 : return type.get_return_type ()->monomorphized_clone ();
401 : : }
402 : :
403 : : } // namespace TyTy
404 : : } // namespace Rust
|