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