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 : 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 : 1782 : TypeCheckCallExpr::visit (ADTType &type)
57 : : {
58 : 1782 : rust_assert (!variant.is_error ());
59 : 1782 : if (variant.get_variant_type () != TyTy::VariantDef::VariantType::TUPLE)
60 : : {
61 : 3 : rust_error_at (
62 : 3 : call.get_locus (), ErrorCode::E0423,
63 : : "expected function, tuple struct or tuple variant, found struct %qs",
64 : 3 : type.get_name ().c_str ());
65 : 3 : return;
66 : : }
67 : :
68 : 1779 : 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 : 1778 : size_t i = 0;
77 : 4025 : for (auto &argument : call.get_arguments ())
78 : : {
79 : 2248 : StructFieldType *field = variant.get_field_at_index (i);
80 : 2248 : BaseType *field_tyty = field->get_field_type ();
81 : 2248 : location_t arg_locus = argument->get_locus ();
82 : :
83 : 2248 : BaseType *arg = Resolver::TypeCheckExpr::Resolve (*argument);
84 : 2248 : 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 : 2248 : HirId coercion_side_id = argument->get_mappings ().get_hirid ();
92 : 4496 : auto res = Resolver::coercion_site (coercion_side_id,
93 : 2248 : TyWithLocation (field_tyty),
94 : 2248 : TyWithLocation (arg, arg_locus),
95 : 2248 : argument->get_locus ());
96 : 2248 : if (res->get_kind () == TyTy::TypeKind::ERROR)
97 : : {
98 : : return;
99 : : }
100 : :
101 : 2247 : i++;
102 : : }
103 : :
104 : 1777 : 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 : 1777 : resolved = type.clone ();
112 : : }
113 : :
114 : : void
115 : 8984 : TypeCheckCallExpr::visit (FnType &type)
116 : : {
117 : 8984 : if (call.num_params () != type.num_params ())
118 : : {
119 : 725 : if (type.is_variadic ())
120 : : {
121 : 722 : 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 : 19475 : for (auto &argument : call.get_arguments ())
140 : : {
141 : 10509 : location_t arg_locus = argument->get_locus ();
142 : 10509 : auto argument_expr_tyty = Resolver::TypeCheckExpr::Resolve (*argument);
143 : 10509 : if (argument_expr_tyty->is<TyTy::ErrorType> ())
144 : 8984 : return;
145 : :
146 : : // it might be a variadic function
147 : 10507 : if (i < type.num_params ())
148 : : {
149 : 9736 : auto &fnparam = type.param_at (i);
150 : 9736 : BaseType *param_ty = fnparam.get_type ();
151 : 9736 : location_t param_locus
152 : 9736 : = fnparam.has_pattern ()
153 : 9736 : ? fnparam.get_pattern ().get_locus ()
154 : 0 : : mappings.lookup_location (param_ty->get_ref ());
155 : :
156 : 9736 : HirId coercion_side_id = argument->get_mappings ().get_hirid ();
157 : 9736 : auto resolved_argument_type
158 : 9736 : = Resolver::coercion_site (coercion_side_id,
159 : 9736 : TyWithLocation (param_ty, param_locus),
160 : : TyWithLocation (argument_expr_tyty,
161 : 9736 : arg_locus),
162 : 9736 : argument->get_locus ());
163 : 9736 : if (resolved_argument_type->get_kind () == TyTy::TypeKind::ERROR)
164 : : {
165 : : return;
166 : : }
167 : : }
168 : : else
169 : : {
170 : 771 : 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 : 10494 : i++;
244 : : }
245 : :
246 : 8966 : 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 : 8966 : type.monomorphize ();
254 : 8966 : 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 : 3018 : TypeCheckMethodCallExpr::TypeCheckMethodCallExpr (
306 : : Analysis::NodeMapping call_mappings, std::vector<Argument> &args,
307 : : location_t call_locus, location_t receiver_locus,
308 : 3018 : TyTy::BaseType *adjusted_self, Resolver::TypeCheckContext *context)
309 : 3018 : : call_mappings (call_mappings), arguments (args), call_locus (call_locus),
310 : 3018 : receiver_locus (receiver_locus), adjusted_self (adjusted_self),
311 : 3018 : context (context), mappings (Analysis::Mappings::get ())
312 : 3018 : {}
313 : :
314 : : BaseType *
315 : 2952 : TypeCheckMethodCallExpr::go (FnType *ref, HIR::MethodCallExpr &call,
316 : : TyTy::BaseType *adjusted_self,
317 : : Resolver::TypeCheckContext *context)
318 : : {
319 : 2952 : std::vector<Argument> args;
320 : 4982 : for (auto &arg : call.get_arguments ())
321 : : {
322 : 2030 : BaseType *argument_expr_tyty = Resolver::TypeCheckExpr::Resolve (*arg);
323 : 2030 : 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 : 2030 : Argument a (arg->get_mappings (), argument_expr_tyty, arg->get_locus ());
331 : 2030 : args.push_back (std::move (a));
332 : : }
333 : :
334 : 2952 : TypeCheckMethodCallExpr checker (call.get_mappings (), args,
335 : : call.get_locus (),
336 : 2952 : call.get_receiver ().get_locus (),
337 : 2952 : adjusted_self, context);
338 : 2952 : return checker.check (*ref);
339 : 2952 : }
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 : 3018 : TypeCheckMethodCallExpr::check (FnType &type)
355 : : {
356 : 3018 : Resolver::unify_site (call_mappings.get_hirid (),
357 : 3018 : TyWithLocation (type.get_self_type ()),
358 : 3018 : TyWithLocation (adjusted_self, receiver_locus),
359 : : call_locus);
360 : :
361 : : // +1 for the receiver self
362 : 3018 : size_t num_args_to_call = arguments.size () + 1;
363 : 3018 : 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 : 5114 : for (auto &argument : arguments)
373 : : {
374 : 2096 : location_t arg_locus = argument.get_locus ();
375 : :
376 : 2096 : auto &fnparam = type.param_at (i);
377 : 2096 : BaseType *param_ty = fnparam.get_type ();
378 : 2096 : location_t param_locus
379 : 2096 : = fnparam.has_pattern ()
380 : 2096 : ? fnparam.get_pattern ().get_locus ()
381 : 0 : : mappings.lookup_location (param_ty->get_ref ());
382 : :
383 : 2096 : auto argument_expr_tyty = argument.get_argument_type ();
384 : 2096 : HirId coercion_side_id = argument.get_mappings ().get_hirid ();
385 : 2096 : auto resolved_argument_type = Resolver::coercion_site (
386 : 2096 : coercion_side_id, TyWithLocation (param_ty, param_locus),
387 : 2096 : TyWithLocation (argument_expr_tyty, arg_locus), arg_locus);
388 : 2096 : if (resolved_argument_type->get_kind () == TyTy::TypeKind::ERROR)
389 : : {
390 : 0 : return new ErrorType (type.get_ref ());
391 : : }
392 : :
393 : 2096 : i++;
394 : : }
395 : :
396 : 3018 : 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 : 3018 : type.monomorphize ();
404 : :
405 : 3018 : return type.get_return_type ()->monomorphized_clone ();
406 : : }
407 : :
408 : : } // namespace TyTy
409 : : } // namespace Rust
|