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