let expr = self.lower_body(None, |this| this.lower_expr(expr));
hir::TyTypeof(expr)
}
- TyKind::TraitObject(ref bounds) => {
+ TyKind::TraitObject(ref bounds, ..) => {
let mut lifetime_bound = None;
let bounds = bounds.iter().filter_map(|bound| {
match *bound {
err.emit();
});
}
- TyKind::TraitObject(ref bounds) => {
+ TyKind::TraitObject(ref bounds, ..) => {
let mut any_lifetime_bounds = false;
for bound in bounds {
if let RegionTyParamBound(ref lifetime) = *bound {
})
}
}
- ast::TyKind::TraitObject(ref bounds) => {
+ ast::TyKind::TraitObject(ref bounds, ..) => {
// FIXME recurse into bounds
let nested = pprust::bounds_to_string(bounds);
Ok(text_sig(nested))
Path(Option<QSelf>, Path),
/// A trait object type `Bound1 + Bound2 + Bound3`
/// where `Bound` is a trait or a lifetime.
- TraitObject(TyParamBounds),
+ TraitObject(TyParamBounds, TraitObjectSyntax),
/// An `impl Bound1 + Bound2 + Bound3` type
/// where `Bound` is a trait or a lifetime.
ImplTrait(TyParamBounds),
Err,
}
+/// Syntax used to declare a trait object.
+#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum TraitObjectSyntax {
+ Dyn,
+ None,
+}
+
/// Inline assembly dialect.
///
/// E.g. `"intel"` as in `asm!("mov eax, 2" : "={eax}"(result) : : : "intel")``
// Default match binding modes (RFC 2005)
(active, match_default_bindings, "1.22.0", Some(42640)),
+
+ // Trait object syntax with `dyn` prefix
+ (active, dyn_trait, "1.22.0", Some(44662)),
);
declare_features! (
gate_feature_post!(&self, never_type, ty.span,
"The `!` type is experimental");
},
+ ast::TyKind::TraitObject(_, ast::TraitObjectSyntax::Dyn) => {
+ gate_feature_post!(&self, dyn_trait, ty.span,
+ "`dyn Trait` syntax is unstable");
+ }
_ => {}
}
visit::walk_ty(self, ty)
TyKind::Typeof(expr) => {
TyKind::Typeof(fld.fold_expr(expr))
}
- TyKind::TraitObject(bounds) => {
- TyKind::TraitObject(bounds.move_map(|b| fld.fold_ty_param_bound(b)))
+ TyKind::TraitObject(bounds, syntax) => {
+ TyKind::TraitObject(bounds.move_map(|b| fld.fold_ty_param_bound(b)), syntax)
}
TyKind::ImplTrait(bounds) => {
TyKind::ImplTrait(bounds.move_map(|b| fld.fold_ty_param_bound(b)))
use ast::{VariantData, StructField};
use ast::StrStyle;
use ast::SelfKind;
-use ast::{TraitItem, TraitRef};
+use ast::{TraitItem, TraitRef, TraitObjectSyntax};
use ast::{Ty, TyKind, TypeBinding, TyParam, TyParamBounds};
use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple};
use ast::{Visibility, WhereClause};
t.is_ident() || *t == token::Underscore
}
+// Returns true if `IDENT t` can start a type - `IDENT::a::b`, `IDENT<u8, u8>`,
+// `IDENT<<u8 as Trait>::AssocTy>`, `IDENT(u8, u8) -> u8`.
+fn can_continue_type_after_ident(t: &token::Token) -> bool {
+ t == &token::ModSep || t == &token::Lt ||
+ t == &token::BinOp(token::Shl) || t == &token::OpenDelim(token::Paren)
+}
+
/// Information about the path to a module.
pub struct ModulePath {
pub name: String,
TyKind::Path(None, ref path) if maybe_bounds => {
self.parse_remaining_bounds(Vec::new(), path.clone(), lo, true)?
}
- TyKind::TraitObject(ref bounds)
+ TyKind::TraitObject(ref bounds, TraitObjectSyntax::None)
if maybe_bounds && bounds.len() == 1 && !trailing_plus => {
let path = match bounds[0] {
TraitTyParamBound(ref pt, ..) => pt.trait_ref.path.clone(),
} else if self.eat(&token::Underscore) {
// A type to be inferred `_`
TyKind::Infer
- } else if self.eat_lt() {
- // Qualified path
- let (qself, path) = self.parse_qpath(PathStyle::Type)?;
- TyKind::Path(Some(qself), path)
- } else if self.token.is_path_start() {
- // Simple path
- let path = self.parse_path(PathStyle::Type)?;
- if self.eat(&token::Not) {
- // Macro invocation in type position
- let (_, tts) = self.expect_delimited_token_tree()?;
- TyKind::Mac(respan(lo.to(self.span), Mac_ { path: path, tts: tts }))
- } else {
- // Just a type path or bound list (trait object type) starting with a trait.
- // `Type`
- // `Trait1 + Trait2 + 'a`
- if allow_plus && self.check(&token::BinOp(token::Plus)) {
- self.parse_remaining_bounds(Vec::new(), path, lo, true)?
- } else {
- TyKind::Path(None, path)
- }
- }
} else if self.token_is_bare_fn_keyword() {
// Function pointer type
self.parse_ty_bare_fn(Vec::new())?
} else if self.eat_keyword(keywords::Impl) {
// FIXME: figure out priority of `+` in `impl Trait1 + Trait2` (#34511).
TyKind::ImplTrait(self.parse_ty_param_bounds()?)
+ } else if self.check_keyword(keywords::Dyn) &&
+ self.look_ahead(1, |t| t.can_begin_bound() && !can_continue_type_after_ident(t)) {
+ // FIXME: figure out priority of `+` in `dyn Trait1 + Trait2` (#34511).
+ self.bump(); // `dyn`
+ TyKind::TraitObject(self.parse_ty_param_bounds()?, TraitObjectSyntax::Dyn)
} else if self.check(&token::Question) ||
- self.check_lifetime() && self.look_ahead(1, |t| t == &token::BinOp(token::Plus)){
+ self.check_lifetime() && self.look_ahead(1, |t| t == &token::BinOp(token::Plus)) {
// Bound list (trait object type)
- TyKind::TraitObject(self.parse_ty_param_bounds_common(allow_plus)?)
+ TyKind::TraitObject(self.parse_ty_param_bounds_common(allow_plus)?,
+ TraitObjectSyntax::None)
+ } else if self.eat_lt() {
+ // Qualified path
+ let (qself, path) = self.parse_qpath(PathStyle::Type)?;
+ TyKind::Path(Some(qself), path)
+ } else if self.token.is_path_start() {
+ // Simple path
+ let path = self.parse_path(PathStyle::Type)?;
+ if self.eat(&token::Not) {
+ // Macro invocation in type position
+ let (_, tts) = self.expect_delimited_token_tree()?;
+ TyKind::Mac(respan(lo.to(self.span), Mac_ { path: path, tts: tts }))
+ } else {
+ // Just a type path or bound list (trait object type) starting with a trait.
+ // `Type`
+ // `Trait1 + Trait2 + 'a`
+ if allow_plus && self.check(&token::BinOp(token::Plus)) {
+ self.parse_remaining_bounds(Vec::new(), path, lo, true)?
+ } else {
+ TyKind::Path(None, path)
+ }
+ }
} else {
let msg = format!("expected type, found {}", self.this_token_descr());
return Err(self.fatal(&msg));
self.bump(); // `+`
bounds.append(&mut self.parse_ty_param_bounds()?);
}
- Ok(TyKind::TraitObject(bounds))
+ Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None))
}
fn maybe_recover_from_bad_type_plus(&mut self, allow_plus: bool, ty: &Ty) -> PResult<'a, ()> {
fn parse_ty_param_bounds_common(&mut self, allow_plus: bool) -> PResult<'a, TyParamBounds> {
let mut bounds = Vec::new();
loop {
+ // This needs to be syncronized with `Token::can_begin_bound`.
let is_bound_start = self.check_path() || self.check_lifetime() ||
self.check(&token::Question) ||
self.check_keyword(keywords::For) ||
}
}
+ /// Returns `true` if the token can appear at the start of a generic bound.
+ pub fn can_begin_bound(&self) -> bool {
+ self.is_path_start() || self.is_lifetime() || self.is_keyword(keywords::For) ||
+ self == &Question || self == &OpenDelim(Paren)
+ }
+
/// Returns `true` if the token is any literal
pub fn is_lit(&self) -> bool {
match *self {
ast::TyKind::Path(Some(ref qself), ref path) => {
self.print_qpath(path, qself, false)?
}
- ast::TyKind::TraitObject(ref bounds) => {
- self.print_bounds("", &bounds[..])?;
+ ast::TyKind::TraitObject(ref bounds, syntax) => {
+ let prefix = if syntax == ast::TraitObjectSyntax::Dyn { "dyn " } else { "" };
+ self.print_bounds(prefix, &bounds[..])?;
}
ast::TyKind::ImplTrait(ref bounds) => {
self.print_bounds("impl ", &bounds[..])?;
visitor.visit_ty(ty);
visitor.visit_expr(expression)
}
- TyKind::TraitObject(ref bounds) |
+ TyKind::TraitObject(ref bounds, ..) |
TyKind::ImplTrait(ref bounds) => {
walk_list!(visitor, visit_ty_param_bound, bounds);
}
(54, Yield, "yield")
// Weak keywords, have special meaning only in specific contexts.
- (55, Default, "default")
- (56, StaticLifetime, "'static")
- (57, Union, "union")
- (58, Catch, "catch")
+ (55, Catch, "catch")
+ (56, Default, "default")
+ (57, Dyn, "dyn")
+ (58, StaticLifetime, "'static")
+ (59, Union, "union")
}
// If an interner exists in TLS, return it. Otherwise, prepare a fresh one.
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+type A0 = dyn;
+//~^ ERROR cannot find type `dyn` in this scope
+type A1 = dyn::dyn;
+//~^ ERROR Use of undeclared type or module `dyn`
+type A2 = dyn<dyn, dyn>;
+//~^ ERROR cannot find type `dyn` in this scope
+//~| ERROR cannot find type `dyn` in this scope
+//~| ERROR cannot find type `dyn` in this scope
+type A3 = dyn<<dyn as dyn>::dyn>;
+//~^ ERROR cannot find type `dyn` in this scope
+//~| ERROR cannot find type `dyn` in this scope
+//~| ERROR Use of undeclared type or module `dyn`
+type A4 = dyn(dyn, dyn) -> dyn;
+//~^ ERROR cannot find type `dyn` in this scope
+//~| ERROR cannot find type `dyn` in this scope
+//~| ERROR cannot find type `dyn` in this scope
+//~| ERROR cannot find type `dyn` in this scope
+
+fn main() {}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait Trait {}
+type A = Box<dyn Trait>; //~ ERROR `dyn Trait` syntax is unstable
+
+fn main() {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(dyn_trait)]
struct Foo;
fn foo(_x: Box<Foo + Send>) { } //~ ERROR expected trait, found struct `Foo`
+type A<T> = Box<dyn Vec<T>>; //~ ERROR expected trait, found struct `Vec`
+
fn main() { }
//~^ ERROR expected a path on the left-hand side of `+`, not `( Copy + Copy)`
let _: Box<(Copy +) + Copy>;
//~^ ERROR expected a path on the left-hand side of `+`, not `( Copy)`
+ let _: Box<(dyn Copy) + Copy>;
+ //~^ ERROR expected a path on the left-hand side of `+`, not `(dyn Copy)`
}
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(dyn_trait)]
+
+use std::fmt::Display;
+
+static BYTE: u8 = 33;
+
+fn main() {
+ let x: &(dyn 'static + Display) = &BYTE;
+ let y: Box<dyn Display + 'static> = Box::new(BYTE);
+ let xstr = format!("{}", x);
+ let ystr = format!("{}", y);
+ assert_eq!(xstr, "33");
+ assert_eq!(ystr, "33");
+}
18 | foo!(true);
| ^^^^ expecting a type here because of type ascription
-error: expected one of `!`, `&&`, `&`, `(`, `*`, `.`, `;`, `<`, `?`, `[`, `_`, `extern`, `fn`, `for`, `impl`, `unsafe`, `}`, an operator, or lifetime, found `true`
+error: expected one of `!`, `&&`, `&`, `(`, `*`, `.`, `;`, `<`, `?`, `[`, `_`, `dyn`, `extern`, `fn`, `for`, `impl`, `unsafe`, `}`, an operator, or lifetime, found `true`
--> $DIR/issue-44406.rs:18:10
|
13 | bar(baz: $rest)
- | - expected one of 19 possible tokens here
+ | - expected one of 20 possible tokens here
...
18 | foo!(true);
| ^^^^ unexpected token