[PR testsuite/116860] Testsuite adjustment for recently added tests
[official-gcc.git] / gcc / rust / typecheck / rust-hir-type-check-expr.cc
blobb3271b678338ea9d607fcf59cbbe2e26051e2813
1 // Copyright (C) 2020-2025 Free Software Foundation, Inc.
3 // This file is part of GCC.
5 // GCC is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU General Public License as published by the Free
7 // Software Foundation; either version 3, or (at your option) any later
8 // version.
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.
15 // You should have received a copy of the GNU General Public License
16 // along with GCC; see the file COPYING3. If not see
17 // <http://www.gnu.org/licenses/>.
19 #include "rust-tyty-call.h"
20 #include "rust-hir-type-check-struct-field.h"
21 #include "rust-hir-path-probe.h"
22 #include "rust-substitution-mapper.h"
23 #include "rust-hir-trait-resolve.h"
24 #include "rust-hir-dot-operator.h"
25 #include "rust-hir-type-check-pattern.h"
26 #include "rust-hir-type-check-expr.h"
27 #include "rust-hir-type-check-stmt.h"
28 #include "rust-hir-type-check-item.h"
29 #include "rust-type-util.h"
31 namespace Rust {
32 namespace Resolver {
34 TypeCheckExpr::TypeCheckExpr () : TypeCheckBase (), infered (nullptr) {}
36 // Perform type checking on expr. Also runs type unification algorithm.
37 // Returns the unified type of expr
38 TyTy::BaseType *
39 TypeCheckExpr::Resolve (HIR::Expr *expr)
41 TypeCheckExpr resolver;
42 expr->accept_vis (resolver);
44 if (resolver.infered == nullptr)
45 return new TyTy::ErrorType (expr->get_mappings ().get_hirid ());
47 auto ref = expr->get_mappings ().get_hirid ();
48 resolver.infered->set_ref (ref);
49 resolver.context->insert_type (expr->get_mappings (), resolver.infered);
51 return resolver.infered;
54 void
55 TypeCheckExpr::visit (HIR::TupleIndexExpr &expr)
57 auto resolved = TypeCheckExpr::Resolve (expr.get_tuple_expr ().get ());
58 if (resolved->get_kind () == TyTy::TypeKind::ERROR)
60 rust_error_at (expr.get_tuple_expr ()->get_locus (),
61 "failed to resolve TupleIndexExpr receiver");
62 return;
65 // FIXME does this require autoderef here?
66 if (resolved->get_kind () == TyTy::TypeKind::REF)
68 TyTy::ReferenceType *r = static_cast<TyTy::ReferenceType *> (resolved);
69 resolved = r->get_base ();
72 bool is_valid_type = resolved->get_kind () == TyTy::TypeKind::ADT
73 || resolved->get_kind () == TyTy::TypeKind::TUPLE;
74 if (!is_valid_type)
76 rust_error_at (expr.get_tuple_expr ()->get_locus (),
77 "Expected Tuple or ADT got: %s",
78 resolved->as_string ().c_str ());
79 return;
82 if (resolved->get_kind () == TyTy::TypeKind::TUPLE)
84 TyTy::TupleType *tuple = static_cast<TyTy::TupleType *> (resolved);
85 TupleIndex index = expr.get_tuple_index ();
86 if ((size_t) index >= tuple->num_fields ())
88 rust_error_at (expr.get_locus (), "unknown field at index %i", index);
89 return;
92 auto field_tyty = tuple->get_field ((size_t) index);
93 if (field_tyty == nullptr)
95 rust_error_at (expr.get_locus (),
96 "failed to lookup field type at index %i", index);
97 return;
100 infered = field_tyty;
101 return;
104 TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (resolved);
105 rust_assert (!adt->is_enum ());
106 rust_assert (adt->number_of_variants () == 1);
108 TyTy::VariantDef *variant = adt->get_variants ().at (0);
109 TupleIndex index = expr.get_tuple_index ();
110 if ((size_t) index >= variant->num_fields ())
112 rust_error_at (expr.get_locus (), "unknown field at index %i", index);
113 return;
116 auto field_tyty = variant->get_field_at_index ((size_t) index);
117 if (field_tyty == nullptr)
119 rust_error_at (expr.get_locus (),
120 "failed to lookup field type at index %i", index);
121 return;
124 infered = field_tyty->get_field_type ();
127 void
128 TypeCheckExpr::visit (HIR::TupleExpr &expr)
130 if (expr.is_unit ())
132 auto unit_node_id = resolver->get_unit_type_node_id ();
133 if (!context->lookup_builtin (unit_node_id, &infered))
135 rust_error_at (expr.get_locus (),
136 "failed to lookup builtin unit type");
138 return;
141 std::vector<TyTy::TyVar> fields;
142 for (auto &elem : expr.get_tuple_elems ())
144 auto field_ty = TypeCheckExpr::Resolve (elem.get ());
145 fields.push_back (TyTy::TyVar (field_ty->get_ref ()));
147 infered = new TyTy::TupleType (expr.get_mappings ().get_hirid (),
148 expr.get_locus (), fields);
151 void
152 TypeCheckExpr::visit (HIR::ReturnExpr &expr)
154 if (!context->have_function_context ())
156 rust_error_at (expr.get_locus (), ErrorCode::E0572,
157 "return statement outside of function body");
158 infered = new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
159 return;
162 auto fn_return_tyty = context->peek_return_type ();
163 location_t expr_locus = expr.has_return_expr ()
164 ? expr.get_expr ()->get_locus ()
165 : expr.get_locus ();
166 TyTy::BaseType *expr_ty
167 = expr.has_return_expr ()
168 ? TypeCheckExpr::Resolve (expr.get_expr ().get ())
169 : TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ());
171 coercion_site (expr.get_mappings ().get_hirid (),
172 TyTy::TyWithLocation (fn_return_tyty),
173 TyTy::TyWithLocation (expr_ty, expr_locus), expr.get_locus ());
175 infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ());
178 void
179 TypeCheckExpr::visit (HIR::CallExpr &expr)
181 TyTy::BaseType *function_tyty
182 = TypeCheckExpr::Resolve (expr.get_fnexpr ().get ());
184 rust_debug_loc (expr.get_locus (), "resolved_call_expr to: {%s}",
185 function_tyty->get_name ().c_str ());
187 TyTy::VariantDef &variant = TyTy::VariantDef::get_error_node ();
188 if (function_tyty->get_kind () == TyTy::TypeKind::ADT)
190 TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (function_tyty);
191 if (adt->is_enum ())
193 // lookup variant id
194 HirId variant_id;
195 bool ok = context->lookup_variant_definition (
196 expr.get_fnexpr ()->get_mappings ().get_hirid (), &variant_id);
197 rust_assert (ok);
199 TyTy::VariantDef *lookup_variant = nullptr;
200 ok = adt->lookup_variant_by_id (variant_id, &lookup_variant);
201 rust_assert (ok);
203 variant = *lookup_variant;
205 else
207 rust_assert (adt->number_of_variants () == 1);
208 variant = *adt->get_variants ().at (0);
211 infered
212 = TyTy::TypeCheckCallExpr::go (function_tyty, expr, variant, context);
213 return;
216 bool resolved_fn_trait_call
217 = resolve_fn_trait_call (expr, function_tyty, &infered);
218 if (resolved_fn_trait_call)
219 return;
221 bool valid_tyty = function_tyty->get_kind () == TyTy::TypeKind::FNDEF
222 || function_tyty->get_kind () == TyTy::TypeKind::FNPTR;
223 if (!valid_tyty)
225 rust_error_at (expr.get_locus (),
226 "Failed to resolve expression of function call");
227 return;
230 infered = TyTy::TypeCheckCallExpr::go (function_tyty, expr, variant, context);
233 void
234 TypeCheckExpr::visit (HIR::AssignmentExpr &expr)
236 infered = TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ());
238 auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ().get ());
239 auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ().get ());
241 coercion_site (expr.get_mappings ().get_hirid (),
242 TyTy::TyWithLocation (lhs, expr.get_lhs ()->get_locus ()),
243 TyTy::TyWithLocation (rhs, expr.get_rhs ()->get_locus ()),
244 expr.get_locus ());
247 void
248 TypeCheckExpr::visit (HIR::CompoundAssignmentExpr &expr)
250 infered = TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ());
252 auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ().get ());
253 auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ().get ());
255 // we dont care about the result of the unify from a compound assignment
256 // since this is a unit-type expr
257 coercion_site (expr.get_mappings ().get_hirid (),
258 TyTy::TyWithLocation (lhs, expr.get_lhs ()->get_locus ()),
259 TyTy::TyWithLocation (rhs, expr.get_rhs ()->get_locus ()),
260 expr.get_locus ());
262 auto lang_item_type
263 = LangItem::CompoundAssignmentOperatorToLangItem (expr.get_expr_type ());
264 bool operator_overloaded
265 = resolve_operator_overload (lang_item_type, expr, lhs, rhs);
266 if (operator_overloaded)
267 return;
269 bool valid_lhs = validate_arithmetic_type (lhs, expr.get_expr_type ());
270 bool valid_rhs = validate_arithmetic_type (rhs, expr.get_expr_type ());
271 bool valid = valid_lhs && valid_rhs;
272 if (!valid)
274 rust_error_at (expr.get_locus (),
275 "cannot apply this operator to types %s and %s",
276 lhs->as_string ().c_str (), rhs->as_string ().c_str ());
277 return;
281 void
282 TypeCheckExpr::visit (HIR::LiteralExpr &expr)
284 infered = resolve_literal (expr.get_mappings (), expr.get_literal (),
285 expr.get_locus ());
288 void
289 TypeCheckExpr::visit (HIR::ArithmeticOrLogicalExpr &expr)
291 auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ().get ());
292 auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ().get ());
294 auto lang_item_type = LangItem::OperatorToLangItem (expr.get_expr_type ());
295 bool operator_overloaded
296 = resolve_operator_overload (lang_item_type, expr, lhs, rhs);
297 if (operator_overloaded)
298 return;
300 bool valid_lhs = validate_arithmetic_type (lhs, expr.get_expr_type ());
301 bool valid_rhs = validate_arithmetic_type (rhs, expr.get_expr_type ());
302 bool valid = valid_lhs && valid_rhs;
303 if (!valid)
305 rust_error_at (expr.get_locus (),
306 "cannot apply this operator to types %s and %s",
307 lhs->as_string ().c_str (), rhs->as_string ().c_str ());
308 return;
311 switch (expr.get_expr_type ())
313 case ArithmeticOrLogicalOperator::LEFT_SHIFT:
314 case ArithmeticOrLogicalOperator::RIGHT_SHIFT: {
315 TyTy::TyWithLocation from (rhs, expr.get_rhs ()->get_locus ());
316 TyTy::TyWithLocation to (lhs, expr.get_lhs ()->get_locus ());
317 infered = cast_site (expr.get_mappings ().get_hirid (), from, to,
318 expr.get_locus ());
320 break;
322 default: {
323 infered = unify_site (
324 expr.get_mappings ().get_hirid (),
325 TyTy::TyWithLocation (lhs, expr.get_lhs ()->get_locus ()),
326 TyTy::TyWithLocation (rhs, expr.get_rhs ()->get_locus ()),
327 expr.get_locus ());
329 break;
333 void
334 TypeCheckExpr::visit (HIR::ComparisonExpr &expr)
336 auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ().get ());
337 auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ().get ());
339 unify_site (expr.get_mappings ().get_hirid (),
340 TyTy::TyWithLocation (lhs, expr.get_lhs ()->get_locus ()),
341 TyTy::TyWithLocation (rhs, expr.get_rhs ()->get_locus ()),
342 expr.get_locus ());
344 bool ok = context->lookup_builtin ("bool", &infered);
345 rust_assert (ok);
348 void
349 TypeCheckExpr::visit (HIR::LazyBooleanExpr &expr)
351 auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ().get ());
352 auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ().get ());
354 // we expect the lhs and rhs must be bools at this point
355 TyTy::BaseType *boolean_node = nullptr;
356 bool ok = context->lookup_builtin ("bool", &boolean_node);
357 rust_assert (ok);
359 // verify the lhs and rhs before unifying together
360 lhs = unify_site (expr.get_mappings ().get_hirid (),
361 TyTy::TyWithLocation (boolean_node,
362 expr.get_lhs ()->get_locus ()),
363 TyTy::TyWithLocation (lhs, expr.get_lhs ()->get_locus ()),
364 expr.get_locus ());
366 rhs = unify_site (expr.get_mappings ().get_hirid (),
367 TyTy::TyWithLocation (boolean_node,
368 expr.get_rhs ()->get_locus ()),
369 TyTy::TyWithLocation (rhs, expr.get_rhs ()->get_locus ()),
370 expr.get_locus ());
372 infered
373 = unify_site (expr.get_mappings ().get_hirid (),
374 TyTy::TyWithLocation (lhs, expr.get_lhs ()->get_locus ()),
375 TyTy::TyWithLocation (rhs, expr.get_rhs ()->get_locus ()),
376 expr.get_locus ());
379 void
380 TypeCheckExpr::visit (HIR::NegationExpr &expr)
382 auto negated_expr_ty = TypeCheckExpr::Resolve (expr.get_expr ().get ());
384 // check for operator overload
385 auto lang_item_type
386 = LangItem::NegationOperatorToLangItem (expr.get_expr_type ());
387 bool operator_overloaded
388 = resolve_operator_overload (lang_item_type, expr, negated_expr_ty,
389 nullptr);
390 if (operator_overloaded)
391 return;
393 // https://doc.rust-lang.org/reference/expressions/operator-expr.html#negation-operators
394 switch (expr.get_expr_type ())
396 case NegationOperator::NEGATE: {
397 bool valid
398 = (negated_expr_ty->get_kind () == TyTy::TypeKind::INT)
399 || (negated_expr_ty->get_kind () == TyTy::TypeKind::UINT)
400 || (negated_expr_ty->get_kind () == TyTy::TypeKind::FLOAT)
401 || (negated_expr_ty->get_kind () == TyTy::TypeKind::ISIZE)
402 || (negated_expr_ty->get_kind () == TyTy::TypeKind::USIZE)
403 || (negated_expr_ty->get_kind () == TyTy::TypeKind::INFER
404 && (((TyTy::InferType *) negated_expr_ty)->get_infer_kind ()
405 == TyTy::InferType::INTEGRAL))
406 || (negated_expr_ty->get_kind () == TyTy::TypeKind::INFER
407 && (((TyTy::InferType *) negated_expr_ty)->get_infer_kind ()
408 == TyTy::InferType::FLOAT));
409 if (!valid)
411 rust_error_at (expr.get_locus (), "cannot apply unary - to %s",
412 negated_expr_ty->as_string ().c_str ());
413 return;
416 break;
418 case NegationOperator::NOT: {
419 bool valid
420 = (negated_expr_ty->get_kind () == TyTy::TypeKind::BOOL)
421 || (negated_expr_ty->get_kind () == TyTy::TypeKind::INT)
422 || (negated_expr_ty->get_kind () == TyTy::TypeKind::UINT)
423 || (negated_expr_ty->get_kind () == TyTy::TypeKind::INFER
424 && (((TyTy::InferType *) negated_expr_ty)->get_infer_kind ()
425 == TyTy::InferType::INTEGRAL));
426 if (!valid)
428 rust_error_at (expr.get_locus (), "cannot apply unary %<!%> to %s",
429 negated_expr_ty->as_string ().c_str ());
430 return;
433 break;
436 infered = negated_expr_ty->clone ();
437 infered->append_reference (negated_expr_ty->get_ref ());
440 void
441 TypeCheckExpr::visit (HIR::IfExpr &expr)
443 TyTy::BaseType *bool_ty = nullptr;
444 bool ok = context->lookup_builtin ("bool", &bool_ty);
445 rust_assert (ok);
447 TyTy::BaseType *cond_type
448 = TypeCheckExpr::Resolve (expr.get_if_condition ().get ());
450 unify_site (expr.get_mappings ().get_hirid (), TyTy::TyWithLocation (bool_ty),
451 TyTy::TyWithLocation (cond_type,
452 expr.get_if_condition ()->get_locus ()),
453 expr.get_locus ());
455 TypeCheckExpr::Resolve (expr.get_if_block ().get ());
457 infered = TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ());
460 void
461 TypeCheckExpr::visit (HIR::IfExprConseqElse &expr)
463 TyTy::BaseType *bool_ty = nullptr;
464 bool ok = context->lookup_builtin ("bool", &bool_ty);
465 rust_assert (ok);
467 TyTy::BaseType *cond_type
468 = TypeCheckExpr::Resolve (expr.get_if_condition ().get ());
470 unify_site (expr.get_mappings ().get_hirid (), TyTy::TyWithLocation (bool_ty),
471 TyTy::TyWithLocation (cond_type,
472 expr.get_if_condition ()->get_locus ()),
473 expr.get_locus ());
475 auto if_blk_resolved = TypeCheckExpr::Resolve (expr.get_if_block ().get ());
476 auto else_blk_resolved
477 = TypeCheckExpr::Resolve (expr.get_else_block ().get ());
479 if (if_blk_resolved->get_kind () == TyTy::NEVER)
480 infered = else_blk_resolved;
481 else if (else_blk_resolved->get_kind () == TyTy::NEVER)
482 infered = if_blk_resolved;
483 else
485 infered = unify_site (
486 expr.get_mappings ().get_hirid (),
487 TyTy::TyWithLocation (if_blk_resolved,
488 expr.get_if_block ()->get_locus ()),
489 TyTy::TyWithLocation (else_blk_resolved,
490 expr.get_else_block ()->get_locus ()),
491 expr.get_locus ());
495 void
496 TypeCheckExpr::visit (HIR::IfLetExpr &expr)
498 // this needs to perform a least upper bound coercion on the blocks and then
499 // unify the scruintee and arms
500 TyTy::BaseType *scrutinee_tyty
501 = TypeCheckExpr::Resolve (expr.get_scrutinee_expr ().get ());
503 for (auto &pattern : expr.get_patterns ())
505 TyTy::BaseType *kase_arm_ty
506 = TypeCheckPattern::Resolve (pattern.get (), scrutinee_tyty);
508 unify_site (expr.get_mappings ().get_hirid (),
509 TyTy::TyWithLocation (scrutinee_tyty),
510 TyTy::TyWithLocation (kase_arm_ty, pattern->get_locus ()),
511 expr.get_locus ());
514 TypeCheckExpr::Resolve (expr.get_if_block ().get ());
516 infered = TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ());
519 void
520 TypeCheckExpr::visit (HIR::IfLetExprConseqElse &expr)
522 TyTy::BaseType *scrutinee_tyty
523 = TypeCheckExpr::Resolve (expr.get_scrutinee_expr ().get ());
525 for (auto &pattern : expr.get_patterns ())
527 TyTy::BaseType *kase_arm_ty
528 = TypeCheckPattern::Resolve (pattern.get (), scrutinee_tyty);
530 unify_site (expr.get_mappings ().get_hirid (),
531 TyTy::TyWithLocation (scrutinee_tyty),
532 TyTy::TyWithLocation (kase_arm_ty, pattern->get_locus ()),
533 expr.get_locus ());
536 auto if_blk_resolved = TypeCheckExpr::Resolve (expr.get_if_block ().get ());
537 auto else_blk_resolved
538 = TypeCheckExpr::Resolve (expr.get_else_block ().get ());
540 if (if_blk_resolved->get_kind () == TyTy::NEVER)
541 infered = else_blk_resolved;
542 else if (else_blk_resolved->get_kind () == TyTy::NEVER)
543 infered = if_blk_resolved;
544 else
546 infered = unify_site (
547 expr.get_mappings ().get_hirid (),
548 TyTy::TyWithLocation (if_blk_resolved,
549 expr.get_if_block ()->get_locus ()),
550 TyTy::TyWithLocation (else_blk_resolved,
551 expr.get_else_block ()->get_locus ()),
552 expr.get_locus ());
556 void
557 TypeCheckExpr::visit (HIR::UnsafeBlockExpr &expr)
559 infered = TypeCheckExpr::Resolve (expr.get_block_expr ().get ());
562 void
563 TypeCheckExpr::visit (HIR::BlockExpr &expr)
565 if (expr.has_label ())
566 context->push_new_loop_context (expr.get_mappings ().get_hirid (),
567 expr.get_locus ());
569 for (auto &s : expr.get_statements ())
571 if (!s->is_item ())
572 continue;
574 TypeCheckStmt::Resolve (s.get ());
577 for (auto &s : expr.get_statements ())
579 if (s->is_item ())
580 continue;
582 auto resolved = TypeCheckStmt::Resolve (s.get ());
583 if (resolved == nullptr)
585 rust_error_at (s->get_locus (), "failure to resolve type");
586 return;
589 if (s->is_unit_check_needed () && !resolved->is_unit ())
591 auto unit
592 = TyTy::TupleType::get_unit_type (s->get_mappings ().get_hirid ());
593 resolved
594 = unify_site (s->get_mappings ().get_hirid (),
595 TyTy::TyWithLocation (unit),
596 TyTy::TyWithLocation (resolved), s->get_locus ());
600 if (expr.has_expr ())
601 infered = TypeCheckExpr::Resolve (expr.get_final_expr ().get ())->clone ();
602 else if (expr.is_tail_reachable ())
603 infered
604 = TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ());
605 else if (expr.has_label ())
607 TyTy::BaseType *loop_context_type = context->pop_loop_context ();
609 bool loop_context_type_infered
610 = (loop_context_type->get_kind () != TyTy::TypeKind::INFER)
611 || ((loop_context_type->get_kind () == TyTy::TypeKind::INFER)
612 && (((TyTy::InferType *) loop_context_type)->get_infer_kind ()
613 != TyTy::InferType::GENERAL));
615 infered = loop_context_type_infered ? loop_context_type
616 : TyTy::TupleType::get_unit_type (
617 expr.get_mappings ().get_hirid ());
619 else
621 // FIXME this seems wrong
622 infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ());
626 void
627 TypeCheckExpr::visit (HIR::RangeFromToExpr &expr)
629 auto lang_item_type = LangItem::Kind::RANGE;
631 DefId respective_lang_item_id = UNKNOWN_DEFID;
632 bool lang_item_defined
633 = mappings->lookup_lang_item (lang_item_type, &respective_lang_item_id);
635 // we need to have it maybe
636 if (!lang_item_defined)
638 rust_internal_error_at (expr.get_locus (),
639 "unable to find relevant lang item: %s",
640 LangItem::ToString (lang_item_type).c_str ());
641 return;
644 // look it up and it _must_ be a struct definition
645 HIR::Item *item = mappings->lookup_defid (respective_lang_item_id);
646 rust_assert (item != nullptr);
648 TyTy::BaseType *item_type = nullptr;
649 bool ok
650 = context->lookup_type (item->get_mappings ().get_hirid (), &item_type);
651 rust_assert (ok);
652 rust_assert (item_type->get_kind () == TyTy::TypeKind::ADT);
653 TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (item_type);
655 // this is a single generic item lets assert that
656 rust_assert (adt->get_num_substitutions () == 1);
658 // resolve the range expressions and these types must unify then we use that
659 // type to substitute into the ADT
660 TyTy::BaseType *from_ty
661 = TypeCheckExpr::Resolve (expr.get_from_expr ().get ());
662 TyTy::BaseType *to_ty = TypeCheckExpr::Resolve (expr.get_to_expr ().get ());
664 TyTy::BaseType *unified = unify_site (
665 expr.get_mappings ().get_hirid (),
666 TyTy::TyWithLocation (from_ty, expr.get_from_expr ()->get_locus ()),
667 TyTy::TyWithLocation (to_ty, expr.get_to_expr ()->get_locus ()),
668 expr.get_locus ());
670 // substitute it in
671 std::vector<TyTy::SubstitutionArg> subst_mappings;
672 const TyTy::SubstitutionParamMapping *param_ref = &adt->get_substs ().at (0);
673 subst_mappings.push_back (TyTy::SubstitutionArg (param_ref, unified));
675 TyTy::SubstitutionArgumentMappings subst (
676 subst_mappings, {}, adt->get_substitution_arguments ().get_regions (),
677 expr.get_locus ());
678 infered = SubstMapperInternal::Resolve (adt, subst);
681 void
682 TypeCheckExpr::visit (HIR::RangeFromExpr &expr)
684 auto lang_item_type = LangItem::Kind::RANGE_FROM;
686 DefId respective_lang_item_id = UNKNOWN_DEFID;
687 bool lang_item_defined
688 = mappings->lookup_lang_item (lang_item_type, &respective_lang_item_id);
690 // we need to have it maybe
691 if (!lang_item_defined)
693 rust_internal_error_at (expr.get_locus (),
694 "unable to find relevant lang item: %s",
695 LangItem::ToString (lang_item_type).c_str ());
696 return;
699 // look it up and it _must_ be a struct definition
700 HIR::Item *item = mappings->lookup_defid (respective_lang_item_id);
701 rust_assert (item != nullptr);
703 TyTy::BaseType *item_type = nullptr;
704 bool ok
705 = context->lookup_type (item->get_mappings ().get_hirid (), &item_type);
706 rust_assert (ok);
707 rust_assert (item_type->get_kind () == TyTy::TypeKind::ADT);
708 TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (item_type);
710 // this is a single generic item lets assert that
711 rust_assert (adt->get_num_substitutions () == 1);
713 // resolve the range expressions and these types must unify then we use that
714 // type to substitute into the ADT
715 TyTy::BaseType *from_ty
716 = TypeCheckExpr::Resolve (expr.get_from_expr ().get ());
718 // substitute it in
719 std::vector<TyTy::SubstitutionArg> subst_mappings;
720 const TyTy::SubstitutionParamMapping *param_ref = &adt->get_substs ().at (0);
721 subst_mappings.push_back (TyTy::SubstitutionArg (param_ref, from_ty));
723 TyTy::SubstitutionArgumentMappings subst (
724 subst_mappings, {}, adt->get_substitution_arguments ().get_regions (),
725 expr.get_locus ());
726 infered = SubstMapperInternal::Resolve (adt, subst);
729 void
730 TypeCheckExpr::visit (HIR::RangeToExpr &expr)
732 auto lang_item_type = LangItem::Kind::RANGE_TO;
734 DefId respective_lang_item_id = UNKNOWN_DEFID;
735 bool lang_item_defined
736 = mappings->lookup_lang_item (lang_item_type, &respective_lang_item_id);
738 // we need to have it maybe
739 if (!lang_item_defined)
741 rust_internal_error_at (expr.get_locus (),
742 "unable to find relevant lang item: %s",
743 LangItem::ToString (lang_item_type).c_str ());
744 return;
747 // look it up and it _must_ be a struct definition
748 HIR::Item *item = mappings->lookup_defid (respective_lang_item_id);
749 rust_assert (item != nullptr);
751 TyTy::BaseType *item_type = nullptr;
752 bool ok
753 = context->lookup_type (item->get_mappings ().get_hirid (), &item_type);
754 rust_assert (ok);
755 rust_assert (item_type->get_kind () == TyTy::TypeKind::ADT);
756 TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (item_type);
758 // this is a single generic item lets assert that
759 rust_assert (adt->get_num_substitutions () == 1);
761 // resolve the range expressions and these types must unify then we use that
762 // type to substitute into the ADT
763 TyTy::BaseType *from_ty = TypeCheckExpr::Resolve (expr.get_to_expr ().get ());
765 // substitute it in
766 std::vector<TyTy::SubstitutionArg> subst_mappings;
767 const TyTy::SubstitutionParamMapping *param_ref = &adt->get_substs ().at (0);
768 subst_mappings.push_back (TyTy::SubstitutionArg (param_ref, from_ty));
770 TyTy::SubstitutionArgumentMappings subst (
771 subst_mappings, {}, adt->get_substitution_arguments ().get_regions (),
772 expr.get_locus ());
773 infered = SubstMapperInternal::Resolve (adt, subst);
776 void
777 TypeCheckExpr::visit (HIR::RangeFullExpr &expr)
779 auto lang_item_type = LangItem::Kind::RANGE_FULL;
781 DefId respective_lang_item_id = UNKNOWN_DEFID;
782 bool lang_item_defined
783 = mappings->lookup_lang_item (lang_item_type, &respective_lang_item_id);
785 // we need to have it maybe
786 if (!lang_item_defined)
788 rust_internal_error_at (expr.get_locus (),
789 "unable to find relevant lang item: %s",
790 LangItem::ToString (lang_item_type).c_str ());
791 return;
794 // look it up and it _must_ be a struct definition
795 HIR::Item *item = mappings->lookup_defid (respective_lang_item_id);
796 rust_assert (item != nullptr);
798 TyTy::BaseType *item_type = nullptr;
799 bool ok
800 = context->lookup_type (item->get_mappings ().get_hirid (), &item_type);
801 rust_assert (ok);
802 rust_assert (item_type->is_unit ());
804 infered = item_type;
807 void
808 TypeCheckExpr::visit (HIR::RangeFromToInclExpr &expr)
810 auto lang_item_type = LangItem::Kind::RANGE_INCLUSIVE;
812 DefId respective_lang_item_id = UNKNOWN_DEFID;
813 bool lang_item_defined
814 = mappings->lookup_lang_item (lang_item_type, &respective_lang_item_id);
816 // we need to have it maybe
817 if (!lang_item_defined)
819 rust_internal_error_at (expr.get_locus (),
820 "unable to find relevant lang item: %s",
821 LangItem::ToString (lang_item_type).c_str ());
822 return;
825 // look it up and it _must_ be a struct definition
826 HIR::Item *item = mappings->lookup_defid (respective_lang_item_id);
827 rust_assert (item != nullptr);
829 TyTy::BaseType *item_type = nullptr;
830 bool ok
831 = context->lookup_type (item->get_mappings ().get_hirid (), &item_type);
832 rust_assert (ok);
833 rust_assert (item_type->get_kind () == TyTy::TypeKind::ADT);
834 TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (item_type);
836 // this is a single generic item lets assert that
837 rust_assert (adt->get_num_substitutions () == 1);
839 // resolve the range expressions and these types must unify then we use that
840 // type to substitute into the ADT
841 TyTy::BaseType *from_ty
842 = TypeCheckExpr::Resolve (expr.get_from_expr ().get ());
843 TyTy::BaseType *to_ty = TypeCheckExpr::Resolve (expr.get_to_expr ().get ());
844 TyTy::BaseType *unified = unify_site (
845 expr.get_mappings ().get_hirid (),
846 TyTy::TyWithLocation (from_ty, expr.get_from_expr ()->get_locus ()),
847 TyTy::TyWithLocation (to_ty, expr.get_to_expr ()->get_locus ()),
848 expr.get_locus ());
850 // substitute it in
851 std::vector<TyTy::SubstitutionArg> subst_mappings;
852 const TyTy::SubstitutionParamMapping *param_ref = &adt->get_substs ().at (0);
853 subst_mappings.push_back (TyTy::SubstitutionArg (param_ref, unified));
855 TyTy::SubstitutionArgumentMappings subst (
856 subst_mappings, {}, adt->get_substitution_arguments ().get_regions (),
857 expr.get_locus ());
858 infered = SubstMapperInternal::Resolve (adt, subst);
861 void
862 TypeCheckExpr::visit (HIR::ArrayIndexExpr &expr)
864 auto array_expr_ty = TypeCheckExpr::Resolve (expr.get_array_expr ().get ());
865 if (array_expr_ty->get_kind () == TyTy::TypeKind::ERROR)
866 return;
868 auto index_expr_ty = TypeCheckExpr::Resolve (expr.get_index_expr ().get ());
869 if (index_expr_ty->get_kind () == TyTy::TypeKind::ERROR)
870 return;
872 // first attempt to use direct array index logic
873 auto direct_array_expr_ty = array_expr_ty;
874 if (direct_array_expr_ty->get_kind () == TyTy::TypeKind::REF)
876 // lets try and deref it since rust allows this
877 auto ref = static_cast<TyTy::ReferenceType *> (direct_array_expr_ty);
878 auto base = ref->get_base ();
879 if (base->get_kind () == TyTy::TypeKind::ARRAY)
880 direct_array_expr_ty = base;
883 TyTy::BaseType *size_ty;
884 bool ok = context->lookup_builtin ("usize", &size_ty);
885 rust_assert (ok);
887 bool maybe_simple_array_access = index_expr_ty->can_eq (size_ty, false);
888 if (maybe_simple_array_access
889 && direct_array_expr_ty->get_kind () == TyTy::TypeKind::ARRAY)
891 unify_site (expr.get_index_expr ()->get_mappings ().get_hirid (),
892 TyTy::TyWithLocation (size_ty),
893 TyTy::TyWithLocation (index_expr_ty,
894 expr.get_index_expr ()->get_locus ()),
895 expr.get_locus ());
897 TyTy::ArrayType *array_type
898 = static_cast<TyTy::ArrayType *> (direct_array_expr_ty);
899 infered = array_type->get_element_type ()->clone ();
900 return;
903 // is this a case of core::ops::index?
904 auto lang_item_type = LangItem::Kind::INDEX;
905 bool operator_overloaded
906 = resolve_operator_overload (lang_item_type, expr, array_expr_ty,
907 index_expr_ty);
908 if (operator_overloaded)
910 // index and index mut always return a reference to the element
911 TyTy::BaseType *resolved = infered;
912 rust_assert (resolved->get_kind () == TyTy::TypeKind::REF);
913 TyTy::ReferenceType *ref = static_cast<TyTy::ReferenceType *> (resolved);
915 infered = ref->get_base ()->clone ();
916 return;
919 // error[E0277]: the type `[{integer}]` cannot be indexed by `u32`
920 rich_location r (line_table, expr.get_locus ());
921 r.add_range (expr.get_array_expr ()->get_locus ());
922 r.add_range (expr.get_index_expr ()->get_locus ());
923 rust_error_at (r, ErrorCode::E0277,
924 "the type %qs cannot be indexed by %qs",
925 array_expr_ty->get_name ().c_str (),
926 index_expr_ty->get_name ().c_str ());
929 void
930 TypeCheckExpr::visit (HIR::ArrayExpr &expr)
932 HIR::ArrayElems &elements = *expr.get_internal_elements ();
934 HIR::Expr *capacity_expr = nullptr;
935 TyTy::BaseType *element_type = nullptr;
936 switch (elements.get_array_expr_type ())
938 case HIR::ArrayElems::ArrayExprType::COPIED: {
939 HIR::ArrayElemsCopied &elems
940 = static_cast<HIR::ArrayElemsCopied &> (elements);
941 element_type
942 = TypeCheckExpr::Resolve (elems.get_elem_to_copy ().get ());
944 auto capacity_type
945 = TypeCheckExpr::Resolve (elems.get_num_copies_expr ().get ());
947 TyTy::BaseType *expected_ty = nullptr;
948 bool ok = context->lookup_builtin ("usize", &expected_ty);
949 rust_assert (ok);
950 context->insert_type (elems.get_num_copies_expr ()->get_mappings (),
951 expected_ty);
953 unify_site (
954 expr.get_mappings ().get_hirid (), TyTy::TyWithLocation (expected_ty),
955 TyTy::TyWithLocation (capacity_type,
956 elems.get_num_copies_expr ()->get_locus ()),
957 expr.get_locus ());
959 capacity_expr = elems.get_num_copies_expr ().get ();
961 break;
963 case HIR::ArrayElems::ArrayExprType::VALUES: {
964 HIR::ArrayElemsValues &elems
965 = static_cast<HIR::ArrayElemsValues &> (elements);
967 std::vector<TyTy::BaseType *> types;
968 for (auto &elem : elems.get_values ())
970 types.push_back (TypeCheckExpr::Resolve (elem.get ()));
973 // this is a LUB
974 element_type
975 = TyTy::TyVar::get_implicit_infer_var (expr.get_locus ()).get_tyty ();
976 for (auto &type : types)
978 element_type
979 = unify_site (expr.get_mappings ().get_hirid (),
980 TyTy::TyWithLocation (element_type),
981 TyTy::TyWithLocation (type, type->get_locus ()),
982 expr.get_locus ());
985 auto crate_num = mappings->get_current_crate ();
986 Analysis::NodeMapping mapping (crate_num, UNKNOWN_NODEID,
987 mappings->get_next_hir_id (crate_num),
988 UNKNOWN_LOCAL_DEFID);
989 std::string capacity_str = std::to_string (elems.get_num_elements ());
990 capacity_expr = new HIR::LiteralExpr (mapping, capacity_str,
991 HIR::Literal::LitType::INT,
992 PrimitiveCoreType::CORETYPE_USIZE,
993 UNDEF_LOCATION, {});
995 // mark the type for this implicit node
996 TyTy::BaseType *expected_ty = nullptr;
997 bool ok = context->lookup_builtin ("usize", &expected_ty);
998 rust_assert (ok);
999 context->insert_type (mapping, expected_ty);
1001 break;
1004 infered = new TyTy::ArrayType (expr.get_mappings ().get_hirid (),
1005 expr.get_locus (), *capacity_expr,
1006 TyTy::TyVar (element_type->get_ref ()));
1009 // empty struct
1010 void
1011 TypeCheckExpr::visit (HIR::StructExprStruct &struct_expr)
1013 TyTy::BaseType *struct_path_ty
1014 = TypeCheckExpr::Resolve (&struct_expr.get_struct_name ());
1015 if (struct_path_ty->get_kind () != TyTy::TypeKind::ADT)
1017 rust_error_at (struct_expr.get_struct_name ().get_locus (),
1018 "expected an ADT type for constructor");
1019 return;
1022 TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (struct_path_ty);
1023 for (auto variant : adt->get_variants ())
1025 if (!variant->get_fields ().empty ())
1027 std::vector<std::string> field_names;
1028 for (auto &field : variant->get_fields ())
1029 field_names.push_back (field->get_name ());
1030 Error missing_fields_error
1031 = TypeCheckStructExpr::make_missing_field_error (
1032 struct_expr.get_locus (), field_names,
1033 struct_path_ty->get_name ());
1034 // We might want to return or handle these in the future emit for now.
1035 missing_fields_error.emit ();
1036 return;
1040 infered = struct_path_ty;
1043 void
1044 TypeCheckExpr::visit (HIR::StructExprStructFields &struct_expr)
1046 infered = TypeCheckStructExpr::Resolve (&struct_expr);
1049 void
1050 TypeCheckExpr::visit (HIR::GroupedExpr &expr)
1052 infered = TypeCheckExpr::Resolve (expr.get_expr_in_parens ().get ());
1055 void
1056 TypeCheckExpr::visit (HIR::FieldAccessExpr &expr)
1058 auto struct_base = TypeCheckExpr::Resolve (expr.get_receiver_expr ().get ());
1060 // FIXME does this require autoderef here?
1061 if (struct_base->get_kind () == TyTy::TypeKind::REF)
1063 TyTy::ReferenceType *r = static_cast<TyTy::ReferenceType *> (struct_base);
1064 struct_base = r->get_base ();
1067 bool is_valid_type = struct_base->get_kind () == TyTy::TypeKind::ADT;
1068 if (!is_valid_type)
1070 rust_error_at (expr.get_locus (),
1071 "expected algebraic data type got: [%s]",
1072 struct_base->as_string ().c_str ());
1073 return;
1076 TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (struct_base);
1077 rust_assert (!adt->is_enum ());
1078 rust_assert (adt->number_of_variants () == 1);
1080 TyTy::VariantDef *vaiant = adt->get_variants ().at (0);
1082 TyTy::StructFieldType *lookup = nullptr;
1083 bool found = vaiant->lookup_field (expr.get_field_name ().as_string (),
1084 &lookup, nullptr);
1085 if (!found)
1087 rust_error_at (expr.get_locus (), "unknown field [%s] for type [%s]",
1088 expr.get_field_name ().as_string ().c_str (),
1089 adt->as_string ().c_str ());
1090 return;
1093 infered = lookup->get_field_type ();
1096 void
1097 TypeCheckExpr::visit (HIR::MethodCallExpr &expr)
1099 auto receiver_tyty = TypeCheckExpr::Resolve (expr.get_receiver ().get ());
1100 if (receiver_tyty->get_kind () == TyTy::TypeKind::ERROR)
1102 rust_error_at (expr.get_receiver ()->get_locus (),
1103 "failed to resolve receiver in MethodCallExpr");
1104 return;
1107 context->insert_receiver (expr.get_mappings ().get_hirid (), receiver_tyty);
1109 rust_debug_loc (expr.get_locus (), "attempting to resolve method for %s",
1110 receiver_tyty->debug_str ().c_str ());
1111 auto candidates
1112 = MethodResolver::Probe (receiver_tyty,
1113 expr.get_method_name ().get_segment ());
1114 if (candidates.empty ())
1116 rich_location richloc (line_table, expr.get_method_name ().get_locus ());
1117 richloc.add_fixit_replace ("method not found");
1118 rust_error_at (
1119 richloc, ErrorCode::E0599,
1120 "no method named %qs found in the current scope",
1121 expr.get_method_name ().get_segment ().as_string ().c_str ());
1122 return;
1125 if (candidates.size () > 1)
1127 rich_location r (line_table, expr.get_method_name ().get_locus ());
1128 std::string rich_msg
1129 = "multiple " + expr.get_method_name ().get_segment ().as_string ()
1130 + " found";
1132 for (auto &c : candidates)
1133 r.add_range (c.candidate.locus);
1135 r.add_fixit_replace (rich_msg.c_str ());
1137 rust_error_at (
1138 r, ErrorCode::E0592, "duplicate definitions with name %qs",
1139 expr.get_method_name ().get_segment ().as_string ().c_str ());
1140 return;
1143 auto candidate = *candidates.begin ();
1144 rust_debug_loc (expr.get_method_name ().get_locus (),
1145 "resolved method to: {%u} {%s} with [%lu] adjustments",
1146 candidate.candidate.ty->get_ref (),
1147 candidate.candidate.ty->debug_str ().c_str (),
1148 (unsigned long) candidate.adjustments.size ());
1150 // Get the adjusted self
1151 Adjuster adj (receiver_tyty);
1152 TyTy::BaseType *adjusted_self = adj.adjust_type (candidate.adjustments);
1153 rust_debug ("receiver: %s adjusted self %s",
1154 receiver_tyty->debug_str ().c_str (),
1155 adjusted_self->debug_str ().c_str ());
1157 // store the adjustments for code-generation to know what to do which must be
1158 // stored onto the receiver to so as we don't trigger duplicate deref mappings
1159 // ICE when an argument is a method call
1160 HirId autoderef_mappings_id
1161 = expr.get_receiver ()->get_mappings ().get_hirid ();
1162 context->insert_autoderef_mappings (autoderef_mappings_id,
1163 std::move (candidate.adjustments));
1165 PathProbeCandidate &resolved_candidate = candidate.candidate;
1166 TyTy::BaseType *lookup_tyty = candidate.candidate.ty;
1167 NodeId resolved_node_id
1168 = resolved_candidate.is_impl_candidate ()
1169 ? resolved_candidate.item.impl.impl_item->get_impl_mappings ()
1170 .get_nodeid ()
1171 : resolved_candidate.item.trait.item_ref->get_mappings ().get_nodeid ();
1173 if (lookup_tyty->get_kind () != TyTy::TypeKind::FNDEF)
1175 rich_location r (line_table, expr.get_method_name ().get_locus ());
1176 r.add_range (resolved_candidate.locus);
1177 rust_error_at (r, "associated impl item is not a method");
1178 return;
1181 TyTy::BaseType *lookup = lookup_tyty;
1182 TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup);
1183 if (!fn->is_method ())
1185 rich_location r (line_table, expr.get_method_name ().get_locus ());
1186 r.add_range (resolved_candidate.locus);
1187 rust_error_at (r, "associated function is not a method");
1188 return;
1191 fn->prepare_higher_ranked_bounds ();
1192 rust_debug_loc (expr.get_locus (), "resolved method call to: {%u} {%s}",
1193 candidate.candidate.ty->get_ref (),
1194 candidate.candidate.ty->debug_str ().c_str ());
1196 if (resolved_candidate.is_impl_candidate ())
1198 auto infer_arguments = TyTy::SubstitutionArgumentMappings::empty ();
1199 infer_arguments.get_mut_regions ()
1200 = fn->get_used_arguments ().get_regions ();
1201 HIR::ImplBlock &impl = *resolved_candidate.item.impl.parent;
1202 TyTy::BaseType *impl_self_infer
1203 = TypeCheckItem::ResolveImplBlockSelfWithInference (impl,
1204 expr.get_locus (),
1205 &infer_arguments);
1206 if (impl_self_infer->get_kind () == TyTy::TypeKind::ERROR)
1208 rich_location r (line_table, expr.get_locus ());
1209 r.add_range (impl.get_type ()->get_locus ());
1210 rust_error_at (
1211 r, "failed to resolve impl type for method call resolution");
1212 return;
1215 if (!infer_arguments.is_empty ())
1217 lookup = SubstMapperInternal::Resolve (lookup, infer_arguments);
1218 lookup->debug ();
1222 // apply any remaining generic arguments
1223 if (expr.get_method_name ().has_generic_args ())
1225 HIR::GenericArgs &args = expr.get_method_name ().get_generic_args ();
1226 rust_debug_loc (args.get_locus (),
1227 "applying generic arguments to method_call: {%s}",
1228 lookup->debug_str ().c_str ());
1230 lookup
1231 = SubstMapper::Resolve (lookup, expr.get_method_name ().get_locus (),
1232 &args);
1233 if (lookup->get_kind () == TyTy::TypeKind::ERROR)
1234 return;
1236 else if (lookup->needs_generic_substitutions ())
1238 rust_debug ("method needs inference: {%s}",
1239 lookup->debug_str ().c_str ());
1240 lookup = SubstMapper::InferSubst (lookup,
1241 expr.get_method_name ().get_locus ());
1244 rust_debug ("type-checking method_call: {%s}", lookup->debug_str ().c_str ());
1246 TyTy::BaseType *function_ret_tyty
1247 = TyTy::TypeCheckMethodCallExpr::go (static_cast<TyTy::FnType *> (lookup),
1248 expr, adjusted_self, context);
1249 if (function_ret_tyty == nullptr
1250 || function_ret_tyty->get_kind () == TyTy::TypeKind::ERROR)
1252 rust_error_at (expr.get_locus (),
1253 "failed to lookup type to MethodCallExpr");
1254 return;
1257 // store the expected fntype
1258 context->insert_type (expr.get_method_name ().get_mappings (), lookup);
1260 // set up the resolved name on the path
1261 if (resolver->get_name_scope ().decl_was_declared_here (resolved_node_id))
1263 resolver->insert_resolved_name (expr.get_mappings ().get_nodeid (),
1264 resolved_node_id);
1266 else
1268 resolver->insert_resolved_misc (expr.get_mappings ().get_nodeid (),
1269 resolved_node_id);
1272 // return the result of the function back
1273 infered = function_ret_tyty;
1276 void
1277 TypeCheckExpr::visit (HIR::LoopExpr &expr)
1279 context->push_new_loop_context (expr.get_mappings ().get_hirid (),
1280 expr.get_locus ());
1281 TyTy::BaseType *block_expr
1282 = TypeCheckExpr::Resolve (expr.get_loop_block ().get ());
1283 if (!block_expr->is_unit ())
1285 rust_error_at (expr.get_loop_block ()->get_locus (),
1286 "expected %<()%> got %s",
1287 block_expr->as_string ().c_str ());
1288 return;
1291 TyTy::BaseType *loop_context_type = context->pop_loop_context ();
1293 bool loop_context_type_infered
1294 = (loop_context_type->get_kind () != TyTy::TypeKind::INFER)
1295 || ((loop_context_type->get_kind () == TyTy::TypeKind::INFER)
1296 && (((TyTy::InferType *) loop_context_type)->get_infer_kind ()
1297 != TyTy::InferType::GENERAL));
1299 infered
1300 = loop_context_type_infered
1301 ? loop_context_type
1302 : TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ());
1305 void
1306 TypeCheckExpr::visit (HIR::WhileLoopExpr &expr)
1308 context->push_new_while_loop_context (expr.get_mappings ().get_hirid ());
1310 TypeCheckExpr::Resolve (expr.get_predicate_expr ().get ());
1311 TyTy::BaseType *block_expr
1312 = TypeCheckExpr::Resolve (expr.get_loop_block ().get ());
1314 if (!block_expr->is_unit ())
1316 rust_error_at (expr.get_loop_block ()->get_locus (),
1317 "expected %<()%> got %s",
1318 block_expr->as_string ().c_str ());
1319 return;
1322 context->pop_loop_context ();
1323 infered = TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ());
1326 void
1327 TypeCheckExpr::visit (HIR::BreakExpr &expr)
1329 if (!context->have_loop_context ())
1331 rust_error_at (expr.get_locus (), ErrorCode::E0268,
1332 "%<break%> outside of a loop or labeled block");
1333 return;
1336 if (expr.has_break_expr ())
1338 TyTy::BaseType *break_expr_tyty
1339 = TypeCheckExpr::Resolve (expr.get_expr ().get ());
1341 TyTy::BaseType *loop_context = context->peek_loop_context ();
1342 if (loop_context->get_kind () == TyTy::TypeKind::ERROR)
1344 rust_error_at (
1345 expr.get_locus (), ErrorCode::E0571,
1346 "can only %<break%> with a value inside a %<loop%> block");
1347 return;
1350 TyTy::BaseType *unified_ty
1351 = unify_site (expr.get_mappings ().get_hirid (),
1352 TyTy::TyWithLocation (loop_context),
1353 TyTy::TyWithLocation (break_expr_tyty,
1354 expr.get_expr ()->get_locus ()),
1355 expr.get_locus ());
1356 context->swap_head_loop_context (unified_ty);
1359 infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ());
1362 void
1363 TypeCheckExpr::visit (HIR::ContinueExpr &expr)
1365 if (!context->have_loop_context ())
1367 rust_error_at (expr.get_locus (), ErrorCode::E0268,
1368 "%<continue%> outside of a loop");
1369 return;
1372 infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ());
1375 void
1376 TypeCheckExpr::visit (HIR::BorrowExpr &expr)
1378 TyTy::BaseType *resolved_base
1379 = TypeCheckExpr::Resolve (expr.get_expr ().get ());
1381 // In Rust this is valid because of DST's
1383 // fn test() {
1384 // let a:&str = "TEST 1";
1385 // let b:&str = &"TEST 2";
1386 // }
1387 if (resolved_base->get_kind () == TyTy::TypeKind::REF)
1389 const TyTy::ReferenceType *ref
1390 = static_cast<const TyTy::ReferenceType *> (resolved_base);
1392 // this might end up being a more generic is_dyn object check but lets
1393 // double check dyn traits type-layout first
1394 if (ref->is_dyn_str_type ())
1396 infered = resolved_base;
1397 return;
1401 infered = new TyTy::ReferenceType (expr.get_mappings ().get_hirid (),
1402 TyTy::TyVar (resolved_base->get_ref ()),
1403 expr.get_mut ());
1406 void
1407 TypeCheckExpr::visit (HIR::DereferenceExpr &expr)
1409 TyTy::BaseType *resolved_base
1410 = TypeCheckExpr::Resolve (expr.get_expr ().get ());
1412 rust_debug_loc (expr.get_locus (), "attempting deref operator overload");
1413 auto lang_item_type = LangItem::Kind::DEREF;
1414 bool operator_overloaded
1415 = resolve_operator_overload (lang_item_type, expr, resolved_base, nullptr);
1416 if (operator_overloaded)
1418 // operator overloaded deref always refurns a reference type lets assert
1419 // this
1420 rust_assert (infered->get_kind () == TyTy::TypeKind::REF);
1421 resolved_base = infered;
1424 bool is_valid_type = resolved_base->get_kind () == TyTy::TypeKind::REF
1425 || resolved_base->get_kind () == TyTy::TypeKind::POINTER;
1426 if (!is_valid_type)
1428 rust_error_at (expr.get_locus (), "expected reference type got %s",
1429 resolved_base->as_string ().c_str ());
1430 return;
1433 if (resolved_base->get_kind () == TyTy::TypeKind::REF)
1435 TyTy::ReferenceType *ref_base
1436 = static_cast<TyTy::ReferenceType *> (resolved_base);
1437 infered = ref_base->get_base ()->clone ();
1439 else
1441 TyTy::PointerType *ref_base
1442 = static_cast<TyTy::PointerType *> (resolved_base);
1443 infered = ref_base->get_base ()->clone ();
1447 void
1448 TypeCheckExpr::visit (HIR::TypeCastExpr &expr)
1450 TyTy::BaseType *expr_to_convert
1451 = TypeCheckExpr::Resolve (expr.get_casted_expr ().get ());
1452 TyTy::BaseType *tyty_to_convert_to
1453 = TypeCheckType::Resolve (expr.get_type_to_convert_to ().get ());
1455 TyTy::TyWithLocation from (expr_to_convert,
1456 expr.get_casted_expr ()->get_locus ());
1457 TyTy::TyWithLocation to (tyty_to_convert_to,
1458 expr.get_type_to_convert_to ()->get_locus ());
1459 infered = cast_site (expr.get_mappings ().get_hirid (), from, to,
1460 expr.get_locus ());
1463 void
1464 TypeCheckExpr::visit (HIR::MatchExpr &expr)
1466 // this needs to perform a least upper bound coercion on the blocks and then
1467 // unify the scruintee and arms
1468 TyTy::BaseType *scrutinee_tyty
1469 = TypeCheckExpr::Resolve (expr.get_scrutinee_expr ().get ());
1471 std::vector<TyTy::BaseType *> kase_block_tys;
1472 for (auto &kase : expr.get_match_cases ())
1474 // lets check the arms
1475 HIR::MatchArm &kase_arm = kase.get_arm ();
1476 for (auto &pattern : kase_arm.get_patterns ())
1478 TyTy::BaseType *kase_arm_ty
1479 = TypeCheckPattern::Resolve (pattern.get (), scrutinee_tyty);
1480 if (kase_arm_ty->get_kind () == TyTy ::TypeKind::ERROR)
1481 return;
1483 TyTy::BaseType *checked_kase = unify_site (
1484 expr.get_mappings ().get_hirid (),
1485 TyTy::TyWithLocation (scrutinee_tyty,
1486 expr.get_scrutinee_expr ()->get_locus ()),
1487 TyTy::TyWithLocation (kase_arm_ty, pattern->get_locus ()),
1488 expr.get_locus ());
1489 if (checked_kase->get_kind () == TyTy::TypeKind::ERROR)
1490 return;
1493 // check the kase type
1494 TyTy::BaseType *kase_block_ty
1495 = TypeCheckExpr::Resolve (kase.get_expr ().get ());
1496 kase_block_tys.push_back (kase_block_ty);
1499 if (kase_block_tys.size () == 0)
1501 infered
1502 = TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ());
1503 return;
1506 // this is a LUB
1507 infered = kase_block_tys.at (0);
1508 for (size_t i = 1; i < kase_block_tys.size (); i++)
1510 TyTy::BaseType *kase_ty = kase_block_tys.at (i);
1511 infered = unify_site (expr.get_mappings ().get_hirid (),
1512 TyTy::TyWithLocation (infered),
1513 TyTy::TyWithLocation (kase_ty), expr.get_locus ());
1517 void
1518 TypeCheckExpr::visit (HIR::ClosureExpr &expr)
1520 TypeCheckContextItem current_context = context->peek_context ();
1521 TyTy::FnType *current_context_fndecl = current_context.get_context_type ();
1523 HirId ref = expr.get_mappings ().get_hirid ();
1524 DefId id = expr.get_mappings ().get_defid ();
1525 RustIdent ident{current_context_fndecl->get_ident ().path, expr.get_locus ()};
1527 // get from parent context
1528 std::vector<TyTy::SubstitutionParamMapping> subst_refs
1529 = current_context_fndecl->clone_substs ();
1531 std::vector<TyTy::TyVar> parameter_types;
1532 for (auto &p : expr.get_params ())
1534 TyTy::BaseType *param_tyty = nullptr;
1535 if (p.has_type_given ())
1537 param_tyty = TypeCheckType::Resolve (p.get_type ().get ());
1539 else
1541 param_tyty = ClosureParamInfer::Resolve (p.get_pattern ().get ());
1544 TyTy::TyVar param_ty (param_tyty->get_ref ());
1545 parameter_types.push_back (param_ty);
1547 TypeCheckPattern::Resolve (p.get_pattern ().get (), param_ty.get_tyty ());
1550 // we generate an implicit hirid for the closure args
1551 HirId implicit_args_id = mappings->get_next_hir_id ();
1552 TyTy::TupleType *closure_args
1553 = new TyTy::TupleType (implicit_args_id, expr.get_locus (),
1554 parameter_types);
1555 context->insert_implicit_type (closure_args);
1557 location_t result_type_locus = expr.has_return_type ()
1558 ? expr.get_return_type ()->get_locus ()
1559 : expr.get_locus ();
1560 TyTy::TyVar result_type
1561 = expr.has_return_type ()
1562 ? TyTy::TyVar (
1563 TypeCheckType::Resolve (expr.get_return_type ().get ())->get_ref ())
1564 : TyTy::TyVar::get_implicit_infer_var (expr.get_locus ());
1566 // resolve the block
1567 location_t closure_expr_locus = expr.get_expr ()->get_locus ();
1568 TyTy::BaseType *closure_expr_ty
1569 = TypeCheckExpr::Resolve (expr.get_expr ().get ());
1570 coercion_site (expr.get_mappings ().get_hirid (),
1571 TyTy::TyWithLocation (result_type.get_tyty (),
1572 result_type_locus),
1573 TyTy::TyWithLocation (closure_expr_ty, closure_expr_locus),
1574 expr.get_locus ());
1576 // generate the closure type
1577 NodeId closure_node_id = expr.get_mappings ().get_nodeid ();
1578 const std::set<NodeId> &captures = resolver->get_captures (closure_node_id);
1579 infered = new TyTy::ClosureType (ref, id, ident, closure_args, result_type,
1580 subst_refs, captures);
1582 // FIXME
1583 // all closures automatically inherit the appropriate fn trait. Lets just
1584 // assume FnOnce for now. I think this is based on the return type of the
1585 // closure
1587 LangItem::Kind lang_item_type = LangItem::Kind::FN_ONCE;
1588 DefId respective_lang_item_id = UNKNOWN_DEFID;
1589 bool lang_item_defined
1590 = mappings->lookup_lang_item (lang_item_type, &respective_lang_item_id);
1591 if (!lang_item_defined)
1593 // FIXME
1594 // we need to have a unified way or error'ing when we are missing lang
1595 // items that is useful
1596 rust_fatal_error (expr.get_locus (), "unable to find lang item: %qs",
1597 LangItem::ToString (lang_item_type).c_str ());
1599 rust_assert (lang_item_defined);
1601 // these lang items are always traits
1602 HIR::Item *item = mappings->lookup_defid (respective_lang_item_id);
1603 rust_assert (item->get_item_kind () == HIR::Item::ItemKind::Trait);
1604 HIR::Trait *trait_item = static_cast<HIR::Trait *> (item);
1606 TraitReference *trait = TraitResolver::Resolve (*trait_item);
1607 rust_assert (!trait->is_error ());
1609 TyTy::TypeBoundPredicate predicate (*trait, BoundPolarity::RegularBound,
1610 expr.get_locus ());
1612 // resolve the trait bound where the <(Args)> are the parameter tuple type
1613 HIR::GenericArgs args = HIR::GenericArgs::create_empty (expr.get_locus ());
1615 // lets generate an implicit Type so that it resolves to the implict tuple
1616 // type we have created
1617 auto crate_num = mappings->get_current_crate ();
1618 Analysis::NodeMapping mapping (crate_num, expr.get_mappings ().get_nodeid (),
1619 implicit_args_id, UNKNOWN_LOCAL_DEFID);
1620 HIR::TupleType *implicit_tuple
1621 = new HIR::TupleType (mapping,
1622 {} // we dont need to fill this out because it will
1623 // auto resolve because the hir id's match
1625 expr.get_locus ());
1626 args.get_type_args ().push_back (std::unique_ptr<HIR::Type> (implicit_tuple));
1628 // apply the arguments
1629 predicate.apply_generic_arguments (&args, false);
1631 // finally inherit the trait bound
1632 infered->inherit_bounds ({predicate});
1635 bool
1636 TypeCheckExpr::resolve_operator_overload (LangItem::Kind lang_item_type,
1637 HIR::OperatorExprMeta expr,
1638 TyTy::BaseType *lhs,
1639 TyTy::BaseType *rhs)
1641 // look up lang item for arithmetic type
1642 std::string associated_item_name = LangItem::ToString (lang_item_type);
1643 DefId respective_lang_item_id = UNKNOWN_DEFID;
1644 bool lang_item_defined
1645 = mappings->lookup_lang_item (lang_item_type, &respective_lang_item_id);
1647 // probe for the lang-item
1648 if (!lang_item_defined)
1649 return false;
1651 // we might be in a static or const context and unknown is fine
1652 TypeCheckContextItem current_context = TypeCheckContextItem::get_error ();
1653 if (context->have_function_context ())
1655 current_context = context->peek_context ();
1658 auto segment = HIR::PathIdentSegment (associated_item_name);
1659 auto candidates = MethodResolver::Probe (lhs, segment);
1661 // remove any recursive candidates
1662 std::set<MethodCandidate> resolved_candidates;
1663 for (auto &c : candidates)
1665 const TyTy::BaseType *candidate_type = c.candidate.ty;
1666 rust_assert (candidate_type->get_kind () == TyTy::TypeKind::FNDEF);
1668 const TyTy::FnType &fn
1669 = *static_cast<const TyTy::FnType *> (candidate_type);
1671 DefId current_fn_defid = current_context.get_defid ();
1672 bool recursive_candidated = fn.get_id () == current_fn_defid;
1673 if (!recursive_candidated)
1675 resolved_candidates.insert (c);
1679 std::vector<TyTy::BaseType *> select_args = {};
1680 if (rhs != nullptr)
1681 select_args = {rhs};
1682 auto selected_candidates
1683 = MethodResolver::Select (resolved_candidates, lhs, select_args);
1685 bool have_implementation_for_lang_item = selected_candidates.size () > 0;
1686 if (!have_implementation_for_lang_item)
1687 return false;
1689 if (selected_candidates.size () > 1)
1691 // mutliple candidates
1692 rich_location r (line_table, expr.get_locus ());
1693 for (auto &c : resolved_candidates)
1694 r.add_range (c.candidate.locus);
1696 rust_error_at (
1697 r, "multiple candidates found for possible operator overload");
1699 return false;
1702 // Get the adjusted self
1703 MethodCandidate candidate = *selected_candidates.begin ();
1704 Adjuster adj (lhs);
1705 TyTy::BaseType *adjusted_self = adj.adjust_type (candidate.adjustments);
1707 // store the adjustments for code-generation to know what to do
1708 context->insert_autoderef_mappings (expr.get_lvalue_mappings ().get_hirid (),
1709 std::move (candidate.adjustments));
1711 // now its just like a method-call-expr
1712 context->insert_receiver (expr.get_mappings ().get_hirid (), lhs);
1714 PathProbeCandidate &resolved_candidate = candidate.candidate;
1715 TyTy::BaseType *lookup_tyty = candidate.candidate.ty;
1716 NodeId resolved_node_id
1717 = resolved_candidate.is_impl_candidate ()
1718 ? resolved_candidate.item.impl.impl_item->get_impl_mappings ()
1719 .get_nodeid ()
1720 : resolved_candidate.item.trait.item_ref->get_mappings ().get_nodeid ();
1722 rust_assert (lookup_tyty->get_kind () == TyTy::TypeKind::FNDEF);
1723 TyTy::BaseType *lookup = lookup_tyty;
1724 TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup);
1725 rust_assert (fn->is_method ());
1727 rust_debug ("is_impl_item_candidate: %s",
1728 resolved_candidate.is_impl_candidate () ? "true" : "false");
1730 if (resolved_candidate.is_impl_candidate ())
1732 auto infer_arguments = TyTy::SubstitutionArgumentMappings::error ();
1733 HIR::ImplBlock &impl = *resolved_candidate.item.impl.parent;
1734 TyTy::BaseType *impl_self_infer
1735 = TypeCheckItem::ResolveImplBlockSelfWithInference (impl,
1736 expr.get_locus (),
1737 &infer_arguments);
1738 if (impl_self_infer->get_kind () == TyTy::TypeKind::ERROR)
1740 return false;
1742 if (!infer_arguments.is_empty ())
1744 lookup = SubstMapperInternal::Resolve (lookup, infer_arguments);
1748 // in the case where we resolve to a trait bound we have to be careful we are
1749 // able to do so there is a case where we are currently resolving the deref
1750 // operator overload function which is generic and this might resolve to the
1751 // trait item of deref which is not valid as its just another recursive case
1752 if (current_context.get_type () == TypeCheckContextItem::ItemType::IMPL_ITEM)
1754 auto &impl_item = current_context.get_impl_item ();
1755 HIR::ImplBlock *parent = impl_item.first;
1756 HIR::Function *fn = impl_item.second;
1758 if (parent->has_trait_ref ()
1759 && fn->get_function_name ().as_string ().compare (
1760 associated_item_name)
1761 == 0)
1763 TraitReference *trait_reference
1764 = TraitResolver::Lookup (*parent->get_trait_ref ().get ());
1765 if (!trait_reference->is_error ())
1767 TyTy::BaseType *lookup = nullptr;
1768 bool ok = context->lookup_type (fn->get_mappings ().get_hirid (),
1769 &lookup);
1770 rust_assert (ok);
1771 rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF);
1773 TyTy::FnType *fntype = static_cast<TyTy::FnType *> (lookup);
1774 rust_assert (fntype->is_method ());
1776 bool is_lang_item_impl
1777 = trait_reference->get_mappings ().get_defid ()
1778 == respective_lang_item_id;
1779 bool self_is_lang_item_self
1780 = fntype->get_self_type ()->is_equal (*adjusted_self);
1781 bool recursive_operator_overload
1782 = is_lang_item_impl && self_is_lang_item_self;
1784 if (recursive_operator_overload)
1785 return false;
1790 // we found a valid operator overload
1791 fn->prepare_higher_ranked_bounds ();
1792 rust_debug_loc (expr.get_locus (), "resolved operator overload to: {%u} {%s}",
1793 candidate.candidate.ty->get_ref (),
1794 candidate.candidate.ty->debug_str ().c_str ());
1796 // handle generics
1797 if (lookup->needs_generic_substitutions ())
1798 lookup = SubstMapper::InferSubst (lookup, expr.get_locus ());
1800 // type check the arguments if required
1801 TyTy::FnType *type = static_cast<TyTy::FnType *> (lookup);
1802 rust_assert (type->num_params () > 0);
1803 auto fnparam = type->param_at (0);
1805 // typecheck the self
1806 unify_site (expr.get_mappings ().get_hirid (),
1807 TyTy::TyWithLocation (fnparam.second),
1808 TyTy::TyWithLocation (adjusted_self), expr.get_locus ());
1809 if (rhs == nullptr)
1811 rust_assert (type->num_params () == 1);
1813 else
1815 rust_assert (type->num_params () == 2);
1816 auto fnparam = type->param_at (1);
1817 unify_site (expr.get_mappings ().get_hirid (),
1818 TyTy::TyWithLocation (fnparam.second),
1819 TyTy::TyWithLocation (rhs), expr.get_locus ());
1822 rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF);
1823 fn = static_cast<TyTy::FnType *> (lookup);
1824 fn->monomorphize ();
1826 // get the return type
1827 TyTy::BaseType *function_ret_tyty
1828 = type->get_return_type ()->monomorphized_clone ();
1830 // store the expected fntype
1831 context->insert_operator_overload (expr.get_mappings ().get_hirid (), type);
1833 // set up the resolved name on the path
1834 resolver->insert_resolved_name (expr.get_mappings ().get_nodeid (),
1835 resolved_node_id);
1837 // return the result of the function back
1838 infered = function_ret_tyty;
1840 return true;
1843 HIR::PathIdentSegment
1844 TypeCheckExpr::resolve_possible_fn_trait_call_method_name (
1845 TyTy::BaseType &receiver, TyTy::TypeBoundPredicate *associated_predicate)
1847 // Question
1848 // do we need to probe possible bounds here? I think not, i think when we
1849 // support Fn traits they are explicitly specified
1851 // FIXME
1852 // the logic to map the FnTrait to their respective call trait-item is
1853 // duplicated over in the backend/rust-compile-expr.cc
1854 for (auto &bound : receiver.get_specified_bounds ())
1856 bool found_fn = bound.get_name ().compare ("Fn") == 0;
1857 bool found_fn_mut = bound.get_name ().compare ("FnMut") == 0;
1858 bool found_fn_once = bound.get_name ().compare ("FnOnce") == 0;
1860 if (found_fn)
1862 *associated_predicate = bound;
1863 return HIR::PathIdentSegment ("call");
1865 else if (found_fn_mut)
1867 *associated_predicate = bound;
1868 return HIR::PathIdentSegment ("call_mut");
1870 else if (found_fn_once)
1872 *associated_predicate = bound;
1873 return HIR::PathIdentSegment ("call_once");
1877 // nothing
1878 *associated_predicate = TyTy::TypeBoundPredicate::error ();
1879 return HIR::PathIdentSegment ("");
1882 bool
1883 TypeCheckExpr::resolve_fn_trait_call (HIR::CallExpr &expr,
1884 TyTy::BaseType *receiver_tyty,
1885 TyTy::BaseType **result)
1887 // we turn this into a method call expr
1888 // TODO: add implicit self argument (?)
1889 auto associated_predicate = TyTy::TypeBoundPredicate::error ();
1890 HIR::PathIdentSegment method_name
1891 = resolve_possible_fn_trait_call_method_name (*receiver_tyty,
1892 &associated_predicate);
1893 if (method_name.is_error () || associated_predicate.is_error ())
1894 return false;
1896 auto candidates = MethodResolver::Probe (receiver_tyty, method_name);
1897 if (candidates.empty ())
1898 return false;
1900 if (candidates.size () > 1)
1902 rich_location r (line_table, expr.get_locus ());
1903 for (auto &c : candidates)
1904 r.add_range (c.candidate.locus);
1906 rust_error_at (
1907 r, "multiple candidates found for function trait method call %qs",
1908 method_name.as_string ().c_str ());
1909 return false;
1912 if (receiver_tyty->get_kind () == TyTy::TypeKind::CLOSURE)
1914 const TyTy::ClosureType &closure
1915 = static_cast<TyTy::ClosureType &> (*receiver_tyty);
1916 closure.setup_fn_once_output ();
1919 auto candidate = *candidates.begin ();
1920 rust_debug_loc (expr.get_locus (),
1921 "resolved call-expr to fn trait: {%u} {%s}",
1922 candidate.candidate.ty->get_ref (),
1923 candidate.candidate.ty->debug_str ().c_str ());
1925 // Get the adjusted self
1926 Adjuster adj (receiver_tyty);
1927 TyTy::BaseType *adjusted_self = adj.adjust_type (candidate.adjustments);
1929 // store the adjustments for code-generation to know what to do which must be
1930 // stored onto the receiver to so as we don't trigger duplicate deref mappings
1931 // ICE when an argument is a method call
1932 HIR::Expr *fnexpr = expr.get_fnexpr ().get ();
1933 HirId autoderef_mappings_id = fnexpr->get_mappings ().get_hirid ();
1934 context->insert_autoderef_mappings (autoderef_mappings_id,
1935 std::move (candidate.adjustments));
1936 context->insert_receiver (expr.get_mappings ().get_hirid (), receiver_tyty);
1938 PathProbeCandidate &resolved_candidate = candidate.candidate;
1939 TyTy::BaseType *lookup_tyty = candidate.candidate.ty;
1940 NodeId resolved_node_id
1941 = resolved_candidate.is_impl_candidate ()
1942 ? resolved_candidate.item.impl.impl_item->get_impl_mappings ()
1943 .get_nodeid ()
1944 : resolved_candidate.item.trait.item_ref->get_mappings ().get_nodeid ();
1946 if (lookup_tyty->get_kind () != TyTy::TypeKind::FNDEF)
1948 rich_location r (line_table, expr.get_locus ());
1949 r.add_range (resolved_candidate.locus);
1950 rust_error_at (r, "associated impl item is not a method");
1951 return false;
1954 TyTy::BaseType *lookup = lookup_tyty;
1955 TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup);
1956 if (!fn->is_method ())
1958 rich_location r (line_table, expr.get_locus ());
1959 r.add_range (resolved_candidate.locus);
1960 rust_error_at (r, "associated function is not a method");
1961 return false;
1964 // fn traits only support tuple argument passing so we need to implicitly set
1965 // this up to get the same type checking we get in the rest of the pipeline
1967 std::vector<TyTy::TyVar> call_args;
1968 for (auto &arg : expr.get_arguments ())
1970 TyTy::BaseType *a = TypeCheckExpr::Resolve (arg.get ());
1971 call_args.push_back (TyTy::TyVar (a->get_ref ()));
1974 // crate implicit tuple
1975 HirId implicit_arg_id = mappings->get_next_hir_id ();
1976 Analysis::NodeMapping mapping (mappings->get_current_crate (), UNKNOWN_NODEID,
1977 implicit_arg_id, UNKNOWN_LOCAL_DEFID);
1979 TyTy::TupleType *tuple
1980 = new TyTy::TupleType (implicit_arg_id, expr.get_locus (), call_args);
1981 context->insert_implicit_type (implicit_arg_id, tuple);
1983 std::vector<TyTy::Argument> args;
1984 TyTy::Argument a (mapping, tuple,
1985 expr.get_locus () /*FIXME is there a better location*/);
1986 args.push_back (std::move (a));
1988 TyTy::BaseType *function_ret_tyty
1989 = TyTy::TypeCheckMethodCallExpr::go (fn, expr.get_mappings (), args,
1990 expr.get_locus (), expr.get_locus (),
1991 adjusted_self, context);
1992 if (function_ret_tyty == nullptr
1993 || function_ret_tyty->get_kind () == TyTy::TypeKind::ERROR)
1995 rust_error_at (expr.get_locus (),
1996 "failed check fn trait call-expr MethodCallExpr");
1997 return false;
2000 // store the expected fntype
2001 context->insert_operator_overload (expr.get_mappings ().get_hirid (), fn);
2003 // set up the resolved name on the path
2004 resolver->insert_resolved_name (expr.get_mappings ().get_nodeid (),
2005 resolved_node_id);
2007 // return the result of the function back
2008 *result = function_ret_tyty;
2010 return true;
2013 bool
2014 TypeCheckExpr::validate_arithmetic_type (
2015 const TyTy::BaseType *tyty, HIR::ArithmeticOrLogicalExpr::ExprType expr_type)
2017 const TyTy::BaseType *type = tyty->destructure ();
2019 // https://doc.rust-lang.org/reference/expressions/operator-expr.html#arithmetic-and-logical-binary-operators
2020 // this will change later when traits are added
2021 switch (expr_type)
2023 case ArithmeticOrLogicalOperator::ADD:
2024 case ArithmeticOrLogicalOperator::SUBTRACT:
2025 case ArithmeticOrLogicalOperator::MULTIPLY:
2026 case ArithmeticOrLogicalOperator::DIVIDE:
2027 case ArithmeticOrLogicalOperator::MODULUS:
2028 return (type->get_kind () == TyTy::TypeKind::INT)
2029 || (type->get_kind () == TyTy::TypeKind::UINT)
2030 || (type->get_kind () == TyTy::TypeKind::FLOAT)
2031 || (type->get_kind () == TyTy::TypeKind::USIZE)
2032 || (type->get_kind () == TyTy::TypeKind::ISIZE)
2033 || (type->get_kind () == TyTy::TypeKind::INFER
2034 && (((const TyTy::InferType *) type)->get_infer_kind ()
2035 == TyTy::InferType::INTEGRAL))
2036 || (type->get_kind () == TyTy::TypeKind::INFER
2037 && (((const TyTy::InferType *) type)->get_infer_kind ()
2038 == TyTy::InferType::FLOAT));
2040 // integers or bools
2041 case ArithmeticOrLogicalOperator::BITWISE_AND:
2042 case ArithmeticOrLogicalOperator::BITWISE_OR:
2043 case ArithmeticOrLogicalOperator::BITWISE_XOR:
2044 return (type->get_kind () == TyTy::TypeKind::INT)
2045 || (type->get_kind () == TyTy::TypeKind::UINT)
2046 || (type->get_kind () == TyTy::TypeKind::USIZE)
2047 || (type->get_kind () == TyTy::TypeKind::ISIZE)
2048 || (type->get_kind () == TyTy::TypeKind::BOOL)
2049 || (type->get_kind () == TyTy::TypeKind::INFER
2050 && (((const TyTy::InferType *) type)->get_infer_kind ()
2051 == TyTy::InferType::INTEGRAL));
2053 // integers only
2054 case ArithmeticOrLogicalOperator::LEFT_SHIFT:
2055 case ArithmeticOrLogicalOperator::RIGHT_SHIFT:
2056 return (type->get_kind () == TyTy::TypeKind::INT)
2057 || (type->get_kind () == TyTy::TypeKind::UINT)
2058 || (type->get_kind () == TyTy::TypeKind::USIZE)
2059 || (type->get_kind () == TyTy::TypeKind::ISIZE)
2060 || (type->get_kind () == TyTy::TypeKind::INFER
2061 && (((const TyTy::InferType *) type)->get_infer_kind ()
2062 == TyTy::InferType::INTEGRAL));
2065 rust_unreachable ();
2066 return false;
2069 } // namespace Resolver
2070 } // namespace Rust