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 : #ifndef RUST_AST_PATH_H
20 : #define RUST_AST_PATH_H
21 : /* "Path" (identifier within namespaces, essentially) handling. Required include
22 : * for virtually all AST-related functionality. */
23 :
24 : #include "optional.h"
25 : #include "rust-ast.h"
26 : #include "rust-hir-map.h"
27 : #include "rust-mapping-common.h"
28 : #include "rust-system.h"
29 : #include "system.h"
30 :
31 : namespace Rust {
32 : namespace AST {
33 :
34 : // The "identifier" (not generic args) aspect of each path expression segment
35 2542263 : class PathIdentSegment
36 : {
37 : std::string segment_name;
38 : location_t locus;
39 :
40 : // only allow identifiers, "super", "self", "Self", "crate", or "$crate"
41 : public:
42 620979 : PathIdentSegment (std::string segment_name, location_t locus)
43 626208 : : segment_name (std::move (segment_name)), locus (locus)
44 : {}
45 :
46 : // Creates an error PathIdentSegment.
47 11 : static PathIdentSegment create_error ()
48 : {
49 11 : return PathIdentSegment ("", UNDEF_LOCATION);
50 : }
51 :
52 : // Returns whether PathIdentSegment is in an error state.
53 497434 : bool is_error () const { return segment_name.empty (); }
54 :
55 1076113 : std::string as_string () const { return segment_name; }
56 :
57 368871 : location_t get_locus () const { return locus; }
58 :
59 40536 : bool is_super_path_seg () const
60 : {
61 81072 : return as_string ().compare ("super") == 0;
62 : }
63 40535 : bool is_crate_path_seg () const
64 : {
65 81070 : return as_string ().compare ("crate") == 0;
66 : }
67 705014 : bool is_lower_self_seg () const { return as_string ().compare ("self") == 0; }
68 323928 : bool is_big_self_seg () const { return as_string ().compare ("Self") == 0; }
69 : };
70 :
71 : // A binding of an identifier to a type used in generic arguments in paths
72 : struct GenericArgsBinding
73 : {
74 : public:
75 : enum class Kind
76 : {
77 : Equality,
78 : Constraint
79 : };
80 :
81 : private:
82 : Identifier identifier;
83 : std::unique_ptr<Type> type;
84 : location_t locus;
85 : Kind kind;
86 :
87 : public:
88 : // Returns whether binding is in an error state.
89 511 : bool is_error () const
90 : {
91 511 : return type == nullptr;
92 : // and also identifier is empty, but cheaper computation
93 : }
94 :
95 0 : GenericArgsBinding reconstruct () const
96 : {
97 0 : std::unique_ptr<Type> new_type = nullptr;
98 0 : if (type)
99 0 : new_type = type->reconstruct ();
100 :
101 0 : return GenericArgsBinding (identifier, std::move (new_type), locus, kind);
102 0 : }
103 :
104 : // Creates an error state generic args binding.
105 0 : static GenericArgsBinding create_error ()
106 : {
107 0 : return GenericArgsBinding ({""}, nullptr);
108 : }
109 :
110 : // Pointer type for type in constructor to enable polymorphism
111 511 : GenericArgsBinding (Identifier ident, std::unique_ptr<Type> type_ptr,
112 : location_t locus = UNDEF_LOCATION,
113 : Kind kind = Kind::Equality)
114 511 : : identifier (std::move (ident)), type (std::move (type_ptr)),
115 511 : locus (locus), kind (kind)
116 : {}
117 :
118 : // Copy constructor has to deep copy the type as it is a unique pointer
119 2117 : GenericArgsBinding (GenericArgsBinding const &other)
120 2117 : : identifier (other.identifier), locus (other.locus), kind (other.kind)
121 : {
122 : // guard to protect from null pointer dereference
123 2117 : if (other.type != nullptr)
124 2117 : type = other.type->clone_type ();
125 2117 : }
126 :
127 : // default destructor
128 2635 : ~GenericArgsBinding () = default;
129 :
130 : // Overload assignment operator to deep copy the pointed-to type
131 : GenericArgsBinding &operator= (GenericArgsBinding const &other)
132 : {
133 : identifier = other.identifier;
134 : locus = other.locus;
135 : kind = other.kind;
136 :
137 : // guard to protect from null pointer dereference
138 : if (other.type != nullptr)
139 : type = other.type->clone_type ();
140 : else
141 : type = nullptr;
142 :
143 : return *this;
144 : }
145 :
146 : // move constructors
147 520 : GenericArgsBinding (GenericArgsBinding &&other) = default;
148 : GenericArgsBinding &operator= (GenericArgsBinding &&other) = default;
149 :
150 : std::string as_string () const;
151 :
152 : // TODO: is this better? Or is a "vis_pattern" better?
153 60041 : Type &get_type ()
154 : {
155 60041 : rust_assert (type != nullptr);
156 60041 : return *type;
157 : }
158 :
159 24679 : std::unique_ptr<Type> &get_type_ptr ()
160 : {
161 24679 : rust_assert (type != nullptr);
162 24679 : return type;
163 : }
164 :
165 145 : location_t get_locus () const { return locus; }
166 :
167 145 : Identifier get_identifier () const { return identifier; }
168 186 : Kind get_kind () const { return kind; }
169 : };
170 :
171 : /* Class representing a const generic application */
172 : class GenericArg
173 : {
174 : public:
175 : /**
176 : * const generic arguments cannot always be differentiated with generic type
177 : * arguments during parsing, e.g:
178 : * ```rust
179 : * let a: Foo<N>;
180 : * ```
181 : *
182 : * Is N a type? A constant defined elsewhere? The parser cannot know, and must
183 : * not draw any conclusions. We must wait until later passes of the compiler
184 : * to decide whether this refers to a constant item or a type.
185 : *
186 : * On the other hand, simple expressions like literals or block expressions
187 : * will always be constant expressions: There is no ambiguity at all.
188 : */
189 : enum class Kind
190 : {
191 : Const, // A const value
192 : Type, // A type argument (not discernable during parsing)
193 : Either, // Either a type or a const value, cleared up during resolving
194 : };
195 :
196 188 : static GenericArg create_const (std::unique_ptr<Expr> expression)
197 : {
198 188 : auto locus = expression->get_locus ();
199 188 : return GenericArg (std::move (expression), nullptr, {""}, Kind::Const,
200 376 : locus);
201 : }
202 :
203 20018 : static GenericArg create_type (std::unique_ptr<Type> type)
204 : {
205 20018 : auto locus = type->get_locus ();
206 60054 : return GenericArg (nullptr, std::move (type), {""}, Kind::Type, locus);
207 : }
208 :
209 16236 : static GenericArg create_ambiguous (Identifier path, location_t locus)
210 : {
211 32472 : return GenericArg (nullptr, nullptr, std::move (path), Kind::Either, locus);
212 : }
213 :
214 8 : GenericArg reconstruct () const
215 : {
216 8 : switch (kind)
217 : {
218 1 : case Kind::Type:
219 1 : return create_type (type->reconstruct ());
220 0 : case Kind::Const:
221 : // FIXME: Use reconstruct_expr when available
222 0 : return create_const (expression->clone_expr ());
223 7 : case Kind::Either:
224 7 : default:
225 : // For ambiguous or error states, copy constructs are sufficient
226 7 : return GenericArg (*this);
227 : }
228 : }
229 :
230 126845 : GenericArg (const GenericArg &other)
231 126845 : : path (other.path), kind (other.kind), locus (other.locus)
232 : {
233 126845 : if (other.expression)
234 274 : expression = other.expression->clone_expr ();
235 126845 : if (other.type)
236 44647 : type = other.type->clone_type ();
237 126845 : }
238 :
239 : GenericArg operator= (const GenericArg &other)
240 : {
241 : kind = other.kind;
242 : path = other.path;
243 : locus = other.locus;
244 :
245 : if (other.expression)
246 : expression = other.expression->clone_expr ();
247 : if (other.type)
248 : type = other.type->clone_type ();
249 :
250 : return *this;
251 : }
252 :
253 49091 : GenericArg (GenericArg &&other) = default;
254 12464 : GenericArg &operator= (GenericArg &&other) = default;
255 :
256 3986636 : Kind get_kind () const { return kind; }
257 1 : location_t get_locus () const { return locus; }
258 :
259 2185503 : void accept_vis (AST::ASTVisitor &visitor)
260 : {
261 2185503 : switch (get_kind ())
262 : {
263 2720 : case Kind::Const:
264 2720 : get_expression ().accept_vis (visitor);
265 2720 : break;
266 702322 : case Kind::Type:
267 702322 : get_type ().accept_vis (visitor);
268 702322 : break;
269 : case Kind::Either:
270 : break;
271 : }
272 2185503 : }
273 :
274 3545 : Expr &get_expression ()
275 : {
276 3545 : rust_assert (kind == Kind::Const);
277 :
278 3545 : return *expression;
279 : }
280 :
281 323 : std::unique_ptr<Expr> &get_expression_ptr ()
282 : {
283 323 : rust_assert (kind == Kind::Const);
284 :
285 323 : return expression;
286 : }
287 :
288 1073598 : Type &get_type ()
289 : {
290 1073598 : rust_assert (kind == Kind::Type);
291 :
292 1073598 : return *type;
293 : }
294 :
295 157255 : std::unique_ptr<Type> &get_type_ptr ()
296 : {
297 157255 : rust_assert (kind == Kind::Type);
298 :
299 157255 : return type;
300 : }
301 :
302 24933 : const std::string get_path () const
303 : {
304 24933 : rust_assert (kind == Kind::Either);
305 :
306 24933 : return path.as_string ();
307 : }
308 :
309 0 : std::string as_string () const
310 : {
311 0 : switch (get_kind ())
312 : {
313 0 : case Kind::Either:
314 0 : return "Ambiguous: " + path.as_string ();
315 0 : case Kind::Const:
316 0 : return "Const: { " + expression->as_string () + " }";
317 0 : case Kind::Type:
318 0 : return "Type: " + type->as_string ();
319 : }
320 :
321 0 : return "";
322 : }
323 :
324 : /**
325 : * Disambiguate an ambiguous generic argument to a const generic argument,
326 : * unequivocally
327 : */
328 : GenericArg disambiguate_to_const () const;
329 :
330 : /**
331 : * Disambiguate an ambiguous generic argument to a type argument,
332 : * unequivocally
333 : */
334 : GenericArg disambiguate_to_type () const;
335 :
336 : private:
337 36442 : GenericArg (std::unique_ptr<Expr> expression, std::unique_ptr<Type> type,
338 : Identifier path, Kind kind, location_t locus)
339 16790 : : expression (std::move (expression)), type (std::move (type)),
340 36442 : path (std::move (path)), kind (kind), locus (locus)
341 : {}
342 :
343 : /**
344 : * Expression associated with a `Clear` const generic application
345 : * A null pointer here is allowed in the case that the const argument is
346 : * ambiguous.
347 : */
348 : std::unique_ptr<Expr> expression;
349 :
350 : /**
351 : * If the argument ends up being a type argument instead. A null pointer will
352 : * be present here until the resolving phase.
353 : */
354 : std::unique_ptr<Type> type;
355 :
356 : /**
357 : * Optional path which cannot be differentiated between a constant item and
358 : * a type. Only used for ambiguous const generic arguments, otherwise
359 : * empty.
360 : */
361 : Identifier path;
362 :
363 : /* Which kind of const generic application are we dealing with */
364 : Kind kind;
365 :
366 : location_t locus;
367 : };
368 :
369 : /**
370 : * Representation of const generic parameters
371 : */
372 : class ConstGenericParam : public GenericParam
373 : {
374 : /* Name of the parameter */
375 : Identifier name;
376 :
377 : /* Mandatory type of the const parameter - a null pointer is an error */
378 : std::unique_ptr<AST::Type> type;
379 :
380 : /**
381 : * Default value for the const generic parameter
382 : */
383 : tl::optional<GenericArg> default_value;
384 :
385 : AST::AttrVec outer_attrs;
386 : location_t locus;
387 :
388 : public:
389 207 : ConstGenericParam (Identifier name, std::unique_ptr<AST::Type> type,
390 : tl::optional<GenericArg> default_value,
391 : AST::AttrVec outer_attrs, location_t locus)
392 207 : : name (name), type (std::move (type)),
393 207 : default_value (std::move (default_value)), outer_attrs (outer_attrs),
394 207 : locus (locus)
395 207 : {}
396 :
397 467 : ConstGenericParam (const ConstGenericParam &other)
398 467 : : GenericParam (), name (other.name), type (other.type->clone_type ()),
399 467 : default_value (other.default_value), outer_attrs (other.outer_attrs),
400 467 : locus (other.locus)
401 467 : {}
402 :
403 16790 : bool has_type () const { return type != nullptr; }
404 16983 : bool has_default_value () const { return default_value.has_value (); }
405 :
406 3113 : const Identifier &get_name () const { return name; }
407 :
408 16892 : AST::AttrVec &get_outer_attrs () { return outer_attrs; }
409 :
410 13691 : AST::Type &get_type ()
411 : {
412 13691 : rust_assert (has_type ());
413 :
414 13691 : return *type;
415 : }
416 :
417 3099 : std::unique_ptr<AST::Type> &get_type_ptr ()
418 : {
419 3099 : rust_assert (has_type ());
420 :
421 3099 : return type;
422 : }
423 :
424 402 : GenericArg &get_default_value_unchecked ()
425 : {
426 402 : rust_assert (has_default_value ());
427 :
428 402 : return default_value.value ();
429 : }
430 :
431 0 : const GenericArg &get_default_value_unchecked () const
432 : {
433 0 : rust_assert (has_default_value ());
434 :
435 0 : return default_value.value ();
436 : }
437 :
438 7 : tl::optional<GenericArg> &get_default_value () { return default_value; }
439 :
440 : const tl::optional<GenericArg> &get_default_value () const
441 : {
442 : return default_value;
443 : }
444 :
445 : std::string as_string () const override;
446 :
447 : void accept_vis (ASTVisitor &vis) override;
448 :
449 3291 : location_t get_locus () const override final { return locus; }
450 :
451 607 : Kind get_kind () const override final { return Kind::Const; }
452 :
453 : protected:
454 : /* Use covariance to implement clone function as returning this object rather
455 : * than base */
456 467 : ConstGenericParam *clone_generic_param_impl () const override
457 : {
458 467 : return new ConstGenericParam (*this);
459 : }
460 : };
461 :
462 : // Generic arguments allowed in each path expression segment - inline?
463 : struct GenericArgs
464 : {
465 : std::vector<Lifetime> lifetime_args;
466 : std::vector<GenericArg> generic_args;
467 : std::vector<GenericArgsBinding> binding_args;
468 : location_t locus;
469 :
470 : public:
471 : // Returns true if there are any generic arguments
472 39933936 : bool has_generic_args () const
473 : {
474 39543691 : return !(lifetime_args.empty () && generic_args.empty ()
475 35784106 : && binding_args.empty ());
476 : }
477 :
478 472600 : GenericArgs (std::vector<Lifetime> lifetime_args,
479 : std::vector<GenericArg> generic_args,
480 : std::vector<GenericArgsBinding> binding_args,
481 : location_t locus = UNDEF_LOCATION)
482 472600 : : lifetime_args (std::move (lifetime_args)),
483 472600 : generic_args (std::move (generic_args)),
484 472600 : binding_args (std::move (binding_args)), locus (locus)
485 472600 : {}
486 :
487 : // copy constructor with vector clone
488 1031077 : GenericArgs (GenericArgs const &other)
489 1031077 : : lifetime_args (other.lifetime_args), binding_args (other.binding_args),
490 1031077 : locus (other.locus)
491 : {
492 1031077 : generic_args.clear ();
493 1031077 : generic_args.reserve (other.generic_args.size ());
494 1156964 : for (const auto &arg : other.generic_args)
495 125887 : generic_args.emplace_back (arg);
496 1031077 : }
497 :
498 2320873 : ~GenericArgs () = default;
499 :
500 246 : GenericArgs reconstruct () const
501 : {
502 246 : std::vector<GenericArg> new_args;
503 246 : new_args.reserve (generic_args.size ());
504 254 : for (const auto &arg : generic_args)
505 8 : new_args.push_back (arg.reconstruct ());
506 :
507 246 : std::vector<GenericArgsBinding> new_bindings;
508 246 : new_bindings.reserve (binding_args.size ());
509 246 : for (const auto &binding : binding_args)
510 0 : new_bindings.push_back (binding.reconstruct ());
511 :
512 : // Lifetimes are values, so they can be copied directly
513 246 : return GenericArgs (lifetime_args, std::move (new_args),
514 246 : std::move (new_bindings), locus);
515 246 : }
516 :
517 : // overloaded assignment operator to vector clone
518 : GenericArgs &operator= (GenericArgs const &other)
519 : {
520 : lifetime_args = other.lifetime_args;
521 : binding_args = other.binding_args;
522 : locus = other.locus;
523 :
524 : generic_args.clear ();
525 : generic_args.reserve (other.generic_args.size ());
526 : for (const auto &arg : other.generic_args)
527 : generic_args.emplace_back (arg);
528 :
529 : return *this;
530 : }
531 :
532 : // move constructors
533 1001154 : GenericArgs (GenericArgs &&other) = default;
534 : GenericArgs &operator= (GenericArgs &&other) = default;
535 :
536 : // Creates an empty GenericArgs (no arguments)
537 447156 : static GenericArgs create_empty () { return GenericArgs ({}, {}, {}); }
538 :
539 : std::string as_string () const;
540 :
541 4071391 : std::vector<GenericArg> &get_generic_args () { return generic_args; }
542 :
543 4071406 : std::vector<GenericArgsBinding> &get_binding_args () { return binding_args; }
544 :
545 : const std::vector<GenericArgsBinding> &get_binding_args () const
546 : {
547 : return binding_args;
548 : }
549 :
550 1693230 : std::vector<Lifetime> &get_lifetime_args () { return lifetime_args; };
551 :
552 : const std::vector<Lifetime> &get_lifetime_args () const
553 : {
554 : return lifetime_args;
555 : };
556 :
557 5097 : location_t get_locus () const { return locus; }
558 : };
559 :
560 : /* A segment of a path in expression, including an identifier aspect and maybe
561 : * generic args */
562 1502502 : class PathExprSegment
563 : { // or should this extend PathIdentSegment?
564 : private:
565 : PathIdentSegment segment_name;
566 : GenericArgs generic_args;
567 : location_t locus;
568 : NodeId node_id;
569 :
570 : public:
571 : // Returns true if there are any generic arguments
572 51154973 : bool has_generic_args () const { return generic_args.has_generic_args (); }
573 :
574 : // Constructor for segment (from IdentSegment and GenericArgs)
575 449006 : PathExprSegment (PathIdentSegment segment_name, location_t locus,
576 : GenericArgs generic_args = GenericArgs::create_empty ())
577 449006 : : segment_name (std::move (segment_name)),
578 449006 : generic_args (std::move (generic_args)), locus (locus),
579 449006 : node_id (Analysis::Mappings::get ().get_next_node_id ())
580 449006 : {}
581 :
582 : /* Constructor for segment with generic arguments (from segment name and all
583 : * args) */
584 578 : PathExprSegment (std::string segment_name, location_t locus,
585 : std::vector<Lifetime> lifetime_args = {},
586 : std::vector<GenericArg> generic_args = {},
587 : std::vector<GenericArgsBinding> binding_args = {})
588 578 : : segment_name (PathIdentSegment (std::move (segment_name), locus)),
589 578 : generic_args (GenericArgs (std::move (lifetime_args),
590 : std::move (generic_args),
591 578 : std::move (binding_args))),
592 578 : locus (locus), node_id (Analysis::Mappings::get ().get_next_node_id ())
593 578 : {}
594 :
595 : // Returns whether path expression segment is in an error state.
596 496909 : bool is_error () const { return segment_name.is_error (); }
597 :
598 : // Creates an error-state path expression segment.
599 11 : static PathExprSegment create_error ()
600 : {
601 11 : return PathExprSegment (PathIdentSegment::create_error (), UNDEF_LOCATION);
602 : }
603 :
604 : std::string as_string () const;
605 :
606 98497 : location_t get_locus () const { return locus; }
607 :
608 : // TODO: is this better? Or is a "vis_pattern" better?
609 153106 : GenericArgs &get_generic_args ()
610 : {
611 153106 : rust_assert (has_generic_args ());
612 153106 : return generic_args;
613 : }
614 :
615 21196481 : PathIdentSegment &get_ident_segment () { return segment_name; }
616 437075 : const PathIdentSegment &get_ident_segment () const { return segment_name; }
617 :
618 172411 : NodeId get_node_id () const { return node_id; }
619 :
620 238 : PathExprSegment reconstruct () const
621 : {
622 238 : return PathExprSegment (segment_name, locus, generic_args.reconstruct ());
623 : }
624 :
625 : bool is_super_path_seg () const
626 : {
627 : return !has_generic_args () && get_ident_segment ().is_super_path_seg ();
628 : }
629 :
630 : bool is_crate_path_seg () const
631 : {
632 : return !has_generic_args () && get_ident_segment ().is_crate_path_seg ();
633 : }
634 :
635 314046 : bool is_lower_self_seg () const
636 : {
637 627553 : return !has_generic_args () && get_ident_segment ().is_lower_self_seg ();
638 : }
639 : };
640 :
641 : // AST node representing a pattern that involves a "path" - abstract base
642 : // class
643 : class Path : public Pattern
644 : {
645 : public:
646 : enum class Kind
647 : {
648 : LangItem,
649 : Regular,
650 : };
651 :
652 392058 : Path (std::vector<PathExprSegment> segments)
653 392058 : : segments (std::move (segments)), lang_item (tl::nullopt),
654 392058 : kind (Kind::Regular)
655 : {}
656 :
657 2221 : Path (LangItem::Kind lang_item)
658 2221 : : segments ({}), lang_item (lang_item), kind (Kind::LangItem)
659 2221 : {}
660 :
661 : // Returns whether path has segments.
662 104147 : bool has_segments () const
663 : {
664 104147 : rust_assert (kind == Kind::Regular);
665 104147 : return !segments.empty ();
666 : }
667 :
668 : /* Converts path segments to their equivalent SimplePath segments if
669 : * possible, and creates a SimplePath from them. */
670 : SimplePath convert_to_simple_path (bool with_opening_scope_resolution) const;
671 :
672 : /* Returns whether the path is a single segment (excluding qualified path
673 : * initial as segment). */
674 548739 : bool is_single_segment () const
675 : {
676 548739 : rust_assert (kind == Kind::Regular);
677 548739 : return segments.size () == 1;
678 : }
679 :
680 : std::string as_string () const override;
681 :
682 19927637 : bool is_lang_item () const { return kind == Kind::LangItem; }
683 :
684 : // TODO: this seems kinda dodgy
685 20291483 : std::vector<PathExprSegment> &get_segments ()
686 : {
687 20291483 : rust_assert (kind == Kind::Regular);
688 20291483 : return segments;
689 : }
690 102159 : const std::vector<PathExprSegment> &get_segments () const
691 : {
692 102159 : rust_assert (kind == Kind::Regular);
693 102159 : return segments;
694 : }
695 :
696 2104 : LangItem::Kind get_lang_item () const
697 : {
698 2104 : rust_assert (kind == Kind::LangItem);
699 2104 : return *lang_item;
700 : }
701 :
702 24759 : Pattern::Kind get_pattern_kind () override { return Pattern::Kind::Path; }
703 : Path::Kind get_path_kind () { return kind; }
704 :
705 : protected:
706 : std::vector<PathExprSegment> segments;
707 : tl::optional<LangItem::Kind> lang_item;
708 :
709 : Path::Kind kind;
710 : };
711 :
712 : /* AST node representing a path-in-expression pattern (path that allows
713 : * generic arguments) */
714 : class PathInExpression : public Path, public ExprWithoutBlock
715 : {
716 : std::vector<Attribute> outer_attrs;
717 : bool has_opening_scope_resolution;
718 : location_t locus;
719 : NodeId _node_id;
720 :
721 : bool marked_for_strip;
722 :
723 : public:
724 : std::string as_string () const override;
725 :
726 : // Constructor
727 391815 : PathInExpression (std::vector<PathExprSegment> path_segments,
728 : std::vector<Attribute> outer_attrs, location_t locus,
729 : bool has_opening_scope_resolution = false)
730 391815 : : Path (std::move (path_segments)), outer_attrs (std::move (outer_attrs)),
731 391815 : has_opening_scope_resolution (has_opening_scope_resolution),
732 391815 : locus (locus), _node_id (Analysis::Mappings::get ().get_next_node_id ()),
733 391815 : marked_for_strip (false)
734 391815 : {}
735 :
736 2221 : PathInExpression (LangItem::Kind lang_item,
737 : std::vector<Attribute> outer_attrs, location_t locus)
738 2221 : : Path (lang_item), outer_attrs (std::move (outer_attrs)),
739 2221 : has_opening_scope_resolution (false), locus (locus),
740 2221 : _node_id (Analysis::Mappings::get ().get_next_node_id ()),
741 2221 : marked_for_strip (false)
742 2221 : {}
743 :
744 : // Creates an error state path in expression.
745 11 : static PathInExpression create_error ()
746 : {
747 11 : return PathInExpression (std::vector<PathExprSegment> (), {},
748 22 : UNDEF_LOCATION);
749 : }
750 :
751 : // Returns whether path in expression is in an error state.
752 48555 : bool is_error () const { return !has_segments (); }
753 :
754 : /* Converts PathInExpression to SimplePath if possible (i.e. no generic
755 : * arguments). Otherwise returns an empty SimplePath. */
756 55592 : SimplePath as_simple_path () const
757 : {
758 : /* delegate to parent class as can't access segments. however,
759 : * QualifiedPathInExpression conversion to simple path wouldn't make
760 : * sense, so the method in the parent class should be protected, not
761 : * public. Have to pass in opening scope resolution as parent class has no
762 : * access to it.
763 : */
764 55592 : return convert_to_simple_path (has_opening_scope_resolution);
765 : }
766 :
767 119 : std::unique_ptr<PathInExpression> reconstruct () const
768 : {
769 119 : std::vector<PathExprSegment> new_segments;
770 119 : new_segments.reserve (segments.size ());
771 357 : for (const auto &seg : segments)
772 476 : new_segments.push_back (seg.reconstruct ());
773 :
774 119 : auto *new_path
775 119 : = new PathInExpression (std::move (new_segments), outer_attrs, locus,
776 119 : has_opening_scope_resolution);
777 :
778 119 : return std::unique_ptr<PathInExpression> (new_path);
779 119 : }
780 :
781 289816 : location_t get_locus () const override final { return locus; }
782 :
783 : void accept_vis (ASTVisitor &vis) override;
784 :
785 0 : void mark_for_strip () override { marked_for_strip = true; }
786 5901263 : bool is_marked_for_strip () const override { return marked_for_strip; }
787 :
788 157330 : bool opening_scope_resolution () const
789 : {
790 157330 : return has_opening_scope_resolution;
791 : }
792 :
793 2601098 : NodeId get_node_id () const override { return _node_id; }
794 :
795 : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
796 23520205 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
797 :
798 29788 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
799 : {
800 29788 : outer_attrs = std::move (new_attrs);
801 0 : }
802 :
803 : PathExprSegment &get_final_segment () { return get_segments ().back (); }
804 : const PathExprSegment &get_final_segment () const
805 : {
806 : return get_segments ().back ();
807 : }
808 :
809 101812 : Expr::Kind get_expr_kind () const override
810 : {
811 101812 : return Expr::Kind::PathInExpression;
812 : }
813 :
814 : protected:
815 : /* Use covariance to implement clone function as returning this object
816 : * rather than base */
817 5180 : PathInExpression *clone_pattern_impl () const final override
818 : {
819 5180 : return clone_path_in_expression_impl ();
820 : }
821 :
822 : /* Use covariance to implement clone function as returning this object
823 : * rather than base */
824 0 : PathInExpression *clone_expr_without_block_impl () const final override
825 : {
826 0 : return clone_path_in_expression_impl ();
827 : }
828 :
829 597834 : /*virtual*/ PathInExpression *clone_path_in_expression_impl () const
830 : {
831 597834 : return new PathInExpression (*this);
832 : }
833 : };
834 :
835 : /* Base class for segments used in type paths - not abstract (represents an
836 : * ident-only segment) */
837 : class TypePathSegment
838 : {
839 : public:
840 : enum SegmentType
841 : {
842 : REG,
843 : GENERIC,
844 : FUNCTION
845 : };
846 :
847 : private:
848 : tl::optional<LangItem::Kind> lang_item;
849 : PathIdentSegment ident_segment;
850 : location_t locus;
851 :
852 : protected:
853 : /* This is protected because it is only really used by derived classes, not
854 : * the base. */
855 : bool has_separating_scope_resolution;
856 : NodeId node_id;
857 :
858 : public:
859 : // Clone function implementation - not pure virtual as overrided by
860 : // subclasses
861 522895 : virtual TypePathSegment *clone_type_path_segment_impl () const
862 : {
863 522895 : return new TypePathSegment (*this);
864 : }
865 209 : virtual TypePathSegment *reconstruct_impl () const
866 : {
867 418 : return new TypePathSegment (lang_item, ident_segment,
868 209 : has_separating_scope_resolution, locus);
869 : }
870 :
871 : public:
872 535530 : virtual ~TypePathSegment () {}
873 :
874 113 : virtual SegmentType get_type () const { return SegmentType::REG; }
875 :
876 : // Unique pointer custom clone function
877 614103 : std::unique_ptr<TypePathSegment> clone_type_path_segment () const
878 : {
879 614103 : return std::unique_ptr<TypePathSegment> (clone_type_path_segment_impl ());
880 : }
881 : // Unique pointer custom reconstruct function
882 0 : std::unique_ptr<TypePathSegment> reconstruct () const
883 : {
884 0 : return reconstruct_base (this);
885 : }
886 :
887 150021 : TypePathSegment (PathIdentSegment ident_segment,
888 : bool has_separating_scope_resolution, location_t locus)
889 300042 : : lang_item (tl::nullopt), ident_segment (std::move (ident_segment)),
890 150021 : locus (locus),
891 150021 : has_separating_scope_resolution (has_separating_scope_resolution),
892 150021 : node_id (Analysis::Mappings::get ().get_next_node_id ())
893 150021 : {}
894 :
895 1522 : TypePathSegment (LangItem::Kind lang_item, PathIdentSegment ident_segment,
896 : location_t locus)
897 3044 : : lang_item (lang_item), ident_segment (ident_segment), locus (locus),
898 1522 : has_separating_scope_resolution (false),
899 1522 : node_id (Analysis::Mappings::get ().get_next_node_id ())
900 1522 : {}
901 :
902 20134 : TypePathSegment (std::string segment_name,
903 : bool has_separating_scope_resolution, location_t locus)
904 20134 : : lang_item (tl::nullopt),
905 20134 : ident_segment (PathIdentSegment (std::move (segment_name), locus)),
906 20134 : locus (locus),
907 20134 : has_separating_scope_resolution (has_separating_scope_resolution),
908 40268 : node_id (Analysis::Mappings::get ().get_next_node_id ())
909 20134 : {}
910 :
911 : // General constructor
912 209 : TypePathSegment (tl::optional<LangItem::Kind> lang_item,
913 : PathIdentSegment ident_segment,
914 : bool has_separating_scope_resolution, location_t locus)
915 418 : : lang_item (lang_item), ident_segment (ident_segment), locus (locus),
916 209 : has_separating_scope_resolution (has_separating_scope_resolution),
917 209 : node_id (Analysis::Mappings::get ().get_next_node_id ())
918 209 : {}
919 :
920 639491 : TypePathSegment (TypePathSegment const &other)
921 639491 : : lang_item (other.lang_item), ident_segment (other.ident_segment),
922 639491 : locus (other.locus),
923 639491 : has_separating_scope_resolution (other.has_separating_scope_resolution),
924 639491 : node_id (other.node_id)
925 639491 : {}
926 :
927 : TypePathSegment &operator= (TypePathSegment const &other)
928 : {
929 : ident_segment = other.ident_segment;
930 : lang_item = other.lang_item;
931 : locus = other.locus;
932 : has_separating_scope_resolution = other.has_separating_scope_resolution;
933 : node_id = other.node_id;
934 :
935 : return *this;
936 : }
937 :
938 : TypePathSegment (TypePathSegment &&other) = default;
939 : TypePathSegment &operator= (TypePathSegment &&other) = default;
940 :
941 2574 : virtual std::string as_string () const
942 : {
943 2574 : if (lang_item.has_value ())
944 0 : return LangItem::PrettyString (*lang_item);
945 :
946 2574 : return ident_segment.as_string ();
947 : }
948 :
949 : /* Returns whether the type path segment is in an error state. May be
950 : * virtual in future. */
951 525 : bool is_error () const { return ident_segment.is_error (); }
952 :
953 : /* Returns whether segment is identifier only (as opposed to generic args or
954 : * function). Overridden in derived classes with other segments. */
955 498 : virtual bool is_ident_only () const { return true; }
956 :
957 463973 : bool is_lang_item () const { return lang_item.has_value (); }
958 :
959 4319 : location_t get_locus () const { return locus; }
960 :
961 : // not pure virtual as class not abstract
962 : virtual void accept_vis (ASTVisitor &vis);
963 :
964 62761 : bool get_separating_scope_resolution () const
965 : {
966 62761 : return has_separating_scope_resolution;
967 : }
968 :
969 516762 : PathIdentSegment &get_ident_segment () { return ident_segment; };
970 :
971 44 : const PathIdentSegment &get_ident_segment () const { return ident_segment; };
972 :
973 3213 : LangItem::Kind get_lang_item () const
974 : {
975 3213 : rust_assert (is_lang_item ());
976 3213 : return *lang_item;
977 : }
978 :
979 208540 : NodeId get_node_id () const { return node_id; }
980 :
981 : bool is_crate_path_seg () const
982 : {
983 : return get_ident_segment ().is_crate_path_seg ();
984 : }
985 : bool is_super_path_seg () const
986 : {
987 : return get_ident_segment ().is_super_path_seg ();
988 : }
989 : bool is_big_self_seg () const
990 : {
991 : return get_ident_segment ().is_big_self_seg ();
992 : }
993 : bool is_lower_self_seg () const
994 : {
995 : return get_ident_segment ().is_lower_self_seg ();
996 : }
997 : };
998 :
999 : // Segment used in type path with generic args
1000 : class TypePathSegmentGeneric : public TypePathSegment
1001 : {
1002 : GenericArgs generic_args;
1003 :
1004 : public:
1005 15 : SegmentType get_type () const override { return SegmentType::GENERIC; }
1006 :
1007 7433626 : bool has_generic_args () const { return generic_args.has_generic_args (); }
1008 :
1009 0 : bool is_ident_only () const override { return false; }
1010 :
1011 : // Constructor with PathIdentSegment and GenericArgs
1012 21639 : TypePathSegmentGeneric (PathIdentSegment ident_segment,
1013 : bool has_separating_scope_resolution,
1014 : GenericArgs generic_args, location_t locus)
1015 : : TypePathSegment (std::move (ident_segment),
1016 : has_separating_scope_resolution, locus),
1017 21639 : generic_args (std::move (generic_args))
1018 21639 : {}
1019 :
1020 135 : TypePathSegmentGeneric (LangItem::Kind lang_item,
1021 : PathIdentSegment ident_segment,
1022 : GenericArgs generic_args, location_t locus)
1023 : : TypePathSegment (lang_item, ident_segment, locus),
1024 135 : generic_args (std::move (generic_args))
1025 135 : {}
1026 :
1027 : // Constructor from segment name and all args
1028 : TypePathSegmentGeneric (std::string segment_name,
1029 : bool has_separating_scope_resolution,
1030 : std::vector<Lifetime> lifetime_args,
1031 : std::vector<GenericArg> generic_args,
1032 : std::vector<GenericArgsBinding> binding_args,
1033 : location_t locus)
1034 : : TypePathSegment (std::move (segment_name),
1035 : has_separating_scope_resolution, locus),
1036 : generic_args (GenericArgs (std::move (lifetime_args),
1037 : std::move (generic_args),
1038 : std::move (binding_args)))
1039 : {}
1040 :
1041 : // Copy constructor with vector clone
1042 114693 : TypePathSegmentGeneric (TypePathSegmentGeneric const &other)
1043 114693 : : TypePathSegment (other), generic_args (other.generic_args)
1044 114693 : {}
1045 :
1046 : // Overloaded assignment operator with vector clone
1047 : TypePathSegmentGeneric &operator= (TypePathSegmentGeneric const &other)
1048 : {
1049 : generic_args = other.generic_args;
1050 :
1051 : return *this;
1052 : }
1053 :
1054 : // move constructors
1055 : TypePathSegmentGeneric (TypePathSegmentGeneric &&other) = default;
1056 : TypePathSegmentGeneric &operator= (TypePathSegmentGeneric &&other) = default;
1057 :
1058 : std::string as_string () const override;
1059 :
1060 : void accept_vis (ASTVisitor &vis) override;
1061 :
1062 : // TODO: is this better? Or is a "vis_pattern" better?
1063 3914998 : GenericArgs &get_generic_args () { return generic_args; }
1064 :
1065 : // Use covariance to override base class method
1066 114693 : TypePathSegmentGeneric *clone_type_path_segment_impl () const override
1067 : {
1068 114693 : return new TypePathSegmentGeneric (*this);
1069 : }
1070 :
1071 8 : TypePathSegmentGeneric *reconstruct_impl () const override
1072 : {
1073 8 : return new TypePathSegmentGeneric (get_ident_segment (),
1074 8 : has_separating_scope_resolution,
1075 24 : generic_args.reconstruct (),
1076 8 : get_locus ());
1077 : }
1078 : };
1079 :
1080 : // A function as represented in a type path
1081 : struct TypePathFunction
1082 : {
1083 : private:
1084 : // TODO: remove
1085 : /*bool has_inputs;
1086 : TypePathFnInputs inputs;*/
1087 : // inlined from TypePathFnInputs
1088 : std::vector<std::unique_ptr<Type>> inputs;
1089 :
1090 : // bool has_type;
1091 : std::unique_ptr<Type> return_type;
1092 :
1093 : // FIXME: think of better way to mark as invalid than taking up storage
1094 : bool is_invalid;
1095 :
1096 : location_t locus;
1097 :
1098 : protected:
1099 : // Constructor only used to create invalid type path functions.
1100 0 : TypePathFunction (bool is_invalid, location_t locus)
1101 0 : : is_invalid (is_invalid), locus (locus)
1102 : {}
1103 :
1104 : public:
1105 : // Returns whether the return type of the function has been specified.
1106 179221 : bool has_return_type () const { return return_type != nullptr; }
1107 :
1108 : // Returns whether the function has inputs.
1109 28 : bool has_inputs () const { return !inputs.empty (); }
1110 :
1111 : // Returns whether function is in an error state.
1112 179834 : bool is_error () const { return is_invalid; }
1113 :
1114 : // Creates an error state function.
1115 0 : static TypePathFunction create_error ()
1116 : {
1117 0 : return TypePathFunction (true, UNDEF_LOCATION);
1118 : }
1119 :
1120 : // Constructor
1121 613 : TypePathFunction (std::vector<std::unique_ptr<Type>> inputs, location_t locus,
1122 : std::unique_ptr<Type> type = nullptr)
1123 613 : : inputs (std::move (inputs)), return_type (std::move (type)),
1124 613 : is_invalid (false), locus (locus)
1125 : {}
1126 :
1127 : // Copy constructor with clone
1128 1903 : TypePathFunction (TypePathFunction const &other)
1129 1903 : : is_invalid (other.is_invalid)
1130 : {
1131 : // guard to protect from null pointer dereference
1132 1903 : if (other.return_type != nullptr)
1133 1825 : return_type = other.return_type->clone_type ();
1134 :
1135 1903 : inputs.reserve (other.inputs.size ());
1136 4503 : for (const auto &e : other.inputs)
1137 2600 : inputs.push_back (e->clone_type ());
1138 1903 : }
1139 :
1140 613 : ~TypePathFunction () = default;
1141 :
1142 : // Overloaded assignment operator to clone type
1143 : TypePathFunction &operator= (TypePathFunction const &other)
1144 : {
1145 : is_invalid = other.is_invalid;
1146 :
1147 : // guard to protect from null pointer dereference
1148 : if (other.return_type != nullptr)
1149 : return_type = other.return_type->clone_type ();
1150 : else
1151 : return_type = nullptr;
1152 :
1153 : inputs.reserve (other.inputs.size ());
1154 : for (const auto &e : other.inputs)
1155 : inputs.push_back (e->clone_type ());
1156 :
1157 : return *this;
1158 : }
1159 :
1160 : // move constructors
1161 613 : TypePathFunction (TypePathFunction &&other) = default;
1162 : TypePathFunction &operator= (TypePathFunction &&other) = default;
1163 :
1164 : std::string as_string () const;
1165 :
1166 : // TODO: this mutable getter seems really dodgy. Think up better way.
1167 : const std::vector<std::unique_ptr<Type>> &get_params () const
1168 : {
1169 : return inputs;
1170 : }
1171 179220 : std::vector<std::unique_ptr<Type>> &get_params () { return inputs; }
1172 :
1173 : // TODO: is this better? Or is a "vis_pattern" better?
1174 137896 : Type &get_return_type ()
1175 : {
1176 137896 : rust_assert (has_return_type ());
1177 137896 : return *return_type;
1178 : }
1179 :
1180 35325 : std::unique_ptr<Type> &get_return_type_ptr ()
1181 : {
1182 35325 : rust_assert (has_return_type ());
1183 35325 : return return_type;
1184 : }
1185 :
1186 0 : TypePathFunction reconstruct () const
1187 : {
1188 0 : std::vector<std::unique_ptr<Type>> new_inputs;
1189 0 : new_inputs.reserve (inputs.size ());
1190 0 : for (const auto &e : inputs)
1191 0 : new_inputs.push_back (e->reconstruct ());
1192 :
1193 0 : std::unique_ptr<Type> new_ret = nullptr;
1194 0 : if (return_type)
1195 0 : new_ret = return_type->reconstruct ();
1196 :
1197 0 : return TypePathFunction (std::move (new_inputs), locus,
1198 0 : std::move (new_ret));
1199 0 : }
1200 :
1201 28 : location_t get_locus () const { return locus; }
1202 : };
1203 :
1204 : // Segment used in type path with a function argument
1205 : class TypePathSegmentFunction : public TypePathSegment
1206 : {
1207 : TypePathFunction function_path;
1208 :
1209 : public:
1210 77 : SegmentType get_type () const override { return SegmentType::FUNCTION; }
1211 :
1212 : // Constructor with PathIdentSegment and TypePathFn
1213 613 : TypePathSegmentFunction (PathIdentSegment ident_segment,
1214 : bool has_separating_scope_resolution,
1215 : TypePathFunction function_path, location_t locus)
1216 : : TypePathSegment (std::move (ident_segment),
1217 : has_separating_scope_resolution, locus),
1218 613 : function_path (std::move (function_path))
1219 613 : {}
1220 :
1221 : // Constructor with segment name and TypePathFn
1222 : TypePathSegmentFunction (std::string segment_name,
1223 : bool has_separating_scope_resolution,
1224 : TypePathFunction function_path, location_t locus)
1225 : : TypePathSegment (std::move (segment_name),
1226 : has_separating_scope_resolution, locus),
1227 : function_path (std::move (function_path))
1228 : {}
1229 :
1230 : std::string as_string () const override;
1231 :
1232 28 : bool is_ident_only () const override { return false; }
1233 :
1234 : void accept_vis (ASTVisitor &vis) override;
1235 :
1236 : // TODO: is this better? Or is a "vis_pattern" better?
1237 179221 : TypePathFunction &get_type_path_function ()
1238 : {
1239 179221 : rust_assert (!function_path.is_error ());
1240 179221 : return function_path;
1241 : }
1242 :
1243 : // Use covariance to override base class method
1244 1903 : TypePathSegmentFunction *clone_type_path_segment_impl () const override
1245 : {
1246 1903 : return new TypePathSegmentFunction (*this);
1247 : }
1248 :
1249 0 : TypePathSegmentFunction *reconstruct_impl () const override
1250 : {
1251 0 : return new TypePathSegmentFunction (get_ident_segment (),
1252 0 : has_separating_scope_resolution,
1253 0 : function_path.reconstruct (),
1254 0 : get_locus ());
1255 : }
1256 : };
1257 :
1258 230993 : class TypePath : public TypeNoBounds
1259 : {
1260 : bool has_opening_scope_resolution;
1261 : std::vector<std::unique_ptr<TypePathSegment>> segments;
1262 : location_t locus;
1263 :
1264 : protected:
1265 : /* Use covariance to implement clone function as returning this object
1266 : * rather than base */
1267 447885 : TypePath *clone_type_no_bounds_impl () const override
1268 : {
1269 447885 : return new TypePath (*this);
1270 : }
1271 215 : TypePath *reconstruct_impl () const override
1272 : {
1273 1075 : return new TypePath (reconstruct_vec (segments), locus,
1274 430 : has_opening_scope_resolution);
1275 : }
1276 :
1277 : public:
1278 : /* Returns whether the TypePath has an opening scope resolution operator
1279 : * (i.e. is global path or crate-relative path, not module-relative) */
1280 258519 : bool has_opening_scope_resolution_op () const
1281 : {
1282 258519 : return has_opening_scope_resolution;
1283 : }
1284 :
1285 : // Returns whether the TypePath is in an invalid state.
1286 2112983 : bool is_error () const { return segments.empty (); }
1287 :
1288 : // Creates an error state TypePath.
1289 4034 : static TypePath create_error ()
1290 : {
1291 12102 : return TypePath (std::vector<std::unique_ptr<TypePathSegment>> (),
1292 4034 : UNDEF_LOCATION);
1293 : }
1294 :
1295 : // Constructor
1296 164041 : TypePath (std::vector<std::unique_ptr<TypePathSegment>> segments,
1297 : location_t locus, bool has_opening_scope_resolution = false)
1298 : : TypeNoBounds (),
1299 164041 : has_opening_scope_resolution (has_opening_scope_resolution),
1300 164041 : segments (std::move (segments)), locus (locus)
1301 : {}
1302 :
1303 0 : TypePath (LangItem::Kind lang_item,
1304 : std::vector<std::unique_ptr<TypePathSegment>> segments,
1305 : location_t locus, bool has_opening_scope_resolution = false)
1306 : : TypeNoBounds (),
1307 0 : has_opening_scope_resolution (has_opening_scope_resolution),
1308 0 : segments (std::move (segments)), locus (locus)
1309 : {}
1310 :
1311 : // Copy constructor with vector clone
1312 581529 : TypePath (TypePath const &other)
1313 : : TypeNoBounds (other),
1314 581529 : has_opening_scope_resolution (other.has_opening_scope_resolution),
1315 581529 : locus (other.locus)
1316 : {
1317 581529 : segments.reserve (other.segments.size ());
1318 1195632 : for (const auto &e : other.segments)
1319 614103 : segments.push_back (e->clone_type_path_segment ());
1320 581529 : }
1321 :
1322 : // Overloaded assignment operator with clone
1323 : TypePath &operator= (TypePath const &other)
1324 : {
1325 : TypeNoBounds::operator= (other);
1326 : has_opening_scope_resolution = other.has_opening_scope_resolution;
1327 : locus = other.locus;
1328 :
1329 : segments.reserve (other.segments.size ());
1330 : for (const auto &e : other.segments)
1331 : segments.push_back (e->clone_type_path_segment ());
1332 :
1333 : return *this;
1334 : }
1335 :
1336 : // move constructors
1337 142536 : TypePath (TypePath &&other) = default;
1338 3746 : TypePath &operator= (TypePath &&other) = default;
1339 :
1340 : std::string as_string () const override;
1341 :
1342 : std::string make_debug_string () const;
1343 :
1344 : /* Converts TypePath to SimplePath if possible (i.e. no generic or function
1345 : * arguments). Otherwise returns an empty SimplePath. */
1346 : SimplePath as_simple_path () const;
1347 :
1348 : // Creates a trait bound with a clone of this type path as its only element.
1349 : TraitBound *to_trait_bound (bool in_parens) const override;
1350 :
1351 178945 : location_t get_locus () const override final { return locus; }
1352 2415508 : NodeId get_node_id () const override { return node_id; }
1353 :
1354 0 : void mark_for_strip () override {}
1355 4330331 : bool is_marked_for_strip () const override { return false; }
1356 :
1357 : void accept_vis (ASTVisitor &vis) override;
1358 :
1359 : // TODO: this seems kinda dodgy
1360 60889 : std::vector<std::unique_ptr<TypePathSegment>> &get_segments ()
1361 : {
1362 18939751 : return segments;
1363 : }
1364 136690 : const std::vector<std::unique_ptr<TypePathSegment>> &get_segments () const
1365 : {
1366 136725 : return segments;
1367 : }
1368 :
1369 : size_t get_num_segments () const { return segments.size (); }
1370 :
1371 1491 : Type::Kind get_type_kind () const override { return Type::Kind::TypePath; }
1372 : };
1373 :
1374 : struct QualifiedPathType
1375 : {
1376 : private:
1377 : std::unique_ptr<Type> type_to_invoke_on;
1378 : TypePath trait_path;
1379 : location_t locus;
1380 : NodeId node_id;
1381 :
1382 : public:
1383 : // Constructor
1384 3824 : QualifiedPathType (std::unique_ptr<Type> invoke_on_type,
1385 : location_t locus = UNDEF_LOCATION,
1386 : TypePath trait_path = TypePath::create_error ())
1387 3824 : : type_to_invoke_on (std::move (invoke_on_type)), trait_path (trait_path),
1388 3824 : locus (locus), node_id (Analysis::Mappings::get ().get_next_node_id ())
1389 3824 : {}
1390 :
1391 : // Copy constructor uses custom deep copy for Type to preserve polymorphism
1392 26377 : QualifiedPathType (QualifiedPathType const &other)
1393 26377 : : trait_path (other.trait_path), locus (other.locus)
1394 : {
1395 26377 : node_id = other.node_id;
1396 : // guard to prevent null dereference
1397 26377 : if (other.type_to_invoke_on != nullptr)
1398 26377 : type_to_invoke_on = other.type_to_invoke_on->clone_type ();
1399 26377 : }
1400 :
1401 : // default destructor
1402 37789 : ~QualifiedPathType () = default;
1403 :
1404 : // overload assignment operator to use custom clone method
1405 : QualifiedPathType &operator= (QualifiedPathType const &other)
1406 : {
1407 : node_id = other.node_id;
1408 : trait_path = other.trait_path;
1409 : locus = other.locus;
1410 :
1411 : // guard to prevent null dereference
1412 : if (other.type_to_invoke_on != nullptr)
1413 : type_to_invoke_on = other.type_to_invoke_on->clone_type ();
1414 : else
1415 : type_to_invoke_on = nullptr;
1416 :
1417 : return *this;
1418 : }
1419 :
1420 : // move constructor
1421 11412 : QualifiedPathType (QualifiedPathType &&other) = default;
1422 0 : QualifiedPathType &operator= (QualifiedPathType &&other) = default;
1423 :
1424 0 : QualifiedPathType reconstruct () const
1425 : {
1426 0 : auto new_type = type_to_invoke_on->reconstruct ();
1427 :
1428 : // trait_path is stored by value, but reconstruct returns a unique_ptr.
1429 : // We must dereference it to pass to the constructor.
1430 : // This is safe because the constructor makes its own copy/move.
1431 0 : auto new_trait_path_ptr = trait_path.reconstruct ();
1432 0 : TypePath *concrete_ptr
1433 0 : = static_cast<TypePath *> (new_trait_path_ptr.get ());
1434 :
1435 0 : return QualifiedPathType (std::move (new_type), locus, *concrete_ptr);
1436 0 : }
1437 :
1438 : // Returns whether the qualified path type has a rebind as clause.
1439 1002298 : bool has_as_clause () const { return !trait_path.is_error (); }
1440 :
1441 : // Returns whether the qualified path type is in an error state.
1442 1016734 : bool is_error () const { return type_to_invoke_on == nullptr; }
1443 :
1444 : // Creates an error state qualified path type.
1445 0 : static QualifiedPathType create_error ()
1446 : {
1447 0 : return QualifiedPathType (nullptr);
1448 : }
1449 :
1450 : std::string as_string () const;
1451 :
1452 985 : location_t get_locus () const { return locus; }
1453 :
1454 : // TODO: is this better? Or is a "vis_pattern" better?
1455 784782 : Type &get_type ()
1456 : {
1457 784782 : rust_assert (type_to_invoke_on != nullptr);
1458 784782 : return *type_to_invoke_on;
1459 : }
1460 :
1461 217516 : std::unique_ptr<Type> &get_type_ptr ()
1462 : {
1463 217516 : rust_assert (type_to_invoke_on != nullptr);
1464 217516 : return type_to_invoke_on;
1465 : }
1466 :
1467 : // TODO: is this better? Or is a "vis_pattern" better?
1468 968356 : TypePath &get_as_type_path ()
1469 : {
1470 968356 : rust_assert (has_as_clause ());
1471 968356 : return trait_path;
1472 : }
1473 :
1474 371 : NodeId get_node_id () const { return node_id; }
1475 : };
1476 :
1477 : /* AST node representing a qualified path-in-expression pattern (path that
1478 : * allows specifying trait functions) */
1479 : class QualifiedPathInExpression : public Path, public ExprWithoutBlock
1480 : {
1481 : std::vector<Attribute> outer_attrs;
1482 : QualifiedPathType path_type;
1483 : location_t locus;
1484 : NodeId _node_id;
1485 :
1486 : public:
1487 : std::string as_string () const override;
1488 :
1489 243 : QualifiedPathInExpression (QualifiedPathType qual_path_type,
1490 : std::vector<PathExprSegment> path_segments,
1491 : std::vector<Attribute> outer_attrs,
1492 : location_t locus)
1493 243 : : Path (std::move (path_segments)), outer_attrs (std::move (outer_attrs)),
1494 243 : path_type (std::move (qual_path_type)), locus (locus),
1495 243 : _node_id (Analysis::Mappings::get ().get_next_node_id ())
1496 243 : {}
1497 :
1498 : /* TODO: maybe make a shortcut constructor that has QualifiedPathType
1499 : * elements as params */
1500 :
1501 : // Returns whether qualified path in expression is in an error state.
1502 10642 : bool is_error () const { return path_type.is_error (); }
1503 :
1504 : // Creates an error qualified path in expression.
1505 0 : static QualifiedPathInExpression create_error ()
1506 : {
1507 0 : return QualifiedPathInExpression (QualifiedPathType::create_error (), {},
1508 0 : {}, UNDEF_LOCATION);
1509 : }
1510 :
1511 409 : location_t get_locus () const override final { return locus; }
1512 :
1513 : void accept_vis (ASTVisitor &vis) override;
1514 :
1515 : // Invalid if path_type is error, so base stripping on that.
1516 0 : void mark_for_strip () override
1517 : {
1518 0 : path_type = QualifiedPathType::create_error ();
1519 0 : }
1520 10642 : bool is_marked_for_strip () const override { return is_error (); }
1521 :
1522 : // TODO: is this better? Or is a "vis_pattern" better?
1523 45191 : QualifiedPathType &get_qualified_path_type ()
1524 : {
1525 45191 : rust_assert (!path_type.is_error ());
1526 45191 : return path_type;
1527 : }
1528 :
1529 : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
1530 53554 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
1531 :
1532 213 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
1533 : {
1534 213 : outer_attrs = std::move (new_attrs);
1535 0 : }
1536 :
1537 3868 : NodeId get_node_id () const override { return _node_id; }
1538 :
1539 243 : Expr::Kind get_expr_kind () const override
1540 : {
1541 243 : return Expr::Kind::QualifiedPathInExpression;
1542 : }
1543 :
1544 : std::unique_ptr<QualifiedPathInExpression> reconstruct () const
1545 : {
1546 : std::vector<PathExprSegment> new_segments;
1547 : new_segments.reserve (segments.size ());
1548 : for (const auto &seg : segments)
1549 : new_segments.push_back (seg.reconstruct ());
1550 :
1551 : auto *new_path = new QualifiedPathInExpression (path_type.reconstruct (),
1552 : std::move (new_segments),
1553 : outer_attrs, locus);
1554 :
1555 : return std::unique_ptr<QualifiedPathInExpression> (new_path);
1556 : }
1557 :
1558 : protected:
1559 : /* Use covariance to implement clone function as returning this object
1560 : * rather than base */
1561 0 : QualifiedPathInExpression *clone_pattern_impl () const final override
1562 : {
1563 0 : return clone_qual_path_in_expression_impl ();
1564 : }
1565 :
1566 : /* Use covariance to implement clone function as returning this object
1567 : * rather than base */
1568 : QualifiedPathInExpression *
1569 0 : clone_expr_without_block_impl () const final override
1570 : {
1571 0 : return clone_qual_path_in_expression_impl ();
1572 : }
1573 :
1574 : /*virtual*/ QualifiedPathInExpression *
1575 959 : clone_qual_path_in_expression_impl () const
1576 : {
1577 959 : return new QualifiedPathInExpression (*this);
1578 : }
1579 : };
1580 :
1581 : /* Represents a qualified path in a type; used for disambiguating trait
1582 : * function calls */
1583 : class QualifiedPathInType : public TypeNoBounds
1584 : {
1585 : QualifiedPathType path_type;
1586 : std::unique_ptr<TypePathSegment> associated_segment;
1587 : std::vector<std::unique_ptr<TypePathSegment>> segments;
1588 : location_t locus;
1589 :
1590 : protected:
1591 : /* Use covariance to implement clone function as returning this object
1592 : * rather than base */
1593 25388 : QualifiedPathInType *clone_type_no_bounds_impl () const override
1594 : {
1595 25388 : return new QualifiedPathInType (*this);
1596 : }
1597 0 : QualifiedPathInType *reconstruct_impl () const override
1598 : {
1599 0 : return new QualifiedPathInType (path_type.reconstruct (),
1600 0 : associated_segment->reconstruct (),
1601 0 : reconstruct_vec (segments), locus);
1602 : }
1603 :
1604 : public:
1605 3581 : QualifiedPathInType (
1606 : QualifiedPathType qual_path_type,
1607 : std::unique_ptr<TypePathSegment> associated_segment,
1608 : std::vector<std::unique_ptr<TypePathSegment>> path_segments,
1609 : location_t locus)
1610 3581 : : path_type (std::move (qual_path_type)),
1611 3581 : associated_segment (std::move (associated_segment)),
1612 3581 : segments (std::move (path_segments)), locus (locus)
1613 3581 : {}
1614 :
1615 : // Copy constructor with vector clone
1616 25388 : QualifiedPathInType (QualifiedPathInType const &other)
1617 25388 : : path_type (other.path_type), locus (other.locus)
1618 : {
1619 25388 : auto seg = other.associated_segment->clone_type_path_segment_impl ();
1620 25388 : associated_segment = std::unique_ptr<TypePathSegment> (seg);
1621 :
1622 25388 : segments.reserve (other.segments.size ());
1623 25388 : for (const auto &e : other.segments)
1624 0 : segments.push_back (e->clone_type_path_segment ());
1625 25388 : }
1626 :
1627 : // Overloaded assignment operator with vector clone
1628 : QualifiedPathInType &operator= (QualifiedPathInType const &other)
1629 : {
1630 : auto seg = other.associated_segment->clone_type_path_segment_impl ();
1631 : associated_segment = std::unique_ptr<TypePathSegment> (seg);
1632 :
1633 : path_type = other.path_type;
1634 : locus = other.locus;
1635 :
1636 : segments.reserve (other.segments.size ());
1637 : for (const auto &e : other.segments)
1638 : segments.push_back (e->clone_type_path_segment ());
1639 :
1640 : return *this;
1641 : }
1642 :
1643 : // move constructors
1644 3581 : QualifiedPathInType (QualifiedPathInType &&other) = default;
1645 : QualifiedPathInType &operator= (QualifiedPathInType &&other) = default;
1646 :
1647 : // Returns whether qualified path in type is in an error state.
1648 3581 : bool is_error () const { return path_type.is_error (); }
1649 :
1650 : // Creates an error state qualified path in type.
1651 0 : static QualifiedPathInType create_error ()
1652 : {
1653 0 : return QualifiedPathInType (
1654 0 : QualifiedPathType::create_error (), nullptr,
1655 0 : std::vector<std::unique_ptr<TypePathSegment>> (), UNDEF_LOCATION);
1656 : }
1657 :
1658 : std::string as_string () const override;
1659 :
1660 : void accept_vis (ASTVisitor &vis) override;
1661 :
1662 : // TODO: is this better? Or is a "vis_pattern" better?
1663 957848 : QualifiedPathType &get_qualified_path_type ()
1664 : {
1665 957848 : rust_assert (!path_type.is_error ());
1666 957848 : return path_type;
1667 : }
1668 :
1669 : std::unique_ptr<TypePathSegment> &get_associated_segment ()
1670 : {
1671 647823 : return associated_segment;
1672 : }
1673 :
1674 : // TODO: this seems kinda dodgy
1675 : std::vector<std::unique_ptr<TypePathSegment>> &get_segments ()
1676 : {
1677 750941 : return segments;
1678 : }
1679 : const std::vector<std::unique_ptr<TypePathSegment>> &get_segments () const
1680 : {
1681 : return segments;
1682 : }
1683 :
1684 275 : location_t get_locus () const override final { return locus; }
1685 :
1686 0 : Type::Kind get_type_kind () const override
1687 : {
1688 0 : return Type::Kind::QualifiedPathInType;
1689 : }
1690 : };
1691 : } // namespace AST
1692 : } // namespace Rust
1693 :
1694 : #endif
|