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
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
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"
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";
40 err_msg
+= "arguments";
43 if (unexpected_arg_count
== 1)
45 err_msg
+= " but %lu argument was supplied";
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
);
56 TypeCheckCallExpr::visit (ADTType
&type
)
58 rust_assert (!variant
.is_error ());
59 if (variant
.get_variant_type () != TyTy::VariantDef::VariantType::TUPLE
)
62 call
.get_locus (), ErrorCode::E0423
,
63 "expected function, tuple struct or tuple variant, found struct %qs",
64 type
.get_name ().c_str ());
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 ());
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");
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
)
104 if (i
!= call
.num_params ())
106 emit_unexpected_argument_error (call
.get_locus (), (unsigned long) i
,
107 (unsigned long) call
.num_params ());
111 resolved
= type
.clone ();
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 ());
131 emit_unexpected_argument_error (call
.get_locus (),
132 (unsigned long) call
.num_params (),
133 (unsigned long) type
.num_params ());
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
)
147 argument
->get_locus (),
148 "failed to resolve type for argument expr in CallExpr");
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
,
169 argument
->get_locus ());
170 if (resolved_argument_type
->get_kind () == TyTy::TypeKind::ERROR
)
177 switch (argument_expr_tyty
->get_kind ())
179 case TyTy::TypeKind::ERROR
:
181 case TyTy::TypeKind::INT
: {
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");
196 case TyTy::TypeKind::UINT
: {
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");
212 case TyTy::TypeKind::FLOAT
: {
213 if (static_cast<TyTy::FloatType
&> (*argument_expr_tyty
)
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");
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");
233 case TyTy::TypeKind::FNDEF
: {
235 arg_locus
, ErrorCode::E0617
,
236 "unexpected function definition type as variadic "
237 "argument - cast to function pointer");
248 if (i
< call
.num_params ())
250 emit_unexpected_argument_error (call
.get_locus (), (unsigned long) i
,
251 (unsigned long) call
.num_params ());
255 type
.monomorphize ();
256 resolved
= type
.get_return_type ()->clone ();
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 ());
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
)
280 argument
->get_locus (),
281 "failed to resolve type for argument expr in CallExpr");
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
)
296 if (i
!= call
.num_params ())
298 emit_unexpected_argument_error (call
.get_locus (), (unsigned long) i
,
299 (unsigned long) call
.num_params ());
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 ())
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
,
340 call
.get_receiver ()->get_locus (),
341 adjusted_self
, context
);
342 return checker
.check (*ref
);
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
);
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
),
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 ());
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 ());
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 ();