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-type-util.h"
22 :
23 : namespace Rust {
24 : namespace TyTy {
25 :
26 : void
27 4 : 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 4 : std::string err_msg = "this function takes %lu ";
34 4 : if (expected_arg_count == 1)
35 : {
36 1 : err_msg += "argument";
37 : }
38 : else
39 : {
40 3 : err_msg += "arguments";
41 : }
42 :
43 4 : if (unexpected_arg_count == 1)
44 : {
45 1 : err_msg += " but %lu argument was supplied";
46 : }
47 : else
48 : {
49 3 : err_msg += " but %lu arguments were supplied";
50 : }
51 4 : rust_error_at (loc, ErrorCode::E0061, err_msg.c_str (), expected_arg_count,
52 : unexpected_arg_count);
53 4 : }
54 :
55 : void
56 1811 : TypeCheckCallExpr::visit (ADTType &type)
57 : {
58 1811 : rust_assert (!variant.is_error ());
59 1811 : if (variant.get_variant_type () != TyTy::VariantDef::VariantType::TUPLE)
60 : {
61 3 : rust_error_at (
62 3 : call.get_locus (), ErrorCode::E0618,
63 : "expected function, tuple struct or tuple variant, found struct %qs",
64 3 : type.get_name ().c_str ());
65 3 : return;
66 : }
67 :
68 1808 : if (call.num_params () != variant.num_fields ())
69 : {
70 2 : emit_unexpected_argument_error (call.get_locus (),
71 1 : (unsigned long) call.num_params (),
72 1 : (unsigned long) variant.num_fields ());
73 1 : return;
74 : }
75 :
76 1807 : size_t i = 0;
77 4121 : for (auto &argument : call.get_arguments ())
78 : {
79 2315 : StructFieldType *field = variant.get_field_at_index (i);
80 2315 : BaseType *field_tyty = field->get_field_type ();
81 2315 : location_t arg_locus = argument->get_locus ();
82 :
83 2315 : BaseType *arg = Resolver::TypeCheckExpr::Resolve (*argument);
84 2315 : 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 2315 : HirId coercion_side_id = argument->get_mappings ().get_hirid ();
92 4630 : auto res = Resolver::coercion_site (coercion_side_id,
93 2315 : TyWithLocation (field_tyty),
94 2315 : TyWithLocation (arg, arg_locus),
95 2315 : argument->get_locus ());
96 2315 : if (res->get_kind () == TyTy::TypeKind::ERROR)
97 : {
98 : return;
99 : }
100 :
101 2314 : i++;
102 : }
103 :
104 1806 : 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 1806 : resolved = type.clone ();
112 : }
113 :
114 : void
115 9112 : TypeCheckCallExpr::visit (FnType &type)
116 : {
117 9112 : if (call.num_params () != type.num_params ())
118 : {
119 732 : if (type.is_variadic ())
120 : {
121 729 : 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 3 : emit_unexpected_argument_error (call.get_locus (),
132 3 : (unsigned long) call.num_params (),
133 3 : (unsigned long) type.num_params ());
134 3 : return;
135 : }
136 : }
137 :
138 : size_t i = 0;
139 19732 : for (auto &argument : call.get_arguments ())
140 : {
141 10638 : location_t arg_locus = argument->get_locus ();
142 10638 : auto argument_expr_tyty = Resolver::TypeCheckExpr::Resolve (*argument);
143 10638 : if (argument_expr_tyty->is<TyTy::ErrorType> ())
144 9112 : return;
145 :
146 : // it might be a variadic function
147 10636 : if (i < type.num_params ())
148 : {
149 9858 : auto &fnparam = type.param_at (i);
150 9858 : BaseType *param_ty = fnparam.get_type ();
151 9858 : location_t param_locus
152 9858 : = fnparam.has_pattern ()
153 9858 : ? fnparam.get_pattern ().get_locus ()
154 0 : : mappings.lookup_location (param_ty->get_ref ());
155 :
156 9858 : HirId coercion_side_id = argument->get_mappings ().get_hirid ();
157 9858 : auto resolved_argument_type
158 9858 : = Resolver::coercion_site (coercion_side_id,
159 9858 : TyWithLocation (param_ty, param_locus),
160 : TyWithLocation (argument_expr_tyty,
161 9858 : arg_locus),
162 9858 : argument->get_locus ());
163 9858 : if (resolved_argument_type->get_kind () == TyTy::TypeKind::ERROR)
164 : {
165 : return;
166 : }
167 : }
168 : else
169 : {
170 778 : switch (argument_expr_tyty->get_kind ())
171 : {
172 : case TyTy::TypeKind::ERROR:
173 : return;
174 453 : case TyTy::TypeKind::INT:
175 453 : {
176 453 : auto &int_ty
177 : = static_cast<TyTy::IntType &> (*argument_expr_tyty);
178 453 : if ((int_ty.get_int_kind () == TyTy::IntType::IntKind::I8)
179 453 : || (int_ty.get_int_kind () == TyTy::IntType::IntKind::I16))
180 : {
181 1 : rich_location richloc (line_table, arg_locus);
182 1 : richloc.add_fixit_replace (
183 : "cast the value to c_int: as c_int");
184 1 : rust_error_at (richloc, ErrorCode::E0617,
185 : "expected %<c_int%> variadic argument");
186 1 : return;
187 1 : }
188 : break;
189 : }
190 78 : case TyTy::TypeKind::UINT:
191 78 : {
192 78 : auto &uint_ty
193 : = static_cast<TyTy::UintType &> (*argument_expr_tyty);
194 78 : if ((uint_ty.get_uint_kind () == TyTy::UintType::UintKind::U8)
195 78 : || (uint_ty.get_uint_kind ()
196 : == TyTy::UintType::UintKind::U16))
197 : {
198 1 : rich_location richloc (line_table, arg_locus);
199 1 : richloc.add_fixit_replace (
200 : "cast the value to c_uint: as c_uint");
201 1 : rust_error_at (richloc, ErrorCode::E0617,
202 : "expected %<c_uint%> variadic argument");
203 1 : return;
204 1 : }
205 : break;
206 : }
207 1 : case TyTy::TypeKind::FLOAT:
208 1 : {
209 1 : if (static_cast<TyTy::FloatType &> (*argument_expr_tyty)
210 1 : .get_float_kind ()
211 : == TyTy::FloatType::FloatKind::F32)
212 : {
213 1 : rich_location richloc (line_table, arg_locus);
214 1 : richloc.add_fixit_replace (
215 : "cast the value to c_double: as c_double");
216 1 : rust_error_at (richloc, ErrorCode::E0617,
217 : "expected %<c_double%> variadic argument");
218 1 : return;
219 1 : }
220 : break;
221 : }
222 0 : case TyTy::TypeKind::BOOL:
223 0 : {
224 0 : rich_location richloc (line_table, arg_locus);
225 0 : richloc.add_fixit_replace ("cast the value to c_int: as c_int");
226 0 : rust_error_at (arg_locus, ErrorCode::E0617,
227 : "expected %<c_int%> variadic argument");
228 0 : return;
229 0 : }
230 0 : case TyTy::TypeKind::FNDEF:
231 0 : {
232 0 : rust_error_at (
233 : arg_locus, ErrorCode::E0617,
234 : "unexpected function definition type as variadic "
235 : "argument - cast to function pointer");
236 : }
237 0 : return;
238 : default:
239 : break;
240 : }
241 : }
242 :
243 10623 : i++;
244 : }
245 :
246 9094 : if (i < call.num_params ())
247 : {
248 0 : emit_unexpected_argument_error (call.get_locus (), (unsigned long) i,
249 0 : (unsigned long) call.num_params ());
250 0 : return;
251 : }
252 :
253 9094 : type.monomorphize ();
254 9094 : resolved = type.get_return_type ()->monomorphized_clone ();
255 : }
256 :
257 : void
258 29 : TypeCheckCallExpr::visit (FnPtr &type)
259 : {
260 29 : if (call.num_params () != type.num_params ())
261 : {
262 0 : emit_unexpected_argument_error (call.get_locus (),
263 0 : (unsigned long) call.num_params (),
264 0 : (unsigned long) type.num_params ());
265 0 : return;
266 : }
267 :
268 : size_t i = 0;
269 57 : for (auto &argument : call.get_arguments ())
270 : {
271 29 : location_t arg_locus = argument->get_locus ();
272 29 : BaseType *fnparam = type.get_param_type_at (i);
273 29 : auto argument_expr_tyty = Resolver::TypeCheckExpr::Resolve (*argument);
274 29 : if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR)
275 : {
276 0 : rust_error_at (
277 0 : argument->get_locus (),
278 : "failed to resolve type for argument expr in CallExpr");
279 0 : return;
280 : }
281 :
282 58 : auto resolved_argument_type = Resolver::coercion_site (
283 29 : argument->get_mappings ().get_hirid (), TyWithLocation (fnparam),
284 29 : TyWithLocation (argument_expr_tyty, arg_locus), argument->get_locus ());
285 29 : if (resolved_argument_type->get_kind () == TyTy::TypeKind::ERROR)
286 : {
287 : return;
288 : }
289 :
290 28 : i++;
291 : }
292 :
293 28 : if (i != call.num_params ())
294 : {
295 0 : emit_unexpected_argument_error (call.get_locus (), (unsigned long) i,
296 0 : (unsigned long) call.num_params ());
297 0 : return;
298 : }
299 :
300 28 : resolved = type.get_return_type ()->monomorphized_clone ();
301 : }
302 :
303 : // method call checker
304 :
305 3028 : TypeCheckMethodCallExpr::TypeCheckMethodCallExpr (
306 : Analysis::NodeMapping call_mappings, std::vector<Argument> &args,
307 : location_t call_locus, location_t receiver_locus,
308 3028 : TyTy::BaseType *adjusted_self, Resolver::TypeCheckContext *context)
309 3028 : : call_mappings (call_mappings), arguments (args), call_locus (call_locus),
310 3028 : receiver_locus (receiver_locus), adjusted_self (adjusted_self),
311 3028 : context (context), mappings (Analysis::Mappings::get ())
312 3028 : {}
313 :
314 : BaseType *
315 2962 : TypeCheckMethodCallExpr::go (FnType *ref, HIR::MethodCallExpr &call,
316 : TyTy::BaseType *adjusted_self,
317 : Resolver::TypeCheckContext *context)
318 : {
319 2962 : std::vector<Argument> args;
320 4995 : for (auto &arg : call.get_arguments ())
321 : {
322 2033 : BaseType *argument_expr_tyty = Resolver::TypeCheckExpr::Resolve (*arg);
323 2033 : if (argument_expr_tyty->get_kind () == TyTy::TypeKind::ERROR)
324 : {
325 0 : rust_error_at (arg->get_locus (),
326 : "failed to resolve type for argument");
327 0 : return new ErrorType (ref->get_ref ());
328 : }
329 :
330 2033 : args.emplace_back (arg->get_mappings (), argument_expr_tyty,
331 2033 : arg->get_locus ());
332 : }
333 :
334 2962 : TypeCheckMethodCallExpr checker (call.get_mappings (), args,
335 : call.get_locus (),
336 2962 : call.get_receiver ().get_locus (),
337 2962 : adjusted_self, context);
338 2962 : return checker.check (*ref);
339 2962 : }
340 :
341 : BaseType *
342 66 : TypeCheckMethodCallExpr::go (FnType *ref, Analysis::NodeMapping call_mappings,
343 : std::vector<Argument> &args, location_t call_locus,
344 : location_t receiver_locus,
345 : TyTy::BaseType *adjusted_self,
346 : Resolver::TypeCheckContext *context)
347 : {
348 66 : TypeCheckMethodCallExpr checker (call_mappings, args, call_locus,
349 66 : receiver_locus, adjusted_self, context);
350 66 : return checker.check (*ref);
351 : }
352 :
353 : BaseType *
354 3028 : TypeCheckMethodCallExpr::check (FnType &type)
355 : {
356 3028 : Resolver::unify_site (call_mappings.get_hirid (),
357 3028 : TyWithLocation (type.get_self_type ()),
358 3028 : TyWithLocation (adjusted_self, receiver_locus),
359 : call_locus);
360 :
361 : // +1 for the receiver self
362 3028 : size_t num_args_to_call = arguments.size () + 1;
363 3028 : if (num_args_to_call != type.num_params ())
364 : {
365 0 : emit_unexpected_argument_error (call_locus,
366 : (unsigned long) num_args_to_call,
367 0 : (unsigned long) type.num_params ());
368 0 : return new ErrorType (type.get_ref ());
369 : }
370 :
371 : size_t i = 1;
372 5127 : for (auto &argument : arguments)
373 : {
374 2099 : location_t arg_locus = argument.get_locus ();
375 :
376 2099 : auto &fnparam = type.param_at (i);
377 2099 : BaseType *param_ty = fnparam.get_type ();
378 2099 : location_t param_locus
379 2099 : = fnparam.has_pattern ()
380 2099 : ? fnparam.get_pattern ().get_locus ()
381 0 : : mappings.lookup_location (param_ty->get_ref ());
382 :
383 2099 : auto argument_expr_tyty = argument.get_argument_type ();
384 2099 : HirId coercion_side_id = argument.get_mappings ().get_hirid ();
385 2099 : auto resolved_argument_type = Resolver::coercion_site (
386 2099 : coercion_side_id, TyWithLocation (param_ty, param_locus),
387 2099 : TyWithLocation (argument_expr_tyty, arg_locus), arg_locus);
388 2099 : if (resolved_argument_type->get_kind () == TyTy::TypeKind::ERROR)
389 : {
390 0 : return new ErrorType (type.get_ref ());
391 : }
392 :
393 2099 : i++;
394 : }
395 :
396 3028 : if (i != num_args_to_call)
397 : {
398 0 : emit_unexpected_argument_error (call_locus, (unsigned long) i,
399 0 : (unsigned long) arguments.size ());
400 0 : return new ErrorType (type.get_ref ());
401 : }
402 :
403 3028 : type.monomorphize ();
404 :
405 3028 : return type.get_return_type ()->monomorphized_clone ();
406 : }
407 :
408 : } // namespace TyTy
409 : } // namespace Rust
|