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