]>
Commit | Line | Data |
---|---|---|
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 | ||
27 | namespace Rust { | |
28 | namespace AST { | |
29 | ||
30 | // The "identifier" (not generic args) aspect of each path expression segment | |
31 | class PathIdentSegment | |
32 | { | |
33 | std::string segment_name; | |
34 | Location locus; | |
35 | ||
36 | // only allow identifiers, "super", "self", "Self", "crate", or "$crate" | |
37 | public: | |
38 | PathIdentSegment (std::string segment_name, Location locus) | |
39 | : segment_name (std::move (segment_name)), locus (locus) | |
40 | {} | |
41 | ||
42 | // Creates an error PathIdentSegment. | |
43 | static PathIdentSegment create_error () | |
44 | { | |
45 | return PathIdentSegment ("", Location ()); | |
46 | } | |
47 | ||
48 | // Returns whether PathIdentSegment is in an error state. | |
49 | bool is_error () const { return segment_name.empty (); } | |
50 | ||
51 | std::string as_string () const { return segment_name; } | |
52 | ||
53 | Location get_locus () const { return locus; } | |
54 | ||
55 | bool is_super_segment () const { return as_string ().compare ("super") == 0; } | |
56 | bool is_crate_segment () const { return as_string ().compare ("crate") == 0; } | |
57 | bool is_lower_self () const { return as_string ().compare ("self") == 0; } | |
58 | bool is_big_self () const { return as_string ().compare ("Self") == 0; } | |
59 | }; | |
60 | ||
61 | // A binding of an identifier to a type used in generic arguments in paths | |
62 | struct GenericArgsBinding | |
63 | { | |
64 | private: | |
65 | Identifier identifier; | |
66 | std::unique_ptr<Type> type; | |
67 | Location locus; | |
68 | ||
69 | public: | |
70 | // Returns whether binding is in an error state. | |
71 | bool is_error () const | |
72 | { | |
73 | return type == nullptr; | |
74 | // and also identifier is empty, but cheaper computation | |
75 | } | |
76 | ||
77 | // Creates an error state generic args binding. | |
78 | static GenericArgsBinding create_error () | |
79 | { | |
80 | return GenericArgsBinding ("", nullptr); | |
81 | } | |
82 | ||
83 | // Pointer type for type in constructor to enable polymorphism | |
84 | GenericArgsBinding (Identifier ident, std::unique_ptr<Type> type_ptr, | |
85 | Location locus = Location ()) | |
86 | : identifier (std::move (ident)), type (std::move (type_ptr)), locus (locus) | |
87 | {} | |
88 | ||
89 | // Copy constructor has to deep copy the type as it is a unique pointer | |
90 | GenericArgsBinding (GenericArgsBinding const &other) | |
91 | : identifier (other.identifier), locus (other.locus) | |
92 | { | |
93 | // guard to protect from null pointer dereference | |
94 | if (other.type != nullptr) | |
95 | type = other.type->clone_type (); | |
96 | } | |
97 | ||
98 | // default destructor | |
99 | ~GenericArgsBinding () = default; | |
100 | ||
101 | // Overload assignment operator to deep copy the pointed-to type | |
102 | GenericArgsBinding &operator= (GenericArgsBinding const &other) | |
103 | { | |
104 | identifier = other.identifier; | |
105 | locus = other.locus; | |
106 | ||
107 | // guard to protect from null pointer dereference | |
108 | if (other.type != nullptr) | |
109 | type = other.type->clone_type (); | |
110 | else | |
111 | type = nullptr; | |
112 | ||
113 | return *this; | |
114 | } | |
115 | ||
116 | // move constructors | |
117 | GenericArgsBinding (GenericArgsBinding &&other) = default; | |
118 | GenericArgsBinding &operator= (GenericArgsBinding &&other) = default; | |
119 | ||
120 | std::string as_string () const; | |
121 | ||
122 | // TODO: is this better? Or is a "vis_pattern" better? | |
123 | std::unique_ptr<Type> &get_type () | |
124 | { | |
125 | rust_assert (type != nullptr); | |
126 | return type; | |
127 | } | |
128 | ||
129 | Location get_locus () const { return locus; } | |
130 | ||
131 | Identifier get_identifier () const { return identifier; } | |
132 | }; | |
133 | ||
134 | /* Class representing a const generic application */ | |
135 | class GenericArg | |
136 | { | |
137 | public: | |
138 | /** | |
139 | * const generic arguments cannot always be differentiated with generic type | |
140 | * arguments during parsing, e.g: | |
141 | * ```rust | |
142 | * let a: Foo<N>; | |
143 | * ``` | |
144 | * | |
145 | * Is N a type? A constant defined elsewhere? The parser cannot know, and must | |
146 | * not draw any conclusions. We must wait until later passes of the compiler | |
147 | * to decide whether this refers to a constant item or a type. | |
148 | * | |
149 | * On the other hand, simple expressions like literals or block expressions | |
150 | * will always be constant expressions: There is no ambiguity at all. | |
151 | */ | |
152 | enum class Kind | |
153 | { | |
154 | Error, | |
155 | Const, // A const value | |
156 | Type, // A type argument (not discernable during parsing) | |
157 | Either, // Either a type or a const value, cleared up during resolving | |
158 | }; | |
159 | ||
160 | static GenericArg create_error () | |
161 | { | |
162 | return GenericArg (nullptr, nullptr, "", Kind::Error, Location ()); | |
163 | } | |
164 | ||
165 | static GenericArg create_const (std::unique_ptr<Expr> expression) | |
166 | { | |
167 | auto locus = expression->get_locus (); | |
168 | return GenericArg (std::move (expression), nullptr, "", Kind::Const, locus); | |
169 | } | |
170 | ||
171 | static GenericArg create_type (std::unique_ptr<Type> type) | |
172 | { | |
173 | auto locus = type->get_locus (); | |
174 | return GenericArg (nullptr, std::move (type), "", Kind::Type, locus); | |
175 | } | |
176 | ||
177 | static GenericArg create_ambiguous (Identifier path, Location locus) | |
178 | { | |
179 | return GenericArg (nullptr, nullptr, std::move (path), Kind::Either, locus); | |
180 | } | |
181 | ||
182 | GenericArg (const GenericArg &other) | |
183 | : path (other.path), kind (other.kind), locus (other.locus) | |
184 | { | |
185 | if (other.expression) | |
186 | expression = other.expression->clone_expr (); | |
187 | if (other.type) | |
188 | type = other.type->clone_type (); | |
189 | } | |
190 | ||
191 | GenericArg operator= (const GenericArg &other) | |
192 | { | |
193 | kind = other.kind; | |
194 | path = other.path; | |
195 | locus = other.locus; | |
196 | ||
197 | if (other.expression) | |
198 | expression = other.expression->clone_expr (); | |
199 | if (other.type) | |
200 | type = other.type->clone_type (); | |
201 | ||
202 | return *this; | |
203 | } | |
204 | ||
205 | bool is_error () const { return kind == Kind::Error; } | |
206 | ||
207 | Kind get_kind () const { return kind; } | |
208 | const Location &get_locus () const { return locus; } | |
209 | ||
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 | ||
277 | private: | |
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 | */ | |
313 | class 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 | ||
329 | public: | |
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 | ||
378 | protected: | |
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? | |
388 | struct GenericArgs | |
389 | { | |
390 | std::vector<Lifetime> lifetime_args; | |
391 | std::vector<GenericArg> generic_args; | |
392 | std::vector<GenericArgsBinding> binding_args; | |
393 | Location locus; | |
394 | ||
395 | public: | |
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 */ | |
453 | class PathExprSegment | |
454 | { // or should this extend PathIdentSegment? | |
455 | private: | |
456 | PathIdentSegment segment_name; | |
457 | GenericArgs generic_args; | |
458 | Location locus; | |
459 | NodeId node_id; | |
460 | ||
461 | public: | |
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 | |
528 | class PathPattern : public Pattern | |
529 | { | |
530 | std::vector<PathExprSegment> segments; | |
531 | ||
532 | protected: | |
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 | ||
551 | public: | |
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) */ | |
565 | class 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 | ||
572 | public: | |
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 | ||
632 | protected: | |
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) */ | |
655 | class TypePathSegment | |
656 | { | |
657 | public: | |
658 | enum SegmentType | |
659 | { | |
660 | REG, | |
661 | GENERIC, | |
662 | FUNCTION | |
663 | }; | |
664 | ||
665 | private: | |
666 | PathIdentSegment ident_segment; | |
667 | Location locus; | |
668 | ||
669 | protected: | |
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 | ||
682 | public: | |
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 | |
749 | class TypePathSegmentGeneric : public TypePathSegment | |
750 | { | |
751 | GenericArgs generic_args; | |
752 | ||
753 | public: | |
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 | ||
794 | protected: | |
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 | |
803 | struct TypePathFunction | |
804 | { | |
805 | private: | |
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 | ||
820 | protected: | |
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 | ||
826 | public: | |
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 | |
906 | class TypePathSegmentFunction : public TypePathSegment | |
907 | { | |
908 | TypePathFunction function_path; | |
909 | ||
910 | public: | |
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 | ||
944 | protected: | |
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 | |
953 | class TypePath : public TypeNoBounds | |
954 | { | |
955 | bool has_opening_scope_resolution; | |
956 | std::vector<std::unique_ptr<TypePathSegment> > segments; | |
957 | Location locus; | |
958 | ||
959 | protected: | |
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 | ||
967 | public: | |
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 | ||
1046 | struct QualifiedPathType | |
1047 | { | |
1048 | private: | |
1049 | std::unique_ptr<Type> type_to_invoke_on; | |
1050 | TypePath trait_path; | |
1051 | Location locus; | |
1052 | NodeId node_id; | |
1053 | ||
1054 | public: | |
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) */ | |
1132 | class QualifiedPathInExpression : public PathPattern, public PathExpr | |
1133 | { | |
1134 | std::vector<Attribute> outer_attrs; | |
1135 | QualifiedPathType path_type; | |
1136 | Location locus; | |
1137 | NodeId _node_id; | |
1138 | ||
1139 | public: | |
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 | ||
1194 | protected: | |
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 */ | |
1219 | class 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 | ||
1226 | protected: | |
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 | ||
1234 | public: | |
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 |