]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/rust/ast/rust-path.h
Update copyright years.
[thirdparty/gcc.git] / gcc / rust / ast / rust-path.h
1 // Copyright (C) 2020-2023 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 "rust-ast.h"
25 #include "system.h"
26
27 namespace Rust {
28 namespace AST {
29
30 // The "identifier" (not generic args) aspect of each path expression segment
31 class PathIdentSegment
32 {
33 std::string segment_name;
34 Location locus;
35
36 // only allow identifiers, "super", "self", "Self", "crate", or "$crate"
37 public:
38 PathIdentSegment (std::string segment_name, Location locus)
39 : segment_name (std::move (segment_name)), locus (locus)
40 {}
41
42 // Creates an error PathIdentSegment.
43 static PathIdentSegment create_error ()
44 {
45 return PathIdentSegment ("", Location ());
46 }
47
48 // Returns whether PathIdentSegment is in an error state.
49 bool is_error () const { return segment_name.empty (); }
50
51 std::string as_string () const { return segment_name; }
52
53 Location get_locus () const { return locus; }
54
55 bool is_super_segment () const { return as_string ().compare ("super") == 0; }
56 bool is_crate_segment () const { return as_string ().compare ("crate") == 0; }
57 bool is_lower_self () const { return as_string ().compare ("self") == 0; }
58 bool is_big_self () const { return as_string ().compare ("Self") == 0; }
59 };
60
61 // A binding of an identifier to a type used in generic arguments in paths
62 struct GenericArgsBinding
63 {
64 private:
65 Identifier identifier;
66 std::unique_ptr<Type> type;
67 Location locus;
68
69 public:
70 // Returns whether binding is in an error state.
71 bool is_error () const
72 {
73 return type == nullptr;
74 // and also identifier is empty, but cheaper computation
75 }
76
77 // Creates an error state generic args binding.
78 static GenericArgsBinding create_error ()
79 {
80 return GenericArgsBinding ("", nullptr);
81 }
82
83 // Pointer type for type in constructor to enable polymorphism
84 GenericArgsBinding (Identifier ident, std::unique_ptr<Type> type_ptr,
85 Location locus = Location ())
86 : identifier (std::move (ident)), type (std::move (type_ptr)), locus (locus)
87 {}
88
89 // Copy constructor has to deep copy the type as it is a unique pointer
90 GenericArgsBinding (GenericArgsBinding const &other)
91 : identifier (other.identifier), locus (other.locus)
92 {
93 // guard to protect from null pointer dereference
94 if (other.type != nullptr)
95 type = other.type->clone_type ();
96 }
97
98 // default destructor
99 ~GenericArgsBinding () = default;
100
101 // Overload assignment operator to deep copy the pointed-to type
102 GenericArgsBinding &operator= (GenericArgsBinding const &other)
103 {
104 identifier = other.identifier;
105 locus = other.locus;
106
107 // guard to protect from null pointer dereference
108 if (other.type != nullptr)
109 type = other.type->clone_type ();
110 else
111 type = nullptr;
112
113 return *this;
114 }
115
116 // move constructors
117 GenericArgsBinding (GenericArgsBinding &&other) = default;
118 GenericArgsBinding &operator= (GenericArgsBinding &&other) = default;
119
120 std::string as_string () const;
121
122 // TODO: is this better? Or is a "vis_pattern" better?
123 std::unique_ptr<Type> &get_type ()
124 {
125 rust_assert (type != nullptr);
126 return type;
127 }
128
129 Location get_locus () const { return locus; }
130
131 Identifier get_identifier () const { return identifier; }
132 };
133
134 /* Class representing a const generic application */
135 class GenericArg
136 {
137 public:
138 /**
139 * const generic arguments cannot always be differentiated with generic type
140 * arguments during parsing, e.g:
141 * ```rust
142 * let a: Foo<N>;
143 * ```
144 *
145 * Is N a type? A constant defined elsewhere? The parser cannot know, and must
146 * not draw any conclusions. We must wait until later passes of the compiler
147 * to decide whether this refers to a constant item or a type.
148 *
149 * On the other hand, simple expressions like literals or block expressions
150 * will always be constant expressions: There is no ambiguity at all.
151 */
152 enum class Kind
153 {
154 Error,
155 Const, // A const value
156 Type, // A type argument (not discernable during parsing)
157 Either, // Either a type or a const value, cleared up during resolving
158 };
159
160 static GenericArg create_error ()
161 {
162 return GenericArg (nullptr, nullptr, "", Kind::Error, Location ());
163 }
164
165 static GenericArg create_const (std::unique_ptr<Expr> expression)
166 {
167 auto locus = expression->get_locus ();
168 return GenericArg (std::move (expression), nullptr, "", Kind::Const, locus);
169 }
170
171 static GenericArg create_type (std::unique_ptr<Type> type)
172 {
173 auto locus = type->get_locus ();
174 return GenericArg (nullptr, std::move (type), "", Kind::Type, locus);
175 }
176
177 static GenericArg create_ambiguous (Identifier path, Location locus)
178 {
179 return GenericArg (nullptr, nullptr, std::move (path), Kind::Either, locus);
180 }
181
182 GenericArg (const GenericArg &other)
183 : path (other.path), kind (other.kind), locus (other.locus)
184 {
185 if (other.expression)
186 expression = other.expression->clone_expr ();
187 if (other.type)
188 type = other.type->clone_type ();
189 }
190
191 GenericArg operator= (const GenericArg &other)
192 {
193 kind = other.kind;
194 path = other.path;
195 locus = other.locus;
196
197 if (other.expression)
198 expression = other.expression->clone_expr ();
199 if (other.type)
200 type = other.type->clone_type ();
201
202 return *this;
203 }
204
205 bool is_error () const { return kind == Kind::Error; }
206
207 Kind get_kind () const { return kind; }
208 const Location &get_locus () const { return locus; }
209
210 std::unique_ptr<Expr> &get_expression ()
211 {
212 rust_assert (kind == Kind::Const);
213
214 return expression;
215 }
216
217 std::unique_ptr<Type> &get_type ()
218 {
219 rust_assert (kind == Kind::Type);
220
221 return type;
222 }
223
224 const std::string &get_path () const
225 {
226 rust_assert (kind == Kind::Either);
227
228 return path;
229 }
230
231 std::string as_string () const
232 {
233 switch (get_kind ())
234 {
235 case Kind::Error:
236 gcc_unreachable ();
237 case Kind::Either:
238 return "Ambiguous: " + path;
239 case Kind::Const:
240 return "Const: { " + expression->as_string () + " }";
241 case Kind::Type:
242 return "Type: " + type->as_string ();
243 }
244
245 return "";
246 }
247
248 /**
249 * Disambiguate an ambiguous generic argument to a const generic argument,
250 * unequivocally
251 */
252 GenericArg disambiguate_to_const () const;
253
254 /**
255 * Disambiguate an ambiguous generic argument to a type argument,
256 * unequivocally
257 */
258 GenericArg disambiguate_to_type () const;
259
260 private:
261 GenericArg (std::unique_ptr<Expr> expression, std::unique_ptr<Type> type,
262 Identifier path, Kind kind, Location locus)
263 : expression (std::move (expression)), type (std::move (type)),
264 path (std::move (path)), kind (kind), locus (locus)
265 {}
266
267 /**
268 * Expression associated with a `Clear` const generic application
269 * A null pointer here is allowed in the case that the const argument is
270 * ambiguous.
271 */
272 std::unique_ptr<Expr> expression;
273
274 /**
275 * If the argument ends up being a type argument instead. A null pointer will
276 * be present here until the resolving phase.
277 */
278 std::unique_ptr<Type> type;
279
280 /**
281 * Optional path which cannot be differentiated between a constant item and
282 * a type. Only used for ambiguous const generic arguments, otherwise
283 * empty.
284 */
285 Identifier path;
286
287 /* Which kind of const generic application are we dealing with */
288 Kind kind;
289
290 Location locus;
291 };
292
293 /**
294 * Representation of const generic parameters
295 */
296 class ConstGenericParam : public GenericParam
297 {
298 /* Name of the parameter */
299 Identifier name;
300
301 /* Mandatory type of the const parameter - a null pointer is an error */
302 std::unique_ptr<AST::Type> type;
303
304 /**
305 * Default value for the const generic parameter
306 */
307 GenericArg default_value;
308
309 Attribute outer_attr;
310 Location locus;
311
312 public:
313 ConstGenericParam (Identifier name, std::unique_ptr<AST::Type> type,
314 GenericArg default_value, Attribute outer_attr,
315 Location locus)
316 : name (name), type (std::move (type)),
317 default_value (std::move (default_value)), outer_attr (outer_attr),
318 locus (locus)
319 {}
320
321 ConstGenericParam (const ConstGenericParam &other)
322 : GenericParam (), name (other.name), type (other.type->clone_type ()),
323 default_value (other.default_value), outer_attr (other.outer_attr),
324 locus (other.locus)
325 {}
326
327 bool has_type () const { return type != nullptr; }
328 bool has_default_value () const { return !default_value.is_error (); }
329
330 const Identifier &get_name () const { return name; }
331
332 std::unique_ptr<AST::Type> &get_type ()
333 {
334 rust_assert (has_type ());
335
336 return type;
337 }
338
339 GenericArg &get_default_value ()
340 {
341 rust_assert (has_default_value ());
342
343 return default_value;
344 }
345
346 const GenericArg &get_default_value () const
347 {
348 rust_assert (has_default_value ());
349
350 return default_value;
351 }
352
353 std::string as_string () const override;
354
355 void accept_vis (ASTVisitor &vis) override;
356
357 Location get_locus () const override final { return locus; }
358
359 Kind get_kind () const override final { return Kind::Const; }
360
361 protected:
362 /* Use covariance to implement clone function as returning this object rather
363 * than base */
364 ConstGenericParam *clone_generic_param_impl () const override
365 {
366 return new ConstGenericParam (*this);
367 }
368 };
369
370 // Generic arguments allowed in each path expression segment - inline?
371 struct GenericArgs
372 {
373 std::vector<Lifetime> lifetime_args;
374 std::vector<GenericArg> generic_args;
375 std::vector<GenericArgsBinding> binding_args;
376 Location locus;
377
378 public:
379 // Returns true if there are any generic arguments
380 bool has_generic_args () const
381 {
382 return !(lifetime_args.empty () && generic_args.empty ()
383 && binding_args.empty ());
384 }
385
386 GenericArgs (std::vector<Lifetime> lifetime_args,
387 std::vector<GenericArg> generic_args,
388 std::vector<GenericArgsBinding> binding_args,
389 Location locus = Location ())
390 : lifetime_args (std::move (lifetime_args)),
391 generic_args (std::move (generic_args)),
392 binding_args (std::move (binding_args)), locus (locus)
393 {}
394
395 // copy constructor with vector clone
396 GenericArgs (GenericArgs const &other)
397 : lifetime_args (other.lifetime_args), generic_args (other.generic_args),
398 binding_args (other.binding_args), locus (other.locus)
399 {}
400
401 ~GenericArgs () = default;
402
403 // overloaded assignment operator to vector clone
404 GenericArgs &operator= (GenericArgs const &other)
405 {
406 lifetime_args = other.lifetime_args;
407 generic_args = other.generic_args;
408 binding_args = other.binding_args;
409 locus = other.locus;
410
411 return *this;
412 }
413
414 // move constructors
415 GenericArgs (GenericArgs &&other) = default;
416 GenericArgs &operator= (GenericArgs &&other) = default;
417
418 // Creates an empty GenericArgs (no arguments)
419 static GenericArgs create_empty () { return GenericArgs ({}, {}, {}); }
420
421 std::string as_string () const;
422
423 // TODO: is this better? Or is a "vis_pattern" better?
424 std::vector<GenericArg> &get_generic_args () { return generic_args; }
425
426 // TODO: is this better? Or is a "vis_pattern" better?
427 std::vector<GenericArgsBinding> &get_binding_args () { return binding_args; }
428
429 std::vector<Lifetime> &get_lifetime_args () { return lifetime_args; };
430
431 Location get_locus () { return locus; }
432 };
433
434 /* A segment of a path in expression, including an identifier aspect and maybe
435 * generic args */
436 class PathExprSegment
437 { // or should this extend PathIdentSegment?
438 private:
439 PathIdentSegment segment_name;
440 GenericArgs generic_args;
441 Location locus;
442 NodeId node_id;
443
444 public:
445 // Returns true if there are any generic arguments
446 bool has_generic_args () const { return generic_args.has_generic_args (); }
447
448 // Constructor for segment (from IdentSegment and GenericArgs)
449 PathExprSegment (PathIdentSegment segment_name, Location locus,
450 GenericArgs generic_args = GenericArgs::create_empty ())
451 : segment_name (std::move (segment_name)),
452 generic_args (std::move (generic_args)), locus (locus),
453 node_id (Analysis::Mappings::get ()->get_next_node_id ())
454 {}
455
456 /* Constructor for segment with generic arguments (from segment name and all
457 * args) */
458 PathExprSegment (std::string segment_name, Location locus,
459 std::vector<Lifetime> lifetime_args = {},
460 std::vector<GenericArg> generic_args = {},
461 std::vector<GenericArgsBinding> binding_args = {})
462 : segment_name (PathIdentSegment (std::move (segment_name), locus)),
463 generic_args (GenericArgs (std::move (lifetime_args),
464 std::move (generic_args),
465 std::move (binding_args))),
466 locus (locus), node_id (Analysis::Mappings::get ()->get_next_node_id ())
467 {}
468
469 // Returns whether path expression segment is in an error state.
470 bool is_error () const { return segment_name.is_error (); }
471
472 // Creates an error-state path expression segment.
473 static PathExprSegment create_error ()
474 {
475 return PathExprSegment (PathIdentSegment::create_error (), Location ());
476 }
477
478 std::string as_string () const;
479
480 Location get_locus () const { return locus; }
481
482 // TODO: is this better? Or is a "vis_pattern" better?
483 GenericArgs &get_generic_args ()
484 {
485 rust_assert (has_generic_args ());
486 return generic_args;
487 }
488
489 PathIdentSegment &get_ident_segment () { return segment_name; }
490 const PathIdentSegment &get_ident_segment () const { return segment_name; }
491
492 NodeId get_node_id () const { return node_id; }
493
494 bool is_super_path_seg () const
495 {
496 return !has_generic_args () && get_ident_segment ().is_super_segment ();
497 }
498
499 bool is_crate_path_seg () const
500 {
501 return !has_generic_args () && get_ident_segment ().is_crate_segment ();
502 }
503 bool is_lower_self_seg () const
504 {
505 return !has_generic_args () && get_ident_segment ().is_lower_self ();
506 }
507 };
508
509 // AST node representing a pattern that involves a "path" - abstract base
510 // class
511 class PathPattern : public Pattern
512 {
513 std::vector<PathExprSegment> segments;
514
515 protected:
516 PathPattern (std::vector<PathExprSegment> segments)
517 : segments (std::move (segments))
518 {}
519
520 // Returns whether path has segments.
521 bool has_segments () const { return !segments.empty (); }
522
523 /* Converts path segments to their equivalent SimplePath segments if
524 * possible, and creates a SimplePath from them. */
525 SimplePath convert_to_simple_path (bool with_opening_scope_resolution) const;
526
527 // Removes all segments of the path.
528 void remove_all_segments ()
529 {
530 segments.clear ();
531 segments.shrink_to_fit ();
532 }
533
534 public:
535 /* Returns whether the path is a single segment (excluding qualified path
536 * initial as segment). */
537 bool is_single_segment () const { return segments.size () == 1; }
538
539 std::string as_string () const override;
540
541 // TODO: this seems kinda dodgy
542 std::vector<PathExprSegment> &get_segments () { return segments; }
543 const std::vector<PathExprSegment> &get_segments () const { return segments; }
544 };
545
546 /* AST node representing a path-in-expression pattern (path that allows
547 * generic arguments) */
548 class PathInExpression : public PathPattern, public PathExpr
549 {
550 std::vector<Attribute> outer_attrs;
551 bool has_opening_scope_resolution;
552 Location locus;
553 NodeId _node_id;
554
555 public:
556 std::string as_string () const override;
557
558 // Constructor
559 PathInExpression (std::vector<PathExprSegment> path_segments,
560 std::vector<Attribute> outer_attrs, Location locus,
561 bool has_opening_scope_resolution = false)
562 : PathPattern (std::move (path_segments)),
563 outer_attrs (std::move (outer_attrs)),
564 has_opening_scope_resolution (has_opening_scope_resolution),
565 locus (locus), _node_id (Analysis::Mappings::get ()->get_next_node_id ())
566 {}
567
568 // Creates an error state path in expression.
569 static PathInExpression create_error ()
570 {
571 return PathInExpression ({}, {}, Location ());
572 }
573
574 // Returns whether path in expression is in an error state.
575 bool is_error () const { return !has_segments (); }
576
577 /* Converts PathInExpression to SimplePath if possible (i.e. no generic
578 * arguments). Otherwise returns an empty SimplePath. */
579 SimplePath as_simple_path () const
580 {
581 /* delegate to parent class as can't access segments. however,
582 * QualifiedPathInExpression conversion to simple path wouldn't make
583 * sense, so the method in the parent class should be protected, not
584 * public. Have to pass in opening scope resolution as parent class has no
585 * access to it.
586 */
587 return convert_to_simple_path (has_opening_scope_resolution);
588 }
589
590 Location get_locus () const override final { return locus; }
591
592 void accept_vis (ASTVisitor &vis) override;
593
594 // Invalid if path is empty (error state), so base stripping on that.
595 void mark_for_strip () override { remove_all_segments (); }
596 bool is_marked_for_strip () const override { return is_error (); }
597
598 bool opening_scope_resolution () const
599 {
600 return has_opening_scope_resolution;
601 }
602
603 NodeId get_node_id () const override { return _node_id; }
604
605 const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
606 std::vector<Attribute> &get_outer_attrs () { return outer_attrs; }
607
608 void set_outer_attrs (std::vector<Attribute> new_attrs) override
609 {
610 outer_attrs = std::move (new_attrs);
611 }
612
613 NodeId get_pattern_node_id () const override final { return get_node_id (); }
614
615 protected:
616 /* Use covariance to implement clone function as returning this object
617 * rather than base */
618 PathInExpression *clone_pattern_impl () const final override
619 {
620 return clone_path_in_expression_impl ();
621 }
622
623 /* Use covariance to implement clone function as returning this object
624 * rather than base */
625 PathInExpression *clone_expr_without_block_impl () const final override
626 {
627 return clone_path_in_expression_impl ();
628 }
629
630 /*virtual*/ PathInExpression *clone_path_in_expression_impl () const
631 {
632 return new PathInExpression (*this);
633 }
634 };
635
636 /* Base class for segments used in type paths - not abstract (represents an
637 * ident-only segment) */
638 class TypePathSegment
639 {
640 public:
641 enum SegmentType
642 {
643 REG,
644 GENERIC,
645 FUNCTION
646 };
647
648 private:
649 PathIdentSegment ident_segment;
650 Location locus;
651
652 protected:
653 /* This is protected because it is only really used by derived classes, not
654 * the base. */
655 bool has_separating_scope_resolution;
656 NodeId node_id;
657
658 // Clone function implementation - not pure virtual as overrided by
659 // subclasses
660 virtual TypePathSegment *clone_type_path_segment_impl () const
661 {
662 return new TypePathSegment (*this);
663 }
664
665 public:
666 virtual ~TypePathSegment () {}
667
668 virtual SegmentType get_type () const { return SegmentType::REG; }
669
670 // Unique pointer custom clone function
671 std::unique_ptr<TypePathSegment> clone_type_path_segment () const
672 {
673 return std::unique_ptr<TypePathSegment> (clone_type_path_segment_impl ());
674 }
675
676 TypePathSegment (PathIdentSegment ident_segment,
677 bool has_separating_scope_resolution, Location locus)
678 : ident_segment (std::move (ident_segment)), locus (locus),
679 has_separating_scope_resolution (has_separating_scope_resolution),
680 node_id (Analysis::Mappings::get ()->get_next_node_id ())
681 {}
682
683 TypePathSegment (std::string segment_name,
684 bool has_separating_scope_resolution, Location locus)
685 : ident_segment (PathIdentSegment (std::move (segment_name), locus)),
686 locus (locus),
687 has_separating_scope_resolution (has_separating_scope_resolution),
688 node_id (Analysis::Mappings::get ()->get_next_node_id ())
689 {}
690
691 virtual std::string as_string () const { return ident_segment.as_string (); }
692
693 /* Returns whether the type path segment is in an error state. May be
694 * virtual in future. */
695 bool is_error () const { return ident_segment.is_error (); }
696
697 /* Returns whether segment is identifier only (as opposed to generic args or
698 * function). Overridden in derived classes with other segments. */
699 virtual bool is_ident_only () const { return true; }
700
701 Location get_locus () const { return locus; }
702
703 // not pure virtual as class not abstract
704 virtual void accept_vis (ASTVisitor &vis);
705
706 bool get_separating_scope_resolution () const
707 {
708 return has_separating_scope_resolution;
709 }
710
711 PathIdentSegment &get_ident_segment () { return ident_segment; };
712 const PathIdentSegment &get_ident_segment () const { return ident_segment; };
713
714 NodeId get_node_id () const { return node_id; }
715
716 bool is_crate_path_seg () const
717 {
718 return get_ident_segment ().is_crate_segment ();
719 }
720 bool is_super_path_seg () const
721 {
722 return get_ident_segment ().is_super_segment ();
723 }
724 bool is_big_self_seg () const { return get_ident_segment ().is_big_self (); }
725 bool is_lower_self_seg () const
726 {
727 return get_ident_segment ().is_lower_self ();
728 }
729 };
730
731 // Segment used in type path with generic args
732 class TypePathSegmentGeneric : public TypePathSegment
733 {
734 GenericArgs generic_args;
735
736 public:
737 SegmentType get_type () const override { return SegmentType::GENERIC; }
738
739 bool has_generic_args () const { return generic_args.has_generic_args (); }
740
741 bool is_ident_only () const override { return false; }
742
743 // Constructor with PathIdentSegment and GenericArgs
744 TypePathSegmentGeneric (PathIdentSegment ident_segment,
745 bool has_separating_scope_resolution,
746 GenericArgs generic_args, Location locus)
747 : TypePathSegment (std::move (ident_segment),
748 has_separating_scope_resolution, locus),
749 generic_args (std::move (generic_args))
750 {}
751
752 // Constructor from segment name and all args
753 TypePathSegmentGeneric (std::string segment_name,
754 bool has_separating_scope_resolution,
755 std::vector<Lifetime> lifetime_args,
756 std::vector<GenericArg> generic_args,
757 std::vector<GenericArgsBinding> binding_args,
758 Location locus)
759 : TypePathSegment (std::move (segment_name),
760 has_separating_scope_resolution, locus),
761 generic_args (GenericArgs (std::move (lifetime_args),
762 std::move (generic_args),
763 std::move (binding_args)))
764 {}
765
766 std::string as_string () const override;
767
768 void accept_vis (ASTVisitor &vis) override;
769
770 // TODO: is this better? Or is a "vis_pattern" better?
771 GenericArgs &get_generic_args ()
772 {
773 rust_assert (has_generic_args ());
774 return generic_args;
775 }
776
777 protected:
778 // Use covariance to override base class method
779 TypePathSegmentGeneric *clone_type_path_segment_impl () const override
780 {
781 return new TypePathSegmentGeneric (*this);
782 }
783 };
784
785 // A function as represented in a type path
786 struct TypePathFunction
787 {
788 private:
789 // TODO: remove
790 /*bool has_inputs;
791 TypePathFnInputs inputs;*/
792 // inlined from TypePathFnInputs
793 std::vector<std::unique_ptr<Type> > inputs;
794
795 // bool has_type;
796 std::unique_ptr<Type> return_type;
797
798 // FIXME: think of better way to mark as invalid than taking up storage
799 bool is_invalid;
800
801 Location locus;
802
803 protected:
804 // Constructor only used to create invalid type path functions.
805 TypePathFunction (bool is_invalid, Location locus)
806 : is_invalid (is_invalid), locus (locus)
807 {}
808
809 public:
810 // Returns whether the return type of the function has been specified.
811 bool has_return_type () const { return return_type != nullptr; }
812
813 // Returns whether the function has inputs.
814 bool has_inputs () const { return !inputs.empty (); }
815
816 // Returns whether function is in an error state.
817 bool is_error () const { return is_invalid; }
818
819 // Creates an error state function.
820 static TypePathFunction create_error ()
821 {
822 return TypePathFunction (true, Location ());
823 }
824
825 // Constructor
826 TypePathFunction (std::vector<std::unique_ptr<Type> > inputs, Location locus,
827 std::unique_ptr<Type> type = nullptr)
828 : inputs (std::move (inputs)), return_type (std::move (type)),
829 is_invalid (false), locus (locus)
830 {}
831
832 // Copy constructor with clone
833 TypePathFunction (TypePathFunction const &other)
834 : is_invalid (other.is_invalid)
835 {
836 // guard to protect from null pointer dereference
837 if (other.return_type != nullptr)
838 return_type = other.return_type->clone_type ();
839
840 inputs.reserve (other.inputs.size ());
841 for (const auto &e : other.inputs)
842 inputs.push_back (e->clone_type ());
843 }
844
845 ~TypePathFunction () = default;
846
847 // Overloaded assignment operator to clone type
848 TypePathFunction &operator= (TypePathFunction const &other)
849 {
850 is_invalid = other.is_invalid;
851
852 // guard to protect from null pointer dereference
853 if (other.return_type != nullptr)
854 return_type = other.return_type->clone_type ();
855 else
856 return_type = nullptr;
857
858 inputs.reserve (other.inputs.size ());
859 for (const auto &e : other.inputs)
860 inputs.push_back (e->clone_type ());
861
862 return *this;
863 }
864
865 // move constructors
866 TypePathFunction (TypePathFunction &&other) = default;
867 TypePathFunction &operator= (TypePathFunction &&other) = default;
868
869 std::string as_string () const;
870
871 // TODO: this mutable getter seems really dodgy. Think up better way.
872 const std::vector<std::unique_ptr<Type> > &get_params () const
873 {
874 return inputs;
875 }
876 std::vector<std::unique_ptr<Type> > &get_params () { return inputs; }
877
878 // TODO: is this better? Or is a "vis_pattern" better?
879 std::unique_ptr<Type> &get_return_type ()
880 {
881 rust_assert (has_return_type ());
882 return return_type;
883 }
884 };
885
886 // Segment used in type path with a function argument
887 class TypePathSegmentFunction : public TypePathSegment
888 {
889 TypePathFunction function_path;
890
891 public:
892 SegmentType get_type () const override { return SegmentType::FUNCTION; }
893
894 // Constructor with PathIdentSegment and TypePathFn
895 TypePathSegmentFunction (PathIdentSegment ident_segment,
896 bool has_separating_scope_resolution,
897 TypePathFunction function_path, Location locus)
898 : TypePathSegment (std::move (ident_segment),
899 has_separating_scope_resolution, locus),
900 function_path (std::move (function_path))
901 {}
902
903 // Constructor with segment name and TypePathFn
904 TypePathSegmentFunction (std::string segment_name,
905 bool has_separating_scope_resolution,
906 TypePathFunction function_path, Location locus)
907 : TypePathSegment (std::move (segment_name),
908 has_separating_scope_resolution, locus),
909 function_path (std::move (function_path))
910 {}
911
912 std::string as_string () const override;
913
914 bool is_ident_only () const override { return false; }
915
916 void accept_vis (ASTVisitor &vis) override;
917
918 // TODO: is this better? Or is a "vis_pattern" better?
919 TypePathFunction &get_type_path_function ()
920 {
921 rust_assert (!function_path.is_error ());
922 return function_path;
923 }
924
925 protected:
926 // Use covariance to override base class method
927 TypePathSegmentFunction *clone_type_path_segment_impl () const override
928 {
929 return new TypePathSegmentFunction (*this);
930 }
931 };
932
933 // Path used inside types
934 class TypePath : public TypeNoBounds
935 {
936 bool has_opening_scope_resolution;
937 std::vector<std::unique_ptr<TypePathSegment> > segments;
938 Location locus;
939
940 protected:
941 /* Use covariance to implement clone function as returning this object
942 * rather than base */
943 TypePath *clone_type_no_bounds_impl () const override
944 {
945 return new TypePath (*this);
946 }
947
948 public:
949 /* Returns whether the TypePath has an opening scope resolution operator
950 * (i.e. is global path or crate-relative path, not module-relative) */
951 bool has_opening_scope_resolution_op () const
952 {
953 return has_opening_scope_resolution;
954 }
955
956 // Returns whether the TypePath is in an invalid state.
957 bool is_error () const { return segments.empty (); }
958
959 // Creates an error state TypePath.
960 static TypePath create_error ()
961 {
962 return TypePath (std::vector<std::unique_ptr<TypePathSegment> > (),
963 Location ());
964 }
965
966 // Constructor
967 TypePath (std::vector<std::unique_ptr<TypePathSegment> > segments,
968 Location locus, bool has_opening_scope_resolution = false)
969 : TypeNoBounds (),
970 has_opening_scope_resolution (has_opening_scope_resolution),
971 segments (std::move (segments)), locus (locus)
972 {}
973
974 // Copy constructor with vector clone
975 TypePath (TypePath const &other)
976 : has_opening_scope_resolution (other.has_opening_scope_resolution),
977 locus (other.locus)
978 {
979 segments.reserve (other.segments.size ());
980 for (const auto &e : other.segments)
981 segments.push_back (e->clone_type_path_segment ());
982 }
983
984 // Overloaded assignment operator with clone
985 TypePath &operator= (TypePath const &other)
986 {
987 has_opening_scope_resolution = other.has_opening_scope_resolution;
988 locus = other.locus;
989
990 segments.reserve (other.segments.size ());
991 for (const auto &e : other.segments)
992 segments.push_back (e->clone_type_path_segment ());
993
994 return *this;
995 }
996
997 // move constructors
998 TypePath (TypePath &&other) = default;
999 TypePath &operator= (TypePath &&other) = default;
1000
1001 std::string as_string () const override;
1002
1003 /* Converts TypePath to SimplePath if possible (i.e. no generic or function
1004 * arguments). Otherwise returns an empty SimplePath. */
1005 SimplePath as_simple_path () const;
1006
1007 // Creates a trait bound with a clone of this type path as its only element.
1008 TraitBound *to_trait_bound (bool in_parens) const override;
1009
1010 Location get_locus () const override final { return locus; }
1011
1012 void accept_vis (ASTVisitor &vis) override;
1013
1014 // TODO: this seems kinda dodgy
1015 std::vector<std::unique_ptr<TypePathSegment> > &get_segments ()
1016 {
1017 return segments;
1018 }
1019 const std::vector<std::unique_ptr<TypePathSegment> > &get_segments () const
1020 {
1021 return segments;
1022 }
1023
1024 size_t get_num_segments () const { return segments.size (); }
1025 };
1026
1027 struct QualifiedPathType
1028 {
1029 private:
1030 std::unique_ptr<Type> type_to_invoke_on;
1031 TypePath trait_path;
1032 Location locus;
1033 NodeId node_id;
1034
1035 public:
1036 // Constructor
1037 QualifiedPathType (std::unique_ptr<Type> invoke_on_type,
1038 Location locus = Location (),
1039 TypePath trait_path = TypePath::create_error ())
1040 : type_to_invoke_on (std::move (invoke_on_type)),
1041 trait_path (std::move (trait_path)), locus (locus),
1042 node_id (Analysis::Mappings::get ()->get_next_node_id ())
1043 {}
1044
1045 // Copy constructor uses custom deep copy for Type to preserve polymorphism
1046 QualifiedPathType (QualifiedPathType const &other)
1047 : trait_path (other.trait_path), locus (other.locus)
1048 {
1049 node_id = other.node_id;
1050 // guard to prevent null dereference
1051 if (other.type_to_invoke_on != nullptr)
1052 type_to_invoke_on = other.type_to_invoke_on->clone_type ();
1053 }
1054
1055 // default destructor
1056 ~QualifiedPathType () = default;
1057
1058 // overload assignment operator to use custom clone method
1059 QualifiedPathType &operator= (QualifiedPathType const &other)
1060 {
1061 node_id = other.node_id;
1062 trait_path = other.trait_path;
1063 locus = other.locus;
1064
1065 // guard to prevent null dereference
1066 if (other.type_to_invoke_on != nullptr)
1067 type_to_invoke_on = other.type_to_invoke_on->clone_type ();
1068 else
1069 type_to_invoke_on = nullptr;
1070
1071 return *this;
1072 }
1073
1074 // move constructor
1075 QualifiedPathType (QualifiedPathType &&other) = default;
1076 QualifiedPathType &operator= (QualifiedPathType &&other) = default;
1077
1078 // Returns whether the qualified path type has a rebind as clause.
1079 bool has_as_clause () const { return !trait_path.is_error (); }
1080
1081 // Returns whether the qualified path type is in an error state.
1082 bool is_error () const { return type_to_invoke_on == nullptr; }
1083
1084 // Creates an error state qualified path type.
1085 static QualifiedPathType create_error ()
1086 {
1087 return QualifiedPathType (nullptr);
1088 }
1089
1090 std::string as_string () const;
1091
1092 Location get_locus () const { return locus; }
1093
1094 // TODO: is this better? Or is a "vis_pattern" better?
1095 std::unique_ptr<Type> &get_type ()
1096 {
1097 rust_assert (type_to_invoke_on != nullptr);
1098 return type_to_invoke_on;
1099 }
1100
1101 // TODO: is this better? Or is a "vis_pattern" better?
1102 TypePath &get_as_type_path ()
1103 {
1104 rust_assert (has_as_clause ());
1105 return trait_path;
1106 }
1107
1108 NodeId get_node_id () const { return node_id; }
1109 };
1110
1111 /* AST node representing a qualified path-in-expression pattern (path that
1112 * allows specifying trait functions) */
1113 class QualifiedPathInExpression : public PathPattern, public PathExpr
1114 {
1115 std::vector<Attribute> outer_attrs;
1116 QualifiedPathType path_type;
1117 Location locus;
1118 NodeId _node_id;
1119
1120 public:
1121 std::string as_string () const override;
1122
1123 QualifiedPathInExpression (QualifiedPathType qual_path_type,
1124 std::vector<PathExprSegment> path_segments,
1125 std::vector<Attribute> outer_attrs, Location locus)
1126 : PathPattern (std::move (path_segments)),
1127 outer_attrs (std::move (outer_attrs)),
1128 path_type (std::move (qual_path_type)), locus (locus),
1129 _node_id (Analysis::Mappings::get ()->get_next_node_id ())
1130 {}
1131
1132 /* TODO: maybe make a shortcut constructor that has QualifiedPathType
1133 * elements as params */
1134
1135 // Returns whether qualified path in expression is in an error state.
1136 bool is_error () const { return path_type.is_error (); }
1137
1138 // Creates an error qualified path in expression.
1139 static QualifiedPathInExpression create_error ()
1140 {
1141 return QualifiedPathInExpression (QualifiedPathType::create_error (), {},
1142 {}, Location ());
1143 }
1144
1145 Location get_locus () const override final { return locus; }
1146
1147 void accept_vis (ASTVisitor &vis) override;
1148
1149 // Invalid if path_type is error, so base stripping on that.
1150 void mark_for_strip () override
1151 {
1152 path_type = QualifiedPathType::create_error ();
1153 }
1154 bool is_marked_for_strip () const override { return is_error (); }
1155
1156 // TODO: is this better? Or is a "vis_pattern" better?
1157 QualifiedPathType &get_qualified_path_type ()
1158 {
1159 rust_assert (!path_type.is_error ());
1160 return path_type;
1161 }
1162
1163 const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
1164 std::vector<Attribute> &get_outer_attrs () { return outer_attrs; }
1165
1166 void set_outer_attrs (std::vector<Attribute> new_attrs) override
1167 {
1168 outer_attrs = std::move (new_attrs);
1169 }
1170
1171 NodeId get_node_id () const override { return _node_id; }
1172
1173 NodeId get_pattern_node_id () const override final { return get_node_id (); }
1174
1175 protected:
1176 /* Use covariance to implement clone function as returning this object
1177 * rather than base */
1178 QualifiedPathInExpression *clone_pattern_impl () const final override
1179 {
1180 return clone_qual_path_in_expression_impl ();
1181 }
1182
1183 /* Use covariance to implement clone function as returning this object
1184 * rather than base */
1185 QualifiedPathInExpression *
1186 clone_expr_without_block_impl () const final override
1187 {
1188 return clone_qual_path_in_expression_impl ();
1189 }
1190
1191 /*virtual*/ QualifiedPathInExpression *
1192 clone_qual_path_in_expression_impl () const
1193 {
1194 return new QualifiedPathInExpression (*this);
1195 }
1196 };
1197
1198 /* Represents a qualified path in a type; used for disambiguating trait
1199 * function calls */
1200 class QualifiedPathInType : public TypeNoBounds
1201 {
1202 QualifiedPathType path_type;
1203 std::unique_ptr<TypePathSegment> associated_segment;
1204 std::vector<std::unique_ptr<TypePathSegment> > segments;
1205 Location locus;
1206
1207 protected:
1208 /* Use covariance to implement clone function as returning this object
1209 * rather than base */
1210 QualifiedPathInType *clone_type_no_bounds_impl () const override
1211 {
1212 return new QualifiedPathInType (*this);
1213 }
1214
1215 public:
1216 QualifiedPathInType (
1217 QualifiedPathType qual_path_type,
1218 std::unique_ptr<TypePathSegment> associated_segment,
1219 std::vector<std::unique_ptr<TypePathSegment> > path_segments,
1220 Location locus)
1221 : path_type (std::move (qual_path_type)),
1222 associated_segment (std::move (associated_segment)),
1223 segments (std::move (path_segments)), locus (locus)
1224 {}
1225
1226 /* TODO: maybe make a shortcut constructor that has QualifiedPathType
1227 * elements as params */
1228
1229 // Copy constructor with vector clone
1230 QualifiedPathInType (QualifiedPathInType const &other)
1231 : path_type (other.path_type), locus (other.locus)
1232 {
1233 segments.reserve (other.segments.size ());
1234 for (const auto &e : other.segments)
1235 segments.push_back (e->clone_type_path_segment ());
1236 }
1237
1238 // Overloaded assignment operator with vector clone
1239 QualifiedPathInType &operator= (QualifiedPathInType const &other)
1240 {
1241 path_type = other.path_type;
1242 locus = other.locus;
1243
1244 segments.reserve (other.segments.size ());
1245 for (const auto &e : other.segments)
1246 segments.push_back (e->clone_type_path_segment ());
1247
1248 return *this;
1249 }
1250
1251 // move constructors
1252 QualifiedPathInType (QualifiedPathInType &&other) = default;
1253 QualifiedPathInType &operator= (QualifiedPathInType &&other) = default;
1254
1255 // Returns whether qualified path in type is in an error state.
1256 bool is_error () const { return path_type.is_error (); }
1257
1258 // Creates an error state qualified path in type.
1259 static QualifiedPathInType create_error ()
1260 {
1261 return QualifiedPathInType (
1262 QualifiedPathType::create_error (), nullptr,
1263 std::vector<std::unique_ptr<TypePathSegment> > (), Location ());
1264 }
1265
1266 std::string as_string () const override;
1267
1268 void accept_vis (ASTVisitor &vis) override;
1269
1270 // TODO: is this better? Or is a "vis_pattern" better?
1271 QualifiedPathType &get_qualified_path_type ()
1272 {
1273 rust_assert (!path_type.is_error ());
1274 return path_type;
1275 }
1276
1277 std::unique_ptr<TypePathSegment> &get_associated_segment ()
1278 {
1279 return associated_segment;
1280 }
1281
1282 // TODO: this seems kinda dodgy
1283 std::vector<std::unique_ptr<TypePathSegment> > &get_segments ()
1284 {
1285 return segments;
1286 }
1287 const std::vector<std::unique_ptr<TypePathSegment> > &get_segments () const
1288 {
1289 return segments;
1290 }
1291
1292 Location get_locus () const override final { return locus; }
1293 };
1294 } // namespace AST
1295 } // namespace Rust
1296
1297 #endif