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 150489 : 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 150481 : TypeCheckExpr::Resolve (HIR::Expr &expr)
51 : {
52 150481 : TypeCheckExpr resolver;
53 150481 : expr.accept_vis (resolver);
54 :
55 150481 : if (resolver.infered == nullptr)
56 86 : return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
57 :
58 150395 : if (resolver.infered->get_kind () != TyTy::TypeKind::CONST)
59 : {
60 150258 : auto ref = expr.get_mappings ().get_hirid ();
61 150258 : resolver.infered->set_ref (ref);
62 : }
63 150395 : resolver.context->insert_type (expr.get_mappings (), resolver.infered);
64 :
65 150395 : if (auto fn = resolver.infered->try_as<const TyTy::FnType> ())
66 : {
67 10737 : if (fn->is_syn_constant ())
68 28 : resolver.infered = fn->get_return_type ();
69 : }
70 :
71 150395 : return resolver.infered;
72 150481 : }
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 900 : 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 567 : TypeCheckExpr::visit (HIR::TupleExpr &expr)
170 : {
171 567 : if (expr.is_unit ())
172 : {
173 151 : infered = TyTy::TupleType::get_unit_type ();
174 151 : return;
175 : }
176 :
177 416 : std::vector<TyTy::TyVar> fields;
178 1388 : for (auto &elem : expr.get_tuple_elems ())
179 : {
180 972 : auto field_ty = TypeCheckExpr::Resolve (*elem);
181 972 : fields.emplace_back (field_ty->get_ref ());
182 : }
183 832 : infered = new TyTy::TupleType (expr.get_mappings ().get_hirid (),
184 832 : expr.get_locus (), fields);
185 416 : }
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 531 : TypeCheckExpr::visit (HIR::ReturnExpr &expr)
248 : {
249 531 : 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 530 : auto fn_return_tyty = context->peek_return_type ();
258 530 : location_t expr_locus = expr.has_return_expr ()
259 530 : ? expr.get_expr ().get_locus ()
260 32 : : 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 530 : TyTy::BaseType *expr_ty;
271 530 : if (expr.has_return_expr ())
272 : {
273 498 : context->push_expected_type (fn_return_tyty);
274 498 : expr_ty = TypeCheckExpr::Resolve (expr.get_expr ());
275 498 : context->pop_expected_type ();
276 : }
277 : else
278 32 : expr_ty = TyTy::TupleType::get_unit_type ();
279 :
280 1060 : coercion_site (expr.get_mappings ().get_hirid (),
281 530 : TyTy::TyWithLocation (fn_return_tyty),
282 530 : TyTy::TyWithLocation (expr_ty, expr_locus), expr.get_locus ());
283 :
284 530 : infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ());
285 : }
286 :
287 : void
288 12571 : TypeCheckExpr::visit (HIR::CallExpr &expr)
289 : {
290 12571 : TyTy::BaseType *function_tyty = TypeCheckExpr::Resolve (expr.get_fnexpr ());
291 :
292 12571 : rust_debug_loc (expr.get_locus (), "resolved_call_expr to: {%s}",
293 12571 : function_tyty->get_name ().c_str ());
294 :
295 12571 : TyTy::VariantDef &variant = TyTy::VariantDef::get_error_node ();
296 12571 : 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 10754 : bool resolved_fn_trait_call
331 10754 : = resolve_fn_trait_call (expr, function_tyty, &infered);
332 10754 : if (resolved_fn_trait_call)
333 : return;
334 :
335 10688 : bool valid_tyty
336 10728 : = function_tyty->is<TyTy::FnType> () || function_tyty->is<TyTy::FnPtr> ();
337 10688 : 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 11 : return;
347 : }
348 :
349 10677 : 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 10677 : auto discriminant_type_lookup
354 10677 : = mappings.lookup_lang_item (LangItem::Kind::DISCRIMINANT_TYPE);
355 10677 : bool is_discriminant_type = false;
356 10677 : 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 11501 : 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 2499 : TypeCheckExpr::visit (HIR::AssignmentExpr &expr)
399 : {
400 2499 : infered = TyTy::TupleType::get_unit_type ();
401 :
402 2499 : auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ());
403 2499 : auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ());
404 :
405 4998 : coercion_site (expr.get_mappings ().get_hirid (),
406 2499 : TyTy::TyWithLocation (lhs, expr.get_lhs ().get_locus ()),
407 2499 : TyTy::TyWithLocation (rhs, expr.get_rhs ().get_locus ()),
408 : expr.get_locus ());
409 2499 : }
410 :
411 : void
412 677 : TypeCheckExpr::visit (HIR::CompoundAssignmentExpr &expr)
413 : {
414 677 : infered = TyTy::TupleType::get_unit_type ();
415 :
416 677 : auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ());
417 677 : 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 1354 : coercion_site (expr.get_mappings ().get_hirid (),
422 677 : TyTy::TyWithLocation (lhs, expr.get_lhs ().get_locus ()),
423 677 : TyTy::TyWithLocation (rhs, expr.get_rhs ().get_locus ()),
424 : expr.get_locus ());
425 :
426 677 : auto lang_item_type
427 677 : = LangItem::CompoundAssignmentOperatorToLangItem (expr.get_expr_type ());
428 677 : bool operator_overloaded
429 677 : = resolve_operator_overload (lang_item_type, expr, lhs, rhs);
430 677 : if (operator_overloaded)
431 : return;
432 :
433 663 : bool valid_lhs = validate_arithmetic_type (lhs, expr.get_expr_type ());
434 663 : bool valid_rhs = validate_arithmetic_type (rhs, expr.get_expr_type ());
435 663 : bool valid = valid_lhs && valid_rhs;
436 663 : 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 20596 : TypeCheckExpr::visit (HIR::LiteralExpr &expr)
448 : {
449 20596 : infered = resolve_literal (expr.get_mappings (), expr.get_literal (),
450 : expr.get_locus ());
451 20596 : }
452 :
453 : void
454 3386 : TypeCheckExpr::visit (HIR::ArithmeticOrLogicalExpr &expr)
455 : {
456 3386 : auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ());
457 3386 : auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ());
458 :
459 3386 : auto lang_item_type = LangItem::OperatorToLangItem (expr.get_expr_type ());
460 3386 : bool operator_overloaded
461 3386 : = resolve_operator_overload (lang_item_type, expr, lhs, rhs);
462 3386 : if (operator_overloaded)
463 : return;
464 :
465 3217 : bool valid_lhs = validate_arithmetic_type (lhs, expr.get_expr_type ());
466 3217 : bool valid_rhs = validate_arithmetic_type (rhs, expr.get_expr_type ());
467 3217 : bool valid = valid_lhs && valid_rhs;
468 3217 : 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 3214 : 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 3145 : default:
490 3145 : {
491 6290 : infered = unify_site (
492 3145 : expr.get_mappings ().get_hirid (),
493 3145 : TyTy::TyWithLocation (lhs, expr.get_lhs ().get_locus ()),
494 3145 : TyTy::TyWithLocation (rhs, expr.get_rhs ().get_locus ()),
495 : expr.get_locus ());
496 : }
497 3145 : break;
498 : }
499 : }
500 :
501 : void
502 3536 : TypeCheckExpr::visit (HIR::ComparisonExpr &expr)
503 : {
504 3536 : auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ());
505 3536 : auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ());
506 :
507 3536 : auto borrowed_rhs
508 3536 : = new TyTy::ReferenceType (mappings.get_next_hir_id (),
509 3536 : TyTy::TyVar (rhs->get_ref ()), Mutability::Imm);
510 3536 : context->insert_implicit_type (borrowed_rhs->get_ref (), borrowed_rhs);
511 :
512 3536 : auto seg_name = LangItem::ComparisonToSegment (expr.get_expr_type ());
513 7072 : auto segment = HIR::PathIdentSegment (seg_name);
514 3536 : auto lang_item_type = LangItem::ComparisonToLangItem (expr.get_expr_type ());
515 :
516 3536 : bool operator_overloaded
517 3536 : = resolve_operator_overload (lang_item_type, expr, lhs, borrowed_rhs,
518 : segment);
519 3536 : if (operator_overloaded)
520 955 : return;
521 :
522 5162 : unify_site (expr.get_mappings ().get_hirid (),
523 2581 : TyTy::TyWithLocation (lhs, expr.get_lhs ().get_locus ()),
524 2581 : TyTy::TyWithLocation (rhs, expr.get_rhs ().get_locus ()),
525 : expr.get_locus ());
526 :
527 2581 : bool ok = context->lookup_builtin ("bool", &infered);
528 2581 : rust_assert (ok);
529 3536 : }
530 :
531 : void
532 403 : TypeCheckExpr::visit (HIR::LazyBooleanExpr &expr)
533 : {
534 403 : auto lhs = TypeCheckExpr::Resolve (expr.get_lhs ());
535 403 : auto rhs = TypeCheckExpr::Resolve (expr.get_rhs ());
536 :
537 : // we expect the lhs and rhs must be bools at this point
538 403 : TyTy::BaseType *boolean_node = nullptr;
539 403 : bool ok = context->lookup_builtin ("bool", &boolean_node);
540 403 : rust_assert (ok);
541 :
542 : // verify the lhs and rhs before unifying together
543 806 : lhs = unify_site (expr.get_mappings ().get_hirid (),
544 : TyTy::TyWithLocation (boolean_node,
545 403 : expr.get_lhs ().get_locus ()),
546 403 : TyTy::TyWithLocation (lhs, expr.get_lhs ().get_locus ()),
547 : expr.get_locus ());
548 :
549 806 : rhs = unify_site (expr.get_mappings ().get_hirid (),
550 : TyTy::TyWithLocation (boolean_node,
551 403 : expr.get_rhs ().get_locus ()),
552 403 : TyTy::TyWithLocation (rhs, expr.get_rhs ().get_locus ()),
553 : expr.get_locus ());
554 :
555 403 : infered
556 806 : = unify_site (expr.get_mappings ().get_hirid (),
557 403 : TyTy::TyWithLocation (lhs, expr.get_lhs ().get_locus ()),
558 403 : TyTy::TyWithLocation (rhs, expr.get_rhs ().get_locus ()),
559 : expr.get_locus ());
560 403 : }
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 1229 : TypeCheckExpr::visit (HIR::IfExpr &expr)
627 : {
628 1229 : TyTy::BaseType *bool_ty = nullptr;
629 1229 : bool ok = context->lookup_builtin ("bool", &bool_ty);
630 1229 : rust_assert (ok);
631 :
632 1229 : TyTy::BaseType *cond_type = TypeCheckExpr::Resolve (expr.get_if_condition ());
633 :
634 2458 : unify_site (expr.get_mappings ().get_hirid (), TyTy::TyWithLocation (bool_ty),
635 : TyTy::TyWithLocation (cond_type,
636 1229 : expr.get_if_condition ().get_locus ()),
637 : expr.get_locus ());
638 :
639 1229 : TyTy::BaseType *block_type = TypeCheckExpr::Resolve (expr.get_if_block ());
640 :
641 1229 : TyTy::BaseType *unit_ty = nullptr;
642 1229 : ok = context->lookup_builtin ("()", &unit_ty);
643 1229 : rust_assert (ok);
644 :
645 1229 : infered
646 2458 : = coercion_site (expr.get_mappings ().get_hirid (),
647 1229 : TyTy::TyWithLocation (unit_ty),
648 : TyTy::TyWithLocation (block_type,
649 1229 : expr.get_if_block ().get_locus ()),
650 : expr.get_locus ());
651 1229 : }
652 :
653 : void
654 1261 : TypeCheckExpr::visit (HIR::IfExprConseqElse &expr)
655 : {
656 1261 : TyTy::BaseType *bool_ty = nullptr;
657 1261 : bool ok = context->lookup_builtin ("bool", &bool_ty);
658 1261 : rust_assert (ok);
659 :
660 1261 : TyTy::BaseType *cond_type = TypeCheckExpr::Resolve (expr.get_if_condition ());
661 :
662 2522 : unify_site (expr.get_mappings ().get_hirid (), TyTy::TyWithLocation (bool_ty),
663 : TyTy::TyWithLocation (cond_type,
664 1261 : expr.get_if_condition ().get_locus ()),
665 : expr.get_locus ());
666 :
667 1261 : auto if_blk_resolved = TypeCheckExpr::Resolve (expr.get_if_block ());
668 1261 : auto else_blk_resolved = TypeCheckExpr::Resolve (expr.get_else_block ());
669 :
670 1261 : if (if_blk_resolved->get_kind () == TyTy::NEVER)
671 40 : infered = else_blk_resolved;
672 1221 : else if (else_blk_resolved->get_kind () == TyTy::NEVER)
673 7 : infered = if_blk_resolved;
674 : else
675 : {
676 1214 : infered
677 2428 : = unify_site (expr.get_mappings ().get_hirid (),
678 : TyTy::TyWithLocation (if_blk_resolved,
679 1214 : expr.get_if_block ().get_locus ()),
680 : TyTy::TyWithLocation (
681 1214 : else_blk_resolved, expr.get_else_block ().get_locus ()),
682 : expr.get_locus ());
683 : }
684 1261 : }
685 :
686 : void
687 3662 : TypeCheckExpr::visit (HIR::UnsafeBlockExpr &expr)
688 : {
689 3662 : infered = TypeCheckExpr::Resolve (expr.get_block_expr ());
690 3662 : }
691 :
692 : void
693 23218 : TypeCheckExpr::visit (HIR::BlockExpr &expr)
694 : {
695 23218 : bool has_label = expr.has_label ();
696 23218 : 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 23218 : TyTy::BaseType *outer_expected = context->peek_expected_type ();
702 23218 : context->push_expected_type (nullptr);
703 :
704 47408 : for (auto &s : expr.get_statements ())
705 : {
706 24190 : if (!s->is_item ())
707 23762 : continue;
708 :
709 428 : TypeCheckStmt::Resolve (*s);
710 : }
711 :
712 47408 : for (auto &s : expr.get_statements ())
713 : {
714 24190 : if (s->is_item ())
715 428 : continue;
716 :
717 23762 : auto resolved = TypeCheckStmt::Resolve (*s);
718 23762 : 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 0 : return;
725 : }
726 :
727 23762 : 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 23218 : context->pop_expected_type ();
737 :
738 23218 : TyTy::BaseType *tail_expr_type = nullptr;
739 23218 : if (expr.has_expr ())
740 : {
741 16445 : context->push_expected_type (outer_expected);
742 16445 : tail_expr_type = TypeCheckExpr::Resolve (expr.get_final_expr ());
743 16445 : context->pop_expected_type ();
744 : }
745 :
746 23218 : TyTy::BaseType *label_context_type = nullptr;
747 23218 : bool label_context_type_infered = false;
748 23218 : 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 23218 : if (tail_expr_type != nullptr)
760 : {
761 16445 : 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 16443 : infered = tail_expr_type;
775 : }
776 6773 : else if (label_context_type_infered)
777 1 : infered = label_context_type;
778 6772 : else if (expr.is_tail_reachable ())
779 6321 : infered = TyTy::TupleType::get_unit_type ();
780 : else
781 : {
782 : // FIXME this seems wrong
783 451 : infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ());
784 : }
785 : }
786 :
787 : void
788 689 : TypeCheckExpr::visit (HIR::AnonConst &expr)
789 : {
790 689 : if (!expr.is_deferred ())
791 : {
792 677 : infered = TypeCheckExpr::Resolve (expr.get_inner_expr ());
793 677 : 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 7 : TypeCheckExpr::visit (HIR::RangeFromToInclExpr &expr)
1071 : {
1072 7 : auto lang_item_type = LangItem::Kind::RANGE_INCLUSIVE;
1073 :
1074 7 : auto lang_item_defined = mappings.lookup_lang_item (lang_item_type);
1075 : // we need to have it maybe
1076 7 : if (!lang_item_defined)
1077 : {
1078 0 : rust_internal_error_at (expr.get_locus (),
1079 : "unable to find relevant lang item: %s",
1080 0 : LangItem::ToString (lang_item_type).c_str ());
1081 : return;
1082 : }
1083 7 : DefId respective_lang_item_id = lang_item_defined.value ();
1084 :
1085 : // look it up and it _must_ be a struct definition
1086 7 : HIR::Item *item = mappings.lookup_defid (respective_lang_item_id).value ();
1087 :
1088 7 : TyTy::BaseType *item_type = nullptr;
1089 7 : bool ok
1090 7 : = context->lookup_type (item->get_mappings ().get_hirid (), &item_type);
1091 7 : rust_assert (ok);
1092 7 : rust_assert (item_type->get_kind () == TyTy::TypeKind::ADT);
1093 7 : TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (item_type);
1094 :
1095 : // this is a single generic item lets assert that
1096 7 : rust_assert (adt->get_num_substitutions () == 1);
1097 :
1098 : // resolve the range expressions and these types must unify then we use that
1099 : // type to substitute into the ADT
1100 7 : TyTy::BaseType *from_ty = TypeCheckExpr::Resolve (expr.get_from_expr ());
1101 7 : TyTy::BaseType *to_ty = TypeCheckExpr::Resolve (expr.get_to_expr ());
1102 14 : TyTy::BaseType *unified = unify_site (
1103 7 : expr.get_mappings ().get_hirid (),
1104 7 : TyTy::TyWithLocation (from_ty, expr.get_from_expr ().get_locus ()),
1105 7 : TyTy::TyWithLocation (to_ty, expr.get_to_expr ().get_locus ()),
1106 7 : expr.get_locus ());
1107 :
1108 : // substitute it in
1109 7 : std::vector<TyTy::SubstitutionArg> subst_mappings;
1110 7 : const TyTy::SubstitutionParamMapping *param_ref = &adt->get_substs ().at (0);
1111 7 : subst_mappings.emplace_back (param_ref, unified);
1112 :
1113 7 : TyTy::SubstitutionArgumentMappings subst (
1114 7 : subst_mappings, {}, adt->get_substitution_arguments ().get_regions (),
1115 7 : expr.get_locus ());
1116 7 : infered = SubstMapperInternal::Resolve (adt, subst);
1117 7 : }
1118 :
1119 : void
1120 291 : TypeCheckExpr::visit (HIR::ArrayIndexExpr &expr)
1121 : {
1122 291 : auto array_expr_ty = TypeCheckExpr::Resolve (expr.get_array_expr ());
1123 291 : if (array_expr_ty->get_kind () == TyTy::TypeKind::ERROR)
1124 289 : return;
1125 :
1126 290 : auto index_expr_ty = TypeCheckExpr::Resolve (expr.get_index_expr ());
1127 290 : if (index_expr_ty->get_kind () == TyTy::TypeKind::ERROR)
1128 : return;
1129 :
1130 : // first attempt to use direct array index logic
1131 290 : auto direct_array_expr_ty = array_expr_ty;
1132 290 : if (direct_array_expr_ty->get_kind () == TyTy::TypeKind::REF)
1133 : {
1134 : // lets try and deref it since rust allows this
1135 29 : auto ref = static_cast<TyTy::ReferenceType *> (direct_array_expr_ty);
1136 29 : auto base = ref->get_base ();
1137 29 : if (base->get_kind () == TyTy::TypeKind::ARRAY)
1138 290 : direct_array_expr_ty = base;
1139 : }
1140 :
1141 290 : TyTy::BaseType *size_ty;
1142 290 : bool ok = context->lookup_builtin ("usize", &size_ty);
1143 290 : rust_assert (ok);
1144 :
1145 290 : bool maybe_simple_array_access
1146 290 : = types_compatable (TyTy::TyWithLocation (index_expr_ty),
1147 290 : TyTy::TyWithLocation (size_ty), expr.get_locus (),
1148 : false);
1149 290 : if (maybe_simple_array_access
1150 290 : && direct_array_expr_ty->get_kind () == TyTy::TypeKind::ARRAY)
1151 : {
1152 450 : unify_site (expr.get_index_expr ().get_mappings ().get_hirid (),
1153 225 : TyTy::TyWithLocation (size_ty),
1154 : TyTy::TyWithLocation (index_expr_ty,
1155 225 : expr.get_index_expr ().get_locus ()),
1156 : expr.get_locus ());
1157 :
1158 225 : TyTy::ArrayType *array_type
1159 : = static_cast<TyTy::ArrayType *> (direct_array_expr_ty);
1160 225 : infered = array_type->get_element_type ()->clone ();
1161 225 : return;
1162 : }
1163 :
1164 : // is this a case of core::ops::index?
1165 65 : auto lang_item_type = LangItem::Kind::INDEX;
1166 65 : bool operator_overloaded
1167 65 : = resolve_operator_overload (lang_item_type, expr, array_expr_ty,
1168 : index_expr_ty);
1169 65 : if (operator_overloaded)
1170 : {
1171 : // index and index mut always return a reference to the element
1172 63 : TyTy::BaseType *resolved = infered;
1173 63 : rust_assert (resolved->get_kind () == TyTy::TypeKind::REF);
1174 63 : TyTy::ReferenceType *ref = static_cast<TyTy::ReferenceType *> (resolved);
1175 :
1176 63 : infered = ref->get_base ()->clone ();
1177 63 : return;
1178 : }
1179 :
1180 : // error[E0277]: the type `[{integer}]` cannot be indexed by `u32`
1181 2 : rich_location r (line_table, expr.get_locus ());
1182 2 : r.add_range (expr.get_array_expr ().get_locus ());
1183 2 : r.add_range (expr.get_index_expr ().get_locus ());
1184 2 : rust_error_at (r, ErrorCode::E0277, "the type %qs cannot be indexed by %qs",
1185 4 : array_expr_ty->get_name ().c_str (),
1186 2 : index_expr_ty->get_name ().c_str ());
1187 2 : }
1188 :
1189 : void
1190 433 : TypeCheckExpr::visit (HIR::ArrayExpr &expr)
1191 : {
1192 433 : auto &elements = expr.get_internal_elements ();
1193 :
1194 433 : TyTy::BaseType *expected_ty = nullptr;
1195 433 : bool ok = context->lookup_builtin ("usize", &expected_ty);
1196 433 : rust_assert (ok);
1197 :
1198 433 : HIR::Expr *capacity_expr = nullptr;
1199 433 : TyTy::BaseType *element_type = nullptr;
1200 433 : TyTy::BaseType *capacity_type = nullptr;
1201 433 : switch (elements.get_array_expr_type ())
1202 : {
1203 123 : case HIR::ArrayElems::ArrayExprType::COPIED:
1204 123 : {
1205 123 : HIR::ArrayElemsCopied &elems
1206 : = static_cast<HIR::ArrayElemsCopied &> (elements);
1207 123 : element_type = TypeCheckExpr::Resolve (elems.get_elem_to_copy ());
1208 :
1209 123 : auto capacity_expr_ty
1210 123 : = TypeCheckExpr::Resolve (elems.get_num_copies_expr ());
1211 123 : if (capacity_expr_ty->is<TyTy::ErrorType> ())
1212 7 : return;
1213 :
1214 120 : context->insert_type (elems.get_num_copies_expr ().get_mappings (),
1215 : expected_ty);
1216 :
1217 240 : auto result = unify_site (
1218 120 : expr.get_mappings ().get_hirid (), TyTy::TyWithLocation (expected_ty),
1219 : TyTy::TyWithLocation (capacity_expr_ty,
1220 120 : elems.get_num_copies_expr ().get_locus ()),
1221 : expr.get_locus ());
1222 120 : if (result->is<TyTy::ErrorType> ())
1223 : return;
1224 :
1225 116 : capacity_expr = &elems.get_num_copies_expr ();
1226 116 : capacity_type = expected_ty;
1227 : }
1228 116 : break;
1229 :
1230 310 : case HIR::ArrayElems::ArrayExprType::VALUES:
1231 310 : {
1232 310 : HIR::ArrayElemsValues &elems
1233 : = static_cast<HIR::ArrayElemsValues &> (elements);
1234 :
1235 310 : std::vector<TyTy::BaseType *> types;
1236 1827 : for (auto &elem : elems.get_values ())
1237 : {
1238 1517 : types.push_back (TypeCheckExpr::Resolve (*elem));
1239 : }
1240 :
1241 : // this is a LUB
1242 310 : element_type
1243 310 : = TyTy::TyVar::get_implicit_infer_var (expr.get_locus ()).get_tyty ();
1244 1827 : for (auto &type : types)
1245 : {
1246 1517 : element_type
1247 1517 : = unify_site (expr.get_mappings ().get_hirid (),
1248 1517 : TyTy::TyWithLocation (element_type),
1249 1517 : TyTy::TyWithLocation (type, type->get_locus ()),
1250 : expr.get_locus ());
1251 : }
1252 :
1253 310 : auto crate_num = mappings.get_current_crate ();
1254 310 : Analysis::NodeMapping mapping (crate_num, UNKNOWN_NODEID,
1255 310 : mappings.get_next_hir_id (crate_num),
1256 310 : UNKNOWN_LOCAL_DEFID);
1257 310 : std::string capacity_str = std::to_string (elems.get_num_elements ());
1258 310 : capacity_expr = new HIR::LiteralExpr (mapping, capacity_str,
1259 : HIR::Literal::LitType::INT,
1260 : PrimitiveCoreType::CORETYPE_USIZE,
1261 930 : UNDEF_LOCATION, {});
1262 :
1263 : // mark the type for this implicit node
1264 310 : context->insert_type (mapping, expected_ty);
1265 310 : capacity_type = expected_ty;
1266 310 : }
1267 310 : break;
1268 : }
1269 :
1270 426 : rust_assert (capacity_expr);
1271 426 : rust_assert (capacity_type);
1272 426 : auto ctx = Compile::Context::get ();
1273 426 : tree capacity_value
1274 426 : = Compile::HIRCompileBase::query_compile_const_expr (ctx, capacity_type,
1275 : *capacity_expr);
1276 :
1277 : // Create ConstValueType with ref == ty_ref (both pointing to capacity_expr)
1278 : // ty_ref gets updated during substitution via set_ty_ref()
1279 426 : HirId capacity_expr_id = capacity_expr->get_mappings ().get_hirid ();
1280 426 : auto const_type
1281 : = new TyTy::ConstValueType (capacity_value, expected_ty, capacity_expr_id,
1282 426 : capacity_expr_id);
1283 :
1284 : // Insert the ConstValueType at its ref
1285 426 : context->insert_type (capacity_expr->get_mappings (),
1286 426 : const_type->as_base_type ());
1287 :
1288 426 : infered
1289 852 : = new TyTy::ArrayType (expr.get_mappings ().get_hirid (), expr.get_locus (),
1290 : TyTy::TyVar (
1291 426 : const_type->as_base_type ()->get_ty_ref ()),
1292 852 : TyTy::TyVar (element_type->get_ref ()));
1293 : }
1294 :
1295 : // empty struct
1296 : void
1297 81 : TypeCheckExpr::visit (HIR::StructExprStruct &struct_expr)
1298 : {
1299 81 : HIR::PathInExpression &path = struct_expr.get_struct_name ();
1300 :
1301 81 : TyTy::BaseType *struct_path_ty = TypeCheckExpr::Resolve (path);
1302 81 : if (struct_path_ty->get_kind () != TyTy::TypeKind::ADT)
1303 : {
1304 0 : rust_error_at (path.get_locus (), "expected an ADT type for constructor");
1305 1 : return;
1306 : }
1307 :
1308 81 : TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (struct_path_ty);
1309 81 : TyTy::VariantDef *variant;
1310 :
1311 : // unwrap and type check the variant if it's an enum
1312 81 : if (adt->is_enum ())
1313 : {
1314 3 : HirId variant_id;
1315 3 : bool ok = context->lookup_variant_definition (
1316 3 : struct_expr.get_struct_name ().get_mappings ().get_hirid (),
1317 : &variant_id);
1318 3 : if (!ok)
1319 : {
1320 0 : rich_location r (line_table, struct_expr.get_locus ());
1321 0 : r.add_range (struct_expr.get_struct_name ().get_locus ());
1322 0 : rust_error_at (
1323 0 : struct_expr.get_struct_name ().get_locus (), ErrorCode::E0574,
1324 : "expected a struct, variant or union type, found enum %qs",
1325 0 : adt->get_name ().c_str ());
1326 0 : return;
1327 0 : }
1328 :
1329 3 : ok = adt->lookup_variant_by_id (variant_id, &variant);
1330 3 : rust_assert (ok);
1331 : }
1332 : else
1333 : {
1334 78 : rust_assert (adt->number_of_variants () == 1);
1335 78 : variant = adt->get_variants ().at (0);
1336 : }
1337 :
1338 81 : if (!variant->get_fields ().empty ())
1339 : {
1340 1 : std::vector<std::string> field_names;
1341 4 : for (auto &field : variant->get_fields ())
1342 3 : field_names.push_back (field->get_name ());
1343 1 : Error missing_fields_error
1344 : = TypeCheckStructExpr::make_missing_field_error (
1345 1 : struct_expr.get_locus (), field_names, struct_path_ty->get_name ());
1346 : // We might want to return or handle these in the future emit for now.
1347 1 : missing_fields_error.emit ();
1348 1 : return;
1349 1 : }
1350 :
1351 80 : infered = struct_path_ty;
1352 : }
1353 :
1354 : void
1355 1371 : TypeCheckExpr::visit (HIR::StructExprStructFields &struct_expr)
1356 : {
1357 1371 : infered = TypeCheckStructExpr::Resolve (struct_expr);
1358 1371 : }
1359 :
1360 : void
1361 314 : TypeCheckExpr::visit (HIR::GroupedExpr &expr)
1362 : {
1363 314 : infered = TypeCheckExpr::Resolve (expr.get_expr_in_parens ());
1364 314 : }
1365 :
1366 : void
1367 5055 : TypeCheckExpr::visit (HIR::FieldAccessExpr &expr)
1368 : {
1369 5055 : auto struct_base = TypeCheckExpr::Resolve (expr.get_receiver_expr ());
1370 :
1371 : // Box<T> autoderef
1372 5055 : if (auto try_struct_base = TyTy::try_get_box_inner_type (struct_base))
1373 : {
1374 1 : struct_base = *try_struct_base;
1375 : }
1376 :
1377 : // FIXME does this require autoderef here?
1378 5055 : if (struct_base->get_kind () == TyTy::TypeKind::REF)
1379 : {
1380 3465 : TyTy::ReferenceType *r = static_cast<TyTy::ReferenceType *> (struct_base);
1381 3465 : struct_base = r->get_base ();
1382 : }
1383 :
1384 5055 : bool is_valid_type = struct_base->get_kind () == TyTy::TypeKind::ADT;
1385 5055 : if (!is_valid_type)
1386 : {
1387 0 : rust_error_at (expr.get_locus (), "expected algebraic data type got %qs",
1388 0 : struct_base->get_name ().c_str ());
1389 4 : return;
1390 : }
1391 :
1392 5055 : TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (struct_base);
1393 5055 : rust_assert (adt->number_of_variants () > 0);
1394 5055 : TyTy::VariantDef *vaiant = adt->get_variants ().at (0);
1395 :
1396 5055 : TyTy::StructFieldType *lookup = nullptr;
1397 5055 : bool found = vaiant->lookup_field (expr.get_field_name ().as_string (),
1398 : &lookup, nullptr);
1399 5055 : if (!found || adt->is_enum ())
1400 : {
1401 4 : rich_location r (line_table, expr.get_locus ());
1402 4 : r.add_range (expr.get_field_name ().get_locus ());
1403 4 : rust_error_at (r, ErrorCode::E0609, "no field %qs on type %qs",
1404 8 : expr.get_field_name ().as_string ().c_str (),
1405 4 : adt->get_name ().c_str ());
1406 4 : return;
1407 4 : }
1408 :
1409 5051 : infered = lookup->get_field_type ();
1410 : }
1411 :
1412 : bool
1413 43 : is_default_fn (const MethodCandidate &candidate)
1414 : {
1415 43 : if (candidate.candidate.is_impl_candidate ())
1416 : {
1417 43 : auto *item = candidate.candidate.item.impl.impl_item;
1418 :
1419 43 : if (item->get_impl_item_type () == HIR::ImplItem::FUNCTION)
1420 : {
1421 43 : auto &fn = static_cast<HIR::Function &> (*item);
1422 :
1423 43 : return fn.is_default ();
1424 : }
1425 : }
1426 :
1427 : return false;
1428 : }
1429 :
1430 : void
1431 2 : emit_ambiguous_resolution_error (HIR::MethodCallExpr &expr,
1432 : std::set<MethodCandidate> &candidates)
1433 : {
1434 2 : rich_location r (line_table, expr.get_method_name ().get_locus ());
1435 2 : std::string rich_msg = "multiple "
1436 6 : + expr.get_method_name ().get_segment ().to_string ()
1437 2 : + " found";
1438 :
1439 : // We have to filter out default candidates
1440 6 : for (auto &c : candidates)
1441 4 : if (!is_default_fn (c))
1442 4 : r.add_range (c.candidate.locus);
1443 :
1444 2 : r.add_fixit_replace (rich_msg.c_str ());
1445 :
1446 2 : rust_error_at (r, ErrorCode::E0592, "duplicate definitions with name %qs",
1447 6 : expr.get_method_name ().get_segment ().to_string ().c_str ());
1448 2 : }
1449 :
1450 : // We are allowed to have multiple candidates if they are all specializable
1451 : // functions or if all of them except one are specializable functions.
1452 : // In the later case, we just return a valid candidate without erroring out
1453 : // about ambiguity. If there are two or more specialized functions, then we
1454 : // error out.
1455 : //
1456 : // FIXME: The first case is not handled at the moment, so we error out
1457 : tl::optional<const MethodCandidate &>
1458 16 : handle_multiple_candidates (HIR::MethodCallExpr &expr,
1459 : std::set<MethodCandidate> &candidates)
1460 : {
1461 16 : auto all_default = true;
1462 16 : tl::optional<const MethodCandidate &> found = tl::nullopt;
1463 :
1464 53 : for (auto &c : candidates)
1465 : {
1466 39 : if (!is_default_fn (c))
1467 : {
1468 18 : all_default = false;
1469 :
1470 : // We haven't found a final candidate yet, so we can select
1471 : // this one. However, if we already have a candidate, then
1472 : // that means there are multiple non-default candidates - we
1473 : // must error out
1474 18 : if (!found)
1475 : {
1476 : found = c;
1477 : }
1478 : else
1479 : {
1480 2 : emit_ambiguous_resolution_error (expr, candidates);
1481 2 : return tl::nullopt;
1482 : }
1483 : }
1484 : }
1485 :
1486 : // None of the candidates were a non-default (specialized) function, so we
1487 : // error out
1488 14 : if (all_default)
1489 : {
1490 0 : rust_sorry_at (expr.get_locus (),
1491 : "cannot resolve method calls to non-specialized methods "
1492 : "(all function candidates are %qs)",
1493 : "default");
1494 0 : return tl::nullopt;
1495 : }
1496 :
1497 14 : return found;
1498 : }
1499 :
1500 : void
1501 3046 : TypeCheckExpr::visit (HIR::MethodCallExpr &expr)
1502 : {
1503 3046 : auto receiver_tyty = TypeCheckExpr::Resolve (expr.get_receiver ());
1504 3046 : if (receiver_tyty->get_kind () == TyTy::TypeKind::ERROR)
1505 : {
1506 1 : rust_error_at (expr.get_receiver ().get_locus (),
1507 : "failed to resolve receiver in MethodCallExpr");
1508 12 : return;
1509 : }
1510 :
1511 3045 : rust_debug_loc (expr.get_locus (), "attempting to resolve method for %s",
1512 3045 : receiver_tyty->debug_str ().c_str ());
1513 3045 : auto candidates
1514 : = MethodResolver::Probe (receiver_tyty,
1515 3045 : expr.get_method_name ().get_segment ());
1516 3045 : if (candidates.empty ())
1517 : {
1518 7 : rich_location richloc (line_table, expr.get_method_name ().get_locus ());
1519 7 : richloc.add_fixit_replace ("method not found");
1520 7 : rust_error_at (
1521 : richloc, ErrorCode::E0599,
1522 : "no method named %qs found in the current scope",
1523 14 : expr.get_method_name ().get_segment ().to_string ().c_str ());
1524 7 : return;
1525 7 : }
1526 :
1527 3038 : tl::optional<const MethodCandidate &> candidate = *candidates.begin ();
1528 :
1529 3038 : if (candidates.size () > 1)
1530 16 : candidate = handle_multiple_candidates (expr, candidates);
1531 :
1532 3038 : if (!candidate)
1533 : return;
1534 :
1535 3036 : auto found_candidate = *candidate;
1536 :
1537 6072 : rust_debug_loc (expr.get_method_name ().get_locus (),
1538 : "resolved method to: {%u} {%s} with [%lu] adjustments",
1539 3036 : found_candidate.candidate.ty->get_ref (),
1540 3036 : found_candidate.candidate.ty->debug_str ().c_str (),
1541 3036 : (unsigned long) found_candidate.adjustments.size ());
1542 :
1543 : // Get the adjusted self
1544 3036 : Adjuster adj (receiver_tyty);
1545 3036 : TyTy::BaseType *adjusted_self = adj.adjust_type (found_candidate.adjustments);
1546 3036 : rust_debug ("receiver: %s adjusted self %s",
1547 : receiver_tyty->debug_str ().c_str (),
1548 : adjusted_self->debug_str ().c_str ());
1549 :
1550 : // store the adjustments for code-generation to know what to do which must be
1551 : // stored onto the receiver to so as we don't trigger duplicate deref mappings
1552 : // ICE when an argument is a method call
1553 3036 : HirId autoderef_mappings_id
1554 3036 : = expr.get_receiver ().get_mappings ().get_hirid ();
1555 3036 : context->insert_autoderef_mappings (autoderef_mappings_id,
1556 : std::move (found_candidate.adjustments));
1557 :
1558 3036 : PathProbeCandidate &resolved_candidate = found_candidate.candidate;
1559 3036 : TyTy::BaseType *lookup_tyty = found_candidate.candidate.ty;
1560 3036 : NodeId resolved_node_id
1561 3036 : = resolved_candidate.is_impl_candidate ()
1562 3036 : ? resolved_candidate.item.impl.impl_item->get_impl_mappings ()
1563 2069 : .get_nodeid ()
1564 967 : : resolved_candidate.item.trait.item_ref->get_mappings ().get_nodeid ();
1565 :
1566 3036 : if (lookup_tyty->get_kind () != TyTy::TypeKind::FNDEF)
1567 : {
1568 0 : rich_location r (line_table, expr.get_method_name ().get_locus ());
1569 0 : r.add_range (resolved_candidate.locus);
1570 0 : rust_error_at (r, "associated impl item is not a method");
1571 0 : return;
1572 0 : }
1573 :
1574 3036 : TyTy::BaseType *lookup = lookup_tyty;
1575 3036 : TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup);
1576 6072 : if (!fn->is_method ())
1577 : {
1578 0 : rich_location r (line_table, expr.get_method_name ().get_locus ());
1579 0 : r.add_range (resolved_candidate.locus);
1580 0 : rust_error_at (r, "associated function is not a method");
1581 0 : return;
1582 0 : }
1583 :
1584 3036 : rust_debug_loc (expr.get_locus (), "resolved method call to: {%u} {%s}",
1585 3036 : found_candidate.candidate.ty->get_ref (),
1586 3036 : found_candidate.candidate.ty->debug_str ().c_str ());
1587 :
1588 3036 : if (resolved_candidate.is_impl_candidate ())
1589 : {
1590 2069 : auto infer_arguments = TyTy::SubstitutionArgumentMappings::empty ();
1591 2069 : infer_arguments.get_mut_regions ()
1592 2069 : = fn->get_used_arguments ().get_regions ();
1593 2069 : HIR::ImplBlock &impl = *resolved_candidate.item.impl.parent;
1594 2069 : TyTy::BaseType *impl_self_infer
1595 2069 : = TypeCheckItem::ResolveImplBlockSelfWithInference (impl,
1596 : expr.get_locus (),
1597 : &infer_arguments);
1598 2069 : if (impl_self_infer->get_kind () == TyTy::TypeKind::ERROR)
1599 : {
1600 0 : rich_location r (line_table, expr.get_locus ());
1601 0 : r.add_range (impl.get_type ().get_locus ());
1602 0 : rust_error_at (
1603 : r, "failed to resolve impl type for method call resolution");
1604 0 : return;
1605 0 : }
1606 :
1607 2069 : if (!infer_arguments.is_empty ())
1608 554 : lookup = SubstMapperInternal::Resolve (lookup, infer_arguments);
1609 2069 : }
1610 :
1611 : // apply any remaining generic arguments
1612 3036 : if (expr.get_method_name ().has_generic_args ())
1613 : {
1614 29 : HIR::GenericArgs &args = expr.get_method_name ().get_generic_args ();
1615 29 : rust_debug_loc (args.get_locus (),
1616 : "applying generic arguments to method_call: {%s}",
1617 29 : lookup->debug_str ().c_str ());
1618 :
1619 29 : lookup
1620 29 : = SubstMapper::Resolve (lookup, expr.get_method_name ().get_locus (),
1621 : &args);
1622 29 : if (lookup->get_kind () == TyTy::TypeKind::ERROR)
1623 : return;
1624 : }
1625 3007 : else if (lookup->needs_generic_substitutions ())
1626 : {
1627 873 : rust_debug ("method needs inference: {%s}",
1628 : lookup->debug_str ().c_str ());
1629 873 : lookup = SubstMapper::InferSubst (lookup,
1630 873 : expr.get_method_name ().get_locus ());
1631 : }
1632 :
1633 3035 : rust_debug ("type-checking method_call: {%s}", lookup->debug_str ().c_str ());
1634 :
1635 3035 : TyTy::BaseType *function_ret_tyty
1636 3035 : = TyTy::TypeCheckMethodCallExpr::go (static_cast<TyTy::FnType *> (lookup),
1637 : expr, adjusted_self, context);
1638 3035 : if (function_ret_tyty == nullptr
1639 3035 : || function_ret_tyty->get_kind () == TyTy::TypeKind::ERROR)
1640 : {
1641 0 : rust_error_at (expr.get_locus (),
1642 : "failed to lookup type to MethodCallExpr");
1643 0 : return;
1644 : }
1645 :
1646 : // store the expected fntype
1647 3035 : context->insert_type (expr.get_method_name ().get_mappings (), lookup);
1648 :
1649 3035 : auto &nr_ctx = Resolver2_0::FinalizedNameResolutionContext::get ();
1650 :
1651 3035 : nr_ctx.map_usage (Resolver2_0::Usage (expr.get_mappings ().get_nodeid ()),
1652 3035 : Resolver2_0::Definition (resolved_node_id),
1653 : Resolver2_0::Namespace::Values);
1654 :
1655 : // return the result of the function back
1656 3035 : infered = function_ret_tyty;
1657 3046 : }
1658 :
1659 : void
1660 127 : TypeCheckExpr::visit (HIR::LoopExpr &expr)
1661 : {
1662 127 : context->push_new_loop_context (expr.get_mappings ().get_hirid (),
1663 : expr.get_locus ());
1664 127 : TyTy::BaseType *block_expr = TypeCheckExpr::Resolve (expr.get_loop_block ());
1665 127 : if (!block_expr->is_unit ())
1666 : {
1667 0 : rust_error_at (expr.get_loop_block ().get_locus (),
1668 : "expected %<()%> got %s",
1669 0 : block_expr->as_string ().c_str ());
1670 0 : return;
1671 : }
1672 :
1673 127 : TyTy::BaseType *loop_context_type = context->pop_loop_context ();
1674 :
1675 127 : bool loop_context_type_infered
1676 127 : = (loop_context_type->get_kind () != TyTy::TypeKind::INFER)
1677 127 : || ((loop_context_type->get_kind () == TyTy::TypeKind::INFER)
1678 118 : && (((TyTy::InferType *) loop_context_type)->get_infer_kind ()
1679 238 : != TyTy::InferType::GENERAL));
1680 :
1681 127 : infered = loop_context_type_infered ? loop_context_type
1682 111 : : TyTy::TupleType::get_unit_type ();
1683 : }
1684 :
1685 : void
1686 78 : TypeCheckExpr::visit (HIR::WhileLoopExpr &expr)
1687 : {
1688 78 : context->push_new_while_loop_context (expr.get_mappings ().get_hirid ());
1689 78 : TyTy::BaseType *predicate_type
1690 78 : = TypeCheckExpr::Resolve (expr.get_predicate_expr ());
1691 78 : if (predicate_type->get_kind () != TyTy::TypeKind::BOOL
1692 78 : && predicate_type->get_kind () != TyTy::TypeKind::NEVER)
1693 : {
1694 0 : rust_error_at (expr.get_predicate_expr ().get_locus (),
1695 : "expected boolean expression in %<while%> condition");
1696 0 : context->pop_loop_context ();
1697 0 : return;
1698 : }
1699 78 : TyTy::BaseType *block_expr = TypeCheckExpr::Resolve (expr.get_loop_block ());
1700 78 : if (!block_expr->is_unit ())
1701 : {
1702 0 : rust_error_at (expr.get_loop_block ().get_locus (),
1703 : "expected %<()%> got %s",
1704 0 : block_expr->as_string ().c_str ());
1705 0 : context->pop_loop_context ();
1706 0 : return;
1707 : }
1708 78 : context->pop_loop_context ();
1709 78 : infered = TyTy::TupleType::get_unit_type ();
1710 : }
1711 :
1712 : void
1713 91 : TypeCheckExpr::visit (HIR::BreakExpr &expr)
1714 : {
1715 91 : if (!context->have_loop_context ())
1716 : {
1717 2 : rust_error_at (expr.get_locus (), ErrorCode::E0268,
1718 : "%<break%> outside of a loop or labeled block");
1719 2 : return;
1720 : }
1721 :
1722 89 : if (expr.has_break_expr ())
1723 : {
1724 23 : TyTy::BaseType *break_expr_tyty
1725 23 : = TypeCheckExpr::Resolve (expr.get_expr ());
1726 :
1727 23 : TyTy::BaseType *loop_context = context->peek_loop_context ();
1728 23 : if (loop_context->get_kind () == TyTy::TypeKind::ERROR)
1729 : {
1730 4 : rust_error_at (
1731 : expr.get_locus (), ErrorCode::E0571,
1732 : "can only %<break%> with a value inside a %<loop%> block");
1733 4 : return;
1734 : }
1735 :
1736 19 : TyTy::BaseType *unified_ty
1737 38 : = unify_site (expr.get_mappings ().get_hirid (),
1738 19 : TyTy::TyWithLocation (loop_context),
1739 : TyTy::TyWithLocation (break_expr_tyty,
1740 19 : expr.get_expr ().get_locus ()),
1741 : expr.get_locus ());
1742 19 : context->swap_head_loop_context (unified_ty);
1743 : }
1744 :
1745 85 : infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ());
1746 : }
1747 :
1748 : void
1749 16 : TypeCheckExpr::visit (HIR::ContinueExpr &expr)
1750 : {
1751 16 : if (!context->have_loop_context ())
1752 : {
1753 3 : rust_error_at (expr.get_locus (), ErrorCode::E0268,
1754 : "%<continue%> outside of a loop");
1755 3 : return;
1756 : }
1757 13 : infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ());
1758 : }
1759 :
1760 : void
1761 2027 : TypeCheckExpr::visit (HIR::BorrowExpr &expr)
1762 : {
1763 2027 : TyTy::BaseType *resolved_base = TypeCheckExpr::Resolve (expr.get_expr ());
1764 2027 : if (resolved_base->is<TyTy::ErrorType> ())
1765 : return;
1766 :
1767 : // In Rust this is valid because of DST's
1768 : //
1769 : // fn test() {
1770 : // let a:&str = "TEST 1";
1771 : // let b:&str = &"TEST 2";
1772 : // }
1773 2026 : if (resolved_base->get_kind () == TyTy::TypeKind::REF)
1774 : {
1775 43 : const TyTy::ReferenceType *ref
1776 : = static_cast<const TyTy::ReferenceType *> (resolved_base);
1777 :
1778 : // this might end up being a more generic is_dyn object check but lets
1779 : // double check dyn traits type-layout first
1780 43 : if (ref->is_dyn_str_type ())
1781 : {
1782 9 : infered = resolved_base;
1783 9 : return;
1784 : }
1785 : }
1786 :
1787 2017 : if (expr.is_raw_borrow ())
1788 : {
1789 4 : infered = new TyTy::PointerType (expr.get_mappings ().get_hirid (),
1790 4 : TyTy::TyVar (resolved_base->get_ref ()),
1791 8 : expr.get_mut ());
1792 :
1793 4 : return;
1794 : }
1795 :
1796 2013 : infered = new TyTy::ReferenceType (expr.get_mappings ().get_hirid (),
1797 2013 : TyTy::TyVar (resolved_base->get_ref ()),
1798 4026 : expr.get_mut ());
1799 : }
1800 :
1801 : void
1802 3918 : TypeCheckExpr::visit (HIR::DereferenceExpr &expr)
1803 : {
1804 3918 : TyTy::BaseType *resolved_base = TypeCheckExpr::Resolve (expr.get_expr ());
1805 :
1806 3918 : rust_debug_loc (expr.get_locus (), "attempting deref operator overload");
1807 3918 : auto lang_item_type = LangItem::Kind::DEREF;
1808 3918 : bool operator_overloaded
1809 3918 : = resolve_operator_overload (lang_item_type, expr, resolved_base, nullptr);
1810 3918 : if (operator_overloaded)
1811 : {
1812 : // operator overloaded deref always refurns a reference type lets assert
1813 : // this
1814 49 : rust_assert (infered->get_kind () == TyTy::TypeKind::REF);
1815 49 : resolved_base = infered;
1816 : }
1817 :
1818 3918 : bool is_valid_type = resolved_base->get_kind () == TyTy::TypeKind::REF
1819 3918 : || resolved_base->get_kind () == TyTy::TypeKind::POINTER;
1820 :
1821 3918 : auto try_owned_box = TyTy::try_get_box_inner_type (resolved_base);
1822 :
1823 3918 : if (!is_valid_type && !try_owned_box)
1824 : {
1825 0 : rust_error_at (expr.get_locus (), "expected reference type got %s",
1826 0 : resolved_base->as_string ().c_str ());
1827 0 : return;
1828 : }
1829 :
1830 3918 : if (try_owned_box)
1831 : {
1832 1 : infered = (*try_owned_box)->clone ();
1833 : }
1834 3917 : else if (resolved_base->get_kind () == TyTy::TypeKind::REF)
1835 : {
1836 3720 : TyTy::ReferenceType *ref_base
1837 : = static_cast<TyTy::ReferenceType *> (resolved_base);
1838 3720 : infered = ref_base->get_base ()->clone ();
1839 : }
1840 : else
1841 : {
1842 197 : TyTy::PointerType *ref_base
1843 : = static_cast<TyTy::PointerType *> (resolved_base);
1844 197 : infered = ref_base->get_base ()->clone ();
1845 : }
1846 : }
1847 :
1848 : void
1849 5221 : TypeCheckExpr::visit (HIR::TypeCastExpr &expr)
1850 : {
1851 5221 : TyTy::BaseType *expr_to_convert
1852 5221 : = TypeCheckExpr::Resolve (expr.get_casted_expr ());
1853 5221 : TyTy::BaseType *tyty_to_convert_to
1854 5221 : = TypeCheckType::Resolve (expr.get_type_to_convert_to ());
1855 :
1856 5221 : TyTy::TyWithLocation from (expr_to_convert,
1857 5221 : expr.get_casted_expr ().get_locus ());
1858 5221 : TyTy::TyWithLocation to (tyty_to_convert_to,
1859 5221 : expr.get_type_to_convert_to ().get_locus ());
1860 5221 : infered = cast_site (expr.get_mappings ().get_hirid (), from, to,
1861 : expr.get_locus ());
1862 5221 : }
1863 :
1864 : void
1865 1105 : TypeCheckExpr::visit (HIR::MatchExpr &expr)
1866 : {
1867 : // this needs to perform a least upper bound coercion on the blocks and then
1868 : // unify the scruintee and arms
1869 1105 : TyTy::BaseType *scrutinee_tyty
1870 1105 : = TypeCheckExpr::Resolve (expr.get_scrutinee_expr ());
1871 :
1872 : // https://github.com/Rust-GCC/gccrs/issues/3231#issuecomment-2462660048
1873 : // https://github.com/rust-lang/rust/blob/3d1dba830a564d1118361345d7ada47a05241f45/compiler/rustc_hir_typeck/src/_match.rs#L32-L36
1874 1105 : if (!expr.has_match_arms ())
1875 : {
1876 : // this is a special case where rustc returns !
1877 5 : TyTy::BaseType *lookup = nullptr;
1878 5 : bool ok = context->lookup_builtin ("!", &lookup);
1879 5 : rust_assert (ok);
1880 5 : infered = lookup->clone ();
1881 5 : return;
1882 : }
1883 :
1884 1100 : bool saw_error = false;
1885 1100 : std::vector<TyTy::BaseType *> kase_block_tys;
1886 3655 : for (auto &kase : expr.get_match_cases ())
1887 : {
1888 : // lets check the arms
1889 2555 : HIR::MatchArm &kase_arm = kase.get_arm ();
1890 2555 : auto &pattern = kase_arm.get_pattern ();
1891 2555 : TyTy::BaseType *kase_arm_ty
1892 2555 : = TypeCheckPattern::Resolve (*pattern, scrutinee_tyty);
1893 2555 : if (kase_arm_ty->get_kind () == TyTy ::TypeKind::ERROR)
1894 : {
1895 12 : saw_error = true;
1896 12 : continue;
1897 : }
1898 :
1899 5086 : TyTy::BaseType *checked_kase = unify_site (
1900 2543 : expr.get_mappings ().get_hirid (),
1901 : TyTy::TyWithLocation (scrutinee_tyty,
1902 2543 : expr.get_scrutinee_expr ().get_locus ()),
1903 2543 : TyTy::TyWithLocation (kase_arm_ty, pattern->get_locus ()),
1904 : expr.get_locus ());
1905 2543 : if (checked_kase->get_kind () == TyTy::TypeKind::ERROR)
1906 : {
1907 0 : saw_error = true;
1908 0 : continue;
1909 : }
1910 :
1911 : // check the kase type
1912 2543 : TyTy::BaseType *kase_block_ty = TypeCheckExpr::Resolve (kase.get_expr ());
1913 2543 : kase_block_tys.push_back (kase_block_ty);
1914 : }
1915 1100 : if (saw_error)
1916 : return;
1917 :
1918 1094 : if (kase_block_tys.size () == 0)
1919 : {
1920 0 : infered = TyTy::TupleType::get_unit_type ();
1921 0 : return;
1922 : }
1923 :
1924 : // this is a LUB
1925 1094 : infered = kase_block_tys.at (0);
1926 2536 : for (size_t i = 1; i < kase_block_tys.size (); i++)
1927 : {
1928 1442 : TyTy::BaseType *kase_ty = kase_block_tys.at (i);
1929 1442 : infered
1930 1442 : = coercion_site (expr.get_mappings ().get_hirid (),
1931 1442 : TyTy::TyWithLocation (infered),
1932 1442 : TyTy::TyWithLocation (kase_ty), expr.get_locus ());
1933 : }
1934 1100 : }
1935 :
1936 : void
1937 65 : TypeCheckExpr::visit (HIR::ClosureExpr &expr)
1938 : {
1939 65 : std::vector<TyTy::SubstitutionParamMapping> subst_refs;
1940 65 : HirId ref = expr.get_mappings ().get_hirid ();
1941 65 : DefId id = expr.get_mappings ().get_defid ();
1942 65 : RustIdent ident{CanonicalPath::create_empty (), expr.get_locus ()};
1943 :
1944 65 : if (context->have_function_context ())
1945 : {
1946 64 : TypeCheckContextItem current_context = context->peek_context ();
1947 64 : TyTy::FnType *current_context_fndecl
1948 64 : = current_context.get_context_type ();
1949 :
1950 64 : ident = RustIdent{current_context_fndecl->get_ident ().path,
1951 64 : expr.get_locus ()};
1952 :
1953 64 : subst_refs = current_context_fndecl->clone_substs ();
1954 : }
1955 :
1956 65 : std::vector<TyTy::TyVar> parameter_types;
1957 125 : for (auto &p : expr.get_params ())
1958 : {
1959 60 : TyTy::BaseType *param_tyty = nullptr;
1960 60 : if (p.has_type_given ())
1961 : {
1962 58 : param_tyty = TypeCheckType::Resolve (p.get_type ());
1963 : }
1964 : else
1965 : {
1966 2 : param_tyty = ClosureParamInfer::Resolve (p.get_pattern ());
1967 : }
1968 :
1969 60 : TyTy::TyVar param_ty (param_tyty->get_ref ());
1970 60 : parameter_types.push_back (param_ty);
1971 :
1972 60 : TypeCheckPattern::Resolve (p.get_pattern (), param_ty.get_tyty ());
1973 : }
1974 :
1975 : // we generate an implicit hirid for the closure args
1976 65 : HirId implicit_args_id = mappings.get_next_hir_id ();
1977 65 : TyTy::TupleType *closure_args
1978 : = new TyTy::TupleType (implicit_args_id, expr.get_locus (),
1979 65 : parameter_types);
1980 65 : context->insert_implicit_type (closure_args->get_ref (), closure_args);
1981 :
1982 65 : location_t result_type_locus = expr.has_return_type ()
1983 65 : ? expr.get_return_type ().get_locus ()
1984 65 : : expr.get_locus ();
1985 65 : TyTy::TyVar result_type
1986 65 : = expr.has_return_type ()
1987 65 : ? TyTy::TyVar (
1988 : TypeCheckType::Resolve (expr.get_return_type ())->get_ref ())
1989 65 : : TyTy::TyVar::get_implicit_infer_var (expr.get_locus ());
1990 :
1991 : // resolve the block
1992 65 : location_t closure_expr_locus = expr.get_expr ().get_locus ();
1993 65 : TyTy::BaseType *closure_expr_ty = TypeCheckExpr::Resolve (expr.get_expr ());
1994 130 : coercion_site (expr.get_mappings ().get_hirid (),
1995 : TyTy::TyWithLocation (result_type.get_tyty (),
1996 65 : result_type_locus),
1997 65 : TyTy::TyWithLocation (closure_expr_ty, closure_expr_locus),
1998 : expr.get_locus ());
1999 :
2000 : // generate the closure type
2001 65 : NodeId closure_node_id = expr.get_mappings ().get_nodeid ();
2002 :
2003 : // Resolve closure captures
2004 :
2005 65 : std::set<NodeId> captures;
2006 :
2007 65 : if (auto opt_cap
2008 65 : = Analysis::Mappings::get ().lookup_captures (closure_node_id))
2009 42 : for (auto cap : opt_cap.value ())
2010 21 : captures.insert (cap);
2011 :
2012 65 : infered = new TyTy::ClosureType (ref, id, ident, closure_args, result_type,
2013 130 : subst_refs, captures);
2014 :
2015 : // FIXME
2016 : // all closures automatically inherit the appropriate fn trait. Lets just
2017 : // assume FnOnce for now. I think this is based on the return type of the
2018 : // closure
2019 :
2020 65 : LangItem::Kind lang_item_type = LangItem::Kind::FN_ONCE;
2021 :
2022 65 : auto lang_item_defined = mappings.lookup_lang_item (lang_item_type);
2023 65 : if (!lang_item_defined)
2024 : {
2025 : // FIXME
2026 : // we need to have a unified way or error'ing when we are missing lang
2027 : // items that is useful
2028 0 : rust_fatal_error (expr.get_locus (), "unable to find lang item: %qs",
2029 0 : LangItem::ToString (lang_item_type).c_str ());
2030 : }
2031 65 : DefId &respective_lang_item_id = lang_item_defined.value ();
2032 :
2033 : // these lang items are always traits
2034 65 : HIR::Item *item = mappings.lookup_defid (respective_lang_item_id).value ();
2035 65 : rust_assert (item->get_item_kind () == HIR::Item::ItemKind::Trait);
2036 65 : HIR::Trait *trait_item = static_cast<HIR::Trait *> (item);
2037 :
2038 65 : TraitReference *trait = TraitResolver::Resolve (*trait_item);
2039 65 : rust_assert (!trait->is_error ());
2040 :
2041 65 : TyTy::TypeBoundPredicate predicate (*trait, BoundPolarity::RegularBound,
2042 65 : expr.get_locus ());
2043 :
2044 : // resolve the trait bound where the <(Args)> are the parameter tuple type
2045 65 : HIR::GenericArgs args = HIR::GenericArgs::create_empty (expr.get_locus ());
2046 :
2047 : // lets generate an implicit Type so that it resolves to the implict tuple
2048 : // type we have created
2049 65 : auto crate_num = mappings.get_current_crate ();
2050 65 : Analysis::NodeMapping mapping (crate_num, expr.get_mappings ().get_nodeid (),
2051 65 : implicit_args_id, UNKNOWN_LOCAL_DEFID);
2052 65 : HIR::TupleType *implicit_tuple
2053 : = new HIR::TupleType (mapping,
2054 : {} // we dont need to fill this out because it will
2055 : // auto resolve because the hir id's match
2056 : ,
2057 65 : expr.get_locus ());
2058 65 : args.get_type_args ().emplace_back (implicit_tuple);
2059 :
2060 : // apply the arguments
2061 65 : predicate.apply_generic_arguments (&args, false, false);
2062 :
2063 : // finally inherit the trait bound
2064 130 : infered->inherit_bounds ({predicate});
2065 65 : }
2066 :
2067 : bool
2068 12277 : TypeCheckExpr::resolve_operator_overload (
2069 : LangItem::Kind lang_item_type, HIR::OperatorExprMeta expr,
2070 : TyTy::BaseType *lhs, TyTy::BaseType *rhs,
2071 : HIR::PathIdentSegment specified_segment)
2072 : {
2073 : // look up lang item for arithmetic type
2074 12277 : std::string associated_item_name = LangItem::ToString (lang_item_type);
2075 :
2076 12277 : auto lang_item_defined = mappings.lookup_lang_item (lang_item_type);
2077 : // probe for the lang-item
2078 12277 : if (!lang_item_defined)
2079 : return false;
2080 :
2081 2716 : DefId &respective_lang_item_id = lang_item_defined.value ();
2082 2716 : auto def_lookup = mappings.lookup_defid (respective_lang_item_id);
2083 2716 : rust_assert (def_lookup.has_value ());
2084 :
2085 2716 : HIR::Item *def_item = def_lookup.value ();
2086 2716 : rust_assert (def_item->get_item_kind () == HIR::Item::ItemKind::Trait);
2087 2716 : HIR::Trait &trait = *static_cast<HIR::Trait *> (def_item);
2088 2716 : TraitReference *defid_trait_reference = TraitResolver::Resolve (trait);
2089 2716 : rust_assert (!defid_trait_reference->is_error ());
2090 :
2091 : // we might be in a static or const context and unknown is fine
2092 2716 : TypeCheckContextItem current_context = TypeCheckContextItem::get_error ();
2093 2716 : if (context->have_function_context ())
2094 : {
2095 2708 : current_context = context->peek_context ();
2096 : }
2097 :
2098 2716 : auto segment = specified_segment.is_error ()
2099 3730 : ? HIR::PathIdentSegment (associated_item_name)
2100 2716 : : specified_segment;
2101 2716 : auto candidates = MethodResolver::Probe (lhs, segment);
2102 :
2103 : // remove any recursive candidates
2104 2716 : std::set<MethodCandidate> resolved_candidates;
2105 5448 : for (auto &c : candidates)
2106 : {
2107 2732 : const TyTy::BaseType *candidate_type = c.candidate.ty;
2108 2732 : rust_assert (candidate_type->get_kind () == TyTy::TypeKind::FNDEF);
2109 :
2110 2732 : const TyTy::FnType &fn
2111 : = *static_cast<const TyTy::FnType *> (candidate_type);
2112 :
2113 2732 : DefId current_fn_defid = current_context.get_defid ();
2114 5464 : bool recursive_candidated = fn.get_id () == current_fn_defid;
2115 1537 : if (!recursive_candidated)
2116 : {
2117 1537 : resolved_candidates.insert (c);
2118 : }
2119 : }
2120 :
2121 2716 : std::vector<TyTy::BaseType *> select_args = {};
2122 2716 : if (rhs != nullptr)
2123 2490 : select_args = {rhs};
2124 2716 : auto selected_candidates
2125 2716 : = MethodResolver::Select (resolved_candidates, lhs, select_args);
2126 :
2127 2716 : bool have_implementation_for_lang_item = selected_candidates.size () > 0;
2128 2716 : if (!have_implementation_for_lang_item)
2129 : return false;
2130 :
2131 1422 : if (selected_candidates.size () > 1)
2132 : {
2133 8 : auto infer
2134 8 : = TyTy::TyVar::get_implicit_infer_var (expr.get_locus ()).get_tyty ();
2135 8 : auto trait_subst = defid_trait_reference->get_trait_substs ();
2136 8 : rust_assert (trait_subst.size () > 0);
2137 :
2138 8 : TyTy::TypeBoundPredicate pred (respective_lang_item_id, trait_subst,
2139 : BoundPolarity::RegularBound,
2140 8 : expr.get_locus ());
2141 :
2142 8 : std::vector<TyTy::SubstitutionArg> mappings;
2143 8 : auto &self_param_mapping = trait_subst[0];
2144 8 : mappings.emplace_back (&self_param_mapping, lhs);
2145 :
2146 8 : if (rhs != nullptr)
2147 : {
2148 8 : rust_assert (trait_subst.size () == 2);
2149 8 : auto &rhs_param_mapping = trait_subst[1];
2150 8 : mappings.emplace_back (&rhs_param_mapping, lhs);
2151 : }
2152 :
2153 8 : std::map<std::string, TyTy::BaseType *> binding_args;
2154 8 : binding_args["Output"] = infer;
2155 :
2156 8 : TyTy::SubstitutionArgumentMappings arg_mappings (mappings, binding_args,
2157 8 : TyTy::RegionParamList (
2158 8 : trait_subst.size ()),
2159 16 : expr.get_locus ());
2160 8 : pred.apply_argument_mappings (arg_mappings, false);
2161 :
2162 16 : infer->inherit_bounds ({pred});
2163 16 : DeferredOpOverload defer (expr.get_mappings ().get_hirid (),
2164 16 : lang_item_type, specified_segment, pred, expr);
2165 8 : context->insert_deferred_operator_overload (std::move (defer));
2166 :
2167 8 : if (rhs != nullptr)
2168 16 : lhs = unify_site (expr.get_mappings ().get_hirid (),
2169 8 : TyTy::TyWithLocation (lhs),
2170 8 : TyTy::TyWithLocation (rhs), expr.get_locus ());
2171 :
2172 16 : infered = unify_site (expr.get_mappings ().get_hirid (),
2173 8 : TyTy::TyWithLocation (lhs),
2174 8 : TyTy::TyWithLocation (infer), expr.get_locus ());
2175 8 : return true;
2176 8 : }
2177 :
2178 : // Get the adjusted self
2179 1414 : MethodCandidate candidate = *selected_candidates.begin ();
2180 1414 : Adjuster adj (lhs);
2181 1414 : TyTy::BaseType *adjusted_self = adj.adjust_type (candidate.adjustments);
2182 :
2183 : // store the adjustments for code-generation to know what to do
2184 1414 : context->insert_autoderef_mappings (expr.get_lvalue_mappings ().get_hirid (),
2185 : std::move (candidate.adjustments));
2186 :
2187 1414 : PathProbeCandidate &resolved_candidate = candidate.candidate;
2188 1414 : TyTy::BaseType *lookup_tyty = candidate.candidate.ty;
2189 1414 : NodeId resolved_node_id
2190 1414 : = resolved_candidate.is_impl_candidate ()
2191 1414 : ? resolved_candidate.item.impl.impl_item->get_impl_mappings ()
2192 1012 : .get_nodeid ()
2193 402 : : resolved_candidate.item.trait.item_ref->get_mappings ().get_nodeid ();
2194 :
2195 1414 : rust_assert (lookup_tyty->get_kind () == TyTy::TypeKind::FNDEF);
2196 1414 : TyTy::BaseType *lookup = lookup_tyty;
2197 1414 : TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup);
2198 2828 : rust_assert (fn->is_method ());
2199 :
2200 1816 : rust_debug ("is_impl_item_candidate: %s",
2201 : resolved_candidate.is_impl_candidate () ? "true" : "false");
2202 :
2203 : // in the case where we resolve to a trait bound we have to be careful we are
2204 : // able to do so there is a case where we are currently resolving the deref
2205 : // operator overload function which is generic and this might resolve to the
2206 : // trait item of deref which is not valid as its just another recursive case
2207 1414 : if (current_context.get_type () == TypeCheckContextItem::ItemType::IMPL_ITEM)
2208 : {
2209 771 : auto &impl_item = current_context.get_impl_item ();
2210 771 : HIR::ImplBlock *parent = impl_item.first;
2211 771 : HIR::Function *fn = impl_item.second;
2212 :
2213 771 : bool is_deref = lang_item_type == LangItem::Kind::DEREF
2214 771 : || lang_item_type == LangItem::Kind::DEREF_MUT;
2215 3084 : bool is_deref_match = fn->get_function_name ().as_string ().compare (
2216 1542 : LangItem::ToString (LangItem::Kind::DEREF))
2217 : == 0
2218 2167 : || fn->get_function_name ().as_string ().compare (
2219 1396 : LangItem::ToString (LangItem::Kind::DEREF_MUT))
2220 : == 0;
2221 :
2222 771 : bool is_recursive_op
2223 1542 : = fn->get_function_name ().as_string ().compare (associated_item_name)
2224 : == 0
2225 771 : || (is_deref && is_deref_match);
2226 771 : if (parent->has_trait_ref () && is_recursive_op)
2227 : {
2228 335 : TraitReference *trait_reference
2229 335 : = TraitResolver::Lookup (parent->get_trait_ref ());
2230 335 : if (!trait_reference->is_error ())
2231 : {
2232 335 : TyTy::BaseType *lookup = nullptr;
2233 335 : bool ok = context->lookup_type (fn->get_mappings ().get_hirid (),
2234 : &lookup);
2235 335 : rust_assert (ok);
2236 335 : rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF);
2237 :
2238 335 : TyTy::FnType *fntype = static_cast<TyTy::FnType *> (lookup);
2239 670 : rust_assert (fntype->is_method ());
2240 :
2241 335 : bool is_lang_item_impl
2242 335 : = trait_reference->get_mappings ().get_defid ()
2243 337 : == respective_lang_item_id
2244 2 : || (is_deref && is_deref_match);
2245 335 : bool self_is_lang_item_self
2246 335 : = fntype->get_self_type ()->is_equal (*adjusted_self);
2247 335 : bool recursive_operator_overload
2248 : = is_lang_item_impl && self_is_lang_item_self;
2249 :
2250 335 : if (recursive_operator_overload)
2251 150 : return false;
2252 : }
2253 : }
2254 : }
2255 :
2256 : // we found a valid operator overload
2257 1264 : rust_debug_loc (expr.get_locus (), "resolved operator overload to: {%u} {%s}",
2258 1264 : candidate.candidate.ty->get_ref (),
2259 1264 : candidate.candidate.ty->debug_str ().c_str ());
2260 :
2261 : // handle generics
2262 1264 : if (lookup->needs_generic_substitutions ())
2263 381 : lookup = SubstMapper::InferSubst (lookup, expr.get_locus ());
2264 :
2265 : // type check the arguments if required
2266 1264 : TyTy::FnType *type = static_cast<TyTy::FnType *> (lookup);
2267 1264 : rust_assert (type->num_params () > 0);
2268 1264 : auto &fnparam = type->param_at (0);
2269 :
2270 : // typecheck the self
2271 2528 : unify_site (expr.get_mappings ().get_hirid (),
2272 1264 : TyTy::TyWithLocation (fnparam.get_type ()),
2273 1264 : TyTy::TyWithLocation (adjusted_self), expr.get_locus ());
2274 1264 : if (rhs == nullptr)
2275 : {
2276 63 : rust_assert (type->num_params () == 1);
2277 : }
2278 : else
2279 : {
2280 1201 : rust_assert (type->num_params () == 2);
2281 1201 : auto &fnparam = type->param_at (1);
2282 2402 : unify_site (expr.get_mappings ().get_hirid (),
2283 1201 : TyTy::TyWithLocation (fnparam.get_type ()),
2284 1201 : TyTy::TyWithLocation (rhs), expr.get_locus ());
2285 : }
2286 :
2287 1264 : rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF);
2288 1264 : fn = static_cast<TyTy::FnType *> (lookup);
2289 1264 : fn->monomorphize ();
2290 :
2291 : // get the return type
2292 1264 : TyTy::BaseType *function_ret_tyty
2293 1264 : = type->get_return_type ()->monomorphized_clone ();
2294 :
2295 : // store the expected fntype
2296 1264 : context->insert_operator_overload (expr.get_mappings ().get_hirid (), type);
2297 :
2298 : // set up the resolved name on the path
2299 1264 : auto &nr_ctx = Resolver2_0::FinalizedNameResolutionContext::get ();
2300 :
2301 1264 : nr_ctx.map_usage (Resolver2_0::Usage (expr.get_mappings ().get_nodeid ()),
2302 1264 : Resolver2_0::Definition (resolved_node_id),
2303 : Resolver2_0::Namespace::Types);
2304 :
2305 : // return the result of the function back
2306 1264 : infered = function_ret_tyty;
2307 :
2308 1264 : return true;
2309 4130 : }
2310 :
2311 : HIR::PathIdentSegment
2312 10754 : TypeCheckExpr::resolve_possible_fn_trait_call_method_name (
2313 : const TyTy::BaseType &receiver,
2314 : TyTy::TypeBoundPredicate *associated_predicate)
2315 : {
2316 : // FIXME
2317 : // the logic to map the FnTrait to their respective call trait-item is
2318 : // duplicated over in the backend/rust-compile-expr.cc
2319 10781 : for (const auto &bound : receiver.get_specified_bounds ())
2320 : {
2321 93 : bool found_fn = bound.get_name ().compare ("Fn") == 0;
2322 93 : bool found_fn_mut = bound.get_name ().compare ("FnMut") == 0;
2323 93 : bool found_fn_once = bound.get_name ().compare ("FnOnce") == 0;
2324 :
2325 93 : if (found_fn)
2326 : {
2327 0 : *associated_predicate = bound;
2328 0 : return HIR::PathIdentSegment ("call");
2329 : }
2330 93 : else if (found_fn_mut)
2331 : {
2332 0 : *associated_predicate = bound;
2333 0 : return HIR::PathIdentSegment ("call_mut");
2334 : }
2335 93 : else if (found_fn_once)
2336 : {
2337 66 : *associated_predicate = bound;
2338 66 : return HIR::PathIdentSegment ("call_once");
2339 : }
2340 : }
2341 :
2342 10688 : if (receiver.is<TyTy::ReferenceType> ())
2343 : {
2344 0 : const auto &ref = static_cast<const TyTy::ReferenceType &> (receiver);
2345 0 : const auto &underlying = *ref.get_base ();
2346 0 : for (const auto &bound : underlying.get_specified_bounds ())
2347 : {
2348 0 : bool found_fn = bound.get_name ().compare ("Fn") == 0;
2349 0 : bool found_fn_mut = bound.get_name ().compare ("FnMut") == 0;
2350 0 : bool found_fn_once = bound.get_name ().compare ("FnOnce") == 0;
2351 :
2352 0 : if (found_fn)
2353 : {
2354 0 : *associated_predicate = bound;
2355 0 : return HIR::PathIdentSegment ("call");
2356 : }
2357 0 : else if (found_fn_mut)
2358 : {
2359 0 : *associated_predicate = bound;
2360 0 : return HIR::PathIdentSegment ("call_mut");
2361 : }
2362 0 : else if (found_fn_once)
2363 : {
2364 0 : *associated_predicate = bound;
2365 0 : return HIR::PathIdentSegment ("call_once");
2366 : }
2367 : }
2368 : }
2369 :
2370 : // nothing
2371 10688 : *associated_predicate = TyTy::TypeBoundPredicate::error ();
2372 10688 : return HIR::PathIdentSegment ("");
2373 : }
2374 :
2375 : bool
2376 10754 : TypeCheckExpr::resolve_fn_trait_call (HIR::CallExpr &expr,
2377 : TyTy::BaseType *receiver_tyty,
2378 : TyTy::BaseType **result)
2379 : {
2380 : // we turn this into a method call expr
2381 : // TODO: add implicit self argument (?)
2382 10754 : auto associated_predicate = TyTy::TypeBoundPredicate::error ();
2383 10754 : HIR::PathIdentSegment method_name
2384 : = resolve_possible_fn_trait_call_method_name (*receiver_tyty,
2385 10754 : &associated_predicate);
2386 10754 : if (method_name.is_error () || associated_predicate.is_error ())
2387 10688 : return false;
2388 :
2389 66 : auto candidates = MethodResolver::Probe (receiver_tyty, method_name);
2390 66 : if (candidates.empty ())
2391 : return false;
2392 :
2393 66 : if (candidates.size () > 1)
2394 : {
2395 0 : rich_location r (line_table, expr.get_locus ());
2396 0 : for (auto &c : candidates)
2397 0 : r.add_range (c.candidate.locus);
2398 :
2399 0 : rust_error_at (
2400 : r, "multiple candidates found for function trait method call %qs",
2401 0 : method_name.to_string ().c_str ());
2402 0 : return false;
2403 0 : }
2404 :
2405 : // FnOnce::Output is normalized lazily by normalize_projection's closure
2406 : // special-case; no explicit setup is required here.
2407 :
2408 66 : auto candidate = *candidates.begin ();
2409 66 : rust_debug_loc (expr.get_locus (),
2410 : "resolved call-expr to fn trait: {%u} {%s}",
2411 66 : candidate.candidate.ty->get_ref (),
2412 66 : candidate.candidate.ty->debug_str ().c_str ());
2413 :
2414 : // Get the adjusted self
2415 66 : Adjuster adj (receiver_tyty);
2416 66 : TyTy::BaseType *adjusted_self = adj.adjust_type (candidate.adjustments);
2417 :
2418 : // store the adjustments for code-generation to know what to do which must be
2419 : // stored onto the receiver to so as we don't trigger duplicate deref mappings
2420 : // ICE when an argument is a method call
2421 66 : HIR::Expr &fnexpr = expr.get_fnexpr ();
2422 66 : HirId autoderef_mappings_id = fnexpr.get_mappings ().get_hirid ();
2423 66 : context->insert_autoderef_mappings (autoderef_mappings_id,
2424 : std::move (candidate.adjustments));
2425 :
2426 66 : PathProbeCandidate &resolved_candidate = candidate.candidate;
2427 66 : TyTy::BaseType *lookup_tyty = candidate.candidate.ty;
2428 66 : NodeId resolved_node_id
2429 66 : = resolved_candidate.is_impl_candidate ()
2430 66 : ? resolved_candidate.item.impl.impl_item->get_impl_mappings ()
2431 0 : .get_nodeid ()
2432 66 : : resolved_candidate.item.trait.item_ref->get_mappings ().get_nodeid ();
2433 :
2434 66 : if (lookup_tyty->get_kind () != TyTy::TypeKind::FNDEF)
2435 : {
2436 0 : rich_location r (line_table, expr.get_locus ());
2437 0 : r.add_range (resolved_candidate.locus);
2438 0 : rust_error_at (r, "associated impl item is not a method");
2439 0 : return false;
2440 0 : }
2441 :
2442 66 : TyTy::BaseType *lookup = lookup_tyty;
2443 66 : TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup);
2444 132 : if (!fn->is_method ())
2445 : {
2446 0 : rich_location r (line_table, expr.get_locus ());
2447 0 : r.add_range (resolved_candidate.locus);
2448 0 : rust_error_at (r, "associated function is not a method");
2449 0 : return false;
2450 0 : }
2451 :
2452 : // fn traits only support tuple argument passing so we need to implicitly set
2453 : // this up to get the same type checking we get in the rest of the pipeline
2454 :
2455 66 : std::vector<TyTy::TyVar> call_args;
2456 132 : for (auto &arg : expr.get_arguments ())
2457 : {
2458 66 : TyTy::BaseType *a = TypeCheckExpr::Resolve (*arg);
2459 66 : call_args.emplace_back (a->get_ref ());
2460 : }
2461 :
2462 : // crate implicit tuple
2463 66 : HirId implicit_arg_id = mappings.get_next_hir_id ();
2464 66 : Analysis::NodeMapping mapping (mappings.get_current_crate (), UNKNOWN_NODEID,
2465 66 : implicit_arg_id, UNKNOWN_LOCAL_DEFID);
2466 :
2467 66 : TyTy::TupleType *tuple
2468 66 : = new TyTy::TupleType (implicit_arg_id, expr.get_locus (), call_args);
2469 66 : context->insert_implicit_type (implicit_arg_id, tuple);
2470 :
2471 66 : std::vector<TyTy::Argument> args;
2472 66 : args.emplace_back (mapping, tuple,
2473 66 : expr.get_locus () /*FIXME is there a better location*/);
2474 :
2475 66 : TyTy::BaseType *function_ret_tyty
2476 66 : = TyTy::TypeCheckMethodCallExpr::go (fn, expr.get_mappings (), args,
2477 : expr.get_locus (), expr.get_locus (),
2478 : adjusted_self, context);
2479 66 : if (function_ret_tyty == nullptr
2480 66 : || function_ret_tyty->get_kind () == TyTy::TypeKind::ERROR)
2481 : {
2482 0 : rust_error_at (expr.get_locus (),
2483 : "failed check fn trait call-expr MethodCallExpr");
2484 0 : return false;
2485 : }
2486 :
2487 : // store the expected fntype
2488 66 : context->insert_operator_overload (expr.get_mappings ().get_hirid (), fn);
2489 :
2490 : // set up the resolved name on the path
2491 66 : auto &nr_ctx = Resolver2_0::FinalizedNameResolutionContext::get ();
2492 :
2493 : // TODO: What namespace to use for inserting and looking up here? It's a trait
2494 : // call, so NS::Types is right?
2495 :
2496 66 : auto existing = nr_ctx.lookup (expr.get_mappings ().get_nodeid (),
2497 : Resolver2_0::Namespace::Types);
2498 66 : if (existing)
2499 9 : rust_assert (*existing == resolved_node_id);
2500 : else
2501 57 : nr_ctx.map_usage (Resolver2_0::Usage (expr.get_mappings ().get_nodeid ()),
2502 57 : Resolver2_0::Definition (resolved_node_id),
2503 : Resolver2_0::Namespace::Types);
2504 :
2505 : // return the result of the function back
2506 66 : auto mono = function_ret_tyty->monomorphized_clone ();
2507 66 : *result = mono;
2508 :
2509 66 : return true;
2510 10952 : }
2511 :
2512 : bool
2513 7760 : TypeCheckExpr::validate_arithmetic_type (
2514 : const TyTy::BaseType *tyty, HIR::ArithmeticOrLogicalExpr::ExprType expr_type)
2515 : {
2516 7760 : auto type = tyty->destructure ();
2517 7760 : if (type->get_kind () == TyTy::TypeKind::CONST)
2518 : {
2519 15 : auto base_const = type->as_const_type ();
2520 15 : type = base_const->get_specified_type ();
2521 : }
2522 :
2523 : // https://doc.rust-lang.org/reference/expressions/operator-expr.html#arithmetic-and-logical-binary-operators
2524 : // this will change later when traits are added
2525 7760 : switch (expr_type)
2526 : {
2527 6580 : case ArithmeticOrLogicalOperator::ADD:
2528 6580 : case ArithmeticOrLogicalOperator::SUBTRACT:
2529 6580 : case ArithmeticOrLogicalOperator::MULTIPLY:
2530 6580 : case ArithmeticOrLogicalOperator::DIVIDE:
2531 6580 : case ArithmeticOrLogicalOperator::MODULUS:
2532 6580 : return (type->get_kind () == TyTy::TypeKind::INT)
2533 5025 : || (type->get_kind () == TyTy::TypeKind::UINT)
2534 4179 : || (type->get_kind () == TyTy::TypeKind::FLOAT)
2535 3795 : || (type->get_kind () == TyTy::TypeKind::USIZE)
2536 3177 : || (type->get_kind () == TyTy::TypeKind::ISIZE)
2537 3109 : || (type->get_kind () == TyTy::TypeKind::INFER
2538 3106 : && (((const TyTy::InferType *) type)->get_infer_kind ()
2539 : == TyTy::InferType::INTEGRAL))
2540 6620 : || (type->get_kind () == TyTy::TypeKind::INFER
2541 37 : && (((const TyTy::InferType *) type)->get_infer_kind ()
2542 : == TyTy::InferType::FLOAT));
2543 :
2544 : // integers or bools
2545 1014 : case ArithmeticOrLogicalOperator::BITWISE_AND:
2546 1014 : case ArithmeticOrLogicalOperator::BITWISE_OR:
2547 1014 : case ArithmeticOrLogicalOperator::BITWISE_XOR:
2548 1014 : return (type->get_kind () == TyTy::TypeKind::INT)
2549 965 : || (type->get_kind () == TyTy::TypeKind::UINT)
2550 171 : || (type->get_kind () == TyTy::TypeKind::USIZE)
2551 164 : || (type->get_kind () == TyTy::TypeKind::ISIZE)
2552 164 : || (type->get_kind () == TyTy::TypeKind::BOOL)
2553 1136 : || (type->get_kind () == TyTy::TypeKind::INFER
2554 122 : && (((const TyTy::InferType *) type)->get_infer_kind ()
2555 : == TyTy::InferType::INTEGRAL));
2556 :
2557 : // integers only
2558 166 : case ArithmeticOrLogicalOperator::LEFT_SHIFT:
2559 166 : case ArithmeticOrLogicalOperator::RIGHT_SHIFT:
2560 166 : return (type->get_kind () == TyTy::TypeKind::INT)
2561 151 : || (type->get_kind () == TyTy::TypeKind::UINT)
2562 93 : || (type->get_kind () == TyTy::TypeKind::USIZE)
2563 91 : || (type->get_kind () == TyTy::TypeKind::ISIZE)
2564 257 : || (type->get_kind () == TyTy::TypeKind::INFER
2565 91 : && (((const TyTy::InferType *) type)->get_infer_kind ()
2566 : == TyTy::InferType::INTEGRAL));
2567 : }
2568 :
2569 0 : rust_unreachable ();
2570 : return false;
2571 : }
2572 :
2573 : } // namespace Resolver
2574 : } // namespace Rust
|