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 "optional.h"
20 : #include "rust-common.h"
21 : #include "rust-diagnostics.h"
22 : #include "rust-hir-expr.h"
23 : #include "rust-hir-map.h"
24 : #include "rust-rib.h"
25 : #include "rust-system.h"
26 : #include "rust-tyty-call.h"
27 : #include "rust-hir-type-check-struct-field.h"
28 : #include "rust-hir-path-probe.h"
29 : #include "rust-substitution-mapper.h"
30 : #include "rust-hir-trait-resolve.h"
31 : #include "rust-hir-dot-operator.h"
32 : #include "rust-hir-type-check-pattern.h"
33 : #include "rust-hir-type-check-expr.h"
34 : #include "rust-hir-type-check-stmt.h"
35 : #include "rust-hir-type-check-item.h"
36 : #include "rust-type-util.h"
37 : #include "rust-finalized-name-resolution-context.h"
38 : #include "rust-compile-base.h"
39 : #include "rust-tyty-util.h"
40 : #include "rust-tyty.h"
41 :
42 : namespace Rust {
43 : namespace Resolver {
44 :
45 163613 : TypeCheckExpr::TypeCheckExpr () : TypeCheckBase (), infered (nullptr) {}
46 :
47 : TyTy::BaseType *
48 163598 : TypeCheckExpr::Resolve (HIR::Expr &expr)
49 : {
50 163598 : TypeCheckExpr resolver;
51 163598 : expr.accept_vis (resolver);
52 :
53 163594 : if (resolver.infered == nullptr)
54 102 : return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
55 :
56 163492 : if (resolver.infered->get_kind () != TyTy::TypeKind::CONST)
57 : {
58 163344 : auto ref = expr.get_mappings ().get_hirid ();
59 163344 : resolver.infered->set_ref (ref);
60 : }
61 163492 : resolver.context->insert_type (expr.get_mappings (), resolver.infered);
62 :
63 163492 : if (auto fn = resolver.infered->try_as<const TyTy::FnType> ())
64 : {
65 11858 : if (fn->is_syn_constant ())
66 28 : resolver.infered = fn->get_return_type ();
67 : }
68 :
69 163492 : return resolver.infered;
70 163594 : }
71 :
72 : TyTy::BaseType *
73 15 : TypeCheckExpr::ResolveOpOverload (LangItem::Kind lang_item_type,
74 : HIR::OperatorExprMeta expr,
75 : TyTy::BaseType *lhs, TyTy::BaseType *rhs,
76 : HIR::PathIdentSegment specified_segment,
77 : TyTy::BaseType *result_type)
78 : {
79 15 : TypeCheckExpr resolver;
80 :
81 30 : resolver.resolve_operator_overload (lang_item_type, expr, lhs, rhs,
82 : specified_segment, false, result_type);
83 15 : return resolver.infered;
84 15 : }
85 :
86 : void
87 935 : TypeCheckExpr::visit (HIR::TupleIndexExpr &expr)
88 : {
89 935 : auto resolved
90 935 : = TypeCheckExpr::Resolve (expr.get_tuple_expr ())->destructure ();
91 935 : if (resolved->get_kind () == TyTy::TypeKind::ERROR)
92 : {
93 2 : rust_error_at (expr.get_tuple_expr ().get_locus (),
94 : "failed to resolve TupleIndexExpr receiver");
95 2 : return;
96 : }
97 :
98 : // Box<T> autoderef
99 933 : if (auto resolved_base = TyTy::try_get_box_inner_type (resolved))
100 : {
101 2 : resolved = *resolved_base;
102 : }
103 :
104 : // FIXME does this require autoderef here?
105 933 : if (resolved->get_kind () == TyTy::TypeKind::REF)
106 : {
107 323 : TyTy::ReferenceType *r = static_cast<TyTy::ReferenceType *> (resolved);
108 323 : resolved = r->get_base ();
109 : }
110 :
111 933 : bool is_valid_type = resolved->get_kind () == TyTy::TypeKind::ADT
112 933 : || resolved->get_kind () == TyTy::TypeKind::TUPLE;
113 2 : if (!is_valid_type)
114 : {
115 2 : rust_error_at (expr.get_tuple_expr ().get_locus (),
116 : "Expected Tuple or ADT got: %s",
117 2 : resolved->as_string ().c_str ());
118 2 : return;
119 : }
120 :
121 931 : if (resolved->get_kind () == TyTy::TypeKind::TUPLE)
122 : {
123 159 : TyTy::TupleType *tuple = static_cast<TyTy::TupleType *> (resolved);
124 159 : TupleIndex index = expr.get_tuple_index ();
125 159 : if ((size_t) index >= tuple->num_fields ())
126 : {
127 1 : rust_error_at (expr.get_locus (), ErrorCode::E0609,
128 : "no field %qi on type %qs", index,
129 1 : resolved->get_name ().c_str ());
130 1 : return;
131 : }
132 :
133 158 : auto field_tyty = tuple->get_field ((size_t) index);
134 158 : if (field_tyty == nullptr)
135 : {
136 0 : rust_error_at (expr.get_locus (),
137 : "failed to lookup field type at index %i", index);
138 0 : return;
139 : }
140 :
141 158 : infered = field_tyty;
142 158 : return;
143 : }
144 :
145 772 : TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (resolved);
146 772 : if (!adt->is_tuple_struct ())
147 : {
148 4 : rust_error_at (expr.get_locus (),
149 : "expected tuple or tuple struct, found %qs",
150 4 : adt->get_name ().c_str ());
151 4 : return;
152 : }
153 768 : rust_assert (adt->number_of_variants () == 1);
154 :
155 768 : TyTy::VariantDef *variant = adt->get_variants ().at (0);
156 768 : TupleIndex index = expr.get_tuple_index ();
157 768 : if ((size_t) index >= variant->num_fields ())
158 : {
159 0 : rust_error_at (expr.get_locus (), "unknown field at index %i", index);
160 0 : return;
161 : }
162 :
163 768 : auto field_tyty = variant->get_field_at_index ((size_t) index);
164 768 : if (field_tyty == nullptr)
165 : {
166 0 : rust_error_at (expr.get_locus (),
167 : "failed to lookup field type at index %i", index);
168 0 : return;
169 : }
170 :
171 768 : infered = field_tyty->get_field_type ();
172 : }
173 :
174 : void
175 656 : TypeCheckExpr::visit (HIR::TupleExpr &expr)
176 : {
177 656 : if (expr.is_unit ())
178 : {
179 152 : infered = TyTy::TupleType::get_unit_type ();
180 152 : return;
181 : }
182 :
183 504 : std::vector<TyTy::TyVar> fields;
184 1642 : for (auto &elem : expr.get_tuple_elems ())
185 : {
186 1138 : auto field_ty = TypeCheckExpr::Resolve (*elem);
187 1138 : fields.emplace_back (field_ty->get_ref ());
188 : }
189 1008 : infered = new TyTy::TupleType (expr.get_mappings ().get_hirid (),
190 1008 : expr.get_locus (), fields);
191 504 : }
192 :
193 : void
194 6 : TypeCheckExpr::visit (HIR::BoxExpr &expr)
195 : {
196 6 : auto owned_box_defid
197 6 : = mappings.get_lang_item (LangItem::Kind::OWNED_BOX, expr.get_locus ());
198 :
199 6 : HIR::Item *item = mappings.lookup_defid (owned_box_defid).value ();
200 6 : TyTy::BaseType *item_type = TypeCheckItem::Resolve (*item);
201 :
202 6 : if (item_type->get_kind () != TyTy::TypeKind::ADT)
203 : {
204 0 : rust_error_at (item->get_locus (), ErrorCode::E0718,
205 : "%qs language item must be applied to a struct",
206 : "owned_box");
207 2 : return;
208 : }
209 6 : TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (item_type);
210 6 : if (!adt->is_tuple_struct () && !adt->is_struct_struct ())
211 : {
212 1 : rust_error_at (item->get_locus (), ErrorCode::E0718,
213 : "%qs language item must be applied to a struct",
214 : "owned_box");
215 1 : return;
216 : }
217 :
218 : // this is at least one generic item
219 5 : if (adt->get_num_substitutions () < 1)
220 : {
221 1 : rust_error_at (expr.get_locus (),
222 : "%qs lang item must be applied to a struct with at least "
223 : "1 generic argument",
224 : "owned_box");
225 1 : return;
226 : }
227 :
228 4 : TyTy::BaseType *inner_ty = TypeCheckExpr::Resolve (expr.get_expr ());
229 4 : if (inner_ty->get_kind () == TyTy::TypeKind::ERROR)
230 : {
231 0 : infered = inner_ty;
232 0 : return;
233 : }
234 :
235 4 : auto lookup = SubstMapper::InferSubst (adt, expr.get_locus ());
236 4 : rust_assert (lookup->get_kind () == TyTy::TypeKind::ADT);
237 4 : TyTy::ADTType *adt_box = static_cast<TyTy::ADTType *> (lookup);
238 :
239 4 : TyTy::BaseType *infer = adt_box->get_substs ().at (0).get_param_ty ();
240 :
241 8 : unify_site (expr.get_mappings ().get_hirid (),
242 4 : TyTy::TyWithLocation (infer, expr.get_locus ()),
243 4 : TyTy::TyWithLocation (inner_ty, expr.get_locus ()),
244 : expr.get_locus ());
245 :
246 4 : infered = adt_box;
247 : }
248 :
249 : void
250 643 : TypeCheckExpr::visit (HIR::ReturnExpr &expr)
251 : {
252 643 : if (!context->have_function_context ())
253 : {
254 1 : rust_error_at (expr.get_locus (), ErrorCode::E0572,
255 : "return statement outside of function body");
256 1 : infered = new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
257 1 : return;
258 : }
259 :
260 642 : auto fn_return_tyty = context->peek_return_type ();
261 642 : location_t expr_locus = expr.has_return_expr ()
262 642 : ? expr.get_expr ().get_locus ()
263 37 : : expr.get_locus ();
264 :
265 : // Push expected type so the resolver of the return expression
266 : // inference before checking its arguments which is needed
267 : // for things like:
268 : //
269 : // return Try::from_error(...)
270 : //
271 : // Where Self has to bind from the fn return type before the param
272 : // projection can be normalized.
273 642 : TyTy::BaseType *expr_ty;
274 642 : if (expr.has_return_expr ())
275 : {
276 605 : context->push_expected_type (fn_return_tyty);
277 605 : expr_ty = TypeCheckExpr::Resolve (expr.get_expr ());
278 605 : context->pop_expected_type ();
279 : }
280 : else
281 37 : expr_ty = TyTy::TupleType::get_unit_type ();
282 :
283 1284 : coercion_site (expr.get_mappings ().get_hirid (),
284 642 : TyTy::TyWithLocation (fn_return_tyty),
285 642 : TyTy::TyWithLocation (expr_ty, expr_locus), expr.get_locus ());
286 :
287 642 : infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ());
288 : }
289 :
290 : void
291 13812 : TypeCheckExpr::visit (HIR::CallExpr &expr)
292 : {
293 13812 : TyTy::BaseType *function_tyty = TypeCheckExpr::Resolve (expr.get_fnexpr ());
294 :
295 13811 : rust_debug_loc (expr.get_locus (), "resolved_call_expr to: {%s}",
296 : function_tyty->get_name ().c_str ());
297 :
298 13811 : TyTy::VariantDef &variant = TyTy::VariantDef::get_error_node ();
299 13811 : if (function_tyty->get_kind () == TyTy::TypeKind::ADT)
300 : {
301 1937 : TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (function_tyty);
302 1937 : if (adt->is_enum ())
303 : {
304 : // lookup variant id
305 997 : HirId variant_id;
306 997 : bool ok = context->lookup_variant_definition (
307 997 : expr.get_fnexpr ().get_mappings ().get_hirid (), &variant_id);
308 :
309 997 : if (!ok)
310 : {
311 1 : rust_error_at (expr.get_locus (), ErrorCode::E0423,
312 : "expected function, tuple struct or tuple "
313 : "variant, found enum");
314 1 : return;
315 : }
316 :
317 996 : TyTy::VariantDef *lookup_variant = nullptr;
318 996 : ok = adt->lookup_variant_by_id (variant_id, &lookup_variant);
319 996 : rust_assert (ok);
320 :
321 996 : variant = std::move (*lookup_variant->clone ());
322 : }
323 : else
324 : {
325 940 : rust_assert (adt->number_of_variants () == 1);
326 940 : variant = std::move (*adt->get_variants ().at (0)->clone ());
327 : }
328 1936 : infered
329 1936 : = TyTy::TypeCheckCallExpr::go (function_tyty, expr, variant, context);
330 1936 : return;
331 : }
332 :
333 11874 : bool resolved_fn_trait_call
334 11874 : = resolve_fn_trait_call (expr, function_tyty, &infered);
335 11874 : if (resolved_fn_trait_call)
336 : return;
337 :
338 11808 : bool valid_tyty
339 11851 : = function_tyty->is<TyTy::FnType> () || function_tyty->is<TyTy::FnPtr> ();
340 13 : if (!valid_tyty)
341 : {
342 13 : bool emit_error = !function_tyty->is<TyTy::ErrorType> ();
343 13 : if (emit_error)
344 : {
345 2 : rich_location r (line_table, expr.get_locus ());
346 2 : rust_error_at (r, ErrorCode::E0618, "expected function, found %<%s%>",
347 2 : function_tyty->get_name ().c_str ());
348 2 : }
349 : return;
350 : }
351 :
352 11795 : infered = TyTy::TypeCheckCallExpr::go (function_tyty, expr, variant, context);
353 :
354 : // Pre-GATS: associated types were PlaceholderType; post-GATS they are
355 : // ProjectionType, this hHandle both so the isize special-case still fires
356 11795 : auto discriminant_type_lookup
357 11795 : = mappings.lookup_lang_item (LangItem::Kind::DISCRIMINANT_TYPE);
358 11795 : bool is_discriminant_type = false;
359 11795 : if (discriminant_type_lookup)
360 : {
361 824 : if (auto *p = infered->try_as<TyTy::PlaceholderType> ())
362 0 : is_discriminant_type
363 0 : = p->get_def_id () == discriminant_type_lookup.value ();
364 12619 : else if (auto *p = infered->try_as<TyTy::ProjectionType> ())
365 0 : is_discriminant_type
366 0 : = p->get_item_defid () == discriminant_type_lookup.value ();
367 : }
368 0 : if (is_discriminant_type)
369 : {
370 : // This is a special case: discriminant_value returns the repr of the
371 : // enum. We don't currently support repr on enum yet, so the default
372 : // is always isize.
373 0 : bool ok = context->lookup_builtin ("isize", &infered);
374 0 : rust_assert (ok);
375 :
376 0 : rust_assert (function_tyty->is<TyTy::FnType> ());
377 0 : auto &fn = *static_cast<TyTy::FnType *> (function_tyty);
378 0 : rust_assert (fn.has_substitutions ());
379 0 : rust_assert (fn.get_num_type_params () == 1);
380 0 : auto &mapping = fn.get_substs ().at (0);
381 0 : auto param_ty = mapping.get_param_ty ();
382 :
383 0 : if (!param_ty->can_resolve ())
384 : {
385 0 : rust_internal_error_at (expr.get_locus (),
386 : "something wrong computing return type");
387 : return;
388 : }
389 :
390 0 : auto resolved = param_ty->resolve ();
391 0 : if (resolved->is<TyTy::ADTType> ())
392 : {
393 0 : const auto &adt = *static_cast<TyTy::ADTType *> (resolved);
394 0 : infered = adt.get_repr_options ().repr;
395 0 : rust_assert (infered != nullptr);
396 : }
397 : }
398 : }
399 :
400 : void
401 2577 : TypeCheckExpr::visit (HIR::AssignmentExpr &expr)
402 : {
403 2577 : infered = TyTy::TupleType::get_unit_type ();
404 :
405 2577 : auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ());
406 2577 : auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ());
407 :
408 5154 : coercion_site (expr.get_mappings ().get_hirid (),
409 2577 : TyTy::TyWithLocation (lhs, expr.get_lhs ().get_locus ()),
410 2577 : TyTy::TyWithLocation (rhs, expr.get_rhs ().get_locus ()),
411 : expr.get_locus ());
412 2577 : }
413 :
414 : void
415 720 : TypeCheckExpr::visit (HIR::CompoundAssignmentExpr &expr)
416 : {
417 720 : infered = TyTy::TupleType::get_unit_type ();
418 :
419 720 : auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ());
420 720 : auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ());
421 :
422 : // we dont care about the result of the unify from a compound assignment
423 : // since this is a unit-type expr
424 1440 : coercion_site (expr.get_mappings ().get_hirid (),
425 720 : TyTy::TyWithLocation (lhs, expr.get_lhs ().get_locus ()),
426 720 : TyTy::TyWithLocation (rhs, expr.get_rhs ().get_locus ()),
427 : expr.get_locus ());
428 :
429 720 : auto lang_item_type
430 720 : = LangItem::CompoundAssignmentOperatorToLangItem (expr.get_expr_type ());
431 720 : bool operator_overloaded
432 720 : = resolve_operator_overload (lang_item_type, expr, lhs, rhs);
433 720 : if (operator_overloaded)
434 : return;
435 :
436 706 : bool valid_lhs = validate_arithmetic_type (lhs, expr.get_expr_type ());
437 706 : bool valid_rhs = validate_arithmetic_type (rhs, expr.get_expr_type ());
438 706 : bool valid = valid_lhs && valid_rhs;
439 706 : if (!valid)
440 : {
441 0 : rust_error_at (expr.get_locus (),
442 : "cannot apply operator %qs to types %s and %s",
443 0 : expr.get_operator_str ().c_str (),
444 0 : lhs->as_string ().c_str (), rhs->as_string ().c_str ());
445 0 : return;
446 : }
447 : }
448 :
449 : void
450 21956 : TypeCheckExpr::visit (HIR::LiteralExpr &expr)
451 : {
452 21956 : infered = resolve_literal (expr.get_mappings (), expr.get_literal (),
453 : expr.get_locus ());
454 21956 : }
455 :
456 : void
457 3812 : TypeCheckExpr::visit (HIR::ArithmeticOrLogicalExpr &expr)
458 : {
459 3812 : auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ());
460 3812 : auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ());
461 :
462 3812 : auto lang_item_type = LangItem::OperatorToLangItem (expr.get_expr_type ());
463 3812 : bool operator_overloaded
464 3812 : = resolve_operator_overload (lang_item_type, expr, lhs, rhs);
465 3812 : if (operator_overloaded)
466 : return;
467 :
468 3598 : bool valid_lhs = validate_arithmetic_type (lhs, expr.get_expr_type ());
469 3598 : bool valid_rhs = validate_arithmetic_type (rhs, expr.get_expr_type ());
470 3598 : bool valid = valid_lhs && valid_rhs;
471 3598 : if (!valid)
472 : {
473 6 : rust_error_at (expr.get_locus (),
474 : "cannot apply operator %qs to types %s and %s",
475 6 : expr.get_operator_str ().c_str (),
476 6 : lhs->as_string ().c_str (), rhs->as_string ().c_str ());
477 3 : return;
478 : }
479 :
480 3595 : switch (expr.get_expr_type ())
481 : {
482 69 : case ArithmeticOrLogicalOperator::LEFT_SHIFT:
483 69 : case ArithmeticOrLogicalOperator::RIGHT_SHIFT:
484 69 : {
485 69 : TyTy::TyWithLocation from (rhs, expr.get_rhs ().get_locus ());
486 69 : TyTy::TyWithLocation to (lhs, expr.get_lhs ().get_locus ());
487 69 : infered = cast_site (expr.get_mappings ().get_hirid (), from, to,
488 : expr.get_locus ());
489 : }
490 69 : break;
491 :
492 3526 : default:
493 3526 : {
494 7052 : infered = unify_site (
495 3526 : expr.get_mappings ().get_hirid (),
496 3526 : TyTy::TyWithLocation (lhs, expr.get_lhs ().get_locus ()),
497 3526 : TyTy::TyWithLocation (rhs, expr.get_rhs ().get_locus ()),
498 : expr.get_locus ());
499 : }
500 3526 : break;
501 : }
502 : }
503 :
504 : void
505 3903 : TypeCheckExpr::visit (HIR::ComparisonExpr &expr)
506 : {
507 3903 : auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ());
508 3903 : auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ());
509 :
510 3903 : auto borrowed_lhs
511 3903 : = new TyTy::ReferenceType (mappings.get_next_hir_id (),
512 3903 : TyTy::TyVar (lhs->get_ref ()), Mutability::Imm);
513 3903 : context->insert_implicit_type (borrowed_lhs->get_ref (), borrowed_lhs);
514 :
515 3903 : auto borrowed_rhs
516 3903 : = new TyTy::ReferenceType (mappings.get_next_hir_id (),
517 3903 : TyTy::TyVar (rhs->get_ref ()), Mutability::Imm);
518 3903 : context->insert_implicit_type (borrowed_rhs->get_ref (), borrowed_rhs);
519 :
520 3903 : auto seg_name = LangItem::ComparisonToSegment (expr.get_expr_type ());
521 7806 : auto segment = HIR::PathIdentSegment (seg_name);
522 3903 : auto lang_item_type = LangItem::ComparisonToLangItem (expr.get_expr_type ());
523 :
524 3903 : bool operator_overloaded
525 3903 : = resolve_operator_overload (lang_item_type, expr, lhs, borrowed_rhs,
526 : segment, true, nullptr, borrowed_lhs);
527 3903 : if (operator_overloaded)
528 991 : return;
529 :
530 5824 : unify_site (expr.get_mappings ().get_hirid (),
531 2912 : TyTy::TyWithLocation (lhs, expr.get_lhs ().get_locus ()),
532 2912 : TyTy::TyWithLocation (rhs, expr.get_rhs ().get_locus ()),
533 : expr.get_locus ());
534 :
535 2912 : bool ok = context->lookup_builtin ("bool", &infered);
536 2912 : rust_assert (ok);
537 3903 : }
538 :
539 : void
540 481 : TypeCheckExpr::visit (HIR::LazyBooleanExpr &expr)
541 : {
542 481 : auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ());
543 481 : auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ());
544 :
545 : // we expect the lhs and rhs must be bools at this point
546 481 : TyTy::BaseType *boolean_node = nullptr;
547 481 : bool ok = context->lookup_builtin ("bool", &boolean_node);
548 481 : rust_assert (ok);
549 :
550 : // verify the lhs and rhs before unifying together
551 962 : lhs = unify_site (expr.get_mappings ().get_hirid (),
552 : TyTy::TyWithLocation (boolean_node,
553 481 : expr.get_lhs ().get_locus ()),
554 481 : TyTy::TyWithLocation (lhs, expr.get_lhs ().get_locus ()),
555 : expr.get_locus ());
556 :
557 962 : rhs = unify_site (expr.get_mappings ().get_hirid (),
558 : TyTy::TyWithLocation (boolean_node,
559 481 : expr.get_rhs ().get_locus ()),
560 481 : TyTy::TyWithLocation (rhs, expr.get_rhs ().get_locus ()),
561 : expr.get_locus ());
562 :
563 481 : infered
564 962 : = unify_site (expr.get_mappings ().get_hirid (),
565 481 : TyTy::TyWithLocation (lhs, expr.get_lhs ().get_locus ()),
566 481 : TyTy::TyWithLocation (rhs, expr.get_rhs ().get_locus ()),
567 : expr.get_locus ());
568 481 : }
569 :
570 : void
571 715 : TypeCheckExpr::visit (HIR::NegationExpr &expr)
572 : {
573 715 : auto negated_expr_ty = TypeCheckExpr::Resolve (expr.get_expr ());
574 :
575 : // check for operator overload
576 715 : auto lang_item_type
577 715 : = LangItem::NegationOperatorToLangItem (expr.get_expr_type ());
578 715 : bool operator_overloaded
579 715 : = resolve_operator_overload (lang_item_type, expr, negated_expr_ty,
580 : nullptr);
581 715 : if (operator_overloaded)
582 : return;
583 :
584 : // https://doc.rust-lang.org/reference/expressions/operator-expr.html#negation-operators
585 701 : switch (expr.get_expr_type ())
586 : {
587 419 : case NegationOperator::NEGATE:
588 419 : {
589 419 : bool valid
590 419 : = (negated_expr_ty->get_kind () == TyTy::TypeKind::INT)
591 277 : || (negated_expr_ty->get_kind () == TyTy::TypeKind::UINT)
592 277 : || (negated_expr_ty->get_kind () == TyTy::TypeKind::FLOAT)
593 275 : || (negated_expr_ty->get_kind () == TyTy::TypeKind::ISIZE)
594 272 : || (negated_expr_ty->get_kind () == TyTy::TypeKind::USIZE)
595 272 : || (negated_expr_ty->get_kind () == TyTy::TypeKind::INFER
596 271 : && (((TyTy::InferType *) negated_expr_ty)->get_infer_kind ()
597 : == TyTy::InferType::INTEGRAL))
598 420 : || (negated_expr_ty->get_kind () == TyTy::TypeKind::INFER
599 0 : && (((TyTy::InferType *) negated_expr_ty)->get_infer_kind ()
600 700 : == TyTy::InferType::FLOAT));
601 1 : if (!valid)
602 : {
603 1 : rust_error_at (expr.get_locus (), "cannot apply unary - to %s",
604 1 : negated_expr_ty->as_string ().c_str ());
605 1 : return;
606 : }
607 : }
608 : break;
609 :
610 282 : case NegationOperator::NOT:
611 282 : {
612 282 : bool valid
613 282 : = (negated_expr_ty->get_kind () == TyTy::TypeKind::BOOL)
614 61 : || (negated_expr_ty->get_kind () == TyTy::TypeKind::INT)
615 54 : || (negated_expr_ty->get_kind () == TyTy::TypeKind::UINT)
616 12 : || (negated_expr_ty->get_kind () == TyTy::TypeKind::ISIZE)
617 11 : || (negated_expr_ty->get_kind () == TyTy::TypeKind::USIZE)
618 292 : || (negated_expr_ty->get_kind () == TyTy::TypeKind::INFER
619 9 : && (((TyTy::InferType *) negated_expr_ty)->get_infer_kind ()
620 700 : == TyTy::InferType::INTEGRAL));
621 1 : if (!valid)
622 : {
623 1 : rust_error_at (expr.get_locus (), "cannot apply unary %<!%> to %s",
624 1 : negated_expr_ty->as_string ().c_str ());
625 1 : return;
626 : }
627 : }
628 : break;
629 : }
630 :
631 699 : infered = negated_expr_ty->clone ();
632 699 : infered->append_reference (negated_expr_ty->get_ref ());
633 : }
634 :
635 : void
636 1348 : TypeCheckExpr::visit (HIR::IfExpr &expr)
637 : {
638 1348 : TyTy::BaseType *bool_ty = nullptr;
639 1348 : bool ok = context->lookup_builtin ("bool", &bool_ty);
640 1348 : rust_assert (ok);
641 :
642 1348 : TyTy::BaseType *cond_type = TypeCheckExpr::Resolve (expr.get_if_condition ());
643 :
644 2696 : unify_site (expr.get_mappings ().get_hirid (), TyTy::TyWithLocation (bool_ty),
645 : TyTy::TyWithLocation (cond_type,
646 1348 : expr.get_if_condition ().get_locus ()),
647 : expr.get_locus ());
648 :
649 1348 : TyTy::BaseType *block_type = TypeCheckExpr::Resolve (expr.get_if_block ());
650 :
651 1348 : TyTy::BaseType *unit_ty = nullptr;
652 1348 : ok = context->lookup_builtin ("()", &unit_ty);
653 1348 : rust_assert (ok);
654 :
655 1348 : infered
656 2696 : = coercion_site (expr.get_mappings ().get_hirid (),
657 1348 : TyTy::TyWithLocation (unit_ty),
658 : TyTy::TyWithLocation (block_type,
659 1348 : expr.get_if_block ().get_locus ()),
660 : expr.get_locus ());
661 1348 : }
662 :
663 : void
664 1339 : TypeCheckExpr::visit (HIR::IfExprConseqElse &expr)
665 : {
666 1339 : TyTy::BaseType *bool_ty = nullptr;
667 1339 : bool ok = context->lookup_builtin ("bool", &bool_ty);
668 1339 : rust_assert (ok);
669 :
670 1339 : TyTy::BaseType *cond_type = TypeCheckExpr::Resolve (expr.get_if_condition ());
671 :
672 2678 : unify_site (expr.get_mappings ().get_hirid (), TyTy::TyWithLocation (bool_ty),
673 : TyTy::TyWithLocation (cond_type,
674 1339 : expr.get_if_condition ().get_locus ()),
675 : expr.get_locus ());
676 :
677 1339 : auto if_blk_resolved = TypeCheckExpr::Resolve (expr.get_if_block ());
678 1339 : auto else_blk_resolved = TypeCheckExpr::Resolve (expr.get_else_block ());
679 :
680 1339 : if (if_blk_resolved->get_kind () == TyTy::NEVER)
681 40 : infered = else_blk_resolved;
682 1299 : else if (else_blk_resolved->get_kind () == TyTy::NEVER)
683 7 : infered = if_blk_resolved;
684 : else
685 : {
686 1292 : infered
687 2584 : = unify_site (expr.get_mappings ().get_hirid (),
688 : TyTy::TyWithLocation (if_blk_resolved,
689 1292 : expr.get_if_block ().get_locus ()),
690 : TyTy::TyWithLocation (
691 1292 : else_blk_resolved, expr.get_else_block ().get_locus ()),
692 : expr.get_locus ());
693 : }
694 1339 : }
695 :
696 : void
697 4043 : TypeCheckExpr::visit (HIR::UnsafeBlockExpr &expr)
698 : {
699 4043 : infered = TypeCheckExpr::Resolve (expr.get_block_expr ());
700 4043 : }
701 :
702 : void
703 25547 : TypeCheckExpr::visit (HIR::BlockExpr &expr)
704 : {
705 25547 : bool has_label = expr.has_label ();
706 25547 : if (expr.has_label ())
707 3 : context->push_new_loop_context (expr.get_mappings ().get_hirid (),
708 : expr.get_locus ());
709 :
710 : // Forward the caller's expected type to the block's tail expression only.
711 25547 : TyTy::BaseType *outer_expected = context->peek_expected_type ();
712 25547 : context->push_expected_type (nullptr);
713 :
714 51132 : for (auto &s : expr.get_statements ())
715 : {
716 25585 : if (!s->is_item ())
717 25130 : continue;
718 :
719 455 : TypeCheckStmt::Resolve (*s);
720 : }
721 :
722 51132 : for (auto &s : expr.get_statements ())
723 : {
724 25585 : if (s->is_item ())
725 455 : continue;
726 :
727 25130 : auto resolved = TypeCheckStmt::Resolve (*s);
728 25130 : if (resolved == nullptr)
729 : {
730 0 : rust_error_at (s->get_locus (), "failure to resolve type");
731 0 : context->pop_expected_type ();
732 0 : if (has_label)
733 0 : context->pop_loop_context ();
734 25547 : return;
735 : }
736 :
737 25130 : if (s->is_unit_check_needed () && !resolved->is_unit ())
738 : {
739 6 : auto unit = TyTy::TupleType::get_unit_type ();
740 12 : unify_site (s->get_mappings ().get_hirid (),
741 6 : TyTy::TyWithLocation (unit),
742 6 : TyTy::TyWithLocation (resolved), s->get_locus ());
743 : }
744 : }
745 :
746 25547 : context->pop_expected_type ();
747 :
748 25547 : TyTy::BaseType *tail_expr_type = nullptr;
749 25547 : if (expr.has_expr ())
750 : {
751 18300 : context->push_expected_type (outer_expected);
752 18300 : tail_expr_type = TypeCheckExpr::Resolve (expr.get_final_expr ());
753 18300 : context->pop_expected_type ();
754 : }
755 :
756 25547 : TyTy::BaseType *label_context_type = nullptr;
757 25547 : bool label_context_type_infered = false;
758 25547 : if (has_label)
759 : {
760 3 : label_context_type = context->pop_loop_context ();
761 :
762 3 : label_context_type_infered
763 3 : = (label_context_type->get_kind () != TyTy::TypeKind::INFER)
764 3 : || ((label_context_type->get_kind () == TyTy::TypeKind::INFER)
765 3 : && (((TyTy::InferType *) label_context_type)->get_infer_kind ()
766 : != TyTy::InferType::GENERAL));
767 : }
768 :
769 25547 : if (tail_expr_type != nullptr)
770 : {
771 18300 : if (label_context_type_infered)
772 : {
773 2 : if (tail_expr_type->get_kind () == TyTy::TypeKind::NEVER)
774 0 : infered = label_context_type;
775 : else
776 4 : infered = unify_site (
777 2 : expr.get_mappings ().get_hirid (),
778 2 : TyTy::TyWithLocation (label_context_type),
779 : TyTy::TyWithLocation (tail_expr_type,
780 2 : expr.get_final_expr ().get_locus ()),
781 : expr.get_locus ());
782 : }
783 : else
784 18298 : infered = tail_expr_type;
785 : }
786 7247 : else if (label_context_type_infered)
787 1 : infered = label_context_type;
788 7246 : else if (expr.is_tail_reachable ())
789 6692 : infered = TyTy::TupleType::get_unit_type ();
790 : else
791 : {
792 : // FIXME this seems wrong
793 554 : infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ());
794 : }
795 : }
796 :
797 : void
798 815 : TypeCheckExpr::visit (HIR::AnonConst &expr)
799 : {
800 815 : if (!expr.is_deferred ())
801 : {
802 803 : infered = TypeCheckExpr::Resolve (expr.get_inner_expr ());
803 803 : return;
804 : }
805 :
806 12 : TyTy::TyVar var
807 12 : = TyTy::TyVar::get_implicit_const_infer_var (expr.get_locus ());
808 12 : infered = var.get_tyty ();
809 : }
810 :
811 : void
812 15 : TypeCheckExpr::visit (HIR::ConstBlock &expr)
813 : {
814 15 : infered = TypeCheckExpr::Resolve (expr.get_const_expr ());
815 15 : }
816 :
817 : void
818 74 : TypeCheckExpr::visit (HIR::RangeFromToExpr &expr)
819 : {
820 74 : auto lang_item_type = LangItem::Kind::RANGE;
821 :
822 74 : auto lang_item_defined = mappings.lookup_lang_item (lang_item_type);
823 : // we need to have it maybe
824 74 : if (!lang_item_defined)
825 : {
826 0 : rust_internal_error_at (expr.get_locus (),
827 : "unable to find relevant lang item: %s",
828 0 : LangItem::ToString (lang_item_type).c_str ());
829 : return;
830 : }
831 74 : DefId respective_lang_item_id = lang_item_defined.value ();
832 :
833 : // look it up and it _must_ be a struct definition
834 74 : HIR::Item *item = mappings.lookup_defid (respective_lang_item_id).value ();
835 :
836 74 : TyTy::BaseType *item_type = TypeCheckItem::Resolve (*item);
837 74 : rust_assert (item_type->get_kind () == TyTy::TypeKind::ADT);
838 74 : TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (item_type);
839 :
840 : // this is a single generic item lets assert that
841 74 : rust_assert (adt->get_num_substitutions () == 1);
842 :
843 : // resolve the range expressions and these types must unify then we use that
844 : // type to substitute into the ADT
845 74 : TyTy::BaseType *from_ty = TypeCheckExpr::Resolve (expr.get_from_expr ());
846 74 : TyTy::BaseType *to_ty = TypeCheckExpr::Resolve (expr.get_to_expr ());
847 :
848 148 : TyTy::BaseType *unified = unify_site (
849 74 : expr.get_mappings ().get_hirid (),
850 74 : TyTy::TyWithLocation (from_ty, expr.get_from_expr ().get_locus ()),
851 74 : TyTy::TyWithLocation (to_ty, expr.get_to_expr ().get_locus ()),
852 74 : expr.get_locus ());
853 :
854 : // substitute it in
855 74 : std::vector<TyTy::SubstitutionArg> subst_mappings;
856 74 : const TyTy::SubstitutionParamMapping *param_ref = &adt->get_substs ().at (0);
857 74 : subst_mappings.emplace_back (param_ref, unified);
858 :
859 74 : TyTy::SubstitutionArgumentMappings subst (
860 74 : subst_mappings, {}, adt->get_substitution_arguments ().get_regions (),
861 74 : expr.get_locus ());
862 74 : infered = SubstMapperInternal::Resolve (adt, subst);
863 74 : }
864 :
865 : void
866 7 : TypeCheckExpr::visit (HIR::RangeFromExpr &expr)
867 : {
868 7 : auto lang_item_type = LangItem::Kind::RANGE_FROM;
869 :
870 7 : auto lang_item_defined = mappings.lookup_lang_item (lang_item_type);
871 : // we need to have it maybe
872 7 : if (!lang_item_defined)
873 : {
874 0 : rust_internal_error_at (expr.get_locus (),
875 : "unable to find relevant lang item: %s",
876 0 : LangItem::ToString (lang_item_type).c_str ());
877 : return;
878 : }
879 7 : DefId &respective_lang_item_id = lang_item_defined.value ();
880 :
881 : // look it up and it _must_ be a struct definition
882 7 : HIR::Item *item = mappings.lookup_defid (respective_lang_item_id).value ();
883 :
884 7 : TyTy::BaseType *item_type = TypeCheckItem::Resolve (*item);
885 7 : rust_assert (item_type->get_kind () == TyTy::TypeKind::ADT);
886 7 : TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (item_type);
887 :
888 : // this is a single generic item lets assert that
889 7 : rust_assert (adt->get_num_substitutions () == 1);
890 :
891 : // resolve the range expressions and these types must unify then we use that
892 : // type to substitute into the ADT
893 7 : TyTy::BaseType *from_ty = TypeCheckExpr::Resolve (expr.get_from_expr ());
894 :
895 : // substitute it in
896 7 : std::vector<TyTy::SubstitutionArg> subst_mappings;
897 7 : const TyTy::SubstitutionParamMapping *param_ref = &adt->get_substs ().at (0);
898 7 : subst_mappings.emplace_back (param_ref, from_ty);
899 :
900 7 : TyTy::SubstitutionArgumentMappings subst (
901 7 : subst_mappings, {}, adt->get_substitution_arguments ().get_regions (),
902 7 : expr.get_locus ());
903 7 : infered = SubstMapperInternal::Resolve (adt, subst);
904 7 : }
905 :
906 : void
907 7 : TypeCheckExpr::visit (HIR::RangeToExpr &expr)
908 : {
909 7 : auto lang_item_type = LangItem::Kind::RANGE_TO;
910 :
911 7 : auto lang_item_defined = mappings.lookup_lang_item (lang_item_type);
912 : // we need to have it maybe
913 7 : if (!lang_item_defined)
914 : {
915 0 : rust_internal_error_at (expr.get_locus (),
916 : "unable to find relevant lang item: %s",
917 0 : LangItem::ToString (lang_item_type).c_str ());
918 : return;
919 : }
920 :
921 7 : DefId &respective_lang_item_id = lang_item_defined.value ();
922 : // look it up and it _must_ be a struct definition
923 7 : HIR::Item *item = mappings.lookup_defid (respective_lang_item_id).value ();
924 :
925 7 : TyTy::BaseType *item_type = TypeCheckItem::Resolve (*item);
926 7 : rust_assert (item_type->get_kind () == TyTy::TypeKind::ADT);
927 7 : TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (item_type);
928 :
929 : // this is a single generic item lets assert that
930 7 : rust_assert (adt->get_num_substitutions () == 1);
931 :
932 : // resolve the range expressions and these types must unify then we use that
933 : // type to substitute into the ADT
934 7 : TyTy::BaseType *from_ty = TypeCheckExpr::Resolve (expr.get_to_expr ());
935 :
936 : // substitute it in
937 7 : std::vector<TyTy::SubstitutionArg> subst_mappings;
938 7 : const TyTy::SubstitutionParamMapping *param_ref = &adt->get_substs ().at (0);
939 7 : subst_mappings.emplace_back (param_ref, from_ty);
940 :
941 7 : TyTy::SubstitutionArgumentMappings subst (
942 7 : subst_mappings, {}, adt->get_substitution_arguments ().get_regions (),
943 7 : expr.get_locus ());
944 7 : infered = SubstMapperInternal::Resolve (adt, subst);
945 7 : }
946 :
947 : void
948 27 : typecheck_inline_asm_operand (HIR::InlineAsm &expr)
949 : {
950 27 : const auto &operands = expr.get_operands ();
951 27 : using RegisterType = AST::InlineAsmOperand::RegisterType;
952 56 : for (auto &operand : operands)
953 : {
954 29 : switch (operand.get_register_type ())
955 : {
956 10 : case RegisterType::In:
957 10 : {
958 10 : auto in = operand.get_in ();
959 10 : TypeCheckExpr::Resolve (*in.expr);
960 10 : break;
961 10 : }
962 17 : case RegisterType::Out:
963 17 : {
964 17 : auto out = operand.get_out ();
965 17 : TypeCheckExpr::Resolve (*out.expr);
966 17 : break;
967 17 : }
968 0 : case RegisterType::InOut:
969 0 : {
970 0 : auto in_out = operand.get_in_out ();
971 0 : TypeCheckExpr::Resolve (*in_out.expr);
972 0 : break;
973 0 : }
974 2 : case RegisterType::SplitInOut:
975 2 : {
976 2 : auto split_in_out = operand.get_split_in_out ();
977 2 : TypeCheckExpr::Resolve (*split_in_out.in_expr);
978 2 : TypeCheckExpr::Resolve (*split_in_out.out_expr);
979 2 : break;
980 2 : }
981 0 : case RegisterType::Const:
982 0 : {
983 0 : auto anon_const = operand.get_const ().anon_const;
984 0 : TypeCheckExpr::Resolve (anon_const.get_inner_expr ());
985 0 : break;
986 0 : }
987 0 : case RegisterType::Sym:
988 0 : {
989 0 : auto sym = operand.get_sym ();
990 0 : TypeCheckExpr::Resolve (*sym.expr);
991 0 : break;
992 0 : }
993 0 : case RegisterType::Label:
994 0 : {
995 0 : auto label = operand.get_label ();
996 0 : TypeCheckExpr::Resolve (*label.expr);
997 0 : break;
998 0 : }
999 : }
1000 : }
1001 27 : }
1002 : void
1003 27 : TypeCheckExpr::visit (HIR::InlineAsm &expr)
1004 : {
1005 27 : typecheck_inline_asm_operand (expr);
1006 :
1007 : // NOTE: Hoise out if we have noreturn as an option
1008 : // to return a never type
1009 : // TODO : new keyword for memory seems sooooo shaky
1010 27 : if (expr.options.count (AST::InlineAsm::Option::NORETURN) == 1)
1011 1 : infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ());
1012 : else
1013 26 : infered = TyTy::TupleType::get_unit_type ();
1014 27 : }
1015 :
1016 : void
1017 2 : TypeCheckExpr::visit (HIR::LlvmInlineAsm &expr)
1018 : {
1019 : // TODO: verify input/output types?
1020 :
1021 4 : for (auto &i : expr.inputs)
1022 2 : TypeCheckExpr::Resolve (*i.expr);
1023 :
1024 2 : for (auto &o : expr.outputs)
1025 0 : TypeCheckExpr::Resolve (*o.expr);
1026 :
1027 : // always unit type
1028 2 : infered = TyTy::TupleType::get_unit_type ();
1029 2 : }
1030 :
1031 : void
1032 15 : TypeCheckExpr::visit (HIR::OffsetOf &expr)
1033 : {
1034 15 : TypeCheckType::Resolve (expr.get_type ());
1035 :
1036 : // FIXME: Does offset_of always return a usize?
1037 15 : TyTy::BaseType *size_ty;
1038 15 : bool ok = context->lookup_builtin ("usize", &size_ty);
1039 15 : rust_assert (ok);
1040 :
1041 15 : infered = size_ty;
1042 15 : }
1043 :
1044 : void
1045 0 : TypeCheckExpr::visit (HIR::RangeFullExpr &expr)
1046 : {
1047 0 : auto lang_item_type = LangItem::Kind::RANGE_FULL;
1048 :
1049 0 : auto lang_item_defined = mappings.lookup_lang_item (lang_item_type);
1050 : // we need to have it maybe
1051 0 : if (!lang_item_defined)
1052 : {
1053 0 : rust_internal_error_at (expr.get_locus (),
1054 : "unable to find relevant lang item: %s",
1055 0 : LangItem::ToString (lang_item_type).c_str ());
1056 : return;
1057 : }
1058 0 : DefId &respective_lang_item_id = lang_item_defined.value ();
1059 :
1060 : // look it up and it _must_ be a struct definition
1061 0 : HIR::Item *item = mappings.lookup_defid (respective_lang_item_id).value ();
1062 :
1063 0 : TyTy::BaseType *item_type = TypeCheckItem::Resolve (*item);
1064 0 : rust_assert (item_type->is_unit ());
1065 :
1066 0 : infered = item_type;
1067 : }
1068 :
1069 : void
1070 297 : TypeCheckExpr::visit (HIR::ArrayIndexExpr &expr)
1071 : {
1072 297 : auto array_expr_ty = TypeCheckExpr::Resolve (expr.get_array_expr ());
1073 297 : if (array_expr_ty->get_kind () == TyTy::TypeKind::ERROR)
1074 295 : return;
1075 :
1076 296 : auto index_expr_ty = TypeCheckExpr::Resolve (expr.get_index_expr ());
1077 296 : if (index_expr_ty->get_kind () == TyTy::TypeKind::ERROR)
1078 : return;
1079 :
1080 : // first attempt to use direct array index logic
1081 296 : auto direct_array_expr_ty = array_expr_ty;
1082 296 : if (direct_array_expr_ty->get_kind () == TyTy::TypeKind::REF)
1083 : {
1084 : // lets try and deref it since rust allows this
1085 29 : auto ref = static_cast<TyTy::ReferenceType *> (direct_array_expr_ty);
1086 29 : auto base = ref->get_base ();
1087 29 : if (base->get_kind () == TyTy::TypeKind::ARRAY)
1088 15 : direct_array_expr_ty = base;
1089 : }
1090 : // Box<T> autoderef
1091 267 : else if (auto base = TyTy::try_get_box_inner_type (direct_array_expr_ty))
1092 : {
1093 6 : direct_array_expr_ty = *base;
1094 : }
1095 :
1096 296 : TyTy::BaseType *size_ty;
1097 296 : bool ok = context->lookup_builtin ("usize", &size_ty);
1098 296 : rust_assert (ok);
1099 :
1100 296 : bool maybe_simple_array_access
1101 296 : = types_compatable (TyTy::TyWithLocation (index_expr_ty),
1102 296 : TyTy::TyWithLocation (size_ty), expr.get_locus (),
1103 : false);
1104 296 : if (maybe_simple_array_access
1105 296 : && direct_array_expr_ty->get_kind () == TyTy::TypeKind::ARRAY)
1106 : {
1107 456 : unify_site (expr.get_index_expr ().get_mappings ().get_hirid (),
1108 228 : TyTy::TyWithLocation (size_ty),
1109 : TyTy::TyWithLocation (index_expr_ty,
1110 228 : expr.get_index_expr ().get_locus ()),
1111 : expr.get_locus ());
1112 :
1113 228 : TyTy::ArrayType *array_type
1114 : = static_cast<TyTy::ArrayType *> (direct_array_expr_ty);
1115 228 : infered = array_type->get_element_type ()->clone ();
1116 228 : return;
1117 : }
1118 :
1119 : // is this a case of core::ops::index?
1120 68 : auto lang_item_type = LangItem::Kind::INDEX;
1121 68 : bool operator_overloaded
1122 68 : = resolve_operator_overload (lang_item_type, expr, array_expr_ty,
1123 : index_expr_ty);
1124 68 : if (operator_overloaded)
1125 : {
1126 : // index and index mut always return a reference to the element
1127 66 : TyTy::BaseType *resolved = infered;
1128 66 : rust_assert (resolved->get_kind () == TyTy::TypeKind::REF);
1129 66 : TyTy::ReferenceType *ref = static_cast<TyTy::ReferenceType *> (resolved);
1130 :
1131 66 : infered = ref->get_base ()->clone ();
1132 66 : return;
1133 : }
1134 :
1135 : // error[E0277]: the type `[{integer}]` cannot be indexed by `u32`
1136 2 : rich_location r (line_table, expr.get_locus ());
1137 2 : r.add_range (expr.get_array_expr ().get_locus ());
1138 2 : r.add_range (expr.get_index_expr ().get_locus ());
1139 2 : rust_error_at (r, ErrorCode::E0277, "the type %qs cannot be indexed by %qs",
1140 4 : array_expr_ty->get_name ().c_str (),
1141 2 : index_expr_ty->get_name ().c_str ());
1142 2 : }
1143 :
1144 : void
1145 452 : TypeCheckExpr::visit (HIR::ArrayExpr &expr)
1146 : {
1147 452 : auto &elements = expr.get_internal_elements ();
1148 :
1149 452 : TyTy::BaseType *expected_ty = nullptr;
1150 452 : bool ok = context->lookup_builtin ("usize", &expected_ty);
1151 452 : rust_assert (ok);
1152 :
1153 452 : HIR::Expr *capacity_expr = nullptr;
1154 452 : TyTy::BaseType *element_type = nullptr;
1155 452 : TyTy::BaseType *capacity_type = nullptr;
1156 :
1157 452 : switch (elements.get_array_expr_type ())
1158 : {
1159 135 : case HIR::ArrayElems::ArrayExprType::COPIED:
1160 135 : {
1161 135 : HIR::ArrayElemsCopied &elems
1162 : = static_cast<HIR::ArrayElemsCopied &> (elements);
1163 135 : context->push_const_context ();
1164 135 : element_type = TypeCheckExpr::Resolve (elems.get_elem_to_copy ());
1165 135 : context->pop_const_context ();
1166 :
1167 135 : auto capacity_expr_ty
1168 135 : = TypeCheckExpr::Resolve (elems.get_num_copies_expr ());
1169 135 : if (capacity_expr_ty->is<TyTy::ErrorType> ())
1170 10 : return;
1171 :
1172 129 : context->insert_type (elems.get_num_copies_expr ().get_mappings (),
1173 : expected_ty);
1174 :
1175 258 : auto result = unify_site (
1176 129 : expr.get_mappings ().get_hirid (), TyTy::TyWithLocation (expected_ty),
1177 : TyTy::TyWithLocation (capacity_expr_ty,
1178 129 : elems.get_num_copies_expr ().get_locus ()),
1179 : expr.get_locus ());
1180 129 : if (result->is<TyTy::ErrorType> ())
1181 : return;
1182 :
1183 125 : capacity_expr = &elems.get_num_copies_expr ();
1184 125 : capacity_type = expected_ty;
1185 : }
1186 125 : break;
1187 :
1188 317 : case HIR::ArrayElems::ArrayExprType::VALUES:
1189 317 : {
1190 317 : HIR::ArrayElemsValues &elems
1191 : = static_cast<HIR::ArrayElemsValues &> (elements);
1192 317 : context->push_const_context ();
1193 317 : std::vector<TyTy::BaseType *> types;
1194 1855 : for (auto &elem : elems.get_values ())
1195 : {
1196 1538 : auto elem_ty = TypeCheckExpr::Resolve (*elem);
1197 1538 : types.push_back (elem_ty);
1198 : }
1199 317 : context->pop_const_context ();
1200 :
1201 : // this is a LUB
1202 317 : element_type
1203 317 : = TyTy::TyVar::get_implicit_infer_var (expr.get_locus ()).get_tyty ();
1204 1855 : for (auto &type : types)
1205 : {
1206 1538 : element_type
1207 1538 : = unify_site (expr.get_mappings ().get_hirid (),
1208 1538 : TyTy::TyWithLocation (element_type),
1209 1538 : TyTy::TyWithLocation (type, type->get_locus ()),
1210 : expr.get_locus ());
1211 : }
1212 :
1213 317 : auto crate_num = mappings.crate.get_current_crate ();
1214 317 : Analysis::NodeMapping mapping (crate_num, UNKNOWN_NODEID,
1215 317 : mappings.get_next_hir_id (crate_num),
1216 317 : UNKNOWN_LOCAL_DEFID);
1217 317 : std::string capacity_str = std::to_string (elems.get_num_elements ());
1218 317 : capacity_expr = new HIR::LiteralExpr (mapping, capacity_str,
1219 : HIR::Literal::LitType::INT,
1220 : PrimitiveCoreType::CORETYPE_USIZE,
1221 951 : UNDEF_LOCATION, {});
1222 :
1223 : // mark the type for this implicit node
1224 317 : context->insert_type (mapping, expected_ty);
1225 317 : capacity_type = expected_ty;
1226 317 : }
1227 317 : break;
1228 : }
1229 :
1230 442 : rust_assert (capacity_expr);
1231 442 : rust_assert (capacity_type);
1232 442 : auto ctx = Compile::Context::get ();
1233 442 : tree capacity_value
1234 442 : = Compile::HIRCompileBase::query_compile_const_expr (ctx, capacity_type,
1235 : *capacity_expr);
1236 :
1237 : // Create ConstValueType with ref == ty_ref (both pointing to capacity_expr)
1238 : // ty_ref gets updated during substitution via set_ty_ref()
1239 442 : HirId capacity_expr_id = capacity_expr->get_mappings ().get_hirid ();
1240 442 : auto const_type
1241 : = new TyTy::ConstValueType (capacity_value, expected_ty, capacity_expr_id,
1242 442 : capacity_expr_id);
1243 :
1244 : // Insert the ConstValueType at its ref
1245 442 : context->insert_type (capacity_expr->get_mappings (),
1246 442 : const_type->as_base_type ());
1247 :
1248 442 : infered
1249 884 : = new TyTy::ArrayType (expr.get_mappings ().get_hirid (), expr.get_locus (),
1250 : TyTy::TyVar (
1251 442 : const_type->as_base_type ()->get_ty_ref ()),
1252 884 : TyTy::TyVar (element_type->get_ref ()));
1253 : }
1254 :
1255 : // empty struct
1256 : void
1257 81 : TypeCheckExpr::visit (HIR::StructExprStruct &struct_expr)
1258 : {
1259 81 : HIR::PathInExpression &path = struct_expr.get_struct_name ();
1260 :
1261 81 : TyTy::BaseType *struct_path_ty = TypeCheckExpr::Resolve (path);
1262 81 : if (struct_path_ty->get_kind () != TyTy::TypeKind::ADT)
1263 : {
1264 0 : rust_error_at (path.get_locus (), "expected an ADT type for constructor");
1265 1 : return;
1266 : }
1267 :
1268 81 : TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (struct_path_ty);
1269 81 : TyTy::VariantDef *variant;
1270 :
1271 : // unwrap and type check the variant if it's an enum
1272 81 : if (adt->is_enum ())
1273 : {
1274 3 : HirId variant_id;
1275 3 : bool ok = context->lookup_variant_definition (
1276 3 : struct_expr.get_struct_name ().get_mappings ().get_hirid (),
1277 : &variant_id);
1278 3 : if (!ok)
1279 : {
1280 0 : rich_location r (line_table, struct_expr.get_locus ());
1281 0 : r.add_range (struct_expr.get_struct_name ().get_locus ());
1282 0 : rust_error_at (
1283 0 : struct_expr.get_struct_name ().get_locus (), ErrorCode::E0574,
1284 : "expected a struct, variant or union type, found enum %qs",
1285 0 : adt->get_name ().c_str ());
1286 0 : return;
1287 0 : }
1288 :
1289 3 : ok = adt->lookup_variant_by_id (variant_id, &variant);
1290 3 : rust_assert (ok);
1291 : }
1292 : else
1293 : {
1294 78 : rust_assert (adt->number_of_variants () == 1);
1295 78 : variant = adt->get_variants ().at (0);
1296 : }
1297 :
1298 81 : if (!variant->get_fields ().empty ())
1299 : {
1300 1 : std::vector<std::string> field_names;
1301 4 : for (auto &field : variant->get_fields ())
1302 3 : field_names.push_back (field->get_name ());
1303 1 : Error missing_fields_error
1304 : = TypeCheckStructExpr::make_missing_field_error (
1305 1 : struct_expr.get_locus (), field_names, struct_path_ty->get_name ());
1306 : // We might want to return or handle these in the future emit for now.
1307 1 : missing_fields_error.emit ();
1308 1 : return;
1309 1 : }
1310 :
1311 80 : infered = struct_path_ty;
1312 : }
1313 :
1314 : void
1315 1450 : TypeCheckExpr::visit (HIR::StructExprStructFields &struct_expr)
1316 : {
1317 1450 : infered = TypeCheckStructExpr::Resolve (struct_expr);
1318 1450 : }
1319 :
1320 : void
1321 367 : TypeCheckExpr::visit (HIR::GroupedExpr &expr)
1322 : {
1323 367 : infered = TypeCheckExpr::Resolve (expr.get_expr_in_parens ());
1324 366 : }
1325 :
1326 : void
1327 5134 : TypeCheckExpr::visit (HIR::FieldAccessExpr &expr)
1328 : {
1329 5134 : auto struct_base = TypeCheckExpr::Resolve (expr.get_receiver_expr ());
1330 :
1331 : // Box<T> autoderef
1332 5134 : if (auto try_struct_base = TyTy::try_get_box_inner_type (struct_base))
1333 : {
1334 3 : struct_base = *try_struct_base;
1335 : }
1336 :
1337 : // FIXME does this require autoderef here?
1338 5134 : if (struct_base->get_kind () == TyTy::TypeKind::REF)
1339 : {
1340 3509 : TyTy::ReferenceType *r = static_cast<TyTy::ReferenceType *> (struct_base);
1341 3509 : struct_base = r->get_base ();
1342 : }
1343 :
1344 5134 : bool is_valid_type = struct_base->get_kind () == TyTy::TypeKind::ADT;
1345 5134 : if (!is_valid_type)
1346 : {
1347 2 : rust_error_at (expr.get_locus (), "expected algebraic data type got %qs",
1348 2 : struct_base->get_name ().c_str ());
1349 6 : return;
1350 : }
1351 :
1352 5132 : TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (struct_base);
1353 5132 : rust_assert (adt->number_of_variants () > 0);
1354 5132 : TyTy::VariantDef *vaiant = adt->get_variants ().at (0);
1355 :
1356 5132 : TyTy::StructFieldType *lookup = nullptr;
1357 5132 : bool found = vaiant->lookup_field (expr.get_field_name ().as_string (),
1358 : &lookup, nullptr);
1359 5132 : if (!found || adt->is_enum ())
1360 : {
1361 4 : rich_location r (line_table, expr.get_locus ());
1362 4 : r.add_range (expr.get_field_name ().get_locus ());
1363 4 : rust_error_at (r, ErrorCode::E0609, "no field %qs on type %qs",
1364 8 : expr.get_field_name ().as_string ().c_str (),
1365 4 : adt->get_name ().c_str ());
1366 4 : return;
1367 4 : }
1368 :
1369 5128 : infered = lookup->get_field_type ();
1370 : }
1371 :
1372 : bool
1373 43 : is_default_fn (const MethodCandidate &candidate)
1374 : {
1375 43 : if (candidate.candidate.is_impl_candidate ())
1376 : {
1377 43 : auto *item = candidate.candidate.item.impl.impl_item;
1378 :
1379 43 : if (item->get_impl_item_type () == HIR::ImplItem::FUNCTION)
1380 : {
1381 43 : auto &fn = static_cast<HIR::Function &> (*item);
1382 :
1383 43 : return fn.is_default ();
1384 : }
1385 : }
1386 :
1387 : return false;
1388 : }
1389 :
1390 : void
1391 2 : emit_ambiguous_resolution_error (HIR::MethodCallExpr &expr,
1392 : std::set<MethodCandidate> &candidates)
1393 : {
1394 2 : rich_location r (line_table, expr.get_method_name ().get_locus ());
1395 2 : std::string rich_msg = "multiple "
1396 6 : + expr.get_method_name ().get_segment ().to_string ()
1397 2 : + " found";
1398 :
1399 : // We have to filter out default candidates
1400 6 : for (auto &c : candidates)
1401 4 : if (!is_default_fn (c))
1402 4 : r.add_range (c.candidate.locus);
1403 :
1404 2 : r.add_fixit_replace (rich_msg.c_str ());
1405 :
1406 2 : rust_error_at (r, ErrorCode::E0592, "duplicate definitions with name %qs",
1407 6 : expr.get_method_name ().get_segment ().to_string ().c_str ());
1408 2 : }
1409 :
1410 : // We are allowed to have multiple candidates if they are all specializable
1411 : // functions or if all of them except one are specializable functions.
1412 : // In the later case, we just return a valid candidate without erroring out
1413 : // about ambiguity. If there are two or more specialized functions, then we
1414 : // error out.
1415 : //
1416 : // FIXME: The first case is not handled at the moment, so we error out
1417 : tl::optional<const MethodCandidate &>
1418 16 : handle_multiple_candidates (HIR::MethodCallExpr &expr,
1419 : std::set<MethodCandidate> &candidates)
1420 : {
1421 16 : auto all_default = true;
1422 16 : tl::optional<const MethodCandidate &> found = tl::nullopt;
1423 :
1424 53 : for (auto &c : candidates)
1425 : {
1426 39 : if (!is_default_fn (c))
1427 : {
1428 18 : all_default = false;
1429 :
1430 : // We haven't found a final candidate yet, so we can select
1431 : // this one. However, if we already have a candidate, then
1432 : // that means there are multiple non-default candidates - we
1433 : // must error out
1434 18 : if (!found)
1435 : {
1436 : found = c;
1437 : }
1438 : else
1439 : {
1440 2 : emit_ambiguous_resolution_error (expr, candidates);
1441 2 : return tl::nullopt;
1442 : }
1443 : }
1444 : }
1445 :
1446 : // None of the candidates were a non-default (specialized) function, so we
1447 : // error out
1448 14 : if (all_default)
1449 : {
1450 0 : rust_sorry_at (expr.get_locus (),
1451 : "cannot resolve method calls to non-specialized methods "
1452 : "(all function candidates are %qs)",
1453 : "default");
1454 0 : return tl::nullopt;
1455 : }
1456 :
1457 14 : return found;
1458 : }
1459 :
1460 : void
1461 3166 : TypeCheckExpr::visit (HIR::MethodCallExpr &expr)
1462 : {
1463 3166 : auto receiver_tyty = TypeCheckExpr::Resolve (expr.get_receiver ());
1464 3166 : if (receiver_tyty->get_kind () == TyTy::TypeKind::ERROR)
1465 : {
1466 1 : rust_error_at (expr.get_receiver ().get_locus (),
1467 : "failed to resolve receiver in MethodCallExpr");
1468 12 : return;
1469 : }
1470 :
1471 3165 : rust_debug_loc (expr.get_locus (), "attempting to resolve method for %s",
1472 : receiver_tyty->debug_str ().c_str ());
1473 3165 : auto candidates
1474 : = MethodResolver::Probe (receiver_tyty,
1475 3165 : expr.get_method_name ().get_segment ());
1476 3165 : if (candidates.empty ())
1477 : {
1478 7 : rich_location richloc (line_table, expr.get_method_name ().get_locus ());
1479 7 : richloc.add_fixit_replace ("method not found");
1480 7 : rust_error_at (
1481 : richloc, ErrorCode::E0599,
1482 : "no method named %qs found in the current scope",
1483 14 : expr.get_method_name ().get_segment ().to_string ().c_str ());
1484 7 : return;
1485 7 : }
1486 :
1487 3158 : tl::optional<const MethodCandidate &> candidate = *candidates.begin ();
1488 :
1489 3158 : if (candidates.size () > 1)
1490 16 : candidate = handle_multiple_candidates (expr, candidates);
1491 :
1492 3158 : if (!candidate)
1493 : return;
1494 :
1495 3156 : auto found_candidate = *candidate;
1496 :
1497 3156 : rust_debug_loc (expr.get_method_name ().get_locus (),
1498 : "resolved method to: {%u} {%s} with [%lu] adjustments",
1499 : found_candidate.candidate.ty->get_ref (),
1500 : found_candidate.candidate.ty->debug_str ().c_str (),
1501 : (unsigned long) found_candidate.adjustments.size ());
1502 :
1503 : // Get the adjusted self
1504 3156 : Adjuster adj (receiver_tyty);
1505 3156 : TyTy::BaseType *adjusted_self = adj.adjust_type (found_candidate.adjustments);
1506 3156 : rust_debug ("receiver: %s adjusted self %s",
1507 : receiver_tyty->debug_str ().c_str (),
1508 : adjusted_self->debug_str ().c_str ());
1509 :
1510 : // store the adjustments for code-generation to know what to do which must be
1511 : // stored onto the receiver to so as we don't trigger duplicate deref mappings
1512 : // ICE when an argument is a method call
1513 3156 : HirId autoderef_mappings_id
1514 3156 : = expr.get_receiver ().get_mappings ().get_hirid ();
1515 3156 : context->insert_autoderef_mappings (autoderef_mappings_id,
1516 : std::move (found_candidate.adjustments));
1517 :
1518 3156 : PathProbeCandidate &resolved_candidate = found_candidate.candidate;
1519 3156 : TyTy::BaseType *lookup_tyty = found_candidate.candidate.ty;
1520 3156 : NodeId resolved_node_id
1521 3156 : = resolved_candidate.is_impl_candidate ()
1522 3156 : ? resolved_candidate.item.impl.impl_item->get_impl_mappings ()
1523 2165 : .get_nodeid ()
1524 991 : : resolved_candidate.item.trait.item_ref->get_mappings ().get_nodeid ();
1525 :
1526 3156 : if (lookup_tyty->get_kind () != TyTy::TypeKind::FNDEF)
1527 : {
1528 0 : rich_location r (line_table, expr.get_method_name ().get_locus ());
1529 0 : r.add_range (resolved_candidate.locus);
1530 0 : rust_error_at (r, "associated impl item is not a method");
1531 0 : return;
1532 0 : }
1533 :
1534 3156 : TyTy::BaseType *lookup = lookup_tyty;
1535 3156 : TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup);
1536 6312 : if (!fn->is_method ())
1537 : {
1538 0 : rich_location r (line_table, expr.get_method_name ().get_locus ());
1539 0 : r.add_range (resolved_candidate.locus);
1540 0 : rust_error_at (r, "associated function is not a method");
1541 0 : return;
1542 0 : }
1543 :
1544 3156 : rust_debug_loc (expr.get_locus (), "resolved method call to: {%u} {%s}",
1545 : found_candidate.candidate.ty->get_ref (),
1546 : found_candidate.candidate.ty->debug_str ().c_str ());
1547 :
1548 3156 : if (resolved_candidate.is_impl_candidate ())
1549 : {
1550 2165 : auto infer_arguments = TyTy::SubstitutionArgumentMappings::empty ();
1551 2165 : infer_arguments.get_mut_regions ()
1552 2165 : = fn->get_used_arguments ().get_regions ();
1553 2165 : HIR::ImplBlock &impl = *resolved_candidate.item.impl.parent;
1554 2165 : TyTy::BaseType *impl_self_infer
1555 2165 : = TypeCheckItem::ResolveImplBlockSelfWithInference (impl,
1556 : expr.get_locus (),
1557 : &infer_arguments);
1558 2165 : if (impl_self_infer->get_kind () == TyTy::TypeKind::ERROR)
1559 : {
1560 0 : rich_location r (line_table, expr.get_locus ());
1561 0 : r.add_range (impl.get_type ().get_locus ());
1562 0 : rust_error_at (
1563 : r, "failed to resolve impl type for method call resolution");
1564 0 : return;
1565 0 : }
1566 :
1567 2165 : if (!infer_arguments.is_empty ())
1568 588 : lookup = SubstMapperInternal::Resolve (lookup, infer_arguments);
1569 2165 : }
1570 :
1571 : // apply any remaining generic arguments
1572 3156 : if (expr.get_method_name ().has_generic_args ())
1573 : {
1574 29 : HIR::GenericArgs &args = expr.get_method_name ().get_generic_args ();
1575 29 : rust_debug_loc (args.get_locus (),
1576 : "applying generic arguments to method_call: {%s}",
1577 : lookup->debug_str ().c_str ());
1578 :
1579 29 : lookup
1580 29 : = SubstMapper::Resolve (lookup, expr.get_method_name ().get_locus (),
1581 : &args);
1582 29 : if (lookup->get_kind () == TyTy::TypeKind::ERROR)
1583 : return;
1584 : }
1585 3127 : else if (lookup->needs_generic_substitutions ())
1586 : {
1587 893 : rust_debug ("method needs inference: {%s}",
1588 : lookup->debug_str ().c_str ());
1589 893 : lookup = SubstMapper::InferSubst (lookup,
1590 893 : expr.get_method_name ().get_locus ());
1591 : }
1592 :
1593 3155 : rust_debug ("type-checking method_call: {%s}", lookup->debug_str ().c_str ());
1594 :
1595 3155 : TyTy::BaseType *function_ret_tyty
1596 3155 : = TyTy::TypeCheckMethodCallExpr::go (static_cast<TyTy::FnType *> (lookup),
1597 : expr, adjusted_self, context);
1598 3155 : if (function_ret_tyty == nullptr
1599 3155 : || function_ret_tyty->get_kind () == TyTy::TypeKind::ERROR)
1600 : {
1601 0 : rust_error_at (expr.get_locus (),
1602 : "failed to lookup type to MethodCallExpr");
1603 0 : return;
1604 : }
1605 :
1606 : // store the expected fntype
1607 3155 : context->insert_type (expr.get_method_name ().get_mappings (), lookup);
1608 :
1609 3155 : auto &nr_ctx = Resolver2_0::FinalizedNameResolutionContext::get ();
1610 :
1611 3155 : nr_ctx.map_usage (Resolver2_0::Usage (expr.get_mappings ().get_nodeid ()),
1612 3155 : Resolver2_0::Definition (resolved_node_id),
1613 : Resolver2_0::Namespace::Values);
1614 :
1615 : // return the result of the function back
1616 3155 : infered = function_ret_tyty;
1617 3166 : }
1618 :
1619 : void
1620 152 : TypeCheckExpr::visit (HIR::LoopExpr &expr)
1621 : {
1622 152 : context->push_new_loop_context (expr.get_mappings ().get_hirid (),
1623 : expr.get_locus ());
1624 152 : TyTy::BaseType *block_expr = TypeCheckExpr::Resolve (expr.get_loop_block ());
1625 152 : if (!block_expr->is_unit ())
1626 : {
1627 0 : rust_error_at (expr.get_loop_block ().get_locus (),
1628 : "expected %<()%> got %s",
1629 0 : block_expr->as_string ().c_str ());
1630 0 : return;
1631 : }
1632 :
1633 152 : TyTy::BaseType *loop_context_type = context->pop_loop_context ();
1634 :
1635 152 : bool loop_context_type_infered
1636 152 : = (loop_context_type->get_kind () != TyTy::TypeKind::INFER)
1637 152 : || ((loop_context_type->get_kind () == TyTy::TypeKind::INFER)
1638 142 : && (((TyTy::InferType *) loop_context_type)->get_infer_kind ()
1639 286 : != TyTy::InferType::GENERAL));
1640 :
1641 152 : infered = loop_context_type_infered ? loop_context_type
1642 134 : : TyTy::TupleType::get_unit_type ();
1643 : }
1644 :
1645 : void
1646 94 : TypeCheckExpr::visit (HIR::WhileLoopExpr &expr)
1647 : {
1648 94 : context->push_new_while_loop_context (expr.get_mappings ().get_hirid ());
1649 94 : TyTy::BaseType *predicate_type
1650 94 : = TypeCheckExpr::Resolve (expr.get_predicate_expr ());
1651 94 : if (predicate_type->get_kind () != TyTy::TypeKind::BOOL
1652 94 : && predicate_type->get_kind () != TyTy::TypeKind::NEVER)
1653 : {
1654 0 : rust_error_at (expr.get_predicate_expr ().get_locus (),
1655 : "expected boolean expression in %<while%> condition");
1656 0 : context->pop_loop_context ();
1657 0 : return;
1658 : }
1659 94 : TyTy::BaseType *block_expr = TypeCheckExpr::Resolve (expr.get_loop_block ());
1660 94 : if (!block_expr->is_unit ())
1661 : {
1662 0 : rust_error_at (expr.get_loop_block ().get_locus (),
1663 : "expected %<()%> got %s",
1664 0 : block_expr->as_string ().c_str ());
1665 0 : context->pop_loop_context ();
1666 0 : return;
1667 : }
1668 94 : context->pop_loop_context ();
1669 94 : infered = TyTy::TupleType::get_unit_type ();
1670 : }
1671 :
1672 : void
1673 120 : TypeCheckExpr::visit (HIR::BreakExpr &expr)
1674 : {
1675 120 : if (!context->have_loop_context ())
1676 : {
1677 2 : rust_error_at (expr.get_locus (), ErrorCode::E0268,
1678 : "%<break%> outside of a loop or labeled block");
1679 2 : return;
1680 : }
1681 :
1682 118 : if (expr.has_break_expr ())
1683 : {
1684 25 : TyTy::BaseType *break_expr_tyty
1685 25 : = TypeCheckExpr::Resolve (expr.get_expr ());
1686 :
1687 25 : TyTy::BaseType *loop_context = context->peek_loop_context ();
1688 25 : if (loop_context->get_kind () == TyTy::TypeKind::ERROR)
1689 : {
1690 4 : rust_error_at (
1691 : expr.get_locus (), ErrorCode::E0571,
1692 : "can only %<break%> with a value inside a %<loop%> block");
1693 4 : return;
1694 : }
1695 :
1696 21 : TyTy::BaseType *unified_ty
1697 42 : = unify_site (expr.get_mappings ().get_hirid (),
1698 21 : TyTy::TyWithLocation (loop_context),
1699 : TyTy::TyWithLocation (break_expr_tyty,
1700 21 : expr.get_expr ().get_locus ()),
1701 : expr.get_locus ());
1702 21 : context->swap_head_loop_context (unified_ty);
1703 : }
1704 :
1705 114 : infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ());
1706 : }
1707 :
1708 : void
1709 28 : TypeCheckExpr::visit (HIR::ContinueExpr &expr)
1710 : {
1711 28 : if (!context->have_loop_context ())
1712 : {
1713 3 : rust_error_at (expr.get_locus (), ErrorCode::E0268,
1714 : "%<continue%> outside of a loop");
1715 3 : return;
1716 : }
1717 25 : infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ());
1718 : }
1719 :
1720 : void
1721 2158 : TypeCheckExpr::visit (HIR::BorrowExpr &expr)
1722 : {
1723 2158 : TyTy::BaseType *resolved_base = TypeCheckExpr::Resolve (expr.get_expr ());
1724 2158 : if (resolved_base->is<TyTy::ErrorType> ())
1725 : return;
1726 :
1727 : // In Rust this is valid because of DST's
1728 : //
1729 : // fn test() {
1730 : // let a:&str = "TEST 1";
1731 : // let b:&str = &"TEST 2";
1732 : // }
1733 2157 : if (resolved_base->get_kind () == TyTy::TypeKind::REF)
1734 : {
1735 43 : const TyTy::ReferenceType *ref
1736 : = static_cast<const TyTy::ReferenceType *> (resolved_base);
1737 :
1738 : // this might end up being a more generic is_dyn object check but lets
1739 : // double check dyn traits type-layout first
1740 43 : if (ref->is_dyn_str_type ())
1741 : {
1742 9 : infered = resolved_base;
1743 9 : return;
1744 : }
1745 : }
1746 :
1747 2148 : if (expr.is_raw_borrow ())
1748 : {
1749 4 : infered = new TyTy::PointerType (expr.get_mappings ().get_hirid (),
1750 4 : TyTy::TyVar (resolved_base->get_ref ()),
1751 8 : expr.get_mut ());
1752 :
1753 4 : return;
1754 : }
1755 :
1756 2144 : infered = new TyTy::ReferenceType (expr.get_mappings ().get_hirid (),
1757 2144 : TyTy::TyVar (resolved_base->get_ref ()),
1758 4288 : expr.get_mut ());
1759 : }
1760 :
1761 : void
1762 4287 : TypeCheckExpr::visit (HIR::DereferenceExpr &expr)
1763 : {
1764 4287 : TyTy::BaseType *resolved_base = TypeCheckExpr::Resolve (expr.get_expr ());
1765 :
1766 4287 : rust_debug_loc (expr.get_locus (), "attempting deref operator overload");
1767 4287 : auto lang_item_type = LangItem::Kind::DEREF;
1768 4287 : bool operator_overloaded
1769 4287 : = resolve_operator_overload (lang_item_type, expr, resolved_base, nullptr);
1770 4287 : if (operator_overloaded)
1771 : {
1772 : // operator overloaded deref always refurns a reference type lets assert
1773 : // this
1774 50 : rust_assert (infered->get_kind () == TyTy::TypeKind::REF);
1775 50 : resolved_base = infered;
1776 : }
1777 :
1778 4287 : bool is_valid_type = resolved_base->get_kind () == TyTy::TypeKind::REF
1779 4287 : || resolved_base->get_kind () == TyTy::TypeKind::POINTER;
1780 :
1781 4287 : auto try_owned_box = TyTy::try_get_box_inner_type (resolved_base);
1782 :
1783 4287 : if (!is_valid_type && !try_owned_box)
1784 : {
1785 0 : rust_error_at (expr.get_locus (), "expected reference type got %s",
1786 0 : resolved_base->as_string ().c_str ());
1787 0 : return;
1788 : }
1789 :
1790 4287 : if (try_owned_box)
1791 : {
1792 1 : infered = (*try_owned_box)->clone ();
1793 : }
1794 4286 : else if (resolved_base->get_kind () == TyTy::TypeKind::REF)
1795 : {
1796 4077 : TyTy::ReferenceType *ref_base
1797 : = static_cast<TyTy::ReferenceType *> (resolved_base);
1798 4077 : infered = ref_base->get_base ()->clone ();
1799 : }
1800 : else
1801 : {
1802 209 : TyTy::PointerType *ref_base
1803 : = static_cast<TyTy::PointerType *> (resolved_base);
1804 209 : infered = ref_base->get_base ()->clone ();
1805 : }
1806 : }
1807 :
1808 : void
1809 5699 : TypeCheckExpr::visit (HIR::TypeCastExpr &expr)
1810 : {
1811 5699 : TyTy::BaseType *expr_to_convert
1812 5699 : = TypeCheckExpr::Resolve (expr.get_casted_expr ());
1813 5699 : TyTy::BaseType *tyty_to_convert_to
1814 5699 : = TypeCheckType::Resolve (expr.get_type_to_convert_to ());
1815 :
1816 5699 : TyTy::TyWithLocation from (expr_to_convert,
1817 5699 : expr.get_casted_expr ().get_locus ());
1818 5699 : TyTy::TyWithLocation to (tyty_to_convert_to,
1819 5699 : expr.get_type_to_convert_to ().get_locus ());
1820 5699 : infered = cast_site (expr.get_mappings ().get_hirid (), from, to,
1821 : expr.get_locus ());
1822 5699 : }
1823 :
1824 : void
1825 1188 : TypeCheckExpr::visit (HIR::MatchExpr &expr)
1826 : {
1827 : // this needs to perform a least upper bound coercion on the blocks and then
1828 : // unify the scruintee and arms
1829 1188 : TyTy::BaseType *scrutinee_tyty
1830 1188 : = TypeCheckExpr::Resolve (expr.get_scrutinee_expr ());
1831 :
1832 : // https://github.com/Rust-GCC/gccrs/issues/3231#issuecomment-2462660048
1833 : // https://github.com/rust-lang/rust/blob/3d1dba830a564d1118361345d7ada47a05241f45/compiler/rustc_hir_typeck/src/_match.rs#L32-L36
1834 1188 : if (!expr.has_match_arms ())
1835 : {
1836 : // this is a special case where rustc returns !
1837 5 : TyTy::BaseType *lookup = nullptr;
1838 5 : bool ok = context->lookup_builtin ("!", &lookup);
1839 5 : rust_assert (ok);
1840 5 : infered = lookup->clone ();
1841 5 : return;
1842 : }
1843 :
1844 1183 : bool saw_error = false;
1845 1183 : std::vector<TyTy::BaseType *> kase_block_tys;
1846 3948 : for (auto &kase : expr.get_match_cases ())
1847 : {
1848 : // lets check the arms
1849 2765 : HIR::MatchArm &kase_arm = kase.get_arm ();
1850 2765 : auto &pattern = kase_arm.get_pattern ();
1851 2765 : TyTy::BaseType *kase_arm_ty
1852 2765 : = TypeCheckPattern::Resolve (*pattern, scrutinee_tyty);
1853 2765 : if (kase_arm_ty->get_kind () == TyTy ::TypeKind::ERROR)
1854 : {
1855 11 : saw_error = true;
1856 13 : continue;
1857 : }
1858 :
1859 5508 : TyTy::BaseType *checked_kase = unify_site (
1860 2754 : expr.get_mappings ().get_hirid (),
1861 : TyTy::TyWithLocation (scrutinee_tyty,
1862 2754 : expr.get_scrutinee_expr ().get_locus ()),
1863 2754 : TyTy::TyWithLocation (kase_arm_ty, pattern->get_locus ()),
1864 : expr.get_locus ());
1865 2754 : if (checked_kase->get_kind () == TyTy::TypeKind::ERROR)
1866 : {
1867 2 : saw_error = true;
1868 2 : continue;
1869 : }
1870 :
1871 : // the guard is a bool condition evaluated with the bindings of the
1872 : // pattern in scope
1873 2752 : if (kase_arm.has_match_arm_guard ())
1874 : {
1875 62 : TyTy::BaseType *bool_ty = nullptr;
1876 62 : bool ok = context->lookup_builtin ("bool", &bool_ty);
1877 62 : rust_assert (ok);
1878 :
1879 62 : HIR::Expr &guard = kase_arm.get_guard_expr ();
1880 62 : TyTy::BaseType *guard_ty = TypeCheckExpr::Resolve (guard);
1881 62 : unify_site (guard.get_mappings ().get_hirid (),
1882 62 : TyTy::TyWithLocation (bool_ty),
1883 62 : TyTy::TyWithLocation (guard_ty, guard.get_locus ()),
1884 62 : guard.get_locus ());
1885 : }
1886 :
1887 : // check the kase type
1888 2752 : TyTy::BaseType *kase_block_ty = TypeCheckExpr::Resolve (kase.get_expr ());
1889 2752 : kase_block_tys.push_back (kase_block_ty);
1890 : }
1891 1183 : if (saw_error)
1892 : return;
1893 :
1894 1176 : if (kase_block_tys.size () == 0)
1895 : {
1896 0 : infered = TyTy::TupleType::get_unit_type ();
1897 0 : return;
1898 : }
1899 :
1900 : // this is a LUB
1901 1176 : infered = kase_block_tys.at (0);
1902 2744 : for (size_t i = 1; i < kase_block_tys.size (); i++)
1903 : {
1904 1568 : TyTy::BaseType *kase_ty = kase_block_tys.at (i);
1905 1568 : infered
1906 1568 : = coercion_site (expr.get_mappings ().get_hirid (),
1907 1568 : TyTy::TyWithLocation (infered),
1908 1568 : TyTy::TyWithLocation (kase_ty), expr.get_locus ());
1909 : }
1910 1183 : }
1911 :
1912 : void
1913 66 : TypeCheckExpr::visit (HIR::ClosureExpr &expr)
1914 : {
1915 66 : std::vector<TyTy::SubstitutionParamMapping> subst_refs;
1916 66 : HirId ref = expr.get_mappings ().get_hirid ();
1917 66 : DefId id = expr.get_mappings ().get_defid ();
1918 66 : RustIdent ident{CanonicalPath::create_empty (), expr.get_locus ()};
1919 :
1920 66 : if (context->have_function_context ())
1921 : {
1922 64 : TypeCheckContextItem current_context = context->peek_context ();
1923 64 : TyTy::FnType *current_context_fndecl
1924 64 : = current_context.get_context_type ();
1925 :
1926 64 : ident = RustIdent{current_context_fndecl->get_ident ().path,
1927 64 : expr.get_locus ()};
1928 :
1929 64 : subst_refs = current_context_fndecl->clone_substs ();
1930 : }
1931 :
1932 66 : std::vector<TyTy::TyVar> parameter_types;
1933 126 : for (auto &p : expr.get_params ())
1934 : {
1935 60 : TyTy::BaseType *param_tyty = nullptr;
1936 60 : if (p.has_type_given ())
1937 : {
1938 58 : param_tyty = TypeCheckType::Resolve (p.get_type ());
1939 : }
1940 : else
1941 : {
1942 2 : param_tyty = ClosureParamInfer::Resolve (p.get_pattern ());
1943 : }
1944 :
1945 60 : TyTy::TyVar param_ty (param_tyty->get_ref ());
1946 60 : parameter_types.push_back (param_ty);
1947 :
1948 60 : TypeCheckPattern::Resolve (p.get_pattern (), param_ty.get_tyty ());
1949 : }
1950 :
1951 : // we generate an implicit hirid for the closure args
1952 66 : HirId implicit_args_id = mappings.get_next_hir_id ();
1953 66 : TyTy::TupleType *closure_args
1954 : = new TyTy::TupleType (implicit_args_id, expr.get_locus (),
1955 66 : parameter_types);
1956 66 : context->insert_implicit_type (closure_args->get_ref (), closure_args);
1957 :
1958 66 : location_t result_type_locus = expr.has_return_type ()
1959 66 : ? expr.get_return_type ().get_locus ()
1960 66 : : expr.get_locus ();
1961 66 : TyTy::TyVar result_type
1962 66 : = expr.has_return_type ()
1963 66 : ? TyTy::TyVar (
1964 : TypeCheckType::Resolve (expr.get_return_type ())->get_ref ())
1965 66 : : TyTy::TyVar::get_implicit_infer_var (expr.get_locus ());
1966 :
1967 : // resolve the block
1968 66 : location_t closure_expr_locus = expr.get_expr ().get_locus ();
1969 66 : TyTy::BaseType *closure_expr_ty = TypeCheckExpr::Resolve (expr.get_expr ());
1970 132 : coercion_site (expr.get_mappings ().get_hirid (),
1971 : TyTy::TyWithLocation (result_type.get_tyty (),
1972 66 : result_type_locus),
1973 66 : TyTy::TyWithLocation (closure_expr_ty, closure_expr_locus),
1974 : expr.get_locus ());
1975 :
1976 : // generate the closure type
1977 66 : NodeId closure_node_id = expr.get_mappings ().get_nodeid ();
1978 :
1979 : // Resolve closure captures
1980 :
1981 66 : std::set<NodeId> captures;
1982 :
1983 66 : if (auto opt_cap
1984 66 : = Analysis::Mappings::get ().lookup_captures (closure_node_id))
1985 42 : for (auto cap : opt_cap.value ())
1986 21 : captures.insert (cap);
1987 :
1988 66 : infered = new TyTy::ClosureType (ref, id, ident, closure_args, result_type,
1989 132 : subst_refs, captures);
1990 :
1991 : // FIXME
1992 : // all closures automatically inherit the appropriate fn trait. Lets just
1993 : // assume FnOnce for now. I think this is based on the return type of the
1994 : // closure
1995 :
1996 66 : LangItem::Kind lang_item_type = LangItem::Kind::FN_ONCE;
1997 :
1998 66 : DefId respective_lang_item_id
1999 66 : = mappings.get_lang_item (lang_item_type, expr.get_locus ());
2000 :
2001 : // these lang items are always traits
2002 65 : HIR::Item *item = mappings.lookup_defid (respective_lang_item_id).value ();
2003 65 : rust_assert (item->get_item_kind () == HIR::Item::ItemKind::Trait);
2004 65 : HIR::Trait *trait_item = static_cast<HIR::Trait *> (item);
2005 :
2006 65 : TraitReference *trait = TraitResolver::Resolve (*trait_item);
2007 65 : rust_assert (!trait->is_error ());
2008 :
2009 65 : TyTy::TypeBoundPredicate predicate (*trait, BoundPolarity::RegularBound,
2010 65 : expr.get_locus ());
2011 :
2012 : // resolve the trait bound where the <(Args)> are the parameter tuple type
2013 65 : HIR::GenericArgs args = HIR::GenericArgs::create_empty (expr.get_locus ());
2014 :
2015 : // lets generate an implicit Type so that it resolves to the implict tuple
2016 : // type we have created
2017 65 : auto crate_num = mappings.crate.get_current_crate ();
2018 65 : Analysis::NodeMapping mapping (crate_num, expr.get_mappings ().get_nodeid (),
2019 65 : implicit_args_id, UNKNOWN_LOCAL_DEFID);
2020 65 : HIR::TupleType *implicit_tuple
2021 : = new HIR::TupleType (mapping,
2022 : {} // we dont need to fill this out because it will
2023 : // auto resolve because the hir id's match
2024 : ,
2025 65 : expr.get_locus ());
2026 65 : args.get_type_args ().emplace_back (implicit_tuple);
2027 :
2028 : // apply the arguments
2029 65 : predicate.apply_generic_arguments (&args, false, false);
2030 :
2031 : // finally inherit the trait bound
2032 65 : infered->inherit_bound (predicate);
2033 65 : }
2034 :
2035 : bool
2036 13520 : TypeCheckExpr::resolve_operator_overload (
2037 : LangItem::Kind lang_item_type, HIR::OperatorExprMeta expr,
2038 : TyTy::BaseType *lhs, TyTy::BaseType *rhs,
2039 : HIR::PathIdentSegment specified_segment, bool allow_defer,
2040 : TyTy::BaseType *result_type, TyTy::BaseType *probe_lhs)
2041 : {
2042 : // look up lang item for arithmetic type
2043 13520 : std::string associated_item_name = LangItem::ToString (lang_item_type);
2044 :
2045 13520 : auto lang_item_defined = mappings.lookup_lang_item (lang_item_type);
2046 : // probe for the lang-item
2047 13520 : if (!lang_item_defined)
2048 : return false;
2049 :
2050 3112 : DefId &respective_lang_item_id = lang_item_defined.value ();
2051 3112 : auto def_lookup = mappings.lookup_defid (respective_lang_item_id);
2052 3112 : rust_assert (def_lookup.has_value ());
2053 :
2054 3112 : HIR::Item *def_item = def_lookup.value ();
2055 3112 : rust_assert (def_item->get_item_kind () == HIR::Item::ItemKind::Trait);
2056 3112 : HIR::Trait &trait = *static_cast<HIR::Trait *> (def_item);
2057 :
2058 : // we might be in a static or const context and unknown is fine
2059 3112 : TypeCheckContextItem current_context = TypeCheckContextItem::get_error ();
2060 3112 : if (context->have_function_context ())
2061 : {
2062 3097 : current_context = context->peek_context ();
2063 : }
2064 :
2065 3112 : auto segment = specified_segment.is_error ()
2066 4402 : ? HIR::PathIdentSegment (associated_item_name)
2067 3112 : : specified_segment;
2068 3112 : TyTy::BaseType *method_receiver = probe_lhs == nullptr ? lhs : probe_lhs;
2069 3112 : auto candidates
2070 3112 : = MethodResolver::Probe (method_receiver, segment, false, &trait);
2071 :
2072 : // remove any recursive candidates
2073 3112 : std::set<MethodCandidate> resolved_candidates;
2074 6452 : for (auto &c : candidates)
2075 : {
2076 3340 : const TyTy::BaseType *candidate_type = c.candidate.ty;
2077 3340 : rust_assert (candidate_type->get_kind () == TyTy::TypeKind::FNDEF);
2078 :
2079 3340 : const TyTy::FnType &fn
2080 : = *static_cast<const TyTy::FnType *> (candidate_type);
2081 :
2082 3362 : if (probe_lhs != nullptr
2083 5187 : && !types_compatable (TyTy::TyWithLocation (fn.get_self_type ()),
2084 1847 : TyTy::TyWithLocation (probe_lhs),
2085 : UNDEF_LOCATION, false /* emit_errors */))
2086 22 : continue;
2087 :
2088 3318 : DefId current_fn_defid = current_context.get_defid ();
2089 6636 : bool recursive_candidated = fn.get_id () == current_fn_defid;
2090 1850 : if (!recursive_candidated)
2091 : {
2092 1850 : resolved_candidates.insert (c);
2093 : }
2094 : }
2095 :
2096 3112 : std::vector<TyTy::BaseType *> select_args = {};
2097 3112 : if (rhs != nullptr)
2098 2882 : select_args = {rhs};
2099 3112 : auto selected_candidates
2100 3112 : = MethodResolver::Select (resolved_candidates, method_receiver, select_args,
2101 3112 : result_type);
2102 :
2103 3112 : bool have_implementation_for_lang_item = selected_candidates.size () > 0;
2104 3112 : if (!have_implementation_for_lang_item)
2105 : return false;
2106 :
2107 1514 : if (selected_candidates.size () > 1)
2108 : {
2109 15 : if (!allow_defer)
2110 : return false;
2111 :
2112 15 : TyTy::TyVar result_type
2113 15 : = TyTy::TyVar::get_implicit_infer_var (expr.get_locus ());
2114 15 : TyTy::BaseType *result_tyty = result_type.get_tyty ();
2115 15 : rust_assert (result_tyty != nullptr);
2116 15 : rust_debug ("deferring operator expr=%u result-ref=%u result-ty-ref=%u "
2117 : "lhs-ref=%u rhs-ref=%u",
2118 : expr.get_mappings ().get_hirid (), result_type.get_ref (),
2119 : result_tyty->get_ty_ref (), lhs->get_ref (),
2120 : rhs == nullptr ? UNKNOWN_HIRID : rhs->get_ref ());
2121 30 : DeferredOpOverload defer (expr.get_mappings ().get_hirid (),
2122 : lang_item_type, specified_segment, expr,
2123 30 : result_type);
2124 15 : context->insert_deferred_operator_overload (std::move (defer));
2125 :
2126 15 : infered = result_tyty;
2127 15 : return true;
2128 15 : }
2129 :
2130 : // Get the adjusted self
2131 1499 : MethodCandidate candidate = *selected_candidates.begin ();
2132 1499 : if (probe_lhs != nullptr)
2133 992 : candidate.adjustments.insert (
2134 992 : candidate.adjustments.begin (),
2135 992 : Adjustment (Adjustment::AdjustmentType::IMM_REF, lhs, probe_lhs));
2136 1499 : Adjuster adj (lhs);
2137 1499 : TyTy::BaseType *adjusted_self = adj.adjust_type (candidate.adjustments);
2138 :
2139 : // store the adjustments for code-generation to know what to do
2140 1499 : context->insert_autoderef_mappings (expr.get_lvalue_mappings ().get_hirid (),
2141 : std::move (candidate.adjustments));
2142 :
2143 1499 : PathProbeCandidate &resolved_candidate = candidate.candidate;
2144 1499 : TyTy::BaseType *lookup_tyty = candidate.candidate.ty;
2145 1499 : NodeId resolved_node_id
2146 1499 : = resolved_candidate.is_impl_candidate ()
2147 1499 : ? resolved_candidate.item.impl.impl_item->get_impl_mappings ()
2148 1095 : .get_nodeid ()
2149 404 : : resolved_candidate.item.trait.item_ref->get_mappings ().get_nodeid ();
2150 :
2151 1499 : rust_assert (lookup_tyty->get_kind () == TyTy::TypeKind::FNDEF);
2152 1499 : TyTy::BaseType *lookup = lookup_tyty;
2153 1499 : TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup);
2154 2998 : rust_assert (fn->is_method ());
2155 :
2156 1499 : rust_debug ("is_impl_item_candidate: %s",
2157 : resolved_candidate.is_impl_candidate () ? "true" : "false");
2158 :
2159 : // in the case where we resolve to a trait bound we have to be careful we are
2160 : // able to do so there is a case where we are currently resolving the deref
2161 : // operator overload function which is generic and this might resolve to the
2162 : // trait item of deref which is not valid as its just another recursive case
2163 1499 : if (current_context.get_type () == TypeCheckContextItem::ItemType::IMPL_ITEM)
2164 : {
2165 781 : auto &impl_item = current_context.get_impl_item ();
2166 781 : HIR::ImplBlock *parent = impl_item.first;
2167 781 : HIR::Function *fn = impl_item.second;
2168 :
2169 781 : bool is_deref = lang_item_type == LangItem::Kind::DEREF
2170 781 : || lang_item_type == LangItem::Kind::DEREF_MUT;
2171 3124 : bool is_deref_match = fn->get_function_name ().as_string ().compare (
2172 1562 : LangItem::ToString (LangItem::Kind::DEREF))
2173 : == 0
2174 2196 : || fn->get_function_name ().as_string ().compare (
2175 1415 : LangItem::ToString (LangItem::Kind::DEREF_MUT))
2176 : == 0;
2177 :
2178 781 : bool is_recursive_op
2179 1562 : = fn->get_function_name ().as_string ().compare (associated_item_name)
2180 : == 0
2181 781 : || (is_deref && is_deref_match);
2182 781 : if (parent->has_trait_ref () && is_recursive_op)
2183 : {
2184 336 : TraitReference *trait_reference
2185 336 : = TraitResolver::Lookup (parent->get_trait_ref ());
2186 336 : if (!trait_reference->is_error ())
2187 : {
2188 336 : TyTy::BaseType *lookup = nullptr;
2189 336 : bool ok = context->lookup_type (fn->get_mappings ().get_hirid (),
2190 : &lookup);
2191 336 : rust_assert (ok);
2192 336 : rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF);
2193 :
2194 336 : TyTy::FnType *fntype = static_cast<TyTy::FnType *> (lookup);
2195 672 : rust_assert (fntype->is_method ());
2196 :
2197 336 : bool is_lang_item_impl
2198 336 : = trait_reference->get_mappings ().get_defid ()
2199 338 : == respective_lang_item_id
2200 2 : || (is_deref && is_deref_match);
2201 336 : bool self_is_lang_item_self
2202 336 : = fntype->get_self_type ()->is_equal (*adjusted_self);
2203 336 : bool recursive_operator_overload
2204 : = is_lang_item_impl && self_is_lang_item_self;
2205 :
2206 336 : if (recursive_operator_overload)
2207 150 : return false;
2208 : }
2209 : }
2210 : }
2211 :
2212 : // we found a valid operator overload
2213 1349 : rust_debug_loc (expr.get_locus (), "resolved operator overload to: {%u} {%s}",
2214 : candidate.candidate.ty->get_ref (),
2215 : candidate.candidate.ty->debug_str ().c_str ());
2216 :
2217 : // handle generics
2218 1349 : if (lookup->needs_generic_substitutions ())
2219 397 : lookup = SubstMapper::InferSubst (lookup, expr.get_locus ());
2220 :
2221 : // type check the arguments if required
2222 1349 : TyTy::FnType *type = static_cast<TyTy::FnType *> (lookup);
2223 1349 : rust_assert (type->num_params () > 0);
2224 1349 : auto &fnparam = type->param_at (0);
2225 :
2226 : // typecheck the self
2227 2698 : unify_site (expr.get_mappings ().get_hirid (),
2228 1349 : TyTy::TyWithLocation (fnparam.get_type ()),
2229 1349 : TyTy::TyWithLocation (adjusted_self), expr.get_locus ());
2230 1349 : if (rhs == nullptr)
2231 : {
2232 64 : rust_assert (type->num_params () == 1);
2233 : }
2234 : else
2235 : {
2236 1285 : rust_assert (type->num_params () == 2);
2237 1285 : auto &fnparam = type->param_at (1);
2238 2570 : unify_site (expr.get_mappings ().get_hirid (),
2239 1285 : TyTy::TyWithLocation (fnparam.get_type ()),
2240 1285 : TyTy::TyWithLocation (rhs), expr.get_locus ());
2241 : }
2242 :
2243 1349 : rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF);
2244 1349 : fn = static_cast<TyTy::FnType *> (lookup);
2245 1349 : fn->monomorphize ();
2246 :
2247 : // get the return type
2248 1349 : TyTy::BaseType *function_ret_tyty
2249 1349 : = type->get_return_type ()->monomorphized_clone ();
2250 :
2251 : // store the expected fntype
2252 1349 : context->insert_operator_overload (expr.get_mappings ().get_hirid (), type);
2253 :
2254 : // set up the resolved name on the path
2255 1349 : auto &nr_ctx = Resolver2_0::FinalizedNameResolutionContext::get ();
2256 :
2257 1349 : nr_ctx.map_usage (Resolver2_0::Usage (expr.get_mappings ().get_nodeid ()),
2258 1349 : Resolver2_0::Definition (resolved_node_id),
2259 : Resolver2_0::Namespace::Types);
2260 :
2261 : // return the result of the function back
2262 1349 : infered = function_ret_tyty;
2263 :
2264 1349 : return true;
2265 4611 : }
2266 :
2267 : HIR::PathIdentSegment
2268 11874 : TypeCheckExpr::resolve_possible_fn_trait_call_method_name (
2269 : const TyTy::BaseType &receiver,
2270 : TyTy::TypeBoundPredicate *associated_predicate)
2271 : {
2272 : // FIXME
2273 : // the logic to map the FnTrait to their respective call trait-item is
2274 : // duplicated over in the backend/rust-compile-expr.cc
2275 11901 : for (const auto &bound : receiver.get_specified_bounds ())
2276 : {
2277 93 : bool found_fn = bound.get_name ().compare ("Fn") == 0;
2278 93 : bool found_fn_mut = bound.get_name ().compare ("FnMut") == 0;
2279 93 : bool found_fn_once = bound.get_name ().compare ("FnOnce") == 0;
2280 :
2281 93 : if (found_fn)
2282 : {
2283 0 : *associated_predicate = bound;
2284 0 : return HIR::PathIdentSegment ("call");
2285 : }
2286 93 : else if (found_fn_mut)
2287 : {
2288 0 : *associated_predicate = bound;
2289 0 : return HIR::PathIdentSegment ("call_mut");
2290 : }
2291 93 : else if (found_fn_once)
2292 : {
2293 66 : *associated_predicate = bound;
2294 66 : return HIR::PathIdentSegment ("call_once");
2295 : }
2296 : }
2297 :
2298 11808 : if (receiver.is<TyTy::ReferenceType> ())
2299 : {
2300 0 : const auto &ref = static_cast<const TyTy::ReferenceType &> (receiver);
2301 0 : const auto &underlying = *ref.get_base ();
2302 0 : for (const auto &bound : underlying.get_specified_bounds ())
2303 : {
2304 0 : bool found_fn = bound.get_name ().compare ("Fn") == 0;
2305 0 : bool found_fn_mut = bound.get_name ().compare ("FnMut") == 0;
2306 0 : bool found_fn_once = bound.get_name ().compare ("FnOnce") == 0;
2307 :
2308 0 : if (found_fn)
2309 : {
2310 0 : *associated_predicate = bound;
2311 0 : return HIR::PathIdentSegment ("call");
2312 : }
2313 0 : else if (found_fn_mut)
2314 : {
2315 0 : *associated_predicate = bound;
2316 0 : return HIR::PathIdentSegment ("call_mut");
2317 : }
2318 0 : else if (found_fn_once)
2319 : {
2320 0 : *associated_predicate = bound;
2321 0 : return HIR::PathIdentSegment ("call_once");
2322 : }
2323 : }
2324 : }
2325 :
2326 : // nothing
2327 11808 : *associated_predicate = TyTy::TypeBoundPredicate::error ();
2328 11808 : return HIR::PathIdentSegment ("");
2329 : }
2330 :
2331 : bool
2332 11874 : TypeCheckExpr::resolve_fn_trait_call (HIR::CallExpr &expr,
2333 : TyTy::BaseType *receiver_tyty,
2334 : TyTy::BaseType **result)
2335 : {
2336 : // we turn this into a method call expr
2337 : // TODO: add implicit self argument (?)
2338 11874 : auto associated_predicate = TyTy::TypeBoundPredicate::error ();
2339 11874 : HIR::PathIdentSegment method_name
2340 : = resolve_possible_fn_trait_call_method_name (*receiver_tyty,
2341 11874 : &associated_predicate);
2342 11874 : if (method_name.is_error () || associated_predicate.is_error ())
2343 : return false;
2344 :
2345 66 : auto candidates = MethodResolver::Probe (receiver_tyty, method_name);
2346 66 : if (candidates.empty ())
2347 : return false;
2348 :
2349 66 : if (candidates.size () > 1)
2350 : {
2351 0 : rich_location r (line_table, expr.get_locus ());
2352 0 : for (auto &c : candidates)
2353 0 : r.add_range (c.candidate.locus);
2354 :
2355 0 : rust_error_at (
2356 : r, "multiple candidates found for function trait method call %qs",
2357 0 : method_name.to_string ().c_str ());
2358 0 : return false;
2359 0 : }
2360 :
2361 : // FnOnce::Output is normalized lazily by normalize_projection's closure
2362 : // special-case; no explicit setup is required here.
2363 :
2364 66 : auto candidate = *candidates.begin ();
2365 66 : rust_debug_loc (expr.get_locus (),
2366 : "resolved call-expr to fn trait: {%u} {%s}",
2367 : candidate.candidate.ty->get_ref (),
2368 : candidate.candidate.ty->debug_str ().c_str ());
2369 :
2370 : // Get the adjusted self
2371 66 : Adjuster adj (receiver_tyty);
2372 66 : TyTy::BaseType *adjusted_self = adj.adjust_type (candidate.adjustments);
2373 :
2374 : // store the adjustments for code-generation to know what to do which must be
2375 : // stored onto the receiver to so as we don't trigger duplicate deref mappings
2376 : // ICE when an argument is a method call
2377 66 : HIR::Expr &fnexpr = expr.get_fnexpr ();
2378 66 : HirId autoderef_mappings_id = fnexpr.get_mappings ().get_hirid ();
2379 66 : context->insert_autoderef_mappings (autoderef_mappings_id,
2380 : std::move (candidate.adjustments));
2381 :
2382 66 : PathProbeCandidate &resolved_candidate = candidate.candidate;
2383 66 : TyTy::BaseType *lookup_tyty = candidate.candidate.ty;
2384 66 : NodeId resolved_node_id
2385 66 : = resolved_candidate.is_impl_candidate ()
2386 66 : ? resolved_candidate.item.impl.impl_item->get_impl_mappings ()
2387 0 : .get_nodeid ()
2388 66 : : resolved_candidate.item.trait.item_ref->get_mappings ().get_nodeid ();
2389 :
2390 66 : if (lookup_tyty->get_kind () != TyTy::TypeKind::FNDEF)
2391 : {
2392 0 : rich_location r (line_table, expr.get_locus ());
2393 0 : r.add_range (resolved_candidate.locus);
2394 0 : rust_error_at (r, "associated impl item is not a method");
2395 0 : return false;
2396 0 : }
2397 :
2398 66 : TyTy::BaseType *lookup = lookup_tyty;
2399 66 : TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup);
2400 132 : if (!fn->is_method ())
2401 : {
2402 0 : rich_location r (line_table, expr.get_locus ());
2403 0 : r.add_range (resolved_candidate.locus);
2404 0 : rust_error_at (r, "associated function is not a method");
2405 0 : return false;
2406 0 : }
2407 :
2408 : // fn traits only support tuple argument passing so we need to implicitly set
2409 : // this up to get the same type checking we get in the rest of the pipeline
2410 :
2411 66 : std::vector<TyTy::TyVar> call_args;
2412 132 : for (auto &arg : expr.get_arguments ())
2413 : {
2414 66 : TyTy::BaseType *a = TypeCheckExpr::Resolve (*arg);
2415 66 : call_args.emplace_back (a->get_ref ());
2416 : }
2417 :
2418 : // crate implicit tuple
2419 66 : HirId implicit_arg_id = mappings.get_next_hir_id ();
2420 66 : Analysis::NodeMapping mapping (mappings.crate.get_current_crate (),
2421 : UNKNOWN_NODEID, implicit_arg_id,
2422 66 : UNKNOWN_LOCAL_DEFID);
2423 :
2424 66 : TyTy::TupleType *tuple
2425 66 : = new TyTy::TupleType (implicit_arg_id, expr.get_locus (), call_args);
2426 66 : context->insert_implicit_type (implicit_arg_id, tuple);
2427 :
2428 66 : std::vector<TyTy::Argument> args;
2429 66 : args.emplace_back (mapping, tuple,
2430 66 : expr.get_locus () /*FIXME is there a better location*/);
2431 :
2432 66 : TyTy::BaseType *function_ret_tyty
2433 66 : = TyTy::TypeCheckMethodCallExpr::go (fn, expr.get_mappings (), args,
2434 : expr.get_locus (), expr.get_locus (),
2435 : adjusted_self, context);
2436 66 : if (function_ret_tyty == nullptr
2437 66 : || function_ret_tyty->get_kind () == TyTy::TypeKind::ERROR)
2438 : {
2439 0 : rust_error_at (expr.get_locus (),
2440 : "failed check fn trait call-expr MethodCallExpr");
2441 0 : return false;
2442 : }
2443 :
2444 : // store the expected fntype
2445 66 : context->insert_operator_overload (expr.get_mappings ().get_hirid (), fn);
2446 :
2447 : // set up the resolved name on the path
2448 66 : auto &nr_ctx = Resolver2_0::FinalizedNameResolutionContext::get ();
2449 :
2450 : // TODO: What namespace to use for inserting and looking up here? It's a trait
2451 : // call, so NS::Types is right?
2452 :
2453 66 : auto existing = nr_ctx.lookup (expr.get_mappings ().get_nodeid (),
2454 : Resolver2_0::Namespace::Types);
2455 66 : if (existing)
2456 9 : rust_assert (*existing == resolved_node_id);
2457 : else
2458 57 : nr_ctx.map_usage (Resolver2_0::Usage (expr.get_mappings ().get_nodeid ()),
2459 57 : Resolver2_0::Definition (resolved_node_id),
2460 : Resolver2_0::Namespace::Types);
2461 :
2462 : // return the result of the function back
2463 66 : auto mono = function_ret_tyty->monomorphized_clone ();
2464 66 : *result = mono;
2465 :
2466 66 : return true;
2467 12072 : }
2468 :
2469 : bool
2470 8608 : TypeCheckExpr::validate_arithmetic_type (
2471 : const TyTy::BaseType *tyty, HIR::ArithmeticOrLogicalExpr::ExprType expr_type)
2472 : {
2473 8608 : auto type = tyty->destructure ();
2474 8608 : if (type->get_kind () == TyTy::TypeKind::CONST)
2475 : {
2476 15 : auto base_const = type->as_const_type ();
2477 15 : type = base_const->get_specified_type ();
2478 : }
2479 :
2480 : // https://doc.rust-lang.org/reference/expressions/operator-expr.html#arithmetic-and-logical-binary-operators
2481 : // this will change later when traits are added
2482 8608 : switch (expr_type)
2483 : {
2484 7392 : case ArithmeticOrLogicalOperator::ADD:
2485 7392 : case ArithmeticOrLogicalOperator::SUBTRACT:
2486 7392 : case ArithmeticOrLogicalOperator::MULTIPLY:
2487 7392 : case ArithmeticOrLogicalOperator::DIVIDE:
2488 7392 : case ArithmeticOrLogicalOperator::MODULUS:
2489 7392 : return (type->get_kind () == TyTy::TypeKind::INT)
2490 5543 : || (type->get_kind () == TyTy::TypeKind::UINT)
2491 4496 : || (type->get_kind () == TyTy::TypeKind::FLOAT)
2492 4046 : || (type->get_kind () == TyTy::TypeKind::USIZE)
2493 3349 : || (type->get_kind () == TyTy::TypeKind::ISIZE)
2494 3267 : || (type->get_kind () == TyTy::TypeKind::INFER
2495 3264 : && (((const TyTy::InferType *) type)->get_infer_kind ()
2496 : == TyTy::InferType::INTEGRAL))
2497 7432 : || (type->get_kind () == TyTy::TypeKind::INFER
2498 37 : && (((const TyTy::InferType *) type)->get_infer_kind ()
2499 : == TyTy::InferType::FLOAT));
2500 :
2501 : // integers or bools
2502 1050 : case ArithmeticOrLogicalOperator::BITWISE_AND:
2503 1050 : case ArithmeticOrLogicalOperator::BITWISE_OR:
2504 1050 : case ArithmeticOrLogicalOperator::BITWISE_XOR:
2505 1050 : return (type->get_kind () == TyTy::TypeKind::INT)
2506 973 : || (type->get_kind () == TyTy::TypeKind::UINT)
2507 173 : || (type->get_kind () == TyTy::TypeKind::USIZE)
2508 166 : || (type->get_kind () == TyTy::TypeKind::ISIZE)
2509 166 : || (type->get_kind () == TyTy::TypeKind::BOOL)
2510 1174 : || (type->get_kind () == TyTy::TypeKind::INFER
2511 124 : && (((const TyTy::InferType *) type)->get_infer_kind ()
2512 : == TyTy::InferType::INTEGRAL));
2513 :
2514 : // integers only
2515 166 : case ArithmeticOrLogicalOperator::LEFT_SHIFT:
2516 166 : case ArithmeticOrLogicalOperator::RIGHT_SHIFT:
2517 166 : return (type->get_kind () == TyTy::TypeKind::INT)
2518 151 : || (type->get_kind () == TyTy::TypeKind::UINT)
2519 93 : || (type->get_kind () == TyTy::TypeKind::USIZE)
2520 91 : || (type->get_kind () == TyTy::TypeKind::ISIZE)
2521 257 : || (type->get_kind () == TyTy::TypeKind::INFER
2522 91 : && (((const TyTy::InferType *) type)->get_infer_kind ()
2523 : == TyTy::InferType::INTEGRAL));
2524 : }
2525 :
2526 0 : rust_unreachable ();
2527 : return false;
2528 : }
2529 :
2530 : } // namespace Resolver
2531 : } // namespace Rust
|