]>
Commit | Line | Data |
---|---|---|
6441eb6d | 1 | // Copyright (C) 2020-2025 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 | ||
63023c03 | 24 | #include "optional.h" |
d588754c | 25 | #include "rust-ast.h" |
96cd17a7 AC |
26 | #include "rust-hir-map.h" |
27 | #include "rust-mapping-common.h" | |
28 | #include "rust-system.h" | |
d588754c JP |
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; | |
d991a3f1 | 38 | location_t locus; |
d588754c JP |
39 | |
40 | // only allow identifiers, "super", "self", "Self", "crate", or "$crate" | |
41 | public: | |
d991a3f1 | 42 | PathIdentSegment (std::string segment_name, location_t locus) |
d588754c JP |
43 | : segment_name (std::move (segment_name)), locus (locus) |
44 | {} | |
45 | ||
46 | // Creates an error PathIdentSegment. | |
47 | static PathIdentSegment create_error () | |
48 | { | |
1678cdd3 | 49 | return PathIdentSegment ("", UNDEF_LOCATION); |
d588754c JP |
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 | ||
df1da364 | 57 | location_t get_locus () const { return locus; } |
d588754c | 58 | |
3fe905eb OA |
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; } | |
d588754c JP |
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; | |
d991a3f1 | 77 | location_t locus; |
d588754c JP |
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 | { | |
fcb228d1 | 90 | return GenericArgsBinding ({""}, nullptr); |
d588754c JP |
91 | } |
92 | ||
93 | // Pointer type for type in constructor to enable polymorphism | |
94 | GenericArgsBinding (Identifier ident, std::unique_ptr<Type> type_ptr, | |
d991a3f1 | 95 | location_t locus = UNDEF_LOCATION) |
d588754c JP |
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? | |
e01c9f40 PEP |
133 | Type &get_type () |
134 | { | |
135 | rust_assert (type != nullptr); | |
136 | return *type; | |
137 | } | |
138 | ||
139 | std::unique_ptr<Type> &get_type_ptr () | |
d588754c JP |
140 | { |
141 | rust_assert (type != nullptr); | |
142 | return type; | |
143 | } | |
144 | ||
df1da364 | 145 | location_t get_locus () const { return locus; } |
d588754c JP |
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 | { | |
d588754c JP |
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 | ||
d588754c JP |
175 | static GenericArg create_const (std::unique_ptr<Expr> expression) |
176 | { | |
177 | auto locus = expression->get_locus (); | |
fcb228d1 PEP |
178 | return GenericArg (std::move (expression), nullptr, {""}, Kind::Const, |
179 | locus); | |
d588754c JP |
180 | } |
181 | ||
182 | static GenericArg create_type (std::unique_ptr<Type> type) | |
183 | { | |
184 | auto locus = type->get_locus (); | |
fcb228d1 | 185 | return GenericArg (nullptr, std::move (type), {""}, Kind::Type, locus); |
d588754c JP |
186 | } |
187 | ||
d991a3f1 | 188 | static GenericArg create_ambiguous (Identifier path, location_t locus) |
d588754c JP |
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 | ||
fca49c4d PH |
216 | GenericArg (GenericArg &&other) = default; |
217 | GenericArg &operator= (GenericArg &&other) = default; | |
218 | ||
d588754c | 219 | Kind get_kind () const { return kind; } |
e99e565e | 220 | location_t get_locus () const { return locus; } |
d588754c | 221 | |
2f1035fc AC |
222 | void accept_vis (AST::ASTVisitor &visitor) |
223 | { | |
224 | switch (get_kind ()) | |
225 | { | |
226 | case Kind::Const: | |
e01c9f40 | 227 | get_expression ().accept_vis (visitor); |
2f1035fc AC |
228 | break; |
229 | case Kind::Type: | |
e01c9f40 | 230 | get_type ().accept_vis (visitor); |
2f1035fc AC |
231 | break; |
232 | case Kind::Either: | |
233 | break; | |
2f1035fc AC |
234 | } |
235 | } | |
236 | ||
e01c9f40 PEP |
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 () | |
d588754c JP |
245 | { |
246 | rust_assert (kind == Kind::Const); | |
247 | ||
248 | return expression; | |
249 | } | |
250 | ||
e01c9f40 PEP |
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 () | |
d588754c JP |
259 | { |
260 | rust_assert (kind == Kind::Type); | |
261 | ||
262 | return type; | |
263 | } | |
264 | ||
ed866110 | 265 | const std::string get_path () const |
d588754c JP |
266 | { |
267 | rust_assert (kind == Kind::Either); | |
268 | ||
fcb228d1 | 269 | return path.as_string (); |
d588754c JP |
270 | } |
271 | ||
272 | std::string as_string () const | |
273 | { | |
274 | switch (get_kind ()) | |
275 | { | |
d588754c | 276 | case Kind::Either: |
fcb228d1 | 277 | return "Ambiguous: " + path.as_string (); |
d588754c JP |
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, | |
d991a3f1 | 301 | Identifier path, Kind kind, location_t locus) |
d588754c JP |
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 | ||
d991a3f1 | 329 | location_t locus; |
d588754c JP |
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 | */ | |
e905c04b | 346 | tl::optional<GenericArg> default_value; |
d588754c | 347 | |
6fef5bc4 | 348 | AST::AttrVec outer_attrs; |
d991a3f1 | 349 | location_t locus; |
d588754c JP |
350 | |
351 | public: | |
352 | ConstGenericParam (Identifier name, std::unique_ptr<AST::Type> type, | |
e905c04b PEP |
353 | tl::optional<GenericArg> default_value, |
354 | AST::AttrVec outer_attrs, location_t locus) | |
d588754c | 355 | : name (name), type (std::move (type)), |
6fef5bc4 | 356 | default_value (std::move (default_value)), outer_attrs (outer_attrs), |
d588754c JP |
357 | locus (locus) |
358 | {} | |
359 | ||
360 | ConstGenericParam (const ConstGenericParam &other) | |
361 | : GenericParam (), name (other.name), type (other.type->clone_type ()), | |
6fef5bc4 | 362 | default_value (other.default_value), outer_attrs (other.outer_attrs), |
d588754c JP |
363 | locus (other.locus) |
364 | {} | |
365 | ||
366 | bool has_type () const { return type != nullptr; } | |
e905c04b | 367 | bool has_default_value () const { return default_value.has_value (); } |
d588754c JP |
368 | |
369 | const Identifier &get_name () const { return name; } | |
370 | ||
6fef5bc4 | 371 | AST::AttrVec &get_outer_attrs () { return outer_attrs; } |
7065e2db | 372 | |
e01c9f40 | 373 | AST::Type &get_type () |
d588754c JP |
374 | { |
375 | rust_assert (has_type ()); | |
376 | ||
e01c9f40 | 377 | return *type; |
d588754c JP |
378 | } |
379 | ||
e905c04b | 380 | GenericArg &get_default_value_unchecked () |
d588754c JP |
381 | { |
382 | rust_assert (has_default_value ()); | |
383 | ||
e905c04b | 384 | return default_value.value (); |
d588754c JP |
385 | } |
386 | ||
e905c04b | 387 | const GenericArg &get_default_value_unchecked () const |
d588754c JP |
388 | { |
389 | rust_assert (has_default_value ()); | |
390 | ||
e905c04b | 391 | return default_value.value (); |
d588754c JP |
392 | } |
393 | ||
394 | std::string as_string () const override; | |
395 | ||
396 | void accept_vis (ASTVisitor &vis) override; | |
397 | ||
df1da364 | 398 | location_t get_locus () const override final { return locus; } |
d588754c JP |
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; | |
d991a3f1 | 417 | location_t locus; |
d588754c JP |
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, | |
d991a3f1 | 430 | location_t locus = UNDEF_LOCATION) |
d588754c JP |
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) | |
fca49c4d PH |
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 | } | |
d588754c JP |
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; | |
d588754c JP |
455 | binding_args = other.binding_args; |
456 | locus = other.locus; | |
457 | ||
fca49c4d PH |
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 | ||
d588754c JP |
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 | ||
d588754c JP |
477 | std::vector<GenericArg> &get_generic_args () { return generic_args; } |
478 | ||
d588754c JP |
479 | std::vector<GenericArgsBinding> &get_binding_args () { return binding_args; } |
480 | ||
9b4f8f2d PH |
481 | const std::vector<GenericArgsBinding> &get_binding_args () const |
482 | { | |
483 | return binding_args; | |
484 | } | |
485 | ||
d588754c JP |
486 | std::vector<Lifetime> &get_lifetime_args () { return lifetime_args; }; |
487 | ||
9b4f8f2d PH |
488 | const std::vector<Lifetime> &get_lifetime_args () const |
489 | { | |
490 | return lifetime_args; | |
491 | }; | |
492 | ||
493 | location_t get_locus () const { return locus; } | |
d588754c JP |
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; | |
d991a3f1 | 503 | location_t locus; |
d588754c JP |
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) | |
d991a3f1 | 511 | PathExprSegment (PathIdentSegment segment_name, location_t locus, |
d588754c JP |
512 | GenericArgs generic_args = GenericArgs::create_empty ()) |
513 | : segment_name (std::move (segment_name)), | |
514 | generic_args (std::move (generic_args)), locus (locus), | |
fd788dd5 | 515 | node_id (Analysis::Mappings::get ().get_next_node_id ()) |
d588754c JP |
516 | {} |
517 | ||
518 | /* Constructor for segment with generic arguments (from segment name and all | |
519 | * args) */ | |
d991a3f1 | 520 | PathExprSegment (std::string segment_name, location_t locus, |
d588754c JP |
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))), | |
fd788dd5 | 528 | locus (locus), node_id (Analysis::Mappings::get ().get_next_node_id ()) |
d588754c JP |
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 | { | |
1678cdd3 | 537 | return PathExprSegment (PathIdentSegment::create_error (), UNDEF_LOCATION); |
d588754c JP |
538 | } |
539 | ||
540 | std::string as_string () const; | |
541 | ||
df1da364 | 542 | location_t get_locus () const { return locus; } |
d588754c JP |
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 | { | |
3fe905eb | 558 | return !has_generic_args () && get_ident_segment ().is_super_path_seg (); |
d588754c JP |
559 | } |
560 | ||
561 | bool is_crate_path_seg () const | |
562 | { | |
3fe905eb | 563 | return !has_generic_args () && get_ident_segment ().is_crate_path_seg (); |
d588754c | 564 | } |
c5925f34 | 565 | |
d588754c JP |
566 | bool is_lower_self_seg () const |
567 | { | |
3fe905eb | 568 | return !has_generic_args () && get_ident_segment ().is_lower_self_seg (); |
d588754c JP |
569 | } |
570 | }; | |
571 | ||
572 | // AST node representing a pattern that involves a "path" - abstract base | |
573 | // class | |
96cd17a7 | 574 | class Path : public Pattern |
d588754c | 575 | { |
96cd17a7 AC |
576 | public: |
577 | enum class Kind | |
578 | { | |
579 | LangItem, | |
580 | Regular, | |
581 | }; | |
582 | ||
63023c03 AC |
583 | Path (std::vector<PathExprSegment> segments) |
584 | : segments (std::move (segments)), lang_item (tl::nullopt), | |
585 | kind (Kind::Regular) | |
d588754c JP |
586 | {} |
587 | ||
63023c03 AC |
588 | Path (LangItem::Kind lang_item) |
589 | : segments ({}), lang_item (lang_item), kind (Kind::LangItem) | |
590 | {} | |
96cd17a7 | 591 | |
d588754c | 592 | // Returns whether path has segments. |
63023c03 AC |
593 | bool has_segments () const |
594 | { | |
595 | rust_assert (kind == Kind::Regular); | |
596 | return !segments.empty (); | |
597 | } | |
d588754c | 598 | |
96cd17a7 AC |
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; | |
d588754c | 602 | |
63023c03 AC |
603 | /* Returns whether the path is a single segment (excluding qualified path |
604 | * initial as segment). */ | |
605 | bool is_single_segment () const | |
96cd17a7 | 606 | { |
63023c03 AC |
607 | rust_assert (kind == Kind::Regular); |
608 | return segments.size () == 1; | |
96cd17a7 | 609 | } |
eacbbac9 | 610 | |
63023c03 | 611 | std::string as_string () const override; |
96cd17a7 | 612 | |
1b745da3 AC |
613 | bool is_lang_item () const { return kind == Kind::LangItem; } |
614 | ||
63023c03 AC |
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 | } | |
96cd17a7 | 626 | |
63023c03 | 627 | LangItem::Kind get_lang_item () const |
96cd17a7 | 628 | { |
63023c03 AC |
629 | rust_assert (kind == Kind::LangItem); |
630 | return *lang_item; | |
96cd17a7 AC |
631 | } |
632 | ||
63023c03 AC |
633 | Pattern::Kind get_pattern_kind () override { return Pattern::Kind::Path; } |
634 | Path::Kind get_path_kind () { return kind; } | |
c482c358 | 635 | |
63023c03 AC |
636 | protected: |
637 | std::vector<PathExprSegment> segments; | |
638 | tl::optional<LangItem::Kind> lang_item; | |
eacbbac9 | 639 | |
63023c03 | 640 | Path::Kind kind; |
d588754c JP |
641 | }; |
642 | ||
643 | /* AST node representing a path-in-expression pattern (path that allows | |
644 | * generic arguments) */ | |
63023c03 | 645 | class PathInExpression : public Path, public ExprWithoutBlock |
d588754c JP |
646 | { |
647 | std::vector<Attribute> outer_attrs; | |
648 | bool has_opening_scope_resolution; | |
d991a3f1 | 649 | location_t locus; |
d588754c | 650 | NodeId _node_id; |
63023c03 | 651 | |
b4e8bc15 AC |
652 | bool marked_for_strip; |
653 | ||
d588754c JP |
654 | public: |
655 | std::string as_string () const override; | |
656 | ||
657 | // Constructor | |
658 | PathInExpression (std::vector<PathExprSegment> path_segments, | |
d991a3f1 | 659 | std::vector<Attribute> outer_attrs, location_t locus, |
d588754c | 660 | bool has_opening_scope_resolution = false) |
63023c03 | 661 | : Path (std::move (path_segments)), outer_attrs (std::move (outer_attrs)), |
d588754c | 662 | has_opening_scope_resolution (has_opening_scope_resolution), |
b4e8bc15 AC |
663 | locus (locus), _node_id (Analysis::Mappings::get ().get_next_node_id ()), |
664 | marked_for_strip (false) | |
d588754c JP |
665 | {} |
666 | ||
63023c03 | 667 | PathInExpression (LangItem::Kind lang_item, |
b76ee925 | 668 | std::vector<Attribute> outer_attrs, location_t locus) |
63023c03 | 669 | : Path (lang_item), outer_attrs (std::move (outer_attrs)), |
b76ee925 AC |
670 | has_opening_scope_resolution (false), locus (locus), |
671 | _node_id (Analysis::Mappings::get ().get_next_node_id ()), | |
b76ee925 AC |
672 | marked_for_strip (false) |
673 | {} | |
674 | ||
d588754c JP |
675 | // Creates an error state path in expression. |
676 | static PathInExpression create_error () | |
677 | { | |
b76ee925 AC |
678 | return PathInExpression (std::vector<PathExprSegment> (), {}, |
679 | UNDEF_LOCATION); | |
d588754c JP |
680 | } |
681 | ||
682 | // Returns whether path in expression is in an error state. | |
63023c03 | 683 | bool is_error () const { return !has_segments (); } |
d588754c JP |
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 | { | |
63023c03 AC |
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); | |
d588754c JP |
696 | } |
697 | ||
df1da364 | 698 | location_t get_locus () const override final { return locus; } |
d588754c JP |
699 | |
700 | void accept_vis (ASTVisitor &vis) override; | |
701 | ||
b4e8bc15 AC |
702 | void mark_for_strip () override { marked_for_strip = true; } |
703 | bool is_marked_for_strip () const override { return marked_for_strip; } | |
d588754c JP |
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; } | |
36bca0cc | 713 | std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; } |
d588754c JP |
714 | |
715 | void set_outer_attrs (std::vector<Attribute> new_attrs) override | |
716 | { | |
717 | outer_attrs = std::move (new_attrs); | |
718 | } | |
719 | ||
63023c03 | 720 | PathExprSegment &get_final_segment () { return get_segments ().back (); } |
c5925f34 AC |
721 | const PathExprSegment &get_final_segment () const |
722 | { | |
63023c03 | 723 | return get_segments ().back (); |
c5925f34 AC |
724 | } |
725 | ||
9c50565e AC |
726 | Expr::Kind get_expr_kind () const override |
727 | { | |
728 | return Expr::Kind::PathInExpression; | |
729 | } | |
730 | ||
d588754c JP |
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: | |
63023c03 AC |
765 | tl::optional<LangItem::Kind> lang_item; |
766 | tl::optional<PathIdentSegment> ident_segment; | |
d991a3f1 | 767 | location_t locus; |
d588754c JP |
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 | ||
fca49c4d | 775 | public: |
d588754c JP |
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, | |
d991a3f1 | 795 | bool has_separating_scope_resolution, location_t locus) |
63023c03 AC |
796 | : lang_item (tl::nullopt), ident_segment (std::move (ident_segment)), |
797 | locus (locus), | |
d588754c | 798 | has_separating_scope_resolution (has_separating_scope_resolution), |
fd788dd5 | 799 | node_id (Analysis::Mappings::get ().get_next_node_id ()) |
d588754c JP |
800 | {} |
801 | ||
63023c03 AC |
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 | ||
d588754c | 808 | TypePathSegment (std::string segment_name, |
d991a3f1 | 809 | bool has_separating_scope_resolution, location_t locus) |
63023c03 AC |
810 | : lang_item (tl::nullopt), |
811 | ident_segment (PathIdentSegment (std::move (segment_name), locus)), | |
d588754c JP |
812 | locus (locus), |
813 | has_separating_scope_resolution (has_separating_scope_resolution), | |
fd788dd5 | 814 | node_id (Analysis::Mappings::get ().get_next_node_id ()) |
d588754c JP |
815 | {} |
816 | ||
fca49c4d | 817 | TypePathSegment (TypePathSegment const &other) |
63023c03 AC |
818 | : lang_item (other.lang_item), ident_segment (other.ident_segment), |
819 | locus (other.locus), | |
fca49c4d PH |
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; | |
63023c03 | 827 | lang_item = other.lang_item; |
fca49c4d PH |
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 | ||
63023c03 AC |
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 | } | |
d588754c JP |
845 | |
846 | /* Returns whether the type path segment is in an error state. May be | |
847 | * virtual in future. */ | |
63023c03 AC |
848 | bool is_error () const |
849 | { | |
850 | rust_assert (ident_segment); | |
851 | return ident_segment->is_error (); | |
852 | } | |
d588754c JP |
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 | ||
63023c03 AC |
858 | bool is_lang_item () const { return lang_item.has_value (); } |
859 | ||
df1da364 | 860 | location_t get_locus () const { return locus; } |
d588754c JP |
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 | ||
63023c03 AC |
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 | } | |
d588754c JP |
887 | |
888 | NodeId get_node_id () const { return node_id; } | |
889 | ||
890 | bool is_crate_path_seg () const | |
891 | { | |
3fe905eb | 892 | return get_ident_segment ().is_crate_path_seg (); |
d588754c JP |
893 | } |
894 | bool is_super_path_seg () const | |
895 | { | |
3fe905eb OA |
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 (); | |
d588754c | 901 | } |
d588754c JP |
902 | bool is_lower_self_seg () const |
903 | { | |
3fe905eb | 904 | return get_ident_segment ().is_lower_self_seg (); |
d588754c JP |
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, | |
d991a3f1 | 923 | GenericArgs generic_args, location_t locus) |
d588754c JP |
924 | : TypePathSegment (std::move (ident_segment), |
925 | has_separating_scope_resolution, locus), | |
926 | generic_args (std::move (generic_args)) | |
927 | {} | |
928 | ||
63023c03 AC |
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 | ||
d588754c JP |
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, | |
d991a3f1 | 941 | location_t locus) |
d588754c JP |
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 | ||
fca49c4d PH |
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 | ||
d588754c JP |
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 | ||
d588754c JP |
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 | |
63023c03 | 992 | std::vector<std::unique_ptr<Type>> inputs; |
d588754c JP |
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 | ||
d991a3f1 | 1000 | location_t locus; |
d588754c JP |
1001 | |
1002 | protected: | |
1003 | // Constructor only used to create invalid type path functions. | |
d991a3f1 | 1004 | TypePathFunction (bool is_invalid, location_t locus) |
d588754c JP |
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 | { | |
1678cdd3 | 1021 | return TypePathFunction (true, UNDEF_LOCATION); |
d588754c JP |
1022 | } |
1023 | ||
1024 | // Constructor | |
63023c03 AC |
1025 | TypePathFunction (std::vector<std::unique_ptr<Type>> inputs, location_t locus, |
1026 | std::unique_ptr<Type> type = nullptr) | |
d588754c JP |
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. | |
63023c03 | 1071 | const std::vector<std::unique_ptr<Type>> &get_params () const |
d588754c JP |
1072 | { |
1073 | return inputs; | |
1074 | } | |
63023c03 | 1075 | std::vector<std::unique_ptr<Type>> &get_params () { return inputs; } |
d588754c JP |
1076 | |
1077 | // TODO: is this better? Or is a "vis_pattern" better? | |
e01c9f40 PEP |
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 () | |
d588754c JP |
1085 | { |
1086 | rust_assert (has_return_type ()); | |
1087 | return return_type; | |
1088 | } | |
875f722d | 1089 | |
df1da364 | 1090 | location_t get_locus () const { return locus; } |
d588754c JP |
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, | |
d991a3f1 | 1104 | TypePathFunction function_path, location_t locus) |
d588754c JP |
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, | |
d991a3f1 | 1113 | TypePathFunction function_path, location_t locus) |
d588754c JP |
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 | ||
d588754c JP |
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 | ||
63023c03 | 1139 | class TypePath : public TypeNoBounds |
d588754c JP |
1140 | { |
1141 | bool has_opening_scope_resolution; | |
63023c03 | 1142 | std::vector<std::unique_ptr<TypePathSegment>> segments; |
eacbbac9 | 1143 | location_t locus; |
d588754c JP |
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 | { | |
63023c03 | 1167 | return TypePath (std::vector<std::unique_ptr<TypePathSegment>> (), |
eacbbac9 | 1168 | UNDEF_LOCATION); |
d588754c JP |
1169 | } |
1170 | ||
1171 | // Constructor | |
63023c03 AC |
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, | |
d991a3f1 | 1181 | location_t locus, bool has_opening_scope_resolution = false) |
d588754c JP |
1182 | : TypeNoBounds (), |
1183 | has_opening_scope_resolution (has_opening_scope_resolution), | |
eacbbac9 | 1184 | segments (std::move (segments)), locus (locus) |
d588754c JP |
1185 | {} |
1186 | ||
1187 | // Copy constructor with vector clone | |
1188 | TypePath (TypePath const &other) | |
eacbbac9 AC |
1189 | : has_opening_scope_resolution (other.has_opening_scope_resolution), |
1190 | locus (other.locus) | |
d588754c | 1191 | { |
eacbbac9 | 1192 | node_id = other.node_id; |
d588754c JP |
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 | { | |
eacbbac9 | 1201 | node_id = other.node_id; |
d588754c | 1202 | has_opening_scope_resolution = other.has_opening_scope_resolution; |
eacbbac9 | 1203 | locus = other.locus; |
d588754c JP |
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 | ||
eacbbac9 | 1225 | location_t get_locus () const override final { return locus; } |
63023c03 | 1226 | NodeId get_node_id () const { return node_id; } |
eacbbac9 AC |
1227 | |
1228 | void mark_for_strip () override {} | |
1229 | bool is_marked_for_strip () const override { return false; } | |
1230 | ||
d588754c JP |
1231 | void accept_vis (ASTVisitor &vis) override; |
1232 | ||
1233 | // TODO: this seems kinda dodgy | |
63023c03 | 1234 | std::vector<std::unique_ptr<TypePathSegment>> &get_segments () |
d588754c JP |
1235 | { |
1236 | return segments; | |
1237 | } | |
63023c03 | 1238 | const std::vector<std::unique_ptr<TypePathSegment>> &get_segments () const |
d588754c JP |
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; | |
63023c03 | 1250 | TypePath trait_path; |
d991a3f1 | 1251 | location_t locus; |
d588754c JP |
1252 | NodeId node_id; |
1253 | ||
1254 | public: | |
1255 | // Constructor | |
1256 | QualifiedPathType (std::unique_ptr<Type> invoke_on_type, | |
d991a3f1 | 1257 | location_t locus = UNDEF_LOCATION, |
d588754c | 1258 | TypePath trait_path = TypePath::create_error ()) |
63023c03 | 1259 | : type_to_invoke_on (std::move (invoke_on_type)), trait_path (trait_path), |
c482c358 | 1260 | locus (locus), node_id (Analysis::Mappings::get ().get_next_node_id ()) |
d588754c JP |
1261 | {} |
1262 | ||
1263 | // Copy constructor uses custom deep copy for Type to preserve polymorphism | |
1264 | QualifiedPathType (QualifiedPathType const &other) | |
63023c03 | 1265 | : trait_path (other.trait_path), locus (other.locus) |
d588754c JP |
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; | |
63023c03 | 1280 | trait_path = other.trait_path; |
d588754c JP |
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. | |
63023c03 | 1297 | bool has_as_clause () const { return !trait_path.is_error (); } |
d588754c JP |
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 | ||
df1da364 | 1310 | location_t get_locus () const { return locus; } |
d588754c JP |
1311 | |
1312 | // TODO: is this better? Or is a "vis_pattern" better? | |
e01c9f40 PEP |
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 () | |
d588754c JP |
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? | |
63023c03 | 1326 | TypePath &get_as_type_path () |
d588754c JP |
1327 | { |
1328 | rust_assert (has_as_clause ()); | |
63023c03 | 1329 | return trait_path; |
d588754c JP |
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) */ | |
63023c03 | 1337 | class QualifiedPathInExpression : public Path, public ExprWithoutBlock |
d588754c JP |
1338 | { |
1339 | std::vector<Attribute> outer_attrs; | |
1340 | QualifiedPathType path_type; | |
63023c03 AC |
1341 | location_t locus; |
1342 | NodeId _node_id; | |
d588754c JP |
1343 | |
1344 | public: | |
1345 | std::string as_string () const override; | |
1346 | ||
1347 | QualifiedPathInExpression (QualifiedPathType qual_path_type, | |
1348 | std::vector<PathExprSegment> path_segments, | |
d991a3f1 OA |
1349 | std::vector<Attribute> outer_attrs, |
1350 | location_t locus) | |
63023c03 AC |
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 ()) | |
d588754c JP |
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 (), {}, | |
1678cdd3 | 1366 | {}, UNDEF_LOCATION); |
d588754c JP |
1367 | } |
1368 | ||
63023c03 | 1369 | location_t get_locus () const override final { return locus; } |
d588754c JP |
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; } | |
36bca0cc | 1388 | std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; } |
d588754c JP |
1389 | |
1390 | void set_outer_attrs (std::vector<Attribute> new_attrs) override | |
1391 | { | |
1392 | outer_attrs = std::move (new_attrs); | |
1393 | } | |
1394 | ||
63023c03 | 1395 | NodeId get_node_id () const override { return _node_id; } |
d588754c | 1396 | |
9c50565e AC |
1397 | Expr::Kind get_expr_kind () const override |
1398 | { | |
1399 | return Expr::Kind::QualifiedPathInExpression; | |
1400 | } | |
1401 | ||
d588754c JP |
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; | |
63023c03 | 1431 | std::vector<std::unique_ptr<TypePathSegment>> segments; |
d991a3f1 | 1432 | location_t locus; |
d588754c JP |
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, | |
63023c03 | 1446 | std::vector<std::unique_ptr<TypePathSegment>> path_segments, |
d991a3f1 | 1447 | location_t locus) |
d588754c JP |
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 | ||
d588754c JP |
1453 | // Copy constructor with vector clone |
1454 | QualifiedPathInType (QualifiedPathInType const &other) | |
1455 | : path_type (other.path_type), locus (other.locus) | |
1456 | { | |
fca49c4d PH |
1457 | auto seg = other.associated_segment->clone_type_path_segment_impl (); |
1458 | associated_segment = std::unique_ptr<TypePathSegment> (seg); | |
1459 | ||
d588754c JP |
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 | { | |
fca49c4d PH |
1468 | auto seg = other.associated_segment->clone_type_path_segment_impl (); |
1469 | associated_segment = std::unique_ptr<TypePathSegment> (seg); | |
1470 | ||
d588754c JP |
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, | |
63023c03 | 1493 | std::vector<std::unique_ptr<TypePathSegment>> (), UNDEF_LOCATION); |
d588754c JP |
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 | |
63023c03 | 1513 | std::vector<std::unique_ptr<TypePathSegment>> &get_segments () |
d588754c JP |
1514 | { |
1515 | return segments; | |
1516 | } | |
63023c03 | 1517 | const std::vector<std::unique_ptr<TypePathSegment>> &get_segments () const |
d588754c JP |
1518 | { |
1519 | return segments; | |
1520 | } | |
1521 | ||
df1da364 | 1522 | location_t get_locus () const override final { return locus; } |
d588754c JP |
1523 | }; |
1524 | } // namespace AST | |
1525 | } // namespace Rust | |
1526 | ||
1527 | #endif |