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 "rust-system.h"
20 : #include "rust-type-util.h"
21 : #include "rust-diagnostics.h"
22 : #include "rust-hir-map.h"
23 : #include "rust-hir-type-check-implitem.h"
24 : #include "rust-hir-type-check-item.h"
25 : #include "rust-hir-type-check.h"
26 : #include "rust-casts.h"
27 : #include "rust-mapping-common.h"
28 : #include "rust-rib.h"
29 : #include "rust-unify.h"
30 : #include "rust-coercion.h"
31 : #include "rust-hir-type-bounds.h"
32 : #include "rust-hir-trait-resolve.h"
33 : #include "rust-substitution-mapper.h"
34 : #include "rust-finalized-name-resolution-context.h"
35 :
36 : namespace Rust {
37 : namespace Resolver {
38 :
39 : const size_t kNormalizeProjectionLimit = 10;
40 :
41 : bool
42 2431197 : query_type (HirId reference, TyTy::BaseType **result)
43 : {
44 2431197 : auto &mappings = Analysis::Mappings::get ();
45 2431197 : TypeCheckContext *context = TypeCheckContext::get ();
46 :
47 2431197 : if (context->lookup_type (reference, result))
48 : return true;
49 :
50 13987 : if (context->query_in_progress (reference))
51 : return false;
52 :
53 10960 : context->insert_query (reference);
54 :
55 10960 : std::pair<HIR::Enum *, HIR::EnumItem *> enum_candidiate
56 10960 : = mappings.lookup_hir_enumitem (reference);
57 21920 : bool enum_candidiate_ok
58 10960 : = enum_candidiate.first != nullptr && enum_candidiate.second != nullptr;
59 10960 : if (enum_candidiate_ok)
60 : {
61 4273 : HIR::Enum *parent = enum_candidiate.first;
62 4273 : HIR::EnumItem *enum_item = enum_candidiate.second;
63 4273 : rust_debug_loc (enum_item->get_locus (), "resolved item {%u} to",
64 : reference);
65 :
66 4273 : *result = TypeCheckItem::Resolve (*parent);
67 :
68 4273 : context->query_completed (reference);
69 4273 : return true;
70 : }
71 :
72 6687 : if (auto item = mappings.lookup_hir_item (reference))
73 : {
74 1007 : rust_debug_loc (item.value ()->get_locus (), "resolved item {%u} to",
75 : reference);
76 1007 : *result = TypeCheckItem::Resolve (*item.value ());
77 1007 : context->query_completed (reference);
78 1007 : return true;
79 : }
80 :
81 5680 : if (auto impl_item = mappings.lookup_hir_implitem (reference))
82 : {
83 2991 : auto impl_block
84 2991 : = mappings.lookup_hir_impl_block (impl_item->second).value ();
85 :
86 2991 : tl::optional<ImplTraitFrameGuard> guard;
87 2991 : if (impl_block->has_trait_ref ())
88 : {
89 2479 : bool failure_flag = false;
90 2479 : auto substitutions
91 : = TypeCheckItem::ResolveImplBlockSubstitutions (*impl_block,
92 2479 : failure_flag);
93 2479 : if (failure_flag)
94 : {
95 0 : context->query_completed (reference);
96 0 : return false;
97 : }
98 :
99 2479 : TyTy::BaseType *self = nullptr;
100 2479 : bool ok
101 2479 : = query_type (impl_block->get_type ().get_mappings ().get_hirid (),
102 : &self);
103 2479 : if (!ok)
104 : {
105 0 : context->query_completed (reference);
106 0 : return false;
107 : }
108 :
109 2479 : HIR::TypePath &ref = impl_block->get_trait_ref ();
110 2479 : auto trait_reference = TraitResolver::Resolve (ref);
111 2479 : if (trait_reference->is_error ())
112 : {
113 0 : context->query_completed (reference);
114 0 : return false;
115 : }
116 :
117 2479 : auto specified_bound = TypeCheckBase::ResolvePredicateFromBound (
118 2479 : ref, impl_block->get_type (), impl_block->get_polarity ());
119 :
120 2479 : std::map<DefId, AssocTypeEntry> assoc_types_by_trait_item;
121 2479 : std::vector<const TraitItemReference *> trait_item_refs;
122 2479 : TypeCheckItem::ResolveImplTraitAssociatedTypes (
123 : context, *impl_block, specified_bound, self, substitutions,
124 : assoc_types_by_trait_item, trait_item_refs);
125 :
126 2479 : ImplTraitContextFrame frame{trait_reference, self,
127 2479 : std::move (assoc_types_by_trait_item)};
128 2479 : guard.emplace (frame);
129 2479 : }
130 :
131 : // found an impl item
132 2991 : rust_debug_loc (impl_item->first->get_locus (),
133 : "resolved impl-item {%u} to", reference);
134 :
135 2991 : *result = TypeCheckItem::ResolveImplItem (*impl_block, *impl_item->first);
136 2991 : context->query_completed (reference);
137 2991 : return true;
138 2991 : }
139 :
140 : // is it an impl_type?
141 2689 : if (auto impl_block_by_type = mappings.lookup_impl_block_type (reference))
142 : {
143 : // found an impl item
144 2628 : HIR::ImplBlock *impl = impl_block_by_type.value ();
145 2628 : rust_debug_loc (impl->get_locus (), "resolved impl block type {%u} to",
146 : reference);
147 :
148 : // this could be recursive to the root type
149 2628 : if (impl->has_type ())
150 : {
151 2628 : HIR::Type &ty = impl->get_type ();
152 2628 : NodeId ref_node_id = UNKNOWN_NODEID;
153 2628 : NodeId ast_node_id = ty.get_mappings ().get_nodeid ();
154 :
155 2628 : auto &nr_ctx = Resolver2_0::FinalizedNameResolutionContext::get ();
156 :
157 : // assign the ref_node_id if we've found something
158 2628 : nr_ctx.lookup (ast_node_id, Resolver2_0::Namespace::Types)
159 5179 : .map ([&ref_node_id] (NodeId resolved) { ref_node_id = resolved; });
160 :
161 2628 : if (ref_node_id != UNKNOWN_NODEID)
162 : {
163 2551 : tl::optional<HirId> hid
164 2551 : = mappings.lookup_node_to_hir (ref_node_id);
165 2551 : if (hid.has_value () && context->query_in_progress (hid.value ()))
166 : {
167 2 : context->query_completed (reference);
168 2 : return false;
169 : }
170 : }
171 : }
172 :
173 2626 : *result = TypeCheckItem::ResolveImplBlockSelf (*impl);
174 2626 : context->query_completed (reference);
175 2626 : return true;
176 : }
177 :
178 : // is it an extern item?
179 61 : if (auto extern_item = mappings.lookup_hir_extern_item (reference))
180 : {
181 58 : auto block = mappings.lookup_hir_extern_block (extern_item->second);
182 58 : rust_assert (block.has_value ());
183 :
184 58 : *result
185 58 : = TypeCheckTopLevelExternItem::Resolve (*extern_item.value ().first,
186 58 : *block.value ());
187 58 : context->query_completed (reference);
188 58 : return true;
189 : }
190 :
191 : // more?
192 3 : location_t possible_locus = mappings.lookup_location (reference);
193 3 : rust_debug_loc (possible_locus, "query system failed to resolve: [%u]",
194 : reference);
195 3 : context->query_completed (reference);
196 :
197 3 : return false;
198 : }
199 :
200 : bool
201 2325021 : types_compatable (TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
202 : location_t unify_locus, bool emit_errors, bool check_bounds)
203 : {
204 2325021 : TyTy::BaseType *result
205 2325021 : = unify_site_and (UNKNOWN_HIRID, lhs, rhs, unify_locus, emit_errors,
206 : false /*commit*/, true /*infer*/, true /*cleanup*/,
207 : check_bounds);
208 2325021 : return result->get_kind () != TyTy::TypeKind::ERROR;
209 : }
210 :
211 : TyTy::BaseType *
212 31043 : unify_site (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
213 : location_t unify_locus)
214 : {
215 31043 : TyTy::BaseType *expected = lhs.get_ty ();
216 31043 : TyTy::BaseType *expr = rhs.get_ty ();
217 :
218 31043 : rust_debug ("unify_site id={%u} expected={%s} expr={%s}", id,
219 : expected->debug_str ().c_str (), expr->debug_str ().c_str ());
220 :
221 31043 : std::vector<UnifyRules::CommitSite> commits;
222 31043 : std::vector<UnifyRules::InferenceSite> infers;
223 31043 : return UnifyRules::Resolve (lhs, rhs, unify_locus, true /*commit*/,
224 : true /*emit_error*/, false /*infer*/,
225 31043 : true /*check_bounds*/, commits, infers);
226 31043 : }
227 :
228 : TyTy::BaseType *
229 2454713 : unify_site_and (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
230 : location_t unify_locus, bool emit_errors, bool commit_if_ok,
231 : bool implicit_infer_vars, bool cleanup, bool check_bounds)
232 : {
233 2454713 : TypeCheckContext &context = *TypeCheckContext::get ();
234 :
235 2454713 : TyTy::BaseType *expected = lhs.get_ty ();
236 2454713 : TyTy::BaseType *expr = rhs.get_ty ();
237 :
238 9450163 : rust_debug_loc (unify_locus,
239 : "begin unify_site_and commit %s infer %s check_bounds %s "
240 : "id={%u} expected={%s} expr={%s}",
241 : commit_if_ok ? "true" : "false",
242 : implicit_infer_vars ? "true" : "false",
243 : check_bounds ? "true" : "false", id == UNKNOWN_HIRID ? 0 : id,
244 4909426 : expected->debug_str ().c_str (), expr->debug_str ().c_str ());
245 :
246 2454713 : std::vector<UnifyRules::CommitSite> commits;
247 2454713 : std::vector<UnifyRules::InferenceSite> infers;
248 2454713 : TyTy::BaseType *result
249 2454713 : = UnifyRules::Resolve (lhs, rhs, unify_locus, false /*commit inline*/,
250 : emit_errors, implicit_infer_vars, check_bounds,
251 : commits, infers);
252 2454713 : bool ok = result->get_kind () != TyTy::TypeKind::ERROR;
253 :
254 4420112 : rust_debug_loc (unify_locus,
255 : "unify_site_and done ok=%s commit %s infer %s id={%u} "
256 : "expected={%s} expr={%s}",
257 : ok ? "true" : "false", commit_if_ok ? "true" : "false",
258 : implicit_infer_vars ? "true" : "false",
259 4909426 : id == UNKNOWN_HIRID ? 0 : id, expected->debug_str ().c_str (),
260 2454713 : expr->debug_str ().c_str ());
261 :
262 2454713 : if (ok && commit_if_ok)
263 : {
264 216629 : for (auto &c : commits)
265 : {
266 128065 : UnifyRules::commit (c.lhs, c.rhs, c.resolved);
267 : }
268 : }
269 2366149 : else if (cleanup)
270 : {
271 2492778 : for (auto &i : infers)
272 : {
273 127124 : if (i.param != nullptr)
274 : {
275 127075 : i.param->set_ref (i.pref);
276 127075 : i.param->set_ty_ref (i.ptyref);
277 : }
278 :
279 : // remove the inference variable
280 127124 : context.clear_type (i.infer);
281 : // FIXME: Don't delete - result might point to this
282 : // delete i.infer;
283 : }
284 : }
285 2454713 : return result;
286 2454713 : }
287 :
288 : TyTy::BaseType *
289 40382 : coercion_site (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
290 : location_t locus)
291 : {
292 40382 : TyTy::BaseType *expected = lhs.get_ty ();
293 40382 : TyTy::BaseType *expr = rhs.get_ty ();
294 :
295 40382 : rust_debug ("coercion_site id={%u} expected={%s} expr={%s}", id,
296 : expected->debug_str ().c_str (), expr->debug_str ().c_str ());
297 :
298 40382 : auto context = TypeCheckContext::get ();
299 40382 : if (expected->get_kind () == TyTy::TypeKind::ERROR
300 40382 : || expr->get_kind () == TyTy::TypeKind::ERROR)
301 22 : return expr;
302 :
303 : // can we autoderef it?
304 40360 : auto result = TypeCoercionRules::Coerce (expr, expected, locus,
305 40360 : true /*allow-autodref*/);
306 :
307 : // the result needs to be unified
308 40360 : TyTy::BaseType *receiver = expr;
309 40360 : if (!result.is_error ())
310 : {
311 40309 : receiver = result.tyty;
312 : }
313 :
314 40360 : rust_debug ("coerce_default_unify(a={%s}, b={%s})",
315 : receiver->debug_str ().c_str (), expected->debug_str ().c_str ());
316 40360 : TyTy::BaseType *coerced
317 40360 : = unify_site_and (id, lhs,
318 40360 : TyTy::TyWithLocation (receiver, rhs.get_locus ()), locus,
319 : true /*emit_error*/, true /*commit*/, true /*infer*/,
320 : true /*cleanup*/);
321 40360 : context->insert_autoderef_mappings (id, std::move (result.adjustments));
322 40360 : return coerced;
323 40360 : }
324 :
325 : TyTy::BaseType *
326 1326 : try_coercion (HirId id, TyTy::TyWithLocation lhs, TyTy::TyWithLocation rhs,
327 : location_t locus)
328 : {
329 1326 : TyTy::BaseType *expected = lhs.get_ty ();
330 1326 : TyTy::BaseType *expr = rhs.get_ty ();
331 :
332 1326 : rust_debug ("try_coercion_site id={%u} expected={%s} expr={%s}", id,
333 : expected->debug_str ().c_str (), expr->debug_str ().c_str ());
334 :
335 1326 : auto result = TypeCoercionRules::TryCoerce (expr, expected, locus,
336 1326 : true /*allow-autodref*/);
337 1326 : if (result.is_error ())
338 27 : return new TyTy::ErrorType (id);
339 :
340 1299 : return result.tyty;
341 1326 : }
342 :
343 : TyTy::BaseType *
344 5290 : cast_site (HirId id, TyTy::TyWithLocation from, TyTy::TyWithLocation to,
345 : location_t cast_locus)
346 : {
347 5290 : rust_debug ("cast_site id={%u} from={%s} to={%s}", id,
348 : from.get_ty ()->debug_str ().c_str (),
349 : to.get_ty ()->debug_str ().c_str ());
350 :
351 5290 : auto context = TypeCheckContext::get ();
352 5290 : if (from.get_ty ()->get_kind () == TyTy::TypeKind::ERROR
353 5290 : || to.get_ty ()->get_kind () == TyTy::TypeKind::ERROR)
354 : return to.get_ty ();
355 :
356 : // do the cast
357 5290 : auto result = TypeCastRules::resolve (cast_locus, from, to);
358 :
359 : // we assume error has already been emitted
360 5290 : if (result.is_error ())
361 : return to.get_ty ();
362 :
363 : // the result needs to be unified
364 5274 : TyTy::BaseType *casted_result = result.tyty;
365 5274 : rust_debug ("cast_default_unify(a={%s}, b={%s})",
366 : casted_result->debug_str ().c_str (),
367 : to.get_ty ()->debug_str ().c_str ());
368 :
369 5274 : TyTy::BaseType *casted
370 5274 : = unify_site (id, to,
371 5274 : TyTy::TyWithLocation (casted_result, from.get_locus ()),
372 : cast_locus);
373 5274 : context->insert_cast_autoderef_mappings (id, std::move (result.adjustments));
374 5274 : return casted;
375 5290 : }
376 :
377 : AssociatedImplTrait *
378 9244 : lookup_associated_impl_block (const TyTy::TypeBoundPredicate &bound,
379 : TyTy::BaseType *binding, bool *ambigious)
380 : {
381 9244 : auto context = TypeCheckContext::get ();
382 :
383 : // setup any associated type mappings for the specified bonds and this
384 : // type
385 9244 : auto candidates = TypeBoundsProbe::Probe (binding);
386 9244 : std::vector<AssociatedImplTrait *> associated_impl_traits;
387 46540 : for (auto &probed_bound : candidates)
388 : {
389 37296 : HIR::ImplBlock *associated_impl = probed_bound.second;
390 :
391 37296 : HirId impl_block_id = associated_impl->get_mappings ().get_hirid ();
392 37296 : AssociatedImplTrait *associated = nullptr;
393 37296 : bool found_impl_trait
394 37296 : = context->lookup_associated_trait_impl (impl_block_id, &associated);
395 37296 : if (found_impl_trait)
396 : {
397 : // compare the bounds from here i think is what we can do:
398 17665 : if (bound.is_equal (associated->get_predicate ()))
399 : {
400 2064 : associated_impl_traits.push_back (associated);
401 : }
402 : }
403 : }
404 :
405 9244 : if (associated_impl_traits.empty ())
406 : return nullptr;
407 :
408 : // This code is important when you look at slices for example when
409 : // you have a slice such as:
410 : //
411 : // let slice = &array[1..3]
412 : //
413 : // the higher ranked bounds will end up having an Index trait
414 : // implementation for Range<usize> so we need this code to resolve
415 : // that we have an integer inference variable that needs to become
416 : // a usize
417 : //
418 : // The other complicated issue is that we might have an intrinsic
419 : // which requires the :Clone or Copy bound but the libcore adds
420 : // implementations for all the integral types so when there are
421 : // multiple candidates we need to resolve to the default
422 : // implementation for that type otherwise its an error for
423 : // ambiguous type bounds
424 :
425 : // if we have a non-general inference variable we need to be
426 : // careful about the selection here
427 2042 : bool is_infer_var = binding->get_kind () == TyTy::TypeKind::INFER;
428 2042 : bool is_integer_infervar
429 : = is_infer_var
430 2042 : && static_cast<const TyTy::InferType *> (binding)->get_infer_kind ()
431 2106 : == TyTy::InferType::InferTypeKind::INTEGRAL;
432 64 : bool is_float_infervar
433 : = is_infer_var
434 64 : && static_cast<const TyTy::InferType *> (binding)->get_infer_kind ()
435 2042 : == TyTy::InferType::InferTypeKind::FLOAT;
436 :
437 2042 : AssociatedImplTrait *associate_impl_trait = nullptr;
438 2042 : if (associated_impl_traits.size () == 1)
439 : {
440 : // just go for it
441 2020 : associate_impl_trait = associated_impl_traits.at (0);
442 : }
443 22 : else if (is_integer_infervar)
444 : {
445 0 : TyTy::BaseType *type = nullptr;
446 0 : bool ok = context->lookup_builtin ("i32", &type);
447 0 : rust_assert (ok);
448 :
449 0 : for (auto &impl : associated_impl_traits)
450 : {
451 0 : bool found = impl->get_self ()->is_equal (*type);
452 0 : if (found)
453 : {
454 0 : associate_impl_trait = impl;
455 0 : break;
456 : }
457 : }
458 : }
459 22 : else if (is_float_infervar)
460 : {
461 0 : TyTy::BaseType *type = nullptr;
462 0 : bool ok = context->lookup_builtin ("f64", &type);
463 0 : rust_assert (ok);
464 :
465 0 : for (auto &impl : associated_impl_traits)
466 : {
467 0 : bool found = impl->get_self ()->is_equal (*type);
468 0 : if (found)
469 : {
470 0 : associate_impl_trait = impl;
471 0 : break;
472 : }
473 : }
474 : }
475 :
476 2042 : if (associate_impl_trait == nullptr && ambigious != nullptr)
477 : {
478 22 : *ambigious = true;
479 : }
480 :
481 : return associate_impl_trait;
482 9244 : }
483 :
484 : void
485 10630 : rebind_projection_self_from_fn (TyTy::FnType &fn, TyTy::BaseType *root)
486 : {
487 : // After substitution+monomorphize the fn's substitution clones carry the
488 : // call-site bindings. Inner projections in the return/params can still
489 : // reference the traits formal Self via TyVar(formal.ref) whose type table
490 : // entry resolves to the unbound formal
491 10630 : std::map<HirId, TyTy::BaseGeneric *> bound_by_formal;
492 15633 : for (auto &sub : fn.get_substs ())
493 : {
494 5003 : auto *pty = sub.get_param_ty ();
495 5003 : if (pty == nullptr || pty->get_kind () != TyTy::TypeKind::PARAM
496 9999 : || !pty->can_resolve ())
497 93 : continue;
498 4910 : bound_by_formal[pty->get_ref ()] = pty;
499 : }
500 :
501 10630 : std::function<void (TyTy::BaseType *)> rebind;
502 34028 : rebind = [&] (TyTy::BaseType *ty) {
503 12768 : if (ty == nullptr)
504 : return;
505 :
506 12768 : if (auto *proj = ty->try_as<TyTy::ProjectionType> ())
507 : {
508 171 : auto *self = proj->get_self ();
509 171 : if (self->get_kind () == TyTy::TypeKind::PARAM)
510 : {
511 140 : auto it = bound_by_formal.find (self->get_ref ());
512 140 : if (it != bound_by_formal.end ())
513 126 : proj->set_self (it->second);
514 : }
515 :
516 437 : for (auto &sub : proj->get_substs ())
517 : {
518 266 : auto *param = sub.get_param_ty ();
519 266 : if (param == nullptr || param->get_kind () != TyTy::TypeKind::PARAM
520 532 : || param->can_resolve ())
521 266 : continue;
522 :
523 30 : auto it = bound_by_formal.find (param->get_ref ());
524 30 : if (it == bound_by_formal.end ()
525 30 : || it->second->get_kind () != TyTy::TypeKind::PARAM)
526 0 : continue;
527 :
528 30 : auto *bound = static_cast<TyTy::ParamType *> (it->second);
529 30 : if (bound->can_resolve ())
530 30 : param->set_ty_ref (bound->get_ty_ref ());
531 : }
532 : return;
533 : }
534 :
535 12597 : if (auto *adt = ty->try_as<TyTy::ADTType> ())
536 : {
537 2668 : for (auto &variant : adt->get_variants ())
538 3163 : for (auto &field : variant->get_fields ())
539 1516 : rebind (field->get_field_type ());
540 : return;
541 : }
542 :
543 11576 : if (auto *ref = ty->try_as<TyTy::ReferenceType> ())
544 54 : rebind (ref->get_base ());
545 11522 : else if (auto *ptr = ty->try_as<TyTy::PointerType> ())
546 200 : rebind (ptr->get_base ());
547 11322 : else if (auto *tup = ty->try_as<TyTy::TupleType> ())
548 4546 : for (size_t i = 0; i < tup->num_fields (); i++)
549 368 : rebind (tup->get_field (i));
550 10630 : };
551 :
552 10630 : rebind (root);
553 10630 : }
554 :
555 : TyTy::BaseType *
556 11390 : normalize_projection (TyTy::ProjectionType *proj, location_t locus,
557 : bool emit_errors, bool unify_self)
558 : {
559 11390 : static std::vector<TyTy::ProjectionType *> active_projections;
560 22780 : if (ScopedPush<TyTy::ProjectionType *>::contains (active_projections, proj))
561 : return proj;
562 :
563 11362 : ScopedPush<TyTy::ProjectionType *> guard (active_projections, proj);
564 :
565 11362 : if (!proj->is_trait_position ())
566 181 : return proj->get ();
567 :
568 : // special case the discriminant_type lang item
569 11181 : auto &mappings = Analysis::Mappings::get ();
570 11181 : auto *ctx = TypeCheckContext::get ();
571 11181 : if (auto discriminant_type_id
572 11181 : = mappings.lookup_lang_item (LangItem::Kind::DISCRIMINANT_TYPE))
573 : {
574 72 : if (proj->get_item_defid () == discriminant_type_id.value ())
575 : {
576 72 : TyTy::BaseType *isize_ty = nullptr;
577 72 : bool ok = ctx->lookup_builtin ("isize", &isize_ty);
578 72 : rust_assert (ok);
579 :
580 : // If the self type is a concrete ADT, use its repr.
581 72 : TyTy::BaseType *self = proj->get_self ()->destructure ();
582 72 : if (auto *adt = self->try_as<TyTy::ADTType> ())
583 : {
584 0 : auto *repr = adt->get_repr_options ().repr;
585 0 : if (repr != nullptr)
586 : return repr;
587 : }
588 72 : return isize_ty;
589 : }
590 : }
591 :
592 11109 : ImplTraitContextFrame frame;
593 11109 : if (!ctx->find_matching_impl_trait_frame (*proj->get_trait_ref (), &frame))
594 : {
595 : // No concrete impl frame check WHERE clause bindings on the self type
596 : //
597 : // fn foo<T: Trait<AssocType = X>>()
598 : //
599 : // normalizes
600 : //
601 : // <T as Trait>::AssocType -> X.
602 :
603 6659 : TyTy::BaseType *self = proj->get_self ()->destructure ();
604 6659 : const DefId item_defid = proj->get_item_defid ();
605 :
606 : // find the name of the associated type from the trait reference
607 6659 : std::string assoc_name;
608 7545 : for (const auto &ti : proj->get_trait_ref ()->get_trait_items ())
609 : {
610 8431 : if (ti.get_mappings ().get_defid () == item_defid)
611 : {
612 6659 : assoc_name = ti.get_identifier ();
613 6659 : break;
614 : }
615 : }
616 :
617 6659 : if (!assoc_name.empty ())
618 : {
619 11572 : for (auto &bound : self->get_specified_bounds ())
620 : {
621 4973 : if (!bound.get ()->is_equal (*proj->get_trait_ref ()))
622 1507 : continue;
623 :
624 3466 : auto &binding
625 3466 : = bound.get_substitution_arguments ().get_binding_args ();
626 3466 : auto it = binding.find (assoc_name);
627 3466 : if (it != binding.end ())
628 60 : return it->second;
629 : }
630 : }
631 :
632 : // If self is a trait-position projection recursively normalize it first
633 : // so the impl-block lookup below works on a concrete type.
634 6599 : if (auto *self_proj = self->try_as<TyTy::ProjectionType> ())
635 : {
636 0 : if (self_proj->is_trait_position ())
637 : {
638 0 : auto *norm = normalize_projection (self_proj, locus, emit_errors,
639 : unify_self);
640 0 : if (norm != self_proj
641 0 : && norm->get_kind () != TyTy::TypeKind::ERROR)
642 0 : self = norm->destructure ();
643 : }
644 : else
645 : {
646 0 : auto *base = self_proj->get ();
647 0 : if (base && base != self_proj)
648 0 : self = base->destructure ();
649 : }
650 : }
651 :
652 : // Direct impl-block lookup for concrete self types (no active frame).
653 6599 : if (!assoc_name.empty () && self->get_kind () != TyTy::TypeKind::PARAM
654 3320 : && self->get_kind () != TyTy::TypeKind::INFER
655 9919 : && self->get_kind () != TyTy::TypeKind::PROJECTION)
656 : {
657 3320 : auto candidates = TypeBoundsProbe::Probe (self);
658 8729 : for (auto &probed : candidates)
659 : {
660 8629 : HIR::ImplBlock *impl_block = probed.second;
661 8629 : if (!impl_block->has_trait_ref ())
662 200 : continue;
663 :
664 8429 : HIR::TypePath &ref = impl_block->get_trait_ref ();
665 8429 : auto *tref = TraitResolver::Resolve (ref);
666 8429 : if (tref->is_error ()
667 8429 : || !tref->is_equal (*proj->get_trait_ref ()))
668 5209 : continue;
669 :
670 4027 : for (auto &impl_item : impl_block->get_impl_items ())
671 : {
672 8054 : if (impl_item->get_impl_item_name ().compare (assoc_name)
673 4027 : != 0)
674 807 : continue;
675 :
676 3220 : TyTy::BaseType *result = nullptr;
677 3220 : if (query_type (impl_item->get_impl_mappings ().get_hirid (),
678 : &result))
679 : {
680 3220 : AssociatedImplTrait *associated = nullptr;
681 3220 : if (ctx->lookup_associated_trait_impl (
682 3220 : impl_block->get_mappings ().get_hirid (),
683 : &associated)
684 3220 : && associated != nullptr)
685 : {
686 3220 : auto mapping
687 : = associated->bind_impl_for_projection (*proj,
688 3220 : locus);
689 3220 : if (!mapping.is_error ())
690 3213 : result
691 3213 : = SubstMapperInternal::Resolve (result, mapping);
692 3220 : }
693 :
694 : // impl type aliases are stored as non-trait-position
695 : // ProjectionType; unwrap to base only when there are no
696 : // substitution params (non-GAT)
697 3220 : if (auto *p = result->try_as<TyTy::ProjectionType> ())
698 : {
699 3220 : if (!p->is_trait_position ())
700 : {
701 3220 : bool all_substs_bound = true;
702 4327 : for (auto &s : p->get_substs ())
703 : {
704 2840 : auto *sp = s.get_param_ty ();
705 2840 : if (sp == nullptr || !sp->can_resolve ()
706 5433 : || sp->resolve ()->get_kind ()
707 : == TyTy::TypeKind::PARAM)
708 : {
709 : all_substs_bound = false;
710 : break;
711 : }
712 : }
713 :
714 : // Also unwrap when the base is already concrete
715 3220 : bool base_is_concrete
716 3220 : = p->get () != nullptr
717 3220 : && p->get ()->is_concrete ();
718 3220 : if (!p->has_substitutions () || all_substs_bound
719 3220 : || base_is_concrete)
720 3142 : result = p->get ();
721 : }
722 : }
723 :
724 3220 : return result;
725 : }
726 0 : break;
727 : }
728 : }
729 3320 : }
730 :
731 : // special-case FnOnce::Output
732 3379 : if (proj->is_trait_position ())
733 : {
734 3379 : auto fn_once_lookup
735 3379 : = mappings.lookup_lang_item (LangItem::Kind::FN_ONCE);
736 3379 : auto fn_once_output_lookup
737 3379 : = mappings.lookup_lang_item (LangItem::Kind::FN_ONCE_OUTPUT);
738 3379 : if (!fn_once_lookup || !fn_once_output_lookup)
739 3318 : return proj;
740 :
741 161 : DefId &fn_once_trait_id = fn_once_lookup.value ();
742 161 : DefId &fn_once_output_id = fn_once_output_lookup.value ();
743 161 : DefId proj_trait_id = proj->get_trait_ref ()->get_defid ();
744 161 : DefId proj_trait_item_id = proj->get_item_defid ();
745 :
746 322 : if (proj_trait_id == fn_once_trait_id
747 222 : && proj_trait_item_id == fn_once_output_id)
748 : {
749 161 : auto pself = proj->get_self ();
750 222 : if (auto closure = pself->try_as<TyTy::ClosureType> ())
751 100 : return &closure->get_result_type ();
752 : }
753 : }
754 :
755 61 : return proj;
756 6659 : }
757 :
758 4450 : if (unify_self)
759 : {
760 0 : TyTy::BaseType *proj_self = proj->get_self ();
761 0 : TyTy::BaseType *impl_self = frame.self;
762 0 : TyTy::BaseType *self
763 0 : = unify_site_and (/*id*/ 0, TyTy::TyWithLocation (proj_self, locus),
764 0 : TyTy::TyWithLocation (impl_self, locus), locus,
765 : /*emit_errors*/ false,
766 : /*commit*/ false,
767 : /*infer*/ false,
768 : /*cleanup*/ true,
769 : /*check_bounds*/ false);
770 :
771 0 : if (self->get_kind () == TyTy::TypeKind::ERROR)
772 : return self;
773 : }
774 :
775 : // Lookup the trait item -> impl type mapping (key = trait item DefId).
776 4450 : const DefId item = proj->get_item_defid ();
777 4450 : auto it = frame.assoc_types_by_trait_item.find (item);
778 4450 : if (it == frame.assoc_types_by_trait_item.end ())
779 : {
780 : return proj;
781 : }
782 :
783 4450 : auto &entry = it->second;
784 4450 : auto impl_value = entry.value;
785 :
786 : // chase the impl body through any further projections it contains
787 4450 : TyTy::BaseType *normalized = impl_value;
788 8900 : for (size_t i = 0; i < kNormalizeProjectionLimit; i++)
789 : {
790 8900 : if (!normalized->is<TyTy::ProjectionType> ())
791 : break;
792 :
793 4499 : auto p = normalized->as<TyTy::ProjectionType> ();
794 4499 : if (p->is_trait_position ())
795 : {
796 49 : auto *n = normalize_projection (p, locus, emit_errors, unify_self);
797 49 : if (n == p)
798 : break;
799 :
800 : normalized = n;
801 : }
802 : else
803 : {
804 4450 : auto *v = p->get ();
805 4450 : if (v == nullptr || v == p)
806 : break;
807 :
808 : normalized = v;
809 : }
810 : }
811 :
812 : return normalized;
813 11362 : }
814 :
815 : } // namespace Resolver
816 : } // namespace Rust
|