blob: 896cb7e4024d0de90243aab9fd74c896040d0b52 [file] [log] [blame]
David Tolnayb79ee962016-09-04 09:39:20 -07001use super::*;
2
David Tolnayb79ee962016-09-04 09:39:20 -07003#[derive(Debug, Clone, Eq, PartialEq)]
4pub enum Ty {
5 /// A variable-length array (`[T]`)
6 Vec(Box<Ty>),
7 /// A fixed length array (`[T; n]`)
8 FixedLengthVec(Box<Ty>, usize),
9 /// A raw pointer (`*const T` or `*mut T`)
10 Ptr(Box<MutTy>),
11 /// A reference (`&'a T` or `&'a mut T`)
12 Rptr(Option<Lifetime>, Box<MutTy>),
13 /// A bare function (e.g. `fn(usize) -> bool`)
14 BareFn(Box<BareFnTy>),
15 /// The never type (`!`)
16 Never,
17 /// A tuple (`(A, B, C, D, ...)`)
18 Tup(Vec<Ty>),
19 /// A path (`module::module::...::Type`), optionally
20 /// "qualified", e.g. `<Vec<T> as SomeTrait>::SomeType`.
21 ///
22 /// Type parameters are stored in the Path itself
23 Path(Option<QSelf>, Path),
24 /// Something like `A+B`. Note that `B` must always be a path.
25 ObjectSum(Box<Ty>, Vec<TyParamBound>),
26 /// A type like `for<'a> Foo<&'a Bar>`
27 PolyTraitRef(Vec<TyParamBound>),
28 /// An `impl TraitA+TraitB` type.
29 ImplTrait(Vec<TyParamBound>),
30 /// No-op; kept solely so that we can pretty-print faithfully
31 Paren(Box<Ty>),
32 /// TyKind::Infer means the type should be inferred instead of it having been
33 /// specified. This can appear anywhere in a type.
34 Infer,
35}
36
37#[derive(Debug, Clone, Eq, PartialEq)]
38pub struct MutTy {
39 pub ty: Ty,
40 pub mutability: Mutability,
41}
42
43#[derive(Debug, Clone, Eq, PartialEq)]
44pub enum Mutability {
45 Mutable,
46 Immutable,
47}
48
49#[derive(Debug, Clone, Eq, PartialEq)]
50pub struct Path {
51 pub global: bool,
52 pub segments: Vec<PathSegment>,
53}
54
55/// A segment of a path: an identifier, an optional lifetime, and a set of types.
56///
57/// E.g. `std`, `String` or `Box<T>`
58#[derive(Debug, Clone, Eq, PartialEq)]
59pub struct PathSegment {
60 pub ident: Ident,
61 pub parameters: PathParameters,
62}
63
64impl PathSegment {
65 pub fn ident(ident: Ident) -> Self {
66 PathSegment {
67 ident: ident,
68 parameters: PathParameters::none(),
69 }
70 }
71}
72
73/// Parameters of a path segment.
74///
75/// E.g. `<A, B>` as in `Foo<A, B>` or `(A, B)` as in `Foo(A, B)`
76#[derive(Debug, Clone, Eq, PartialEq)]
77pub enum PathParameters {
78 /// The `<'a, A, B, C>` in `foo::bar::baz::<'a, A, B, C>`
79 AngleBracketed(AngleBracketedParameterData),
80 /// The `(A, B)` and `C` in `Foo(A, B) -> C`
81 Parenthesized(ParenthesizedParameterData),
82}
83
84impl PathParameters {
85 pub fn none() -> Self {
86 PathParameters::AngleBracketed(AngleBracketedParameterData::default())
87 }
88}
89
90/// A path like `Foo<'a, T>`
91#[derive(Debug, Clone, Eq, PartialEq, Default)]
92pub struct AngleBracketedParameterData {
93 /// The lifetime parameters for this path segment.
94 pub lifetimes: Vec<Lifetime>,
95 /// The type parameters for this path segment, if present.
96 pub types: Vec<Ty>,
97 /// Bindings (equality constraints) on associated types, if present.
98 ///
99 /// E.g., `Foo<A=Bar>`.
100 pub bindings: Vec<TypeBinding>,
101}
102
103/// Bind a type to an associated type: `A=Foo`.
104#[derive(Debug, Clone, Eq, PartialEq)]
105pub struct TypeBinding {
106 pub ident: Ident,
107 pub ty: Ty,
108}
109
110/// A path like `Foo(A,B) -> C`
111#[derive(Debug, Clone, Eq, PartialEq)]
112pub struct ParenthesizedParameterData {
113 /// `(A, B)`
114 pub inputs: Vec<Ty>,
115 /// `C`
116 pub output: Option<Ty>,
117}
118
119#[derive(Debug, Clone, Eq, PartialEq)]
120pub struct PolyTraitRef {
121 /// The `'a` in `<'a> Foo<&'a T>`
122 pub bound_lifetimes: Vec<LifetimeDef>,
123 /// The `Foo<&'a T>` in `<'a> Foo<&'a T>`
124 pub trait_ref: Path,
125}
126
127/// The explicit Self type in a "qualified path". The actual
128/// path, including the trait and the associated item, is stored
129/// separately. `position` represents the index of the associated
130/// item qualified with this Self type.
131///
132/// ```rust,ignore
133/// <Vec<T> as a::b::Trait>::AssociatedItem
134/// ^~~~~ ~~~~~~~~~~~~~~^
135/// ty position = 3
136///
137/// <Vec<T>>::AssociatedItem
138/// ^~~~~ ^
139/// ty position = 0
140/// ```
141#[derive(Debug, Clone, Eq, PartialEq)]
142pub struct QSelf {
143 pub ty: Box<Ty>,
144 pub position: usize
145}
146
147#[derive(Debug, Clone, Eq, PartialEq)]
148pub struct BareFnTy {
149 pub lifetimes: Vec<LifetimeDef>,
150 pub decl: FnDecl
151}
152
153/// Header (not the body) of a function declaration.
154///
155/// E.g. `fn foo(bar: baz)`
156#[derive(Debug, Clone, Eq, PartialEq)]
157pub struct FnDecl {
158 pub inputs: Vec<Arg>,
159 pub output: FunctionRetTy,
160}
161
162/// An argument in a function header.
163///
164/// E.g. `bar: usize` as in `fn foo(bar: usize)`
165#[derive(Debug, Clone, Eq, PartialEq)]
166pub struct Arg {
167 pub pat: Option<Ident>,
168 pub ty: Ty,
169}
170
171#[derive(Debug, Clone, Eq, PartialEq)]
172pub enum FunctionRetTy {
173 /// Return type is not specified.
174 ///
175 /// Functions default to `()` and
176 /// closures default to inference. Span points to where return
177 /// type would be inserted.
178 Default,
179 /// Everything else
180 Ty(Ty),
181}
182
David Tolnay86eca752016-09-04 11:26:41 -0700183#[cfg(feature = "parsing")]
David Tolnay9d8f1972016-09-04 11:58:48 -0700184pub mod parsing {
185 use super::*;
186 use common::parsing::word;
187 use generics::parsing::{lifetime, lifetime_def, ty_param_bound, bound_lifetimes};
188 use nom::{digit, multispace};
189 use std::str;
David Tolnayda4049b2016-09-04 10:59:23 -0700190
David Tolnay9d8f1972016-09-04 11:58:48 -0700191 named!(pub ty<&str, Ty>, alt!(
192 ty_vec
David Tolnayda4049b2016-09-04 10:59:23 -0700193 |
David Tolnay9d8f1972016-09-04 11:58:48 -0700194 ty_fixed_length_vec
David Tolnayb79ee962016-09-04 09:39:20 -0700195 |
David Tolnay9d8f1972016-09-04 11:58:48 -0700196 ty_ptr
197 |
198 ty_rptr
199 |
200 ty_bare_fn
201 |
202 ty_never
203 |
204 ty_tup
205 |
206 ty_path
207 |
208 ty_qpath
209 |
210 ty_impl_trait
211 |
212 ty_paren
213 ));
David Tolnayb79ee962016-09-04 09:39:20 -0700214
David Tolnay9d8f1972016-09-04 11:58:48 -0700215 named!(ty_vec<&str, Ty>, do_parse!(
216 punct!("[") >>
217 elem: ty >>
218 punct!("]") >>
219 (Ty::Vec(Box::new(elem)))
220 ));
David Tolnayb79ee962016-09-04 09:39:20 -0700221
David Tolnay9d8f1972016-09-04 11:58:48 -0700222 named!(ty_fixed_length_vec<&str, Ty>, do_parse!(
223 punct!("[") >>
224 elem: ty >>
225 punct!(";") >>
226 opt!(multispace) >>
227 size: map_res!(digit, str::parse) >>
228 (Ty::FixedLengthVec(Box::new(elem), size))
229 ));
230
231 named!(ty_ptr<&str, Ty>, do_parse!(
232 punct!("*") >>
233 mutability: alt!(
234 punct!("const") => { |_| Mutability::Immutable }
235 |
236 punct!("mut") => { |_| Mutability::Mutable }
237 ) >>
238 target: ty >>
239 (Ty::Ptr(Box::new(MutTy {
240 ty: target,
241 mutability: mutability,
242 })))
243 ));
244
245 named!(ty_rptr<&str, Ty>, do_parse!(
246 punct!("&") >>
247 life: opt!(lifetime) >>
248 mutability: mutability >>
249 target: ty >>
250 (Ty::Rptr(life, Box::new(MutTy {
251 ty: target,
252 mutability: mutability,
253 })))
254 ));
255
256 named!(ty_bare_fn<&str, Ty>, do_parse!(
257 punct!("fn") >>
258 multispace >>
259 lifetimes: opt_vec!(delimited!(
260 punct!("<"),
261 separated_list!(punct!(","), lifetime_def),
262 punct!(">")
David Tolnay6b7aaf02016-09-04 10:39:25 -0700263 )) >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700264 punct!("(") >>
265 inputs: separated_list!(punct!(","), fn_arg) >>
266 punct!(")") >>
267 output: opt!(preceded!(
268 punct!("->"),
269 ty
270 )) >>
271 (Ty::BareFn(Box::new(BareFnTy {
272 lifetimes: lifetimes,
273 decl: FnDecl {
274 inputs: inputs,
275 output: match output {
276 Some(ty) => FunctionRetTy::Ty(ty),
277 None => FunctionRetTy::Default,
278 },
279 },
280 })))
281 ));
282
283 named!(ty_never<&str, Ty>, map!(punct!("!"), |_| Ty::Never));
284
285 named!(ty_tup<&str, Ty>, do_parse!(
286 punct!("(") >>
287 elems: separated_list!(punct!(","), ty) >>
288 punct!(")") >>
289 (Ty::Tup(elems))
290 ));
291
292 named!(ty_path<&str, Ty>, map!(path, |p| Ty::Path(None, p)));
293
294 named!(ty_qpath<&str, Ty>, do_parse!(
295 punct!("<") >>
296 this: map!(ty, Box::new) >>
297 path: opt!(preceded!(
298 tuple!(punct!("as"), multispace),
299 path
David Tolnay6b7aaf02016-09-04 10:39:25 -0700300 )) >>
301 punct!(">") >>
David Tolnay9d8f1972016-09-04 11:58:48 -0700302 punct!("::") >>
303 rest: separated_nonempty_list!(punct!("::"), path_segment) >>
304 ({
305 match path {
306 Some(mut path) => {
307 let pos = path.segments.len();
308 path.segments.extend(rest);
309 Ty::Path(Some(QSelf { ty: this, position: pos }), path)
David Tolnayb79ee962016-09-04 09:39:20 -0700310 }
David Tolnay9d8f1972016-09-04 11:58:48 -0700311 None => {
312 Ty::Path(Some(QSelf { ty: this, position: 0 }), Path {
313 global: false,
314 segments: rest,
315 })
316 }
317 }
David Tolnay6b7aaf02016-09-04 10:39:25 -0700318 })
David Tolnay9d8f1972016-09-04 11:58:48 -0700319 ));
David Tolnayb79ee962016-09-04 09:39:20 -0700320
David Tolnay9d8f1972016-09-04 11:58:48 -0700321 named!(ty_impl_trait<&str, Ty>, do_parse!(
322 punct!("impl") >>
323 multispace >>
324 elem: separated_nonempty_list!(punct!("+"), ty_param_bound) >>
325 (Ty::ImplTrait(elem))
326 ));
David Tolnayb79ee962016-09-04 09:39:20 -0700327
David Tolnay9d8f1972016-09-04 11:58:48 -0700328 named!(ty_paren<&str, Ty>, do_parse!(
329 punct!("(") >>
330 elem: ty >>
331 punct!(")") >>
332 (Ty::Paren(Box::new(elem)))
333 ));
David Tolnayb79ee962016-09-04 09:39:20 -0700334
David Tolnay9d8f1972016-09-04 11:58:48 -0700335 named!(mutability<&str, Mutability>, preceded!(
336 opt!(multispace),
337 alt!(
338 terminated!(tag_s!("mut"), multispace) => { |_| Mutability::Mutable }
339 |
340 epsilon!() => { |_| Mutability::Immutable }
341 )
342 ));
343
344 named!(path<&str, Path>, do_parse!(
345 global: opt!(punct!("::")) >>
346 segments: separated_nonempty_list!(punct!("::"), path_segment) >>
347 (Path {
348 global: global.is_some(),
349 segments: segments,
350 })
351 ));
352
353 named!(path_segment<&str, PathSegment>, alt!(
354 do_parse!(
355 ident: word >>
356 punct!("<") >>
357 lifetimes: separated_list!(punct!(","), lifetime) >>
358 types: opt_vec!(preceded!(
359 cond!(!lifetimes.is_empty(), punct!(",")),
360 separated_nonempty_list!(
361 punct!(","),
362 terminated!(ty, not!(peek!(punct!("="))))
363 )
364 )) >>
365 bindings: opt_vec!(preceded!(
366 cond!(!lifetimes.is_empty() || !types.is_empty(), punct!(",")),
367 separated_nonempty_list!(punct!(","), type_binding)
368 )) >>
369 punct!(">") >>
370 (PathSegment {
371 ident: ident,
372 parameters: PathParameters::AngleBracketed(
373 AngleBracketedParameterData {
374 lifetimes: lifetimes,
375 types: types,
376 bindings: bindings,
377 }
378 ),
379 })
380 )
381 |
382 map!(word, PathSegment::ident)
383 ));
384
385 named!(type_binding<&str, TypeBinding>, do_parse!(
386 ident: word >>
387 punct!("=") >>
388 ty: ty >>
389 (TypeBinding {
390 ident: ident,
391 ty: ty,
392 })
393 ));
394
395 named!(pub poly_trait_ref<&str, PolyTraitRef>, do_parse!(
396 bound_lifetimes: bound_lifetimes >>
397 trait_ref: path >>
398 (PolyTraitRef {
399 bound_lifetimes: bound_lifetimes,
400 trait_ref: trait_ref,
401 })
402 ));
403
404 named!(fn_arg<&str, Arg>, do_parse!(
405 pat: opt!(terminated!(word, punct!(":"))) >>
406 ty: ty >>
407 (Arg {
408 pat: pat,
409 ty: ty,
410 })
411 ));
412}
David Tolnay87d0b442016-09-04 11:52:12 -0700413
414#[cfg(feature = "printing")]
415mod printing {
416 use super::*;
417 use quote::{Tokens, ToTokens};
418
419 impl ToTokens for Ty {
420 fn to_tokens(&self, tokens: &mut Tokens) {
421 match *self {
422 Ty::Vec(ref inner) => {
423 tokens.append("[");
424 inner.to_tokens(tokens);
425 tokens.append("]");
426 }
427 Ty::FixedLengthVec(ref inner, len) => {
428 tokens.append("[");
429 inner.to_tokens(tokens);
430 tokens.append(";");
431 len.to_tokens(tokens);
432 tokens.append("]");
433 }
434 Ty::Ptr(ref target) => {
435 tokens.append("*");
436 match target.mutability {
437 Mutability::Mutable => tokens.append("mut"),
438 Mutability::Immutable => tokens.append("const"),
439 }
440 target.ty.to_tokens(tokens);
441 }
442 Ty::Rptr(ref lifetime, ref target) => {
443 tokens.append("&");
444 lifetime.to_tokens(tokens);
445 if let Mutability::Mutable = target.mutability {
446 tokens.append("mut");
447 }
448 target.ty.to_tokens(tokens);
449 }
450 Ty::BareFn(ref func) => {
451 func.to_tokens(tokens);
452 }
453 Ty::Never => {
454 tokens.append("!");
455 }
456 Ty::Tup(ref elems) => {
457 tokens.append("(");
David Tolnay94ebdf92016-09-04 13:33:16 -0700458 tokens.append_separated(elems, ",");
David Tolnay87d0b442016-09-04 11:52:12 -0700459 if elems.len() == 1 {
460 tokens.append(",");
461 }
462 tokens.append(")");
463 }
464 Ty::Path(ref qself, ref path) => {
465 match *qself {
466 Some(ref qself) => {
467 tokens.append("<");
468 qself.ty.to_tokens(tokens);
469 if qself.position > 0 {
470 tokens.append("as");
471 for (i, segment) in path.segments.iter()
472 .take(qself.position)
473 .enumerate()
474 {
475 if i > 0 || path.global {
476 tokens.append("::");
477 }
478 segment.to_tokens(tokens);
479 }
480 for segment in path.segments.iter()
481 .skip(qself.position)
482 {
483 tokens.append("::");
484 segment.to_tokens(tokens);
485 }
486 }
487 tokens.append(">");
488 }
489 None => path.to_tokens(tokens),
490 }
491 }
492 Ty::ObjectSum(_, _) => unimplemented!(),
493 Ty::PolyTraitRef(_) => unimplemented!(),
494 Ty::ImplTrait(ref bounds) => {
495 tokens.append("impl");
David Tolnay94ebdf92016-09-04 13:33:16 -0700496 tokens.append_separated(bounds, "+");
David Tolnay87d0b442016-09-04 11:52:12 -0700497 }
498 Ty::Paren(ref inner) => {
499 tokens.append("(");
500 inner.to_tokens(tokens);
501 tokens.append(")");
502 }
503 Ty::Infer => {
504 tokens.append("_");
505 }
506 }
507 }
508 }
509
510 impl ToTokens for Path {
511 fn to_tokens(&self, tokens: &mut Tokens) {
512 for (i, segment) in self.segments.iter().enumerate() {
513 if i > 0 || self.global {
514 tokens.append("::");
515 }
516 segment.to_tokens(tokens);
517 }
518 }
519 }
520
521 impl ToTokens for PathSegment {
522 fn to_tokens(&self, tokens: &mut Tokens) {
523 self.ident.to_tokens(tokens);
524 self.parameters.to_tokens(tokens);
525 }
526 }
527
528 impl ToTokens for PathParameters {
529 fn to_tokens(&self, tokens: &mut Tokens) {
530 match *self {
531 PathParameters::AngleBracketed(ref parameters) => {
532 parameters.to_tokens(tokens);
533 }
534 PathParameters::Parenthesized(ref parameters) => {
535 parameters.to_tokens(tokens);
536 }
537 }
538 }
539 }
540
541 impl ToTokens for AngleBracketedParameterData {
542 fn to_tokens(&self, tokens: &mut Tokens) {
543 let has_lifetimes = !self.lifetimes.is_empty();
544 let has_types = !self.types.is_empty();
545 let has_bindings = !self.bindings.is_empty();
546 if !has_lifetimes && !has_types && !has_bindings {
547 return;
548 }
549
550 tokens.append("<");
551
552 let mut first = true;
553 for lifetime in &self.lifetimes {
554 if !first {
555 tokens.append(",");
556 }
557 lifetime.to_tokens(tokens);
558 first = false;
559 }
560 for ty in &self.types {
561 if !first {
562 tokens.append(",");
563 }
564 ty.to_tokens(tokens);
565 first = false;
566 }
567 for binding in &self.bindings {
568 if !first {
569 tokens.append(",");
570 }
571 binding.to_tokens(tokens);
572 first = false;
573 }
574
575 tokens.append(">");
576 }
577 }
578
579 impl ToTokens for TypeBinding {
580 fn to_tokens(&self, tokens: &mut Tokens) {
581 self.ident.to_tokens(tokens);
582 tokens.append("=");
583 self.ty.to_tokens(tokens);
584 }
585 }
586
587 impl ToTokens for ParenthesizedParameterData {
588 fn to_tokens(&self, tokens: &mut Tokens) {
589 tokens.append("(");
David Tolnay94ebdf92016-09-04 13:33:16 -0700590 tokens.append_separated(&self.inputs, ",");
David Tolnay87d0b442016-09-04 11:52:12 -0700591 tokens.append(")");
592 if let Some(ref output) = self.output {
593 tokens.append("->");
594 output.to_tokens(tokens);
595 }
596 }
597 }
598
599 impl ToTokens for PolyTraitRef {
600 fn to_tokens(&self, tokens: &mut Tokens) {
601 if !self.bound_lifetimes.is_empty() {
602 tokens.append("<");
David Tolnay94ebdf92016-09-04 13:33:16 -0700603 tokens.append_separated(&self.bound_lifetimes, ",");
David Tolnay87d0b442016-09-04 11:52:12 -0700604 tokens.append(">");
605 }
606 self.trait_ref.to_tokens(tokens);
607 }
608 }
609
610 impl ToTokens for BareFnTy {
611 fn to_tokens(&self, tokens: &mut Tokens) {
612 tokens.append("fn");
613 if !self.lifetimes.is_empty() {
614 tokens.append("<");
615 for (i, lifetime) in self.lifetimes.iter().enumerate() {
616 if i > 0 {
617 tokens.append(",");
618 }
619 lifetime.to_tokens(tokens);
620 }
621 tokens.append(">");
622 }
623 tokens.append("(");
624 tokens.append(")");
625 }
626 }
627}