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