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