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