libcpp, c, middle-end: Optimize initializers using #embed in C
[official-gcc.git] / gcc / rust / typecheck / rust-hir-type-check-path.cc
blobdd6ab03a3627552d8f2c869dd69f9c8f8eada383
1 // Copyright (C) 2020-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-type-check-expr.h"
20 #include "rust-hir-type-check-type.h"
21 #include "rust-hir-type-check-item.h"
22 #include "rust-hir-trait-resolve.h"
23 #include "rust-substitution-mapper.h"
24 #include "rust-hir-path-probe.h"
25 #include "rust-type-util.h"
26 #include "rust-hir-type-bounds.h"
27 #include "rust-session-manager.h"
28 #include "rust-immutable-name-resolution-context.h"
30 namespace Rust {
31 namespace Resolver {
33 void
34 TypeCheckExpr::visit (HIR::QualifiedPathInExpression &expr)
36 HIR::QualifiedPathType qual_path_type = expr.get_path_type ();
37 TyTy::BaseType *root
38 = TypeCheckType::Resolve (qual_path_type.get_type ().get ());
39 if (root->get_kind () == TyTy::TypeKind::ERROR)
40 return;
42 if (!qual_path_type.has_as_clause ())
44 NodeId root_resolved_node_id = UNKNOWN_NODEID;
45 resolve_segments (root_resolved_node_id, expr.get_segments (), 0, root,
46 expr.get_mappings (), expr.get_locus ());
47 return;
50 // Resolve the trait now
51 std::unique_ptr<HIR::TypePath> &trait_path_ref = qual_path_type.get_trait ();
52 TraitReference *trait_ref = TraitResolver::Resolve (*trait_path_ref.get ());
53 if (trait_ref->is_error ())
54 return;
56 // does this type actually implement this type-bound?
57 if (!TypeBoundsProbe::is_bound_satisfied_for_type (root, trait_ref))
58 return;
60 // then we need to look at the next segment to create perform the correct
61 // projection type
62 if (expr.get_segments ().empty ())
63 return;
65 // get the predicate for the bound
66 auto specified_bound
67 = get_predicate_from_bound (*trait_path_ref.get (),
68 qual_path_type.get_type ().get ());
69 if (specified_bound.is_error ())
70 return;
72 // inherit the bound
73 root->inherit_bounds ({specified_bound});
75 // lookup the associated item from the specified bound
76 HIR::PathExprSegment &item_seg = expr.get_segments ().at (0);
77 HIR::PathIdentSegment item_seg_identifier = item_seg.get_segment ();
78 TyTy::TypeBoundPredicateItem item
79 = specified_bound.lookup_associated_item (item_seg_identifier.as_string ());
80 if (item.is_error ())
82 rust_error_at (item_seg.get_locus (), "unknown associated item");
83 return;
86 // we try to look for the real impl item if possible
87 HIR::ImplItem *impl_item = nullptr;
89 // lookup the associated impl trait for this if we can (it might be generic)
90 AssociatedImplTrait *associated_impl_trait
91 = lookup_associated_impl_block (specified_bound, root);
92 if (associated_impl_trait != nullptr)
94 associated_impl_trait->setup_associated_types (root, specified_bound);
96 for (auto &i :
97 associated_impl_trait->get_impl_block ()->get_impl_items ())
99 bool found = i->get_impl_item_name ().compare (
100 item_seg_identifier.as_string ())
101 == 0;
102 if (found)
104 impl_item = i.get ();
105 break;
110 NodeId root_resolved_node_id = UNKNOWN_NODEID;
111 if (impl_item == nullptr)
113 // this may be valid as there could be a default trait implementation here
114 // and we dont need to worry if the trait item is actually implemented or
115 // not because this will have already been validated as part of the trait
116 // impl block
117 infered = item.get_tyty_for_receiver (root);
118 root_resolved_node_id
119 = item.get_raw_item ()->get_mappings ().get_nodeid ();
121 else
123 HirId impl_item_id = impl_item->get_impl_mappings ().get_hirid ();
124 bool ok = query_type (impl_item_id, &infered);
125 if (!ok)
127 // FIXME
128 // I think query_type should error if required here anyway
129 return;
132 root_resolved_node_id = impl_item->get_impl_mappings ().get_nodeid ();
135 // turbo-fish segment path::<ty>
136 if (item_seg.has_generic_args ())
138 if (!infered->has_substitutions_defined ())
140 rust_error_at (item_seg.get_locus (),
141 "substitutions not supported for %s",
142 infered->as_string ().c_str ());
143 infered = new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
144 return;
146 std::vector<TyTy::Region> regions;
148 infered = SubstMapper::Resolve (infered, expr.get_locus (),
149 &item_seg.get_generic_args (),
150 context->regions_from_generic_args (
151 item_seg.get_generic_args ()));
154 // continue on as a path-in-expression
155 bool fully_resolved = expr.get_segments ().size () <= 1;
156 if (fully_resolved)
158 resolver->insert_resolved_name (expr.get_mappings ().get_nodeid (),
159 root_resolved_node_id);
160 context->insert_receiver (expr.get_mappings ().get_hirid (), root);
161 return;
164 resolve_segments (root_resolved_node_id, expr.get_segments (), 1, infered,
165 expr.get_mappings (), expr.get_locus ());
168 void
169 TypeCheckExpr::visit (HIR::PathInExpression &expr)
171 NodeId resolved_node_id = UNKNOWN_NODEID;
172 size_t offset = -1;
173 TyTy::BaseType *tyseg = resolve_root_path (expr, &offset, &resolved_node_id);
174 if (tyseg->get_kind () == TyTy::TypeKind::ERROR)
175 return;
177 bool fully_resolved = offset == expr.get_segments ().size ();
178 if (fully_resolved)
180 infered = tyseg;
181 return;
184 resolve_segments (resolved_node_id, expr.get_segments (), offset, tyseg,
185 expr.get_mappings (), expr.get_locus ());
188 TyTy::BaseType *
189 TypeCheckExpr::resolve_root_path (HIR::PathInExpression &expr, size_t *offset,
190 NodeId *root_resolved_node_id)
192 TyTy::BaseType *root_tyty = nullptr;
193 *offset = 0;
194 for (size_t i = 0; i < expr.get_num_segments (); i++)
196 HIR::PathExprSegment &seg = expr.get_segments ().at (i);
198 bool have_more_segments = (expr.get_num_segments () - 1 != i);
199 bool is_root = *offset == 0;
200 NodeId ast_node_id = seg.get_mappings ().get_nodeid ();
202 // then lookup the reference_node_id
203 NodeId ref_node_id = UNKNOWN_NODEID;
205 if (flag_name_resolution_2_0)
207 auto nr_ctx
208 = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
210 // assign the ref_node_id if we've found something
211 nr_ctx.lookup (expr.get_mappings ().get_nodeid ())
212 .map ([&ref_node_id] (NodeId resolved) { ref_node_id = resolved; });
214 else if (!resolver->lookup_resolved_name (ast_node_id, &ref_node_id))
215 resolver->lookup_resolved_type (ast_node_id, &ref_node_id);
217 // ref_node_id is the NodeId that the segments refers to.
218 if (ref_node_id == UNKNOWN_NODEID)
220 if (root_tyty != nullptr && *offset > 0)
222 // then we can let the impl path probe take over now
223 return root_tyty;
226 rust_error_at (seg.get_locus (),
227 "failed to type resolve root segment");
228 return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
231 // node back to HIR
232 HirId ref;
233 if (!mappings->lookup_node_to_hir (ref_node_id, &ref))
235 rust_error_at (seg.get_locus (), "456 reverse lookup failure");
236 rust_debug_loc (seg.get_locus (),
237 "failure with [%s] mappings [%s] ref_node_id [%u]",
238 seg.as_string ().c_str (),
239 seg.get_mappings ().as_string ().c_str (),
240 ref_node_id);
242 return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
245 auto seg_is_module = (nullptr != mappings->lookup_module (ref));
246 auto seg_is_crate = mappings->is_local_hirid_crate (ref);
247 if (seg_is_module || seg_is_crate)
249 // A::B::C::this_is_a_module::D::E::F
250 // ^^^^^^^^^^^^^^^^
251 // Currently handling this.
252 if (have_more_segments)
254 (*offset)++;
255 continue;
258 // In the case of :
259 // A::B::C::this_is_a_module
260 // ^^^^^^^^^^^^^^^^
261 // This is an error, we are not expecting a module.
262 rust_error_at (seg.get_locus (), "expected value");
263 return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
266 TyTy::BaseType *lookup = nullptr;
267 if (!query_type (ref, &lookup))
269 if (is_root)
271 rust_error_at (expr.get_locus (), ErrorCode::E0425,
272 "cannot find value %qs in this scope",
273 expr.as_simple_path ().as_string ().c_str ());
275 return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
277 return root_tyty;
280 // is it an enum item?
281 std::pair<HIR::Enum *, HIR::EnumItem *> enum_item_lookup
282 = mappings->lookup_hir_enumitem (ref);
283 bool is_enum_item = enum_item_lookup.first != nullptr
284 && enum_item_lookup.second != nullptr;
285 if (is_enum_item)
287 HirId expr_id = expr.get_mappings ().get_hirid ();
288 HirId variant_id
289 = enum_item_lookup.second->get_mappings ().get_hirid ();
290 context->insert_variant_definition (expr_id, variant_id);
293 // if we have a previous segment type
294 if (root_tyty != nullptr)
296 // if this next segment needs substitution we must apply the
297 // previous type arguments
299 // such as: GenericStruct::<_>::new(123, 456)
300 if (lookup->needs_generic_substitutions ())
302 if (!root_tyty->needs_generic_substitutions ())
304 auto used_args_in_prev_segment
305 = GetUsedSubstArgs::From (root_tyty);
306 lookup
307 = SubstMapperInternal::Resolve (lookup,
308 used_args_in_prev_segment);
313 // turbo-fish segment path::<ty>
314 if (seg.has_generic_args ())
316 lookup = SubstMapper::Resolve (lookup, expr.get_locus (),
317 &seg.get_generic_args (),
318 context->regions_from_generic_args (
319 seg.get_generic_args ()));
320 if (lookup->get_kind () == TyTy::TypeKind::ERROR)
321 return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
323 else if (lookup->needs_generic_substitutions ())
325 lookup = SubstMapper::InferSubst (lookup, expr.get_locus ());
328 *root_resolved_node_id = ref_node_id;
329 *offset = *offset + 1;
330 root_tyty = lookup;
333 return root_tyty;
336 void
337 TypeCheckExpr::resolve_segments (NodeId root_resolved_node_id,
338 std::vector<HIR::PathExprSegment> &segments,
339 size_t offset, TyTy::BaseType *tyseg,
340 const Analysis::NodeMapping &expr_mappings,
341 location_t expr_locus)
343 NodeId resolved_node_id = root_resolved_node_id;
344 TyTy::BaseType *prev_segment = tyseg;
345 bool reciever_is_generic = prev_segment->get_kind () == TyTy::TypeKind::PARAM;
347 for (size_t i = offset; i < segments.size (); i++)
349 HIR::PathExprSegment &seg = segments.at (i);
350 bool probe_impls = !reciever_is_generic;
352 // probe the path is done in two parts one where we search impls if no
353 // candidate is found then we search extensions from traits
354 auto candidates
355 = PathProbeType::Probe (prev_segment, seg.get_segment (), probe_impls,
356 false /*probe_bounds*/,
357 true /*ignore_mandatory_trait_items*/);
358 if (candidates.size () == 0)
360 candidates
361 = PathProbeType::Probe (prev_segment, seg.get_segment (), false,
362 true /*probe_bounds*/,
363 false /*ignore_mandatory_trait_items*/);
365 if (candidates.size () == 0)
367 rust_error_at (
368 seg.get_locus (),
369 "failed to resolve path segment using an impl Probe");
370 return;
374 if (candidates.size () > 1)
376 ReportMultipleCandidateError::Report (candidates, seg.get_segment (),
377 seg.get_locus ());
378 return;
381 auto &candidate = *candidates.begin ();
382 prev_segment = tyseg;
383 tyseg = candidate.ty;
385 HIR::ImplBlock *associated_impl_block = nullptr;
386 if (candidate.is_enum_candidate ())
388 const TyTy::VariantDef *variant = candidate.item.enum_field.variant;
390 HirId variant_id = variant->get_id ();
391 std::pair<HIR::Enum *, HIR::EnumItem *> enum_item_lookup
392 = mappings->lookup_hir_enumitem (variant_id);
393 bool enum_item_ok = enum_item_lookup.first != nullptr
394 && enum_item_lookup.second != nullptr;
395 rust_assert (enum_item_ok);
397 HIR::EnumItem *enum_item = enum_item_lookup.second;
398 resolved_node_id = enum_item->get_mappings ().get_nodeid ();
400 // insert the id of the variant we are resolved to
401 context->insert_variant_definition (expr_mappings.get_hirid (),
402 variant_id);
404 else if (candidate.is_impl_candidate ())
406 resolved_node_id
407 = candidate.item.impl.impl_item->get_impl_mappings ().get_nodeid ();
409 associated_impl_block = candidate.item.impl.parent;
411 else
413 resolved_node_id
414 = candidate.item.trait.item_ref->get_mappings ().get_nodeid ();
416 // lookup the associated-impl-trait
417 HIR::ImplBlock *impl = candidate.item.trait.impl;
418 if (impl != nullptr)
420 // get the associated impl block
421 associated_impl_block = impl;
425 if (associated_impl_block != nullptr)
427 // associated types
428 HirId impl_block_id
429 = associated_impl_block->get_mappings ().get_hirid ();
431 AssociatedImplTrait *associated = nullptr;
432 bool found_impl_trait
433 = context->lookup_associated_trait_impl (impl_block_id,
434 &associated);
436 auto mappings = TyTy::SubstitutionArgumentMappings::error ();
437 TyTy::BaseType *impl_block_ty
438 = TypeCheckItem::ResolveImplBlockSelfWithInference (
439 *associated_impl_block, seg.get_locus (), &mappings);
441 // we need to apply the arguments to the segment type so they get
442 // unified properly
443 if (!mappings.is_error ())
444 tyseg = SubstMapperInternal::Resolve (tyseg, mappings);
446 prev_segment = unify_site (seg.get_mappings ().get_hirid (),
447 TyTy::TyWithLocation (prev_segment),
448 TyTy::TyWithLocation (impl_block_ty),
449 seg.get_locus ());
450 bool ok = prev_segment->get_kind () != TyTy::TypeKind::ERROR;
451 if (!ok)
452 return;
454 if (found_impl_trait)
456 // we need to setup with apropriate bounds
457 HIR::TypePath &bound_path
458 = *associated->get_impl_block ()->get_trait_ref ().get ();
459 const auto &trait_ref = *TraitResolver::Resolve (bound_path);
460 rust_assert (!trait_ref.is_error ());
462 const auto &predicate
463 = impl_block_ty->lookup_predicate (trait_ref.get_defid ());
464 if (!predicate.is_error ())
465 impl_block_ty
466 = associated->setup_associated_types (prev_segment,
467 predicate);
471 if (seg.has_generic_args ())
473 rust_debug_loc (seg.get_locus (), "applying segment generics: %s",
474 tyseg->as_string ().c_str ());
475 tyseg
476 = SubstMapper::Resolve (tyseg, expr_locus, &seg.get_generic_args (),
477 context->regions_from_generic_args (
478 seg.get_generic_args ()));
479 if (tyseg->get_kind () == TyTy::TypeKind::ERROR)
480 return;
482 else if (tyseg->needs_generic_substitutions () && !reciever_is_generic)
484 location_t locus = seg.get_locus ();
485 tyseg = SubstMapper::InferSubst (tyseg, locus);
486 if (tyseg->get_kind () == TyTy::TypeKind::ERROR)
487 return;
491 rust_assert (resolved_node_id != UNKNOWN_NODEID);
492 if (tyseg->needs_generic_substitutions () && !reciever_is_generic)
494 location_t locus = segments.back ().get_locus ();
495 tyseg = SubstMapper::InferSubst (tyseg, locus);
496 if (tyseg->get_kind () == TyTy::TypeKind::ERROR)
497 return;
500 context->insert_receiver (expr_mappings.get_hirid (), prev_segment);
502 // name scope first
503 if (resolver->get_name_scope ().decl_was_declared_here (resolved_node_id))
505 resolver->insert_resolved_name (expr_mappings.get_nodeid (),
506 resolved_node_id);
508 // check the type scope
509 else if (resolver->get_type_scope ().decl_was_declared_here (
510 resolved_node_id))
512 resolver->insert_resolved_type (expr_mappings.get_nodeid (),
513 resolved_node_id);
515 else
517 resolver->insert_resolved_misc (expr_mappings.get_nodeid (),
518 resolved_node_id);
521 infered = tyseg;
524 } // namespace Resolver
525 } // namespace Rust