Skip to content

Commit 7920a7c

Browse files
committed
Auto merge of #45175 - petrochenkov:dyn, r=nikomatsakis
Implement `dyn Trait` syntax (RFC 2113) cc #44662 r? @nikomatsakis
2 parents 9c5e9a5 + 9d37320 commit 7920a7c

File tree

18 files changed

+150
-42
lines changed

18 files changed

+150
-42
lines changed

src/librustc/hir/lowering.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -705,7 +705,7 @@ impl<'a> LoweringContext<'a> {
705705
let expr = self.lower_body(None, |this| this.lower_expr(expr));
706706
hir::TyTypeof(expr)
707707
}
708-
TyKind::TraitObject(ref bounds) => {
708+
TyKind::TraitObject(ref bounds, ..) => {
709709
let mut lifetime_bound = None;
710710
let bounds = bounds.iter().filter_map(|bound| {
711711
match *bound {

src/librustc_passes/ast_validation.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
152152
err.emit();
153153
});
154154
}
155-
TyKind::TraitObject(ref bounds) => {
155+
TyKind::TraitObject(ref bounds, ..) => {
156156
let mut any_lifetime_bounds = false;
157157
for bound in bounds {
158158
if let RegionTyParamBound(ref lifetime) = *bound {

src/librustc_save_analysis/sig.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ impl Sig for ast::Ty {
288288
})
289289
}
290290
}
291-
ast::TyKind::TraitObject(ref bounds) => {
291+
ast::TyKind::TraitObject(ref bounds, ..) => {
292292
// FIXME recurse into bounds
293293
let nested = pprust::bounds_to_string(bounds);
294294
Ok(text_sig(nested))

src/libsyntax/ast.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1419,7 +1419,7 @@ pub enum TyKind {
14191419
Path(Option<QSelf>, Path),
14201420
/// A trait object type `Bound1 + Bound2 + Bound3`
14211421
/// where `Bound` is a trait or a lifetime.
1422-
TraitObject(TyParamBounds),
1422+
TraitObject(TyParamBounds, TraitObjectSyntax),
14231423
/// An `impl Bound1 + Bound2 + Bound3` type
14241424
/// where `Bound` is a trait or a lifetime.
14251425
ImplTrait(TyParamBounds),
@@ -1438,6 +1438,13 @@ pub enum TyKind {
14381438
Err,
14391439
}
14401440

1441+
/// Syntax used to declare a trait object.
1442+
#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
1443+
pub enum TraitObjectSyntax {
1444+
Dyn,
1445+
None,
1446+
}
1447+
14411448
/// Inline assembly dialect.
14421449
///
14431450
/// E.g. `"intel"` as in `asm!("mov eax, 2" : "={eax}"(result) : : : "intel")``

src/libsyntax/feature_gate.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,9 @@ declare_features! (
398398

399399
// Default match binding modes (RFC 2005)
400400
(active, match_default_bindings, "1.22.0", Some(42640)),
401+
402+
// Trait object syntax with `dyn` prefix
403+
(active, dyn_trait, "1.22.0", Some(44662)),
401404
);
402405

403406
declare_features! (
@@ -1417,6 +1420,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
14171420
gate_feature_post!(&self, never_type, ty.span,
14181421
"The `!` type is experimental");
14191422
},
1423+
ast::TyKind::TraitObject(_, ast::TraitObjectSyntax::Dyn) => {
1424+
gate_feature_post!(&self, dyn_trait, ty.span,
1425+
"`dyn Trait` syntax is unstable");
1426+
}
14201427
_ => {}
14211428
}
14221429
visit::walk_ty(self, ty)

src/libsyntax/fold.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -400,8 +400,8 @@ pub fn noop_fold_ty<T: Folder>(t: P<Ty>, fld: &mut T) -> P<Ty> {
400400
TyKind::Typeof(expr) => {
401401
TyKind::Typeof(fld.fold_expr(expr))
402402
}
403-
TyKind::TraitObject(bounds) => {
404-
TyKind::TraitObject(bounds.move_map(|b| fld.fold_ty_param_bound(b)))
403+
TyKind::TraitObject(bounds, syntax) => {
404+
TyKind::TraitObject(bounds.move_map(|b| fld.fold_ty_param_bound(b)), syntax)
405405
}
406406
TyKind::ImplTrait(bounds) => {
407407
TyKind::ImplTrait(bounds.move_map(|b| fld.fold_ty_param_bound(b)))

src/libsyntax/parse/parser.rs

Lines changed: 40 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use ast::{Stmt, StmtKind};
3333
use ast::{VariantData, StructField};
3434
use ast::StrStyle;
3535
use ast::SelfKind;
36-
use ast::{TraitItem, TraitRef};
36+
use ast::{TraitItem, TraitRef, TraitObjectSyntax};
3737
use ast::{Ty, TyKind, TypeBinding, TyParam, TyParamBounds};
3838
use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple};
3939
use ast::{Visibility, WhereClause};
@@ -364,6 +364,13 @@ fn is_ident_or_underscore(t: &token::Token) -> bool {
364364
t.is_ident() || *t == token::Underscore
365365
}
366366

367+
// Returns true if `IDENT t` can start a type - `IDENT::a::b`, `IDENT<u8, u8>`,
368+
// `IDENT<<u8 as Trait>::AssocTy>`, `IDENT(u8, u8) -> u8`.
369+
fn can_continue_type_after_ident(t: &token::Token) -> bool {
370+
t == &token::ModSep || t == &token::Lt ||
371+
t == &token::BinOp(token::Shl) || t == &token::OpenDelim(token::Paren)
372+
}
373+
367374
/// Information about the path to a module.
368375
pub struct ModulePath {
369376
pub name: String,
@@ -1428,7 +1435,7 @@ impl<'a> Parser<'a> {
14281435
TyKind::Path(None, ref path) if maybe_bounds => {
14291436
self.parse_remaining_bounds(Vec::new(), path.clone(), lo, true)?
14301437
}
1431-
TyKind::TraitObject(ref bounds)
1438+
TyKind::TraitObject(ref bounds, TraitObjectSyntax::None)
14321439
if maybe_bounds && bounds.len() == 1 && !trailing_plus => {
14331440
let path = match bounds[0] {
14341441
TraitTyParamBound(ref pt, ..) => pt.trait_ref.path.clone(),
@@ -1472,27 +1479,6 @@ impl<'a> Parser<'a> {
14721479
} else if self.eat(&token::Underscore) {
14731480
// A type to be inferred `_`
14741481
TyKind::Infer
1475-
} else if self.eat_lt() {
1476-
// Qualified path
1477-
let (qself, path) = self.parse_qpath(PathStyle::Type)?;
1478-
TyKind::Path(Some(qself), path)
1479-
} else if self.token.is_path_start() {
1480-
// Simple path
1481-
let path = self.parse_path(PathStyle::Type)?;
1482-
if self.eat(&token::Not) {
1483-
// Macro invocation in type position
1484-
let (_, tts) = self.expect_delimited_token_tree()?;
1485-
TyKind::Mac(respan(lo.to(self.span), Mac_ { path: path, tts: tts }))
1486-
} else {
1487-
// Just a type path or bound list (trait object type) starting with a trait.
1488-
// `Type`
1489-
// `Trait1 + Trait2 + 'a`
1490-
if allow_plus && self.check(&token::BinOp(token::Plus)) {
1491-
self.parse_remaining_bounds(Vec::new(), path, lo, true)?
1492-
} else {
1493-
TyKind::Path(None, path)
1494-
}
1495-
}
14961482
} else if self.token_is_bare_fn_keyword() {
14971483
// Function pointer type
14981484
self.parse_ty_bare_fn(Vec::new())?
@@ -1512,10 +1498,37 @@ impl<'a> Parser<'a> {
15121498
} else if self.eat_keyword(keywords::Impl) {
15131499
// FIXME: figure out priority of `+` in `impl Trait1 + Trait2` (#34511).
15141500
TyKind::ImplTrait(self.parse_ty_param_bounds()?)
1501+
} else if self.check_keyword(keywords::Dyn) &&
1502+
self.look_ahead(1, |t| t.can_begin_bound() && !can_continue_type_after_ident(t)) {
1503+
// FIXME: figure out priority of `+` in `dyn Trait1 + Trait2` (#34511).
1504+
self.bump(); // `dyn`
1505+
TyKind::TraitObject(self.parse_ty_param_bounds()?, TraitObjectSyntax::Dyn)
15151506
} else if self.check(&token::Question) ||
1516-
self.check_lifetime() && self.look_ahead(1, |t| t == &token::BinOp(token::Plus)){
1507+
self.check_lifetime() && self.look_ahead(1, |t| t == &token::BinOp(token::Plus)) {
15171508
// Bound list (trait object type)
1518-
TyKind::TraitObject(self.parse_ty_param_bounds_common(allow_plus)?)
1509+
TyKind::TraitObject(self.parse_ty_param_bounds_common(allow_plus)?,
1510+
TraitObjectSyntax::None)
1511+
} else if self.eat_lt() {
1512+
// Qualified path
1513+
let (qself, path) = self.parse_qpath(PathStyle::Type)?;
1514+
TyKind::Path(Some(qself), path)
1515+
} else if self.token.is_path_start() {
1516+
// Simple path
1517+
let path = self.parse_path(PathStyle::Type)?;
1518+
if self.eat(&token::Not) {
1519+
// Macro invocation in type position
1520+
let (_, tts) = self.expect_delimited_token_tree()?;
1521+
TyKind::Mac(respan(lo.to(self.span), Mac_ { path: path, tts: tts }))
1522+
} else {
1523+
// Just a type path or bound list (trait object type) starting with a trait.
1524+
// `Type`
1525+
// `Trait1 + Trait2 + 'a`
1526+
if allow_plus && self.check(&token::BinOp(token::Plus)) {
1527+
self.parse_remaining_bounds(Vec::new(), path, lo, true)?
1528+
} else {
1529+
TyKind::Path(None, path)
1530+
}
1531+
}
15191532
} else {
15201533
let msg = format!("expected type, found {}", self.this_token_descr());
15211534
return Err(self.fatal(&msg));
@@ -1538,7 +1551,7 @@ impl<'a> Parser<'a> {
15381551
self.bump(); // `+`
15391552
bounds.append(&mut self.parse_ty_param_bounds()?);
15401553
}
1541-
Ok(TyKind::TraitObject(bounds))
1554+
Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None))
15421555
}
15431556

15441557
fn maybe_recover_from_bad_type_plus(&mut self, allow_plus: bool, ty: &Ty) -> PResult<'a, ()> {
@@ -4256,6 +4269,7 @@ impl<'a> Parser<'a> {
42564269
fn parse_ty_param_bounds_common(&mut self, allow_plus: bool) -> PResult<'a, TyParamBounds> {
42574270
let mut bounds = Vec::new();
42584271
loop {
4272+
// This needs to be syncronized with `Token::can_begin_bound`.
42594273
let is_bound_start = self.check_path() || self.check_lifetime() ||
42604274
self.check(&token::Question) ||
42614275
self.check_keyword(keywords::For) ||

src/libsyntax/parse/token.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,12 @@ impl Token {
258258
}
259259
}
260260

261+
/// Returns `true` if the token can appear at the start of a generic bound.
262+
pub fn can_begin_bound(&self) -> bool {
263+
self.is_path_start() || self.is_lifetime() || self.is_keyword(keywords::For) ||
264+
self == &Question || self == &OpenDelim(Paren)
265+
}
266+
261267
/// Returns `true` if the token is any literal
262268
pub fn is_lit(&self) -> bool {
263269
match *self {

src/libsyntax/print/pprust.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,8 +1049,9 @@ impl<'a> State<'a> {
10491049
ast::TyKind::Path(Some(ref qself), ref path) => {
10501050
self.print_qpath(path, qself, false)?
10511051
}
1052-
ast::TyKind::TraitObject(ref bounds) => {
1053-
self.print_bounds("", &bounds[..])?;
1052+
ast::TyKind::TraitObject(ref bounds, syntax) => {
1053+
let prefix = if syntax == ast::TraitObjectSyntax::Dyn { "dyn " } else { "" };
1054+
self.print_bounds(prefix, &bounds[..])?;
10541055
}
10551056
ast::TyKind::ImplTrait(ref bounds) => {
10561057
self.print_bounds("impl ", &bounds[..])?;

src/libsyntax/visit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) {
348348
visitor.visit_ty(ty);
349349
visitor.visit_expr(expression)
350350
}
351-
TyKind::TraitObject(ref bounds) |
351+
TyKind::TraitObject(ref bounds, ..) |
352352
TyKind::ImplTrait(ref bounds) => {
353353
walk_list!(visitor, visit_ty_param_bound, bounds);
354354
}

0 commit comments

Comments
 (0)