Branch data Line data Source code
1 : : // Copyright (C) 2020-2024 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-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 : :
28 : : namespace Rust {
29 : : namespace Resolver {
30 : :
31 : : void
32 : 80 : TypeCheckExpr::visit (HIR::QualifiedPathInExpression &expr)
33 : : {
34 : 80 : HIR::QualifiedPathType qual_path_type = expr.get_path_type ();
35 : 80 : TyTy::BaseType *root
36 : 80 : = TypeCheckType::Resolve (qual_path_type.get_type ().get ());
37 : 80 : if (root->get_kind () == TyTy::TypeKind::ERROR)
38 : : return;
39 : :
40 : 80 : if (!qual_path_type.has_as_clause ())
41 : : {
42 : 17 : NodeId root_resolved_node_id = UNKNOWN_NODEID;
43 : 17 : resolve_segments (root_resolved_node_id, expr.get_segments (), 0, root,
44 : : expr.get_mappings (), expr.get_locus ());
45 : 17 : return;
46 : : }
47 : :
48 : : // Resolve the trait now
49 : 63 : std::unique_ptr<HIR::TypePath> &trait_path_ref = qual_path_type.get_trait ();
50 : 63 : TraitReference *trait_ref = TraitResolver::Resolve (*trait_path_ref.get ());
51 : 63 : if (trait_ref->is_error ())
52 : : return;
53 : :
54 : : // does this type actually implement this type-bound?
55 : 63 : if (!TypeBoundsProbe::is_bound_satisfied_for_type (root, trait_ref))
56 : : return;
57 : :
58 : : // then we need to look at the next segment to create perform the correct
59 : : // projection type
60 : 63 : if (expr.get_segments ().empty ())
61 : : return;
62 : :
63 : : // get the predicate for the bound
64 : 63 : auto specified_bound
65 : 63 : = get_predicate_from_bound (*trait_path_ref.get (),
66 : 63 : qual_path_type.get_type ().get ());
67 : 63 : if (specified_bound.is_error ())
68 : : return;
69 : :
70 : : // inherit the bound
71 : 126 : root->inherit_bounds ({specified_bound});
72 : :
73 : : // lookup the associated item from the specified bound
74 : 63 : HIR::PathExprSegment &item_seg = expr.get_segments ().at (0);
75 : 63 : HIR::PathIdentSegment item_seg_identifier = item_seg.get_segment ();
76 : 63 : TyTy::TypeBoundPredicateItem item
77 : 63 : = specified_bound.lookup_associated_item (item_seg_identifier.as_string ());
78 : 63 : if (item.is_error ())
79 : : {
80 : 0 : rust_error_at (item_seg.get_locus (), "unknown associated item");
81 : 0 : return;
82 : : }
83 : :
84 : : // we try to look for the real impl item if possible
85 : 63 : HIR::ImplItem *impl_item = nullptr;
86 : :
87 : : // lookup the associated impl trait for this if we can (it might be generic)
88 : 63 : AssociatedImplTrait *associated_impl_trait
89 : 63 : = lookup_associated_impl_block (specified_bound, root);
90 : 63 : if (associated_impl_trait != nullptr)
91 : : {
92 : 54 : associated_impl_trait->setup_associated_types (root, specified_bound);
93 : :
94 : 76 : for (auto &i :
95 : 76 : associated_impl_trait->get_impl_block ()->get_impl_items ())
96 : : {
97 : 39 : bool found = i->get_impl_item_name ().compare (
98 : 39 : item_seg_identifier.as_string ())
99 : 39 : == 0;
100 : 39 : if (found)
101 : : {
102 : 17 : impl_item = i.get ();
103 : 17 : break;
104 : : }
105 : : }
106 : : }
107 : :
108 : 100 : NodeId root_resolved_node_id = UNKNOWN_NODEID;
109 : 54 : if (impl_item == nullptr)
110 : : {
111 : : // this may be valid as there could be a default trait implementation here
112 : : // and we dont need to worry if the trait item is actually implemented or
113 : : // not because this will have already been validated as part of the trait
114 : : // impl block
115 : 46 : infered = item.get_tyty_for_receiver (root);
116 : 46 : root_resolved_node_id
117 : 46 : = item.get_raw_item ()->get_mappings ().get_nodeid ();
118 : : }
119 : : else
120 : : {
121 : 17 : HirId impl_item_id = impl_item->get_impl_mappings ().get_hirid ();
122 : 17 : bool ok = query_type (impl_item_id, &infered);
123 : 17 : if (!ok)
124 : : {
125 : : // FIXME
126 : : // I think query_type should error if required here anyway
127 : : return;
128 : : }
129 : :
130 : 17 : root_resolved_node_id = impl_item->get_impl_mappings ().get_nodeid ();
131 : : }
132 : :
133 : : // turbo-fish segment path::<ty>
134 : 63 : if (item_seg.has_generic_args ())
135 : : {
136 : 0 : if (!infered->has_substitutions_defined ())
137 : : {
138 : 0 : rust_error_at (item_seg.get_locus (),
139 : : "substitutions not supported for %s",
140 : 0 : infered->as_string ().c_str ());
141 : 0 : infered = new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
142 : 0 : return;
143 : : }
144 : 0 : std::vector<TyTy::Region> regions;
145 : :
146 : 0 : infered = SubstMapper::Resolve (infered, expr.get_locus (),
147 : 0 : &item_seg.get_generic_args (),
148 : 0 : context->regions_from_generic_args (
149 : 0 : item_seg.get_generic_args ()));
150 : 0 : }
151 : :
152 : : // continue on as a path-in-expression
153 : 63 : bool fully_resolved = expr.get_segments ().size () <= 1;
154 : 63 : if (fully_resolved)
155 : : {
156 : 63 : resolver->insert_resolved_name (expr.get_mappings ().get_nodeid (),
157 : : root_resolved_node_id);
158 : 63 : context->insert_receiver (expr.get_mappings ().get_hirid (), root);
159 : 63 : return;
160 : : }
161 : :
162 : 0 : resolve_segments (root_resolved_node_id, expr.get_segments (), 1, infered,
163 : : expr.get_mappings (), expr.get_locus ());
164 : 206 : }
165 : :
166 : : void
167 : 25335 : TypeCheckExpr::visit (HIR::PathInExpression &expr)
168 : : {
169 : 25335 : NodeId resolved_node_id = UNKNOWN_NODEID;
170 : 25335 : size_t offset = -1;
171 : 25335 : TyTy::BaseType *tyseg = resolve_root_path (expr, &offset, &resolved_node_id);
172 : 25335 : if (tyseg->get_kind () == TyTy::TypeKind::ERROR)
173 : 24539 : return;
174 : :
175 : 25333 : bool fully_resolved = offset == expr.get_segments ().size ();
176 : 25333 : if (fully_resolved)
177 : : {
178 : 24537 : infered = tyseg;
179 : 24537 : return;
180 : : }
181 : :
182 : 796 : resolve_segments (resolved_node_id, expr.get_segments (), offset, tyseg,
183 : : expr.get_mappings (), expr.get_locus ());
184 : : }
185 : :
186 : : TyTy::BaseType *
187 : 25335 : TypeCheckExpr::resolve_root_path (HIR::PathInExpression &expr, size_t *offset,
188 : : NodeId *root_resolved_node_id)
189 : : {
190 : 25335 : TyTy::BaseType *root_tyty = nullptr;
191 : 25335 : *offset = 0;
192 : 52298 : for (size_t i = 0; i < expr.get_num_segments (); i++)
193 : : {
194 : 27761 : HIR::PathExprSegment &seg = expr.get_segments ().at (i);
195 : :
196 : 27761 : bool have_more_segments = (expr.get_num_segments () - 1 != i);
197 : 27761 : bool is_root = *offset == 0;
198 : 27761 : NodeId ast_node_id = seg.get_mappings ().get_nodeid ();
199 : :
200 : : // then lookup the reference_node_id
201 : 27761 : NodeId ref_node_id = UNKNOWN_NODEID;
202 : 27761 : if (!resolver->lookup_resolved_name (ast_node_id, &ref_node_id))
203 : : {
204 : 4560 : resolver->lookup_resolved_type (ast_node_id, &ref_node_id);
205 : : }
206 : :
207 : : // ref_node_id is the NodeId that the segments refers to.
208 : 27761 : if (ref_node_id == UNKNOWN_NODEID)
209 : : {
210 : 796 : if (root_tyty != nullptr && *offset > 0)
211 : : {
212 : : // then we can let the impl path probe take over now
213 : 798 : return root_tyty;
214 : : }
215 : :
216 : 0 : rust_error_at (seg.get_locus (),
217 : : "failed to type resolve root segment");
218 : 0 : return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
219 : : }
220 : :
221 : : // node back to HIR
222 : 26965 : HirId ref;
223 : 26965 : if (!mappings->lookup_node_to_hir (ref_node_id, &ref))
224 : : {
225 : 0 : rust_error_at (seg.get_locus (), "456 reverse lookup failure");
226 : 0 : rust_debug_loc (seg.get_locus (),
227 : : "failure with [%s] mappings [%s] ref_node_id [%u]",
228 : 0 : seg.as_string ().c_str (),
229 : 0 : seg.get_mappings ().as_string ().c_str (),
230 : : ref_node_id);
231 : :
232 : 0 : return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
233 : : }
234 : :
235 : 26965 : auto seg_is_module = (nullptr != mappings->lookup_module (ref));
236 : 26965 : auto seg_is_crate = mappings->is_local_hirid_crate (ref);
237 : 26965 : if (seg_is_module || seg_is_crate)
238 : : {
239 : : // A::B::C::this_is_a_module::D::E::F
240 : : // ^^^^^^^^^^^^^^^^
241 : : // Currently handling this.
242 : 991 : if (have_more_segments)
243 : : {
244 : 991 : (*offset)++;
245 : 991 : continue;
246 : : }
247 : :
248 : : // In the case of :
249 : : // A::B::C::this_is_a_module
250 : : // ^^^^^^^^^^^^^^^^
251 : : // This is an error, we are not expecting a module.
252 : 0 : rust_error_at (seg.get_locus (), "expected value");
253 : 0 : return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
254 : : }
255 : :
256 : 25974 : TyTy::BaseType *lookup = nullptr;
257 : 25974 : if (!query_type (ref, &lookup))
258 : : {
259 : 0 : if (is_root)
260 : : {
261 : 0 : rust_error_at (seg.get_locus (),
262 : : "failed to resolve root segment");
263 : 0 : return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
264 : : }
265 : : return root_tyty;
266 : : }
267 : :
268 : : // is it an enum item?
269 : 25974 : std::pair<HIR::Enum *, HIR::EnumItem *> enum_item_lookup
270 : 25974 : = mappings->lookup_hir_enumitem (ref);
271 : 52602 : bool is_enum_item = enum_item_lookup.first != nullptr
272 : 25974 : && enum_item_lookup.second != nullptr;
273 : 654 : if (is_enum_item)
274 : : {
275 : 654 : HirId expr_id = expr.get_mappings ().get_hirid ();
276 : 654 : HirId variant_id
277 : 654 : = enum_item_lookup.second->get_mappings ().get_hirid ();
278 : 654 : context->insert_variant_definition (expr_id, variant_id);
279 : : }
280 : :
281 : : // if we have a previous segment type
282 : 25974 : if (root_tyty != nullptr)
283 : : {
284 : : // if this next segment needs substitution we must apply the
285 : : // previous type arguments
286 : : //
287 : : // such as: GenericStruct::<_>::new(123, 456)
288 : 639 : if (lookup->needs_generic_substitutions ())
289 : : {
290 : 323 : if (!root_tyty->needs_generic_substitutions ())
291 : : {
292 : 323 : auto used_args_in_prev_segment
293 : 323 : = GetUsedSubstArgs::From (root_tyty);
294 : 323 : lookup
295 : 323 : = SubstMapperInternal::Resolve (lookup,
296 : : used_args_in_prev_segment);
297 : 323 : }
298 : : }
299 : : }
300 : :
301 : : // turbo-fish segment path::<ty>
302 : 25974 : if (seg.has_generic_args ())
303 : : {
304 : 515 : lookup = SubstMapper::Resolve (lookup, expr.get_locus (),
305 : 515 : &seg.get_generic_args (),
306 : 515 : context->regions_from_generic_args (
307 : 515 : seg.get_generic_args ()));
308 : 515 : if (lookup->get_kind () == TyTy::TypeKind::ERROR)
309 : 2 : return new TyTy::ErrorType (expr.get_mappings ().get_hirid ());
310 : : }
311 : 25459 : else if (lookup->needs_generic_substitutions ())
312 : : {
313 : 2098 : lookup = SubstMapper::InferSubst (lookup, expr.get_locus ());
314 : : }
315 : :
316 : 25972 : *root_resolved_node_id = ref_node_id;
317 : 25972 : *offset = *offset + 1;
318 : 25972 : root_tyty = lookup;
319 : : }
320 : :
321 : : return root_tyty;
322 : : }
323 : :
324 : : void
325 : 813 : TypeCheckExpr::resolve_segments (NodeId root_resolved_node_id,
326 : : std::vector<HIR::PathExprSegment> &segments,
327 : : size_t offset, TyTy::BaseType *tyseg,
328 : : const Analysis::NodeMapping &expr_mappings,
329 : : location_t expr_locus)
330 : : {
331 : 813 : NodeId resolved_node_id = root_resolved_node_id;
332 : 813 : TyTy::BaseType *prev_segment = tyseg;
333 : 813 : bool reciever_is_generic = prev_segment->get_kind () == TyTy::TypeKind::PARAM;
334 : :
335 : 1624 : for (size_t i = offset; i < segments.size (); i++)
336 : : {
337 : 813 : HIR::PathExprSegment &seg = segments.at (i);
338 : 813 : bool probe_impls = !reciever_is_generic;
339 : :
340 : : // probe the path is done in two parts one where we search impls if no
341 : : // candidate is found then we search extensions from traits
342 : 813 : auto candidates
343 : 813 : = PathProbeType::Probe (prev_segment, seg.get_segment (), probe_impls,
344 : : false /*probe_bounds*/,
345 : 813 : true /*ignore_mandatory_trait_items*/);
346 : 813 : if (candidates.size () == 0)
347 : : {
348 : 188 : candidates
349 : 188 : = PathProbeType::Probe (prev_segment, seg.get_segment (), false,
350 : : true /*probe_bounds*/,
351 : 188 : false /*ignore_mandatory_trait_items*/);
352 : :
353 : 188 : if (candidates.size () == 0)
354 : : {
355 : 0 : rust_error_at (
356 : : seg.get_locus (),
357 : : "failed to resolve path segment using an impl Probe");
358 : 0 : return;
359 : : }
360 : : }
361 : :
362 : 813 : if (candidates.size () > 1)
363 : : {
364 : 1 : ReportMultipleCandidateError::Report (candidates, seg.get_segment (),
365 : : seg.get_locus ());
366 : 1 : return;
367 : : }
368 : :
369 : 812 : auto &candidate = *candidates.begin ();
370 : 812 : prev_segment = tyseg;
371 : 812 : tyseg = candidate.ty;
372 : :
373 : 812 : HIR::ImplBlock *associated_impl_block = nullptr;
374 : 812 : if (candidate.is_enum_candidate ())
375 : : {
376 : 1 : const TyTy::VariantDef *variant = candidate.item.enum_field.variant;
377 : :
378 : 1 : HirId variant_id = variant->get_id ();
379 : 1 : std::pair<HIR::Enum *, HIR::EnumItem *> enum_item_lookup
380 : 1 : = mappings->lookup_hir_enumitem (variant_id);
381 : 2 : bool enum_item_ok = enum_item_lookup.first != nullptr
382 : 1 : && enum_item_lookup.second != nullptr;
383 : 0 : rust_assert (enum_item_ok);
384 : :
385 : 1 : HIR::EnumItem *enum_item = enum_item_lookup.second;
386 : 1 : resolved_node_id = enum_item->get_mappings ().get_nodeid ();
387 : :
388 : : // insert the id of the variant we are resolved to
389 : 1 : context->insert_variant_definition (expr_mappings.get_hirid (),
390 : : variant_id);
391 : : }
392 : 811 : else if (candidate.is_impl_candidate ())
393 : : {
394 : 623 : resolved_node_id
395 : 623 : = candidate.item.impl.impl_item->get_impl_mappings ().get_nodeid ();
396 : :
397 : 623 : associated_impl_block = candidate.item.impl.parent;
398 : : }
399 : : else
400 : : {
401 : 188 : resolved_node_id
402 : 188 : = candidate.item.trait.item_ref->get_mappings ().get_nodeid ();
403 : :
404 : : // lookup the associated-impl-trait
405 : 188 : HIR::ImplBlock *impl = candidate.item.trait.impl;
406 : 188 : if (impl != nullptr)
407 : : {
408 : : // get the associated impl block
409 : : associated_impl_block = impl;
410 : : }
411 : : }
412 : :
413 : 624 : if (associated_impl_block != nullptr)
414 : : {
415 : : // associated types
416 : 679 : HirId impl_block_id
417 : 679 : = associated_impl_block->get_mappings ().get_hirid ();
418 : :
419 : 679 : AssociatedImplTrait *associated = nullptr;
420 : 679 : bool found_impl_trait
421 : 679 : = context->lookup_associated_trait_impl (impl_block_id,
422 : : &associated);
423 : :
424 : 679 : auto mappings = TyTy::SubstitutionArgumentMappings::error ();
425 : 679 : TyTy::BaseType *impl_block_ty
426 : 679 : = TypeCheckItem::ResolveImplBlockSelfWithInference (
427 : : *associated_impl_block, seg.get_locus (), &mappings);
428 : :
429 : : // we need to apply the arguments to the segment type so they get
430 : : // unified properly
431 : 679 : if (!mappings.is_error ())
432 : 112 : tyseg = SubstMapperInternal::Resolve (tyseg, mappings);
433 : :
434 : 679 : prev_segment = unify_site (seg.get_mappings ().get_hirid (),
435 : : TyTy::TyWithLocation (prev_segment),
436 : : TyTy::TyWithLocation (impl_block_ty),
437 : : seg.get_locus ());
438 : 679 : bool ok = prev_segment->get_kind () != TyTy::TypeKind::ERROR;
439 : 679 : if (!ok)
440 : 1 : return;
441 : :
442 : 678 : if (found_impl_trait)
443 : : {
444 : : // we need to setup with apropriate bounds
445 : 131 : HIR::TypePath &bound_path
446 : 131 : = *associated->get_impl_block ()->get_trait_ref ().get ();
447 : 131 : const auto &trait_ref = *TraitResolver::Resolve (bound_path);
448 : 131 : rust_assert (!trait_ref.is_error ());
449 : :
450 : 131 : const auto &predicate
451 : 131 : = impl_block_ty->lookup_predicate (trait_ref.get_defid ());
452 : 131 : if (!predicate.is_error ())
453 : 116 : impl_block_ty
454 : 116 : = associated->setup_associated_types (prev_segment,
455 : : predicate);
456 : 131 : }
457 : 679 : }
458 : :
459 : 811 : if (seg.has_generic_args ())
460 : : {
461 : 45 : rust_debug_loc (seg.get_locus (), "applying segment generics: %s",
462 : 45 : tyseg->as_string ().c_str ());
463 : 45 : tyseg
464 : 90 : = SubstMapper::Resolve (tyseg, expr_locus, &seg.get_generic_args (),
465 : 45 : context->regions_from_generic_args (
466 : 45 : seg.get_generic_args ()));
467 : 45 : if (tyseg->get_kind () == TyTy::TypeKind::ERROR)
468 : : return;
469 : : }
470 : 766 : else if (tyseg->needs_generic_substitutions () && !reciever_is_generic)
471 : : {
472 : 100 : location_t locus = seg.get_locus ();
473 : 100 : tyseg = SubstMapper::InferSubst (tyseg, locus);
474 : 100 : if (tyseg->get_kind () == TyTy::TypeKind::ERROR)
475 : : return;
476 : : }
477 : 813 : }
478 : :
479 : 811 : rust_assert (resolved_node_id != UNKNOWN_NODEID);
480 : 811 : if (tyseg->needs_generic_substitutions () && !reciever_is_generic)
481 : : {
482 : 0 : location_t locus = segments.back ().get_locus ();
483 : 0 : tyseg = SubstMapper::InferSubst (tyseg, locus);
484 : 0 : if (tyseg->get_kind () == TyTy::TypeKind::ERROR)
485 : : return;
486 : : }
487 : :
488 : 811 : context->insert_receiver (expr_mappings.get_hirid (), prev_segment);
489 : :
490 : : // name scope first
491 : 811 : if (resolver->get_name_scope ().decl_was_declared_here (resolved_node_id))
492 : : {
493 : 810 : resolver->insert_resolved_name (expr_mappings.get_nodeid (),
494 : : resolved_node_id);
495 : : }
496 : : // check the type scope
497 : 1 : else if (resolver->get_type_scope ().decl_was_declared_here (
498 : : resolved_node_id))
499 : : {
500 : 0 : resolver->insert_resolved_type (expr_mappings.get_nodeid (),
501 : : resolved_node_id);
502 : : }
503 : : else
504 : : {
505 : 1 : resolver->insert_resolved_misc (expr_mappings.get_nodeid (),
506 : : resolved_node_id);
507 : : }
508 : :
509 : 811 : infered = tyseg;
510 : : }
511 : :
512 : : } // namespace Resolver
513 : : } // namespace Rust
|