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