Line data Source code
1 : // Copyright (C) 2020-2026 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-hir-type-check.h"
22 : #include "rust-type-util.h"
23 : #include "rust-hir-trait-reference.h"
24 :
25 : namespace Rust {
26 : namespace TyTy {
27 :
28 : void
29 4 : emit_unexpected_argument_error (location_t loc,
30 : unsigned long unexpected_arg_count,
31 : unsigned long expected_arg_count)
32 : {
33 : // https://doc.rust-lang.org/error_codes/E0061.html
34 : // rustc treats 1 as singular and others as plural
35 4 : std::string err_msg = "this function takes %lu ";
36 4 : if (expected_arg_count == 1)
37 : {
38 1 : err_msg += "argument";
39 : }
40 : else
41 : {
42 3 : err_msg += "arguments";
43 : }
44 :
45 4 : if (unexpected_arg_count == 1)
46 : {
47 1 : err_msg += " but %lu argument was supplied";
48 : }
49 : else
50 : {
51 3 : err_msg += " but %lu arguments were supplied";
52 : }
53 4 : rust_error_at (loc, ErrorCode::E0061, err_msg.c_str (), expected_arg_count,
54 : unexpected_arg_count);
55 4 : }
56 :
57 : static bool
58 12918 : validate_call_argument_associated_impl_bounds (BaseType *param_ty,
59 : BaseType *argument_ty,
60 : location_t locus)
61 : {
62 12918 : auto *context = Resolver::TypeCheckContext::get ();
63 :
64 : // impl bodies are checked generically
65 12918 : if (context->have_function_context ()
66 12918 : && context->peek_context ().get_type ()
67 : == Resolver::TypeCheckContextItem::IMPL_ITEM)
68 5344 : return true;
69 :
70 7574 : auto *resolved_argument_ty = argument_ty->destructure ();
71 7574 : if (resolved_argument_ty->get_kind () == TypeKind::PARAM
72 7521 : || resolved_argument_ty->get_kind () == TypeKind::INFER
73 13865 : || resolved_argument_ty->get_kind () == TypeKind::PROJECTION)
74 : return true;
75 :
76 7483 : for (auto bound : param_ty->get_specified_bounds ())
77 : {
78 1200 : bool ambigious = false;
79 1200 : auto associated
80 1200 : = Resolver::lookup_associated_impl_block (bound, argument_ty,
81 : &ambigious);
82 1200 : if (associated == nullptr)
83 1053 : continue;
84 :
85 147 : auto mapping = associated->bind_impl_for_bound (argument_ty, bound, locus,
86 147 : true /*emit_error*/);
87 147 : if (mapping.is_error ())
88 1 : return false;
89 1200 : }
90 :
91 6283 : return true;
92 : }
93 :
94 : void
95 1819 : TypeCheckCallExpr::visit (ADTType &type)
96 : {
97 1819 : rust_assert (!variant.is_error ());
98 1819 : if (variant.get_variant_type () != TyTy::VariantDef::VariantType::TUPLE)
99 : {
100 3 : rust_error_at (
101 3 : call.get_locus (), ErrorCode::E0618,
102 : "expected function, tuple struct or tuple variant, found struct %qs",
103 3 : type.get_name ().c_str ());
104 3 : return;
105 : }
106 :
107 1816 : if (call.num_params () != variant.num_fields ())
108 : {
109 2 : emit_unexpected_argument_error (call.get_locus (),
110 1 : (unsigned long) call.num_params (),
111 1 : (unsigned long) variant.num_fields ());
112 1 : return;
113 : }
114 :
115 1815 : size_t i = 0;
116 4146 : for (auto &argument : call.get_arguments ())
117 : {
118 2332 : StructFieldType *field = variant.get_field_at_index (i);
119 2332 : BaseType *field_tyty = field->get_field_type ();
120 2332 : location_t arg_locus = argument->get_locus ();
121 :
122 2332 : BaseType *arg = Resolver::TypeCheckExpr::Resolve (*argument);
123 2332 : if (arg->get_kind () == TyTy::TypeKind::ERROR)
124 : {
125 0 : rust_error_at (argument->get_locus (),
126 : "failed to resolve argument type");
127 0 : return;
128 : }
129 :
130 2332 : HirId coercion_side_id = argument->get_mappings ().get_hirid ();
131 4664 : auto res = Resolver::coercion_site (coercion_side_id,
132 2332 : TyWithLocation (field_tyty),
133 2332 : TyWithLocation (arg, arg_locus),
134 2332 : argument->get_locus ());
135 2332 : if (res->get_kind () == TyTy::TypeKind::ERROR)
136 : {
137 : return;
138 : }
139 :
140 2331 : i++;
141 : }
142 :
143 1814 : if (i != call.num_params ())
144 : {
145 0 : emit_unexpected_argument_error (call.get_locus (), (unsigned long) i,
146 0 : (unsigned long) call.num_params ());
147 0 : return;
148 : }
149 :
150 1814 : resolved = type.clone ();
151 : }
152 :
153 : void
154 10840 : TypeCheckCallExpr::visit (FnType &type)
155 : {
156 10840 : if (call.num_params () != type.num_params ())
157 : {
158 744 : if (type.is_variadic ())
159 : {
160 741 : if (call.num_params () < type.num_params ())
161 : {
162 0 : emit_unexpected_argument_error (
163 0 : call.get_locus (), (unsigned long) call.num_params (),
164 0 : (unsigned long) type.num_params ());
165 0 : return;
166 : }
167 : }
168 : else
169 : {
170 3 : emit_unexpected_argument_error (call.get_locus (),
171 3 : (unsigned long) call.num_params (),
172 3 : (unsigned long) type.num_params ());
173 3 : return;
174 : }
175 : }
176 :
177 : // if the surrounding context has pushed an expected type, try unifying it
178 : // with the fn's return type before checking arguments. This lets the callee
179 : // result constrain inference variables that may appear in parameter
180 : // projections.
181 :
182 10837 : auto *ctx = Resolver::TypeCheckContext::get ();
183 10837 : TyTy::BaseType *expected = ctx->peek_expected_type ();
184 10837 : const TyTy::BaseType *return_infer
185 10837 : = type.get_return_type ()->contains_infer ();
186 10837 : if (expected != nullptr && return_infer != nullptr)
187 : {
188 171 : Resolver::unify_site_and (call.get_mappings ().get_hirid (),
189 171 : TyWithLocation (expected),
190 171 : TyWithLocation (type.get_return_type ()),
191 171 : call.get_locus (), false /*emit_errors*/,
192 : true /*commit_if_ok*/,
193 : true /*implicit_infer_vars*/, true /*cleanup*/);
194 : }
195 :
196 10837 : size_t i = 0;
197 22419 : for (auto &argument : call.get_arguments ())
198 : {
199 11599 : location_t arg_locus = argument->get_locus ();
200 :
201 11599 : TyTy::BaseType *param_ty = nullptr;
202 11599 : if (i < type.num_params ())
203 10809 : param_ty = type.param_at (i).get_type ();
204 :
205 10809 : if (param_ty != nullptr)
206 10809 : ctx->push_expected_type (param_ty);
207 11599 : auto argument_expr_tyty = Resolver::TypeCheckExpr::Resolve (*argument);
208 11599 : if (param_ty != nullptr)
209 10809 : ctx->pop_expected_type ();
210 11599 : if (argument_expr_tyty->is<TyTy::ErrorType> ())
211 10840 : return;
212 :
213 : // it might be a variadic function
214 11597 : if (i < type.num_params ())
215 : {
216 10807 : auto &fnparam = type.param_at (i);
217 10807 : location_t param_locus
218 10807 : = fnparam.has_pattern ()
219 10807 : ? fnparam.get_pattern ().get_locus ()
220 0 : : mappings.lookup_location (param_ty->get_ref ());
221 :
222 10807 : HirId coercion_side_id = argument->get_mappings ().get_hirid ();
223 10807 : auto resolved_argument_type
224 10807 : = Resolver::coercion_site (coercion_side_id,
225 10807 : TyWithLocation (param_ty, param_locus),
226 : TyWithLocation (argument_expr_tyty,
227 10807 : arg_locus),
228 10807 : argument->get_locus ());
229 10807 : if (resolved_argument_type->get_kind () == TyTy::TypeKind::ERROR)
230 : {
231 : return;
232 : }
233 :
234 10796 : if (!validate_call_argument_associated_impl_bounds (
235 10796 : param_ty, argument_expr_tyty, argument->get_locus ()))
236 : return;
237 : }
238 : else
239 : {
240 790 : switch (argument_expr_tyty->get_kind ())
241 : {
242 : case TyTy::TypeKind::ERROR:
243 : return;
244 464 : case TyTy::TypeKind::INT:
245 464 : {
246 464 : auto &int_ty
247 : = static_cast<TyTy::IntType &> (*argument_expr_tyty);
248 464 : if ((int_ty.get_int_kind () == TyTy::IntType::IntKind::I8)
249 464 : || (int_ty.get_int_kind () == TyTy::IntType::IntKind::I16))
250 : {
251 1 : rich_location richloc (line_table, arg_locus);
252 1 : richloc.add_fixit_replace (
253 : "cast the value to c_int: as c_int");
254 1 : rust_error_at (richloc, ErrorCode::E0617,
255 : "expected %<c_int%> variadic argument");
256 1 : return;
257 1 : }
258 : break;
259 : }
260 78 : case TyTy::TypeKind::UINT:
261 78 : {
262 78 : auto &uint_ty
263 : = static_cast<TyTy::UintType &> (*argument_expr_tyty);
264 78 : if ((uint_ty.get_uint_kind () == TyTy::UintType::UintKind::U8)
265 78 : || (uint_ty.get_uint_kind ()
266 : == TyTy::UintType::UintKind::U16))
267 : {
268 1 : rich_location richloc (line_table, arg_locus);
269 1 : richloc.add_fixit_replace (
270 : "cast the value to c_uint: as c_uint");
271 1 : rust_error_at (richloc, ErrorCode::E0617,
272 : "expected %<c_uint%> variadic argument");
273 1 : return;
274 1 : }
275 : break;
276 : }
277 1 : case TyTy::TypeKind::FLOAT:
278 1 : {
279 1 : if (static_cast<TyTy::FloatType &> (*argument_expr_tyty)
280 1 : .get_float_kind ()
281 : == TyTy::FloatType::FloatKind::F32)
282 : {
283 1 : rich_location richloc (line_table, arg_locus);
284 1 : richloc.add_fixit_replace (
285 : "cast the value to c_double: as c_double");
286 1 : rust_error_at (richloc, ErrorCode::E0617,
287 : "expected %<c_double%> variadic argument");
288 1 : return;
289 1 : }
290 : break;
291 : }
292 0 : case TyTy::TypeKind::BOOL:
293 0 : {
294 0 : rich_location richloc (line_table, arg_locus);
295 0 : richloc.add_fixit_replace ("cast the value to c_int: as c_int");
296 0 : rust_error_at (arg_locus, ErrorCode::E0617,
297 : "expected %<c_int%> variadic argument");
298 0 : return;
299 0 : }
300 0 : case TyTy::TypeKind::FNDEF:
301 0 : {
302 0 : rust_error_at (
303 : arg_locus, ErrorCode::E0617,
304 : "unexpected function definition type as variadic "
305 : "argument - cast to function pointer");
306 : }
307 0 : return;
308 : default:
309 : break;
310 : }
311 : }
312 :
313 11582 : i++;
314 : }
315 :
316 10820 : if (i < call.num_params ())
317 : {
318 0 : emit_unexpected_argument_error (call.get_locus (), (unsigned long) i,
319 0 : (unsigned long) call.num_params ());
320 0 : return;
321 : }
322 :
323 10820 : type.monomorphize ();
324 10820 : Resolver::rebind_projection_self_from_fn (type, type.get_return_type ());
325 :
326 10820 : resolved = type.get_return_type ();
327 : }
328 :
329 : void
330 29 : TypeCheckCallExpr::visit (FnPtr &type)
331 : {
332 29 : if (call.num_params () != type.num_params ())
333 : {
334 0 : emit_unexpected_argument_error (call.get_locus (),
335 0 : (unsigned long) call.num_params (),
336 0 : (unsigned long) type.num_params ());
337 0 : return;
338 : }
339 :
340 57 : size_t i = 0;
341 57 : for (auto &argument : call.get_arguments ())
342 : {
343 29 : location_t arg_locus = argument->get_locus ();
344 29 : BaseType *fnparam = type.get_param_type_at (i);
345 29 : auto argument_expr_tyty = Resolver::TypeCheckExpr::Resolve (*argument);
346 29 : if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR)
347 : {
348 0 : rust_error_at (
349 0 : argument->get_locus (),
350 : "failed to resolve type for argument expr in CallExpr");
351 0 : return;
352 : }
353 :
354 58 : auto resolved_argument_type = Resolver::coercion_site (
355 29 : argument->get_mappings ().get_hirid (), TyWithLocation (fnparam),
356 29 : TyWithLocation (argument_expr_tyty, arg_locus), argument->get_locus ());
357 29 : if (resolved_argument_type->get_kind () == TyTy::TypeKind::ERROR)
358 : {
359 : return;
360 : }
361 :
362 28 : i++;
363 : }
364 :
365 28 : if (i != call.num_params ())
366 : {
367 0 : emit_unexpected_argument_error (call.get_locus (), (unsigned long) i,
368 0 : (unsigned long) call.num_params ());
369 0 : return;
370 : }
371 :
372 28 : resolved = type.get_return_type ()->monomorphized_clone ();
373 : }
374 :
375 : // method call checker
376 :
377 3106 : TypeCheckMethodCallExpr::TypeCheckMethodCallExpr (
378 : Analysis::NodeMapping call_mappings, std::vector<Argument> &args,
379 : location_t call_locus, location_t receiver_locus,
380 : TyTy::BaseType *adjusted_self, Resolver::TypeCheckContext *context)
381 3106 : : call_mappings (call_mappings), arguments (args), call_locus (call_locus),
382 3106 : receiver_locus (receiver_locus), adjusted_self (adjusted_self),
383 3106 : context (context), mappings (Analysis::Mappings::get ())
384 3106 : {}
385 :
386 : BaseType *
387 3040 : TypeCheckMethodCallExpr::go (FnType *ref, HIR::MethodCallExpr &call,
388 : TyTy::BaseType *adjusted_self,
389 : Resolver::TypeCheckContext *context)
390 : {
391 3040 : std::vector<Argument> args;
392 5096 : for (auto &arg : call.get_arguments ())
393 : {
394 2056 : BaseType *argument_expr_tyty = Resolver::TypeCheckExpr::Resolve (*arg);
395 2056 : if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR)
396 : {
397 0 : rust_error_at (arg->get_locus (),
398 : "failed to resolve type for argument");
399 0 : return new ErrorType (ref->get_ref ());
400 : }
401 :
402 2056 : args.emplace_back (arg->get_mappings (), argument_expr_tyty,
403 2056 : arg->get_locus ());
404 : }
405 :
406 3040 : TypeCheckMethodCallExpr checker (call.get_mappings (), args,
407 : call.get_locus (),
408 3040 : call.get_receiver ().get_locus (),
409 3040 : adjusted_self, context);
410 3040 : return checker.check (*ref);
411 3040 : }
412 :
413 : BaseType *
414 66 : TypeCheckMethodCallExpr::go (FnType *ref, Analysis::NodeMapping call_mappings,
415 : std::vector<Argument> &args, location_t call_locus,
416 : location_t receiver_locus,
417 : TyTy::BaseType *adjusted_self,
418 : Resolver::TypeCheckContext *context)
419 : {
420 66 : TypeCheckMethodCallExpr checker (call_mappings, args, call_locus,
421 66 : receiver_locus, adjusted_self, context);
422 66 : return checker.check (*ref);
423 : }
424 :
425 : BaseType *
426 3106 : TypeCheckMethodCallExpr::check (FnType &type)
427 : {
428 3106 : Resolver::unify_site (call_mappings.get_hirid (),
429 3106 : TyWithLocation (type.get_self_type ()),
430 3106 : TyWithLocation (adjusted_self, receiver_locus),
431 : call_locus);
432 :
433 : // +1 for the receiver self
434 3106 : size_t num_args_to_call = arguments.size () + 1;
435 3106 : if (num_args_to_call != type.num_params ())
436 : {
437 0 : emit_unexpected_argument_error (call_locus,
438 : (unsigned long) num_args_to_call,
439 0 : (unsigned long) type.num_params ());
440 0 : return new ErrorType (type.get_ref ());
441 : }
442 :
443 5228 : size_t i = 1;
444 5228 : for (auto &argument : arguments)
445 : {
446 2122 : location_t arg_locus = argument.get_locus ();
447 :
448 2122 : auto &fnparam = type.param_at (i);
449 2122 : BaseType *param_ty = fnparam.get_type ();
450 2122 : location_t param_locus
451 2122 : = fnparam.has_pattern ()
452 2122 : ? fnparam.get_pattern ().get_locus ()
453 0 : : mappings.lookup_location (param_ty->get_ref ());
454 :
455 2122 : auto argument_expr_tyty = argument.get_argument_type ();
456 2122 : HirId coercion_side_id = argument.get_mappings ().get_hirid ();
457 2122 : auto resolved_argument_type = Resolver::coercion_site (
458 2122 : coercion_side_id, TyWithLocation (param_ty, param_locus),
459 2122 : TyWithLocation (argument_expr_tyty, arg_locus), arg_locus);
460 2122 : if (resolved_argument_type->get_kind () == TyTy::TypeKind::ERROR)
461 : {
462 0 : return new ErrorType (type.get_ref ());
463 : }
464 :
465 2122 : if (!validate_call_argument_associated_impl_bounds (
466 : param_ty, argument_expr_tyty, argument.get_locus ()))
467 0 : return new ErrorType (type.get_ref ());
468 :
469 2122 : i++;
470 : }
471 :
472 3106 : if (i != num_args_to_call)
473 : {
474 0 : emit_unexpected_argument_error (call_locus, (unsigned long) i,
475 0 : (unsigned long) arguments.size ());
476 0 : return new ErrorType (type.get_ref ());
477 : }
478 :
479 3106 : type.monomorphize ();
480 :
481 3106 : return type.get_return_type ()->monomorphized_clone ();
482 : }
483 :
484 : } // namespace TyTy
485 : } // namespace Rust
|