Auto merge of #45175 - petrochenkov:dyn, r=nikomatsakis

Implement `dyn Trait` syntax (RFC 2113)

cc https://github.com/rust-lang/rust/issues/44662
r? @nikomatsakis
This commit is contained in:
bors
2017-10-14 16:11:05 +00:00
18 changed files with 150 additions and 42 deletions
+1 -1
View File
@@ -705,7 +705,7 @@ fn lower_ty(&mut self, t: &Ty) -> P<hir::Ty> {
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 {
+1 -1
View File
@@ -152,7 +152,7 @@ fn visit_ty(&mut self, ty: &'a Ty) {
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 {
+1 -1
View File
@@ -288,7 +288,7 @@ fn make(&self, offset: usize, _parent_id: Option<NodeId>, scx: &SaveContext) ->
})
}
}
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))
+8 -1
View File
@@ -1419,7 +1419,7 @@ pub enum TyKind {
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),
@@ -1438,6 +1438,13 @@ pub enum TyKind {
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")``
+7
View File
@@ -398,6 +398,9 @@ pub fn new() -> Features {
// 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! (
@@ -1417,6 +1420,10 @@ fn visit_ty(&mut self, ty: &'a ast::Ty) {
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)
+2 -2
View File
@@ -400,8 +400,8 @@ pub fn noop_fold_ty<T: Folder>(t: P<Ty>, fld: &mut T) -> P<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)))
+40 -26
View File
@@ -33,7 +33,7 @@
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};
@@ -364,6 +364,13 @@ fn is_ident_or_underscore(t: &token::Token) -> bool {
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,
@@ -1428,7 +1435,7 @@ fn parse_ty_common(&mut self, allow_plus: bool) -> PResult<'a, P<Ty>> {
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(),
@@ -1472,6 +1479,35 @@ fn parse_ty_common(&mut self, allow_plus: bool) -> PResult<'a, P<Ty>> {
} else if self.eat(&token::Underscore) {
// A type to be inferred `_`
TyKind::Infer
} else if self.token_is_bare_fn_keyword() {
// Function pointer type
self.parse_ty_bare_fn(Vec::new())?
} else if self.check_keyword(keywords::For) {
// Function pointer type or bound list (trait object type) starting with a poly-trait.
// `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T`
// `for<'lt> Trait1<'lt> + Trait2 + 'a`
let lo = self.span;
let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
if self.token_is_bare_fn_keyword() {
self.parse_ty_bare_fn(lifetime_defs)?
} else {
let path = self.parse_path(PathStyle::Type)?;
let parse_plus = allow_plus && self.check(&token::BinOp(token::Plus));
self.parse_remaining_bounds(lifetime_defs, path, lo, parse_plus)?
}
} 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)) {
// Bound list (trait object type)
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)?;
@@ -1493,29 +1529,6 @@ fn parse_ty_common(&mut self, allow_plus: bool) -> PResult<'a, P<Ty>> {
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.check_keyword(keywords::For) {
// Function pointer type or bound list (trait object type) starting with a poly-trait.
// `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T`
// `for<'lt> Trait1<'lt> + Trait2 + 'a`
let lo = self.span;
let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
if self.token_is_bare_fn_keyword() {
self.parse_ty_bare_fn(lifetime_defs)?
} else {
let path = self.parse_path(PathStyle::Type)?;
let parse_plus = allow_plus && self.check(&token::BinOp(token::Plus));
self.parse_remaining_bounds(lifetime_defs, path, lo, parse_plus)?
}
} 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(&token::Question) ||
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)?)
} else {
let msg = format!("expected type, found {}", self.this_token_descr());
return Err(self.fatal(&msg));
@@ -1538,7 +1551,7 @@ fn parse_remaining_bounds(&mut self, lifetime_defs: Vec<LifetimeDef>, path: ast:
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, ()> {
@@ -4256,6 +4269,7 @@ fn warn_dotdoteq(&self, span: Span) {
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) ||
+6
View File
@@ -258,6 +258,12 @@ pub fn can_begin_type(&self) -> bool {
}
}
/// 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 {
+3 -2
View File
@@ -1049,8 +1049,9 @@ pub fn print_type(&mut self, ty: &ast::Ty) -> io::Result<()> {
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[..])?;
+1 -1
View File
@@ -348,7 +348,7 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) {
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);
}
+5 -4
View File
@@ -309,10 +309,11 @@ fn fresh() -> Self {
(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.
@@ -0,0 +1,29 @@
// 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() {}
@@ -0,0 +1,14 @@
// 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() {}
@@ -8,9 +8,12 @@
// 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() { }
@@ -17,4 +17,6 @@ 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)`
}
+24
View File
@@ -0,0 +1,24 @@
// 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");
}
+2 -2
View File
@@ -13,11 +13,11 @@ error: expected type, found keyword `true`
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