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