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 "optional.h"
21 : #include "rust-hir-item.h"
22 : #include "rust-hir-type-check-expr.h"
23 : #include "rust-hir-type-check.h"
24 : #include "rust-type-util.h"
25 : #include "rust-hir-trait-reference.h"
26 : #include "rust-tyty.h"
27 :
28 : namespace Rust {
29 : namespace TyTy {
30 :
31 : void
32 4 : emit_unexpected_argument_error (location_t loc,
33 : unsigned long unexpected_arg_count,
34 : unsigned long expected_arg_count)
35 : {
36 : // https://doc.rust-lang.org/error_codes/E0061.html
37 : // rustc treats 1 as singular and others as plural
38 4 : std::string err_msg = "this function takes %lu ";
39 4 : if (expected_arg_count == 1)
40 : {
41 1 : err_msg += "argument";
42 : }
43 : else
44 : {
45 3 : err_msg += "arguments";
46 : }
47 :
48 4 : if (unexpected_arg_count == 1)
49 : {
50 1 : err_msg += " but %lu argument was supplied";
51 : }
52 : else
53 : {
54 3 : err_msg += " but %lu arguments were supplied";
55 : }
56 4 : rust_error_at (loc, ErrorCode::E0061, err_msg.c_str (), expected_arg_count,
57 : unexpected_arg_count);
58 4 : }
59 :
60 : static bool
61 14217 : validate_call_argument_associated_impl_bounds (BaseType *param_ty,
62 : BaseType *argument_ty,
63 : location_t locus)
64 : {
65 14217 : auto *context = Resolver::TypeCheckContext::get ();
66 :
67 : // impl bodies are checked generically
68 14217 : if (context->have_function_context ()
69 14217 : && context->peek_context ().get_type ()
70 : == Resolver::TypeCheckContextItem::IMPL_ITEM)
71 6074 : return true;
72 :
73 8143 : auto *resolved_argument_ty = argument_ty->destructure ();
74 8143 : if (resolved_argument_ty->get_kind () == TypeKind::PARAM
75 8074 : || resolved_argument_ty->get_kind () == TypeKind::INFER
76 14888 : || resolved_argument_ty->get_kind () == TypeKind::PROJECTION)
77 : return true;
78 :
79 7951 : for (const auto &bound : param_ty->get_specified_bounds ())
80 : {
81 1214 : bool ambigious = false;
82 1214 : auto associated
83 1214 : = Resolver::lookup_associated_impl_block (bound, argument_ty,
84 : &ambigious);
85 1214 : if (associated == nullptr)
86 1067 : continue;
87 :
88 147 : auto mapping = associated->bind_impl_for_bound (argument_ty, bound, locus,
89 147 : true /*emit_error*/);
90 147 : if (mapping.is_error ())
91 1 : return false;
92 147 : }
93 :
94 : return true;
95 : }
96 :
97 : void
98 1936 : TypeCheckCallExpr::visit (ADTType &type)
99 : {
100 1936 : rust_assert (!variant.is_error ());
101 1936 : if (variant.get_variant_type () != TyTy::VariantDef::VariantType::TUPLE)
102 : {
103 3 : rust_error_at (
104 3 : call.get_locus (), ErrorCode::E0618,
105 : "expected function, tuple struct or tuple variant, found struct %qs",
106 3 : type.get_name ().c_str ());
107 3 : return;
108 : }
109 :
110 1933 : if (call.num_params () != variant.num_fields ())
111 : {
112 2 : emit_unexpected_argument_error (call.get_locus (),
113 1 : (unsigned long) call.num_params (),
114 1 : (unsigned long) variant.num_fields ());
115 1 : return;
116 : }
117 :
118 1932 : size_t i = 0;
119 4401 : for (auto &argument : call.get_arguments ())
120 : {
121 2470 : StructFieldType *field = variant.get_field_at_index (i);
122 2470 : BaseType *field_tyty = field->get_field_type ();
123 2470 : location_t arg_locus = argument->get_locus ();
124 :
125 2470 : BaseType *arg = Resolver::TypeCheckExpr::Resolve (*argument);
126 2470 : if (arg->get_kind () == TyTy::TypeKind::ERROR)
127 : {
128 0 : rust_error_at (argument->get_locus (),
129 : "failed to resolve argument type");
130 0 : return;
131 : }
132 :
133 2470 : HirId coercion_side_id = argument->get_mappings ().get_hirid ();
134 4940 : auto res = Resolver::coercion_site (coercion_side_id,
135 2470 : TyWithLocation (field_tyty),
136 2470 : TyWithLocation (arg, arg_locus),
137 2470 : argument->get_locus ());
138 2470 : if (res->get_kind () == TyTy::TypeKind::ERROR)
139 : {
140 : return;
141 : }
142 :
143 2469 : i++;
144 : }
145 :
146 1931 : if (i != call.num_params ())
147 : {
148 0 : emit_unexpected_argument_error (call.get_locus (), (unsigned long) i,
149 0 : (unsigned long) call.num_params ());
150 0 : return;
151 : }
152 :
153 1931 : resolved = type.clone ();
154 : }
155 :
156 : void
157 11765 : TypeCheckCallExpr::visit (FnType &type)
158 : {
159 11765 : std::vector<size_t> indexes;
160 11765 : const auto lookup = mappings.lookup_defid (type.get_id ());
161 11765 : if (lookup.has_value ())
162 : {
163 4724 : const auto *item = lookup.value ();
164 4724 : rust_assert (item->get_item_kind () == HIR::Item::ItemKind::Function);
165 :
166 4724 : const auto &fn = *static_cast<const HIR::Function *> (item);
167 4724 : auto legacy_const_generic_indexes
168 4724 : = fn.get_legacy_const_generic_indexes ();
169 :
170 4724 : bool malformed_const_generic_indexes
171 4724 : = !legacy_const_generic_indexes.has_value ();
172 4724 : if (malformed_const_generic_indexes)
173 0 : return;
174 :
175 4724 : indexes = legacy_const_generic_indexes.value ();
176 4724 : }
177 :
178 11765 : size_t expected_args = type.num_params () + indexes.size ();
179 11765 : if (call.num_params () < expected_args
180 11765 : || (!type.is_variadic () && call.num_params () != expected_args))
181 : {
182 3 : emit_unexpected_argument_error (call.get_locus (), call.num_params (),
183 : expected_args);
184 3 : return;
185 : }
186 :
187 11762 : if (!indexes.empty ())
188 : {
189 1 : std::set<size_t> seen;
190 2 : for (size_t i = 0; i < indexes.size (); i++)
191 : {
192 1 : size_t index = indexes[i];
193 1 : seen.insert (index);
194 :
195 1 : bool duplicate_index = seen.size () != i + 1;
196 1 : if (index >= call.num_params () || duplicate_index)
197 : {
198 0 : rust_error_at (call.get_locus (), "invalid const argument index");
199 0 : return;
200 : }
201 : }
202 :
203 1 : std::vector<SubstitutionParamMapping *> const_params;
204 2 : for (auto &sub : type.get_substs ())
205 : {
206 1 : if (sub.get_generic_param ().get_kind ()
207 : == HIR::GenericParam::GenericKind::CONST)
208 1 : const_params.push_back (&sub);
209 : }
210 :
211 1 : if (const_params.size () != indexes.size ())
212 : {
213 0 : rust_error_at (
214 0 : call.get_locus (),
215 : "const argument count does not match const parameters");
216 :
217 0 : return;
218 : }
219 :
220 1 : auto &subst_mappings = type.get_substitution_arguments ();
221 3 : for (size_t i = 0; i < indexes.size (); i++)
222 : {
223 1 : size_t cidx = indexes[i];
224 1 : auto &argument = *call.get_arguments ().at (cidx);
225 :
226 1 : auto *param = const_params[i]->get_param_ty ();
227 1 : auto const_ty = param->as_const_type ()->get_specified_type ();
228 1 : auto *value
229 1 : = SubstitutionRef::resolve_const_argument (argument, const_ty);
230 :
231 1 : if (value->is<ErrorType> ())
232 0 : return;
233 :
234 1 : SubstitutionArg existing = SubstitutionArg::error ();
235 1 : bool ok = subst_mappings.get_argument_for_symbol (param, &existing);
236 1 : rust_assert (ok);
237 :
238 1 : Resolver::unify_site (argument.get_mappings ().get_hirid (),
239 1 : TyWithLocation (existing.get_tyty ()),
240 1 : TyWithLocation (value), argument.get_locus ());
241 : }
242 1 : }
243 11762 : call.set_const_argument_indexes (indexes);
244 :
245 : // if the surrounding context has pushed an expected type, try unifying it
246 : // with the fn's return type before checking arguments. This lets the callee
247 : // result constrain inference variables that may appear in parameter
248 : // projections.
249 :
250 11762 : auto *ctx = Resolver::TypeCheckContext::get ();
251 11762 : TyTy::BaseType *expected = ctx->peek_expected_type ();
252 11762 : const TyTy::BaseType *return_infer
253 11762 : = type.get_return_type ()->contains_infer ();
254 11762 : if (expected != nullptr && return_infer != nullptr)
255 : {
256 15 : Resolver::unify_site_and (call.get_mappings ().get_hirid (),
257 15 : TyWithLocation (expected),
258 15 : TyWithLocation (type.get_return_type ()),
259 15 : call.get_locus (), false /*emit_errors*/,
260 : true /*commit_if_ok*/,
261 : true /*implicit_infer_vars*/, true /*cleanup*/);
262 : }
263 :
264 11762 : size_t i;
265 24539 : for (i = 0; i < call.get_arguments ().size (); i++)
266 : {
267 12794 : auto &argument = call.get_arguments ().at (i);
268 25588 : if (call.is_const_argument (i))
269 1 : continue;
270 :
271 12793 : location_t arg_locus = argument->get_locus ();
272 :
273 12793 : TyTy::BaseType *param_ty = nullptr;
274 12793 : if (i < type.num_params ())
275 12003 : param_ty = type.param_at (i).get_type ();
276 :
277 12003 : if (param_ty != nullptr)
278 12003 : ctx->push_expected_type (param_ty);
279 :
280 12793 : auto argument_expr_tyty = Resolver::TypeCheckExpr::Resolve (*argument);
281 12793 : if (param_ty != nullptr)
282 12003 : ctx->pop_expected_type ();
283 12793 : if (argument_expr_tyty->is<TyTy::ErrorType> ())
284 : return;
285 :
286 : // it might be a variadic function
287 12791 : if (i < type.num_params ())
288 : {
289 12001 : auto &fnparam = type.param_at (i);
290 12001 : location_t param_locus
291 12001 : = fnparam.has_pattern ()
292 12001 : ? fnparam.get_pattern ().get_locus ()
293 0 : : mappings.lookup_location (param_ty->get_ref ());
294 :
295 12001 : HirId coercion_side_id = argument->get_mappings ().get_hirid ();
296 12001 : auto resolved_argument_type
297 12001 : = Resolver::coercion_site (coercion_side_id,
298 12001 : TyWithLocation (param_ty, param_locus),
299 : TyWithLocation (argument_expr_tyty,
300 12001 : arg_locus),
301 12001 : argument->get_locus ());
302 12001 : if (resolved_argument_type->get_kind () == TyTy::TypeKind::ERROR)
303 : {
304 : return;
305 : }
306 :
307 11990 : if (!validate_call_argument_associated_impl_bounds (
308 11990 : param_ty, argument_expr_tyty, argument->get_locus ()))
309 : return;
310 : }
311 : else
312 : {
313 790 : switch (argument_expr_tyty->get_kind ())
314 : {
315 : case TyTy::TypeKind::ERROR:
316 : return;
317 464 : case TyTy::TypeKind::INT:
318 464 : {
319 464 : auto &int_ty
320 : = static_cast<TyTy::IntType &> (*argument_expr_tyty);
321 464 : if ((int_ty.get_int_kind () == TyTy::IntType::IntKind::I8)
322 464 : || (int_ty.get_int_kind () == TyTy::IntType::IntKind::I16))
323 : {
324 1 : rich_location richloc (line_table, arg_locus);
325 1 : richloc.add_fixit_replace (
326 : "cast the value to c_int: as c_int");
327 1 : rust_error_at (richloc, ErrorCode::E0617,
328 : "expected %<c_int%> variadic argument");
329 1 : return;
330 1 : }
331 : break;
332 : }
333 78 : case TyTy::TypeKind::UINT:
334 78 : {
335 78 : auto &uint_ty
336 : = static_cast<TyTy::UintType &> (*argument_expr_tyty);
337 78 : if ((uint_ty.get_uint_kind () == TyTy::UintType::UintKind::U8)
338 78 : || (uint_ty.get_uint_kind ()
339 : == TyTy::UintType::UintKind::U16))
340 : {
341 1 : rich_location richloc (line_table, arg_locus);
342 1 : richloc.add_fixit_replace (
343 : "cast the value to c_uint: as c_uint");
344 1 : rust_error_at (richloc, ErrorCode::E0617,
345 : "expected %<c_uint%> variadic argument");
346 1 : return;
347 1 : }
348 : break;
349 : }
350 1 : case TyTy::TypeKind::FLOAT:
351 1 : {
352 1 : if (static_cast<TyTy::FloatType &> (*argument_expr_tyty)
353 1 : .get_float_kind ()
354 : == TyTy::FloatType::FloatKind::F32)
355 : {
356 1 : rich_location richloc (line_table, arg_locus);
357 1 : richloc.add_fixit_replace (
358 : "cast the value to c_double: as c_double");
359 1 : rust_error_at (richloc, ErrorCode::E0617,
360 : "expected %<c_double%> variadic argument");
361 1 : return;
362 1 : }
363 : break;
364 : }
365 0 : case TyTy::TypeKind::BOOL:
366 0 : {
367 0 : rich_location richloc (line_table, arg_locus);
368 0 : richloc.add_fixit_replace ("cast the value to c_int: as c_int");
369 0 : rust_error_at (arg_locus, ErrorCode::E0617,
370 : "expected %<c_int%> variadic argument");
371 0 : return;
372 0 : }
373 0 : case TyTy::TypeKind::FNDEF:
374 0 : {
375 0 : rust_error_at (
376 : arg_locus, ErrorCode::E0617,
377 : "unexpected function definition type as variadic "
378 : "argument - cast to function pointer");
379 : }
380 0 : return;
381 : default:
382 : break;
383 : }
384 : }
385 : }
386 :
387 11745 : if (i + indexes.size () < call.num_params ())
388 : {
389 0 : emit_unexpected_argument_error (call.get_locus (), (unsigned long) i,
390 0 : (unsigned long) call.num_params ());
391 0 : return;
392 : }
393 :
394 11745 : type.monomorphize ();
395 11745 : Resolver::rebind_projection_self_from_fn (type, type.get_return_type ());
396 :
397 11745 : resolved = type.get_return_type ();
398 11765 : }
399 :
400 : void
401 30 : TypeCheckCallExpr::visit (FnPtr &type)
402 : {
403 30 : if (call.num_params () != type.num_params ())
404 : {
405 0 : emit_unexpected_argument_error (call.get_locus (),
406 0 : (unsigned long) call.num_params (),
407 0 : (unsigned long) type.num_params ());
408 0 : return;
409 : }
410 :
411 59 : size_t i = 0;
412 59 : for (auto &argument : call.get_arguments ())
413 : {
414 30 : location_t arg_locus = argument->get_locus ();
415 30 : BaseType *fnparam = type.get_param_type_at (i);
416 30 : auto argument_expr_tyty = Resolver::TypeCheckExpr::Resolve (*argument);
417 30 : if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR)
418 : {
419 0 : rust_error_at (
420 0 : argument->get_locus (),
421 : "failed to resolve type for argument expr in CallExpr");
422 0 : return;
423 : }
424 :
425 60 : auto resolved_argument_type = Resolver::coercion_site (
426 30 : argument->get_mappings ().get_hirid (), TyWithLocation (fnparam),
427 30 : TyWithLocation (argument_expr_tyty, arg_locus), argument->get_locus ());
428 30 : if (resolved_argument_type->get_kind () == TyTy::TypeKind::ERROR)
429 : {
430 : return;
431 : }
432 :
433 29 : i++;
434 : }
435 :
436 29 : if (i != call.num_params ())
437 : {
438 0 : emit_unexpected_argument_error (call.get_locus (), (unsigned long) i,
439 0 : (unsigned long) call.num_params ());
440 0 : return;
441 : }
442 :
443 29 : resolved = type.get_return_type ()->monomorphized_clone ();
444 : }
445 :
446 : // method call checker
447 :
448 3221 : TypeCheckMethodCallExpr::TypeCheckMethodCallExpr (
449 : Analysis::NodeMapping call_mappings, std::vector<Argument> &args,
450 : location_t call_locus, location_t receiver_locus,
451 : TyTy::BaseType *adjusted_self, Resolver::TypeCheckContext *context)
452 3221 : : call_mappings (call_mappings), arguments (args), call_locus (call_locus),
453 3221 : receiver_locus (receiver_locus), adjusted_self (adjusted_self),
454 3221 : context (context), mappings (Analysis::Mappings::get ())
455 3221 : {}
456 :
457 : BaseType *
458 3155 : TypeCheckMethodCallExpr::go (FnType *ref, HIR::MethodCallExpr &call,
459 : TyTy::BaseType *adjusted_self,
460 : Resolver::TypeCheckContext *context)
461 : {
462 3155 : std::vector<Argument> args;
463 5316 : for (auto &arg : call.get_arguments ())
464 : {
465 2161 : BaseType *argument_expr_tyty = Resolver::TypeCheckExpr::Resolve (*arg);
466 2161 : if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR)
467 : {
468 0 : rust_error_at (arg->get_locus (),
469 : "failed to resolve type for argument");
470 0 : return new ErrorType (ref->get_ref ());
471 : }
472 :
473 2161 : args.emplace_back (arg->get_mappings (), argument_expr_tyty,
474 2161 : arg->get_locus ());
475 : }
476 :
477 3155 : TypeCheckMethodCallExpr checker (call.get_mappings (), args,
478 : call.get_locus (),
479 3155 : call.get_receiver ().get_locus (),
480 3155 : adjusted_self, context);
481 3155 : return checker.check (*ref);
482 3155 : }
483 :
484 : BaseType *
485 66 : TypeCheckMethodCallExpr::go (FnType *ref, Analysis::NodeMapping call_mappings,
486 : std::vector<Argument> &args, location_t call_locus,
487 : location_t receiver_locus,
488 : TyTy::BaseType *adjusted_self,
489 : Resolver::TypeCheckContext *context)
490 : {
491 66 : TypeCheckMethodCallExpr checker (call_mappings, args, call_locus,
492 66 : receiver_locus, adjusted_self, context);
493 66 : return checker.check (*ref);
494 : }
495 :
496 : BaseType *
497 3221 : TypeCheckMethodCallExpr::check (FnType &type)
498 : {
499 3221 : Resolver::unify_site (call_mappings.get_hirid (),
500 3221 : TyWithLocation (type.get_self_type ()),
501 3221 : TyWithLocation (adjusted_self, receiver_locus),
502 : call_locus);
503 :
504 : // +1 for the receiver self
505 3221 : size_t num_args_to_call = arguments.size () + 1;
506 3221 : if (num_args_to_call != type.num_params ())
507 : {
508 0 : emit_unexpected_argument_error (call_locus,
509 : (unsigned long) num_args_to_call,
510 0 : (unsigned long) type.num_params ());
511 0 : return new ErrorType (type.get_ref ());
512 : }
513 :
514 5448 : size_t i = 1;
515 5448 : for (auto &argument : arguments)
516 : {
517 2227 : location_t arg_locus = argument.get_locus ();
518 :
519 2227 : auto &fnparam = type.param_at (i);
520 2227 : BaseType *param_ty = fnparam.get_type ();
521 2227 : location_t param_locus
522 2227 : = fnparam.has_pattern ()
523 2227 : ? fnparam.get_pattern ().get_locus ()
524 0 : : mappings.lookup_location (param_ty->get_ref ());
525 :
526 2227 : auto argument_expr_tyty = argument.get_argument_type ();
527 2227 : HirId coercion_side_id = argument.get_mappings ().get_hirid ();
528 2227 : auto resolved_argument_type = Resolver::coercion_site (
529 2227 : coercion_side_id, TyWithLocation (param_ty, param_locus),
530 2227 : TyWithLocation (argument_expr_tyty, arg_locus), arg_locus);
531 2227 : if (resolved_argument_type->get_kind () == TyTy::TypeKind::ERROR)
532 : {
533 0 : return new ErrorType (type.get_ref ());
534 : }
535 :
536 2227 : if (!validate_call_argument_associated_impl_bounds (
537 : param_ty, argument_expr_tyty, argument.get_locus ()))
538 0 : return new ErrorType (type.get_ref ());
539 :
540 2227 : i++;
541 : }
542 :
543 3221 : if (i != num_args_to_call)
544 : {
545 0 : emit_unexpected_argument_error (call_locus, (unsigned long) i,
546 0 : (unsigned long) arguments.size ());
547 0 : return new ErrorType (type.get_ref ());
548 : }
549 :
550 3221 : type.monomorphize ();
551 :
552 3221 : return type.get_return_type ()->monomorphized_clone ();
553 : }
554 :
555 : } // namespace TyTy
556 : } // namespace Rust
|