Daily bump.
[official-gcc.git] / gcc / rust / typecheck / rust-tyty-call.cc
blob723927289f8d360ab831c58ff70f374eb6df5d6b
1 // Copyright (C) 2020-2025 Free Software Foundation, Inc.
3 // This file is part of GCC.
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.
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.
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/>.
19 #include "rust-tyty-call.h"
20 #include "rust-hir-type-check-expr.h"
21 #include "rust-type-util.h"
23 namespace Rust {
24 namespace TyTy {
26 void
27 emit_unexpected_argument_error (location_t loc,
28 unsigned long unexpected_arg_count,
29 unsigned long expected_arg_count)
31 // https://doc.rust-lang.org/error_codes/E0061.html
32 // rustc treats 1 as singular and others as plural
33 std::string err_msg = "this function takes %lu ";
34 if (expected_arg_count == 1)
36 err_msg += "argument";
38 else
40 err_msg += "arguments";
43 if (unexpected_arg_count == 1)
45 err_msg += " but %lu argument was supplied";
47 else
49 err_msg += " but %lu arguments were supplied";
51 rust_error_at (loc, ErrorCode::E0061, err_msg.c_str (), expected_arg_count,
52 unexpected_arg_count);
55 void
56 TypeCheckCallExpr::visit (ADTType &type)
58 rust_assert (!variant.is_error ());
59 if (variant.get_variant_type () != TyTy::VariantDef::VariantType::TUPLE)
61 rust_error_at (
62 call.get_locus (), ErrorCode::E0423,
63 "expected function, tuple struct or tuple variant, found struct %qs",
64 type.get_name ().c_str ());
65 return;
68 if (call.num_params () != variant.num_fields ())
70 emit_unexpected_argument_error (call.get_locus (),
71 (unsigned long) call.num_params (),
72 (unsigned long) variant.num_fields ());
73 return;
76 size_t i = 0;
77 for (auto &argument : call.get_arguments ())
79 StructFieldType *field = variant.get_field_at_index (i);
80 BaseType *field_tyty = field->get_field_type ();
81 location_t arg_locus = argument->get_locus ();
83 BaseType *arg = Resolver::TypeCheckExpr::Resolve (argument.get ());
84 if (arg->get_kind () == TyTy::TypeKind::ERROR)
86 rust_error_at (argument->get_locus (),
87 "failed to resolve argument type");
88 return;
91 HirId coercion_side_id = argument->get_mappings ().get_hirid ();
92 auto res = Resolver::coercion_site (coercion_side_id,
93 TyWithLocation (field_tyty),
94 TyWithLocation (arg, arg_locus),
95 argument->get_locus ());
96 if (res->get_kind () == TyTy::TypeKind::ERROR)
98 return;
101 i++;
104 if (i != call.num_params ())
106 emit_unexpected_argument_error (call.get_locus (), (unsigned long) i,
107 (unsigned long) call.num_params ());
108 return;
111 resolved = type.clone ();
114 void
115 TypeCheckCallExpr::visit (FnType &type)
117 if (call.num_params () != type.num_params ())
119 if (type.is_variadic ())
121 if (call.num_params () < type.num_params ())
123 emit_unexpected_argument_error (
124 call.get_locus (), (unsigned long) call.num_params (),
125 (unsigned long) type.num_params ());
126 return;
129 else
131 emit_unexpected_argument_error (call.get_locus (),
132 (unsigned long) call.num_params (),
133 (unsigned long) type.num_params ());
134 return;
138 size_t i = 0;
139 for (auto &argument : call.get_arguments ())
141 location_t arg_locus = argument->get_locus ();
142 auto argument_expr_tyty
143 = Resolver::TypeCheckExpr::Resolve (argument.get ());
144 if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR)
146 rust_error_at (
147 argument->get_locus (),
148 "failed to resolve type for argument expr in CallExpr");
149 return;
152 // it might be a variadic function
153 if (i < type.num_params ())
155 auto fnparam = type.param_at (i);
156 HIR::Pattern *fn_param_pattern = fnparam.first;
157 BaseType *param_ty = fnparam.second;
158 location_t param_locus
159 = fn_param_pattern == nullptr
160 ? mappings->lookup_location (param_ty->get_ref ())
161 : fn_param_pattern->get_locus ();
163 HirId coercion_side_id = argument->get_mappings ().get_hirid ();
164 auto resolved_argument_type
165 = Resolver::coercion_site (coercion_side_id,
166 TyWithLocation (param_ty, param_locus),
167 TyWithLocation (argument_expr_tyty,
168 arg_locus),
169 argument->get_locus ());
170 if (resolved_argument_type->get_kind () == TyTy::TypeKind::ERROR)
172 return;
175 else
177 switch (argument_expr_tyty->get_kind ())
179 case TyTy::TypeKind::ERROR:
180 return;
181 case TyTy::TypeKind::INT: {
182 auto &int_ty
183 = static_cast<TyTy::IntType &> (*argument_expr_tyty);
184 if ((int_ty.get_int_kind () == TyTy::IntType::IntKind::I8)
185 || (int_ty.get_int_kind () == TyTy::IntType::IntKind::I16))
187 rich_location richloc (line_table, arg_locus);
188 richloc.add_fixit_replace (
189 "cast the value to c_int: as c_int");
190 rust_error_at (richloc, ErrorCode::E0617,
191 "expected %<c_int%> variadic argument");
192 return;
194 break;
196 case TyTy::TypeKind::UINT: {
197 auto &uint_ty
198 = static_cast<TyTy::UintType &> (*argument_expr_tyty);
199 if ((uint_ty.get_uint_kind () == TyTy::UintType::UintKind::U8)
200 || (uint_ty.get_uint_kind ()
201 == TyTy::UintType::UintKind::U16))
203 rich_location richloc (line_table, arg_locus);
204 richloc.add_fixit_replace (
205 "cast the value to c_uint: as c_uint");
206 rust_error_at (richloc, ErrorCode::E0617,
207 "expected %<c_uint%> variadic argument");
208 return;
210 break;
212 case TyTy::TypeKind::FLOAT: {
213 if (static_cast<TyTy::FloatType &> (*argument_expr_tyty)
214 .get_float_kind ()
215 == TyTy::FloatType::FloatKind::F32)
217 rich_location richloc (line_table, arg_locus);
218 richloc.add_fixit_replace (
219 "cast the value to c_double: as c_double");
220 rust_error_at (richloc, ErrorCode::E0617,
221 "expected %<c_double%> variadic argument");
222 return;
224 break;
226 case TyTy::TypeKind::BOOL: {
227 rich_location richloc (line_table, arg_locus);
228 richloc.add_fixit_replace ("cast the value to c_int: as c_int");
229 rust_error_at (arg_locus, ErrorCode::E0617,
230 "expected %<c_int%> variadic argument");
231 return;
233 case TyTy::TypeKind::FNDEF: {
234 rust_error_at (
235 arg_locus, ErrorCode::E0617,
236 "unexpected function definition type as variadic "
237 "argument - cast to function pointer");
239 return;
240 default:
241 break;
245 i++;
248 if (i < call.num_params ())
250 emit_unexpected_argument_error (call.get_locus (), (unsigned long) i,
251 (unsigned long) call.num_params ());
252 return;
255 type.monomorphize ();
256 resolved = type.get_return_type ()->clone ();
259 void
260 TypeCheckCallExpr::visit (FnPtr &type)
262 if (call.num_params () != type.num_params ())
264 emit_unexpected_argument_error (call.get_locus (),
265 (unsigned long) call.num_params (),
266 (unsigned long) type.num_params ());
267 return;
270 size_t i = 0;
271 for (auto &argument : call.get_arguments ())
273 location_t arg_locus = argument->get_locus ();
274 BaseType *fnparam = type.get_param_type_at (i);
275 auto argument_expr_tyty
276 = Resolver::TypeCheckExpr::Resolve (argument.get ());
277 if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR)
279 rust_error_at (
280 argument->get_locus (),
281 "failed to resolve type for argument expr in CallExpr");
282 return;
285 auto resolved_argument_type = Resolver::coercion_site (
286 argument->get_mappings ().get_hirid (), TyWithLocation (fnparam),
287 TyWithLocation (argument_expr_tyty, arg_locus), argument->get_locus ());
288 if (resolved_argument_type->get_kind () == TyTy::TypeKind::ERROR)
290 return;
293 i++;
296 if (i != call.num_params ())
298 emit_unexpected_argument_error (call.get_locus (), (unsigned long) i,
299 (unsigned long) call.num_params ());
300 return;
303 resolved = type.get_return_type ()->monomorphized_clone ();
306 // method call checker
308 TypeCheckMethodCallExpr::TypeCheckMethodCallExpr (
309 Analysis::NodeMapping call_mappings, std::vector<Argument> &args,
310 location_t call_locus, location_t receiver_locus,
311 TyTy::BaseType *adjusted_self, Resolver::TypeCheckContext *context)
312 : call_mappings (call_mappings), arguments (args), call_locus (call_locus),
313 receiver_locus (receiver_locus), adjusted_self (adjusted_self),
314 context (context), mappings (Analysis::Mappings::get ())
317 BaseType *
318 TypeCheckMethodCallExpr::go (FnType *ref, HIR::MethodCallExpr &call,
319 TyTy::BaseType *adjusted_self,
320 Resolver::TypeCheckContext *context)
322 std::vector<Argument> args;
323 for (auto &arg : call.get_arguments ())
325 BaseType *argument_expr_tyty
326 = Resolver::TypeCheckExpr::Resolve (arg.get ());
327 if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR)
329 rust_error_at (arg->get_locus (),
330 "failed to resolve type for argument");
331 return new ErrorType (ref->get_ref ());
334 Argument a (arg->get_mappings (), argument_expr_tyty, arg->get_locus ());
335 args.push_back (std::move (a));
338 TypeCheckMethodCallExpr checker (call.get_mappings (), args,
339 call.get_locus (),
340 call.get_receiver ()->get_locus (),
341 adjusted_self, context);
342 return checker.check (*ref);
345 BaseType *
346 TypeCheckMethodCallExpr::go (FnType *ref, Analysis::NodeMapping call_mappings,
347 std::vector<Argument> &args, location_t call_locus,
348 location_t receiver_locus,
349 TyTy::BaseType *adjusted_self,
350 Resolver::TypeCheckContext *context)
352 TypeCheckMethodCallExpr checker (call_mappings, args, call_locus,
353 receiver_locus, adjusted_self, context);
354 return checker.check (*ref);
357 BaseType *
358 TypeCheckMethodCallExpr::check (FnType &type)
360 Resolver::unify_site (call_mappings.get_hirid (),
361 TyWithLocation (type.get_self_type ()),
362 TyWithLocation (adjusted_self, receiver_locus),
363 call_locus);
365 // +1 for the receiver self
366 size_t num_args_to_call = arguments.size () + 1;
367 if (num_args_to_call != type.num_params ())
369 emit_unexpected_argument_error (call_locus,
370 (unsigned long) num_args_to_call,
371 (unsigned long) type.num_params ());
372 return new ErrorType (type.get_ref ());
375 size_t i = 1;
376 for (auto &argument : arguments)
378 location_t arg_locus = argument.get_locus ();
380 auto fnparam = type.param_at (i);
381 HIR::Pattern *fn_param_pattern = fnparam.first;
382 BaseType *param_ty = fnparam.second;
383 location_t param_locus
384 = fn_param_pattern == nullptr
385 ? mappings->lookup_location (param_ty->get_ref ())
386 : fn_param_pattern->get_locus ();
388 auto argument_expr_tyty = argument.get_argument_type ();
389 HirId coercion_side_id = argument.get_mappings ().get_hirid ();
390 auto resolved_argument_type = Resolver::coercion_site (
391 coercion_side_id, TyWithLocation (param_ty, param_locus),
392 TyWithLocation (argument_expr_tyty, arg_locus), arg_locus);
393 if (resolved_argument_type->get_kind () == TyTy::TypeKind::ERROR)
395 return new ErrorType (type.get_ref ());
398 i++;
401 if (i != num_args_to_call)
403 emit_unexpected_argument_error (call_locus, (unsigned long) i,
404 (unsigned long) arguments.size ());
405 return new ErrorType (type.get_ref ());
408 type.monomorphize ();
410 return type.get_return_type ()->monomorphized_clone ();
413 } // namespace TyTy
414 } // namespace Rust