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 2365193 : 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 578172 : PathIdentSegment (std::string segment_name, location_t locus)
43 584892 : : segment_name (std::move (segment_name)), locus (locus)
44 : {}
45 :
46 : // Creates an error PathIdentSegment.
47 9 : static PathIdentSegment create_error ()
48 : {
49 9 : return PathIdentSegment ("", UNDEF_LOCATION);
50 : }
51 :
52 : // Returns whether PathIdentSegment is in an error state.
53 470108 : bool is_error () const { return segment_name.empty (); }
54 :
55 1026403 : std::string as_string () const { return segment_name; }
56 :
57 351978 : location_t get_locus () const { return locus; }
58 :
59 37549 : bool is_super_path_seg () const
60 : {
61 75098 : return as_string ().compare ("super") == 0;
62 : }
63 37548 : bool is_crate_path_seg () const
64 : {
65 75096 : return as_string ().compare ("crate") == 0;
66 : }
67 674872 : bool is_lower_self_seg () const { return as_string ().compare ("self") == 0; }
68 309522 : 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 331 : bool is_error () const
82 : {
83 331 : 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 331 : GenericArgsBinding (Identifier ident, std::unique_ptr<Type> type_ptr,
104 : location_t locus = UNDEF_LOCATION)
105 331 : : 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 1468 : GenericArgsBinding (GenericArgsBinding const &other)
110 1468 : : identifier (other.identifier), locus (other.locus)
111 : {
112 : // guard to protect from null pointer dereference
113 1468 : if (other.type != nullptr)
114 1468 : type = other.type->clone_type ();
115 1468 : }
116 :
117 : // default destructor
118 1807 : ~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 339 : 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 45667 : Type &get_type ()
143 : {
144 45667 : rust_assert (type != nullptr);
145 45667 : return *type;
146 : }
147 :
148 18384 : std::unique_ptr<Type> &get_type_ptr ()
149 : {
150 18384 : rust_assert (type != nullptr);
151 18384 : return type;
152 : }
153 :
154 112 : location_t get_locus () const { return locus; }
155 :
156 112 : 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 186 : static GenericArg create_const (std::unique_ptr<Expr> expression)
185 : {
186 186 : auto locus = expression->get_locus ();
187 186 : return GenericArg (std::move (expression), nullptr, {""}, Kind::Const,
188 372 : locus);
189 : }
190 :
191 18297 : static GenericArg create_type (std::unique_ptr<Type> type)
192 : {
193 18297 : auto locus = type->get_locus ();
194 54891 : return GenericArg (nullptr, std::move (type), {""}, Kind::Type, locus);
195 : }
196 :
197 13641 : static GenericArg create_ambiguous (Identifier path, location_t locus)
198 : {
199 27282 : return GenericArg (nullptr, nullptr, std::move (path), Kind::Either, locus);
200 : }
201 :
202 3 : GenericArg reconstruct () const
203 : {
204 3 : 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 3 : case Kind::Either:
212 3 : default:
213 : // For ambiguous or error states, copy constructs are sufficient
214 3 : return GenericArg (*this);
215 : }
216 : }
217 :
218 111880 : GenericArg (const GenericArg &other)
219 111880 : : path (other.path), kind (other.kind), locus (other.locus)
220 : {
221 111880 : if (other.expression)
222 268 : expression = other.expression->clone_expr ();
223 111880 : if (other.type)
224 37988 : type = other.type->clone_type ();
225 111880 : }
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 39961 : GenericArg (GenericArg &&other) = default;
242 12335 : GenericArg &operator= (GenericArg &&other) = default;
243 :
244 3851161 : Kind get_kind () const { return kind; }
245 0 : location_t get_locus () const { return locus; }
246 :
247 2093966 : void accept_vis (AST::ASTVisitor &visitor)
248 : {
249 2093966 : switch (get_kind ())
250 : {
251 2681 : case Kind::Const:
252 2681 : get_expression ().accept_vis (visitor);
253 2681 : break;
254 674042 : case Kind::Type:
255 674042 : get_type ().accept_vis (visitor);
256 674042 : break;
257 : case Kind::Either:
258 : break;
259 : }
260 2093966 : }
261 :
262 3503 : Expr &get_expression ()
263 : {
264 3503 : rust_assert (kind == Kind::Const);
265 :
266 3503 : return *expression;
267 : }
268 :
269 323 : std::unique_ptr<Expr> &get_expression_ptr ()
270 : {
271 323 : rust_assert (kind == Kind::Const);
272 :
273 323 : return expression;
274 : }
275 :
276 1034527 : Type &get_type ()
277 : {
278 1034527 : rust_assert (kind == Kind::Type);
279 :
280 1034527 : return *type;
281 : }
282 :
283 153683 : std::unique_ptr<Type> &get_type_ptr ()
284 : {
285 153683 : rust_assert (kind == Kind::Type);
286 :
287 153683 : return type;
288 : }
289 :
290 24675 : const std::string get_path () const
291 : {
292 24675 : rust_assert (kind == Kind::Either);
293 :
294 24675 : 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 32124 : GenericArg (std::unique_ptr<Expr> expression, std::unique_ptr<Type> type,
326 : Identifier path, Kind kind, location_t locus)
327 14014 : : expression (std::move (expression)), type (std::move (type)),
328 32124 : 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 186 : ConstGenericParam (Identifier name, std::unique_ptr<AST::Type> type,
378 : tl::optional<GenericArg> default_value,
379 : AST::AttrVec outer_attrs, location_t locus)
380 186 : : name (name), type (std::move (type)),
381 186 : default_value (std::move (default_value)), outer_attrs (outer_attrs),
382 186 : locus (locus)
383 186 : {}
384 :
385 396 : ConstGenericParam (const ConstGenericParam &other)
386 396 : : GenericParam (), name (other.name), type (other.type->clone_type ()),
387 396 : default_value (other.default_value), outer_attrs (other.outer_attrs),
388 396 : locus (other.locus)
389 396 : {}
390 :
391 16284 : bool has_type () const { return type != nullptr; }
392 16456 : bool has_default_value () const { return default_value.has_value (); }
393 :
394 3028 : const Identifier &get_name () const { return name; }
395 :
396 16371 : AST::AttrVec &get_outer_attrs () { return outer_attrs; }
397 :
398 13270 : AST::Type &get_type ()
399 : {
400 13270 : rust_assert (has_type ());
401 :
402 13270 : return *type;
403 : }
404 :
405 3014 : std::unique_ptr<AST::Type> &get_type_ptr ()
406 : {
407 3014 : rust_assert (has_type ());
408 :
409 3014 : return type;
410 : }
411 :
412 361 : GenericArg &get_default_value_unchecked ()
413 : {
414 361 : rust_assert (has_default_value ());
415 :
416 361 : 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 7 : 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 3197 : location_t get_locus () const override final { return locus; }
438 :
439 544 : 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 396 : ConstGenericParam *clone_generic_param_impl () const override
445 : {
446 396 : 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 39012808 : bool has_generic_args () const
461 : {
462 38644751 : return !(lifetime_args.empty () && generic_args.empty ()
463 34992523 : && binding_args.empty ());
464 : }
465 :
466 443080 : 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 443080 : : lifetime_args (std::move (lifetime_args)),
471 443080 : generic_args (std::move (generic_args)),
472 443080 : binding_args (std::move (binding_args)), locus (locus)
473 443080 : {}
474 :
475 : // copy constructor with vector clone
476 972359 : GenericArgs (GenericArgs const &other)
477 972359 : : lifetime_args (other.lifetime_args), binding_args (other.binding_args),
478 972359 : locus (other.locus)
479 : {
480 972359 : generic_args.clear ();
481 972359 : generic_args.reserve (other.generic_args.size ());
482 1083547 : for (const auto &arg : other.generic_args)
483 111188 : generic_args.emplace_back (arg);
484 972359 : }
485 :
486 2183888 : ~GenericArgs () = default;
487 :
488 196 : GenericArgs reconstruct () const
489 : {
490 196 : std::vector<GenericArg> new_args;
491 196 : new_args.reserve (generic_args.size ());
492 199 : for (const auto &arg : generic_args)
493 3 : new_args.push_back (arg.reconstruct ());
494 :
495 196 : std::vector<GenericArgsBinding> new_bindings;
496 196 : new_bindings.reserve (binding_args.size ());
497 196 : 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 196 : return GenericArgs (lifetime_args, std::move (new_args),
502 196 : std::move (new_bindings), locus);
503 196 : }
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 935754 : GenericArgs (GenericArgs &&other) = default;
522 : GenericArgs &operator= (GenericArgs &&other) = default;
523 :
524 : // Creates an empty GenericArgs (no arguments)
525 421440 : static GenericArgs create_empty () { return GenericArgs ({}, {}, {}); }
526 :
527 : std::string as_string () const;
528 :
529 3942734 : std::vector<GenericArg> &get_generic_args () { return generic_args; }
530 :
531 3942745 : 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 1622877 : 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 4594 : 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 1420851 : 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 50065981 : bool has_generic_args () const { return generic_args.has_generic_args (); }
561 :
562 : // Constructor for segment (from IdentSegment and GenericArgs)
563 423034 : PathExprSegment (PathIdentSegment segment_name, location_t locus,
564 : GenericArgs generic_args = GenericArgs::create_empty ())
565 423034 : : segment_name (std::move (segment_name)),
566 423034 : generic_args (std::move (generic_args)), locus (locus),
567 423034 : node_id (Analysis::Mappings::get ().get_next_node_id ())
568 423034 : {}
569 :
570 : /* Constructor for segment with generic arguments (from segment name and all
571 : * args) */
572 514 : 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 514 : : segment_name (PathIdentSegment (std::move (segment_name), locus)),
577 514 : generic_args (GenericArgs (std::move (lifetime_args),
578 : std::move (generic_args),
579 514 : std::move (binding_args))),
580 514 : locus (locus), node_id (Analysis::Mappings::get ().get_next_node_id ())
581 514 : {}
582 :
583 : // Returns whether path expression segment is in an error state.
584 469583 : bool is_error () const { return segment_name.is_error (); }
585 :
586 : // Creates an error-state path expression segment.
587 9 : static PathExprSegment create_error ()
588 : {
589 9 : return PathExprSegment (PathIdentSegment::create_error (), UNDEF_LOCATION);
590 : }
591 :
592 : std::string as_string () const;
593 :
594 92687 : location_t get_locus () const { return locus; }
595 :
596 : // TODO: is this better? Or is a "vis_pattern" better?
597 144289 : GenericArgs &get_generic_args ()
598 : {
599 144289 : rust_assert (has_generic_args ());
600 144289 : return generic_args;
601 : }
602 :
603 20671057 : PathIdentSegment &get_ident_segment () { return segment_name; }
604 421285 : const PathIdentSegment &get_ident_segment () const { return segment_name; }
605 :
606 165638 : NodeId get_node_id () const { return node_id; }
607 :
608 192 : PathExprSegment reconstruct () const
609 : {
610 192 : 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 301496 : bool is_lower_self_seg () const
624 : {
625 602480 : 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 372435 : Path (std::vector<PathExprSegment> segments)
641 372435 : : segments (std::move (segments)), lang_item (tl::nullopt),
642 372435 : kind (Kind::Regular)
643 : {}
644 :
645 1732 : Path (LangItem::Kind lang_item)
646 1732 : : segments ({}), lang_item (lang_item), kind (Kind::LangItem)
647 1732 : {}
648 :
649 : // Returns whether path has segments.
650 130383 : bool has_segments () const
651 : {
652 130383 : rust_assert (kind == Kind::Regular);
653 130383 : 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 523917 : bool is_single_segment () const
663 : {
664 523917 : rust_assert (kind == Kind::Regular);
665 523917 : return segments.size () == 1;
666 : }
667 :
668 : std::string as_string () const override;
669 :
670 19542413 : bool is_lang_item () const { return kind == Kind::LangItem; }
671 :
672 : // TODO: this seems kinda dodgy
673 19894390 : std::vector<PathExprSegment> &get_segments ()
674 : {
675 19894390 : rust_assert (kind == Kind::Regular);
676 19894390 : return segments;
677 : }
678 100186 : const std::vector<PathExprSegment> &get_segments () const
679 : {
680 100186 : rust_assert (kind == Kind::Regular);
681 100186 : return segments;
682 : }
683 :
684 2012 : LangItem::Kind get_lang_item () const
685 : {
686 2012 : rust_assert (kind == Kind::LangItem);
687 2012 : return *lang_item;
688 : }
689 :
690 24440 : 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 372219 : PathInExpression (std::vector<PathExprSegment> path_segments,
716 : std::vector<Attribute> outer_attrs, location_t locus,
717 : bool has_opening_scope_resolution = false)
718 372219 : : Path (std::move (path_segments)), outer_attrs (std::move (outer_attrs)),
719 372219 : has_opening_scope_resolution (has_opening_scope_resolution),
720 372219 : locus (locus), _node_id (Analysis::Mappings::get ().get_next_node_id ()),
721 372219 : marked_for_strip (false)
722 372219 : {}
723 :
724 1732 : PathInExpression (LangItem::Kind lang_item,
725 : std::vector<Attribute> outer_attrs, location_t locus)
726 1732 : : Path (lang_item), outer_attrs (std::move (outer_attrs)),
727 1732 : has_opening_scope_resolution (false), locus (locus),
728 1732 : _node_id (Analysis::Mappings::get ().get_next_node_id ()),
729 1732 : marked_for_strip (false)
730 1732 : {}
731 :
732 : // Creates an error state path in expression.
733 9 : static PathInExpression create_error ()
734 : {
735 9 : return PathInExpression (std::vector<PathExprSegment> (), {},
736 18 : UNDEF_LOCATION);
737 : }
738 :
739 : // Returns whether path in expression is in an error state.
740 77111 : 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 53272 : 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 53272 : return convert_to_simple_path (has_opening_scope_resolution);
753 : }
754 :
755 96 : std::unique_ptr<PathInExpression> reconstruct () const
756 : {
757 96 : std::vector<PathExprSegment> new_segments;
758 96 : new_segments.reserve (segments.size ());
759 288 : for (const auto &seg : segments)
760 384 : new_segments.push_back (seg.reconstruct ());
761 :
762 96 : auto *new_path
763 96 : = new PathInExpression (std::move (new_segments), outer_attrs, locus,
764 96 : has_opening_scope_resolution);
765 :
766 96 : return std::unique_ptr<PathInExpression> (new_path);
767 96 : }
768 :
769 276570 : 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 5800748 : bool is_marked_for_strip () const override { return marked_for_strip; }
775 :
776 151576 : bool opening_scope_resolution () const
777 : {
778 151576 : return has_opening_scope_resolution;
779 : }
780 :
781 2574871 : NodeId get_node_id () const override { return _node_id; }
782 :
783 : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
784 23054723 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
785 :
786 26250 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
787 : {
788 26250 : 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 95570 : Expr::Kind get_expr_kind () const override
798 : {
799 95570 : return Expr::Kind::PathInExpression;
800 : }
801 :
802 : protected:
803 : /* Use covariance to implement clone function as returning this object
804 : * rather than base */
805 4651 : PathInExpression *clone_pattern_impl () const final override
806 : {
807 4651 : 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 575797 : /*virtual*/ PathInExpression *clone_path_in_expression_impl () const
818 : {
819 575797 : 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 : 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 473357 : virtual TypePathSegment *clone_type_path_segment_impl () const
850 : {
851 473357 : return new TypePathSegment (*this);
852 : }
853 174 : virtual TypePathSegment *reconstruct_impl () const
854 : {
855 348 : return new TypePathSegment (lang_item, ident_segment,
856 174 : has_separating_scope_resolution, locus);
857 : }
858 :
859 : public:
860 485431 : virtual ~TypePathSegment () {}
861 :
862 92 : virtual SegmentType get_type () const { return SegmentType::REG; }
863 :
864 : // Unique pointer custom clone function
865 553805 : std::unique_ptr<TypePathSegment> clone_type_path_segment () const
866 : {
867 553805 : 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 135308 : TypePathSegment (PathIdentSegment ident_segment,
876 : bool has_separating_scope_resolution, location_t locus)
877 270616 : : lang_item (tl::nullopt), ident_segment (std::move (ident_segment)),
878 135308 : locus (locus),
879 135308 : has_separating_scope_resolution (has_separating_scope_resolution),
880 135308 : node_id (Analysis::Mappings::get ().get_next_node_id ())
881 135308 : {}
882 :
883 1208 : TypePathSegment (LangItem::Kind lang_item, PathIdentSegment ident_segment,
884 : location_t locus)
885 2416 : : lang_item (lang_item), ident_segment (ident_segment), locus (locus),
886 1208 : has_separating_scope_resolution (false),
887 1208 : node_id (Analysis::Mappings::get ().get_next_node_id ())
888 1208 : {}
889 :
890 18323 : TypePathSegment (std::string segment_name,
891 : bool has_separating_scope_resolution, location_t locus)
892 18323 : : lang_item (tl::nullopt),
893 18323 : ident_segment (PathIdentSegment (std::move (segment_name), locus)),
894 18323 : locus (locus),
895 18323 : has_separating_scope_resolution (has_separating_scope_resolution),
896 36646 : node_id (Analysis::Mappings::get ().get_next_node_id ())
897 18323 : {}
898 :
899 : // General constructor
900 174 : TypePathSegment (tl::optional<LangItem::Kind> lang_item,
901 : PathIdentSegment ident_segment,
902 : bool has_separating_scope_resolution, location_t locus)
903 348 : : lang_item (lang_item), ident_segment (ident_segment), locus (locus),
904 174 : has_separating_scope_resolution (has_separating_scope_resolution),
905 174 : node_id (Analysis::Mappings::get ().get_next_node_id ())
906 174 : {}
907 :
908 579146 : TypePathSegment (TypePathSegment const &other)
909 579146 : : lang_item (other.lang_item), ident_segment (other.ident_segment),
910 579146 : locus (other.locus),
911 579146 : has_separating_scope_resolution (other.has_separating_scope_resolution),
912 579146 : node_id (other.node_id)
913 579146 : {}
914 :
915 : TypePathSegment &operator= (TypePathSegment const &other)
916 : {
917 : ident_segment = other.ident_segment;
918 : lang_item = other.lang_item;
919 : locus = other.locus;
920 : has_separating_scope_resolution = other.has_separating_scope_resolution;
921 : node_id = other.node_id;
922 :
923 : return *this;
924 : }
925 :
926 : TypePathSegment (TypePathSegment &&other) = default;
927 : TypePathSegment &operator= (TypePathSegment &&other) = default;
928 :
929 2565 : virtual std::string as_string () const
930 : {
931 2565 : if (lang_item.has_value ())
932 0 : return LangItem::PrettyString (*lang_item);
933 :
934 2565 : return ident_segment.as_string ();
935 : }
936 :
937 : /* Returns whether the type path segment is in an error state. May be
938 : * virtual in future. */
939 525 : bool is_error () const { return ident_segment.is_error (); }
940 :
941 : /* Returns whether segment is identifier only (as opposed to generic args or
942 : * function). Overridden in derived classes with other segments. */
943 498 : virtual bool is_ident_only () const { return true; }
944 :
945 436988 : bool is_lang_item () const { return lang_item.has_value (); }
946 :
947 4034 : location_t get_locus () const { return locus; }
948 :
949 : // not pure virtual as class not abstract
950 : virtual void accept_vis (ASTVisitor &vis);
951 :
952 56855 : bool get_separating_scope_resolution () const
953 : {
954 56855 : return has_separating_scope_resolution;
955 : }
956 :
957 492118 : PathIdentSegment &get_ident_segment () { return ident_segment; };
958 :
959 23 : const PathIdentSegment &get_ident_segment () const { return ident_segment; };
960 :
961 3181 : LangItem::Kind get_lang_item () const
962 : {
963 3181 : rust_assert (is_lang_item ());
964 3181 : return *lang_item;
965 : }
966 :
967 197109 : NodeId get_node_id () const { return node_id; }
968 :
969 : bool is_crate_path_seg () const
970 : {
971 : return get_ident_segment ().is_crate_path_seg ();
972 : }
973 : bool is_super_path_seg () const
974 : {
975 : return get_ident_segment ().is_super_path_seg ();
976 : }
977 : bool is_big_self_seg () const
978 : {
979 : return get_ident_segment ().is_big_self_seg ();
980 : }
981 : bool is_lower_self_seg () const
982 : {
983 : return get_ident_segment ().is_lower_self_seg ();
984 : }
985 : };
986 :
987 : // Segment used in type path with generic args
988 : class TypePathSegmentGeneric : public TypePathSegment
989 : {
990 : GenericArgs generic_args;
991 :
992 : public:
993 11 : SegmentType get_type () const override { return SegmentType::GENERIC; }
994 :
995 7217198 : bool has_generic_args () const { return generic_args.has_generic_args (); }
996 :
997 0 : bool is_ident_only () const override { return false; }
998 :
999 : // Constructor with PathIdentSegment and GenericArgs
1000 18331 : TypePathSegmentGeneric (PathIdentSegment ident_segment,
1001 : bool has_separating_scope_resolution,
1002 : GenericArgs generic_args, location_t locus)
1003 : : TypePathSegment (std::move (ident_segment),
1004 : has_separating_scope_resolution, locus),
1005 18331 : generic_args (std::move (generic_args))
1006 18331 : {}
1007 :
1008 107 : TypePathSegmentGeneric (LangItem::Kind lang_item,
1009 : PathIdentSegment ident_segment,
1010 : GenericArgs generic_args, location_t locus)
1011 : : TypePathSegment (lang_item, ident_segment, locus),
1012 107 : generic_args (std::move (generic_args))
1013 107 : {}
1014 :
1015 : // Constructor from segment name and all args
1016 : TypePathSegmentGeneric (std::string segment_name,
1017 : bool has_separating_scope_resolution,
1018 : std::vector<Lifetime> lifetime_args,
1019 : std::vector<GenericArg> generic_args,
1020 : std::vector<GenericArgsBinding> binding_args,
1021 : location_t locus)
1022 : : TypePathSegment (std::move (segment_name),
1023 : has_separating_scope_resolution, locus),
1024 : generic_args (GenericArgs (std::move (lifetime_args),
1025 : std::move (generic_args),
1026 : std::move (binding_args)))
1027 : {}
1028 :
1029 : // Copy constructor with vector clone
1030 104124 : TypePathSegmentGeneric (TypePathSegmentGeneric const &other)
1031 104124 : : TypePathSegment (other), generic_args (other.generic_args)
1032 104124 : {}
1033 :
1034 : // Overloaded assignment operator with vector clone
1035 : TypePathSegmentGeneric &operator= (TypePathSegmentGeneric const &other)
1036 : {
1037 : generic_args = other.generic_args;
1038 :
1039 : return *this;
1040 : }
1041 :
1042 : // move constructors
1043 : TypePathSegmentGeneric (TypePathSegmentGeneric &&other) = default;
1044 : TypePathSegmentGeneric &operator= (TypePathSegmentGeneric &&other) = default;
1045 :
1046 : std::string as_string () const override;
1047 :
1048 : void accept_vis (ASTVisitor &vis) override;
1049 :
1050 : // TODO: is this better? Or is a "vis_pattern" better?
1051 3795417 : GenericArgs &get_generic_args () { return generic_args; }
1052 :
1053 : // Use covariance to override base class method
1054 104124 : TypePathSegmentGeneric *clone_type_path_segment_impl () const override
1055 : {
1056 104124 : return new TypePathSegmentGeneric (*this);
1057 : }
1058 :
1059 4 : TypePathSegmentGeneric *reconstruct_impl () const override
1060 : {
1061 4 : return new TypePathSegmentGeneric (get_ident_segment (),
1062 4 : has_separating_scope_resolution,
1063 12 : generic_args.reconstruct (),
1064 4 : get_locus ());
1065 : }
1066 : };
1067 :
1068 : // A function as represented in a type path
1069 : struct TypePathFunction
1070 : {
1071 : private:
1072 : // TODO: remove
1073 : /*bool has_inputs;
1074 : TypePathFnInputs inputs;*/
1075 : // inlined from TypePathFnInputs
1076 : std::vector<std::unique_ptr<Type>> inputs;
1077 :
1078 : // bool has_type;
1079 : std::unique_ptr<Type> return_type;
1080 :
1081 : // FIXME: think of better way to mark as invalid than taking up storage
1082 : bool is_invalid;
1083 :
1084 : location_t locus;
1085 :
1086 : protected:
1087 : // Constructor only used to create invalid type path functions.
1088 0 : TypePathFunction (bool is_invalid, location_t locus)
1089 0 : : is_invalid (is_invalid), locus (locus)
1090 : {}
1091 :
1092 : public:
1093 : // Returns whether the return type of the function has been specified.
1094 175592 : bool has_return_type () const { return return_type != nullptr; }
1095 :
1096 : // Returns whether the function has inputs.
1097 27 : bool has_inputs () const { return !inputs.empty (); }
1098 :
1099 : // Returns whether function is in an error state.
1100 176128 : bool is_error () const { return is_invalid; }
1101 :
1102 : // Creates an error state function.
1103 0 : static TypePathFunction create_error ()
1104 : {
1105 0 : return TypePathFunction (true, UNDEF_LOCATION);
1106 : }
1107 :
1108 : // Constructor
1109 536 : TypePathFunction (std::vector<std::unique_ptr<Type>> inputs, location_t locus,
1110 : std::unique_ptr<Type> type = nullptr)
1111 536 : : inputs (std::move (inputs)), return_type (std::move (type)),
1112 536 : is_invalid (false), locus (locus)
1113 : {}
1114 :
1115 : // Copy constructor with clone
1116 1665 : TypePathFunction (TypePathFunction const &other)
1117 1665 : : is_invalid (other.is_invalid)
1118 : {
1119 : // guard to protect from null pointer dereference
1120 1665 : if (other.return_type != nullptr)
1121 1600 : return_type = other.return_type->clone_type ();
1122 :
1123 1665 : inputs.reserve (other.inputs.size ());
1124 3982 : for (const auto &e : other.inputs)
1125 2317 : inputs.push_back (e->clone_type ());
1126 1665 : }
1127 :
1128 536 : ~TypePathFunction () = default;
1129 :
1130 : // Overloaded assignment operator to clone type
1131 : TypePathFunction &operator= (TypePathFunction const &other)
1132 : {
1133 : is_invalid = other.is_invalid;
1134 :
1135 : // guard to protect from null pointer dereference
1136 : if (other.return_type != nullptr)
1137 : return_type = other.return_type->clone_type ();
1138 : else
1139 : return_type = nullptr;
1140 :
1141 : inputs.reserve (other.inputs.size ());
1142 : for (const auto &e : other.inputs)
1143 : inputs.push_back (e->clone_type ());
1144 :
1145 : return *this;
1146 : }
1147 :
1148 : // move constructors
1149 536 : TypePathFunction (TypePathFunction &&other) = default;
1150 : TypePathFunction &operator= (TypePathFunction &&other) = default;
1151 :
1152 : std::string as_string () const;
1153 :
1154 : // TODO: this mutable getter seems really dodgy. Think up better way.
1155 : const std::vector<std::unique_ptr<Type>> &get_params () const
1156 : {
1157 : return inputs;
1158 : }
1159 175592 : std::vector<std::unique_ptr<Type>> &get_params () { return inputs; }
1160 :
1161 : // TODO: is this better? Or is a "vis_pattern" better?
1162 135070 : Type &get_return_type ()
1163 : {
1164 135070 : rust_assert (has_return_type ());
1165 135070 : return *return_type;
1166 : }
1167 :
1168 34663 : std::unique_ptr<Type> &get_return_type_ptr ()
1169 : {
1170 34663 : rust_assert (has_return_type ());
1171 34663 : return return_type;
1172 : }
1173 :
1174 0 : TypePathFunction reconstruct () const
1175 : {
1176 0 : std::vector<std::unique_ptr<Type>> new_inputs;
1177 0 : new_inputs.reserve (inputs.size ());
1178 0 : for (const auto &e : inputs)
1179 0 : new_inputs.push_back (e->reconstruct ());
1180 :
1181 0 : std::unique_ptr<Type> new_ret = nullptr;
1182 0 : if (return_type)
1183 0 : new_ret = return_type->reconstruct ();
1184 :
1185 0 : return TypePathFunction (std::move (new_inputs), locus,
1186 0 : std::move (new_ret));
1187 0 : }
1188 :
1189 27 : location_t get_locus () const { return locus; }
1190 : };
1191 :
1192 : // Segment used in type path with a function argument
1193 : class TypePathSegmentFunction : public TypePathSegment
1194 : {
1195 : TypePathFunction function_path;
1196 :
1197 : public:
1198 27 : SegmentType get_type () const override { return SegmentType::FUNCTION; }
1199 :
1200 : // Constructor with PathIdentSegment and TypePathFn
1201 536 : TypePathSegmentFunction (PathIdentSegment ident_segment,
1202 : bool has_separating_scope_resolution,
1203 : TypePathFunction function_path, location_t locus)
1204 : : TypePathSegment (std::move (ident_segment),
1205 : has_separating_scope_resolution, locus),
1206 536 : function_path (std::move (function_path))
1207 536 : {}
1208 :
1209 : // Constructor with segment name and TypePathFn
1210 : TypePathSegmentFunction (std::string segment_name,
1211 : bool has_separating_scope_resolution,
1212 : TypePathFunction function_path, location_t locus)
1213 : : TypePathSegment (std::move (segment_name),
1214 : has_separating_scope_resolution, locus),
1215 : function_path (std::move (function_path))
1216 : {}
1217 :
1218 : std::string as_string () const override;
1219 :
1220 27 : bool is_ident_only () const override { return false; }
1221 :
1222 : void accept_vis (ASTVisitor &vis) override;
1223 :
1224 : // TODO: is this better? Or is a "vis_pattern" better?
1225 175592 : TypePathFunction &get_type_path_function ()
1226 : {
1227 175592 : rust_assert (!function_path.is_error ());
1228 175592 : return function_path;
1229 : }
1230 :
1231 : // Use covariance to override base class method
1232 1665 : TypePathSegmentFunction *clone_type_path_segment_impl () const override
1233 : {
1234 1665 : return new TypePathSegmentFunction (*this);
1235 : }
1236 :
1237 0 : TypePathSegmentFunction *reconstruct_impl () const override
1238 : {
1239 0 : return new TypePathSegmentFunction (get_ident_segment (),
1240 0 : has_separating_scope_resolution,
1241 0 : function_path.reconstruct (),
1242 0 : get_locus ());
1243 : }
1244 : };
1245 :
1246 209500 : class TypePath : public TypeNoBounds
1247 : {
1248 : bool has_opening_scope_resolution;
1249 : std::vector<std::unique_ptr<TypePathSegment>> segments;
1250 : location_t locus;
1251 :
1252 : protected:
1253 : /* Use covariance to implement clone function as returning this object
1254 : * rather than base */
1255 406380 : TypePath *clone_type_no_bounds_impl () const override
1256 : {
1257 406380 : return new TypePath (*this);
1258 : }
1259 178 : TypePath *reconstruct_impl () const override
1260 : {
1261 890 : return new TypePath (reconstruct_vec (segments), locus,
1262 356 : has_opening_scope_resolution);
1263 : }
1264 :
1265 : public:
1266 : /* Returns whether the TypePath has an opening scope resolution operator
1267 : * (i.e. is global path or crate-relative path, not module-relative) */
1268 242293 : bool has_opening_scope_resolution_op () const
1269 : {
1270 242293 : return has_opening_scope_resolution;
1271 : }
1272 :
1273 : // Returns whether the TypePath is in an invalid state.
1274 2091749 : bool is_error () const { return segments.empty (); }
1275 :
1276 : // Creates an error state TypePath.
1277 3971 : static TypePath create_error ()
1278 : {
1279 11913 : return TypePath (std::vector<std::unique_ptr<TypePathSegment>> (),
1280 3971 : UNDEF_LOCATION);
1281 : }
1282 :
1283 : // Constructor
1284 148883 : TypePath (std::vector<std::unique_ptr<TypePathSegment>> segments,
1285 : location_t locus, bool has_opening_scope_resolution = false)
1286 : : TypeNoBounds (),
1287 148883 : has_opening_scope_resolution (has_opening_scope_resolution),
1288 148883 : segments (std::move (segments)), locus (locus)
1289 : {}
1290 :
1291 0 : TypePath (LangItem::Kind lang_item,
1292 : std::vector<std::unique_ptr<TypePathSegment>> segments,
1293 : location_t locus, bool has_opening_scope_resolution = false)
1294 : : TypeNoBounds (),
1295 0 : has_opening_scope_resolution (has_opening_scope_resolution),
1296 0 : segments (std::move (segments)), locus (locus)
1297 : {}
1298 :
1299 : // Copy constructor with vector clone
1300 527893 : TypePath (TypePath const &other)
1301 : : TypeNoBounds (other),
1302 527893 : has_opening_scope_resolution (other.has_opening_scope_resolution),
1303 527893 : locus (other.locus)
1304 : {
1305 527893 : segments.reserve (other.segments.size ());
1306 1081698 : for (const auto &e : other.segments)
1307 553805 : segments.push_back (e->clone_type_path_segment ());
1308 527893 : }
1309 :
1310 : // Overloaded assignment operator with clone
1311 : TypePath &operator= (TypePath const &other)
1312 : {
1313 : TypeNoBounds::operator= (other);
1314 : has_opening_scope_resolution = other.has_opening_scope_resolution;
1315 : locus = other.locus;
1316 :
1317 : segments.reserve (other.segments.size ());
1318 : for (const auto &e : other.segments)
1319 : segments.push_back (e->clone_type_path_segment ());
1320 :
1321 : return *this;
1322 : }
1323 :
1324 : // move constructors
1325 128562 : TypePath (TypePath &&other) = default;
1326 3701 : TypePath &operator= (TypePath &&other) = default;
1327 :
1328 : std::string as_string () const override;
1329 :
1330 : std::string make_debug_string () const;
1331 :
1332 : /* Converts TypePath to SimplePath if possible (i.e. no generic or function
1333 : * arguments). Otherwise returns an empty SimplePath. */
1334 : SimplePath as_simple_path () const;
1335 :
1336 : // Creates a trait bound with a clone of this type path as its only element.
1337 : TraitBound *to_trait_bound (bool in_parens) const override;
1338 :
1339 162438 : location_t get_locus () const override final { return locus; }
1340 2347775 : NodeId get_node_id () const override { return node_id; }
1341 :
1342 0 : void mark_for_strip () override {}
1343 4235625 : bool is_marked_for_strip () const override { return false; }
1344 :
1345 : void accept_vis (ASTVisitor &vis) override;
1346 :
1347 : // TODO: this seems kinda dodgy
1348 55939 : std::vector<std::unique_ptr<TypePathSegment>> &get_segments ()
1349 : {
1350 18381874 : return segments;
1351 : }
1352 131208 : const std::vector<std::unique_ptr<TypePathSegment>> &get_segments () const
1353 : {
1354 131226 : return segments;
1355 : }
1356 :
1357 : size_t get_num_segments () const { return segments.size (); }
1358 :
1359 1482 : Type::Kind get_type_kind () const override { return Type::Kind::TypePath; }
1360 : };
1361 :
1362 : struct QualifiedPathType
1363 : {
1364 : private:
1365 : std::unique_ptr<Type> type_to_invoke_on;
1366 : TypePath trait_path;
1367 : location_t locus;
1368 : NodeId node_id;
1369 :
1370 : public:
1371 : // Constructor
1372 3776 : QualifiedPathType (std::unique_ptr<Type> invoke_on_type,
1373 : location_t locus = UNDEF_LOCATION,
1374 : TypePath trait_path = TypePath::create_error ())
1375 3776 : : type_to_invoke_on (std::move (invoke_on_type)), trait_path (trait_path),
1376 3776 : locus (locus), node_id (Analysis::Mappings::get ().get_next_node_id ())
1377 3776 : {}
1378 :
1379 : // Copy constructor uses custom deep copy for Type to preserve polymorphism
1380 26245 : QualifiedPathType (QualifiedPathType const &other)
1381 26245 : : trait_path (other.trait_path), locus (other.locus)
1382 : {
1383 26245 : node_id = other.node_id;
1384 : // guard to prevent null dereference
1385 26245 : if (other.type_to_invoke_on != nullptr)
1386 26245 : type_to_invoke_on = other.type_to_invoke_on->clone_type ();
1387 26245 : }
1388 :
1389 : // default destructor
1390 37519 : ~QualifiedPathType () = default;
1391 :
1392 : // overload assignment operator to use custom clone method
1393 : QualifiedPathType &operator= (QualifiedPathType const &other)
1394 : {
1395 : node_id = other.node_id;
1396 : trait_path = other.trait_path;
1397 : locus = other.locus;
1398 :
1399 : // guard to prevent null dereference
1400 : if (other.type_to_invoke_on != nullptr)
1401 : type_to_invoke_on = other.type_to_invoke_on->clone_type ();
1402 : else
1403 : type_to_invoke_on = nullptr;
1404 :
1405 : return *this;
1406 : }
1407 :
1408 : // move constructor
1409 11274 : QualifiedPathType (QualifiedPathType &&other) = default;
1410 0 : QualifiedPathType &operator= (QualifiedPathType &&other) = default;
1411 :
1412 0 : QualifiedPathType reconstruct () const
1413 : {
1414 0 : auto new_type = type_to_invoke_on->reconstruct ();
1415 :
1416 : // trait_path is stored by value, but reconstruct returns a unique_ptr.
1417 : // We must dereference it to pass to the constructor.
1418 : // This is safe because the constructor makes its own copy/move.
1419 0 : auto new_trait_path_ptr = trait_path.reconstruct ();
1420 0 : TypePath *concrete_ptr
1421 0 : = static_cast<TypePath *> (new_trait_path_ptr.get ());
1422 :
1423 0 : return QualifiedPathType (std::move (new_type), locus, *concrete_ptr);
1424 0 : }
1425 :
1426 : // Returns whether the qualified path type has a rebind as clause.
1427 998286 : bool has_as_clause () const { return !trait_path.is_error (); }
1428 :
1429 : // Returns whether the qualified path type is in an error state.
1430 1012439 : bool is_error () const { return type_to_invoke_on == nullptr; }
1431 :
1432 : // Creates an error state qualified path type.
1433 0 : static QualifiedPathType create_error ()
1434 : {
1435 0 : return QualifiedPathType (nullptr);
1436 : }
1437 :
1438 : std::string as_string () const;
1439 :
1440 933 : location_t get_locus () const { return locus; }
1441 :
1442 : // TODO: is this better? Or is a "vis_pattern" better?
1443 781163 : Type &get_type ()
1444 : {
1445 781163 : rust_assert (type_to_invoke_on != nullptr);
1446 781163 : return *type_to_invoke_on;
1447 : }
1448 :
1449 217123 : std::unique_ptr<Type> &get_type_ptr ()
1450 : {
1451 217123 : rust_assert (type_to_invoke_on != nullptr);
1452 217123 : return type_to_invoke_on;
1453 : }
1454 :
1455 : // TODO: is this better? Or is a "vis_pattern" better?
1456 964802 : TypePath &get_as_type_path ()
1457 : {
1458 964802 : rust_assert (has_as_clause ());
1459 964802 : return trait_path;
1460 : }
1461 :
1462 358 : NodeId get_node_id () const { return node_id; }
1463 : };
1464 :
1465 : /* AST node representing a qualified path-in-expression pattern (path that
1466 : * allows specifying trait functions) */
1467 : class QualifiedPathInExpression : public Path, public ExprWithoutBlock
1468 : {
1469 : std::vector<Attribute> outer_attrs;
1470 : QualifiedPathType path_type;
1471 : location_t locus;
1472 : NodeId _node_id;
1473 :
1474 : public:
1475 : std::string as_string () const override;
1476 :
1477 216 : QualifiedPathInExpression (QualifiedPathType qual_path_type,
1478 : std::vector<PathExprSegment> path_segments,
1479 : std::vector<Attribute> outer_attrs,
1480 : location_t locus)
1481 216 : : Path (std::move (path_segments)), outer_attrs (std::move (outer_attrs)),
1482 216 : path_type (std::move (qual_path_type)), locus (locus),
1483 216 : _node_id (Analysis::Mappings::get ().get_next_node_id ())
1484 216 : {}
1485 :
1486 : /* TODO: maybe make a shortcut constructor that has QualifiedPathType
1487 : * elements as params */
1488 :
1489 : // Returns whether qualified path in expression is in an error state.
1490 10404 : bool is_error () const { return path_type.is_error (); }
1491 :
1492 : // Creates an error qualified path in expression.
1493 0 : static QualifiedPathInExpression create_error ()
1494 : {
1495 0 : return QualifiedPathInExpression (QualifiedPathType::create_error (), {},
1496 0 : {}, UNDEF_LOCATION);
1497 : }
1498 :
1499 369 : location_t get_locus () const override final { return locus; }
1500 :
1501 : void accept_vis (ASTVisitor &vis) override;
1502 :
1503 : // Invalid if path_type is error, so base stripping on that.
1504 0 : void mark_for_strip () override
1505 : {
1506 0 : path_type = QualifiedPathType::create_error ();
1507 0 : }
1508 10404 : bool is_marked_for_strip () const override { return is_error (); }
1509 :
1510 : // TODO: is this better? Or is a "vis_pattern" better?
1511 43934 : QualifiedPathType &get_qualified_path_type ()
1512 : {
1513 43934 : rust_assert (!path_type.is_error ());
1514 43934 : return path_type;
1515 : }
1516 :
1517 : const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
1518 52166 : std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
1519 :
1520 189 : void set_outer_attrs (std::vector<Attribute> new_attrs) override
1521 : {
1522 189 : outer_attrs = std::move (new_attrs);
1523 0 : }
1524 :
1525 3760 : NodeId get_node_id () const override { return _node_id; }
1526 :
1527 216 : Expr::Kind get_expr_kind () const override
1528 : {
1529 216 : return Expr::Kind::QualifiedPathInExpression;
1530 : }
1531 :
1532 : std::unique_ptr<QualifiedPathInExpression> reconstruct () const
1533 : {
1534 : std::vector<PathExprSegment> new_segments;
1535 : new_segments.reserve (segments.size ());
1536 : for (const auto &seg : segments)
1537 : new_segments.push_back (seg.reconstruct ());
1538 :
1539 : auto *new_path = new QualifiedPathInExpression (path_type.reconstruct (),
1540 : std::move (new_segments),
1541 : outer_attrs, locus);
1542 :
1543 : return std::unique_ptr<QualifiedPathInExpression> (new_path);
1544 : }
1545 :
1546 : protected:
1547 : /* Use covariance to implement clone function as returning this object
1548 : * rather than base */
1549 0 : QualifiedPathInExpression *clone_pattern_impl () const final override
1550 : {
1551 0 : return clone_qual_path_in_expression_impl ();
1552 : }
1553 :
1554 : /* Use covariance to implement clone function as returning this object
1555 : * rather than base */
1556 : QualifiedPathInExpression *
1557 0 : clone_expr_without_block_impl () const final override
1558 : {
1559 0 : return clone_qual_path_in_expression_impl ();
1560 : }
1561 :
1562 : /*virtual*/ QualifiedPathInExpression *
1563 877 : clone_qual_path_in_expression_impl () const
1564 : {
1565 877 : return new QualifiedPathInExpression (*this);
1566 : }
1567 : };
1568 :
1569 : /* Represents a qualified path in a type; used for disambiguating trait
1570 : * function calls */
1571 : class QualifiedPathInType : public TypeNoBounds
1572 : {
1573 : QualifiedPathType path_type;
1574 : std::unique_ptr<TypePathSegment> associated_segment;
1575 : std::vector<std::unique_ptr<TypePathSegment>> segments;
1576 : location_t locus;
1577 :
1578 : protected:
1579 : /* Use covariance to implement clone function as returning this object
1580 : * rather than base */
1581 25341 : QualifiedPathInType *clone_type_no_bounds_impl () const override
1582 : {
1583 25341 : return new QualifiedPathInType (*this);
1584 : }
1585 0 : QualifiedPathInType *reconstruct_impl () const override
1586 : {
1587 0 : return new QualifiedPathInType (path_type.reconstruct (),
1588 0 : associated_segment->reconstruct (),
1589 0 : reconstruct_vec (segments), locus);
1590 : }
1591 :
1592 : public:
1593 3560 : QualifiedPathInType (
1594 : QualifiedPathType qual_path_type,
1595 : std::unique_ptr<TypePathSegment> associated_segment,
1596 : std::vector<std::unique_ptr<TypePathSegment>> path_segments,
1597 : location_t locus)
1598 3560 : : path_type (std::move (qual_path_type)),
1599 3560 : associated_segment (std::move (associated_segment)),
1600 3560 : segments (std::move (path_segments)), locus (locus)
1601 3560 : {}
1602 :
1603 : // Copy constructor with vector clone
1604 25341 : QualifiedPathInType (QualifiedPathInType const &other)
1605 25341 : : path_type (other.path_type), locus (other.locus)
1606 : {
1607 25341 : auto seg = other.associated_segment->clone_type_path_segment_impl ();
1608 25341 : associated_segment = std::unique_ptr<TypePathSegment> (seg);
1609 :
1610 25341 : segments.reserve (other.segments.size ());
1611 25341 : for (const auto &e : other.segments)
1612 0 : segments.push_back (e->clone_type_path_segment ());
1613 25341 : }
1614 :
1615 : // Overloaded assignment operator with vector clone
1616 : QualifiedPathInType &operator= (QualifiedPathInType const &other)
1617 : {
1618 : auto seg = other.associated_segment->clone_type_path_segment_impl ();
1619 : associated_segment = std::unique_ptr<TypePathSegment> (seg);
1620 :
1621 : path_type = other.path_type;
1622 : locus = other.locus;
1623 :
1624 : segments.reserve (other.segments.size ());
1625 : for (const auto &e : other.segments)
1626 : segments.push_back (e->clone_type_path_segment ());
1627 :
1628 : return *this;
1629 : }
1630 :
1631 : // move constructors
1632 3560 : QualifiedPathInType (QualifiedPathInType &&other) = default;
1633 : QualifiedPathInType &operator= (QualifiedPathInType &&other) = default;
1634 :
1635 : // Returns whether qualified path in type is in an error state.
1636 3560 : bool is_error () const { return path_type.is_error (); }
1637 :
1638 : // Creates an error state qualified path in type.
1639 0 : static QualifiedPathInType create_error ()
1640 : {
1641 0 : return QualifiedPathInType (
1642 0 : QualifiedPathType::create_error (), nullptr,
1643 0 : std::vector<std::unique_ptr<TypePathSegment>> (), UNDEF_LOCATION);
1644 : }
1645 :
1646 : std::string as_string () const override;
1647 :
1648 : void accept_vis (ASTVisitor &vis) override;
1649 :
1650 : // TODO: is this better? Or is a "vis_pattern" better?
1651 955078 : QualifiedPathType &get_qualified_path_type ()
1652 : {
1653 955078 : rust_assert (!path_type.is_error ());
1654 955078 : return path_type;
1655 : }
1656 :
1657 : std::unique_ptr<TypePathSegment> &get_associated_segment ()
1658 : {
1659 645350 : return associated_segment;
1660 : }
1661 :
1662 : // TODO: this seems kinda dodgy
1663 : std::vector<std::unique_ptr<TypePathSegment>> &get_segments ()
1664 : {
1665 748394 : return segments;
1666 : }
1667 : const std::vector<std::unique_ptr<TypePathSegment>> &get_segments () const
1668 : {
1669 : return segments;
1670 : }
1671 :
1672 264 : location_t get_locus () const override final { return locus; }
1673 :
1674 0 : Type::Kind get_type_kind () const override
1675 : {
1676 0 : return Type::Kind::QualifiedPathInType;
1677 : }
1678 : };
1679 : } // namespace AST
1680 : } // namespace Rust
1681 :
1682 : #endif
|