libcpp, c, middle-end: Optimize initializers using #embed in C
[official-gcc.git] / gcc / rust / typecheck / rust-hir-trait-resolve.cc
bloba300cecae3157f8f957101d94db29a423b35a525
1 // Copyright (C) 2021-2024 Free Software Foundation, Inc.
3 // This file is part of GCC.
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.
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.
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/>.
19 #include "rust-hir-trait-resolve.h"
20 #include "rust-hir-type-check-expr.h"
21 #include "rust-substitution-mapper.h"
22 #include "rust-type-util.h"
24 namespace Rust {
25 namespace Resolver {
27 TraitItemReference
28 ResolveTraitItemToRef::Resolve (
29 HIR::TraitItem &item, TyTy::BaseType *self,
30 std::vector<TyTy::SubstitutionParamMapping> substitutions)
32 ResolveTraitItemToRef resolver (self, std::move (substitutions));
33 item.accept_vis (resolver);
34 return std::move (resolver.resolved);
37 void
38 ResolveTraitItemToRef::visit (HIR::TraitItemType &type)
40 // create trait-item-ref
41 location_t locus = type.get_locus ();
42 bool is_optional = false;
43 std::string identifier = type.get_name ().as_string ();
45 resolved = TraitItemReference (identifier, is_optional,
46 TraitItemReference::TraitItemType::TYPE, &type,
47 self, substitutions, locus);
50 void
51 ResolveTraitItemToRef::visit (HIR::TraitItemConst &cst)
53 // create trait-item-ref
54 location_t locus = cst.get_locus ();
55 bool is_optional = cst.has_expr ();
56 std::string identifier = cst.get_name ().as_string ();
58 resolved = TraitItemReference (identifier, is_optional,
59 TraitItemReference::TraitItemType::CONST, &cst,
60 self, substitutions, locus);
63 void
64 ResolveTraitItemToRef::visit (HIR::TraitItemFunc &fn)
66 // create trait-item-ref
67 location_t locus = fn.get_locus ();
68 bool is_optional = fn.has_block_defined ();
69 std::string identifier = fn.get_decl ().get_function_name ().as_string ();
71 resolved = TraitItemReference (identifier, is_optional,
72 TraitItemReference::TraitItemType::FN, &fn,
73 self, std::move (substitutions), locus);
76 ResolveTraitItemToRef::ResolveTraitItemToRef (
77 TyTy::BaseType *self,
78 std::vector<TyTy::SubstitutionParamMapping> &&substitutions)
79 : TypeCheckBase (), resolved (TraitItemReference::error ()), self (self),
80 substitutions (std::move (substitutions))
83 // TraitItemReference items
85 TraitReference *
86 TraitResolver::Resolve (HIR::TypePath &path)
88 TraitResolver resolver;
89 return resolver.resolve_path (path);
92 TraitReference *
93 TraitResolver::Resolve (HIR::Trait &trait)
95 TraitResolver resolver;
96 return resolver.resolve_trait (&trait);
99 TraitReference *
100 TraitResolver::Lookup (HIR::TypePath &path)
102 TraitResolver resolver;
103 return resolver.lookup_path (path);
106 TraitResolver::TraitResolver () : TypeCheckBase () {}
108 bool
109 TraitResolver::resolve_path_to_trait (const HIR::TypePath &path,
110 HIR::Trait **resolved) const
112 NodeId ref;
113 if (!resolver->lookup_resolved_type (path.get_mappings ().get_nodeid (),
114 &ref))
116 rust_error_at (path.get_locus (), "Failed to resolve path to node-id");
117 return false;
120 HirId hir_node = UNKNOWN_HIRID;
121 if (!mappings->lookup_node_to_hir (ref, &hir_node))
123 rust_error_at (path.get_locus (), "Failed to resolve path to hir-id");
124 return false;
127 HIR::Item *resolved_item = mappings->lookup_hir_item (hir_node);
128 rust_assert (resolved_item != nullptr);
129 rust_assert (resolved_item->get_item_kind () == HIR::Item::ItemKind::Trait);
130 *resolved = static_cast<HIR::Trait *> (resolved_item);
132 return true;
135 TraitReference *
136 TraitResolver::resolve_path (HIR::TypePath &path)
138 HIR::Trait *resolved_trait_reference;
139 bool ok = resolve_path_to_trait (path, &resolved_trait_reference);
140 if (!ok)
141 return &TraitReference::error_node ();
143 return resolve_trait (resolved_trait_reference);
146 TraitReference *
147 TraitResolver::resolve_trait (HIR::Trait *trait_reference)
149 TraitReference *tref = &TraitReference::error_node ();
150 if (context->lookup_trait_reference (
151 trait_reference->get_mappings ().get_defid (), &tref))
153 return tref;
156 DefId trait_id = trait_reference->get_mappings ().get_defid ();
157 if (context->trait_query_in_progress (trait_id))
159 rust_error_at (
160 trait_reference->get_locus (), ErrorCode::E0391,
161 "cycle detected when computing the super predicates of %qs",
162 trait_reference->get_name ().as_string ().c_str ());
163 return &TraitReference::error_node ();
166 TraitQueryGuard guard (trait_id);
167 TyTy::BaseType *self = nullptr;
168 std::vector<TyTy::SubstitutionParamMapping> substitutions;
170 // this needs to be special cased for the sized trait to not auto implemented
171 // Sized on Self
172 for (auto &generic_param : trait_reference->get_generic_params ())
174 switch (generic_param.get ()->get_kind ())
176 case HIR::GenericParam::GenericKind::LIFETIME:
177 case HIR::GenericParam::GenericKind::CONST:
178 // FIXME: Skipping Lifetime and Const completely until better
179 // handling.
180 break;
182 case HIR::GenericParam::GenericKind::TYPE: {
183 auto &typaram = static_cast<HIR::TypeParam &> (*generic_param);
184 bool is_self
185 = typaram.get_type_representation ().as_string ().compare ("Self")
186 == 0;
188 // https://doc.rust-lang.org/std/marker/trait.Sized.html
189 // The one exception is the implicit Self type of a trait
190 bool apply_sized = !is_self;
191 auto param_type
192 = TypeResolveGenericParam::Resolve (generic_param.get (),
193 apply_sized);
194 context->insert_type (generic_param->get_mappings (), param_type);
195 substitutions.push_back (
196 TyTy::SubstitutionParamMapping (typaram, param_type));
198 if (is_self)
200 rust_assert (param_type->get_kind () == TyTy::TypeKind::PARAM);
201 TyTy::ParamType *p
202 = static_cast<TyTy::ParamType *> (param_type);
203 p->set_implicit_self_trait ();
204 self = p;
207 break;
210 rust_assert (self != nullptr);
212 // Check if there is a super-trait, and apply this bound to the Self
213 // TypeParam
214 std::vector<TyTy::TypeBoundPredicate> specified_bounds;
216 // copy the substitition mappings
217 std::vector<TyTy::SubstitutionParamMapping> self_subst_copy;
218 for (auto &sub : substitutions)
219 self_subst_copy.push_back (sub.clone ());
221 // They also inherit themselves as a bound this enables a trait item to
222 // reference other Self::trait_items
223 auto self_hrtb
224 = TyTy::TypeBoundPredicate (trait_reference->get_mappings ().get_defid (),
225 std::move (self_subst_copy),
226 BoundPolarity::RegularBound,
227 trait_reference->get_locus ());
228 specified_bounds.push_back (self_hrtb);
230 // look for any
231 std::vector<const TraitReference *> super_traits;
232 if (trait_reference->has_type_param_bounds ())
234 for (auto &bound : trait_reference->get_type_param_bounds ())
236 if (bound->get_bound_type ()
237 == HIR::TypeParamBound::BoundType::TRAITBOUND)
239 HIR::TraitBound *b
240 = static_cast<HIR::TraitBound *> (bound.get ());
242 auto predicate = get_predicate_from_bound (
243 b->get_path (),
244 nullptr /*this will setup a PLACEHOLDER for self*/);
245 if (predicate.is_error ())
246 return &TraitReference::error_node ();
248 specified_bounds.push_back (predicate);
249 super_traits.push_back (predicate.get ());
253 self->inherit_bounds (specified_bounds);
255 std::vector<TraitItemReference> item_refs;
256 for (auto &item : trait_reference->get_trait_items ())
258 // make a copy of the substs
259 std::vector<TyTy::SubstitutionParamMapping> item_subst;
260 for (auto &sub : substitutions)
261 item_subst.push_back (sub.clone ());
263 TraitItemReference trait_item_ref
264 = ResolveTraitItemToRef::Resolve (*item.get (), self,
265 std::move (item_subst));
266 item_refs.push_back (std::move (trait_item_ref));
269 TraitReference trait_object (trait_reference, item_refs,
270 std::move (super_traits),
271 std::move (substitutions));
272 context->insert_trait_reference (
273 trait_reference->get_mappings ().get_defid (), std::move (trait_object));
275 tref = &TraitReference::error_node ();
276 bool ok = context->lookup_trait_reference (
277 trait_reference->get_mappings ().get_defid (), &tref);
278 rust_assert (ok);
280 // hook to allow the trait to resolve its optional item blocks, we cant
281 // resolve the blocks of functions etc because it can end up in a recursive
282 // loop of trying to resolve traits as required by the types
283 tref->on_resolved ();
285 return tref;
288 TraitReference *
289 TraitResolver::lookup_path (HIR::TypePath &path)
291 HIR::Trait *resolved_trait_reference;
292 bool ok = resolve_path_to_trait (path, &resolved_trait_reference);
293 if (!ok)
294 return &TraitReference::error_node ();
296 TraitReference *tref = &TraitReference::error_node ();
297 if (context->lookup_trait_reference (
298 resolved_trait_reference->get_mappings ().get_defid (), &tref))
300 return tref;
302 return &TraitReference::error_node ();
305 void
306 TraitItemReference::on_resolved ()
308 switch (type)
310 case CONST:
311 resolve_item (static_cast<HIR::TraitItemConst &> (*hir_trait_item));
312 break;
314 case TYPE:
315 resolve_item (static_cast<HIR::TraitItemType &> (*hir_trait_item));
316 break;
318 case FN:
319 resolve_item (static_cast<HIR::TraitItemFunc &> (*hir_trait_item));
320 break;
322 default:
323 break;
327 void
328 TraitItemReference::resolve_item (HIR::TraitItemType &type)
330 TyTy::BaseType *ty
331 = new TyTy::PlaceholderType (type.get_name ().as_string (),
332 type.get_mappings ().get_hirid ());
333 context->insert_type (type.get_mappings (), ty);
336 void
337 TraitItemReference::resolve_item (HIR::TraitItemConst &constant)
339 // TODO
342 void
343 TraitItemReference::resolve_item (HIR::TraitItemFunc &func)
345 TyTy::BaseType *item_tyty = get_tyty ();
346 if (item_tyty->get_kind () == TyTy::TypeKind::ERROR)
347 return;
349 if (!is_optional ())
350 return;
352 // check the block and return types
353 rust_assert (item_tyty->get_kind () == TyTy::TypeKind::FNDEF);
355 // need to get the return type from this
356 TyTy::FnType *resolved_fn_type = static_cast<TyTy::FnType *> (item_tyty);
357 auto expected_ret_tyty = resolved_fn_type->get_return_type ();
358 context->push_return_type (TypeCheckContextItem (&func), expected_ret_tyty);
360 auto block_expr_ty = TypeCheckExpr::Resolve (func.get_block_expr ().get ());
362 location_t fn_return_locus
363 = func.get_decl ().has_return_type ()
364 ? func.get_decl ().get_return_type ()->get_locus ()
365 : func.get_locus ();
367 coercion_site (func.get_mappings ().get_hirid (),
368 TyTy::TyWithLocation (expected_ret_tyty, fn_return_locus),
369 TyTy::TyWithLocation (block_expr_ty), func.get_locus ());
371 context->pop_return_type ();
374 void
375 TraitItemReference::associated_type_set (TyTy::BaseType *ty) const
377 rust_assert (get_trait_item_type () == TraitItemType::TYPE);
379 TyTy::BaseType *item_ty = get_tyty ();
380 rust_assert (item_ty->get_kind () == TyTy::TypeKind::PLACEHOLDER);
381 TyTy::PlaceholderType *placeholder
382 = static_cast<TyTy::PlaceholderType *> (item_ty);
384 placeholder->set_associated_type (ty->get_ty_ref ());
387 void
388 TraitItemReference::associated_type_reset (bool only_projections) const
390 rust_assert (get_trait_item_type () == TraitItemType::TYPE);
392 TyTy::BaseType *item_ty = get_tyty ();
393 rust_assert (item_ty->get_kind () == TyTy::TypeKind::PLACEHOLDER);
394 TyTy::PlaceholderType *placeholder
395 = static_cast<TyTy::PlaceholderType *> (item_ty);
397 if (!only_projections)
399 placeholder->clear_associated_type ();
401 else
403 if (!placeholder->can_resolve ())
404 return;
406 const TyTy::BaseType *r = placeholder->resolve ();
407 if (r->get_kind () == TyTy::TypeKind::PROJECTION)
409 placeholder->clear_associated_type ();
414 void
415 AssociatedImplTrait::setup_raw_associated_types ()
417 auto &impl_items = impl->get_impl_items ();
418 for (auto &impl_item : impl_items)
420 bool is_type_alias = impl_item->get_impl_item_type ()
421 == HIR::ImplItem::ImplItemType::TYPE_ALIAS;
422 if (!is_type_alias)
423 continue;
425 HIR::TypeAlias &type = *static_cast<HIR::TypeAlias *> (impl_item.get ());
427 TraitItemReference *resolved_trait_item = nullptr;
428 bool ok
429 = trait->lookup_trait_item (type.get_new_type_name ().as_string (),
430 &resolved_trait_item);
431 if (!ok)
432 continue;
433 if (resolved_trait_item->get_trait_item_type ()
434 != TraitItemReference::TraitItemType::TYPE)
435 continue;
437 TyTy::BaseType *lookup;
438 ok = context->lookup_type (type.get_mappings ().get_hirid (), &lookup);
439 rust_assert (ok);
441 resolved_trait_item->associated_type_set (lookup);
445 TyTy::BaseType *
446 AssociatedImplTrait::setup_associated_types (
447 const TyTy::BaseType *self, const TyTy::TypeBoundPredicate &bound,
448 TyTy::SubstitutionArgumentMappings *args)
450 // compute the constrained impl block generic arguments based on self and the
451 // higher ranked trait bound
452 TyTy::BaseType *receiver = self->clone ();
454 // impl<Y> SliceIndex<[Y]> for Range<usize>
455 // vs
456 // I: SliceIndex<[<integer>]> and Range<<integer>>
458 // we need to figure out what Y is
460 TyTy::BaseType *associated_self = get_self ();
462 rust_debug ("setup_associated_types for: %s->%s bound %s",
463 associated_self->debug_str ().c_str (),
464 self->debug_str ().c_str (), bound.as_string ().c_str ());
466 // grab the parameters
467 HIR::ImplBlock &impl_block = *get_impl_block ();
468 std::vector<TyTy::SubstitutionParamMapping> substitutions;
469 for (auto &generic_param : impl_block.get_generic_params ())
471 switch (generic_param.get ()->get_kind ())
473 case HIR::GenericParam::GenericKind::LIFETIME:
474 case HIR::GenericParam::GenericKind::CONST:
475 // FIXME: Skipping Lifetime and Const completely until better
476 // handling.
477 break;
479 case HIR::GenericParam::GenericKind::TYPE: {
480 TyTy::BaseType *l = nullptr;
481 bool ok = context->lookup_type (
482 generic_param->get_mappings ().get_hirid (), &l);
483 if (ok && l->get_kind () == TyTy::TypeKind::PARAM)
485 substitutions.push_back (TyTy::SubstitutionParamMapping (
486 static_cast<HIR::TypeParam &> (*generic_param),
487 static_cast<TyTy::ParamType *> (l)));
490 break;
494 // this callback gives us the parameters that get substituted so we can
495 // compute the constrained type parameters for this impl block
496 std::map<std::string, HirId> param_mappings;
497 TyTy::ParamSubstCb param_subst_cb
498 = [&] (const TyTy::ParamType &p, const TyTy::SubstitutionArg &a) {
499 param_mappings[p.get_symbol ()] = a.get_tyty ()->get_ref ();
502 // generate inference variables for these bound arguments so we can compute
503 // their values
504 location_t locus = UNKNOWN_LOCATION;
505 std::vector<TyTy::SubstitutionArg> subst_args;
506 for (auto &p : substitutions)
508 if (p.needs_substitution ())
510 TyTy::TyVar infer_var = TyTy::TyVar::get_implicit_infer_var (locus);
511 subst_args.push_back (
512 TyTy::SubstitutionArg (&p, infer_var.get_tyty ()));
514 else
516 TyTy::ParamType *param = p.get_param_ty ();
517 TyTy::BaseType *resolved = param->destructure ();
518 subst_args.push_back (TyTy::SubstitutionArg (&p, resolved));
519 param_mappings[param->get_symbol ()] = resolved->get_ref ();
523 TyTy::SubstitutionArgumentMappings infer_arguments (
524 std::move (subst_args), {},
525 TyTy::SubstitutionArgumentMappings::regions_from_nullable_args (args),
526 locus, param_subst_cb);
527 TyTy::BaseType *impl_self_infer
528 = (!associated_self->is_concrete ())
529 ? SubstMapperInternal::Resolve (associated_self, infer_arguments)
530 : associated_self;
532 const TyTy::TypeBoundPredicate &impl_predicate
533 = associated_self->lookup_predicate (bound.get_id ());
534 rust_assert (!impl_predicate.is_error ());
536 // infer the arguments on the predicate
537 std::vector<TyTy::BaseType *> impl_trait_predicate_args;
539 for (size_t i = 0; i < impl_predicate.get_substs ().size (); i++)
541 const auto &arg = impl_predicate.get_substs ().at (i);
542 if (i == 0)
543 continue;
545 const TyTy::ParamType *p = arg.get_param_ty ();
546 TyTy::BaseType *r = p->resolve ();
547 if (!r->is_concrete ())
549 r = SubstMapperInternal::Resolve (r, infer_arguments);
551 impl_trait_predicate_args.push_back (r);
554 // unify the bounds arguments
555 std::vector<TyTy::BaseType *> hrtb_bound_arguments;
556 for (size_t i = 0; i < bound.get_substs ().size (); i++)
558 const auto &arg = bound.get_substs ().at (i);
559 if (i == 0)
560 continue;
562 const TyTy::ParamType *p = arg.get_param_ty ();
563 TyTy::BaseType *r = p->resolve ();
564 if (!r->is_concrete ())
566 r = SubstMapperInternal::Resolve (r, infer_arguments);
568 hrtb_bound_arguments.push_back (r);
571 rust_assert (impl_trait_predicate_args.size ()
572 == hrtb_bound_arguments.size ());
573 for (size_t i = 0; i < impl_trait_predicate_args.size (); i++)
575 TyTy::BaseType *a = impl_trait_predicate_args.at (i);
576 TyTy::BaseType *b = hrtb_bound_arguments.at (i);
578 TyTy::BaseType *result
579 = unify_site_and (a->get_ref (), TyTy::TyWithLocation (a),
580 TyTy::TyWithLocation (b), impl_predicate.get_locus (),
581 true /*emit-errors*/, true /*commit-if-ok*/,
582 false /*infer*/, true /*cleanup-on-fail*/);
583 rust_assert (result->get_kind () != TyTy::TypeKind::ERROR);
586 // we need to unify the receiver with the impl-block Self so that we compute
587 // the type correctly as our receiver may be generic and we are inferring its
588 // generic arguments and this Self might be the concrete version or vice
589 // versa.
590 auto result = unify_site_and (get_impl_block ()->get_mappings ().get_hirid (),
591 TyTy::TyWithLocation (receiver),
592 TyTy::TyWithLocation (impl_self_infer),
593 impl_predicate.get_locus (),
594 true /*emit-errors*/, true /*commit-if-ok*/,
595 false /*infer*/, true /*cleanup-on-fail*/);
596 rust_assert (result->get_kind () != TyTy::TypeKind::ERROR);
597 TyTy::BaseType *self_result = result;
599 // create the argument list
600 std::vector<TyTy::SubstitutionArg> associated_arguments;
601 for (auto &p : substitutions)
603 std::string symbol = p.get_param_ty ()->get_symbol ();
604 auto it = param_mappings.find (symbol);
605 rust_assert (it != param_mappings.end ());
607 HirId id = it->second;
608 TyTy::BaseType *argument = nullptr;
609 bool ok = context->lookup_type (id, &argument);
610 rust_assert (ok);
612 TyTy::SubstitutionArg arg (&p, argument);
613 associated_arguments.push_back (arg);
616 TyTy::SubstitutionArgumentMappings associated_type_args (
617 std::move (associated_arguments), {},
618 TyTy::SubstitutionArgumentMappings::regions_from_nullable_args (args),
619 locus);
621 auto &impl_items = impl->get_impl_items ();
622 for (auto &impl_item : impl_items)
624 bool is_type_alias = impl_item->get_impl_item_type ()
625 == HIR::ImplItem::ImplItemType::TYPE_ALIAS;
626 if (!is_type_alias)
627 continue;
629 HIR::TypeAlias &type = *static_cast<HIR::TypeAlias *> (impl_item.get ());
631 TraitItemReference *resolved_trait_item = nullptr;
632 bool ok
633 = trait->lookup_trait_item (type.get_new_type_name ().as_string (),
634 &resolved_trait_item);
635 if (!ok)
636 continue;
637 if (resolved_trait_item->get_trait_item_type ()
638 != TraitItemReference::TraitItemType::TYPE)
639 continue;
641 TyTy::BaseType *lookup;
642 if (!context->lookup_type (type.get_mappings ().get_hirid (), &lookup))
643 continue;
645 // this might be generic
646 TyTy::BaseType *substituted
647 = SubstMapperInternal::Resolve (lookup, associated_type_args);
648 resolved_trait_item->associated_type_set (substituted);
651 if (args != nullptr)
653 *args = associated_type_args;
656 return self_result;
659 void
660 AssociatedImplTrait::reset_associated_types ()
662 trait->clear_associated_types ();
665 Analysis::NodeMapping
666 TraitItemReference::get_parent_trait_mappings () const
668 auto mappings = Analysis::Mappings::get ();
670 HIR::Trait *trait
671 = mappings->lookup_trait_item_mapping (get_mappings ().get_hirid ());
672 rust_assert (trait != nullptr);
674 return trait->get_mappings ();
677 bool
678 TraitItemReference::is_object_safe () const
680 // https://doc.rust-lang.org/reference/items/traits.html#object-safety
681 switch (get_trait_item_type ())
683 case TraitItemReference::TraitItemType::FN: {
684 // lets be boring and just check that this is indeed a method will do
685 // for now
686 const HIR::TraitItem *item = get_hir_trait_item ();
687 const HIR::TraitItemFunc *fn
688 = static_cast<const HIR::TraitItemFunc *> (item);
689 return fn->get_decl ().is_method ();
692 // constants are not available via dyn dispatch and so is not object safe
693 case TraitItemReference::TraitItemType::CONST:
694 return false;
696 // types are object safe since they are not available via dyn dispatch
697 case TraitItemReference::TraitItemType::TYPE:
698 return true;
700 // this is just an error so lets just fail it
701 case TraitItemReference::TraitItemType::ERROR:
702 return false;
704 return false;
707 } // namespace Resolver
708 } // namespace Rust