]>
Commit | Line | Data |
---|---|---|
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 | 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 | PathIdentSegment (std::string segment_name, location_t locus) | |
43 | : segment_name (std::move (segment_name)), locus (locus) | |
44 | {} | |
45 | ||
46 | // Creates an error PathIdentSegment. | |
47 | static PathIdentSegment create_error () | |
48 | { | |
49 | return PathIdentSegment ("", UNDEF_LOCATION); | |
50 | } | |
51 | ||
52 | // Returns whether PathIdentSegment is in an error state. | |
53 | bool is_error () const { return segment_name.empty (); } | |
54 | ||
55 | std::string as_string () const { return segment_name; } | |
56 | ||
57 | location_t get_locus () const { return locus; } | |
58 | ||
59 | bool is_super_path_seg () const | |
60 | { | |
61 | return as_string ().compare ("super") == 0; | |
62 | } | |
63 | bool is_crate_path_seg () const | |
64 | { | |
65 | return as_string ().compare ("crate") == 0; | |
66 | } | |
67 | bool is_lower_self_seg () const { return as_string ().compare ("self") == 0; } | |
68 | 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 | bool is_error () const | |
82 | { | |
83 | return type == nullptr; | |
84 | // and also identifier is empty, but cheaper computation | |
85 | } | |
86 | ||
87 | // Creates an error state generic args binding. | |
88 | static GenericArgsBinding create_error () | |
89 | { | |
90 | return GenericArgsBinding ({""}, nullptr); | |
91 | } | |
92 | ||
93 | // Pointer type for type in constructor to enable polymorphism | |
94 | GenericArgsBinding (Identifier ident, std::unique_ptr<Type> type_ptr, | |
95 | location_t locus = UNDEF_LOCATION) | |
96 | : 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 | GenericArgsBinding (GenericArgsBinding const &other) | |
101 | : identifier (other.identifier), locus (other.locus) | |
102 | { | |
103 | // guard to protect from null pointer dereference | |
104 | if (other.type != nullptr) | |
105 | type = other.type->clone_type (); | |
106 | } | |
107 | ||
108 | // default destructor | |
109 | ~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 | 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 | Type &get_type () | |
134 | { | |
135 | rust_assert (type != nullptr); | |
136 | return *type; | |
137 | } | |
138 | ||
139 | std::unique_ptr<Type> &get_type_ptr () | |
140 | { | |
141 | rust_assert (type != nullptr); | |
142 | return type; | |
143 | } | |
144 | ||
145 | location_t get_locus () const { return locus; } | |
146 | ||
147 | 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 | static GenericArg create_const (std::unique_ptr<Expr> expression) | |
176 | { | |
177 | auto locus = expression->get_locus (); | |
178 | return GenericArg (std::move (expression), nullptr, {""}, Kind::Const, | |
179 | locus); | |
180 | } | |
181 | ||
182 | static GenericArg create_type (std::unique_ptr<Type> type) | |
183 | { | |
184 | auto locus = type->get_locus (); | |
185 | return GenericArg (nullptr, std::move (type), {""}, Kind::Type, locus); | |
186 | } | |
187 | ||
188 | static GenericArg create_ambiguous (Identifier path, location_t locus) | |
189 | { | |
190 | return GenericArg (nullptr, nullptr, std::move (path), Kind::Either, locus); | |
191 | } | |
192 | ||
193 | GenericArg (const GenericArg &other) | |
194 | : path (other.path), kind (other.kind), locus (other.locus) | |
195 | { | |
196 | if (other.expression) | |
197 | expression = other.expression->clone_expr (); | |
198 | if (other.type) | |
199 | type = other.type->clone_type (); | |
200 | } | |
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 | GenericArg (GenericArg &&other) = default; | |
217 | GenericArg &operator= (GenericArg &&other) = default; | |
218 | ||
219 | Kind get_kind () const { return kind; } | |
220 | location_t get_locus () const { return locus; } | |
221 | ||
222 | void accept_vis (AST::ASTVisitor &visitor) | |
223 | { | |
224 | switch (get_kind ()) | |
225 | { | |
226 | case Kind::Const: | |
227 | get_expression ().accept_vis (visitor); | |
228 | break; | |
229 | case Kind::Type: | |
230 | get_type ().accept_vis (visitor); | |
231 | break; | |
232 | case Kind::Either: | |
233 | break; | |
234 | } | |
235 | } | |
236 | ||
237 | Expr &get_expression () | |
238 | { | |
239 | rust_assert (kind == Kind::Const); | |
240 | ||
241 | return *expression; | |
242 | } | |
243 | ||
244 | std::unique_ptr<Expr> &get_expression_ptr () | |
245 | { | |
246 | rust_assert (kind == Kind::Const); | |
247 | ||
248 | return expression; | |
249 | } | |
250 | ||
251 | Type &get_type () | |
252 | { | |
253 | rust_assert (kind == Kind::Type); | |
254 | ||
255 | return *type; | |
256 | } | |
257 | ||
258 | std::unique_ptr<Type> &get_type_ptr () | |
259 | { | |
260 | rust_assert (kind == Kind::Type); | |
261 | ||
262 | return type; | |
263 | } | |
264 | ||
265 | const std::string get_path () const | |
266 | { | |
267 | rust_assert (kind == Kind::Either); | |
268 | ||
269 | return path.as_string (); | |
270 | } | |
271 | ||
272 | std::string as_string () const | |
273 | { | |
274 | switch (get_kind ()) | |
275 | { | |
276 | case Kind::Either: | |
277 | return "Ambiguous: " + path.as_string (); | |
278 | case Kind::Const: | |
279 | return "Const: { " + expression->as_string () + " }"; | |
280 | case Kind::Type: | |
281 | return "Type: " + type->as_string (); | |
282 | } | |
283 | ||
284 | 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 | GenericArg (std::unique_ptr<Expr> expression, std::unique_ptr<Type> type, | |
301 | Identifier path, Kind kind, location_t locus) | |
302 | : expression (std::move (expression)), type (std::move (type)), | |
303 | 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 | ConstGenericParam (Identifier name, std::unique_ptr<AST::Type> type, | |
353 | tl::optional<GenericArg> default_value, | |
354 | AST::AttrVec outer_attrs, location_t locus) | |
355 | : name (name), type (std::move (type)), | |
356 | default_value (std::move (default_value)), outer_attrs (outer_attrs), | |
357 | locus (locus) | |
358 | {} | |
359 | ||
360 | ConstGenericParam (const ConstGenericParam &other) | |
361 | : GenericParam (), name (other.name), type (other.type->clone_type ()), | |
362 | default_value (other.default_value), outer_attrs (other.outer_attrs), | |
363 | locus (other.locus) | |
364 | {} | |
365 | ||
366 | bool has_type () const { return type != nullptr; } | |
367 | bool has_default_value () const { return default_value.has_value (); } | |
368 | ||
369 | const Identifier &get_name () const { return name; } | |
370 | ||
371 | AST::AttrVec &get_outer_attrs () { return outer_attrs; } | |
372 | ||
373 | AST::Type &get_type () | |
374 | { | |
375 | rust_assert (has_type ()); | |
376 | ||
377 | return *type; | |
378 | } | |
379 | ||
380 | GenericArg &get_default_value_unchecked () | |
381 | { | |
382 | rust_assert (has_default_value ()); | |
383 | ||
384 | return default_value.value (); | |
385 | } | |
386 | ||
387 | const GenericArg &get_default_value_unchecked () const | |
388 | { | |
389 | rust_assert (has_default_value ()); | |
390 | ||
391 | return default_value.value (); | |
392 | } | |
393 | ||
394 | std::string as_string () const override; | |
395 | ||
396 | void accept_vis (ASTVisitor &vis) override; | |
397 | ||
398 | location_t get_locus () const override final { return locus; } | |
399 | ||
400 | 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 | ConstGenericParam *clone_generic_param_impl () const override | |
406 | { | |
407 | 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 | bool has_generic_args () const | |
422 | { | |
423 | return !(lifetime_args.empty () && generic_args.empty () | |
424 | && binding_args.empty ()); | |
425 | } | |
426 | ||
427 | 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 | : lifetime_args (std::move (lifetime_args)), | |
432 | generic_args (std::move (generic_args)), | |
433 | binding_args (std::move (binding_args)), locus (locus) | |
434 | {} | |
435 | ||
436 | // copy constructor with vector clone | |
437 | GenericArgs (GenericArgs const &other) | |
438 | : lifetime_args (other.lifetime_args), binding_args (other.binding_args), | |
439 | locus (other.locus) | |
440 | { | |
441 | generic_args.clear (); | |
442 | generic_args.reserve (other.generic_args.size ()); | |
443 | for (const auto &arg : other.generic_args) | |
444 | { | |
445 | generic_args.push_back (GenericArg (arg)); | |
446 | } | |
447 | } | |
448 | ||
449 | ~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 | GenericArgs (GenericArgs &&other) = default; | |
470 | GenericArgs &operator= (GenericArgs &&other) = default; | |
471 | ||
472 | // Creates an empty GenericArgs (no arguments) | |
473 | static GenericArgs create_empty () { return GenericArgs ({}, {}, {}); } | |
474 | ||
475 | std::string as_string () const; | |
476 | ||
477 | std::vector<GenericArg> &get_generic_args () { return generic_args; } | |
478 | ||
479 | 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 | 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 | 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 | 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 | bool has_generic_args () const { return generic_args.has_generic_args (); } | |
509 | ||
510 | // Constructor for segment (from IdentSegment and GenericArgs) | |
511 | PathExprSegment (PathIdentSegment segment_name, location_t locus, | |
512 | GenericArgs generic_args = GenericArgs::create_empty ()) | |
513 | : segment_name (std::move (segment_name)), | |
514 | generic_args (std::move (generic_args)), locus (locus), | |
515 | node_id (Analysis::Mappings::get ().get_next_node_id ()) | |
516 | {} | |
517 | ||
518 | /* Constructor for segment with generic arguments (from segment name and all | |
519 | * args) */ | |
520 | 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 | : segment_name (PathIdentSegment (std::move (segment_name), locus)), | |
525 | generic_args (GenericArgs (std::move (lifetime_args), | |
526 | std::move (generic_args), | |
527 | std::move (binding_args))), | |
528 | locus (locus), node_id (Analysis::Mappings::get ().get_next_node_id ()) | |
529 | {} | |
530 | ||
531 | // Returns whether path expression segment is in an error state. | |
532 | bool is_error () const { return segment_name.is_error (); } | |
533 | ||
534 | // Creates an error-state path expression segment. | |
535 | static PathExprSegment create_error () | |
536 | { | |
537 | return PathExprSegment (PathIdentSegment::create_error (), UNDEF_LOCATION); | |
538 | } | |
539 | ||
540 | std::string as_string () const; | |
541 | ||
542 | location_t get_locus () const { return locus; } | |
543 | ||
544 | // TODO: is this better? Or is a "vis_pattern" better? | |
545 | GenericArgs &get_generic_args () | |
546 | { | |
547 | rust_assert (has_generic_args ()); | |
548 | return generic_args; | |
549 | } | |
550 | ||
551 | PathIdentSegment &get_ident_segment () { return segment_name; } | |
552 | const PathIdentSegment &get_ident_segment () const { return segment_name; } | |
553 | ||
554 | NodeId get_node_id () const { return node_id; } | |
555 | ||
556 | bool is_super_path_seg () const | |
557 | { | |
558 | return !has_generic_args () && get_ident_segment ().is_super_path_seg (); | |
559 | } | |
560 | ||
561 | bool is_crate_path_seg () const | |
562 | { | |
563 | return !has_generic_args () && get_ident_segment ().is_crate_path_seg (); | |
564 | } | |
565 | ||
566 | bool is_lower_self_seg () const | |
567 | { | |
568 | 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 | Path (std::vector<PathExprSegment> segments) | |
584 | : segments (std::move (segments)), lang_item (tl::nullopt), | |
585 | kind (Kind::Regular) | |
586 | {} | |
587 | ||
588 | Path (LangItem::Kind lang_item) | |
589 | : segments ({}), lang_item (lang_item), kind (Kind::LangItem) | |
590 | {} | |
591 | ||
592 | // Returns whether path has segments. | |
593 | bool has_segments () const | |
594 | { | |
595 | rust_assert (kind == Kind::Regular); | |
596 | 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 | bool is_single_segment () const | |
606 | { | |
607 | rust_assert (kind == Kind::Regular); | |
608 | return segments.size () == 1; | |
609 | } | |
610 | ||
611 | std::string as_string () const override; | |
612 | ||
613 | bool is_lang_item () const { return kind == Kind::LangItem; } | |
614 | ||
615 | // TODO: this seems kinda dodgy | |
616 | std::vector<PathExprSegment> &get_segments () | |
617 | { | |
618 | rust_assert (kind == Kind::Regular); | |
619 | return segments; | |
620 | } | |
621 | const std::vector<PathExprSegment> &get_segments () const | |
622 | { | |
623 | rust_assert (kind == Kind::Regular); | |
624 | return segments; | |
625 | } | |
626 | ||
627 | LangItem::Kind get_lang_item () const | |
628 | { | |
629 | rust_assert (kind == Kind::LangItem); | |
630 | return *lang_item; | |
631 | } | |
632 | ||
633 | 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 | PathInExpression (std::vector<PathExprSegment> path_segments, | |
659 | std::vector<Attribute> outer_attrs, location_t locus, | |
660 | bool has_opening_scope_resolution = false) | |
661 | : Path (std::move (path_segments)), outer_attrs (std::move (outer_attrs)), | |
662 | has_opening_scope_resolution (has_opening_scope_resolution), | |
663 | locus (locus), _node_id (Analysis::Mappings::get ().get_next_node_id ()), | |
664 | marked_for_strip (false) | |
665 | {} | |
666 | ||
667 | PathInExpression (LangItem::Kind lang_item, | |
668 | std::vector<Attribute> outer_attrs, location_t locus) | |
669 | : Path (lang_item), outer_attrs (std::move (outer_attrs)), | |
670 | has_opening_scope_resolution (false), locus (locus), | |
671 | _node_id (Analysis::Mappings::get ().get_next_node_id ()), | |
672 | marked_for_strip (false) | |
673 | {} | |
674 | ||
675 | // Creates an error state path in expression. | |
676 | static PathInExpression create_error () | |
677 | { | |
678 | return PathInExpression (std::vector<PathExprSegment> (), {}, | |
679 | UNDEF_LOCATION); | |
680 | } | |
681 | ||
682 | // Returns whether path in expression is in an error state. | |
683 | 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 | 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 | return convert_to_simple_path (has_opening_scope_resolution); | |
696 | } | |
697 | ||
698 | location_t get_locus () const override final { return locus; } | |
699 | ||
700 | void accept_vis (ASTVisitor &vis) override; | |
701 | ||
702 | void mark_for_strip () override { marked_for_strip = true; } | |
703 | bool is_marked_for_strip () const override { return marked_for_strip; } | |
704 | ||
705 | bool opening_scope_resolution () const | |
706 | { | |
707 | return has_opening_scope_resolution; | |
708 | } | |
709 | ||
710 | NodeId get_node_id () const override { return _node_id; } | |
711 | ||
712 | const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; } | |
713 | std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; } | |
714 | ||
715 | void set_outer_attrs (std::vector<Attribute> new_attrs) override | |
716 | { | |
717 | outer_attrs = std::move (new_attrs); | |
718 | } | |
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 | Expr::Kind get_expr_kind () const override | |
727 | { | |
728 | return Expr::Kind::PathInExpression; | |
729 | } | |
730 | ||
731 | protected: | |
732 | /* Use covariance to implement clone function as returning this object | |
733 | * rather than base */ | |
734 | PathInExpression *clone_pattern_impl () const final override | |
735 | { | |
736 | return clone_path_in_expression_impl (); | |
737 | } | |
738 | ||
739 | /* Use covariance to implement clone function as returning this object | |
740 | * rather than base */ | |
741 | PathInExpression *clone_expr_without_block_impl () const final override | |
742 | { | |
743 | return clone_path_in_expression_impl (); | |
744 | } | |
745 | ||
746 | /*virtual*/ PathInExpression *clone_path_in_expression_impl () const | |
747 | { | |
748 | 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 | virtual TypePathSegment *clone_type_path_segment_impl () const | |
779 | { | |
780 | return new TypePathSegment (*this); | |
781 | } | |
782 | ||
783 | public: | |
784 | virtual ~TypePathSegment () {} | |
785 | ||
786 | virtual SegmentType get_type () const { return SegmentType::REG; } | |
787 | ||
788 | // Unique pointer custom clone function | |
789 | std::unique_ptr<TypePathSegment> clone_type_path_segment () const | |
790 | { | |
791 | return std::unique_ptr<TypePathSegment> (clone_type_path_segment_impl ()); | |
792 | } | |
793 | ||
794 | TypePathSegment (PathIdentSegment ident_segment, | |
795 | bool has_separating_scope_resolution, location_t locus) | |
796 | : lang_item (tl::nullopt), ident_segment (std::move (ident_segment)), | |
797 | locus (locus), | |
798 | has_separating_scope_resolution (has_separating_scope_resolution), | |
799 | node_id (Analysis::Mappings::get ().get_next_node_id ()) | |
800 | {} | |
801 | ||
802 | TypePathSegment (LangItem::Kind lang_item, location_t locus) | |
803 | : lang_item (lang_item), ident_segment (tl::nullopt), locus (locus), | |
804 | has_separating_scope_resolution (false), | |
805 | node_id (Analysis::Mappings::get ().get_next_node_id ()) | |
806 | {} | |
807 | ||
808 | TypePathSegment (std::string segment_name, | |
809 | bool has_separating_scope_resolution, location_t locus) | |
810 | : lang_item (tl::nullopt), | |
811 | ident_segment (PathIdentSegment (std::move (segment_name), locus)), | |
812 | locus (locus), | |
813 | has_separating_scope_resolution (has_separating_scope_resolution), | |
814 | node_id (Analysis::Mappings::get ().get_next_node_id ()) | |
815 | {} | |
816 | ||
817 | TypePathSegment (TypePathSegment const &other) | |
818 | : lang_item (other.lang_item), ident_segment (other.ident_segment), | |
819 | locus (other.locus), | |
820 | has_separating_scope_resolution (other.has_separating_scope_resolution), | |
821 | node_id (other.node_id) | |
822 | {} | |
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 | virtual std::string as_string () const | |
839 | { | |
840 | if (lang_item.has_value ()) | |
841 | return LangItem::PrettyString (*lang_item); | |
842 | ||
843 | 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 | bool is_error () const | |
849 | { | |
850 | rust_assert (ident_segment); | |
851 | 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 | virtual bool is_ident_only () const { return true; } | |
857 | ||
858 | bool is_lang_item () const { return lang_item.has_value (); } | |
859 | ||
860 | 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 | bool get_separating_scope_resolution () const | |
866 | { | |
867 | return has_separating_scope_resolution; | |
868 | } | |
869 | ||
870 | PathIdentSegment &get_ident_segment () | |
871 | { | |
872 | rust_assert (!is_lang_item ()); | |
873 | return *ident_segment; | |
874 | }; | |
875 | ||
876 | const PathIdentSegment &get_ident_segment () const | |
877 | { | |
878 | rust_assert (!is_lang_item ()); | |
879 | return *ident_segment; | |
880 | }; | |
881 | ||
882 | LangItem::Kind get_lang_item () const | |
883 | { | |
884 | rust_assert (is_lang_item ()); | |
885 | return *lang_item; | |
886 | } | |
887 | ||
888 | NodeId get_node_id () const { return node_id; } | |
889 | ||
890 | bool is_crate_path_seg () const | |
891 | { | |
892 | return get_ident_segment ().is_crate_path_seg (); | |
893 | } | |
894 | bool is_super_path_seg () const | |
895 | { | |
896 | 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 | bool is_lower_self_seg () const | |
903 | { | |
904 | 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 | SegmentType get_type () const override { return SegmentType::GENERIC; } | |
915 | ||
916 | bool has_generic_args () const { return generic_args.has_generic_args (); } | |
917 | ||
918 | bool is_ident_only () const override { return false; } | |
919 | ||
920 | // Constructor with PathIdentSegment and GenericArgs | |
921 | TypePathSegmentGeneric (PathIdentSegment ident_segment, | |
922 | bool has_separating_scope_resolution, | |
923 | GenericArgs generic_args, location_t locus) | |
924 | : TypePathSegment (std::move (ident_segment), | |
925 | has_separating_scope_resolution, locus), | |
926 | generic_args (std::move (generic_args)) | |
927 | {} | |
928 | ||
929 | TypePathSegmentGeneric (LangItem::Kind lang_item, GenericArgs generic_args, | |
930 | location_t locus) | |
931 | : TypePathSegment (lang_item, locus), | |
932 | generic_args (std::move (generic_args)) | |
933 | {} | |
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 | TypePathSegmentGeneric (TypePathSegmentGeneric const &other) | |
951 | : TypePathSegment (other), generic_args (other.generic_args) | |
952 | {} | |
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 | GenericArgs &get_generic_args () | |
972 | { | |
973 | rust_assert (has_generic_args ()); | |
974 | return generic_args; | |
975 | } | |
976 | ||
977 | // Use covariance to override base class method | |
978 | TypePathSegmentGeneric *clone_type_path_segment_impl () const override | |
979 | { | |
980 | 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 | TypePathFunction (bool is_invalid, location_t locus) | |
1005 | : is_invalid (is_invalid), locus (locus) | |
1006 | {} | |
1007 | ||
1008 | public: | |
1009 | // Returns whether the return type of the function has been specified. | |
1010 | bool has_return_type () const { return return_type != nullptr; } | |
1011 | ||
1012 | // Returns whether the function has inputs. | |
1013 | bool has_inputs () const { return !inputs.empty (); } | |
1014 | ||
1015 | // Returns whether function is in an error state. | |
1016 | bool is_error () const { return is_invalid; } | |
1017 | ||
1018 | // Creates an error state function. | |
1019 | static TypePathFunction create_error () | |
1020 | { | |
1021 | return TypePathFunction (true, UNDEF_LOCATION); | |
1022 | } | |
1023 | ||
1024 | // Constructor | |
1025 | TypePathFunction (std::vector<std::unique_ptr<Type>> inputs, location_t locus, | |
1026 | std::unique_ptr<Type> type = nullptr) | |
1027 | : inputs (std::move (inputs)), return_type (std::move (type)), | |
1028 | is_invalid (false), locus (locus) | |
1029 | {} | |
1030 | ||
1031 | // Copy constructor with clone | |
1032 | TypePathFunction (TypePathFunction const &other) | |
1033 | : is_invalid (other.is_invalid) | |
1034 | { | |
1035 | // guard to protect from null pointer dereference | |
1036 | if (other.return_type != nullptr) | |
1037 | return_type = other.return_type->clone_type (); | |
1038 | ||
1039 | inputs.reserve (other.inputs.size ()); | |
1040 | for (const auto &e : other.inputs) | |
1041 | inputs.push_back (e->clone_type ()); | |
1042 | } | |
1043 | ||
1044 | ~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 | 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 | std::vector<std::unique_ptr<Type>> &get_params () { return inputs; } | |
1076 | ||
1077 | // TODO: is this better? Or is a "vis_pattern" better? | |
1078 | Type &get_return_type () | |
1079 | { | |
1080 | rust_assert (has_return_type ()); | |
1081 | return *return_type; | |
1082 | } | |
1083 | ||
1084 | std::unique_ptr<Type> &get_return_type_ptr () | |
1085 | { | |
1086 | rust_assert (has_return_type ()); | |
1087 | return return_type; | |
1088 | } | |
1089 | ||
1090 | 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 | SegmentType get_type () const override { return SegmentType::FUNCTION; } | |
1100 | ||
1101 | // Constructor with PathIdentSegment and TypePathFn | |
1102 | TypePathSegmentFunction (PathIdentSegment ident_segment, | |
1103 | bool has_separating_scope_resolution, | |
1104 | TypePathFunction function_path, location_t locus) | |
1105 | : TypePathSegment (std::move (ident_segment), | |
1106 | has_separating_scope_resolution, locus), | |
1107 | function_path (std::move (function_path)) | |
1108 | {} | |
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 | 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 | TypePathFunction &get_type_path_function () | |
1127 | { | |
1128 | rust_assert (!function_path.is_error ()); | |
1129 | return function_path; | |
1130 | } | |
1131 | ||
1132 | // Use covariance to override base class method | |
1133 | TypePathSegmentFunction *clone_type_path_segment_impl () const override | |
1134 | { | |
1135 | return new TypePathSegmentFunction (*this); | |
1136 | } | |
1137 | }; | |
1138 | ||
1139 | 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 | TypePath *clone_type_no_bounds_impl () const override | |
1149 | { | |
1150 | 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 | bool has_opening_scope_resolution_op () const | |
1157 | { | |
1158 | return has_opening_scope_resolution; | |
1159 | } | |
1160 | ||
1161 | // Returns whether the TypePath is in an invalid state. | |
1162 | bool is_error () const { return segments.empty (); } | |
1163 | ||
1164 | // Creates an error state TypePath. | |
1165 | static TypePath create_error () | |
1166 | { | |
1167 | return TypePath (std::vector<std::unique_ptr<TypePathSegment>> (), | |
1168 | UNDEF_LOCATION); | |
1169 | } | |
1170 | ||
1171 | // Constructor | |
1172 | TypePath (std::vector<std::unique_ptr<TypePathSegment>> segments, | |
1173 | location_t locus, bool has_opening_scope_resolution = false) | |
1174 | : TypeNoBounds (), | |
1175 | has_opening_scope_resolution (has_opening_scope_resolution), | |
1176 | segments (std::move (segments)), locus (locus) | |
1177 | {} | |
1178 | ||
1179 | TypePath (LangItem::Kind lang_item, | |
1180 | std::vector<std::unique_ptr<TypePathSegment>> segments, | |
1181 | location_t locus, bool has_opening_scope_resolution = false) | |
1182 | : TypeNoBounds (), | |
1183 | has_opening_scope_resolution (has_opening_scope_resolution), | |
1184 | segments (std::move (segments)), locus (locus) | |
1185 | {} | |
1186 | ||
1187 | // Copy constructor with vector clone | |
1188 | TypePath (TypePath const &other) | |
1189 | : has_opening_scope_resolution (other.has_opening_scope_resolution), | |
1190 | locus (other.locus) | |
1191 | { | |
1192 | node_id = other.node_id; | |
1193 | segments.reserve (other.segments.size ()); | |
1194 | for (const auto &e : other.segments) | |
1195 | segments.push_back (e->clone_type_path_segment ()); | |
1196 | } | |
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 | TypePath (TypePath &&other) = default; | |
1214 | 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 | location_t get_locus () const override final { return locus; } | |
1226 | NodeId get_node_id () const { return node_id; } | |
1227 | ||
1228 | void mark_for_strip () override {} | |
1229 | 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 | std::vector<std::unique_ptr<TypePathSegment>> &get_segments () | |
1235 | { | |
1236 | return segments; | |
1237 | } | |
1238 | const std::vector<std::unique_ptr<TypePathSegment>> &get_segments () const | |
1239 | { | |
1240 | 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 | QualifiedPathType (std::unique_ptr<Type> invoke_on_type, | |
1257 | location_t locus = UNDEF_LOCATION, | |
1258 | TypePath trait_path = TypePath::create_error ()) | |
1259 | : type_to_invoke_on (std::move (invoke_on_type)), trait_path (trait_path), | |
1260 | locus (locus), node_id (Analysis::Mappings::get ().get_next_node_id ()) | |
1261 | {} | |
1262 | ||
1263 | // Copy constructor uses custom deep copy for Type to preserve polymorphism | |
1264 | QualifiedPathType (QualifiedPathType const &other) | |
1265 | : trait_path (other.trait_path), locus (other.locus) | |
1266 | { | |
1267 | node_id = other.node_id; | |
1268 | // guard to prevent null dereference | |
1269 | if (other.type_to_invoke_on != nullptr) | |
1270 | type_to_invoke_on = other.type_to_invoke_on->clone_type (); | |
1271 | } | |
1272 | ||
1273 | // default destructor | |
1274 | ~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 | QualifiedPathType (QualifiedPathType &&other) = default; | |
1294 | QualifiedPathType &operator= (QualifiedPathType &&other) = default; | |
1295 | ||
1296 | // Returns whether the qualified path type has a rebind as clause. | |
1297 | bool has_as_clause () const { return !trait_path.is_error (); } | |
1298 | ||
1299 | // Returns whether the qualified path type is in an error state. | |
1300 | bool is_error () const { return type_to_invoke_on == nullptr; } | |
1301 | ||
1302 | // Creates an error state qualified path type. | |
1303 | static QualifiedPathType create_error () | |
1304 | { | |
1305 | return QualifiedPathType (nullptr); | |
1306 | } | |
1307 | ||
1308 | std::string as_string () const; | |
1309 | ||
1310 | location_t get_locus () const { return locus; } | |
1311 | ||
1312 | // TODO: is this better? Or is a "vis_pattern" better? | |
1313 | Type &get_type () | |
1314 | { | |
1315 | rust_assert (type_to_invoke_on != nullptr); | |
1316 | return *type_to_invoke_on; | |
1317 | } | |
1318 | ||
1319 | std::unique_ptr<Type> &get_type_ptr () | |
1320 | { | |
1321 | rust_assert (type_to_invoke_on != nullptr); | |
1322 | return type_to_invoke_on; | |
1323 | } | |
1324 | ||
1325 | // TODO: is this better? Or is a "vis_pattern" better? | |
1326 | TypePath &get_as_type_path () | |
1327 | { | |
1328 | rust_assert (has_as_clause ()); | |
1329 | return trait_path; | |
1330 | } | |
1331 | ||
1332 | 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 | QualifiedPathInExpression (QualifiedPathType qual_path_type, | |
1348 | std::vector<PathExprSegment> path_segments, | |
1349 | std::vector<Attribute> outer_attrs, | |
1350 | location_t locus) | |
1351 | : Path (std::move (path_segments)), outer_attrs (std::move (outer_attrs)), | |
1352 | path_type (std::move (qual_path_type)), locus (locus), | |
1353 | _node_id (Analysis::Mappings::get ().get_next_node_id ()) | |
1354 | {} | |
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 | bool is_error () const { return path_type.is_error (); } | |
1361 | ||
1362 | // Creates an error qualified path in expression. | |
1363 | static QualifiedPathInExpression create_error () | |
1364 | { | |
1365 | return QualifiedPathInExpression (QualifiedPathType::create_error (), {}, | |
1366 | {}, UNDEF_LOCATION); | |
1367 | } | |
1368 | ||
1369 | 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 | void mark_for_strip () override | |
1375 | { | |
1376 | path_type = QualifiedPathType::create_error (); | |
1377 | } | |
1378 | bool is_marked_for_strip () const override { return is_error (); } | |
1379 | ||
1380 | // TODO: is this better? Or is a "vis_pattern" better? | |
1381 | QualifiedPathType &get_qualified_path_type () | |
1382 | { | |
1383 | rust_assert (!path_type.is_error ()); | |
1384 | return path_type; | |
1385 | } | |
1386 | ||
1387 | const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; } | |
1388 | std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; } | |
1389 | ||
1390 | void set_outer_attrs (std::vector<Attribute> new_attrs) override | |
1391 | { | |
1392 | outer_attrs = std::move (new_attrs); | |
1393 | } | |
1394 | ||
1395 | NodeId get_node_id () const override { return _node_id; } | |
1396 | ||
1397 | Expr::Kind get_expr_kind () const override | |
1398 | { | |
1399 | return Expr::Kind::QualifiedPathInExpression; | |
1400 | } | |
1401 | ||
1402 | protected: | |
1403 | /* Use covariance to implement clone function as returning this object | |
1404 | * rather than base */ | |
1405 | QualifiedPathInExpression *clone_pattern_impl () const final override | |
1406 | { | |
1407 | 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 | clone_expr_without_block_impl () const final override | |
1414 | { | |
1415 | return clone_qual_path_in_expression_impl (); | |
1416 | } | |
1417 | ||
1418 | /*virtual*/ QualifiedPathInExpression * | |
1419 | clone_qual_path_in_expression_impl () const | |
1420 | { | |
1421 | 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 | QualifiedPathInType *clone_type_no_bounds_impl () const override | |
1438 | { | |
1439 | return new QualifiedPathInType (*this); | |
1440 | } | |
1441 | ||
1442 | public: | |
1443 | 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 | : path_type (std::move (qual_path_type)), | |
1449 | associated_segment (std::move (associated_segment)), | |
1450 | segments (std::move (path_segments)), locus (locus) | |
1451 | {} | |
1452 | ||
1453 | // Copy constructor with vector clone | |
1454 | QualifiedPathInType (QualifiedPathInType const &other) | |
1455 | : path_type (other.path_type), locus (other.locus) | |
1456 | { | |
1457 | auto seg = other.associated_segment->clone_type_path_segment_impl (); | |
1458 | associated_segment = std::unique_ptr<TypePathSegment> (seg); | |
1459 | ||
1460 | segments.reserve (other.segments.size ()); | |
1461 | for (const auto &e : other.segments) | |
1462 | segments.push_back (e->clone_type_path_segment ()); | |
1463 | } | |
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 | QualifiedPathInType (QualifiedPathInType &&other) = default; | |
1483 | QualifiedPathInType &operator= (QualifiedPathInType &&other) = default; | |
1484 | ||
1485 | // Returns whether qualified path in type is in an error state. | |
1486 | bool is_error () const { return path_type.is_error (); } | |
1487 | ||
1488 | // Creates an error state qualified path in type. | |
1489 | static QualifiedPathInType create_error () | |
1490 | { | |
1491 | return QualifiedPathInType ( | |
1492 | QualifiedPathType::create_error (), nullptr, | |
1493 | 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 | QualifiedPathType &get_qualified_path_type () | |
1502 | { | |
1503 | rust_assert (!path_type.is_error ()); | |
1504 | return path_type; | |
1505 | } | |
1506 | ||
1507 | std::unique_ptr<TypePathSegment> &get_associated_segment () | |
1508 | { | |
1509 | return associated_segment; | |
1510 | } | |
1511 | ||
1512 | // TODO: this seems kinda dodgy | |
1513 | std::vector<std::unique_ptr<TypePathSegment>> &get_segments () | |
1514 | { | |
1515 | return segments; | |
1516 | } | |
1517 | const std::vector<std::unique_ptr<TypePathSegment>> &get_segments () const | |
1518 | { | |
1519 | return segments; | |
1520 | } | |
1521 | ||
1522 | location_t get_locus () const override final { return locus; } | |
1523 | }; | |
1524 | } // namespace AST | |
1525 | } // namespace Rust | |
1526 | ||
1527 | #endif |