Skip to content

Commit e1d0976

Browse files
committed
rollup merge of #20059: nick29581/self-impl
r? @sfackler closes #20000
2 parents bc1d818 + 31f5ab3 commit e1d0976

File tree

3 files changed

+90
-5
lines changed

3 files changed

+90
-5
lines changed

src/libsyntax/ext/base.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -490,7 +490,7 @@ impl<'a> ExtCtxt<'a> {
490490

491491
/// Returns a `Folder` for deeply expanding all macros in a AST node.
492492
pub fn expander<'b>(&'b mut self) -> expand::MacroExpander<'b, 'a> {
493-
expand::MacroExpander { cx: self }
493+
expand::MacroExpander::new(self)
494494
}
495495

496496
pub fn new_parser_from_tts(&self, tts: &[ast::TokenTree])

src/libsyntax/ext/expand.rs

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use ast::{ItemMac, MacStmtWithSemicolon, Mrk, Stmt, StmtDecl, StmtMac};
1515
use ast::{StmtExpr, StmtSemi};
1616
use ast::TokenTree;
1717
use ast;
18+
use ast_util::path_to_ident;
1819
use ext::mtwt;
1920
use ext::build::AstBuilder;
2021
use attr;
@@ -37,6 +38,30 @@ enum Either<L,R> {
3738
Right(R)
3839
}
3940

41+
pub fn expand_type(t: P<ast::Ty>,
42+
fld: &mut MacroExpander,
43+
impl_ty: Option<P<ast::Ty>>)
44+
-> P<ast::Ty> {
45+
debug!("expanding type {} with impl_ty {}", t, impl_ty);
46+
let t = match (t.node.clone(), impl_ty) {
47+
// Expand uses of `Self` in impls to the concrete type.
48+
(ast::Ty_::TyPath(ref path, _), Some(ref impl_ty)) => {
49+
let path_as_ident = path_to_ident(path);
50+
// Note unhygenic comparison here. I think this is correct, since
51+
// even though `Self` is almost just a type parameter, the treatment
52+
// for this expansion is as if it were a keyword.
53+
if path_as_ident.is_some() &&
54+
path_as_ident.unwrap().name == token::special_idents::type_self.name {
55+
impl_ty.clone()
56+
} else {
57+
t
58+
}
59+
}
60+
_ => t
61+
};
62+
fold::noop_fold_ty(t, fld)
63+
}
64+
4065
pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
4166
e.and_then(|ast::Expr {id, node, span}| match node {
4267
// expr_mac should really be expr_ext or something; it's the
@@ -1065,6 +1090,14 @@ fn expand_and_rename_fn_decl_and_block(fn_decl: P<ast::FnDecl>, block: P<ast::Bl
10651090
/// A tree-folder that performs macro expansion
10661091
pub struct MacroExpander<'a, 'b:'a> {
10671092
pub cx: &'a mut ExtCtxt<'b>,
1093+
// The type of the impl currently being expanded.
1094+
current_impl_type: Option<P<ast::Ty>>,
1095+
}
1096+
1097+
impl<'a, 'b> MacroExpander<'a, 'b> {
1098+
pub fn new(cx: &'a mut ExtCtxt<'b>) -> MacroExpander<'a, 'b> {
1099+
MacroExpander { cx: cx, current_impl_type: None }
1100+
}
10681101
}
10691102

10701103
impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
@@ -1077,7 +1110,14 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
10771110
}
10781111

10791112
fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
1080-
expand_item(item, self)
1113+
let prev_type = self.current_impl_type.clone();
1114+
if let ast::Item_::ItemImpl(_, _, _, ref ty, _) = item.node {
1115+
self.current_impl_type = Some(ty.clone());
1116+
}
1117+
1118+
let result = expand_item(item, self);
1119+
self.current_impl_type = prev_type;
1120+
result
10811121
}
10821122

10831123
fn fold_item_underscore(&mut self, item: ast::Item_) -> ast::Item_ {
@@ -1100,6 +1140,11 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
11001140
expand_method(method, self)
11011141
}
11021142

1143+
fn fold_ty(&mut self, t: P<ast::Ty>) -> P<ast::Ty> {
1144+
let impl_type = self.current_impl_type.clone();
1145+
expand_type(t, self, impl_type)
1146+
}
1147+
11031148
fn new_span(&mut self, span: Span) -> Span {
11041149
new_span(self.cx, span)
11051150
}
@@ -1144,9 +1189,7 @@ pub fn expand_crate(parse_sess: &parse::ParseSess,
11441189
user_exts: Vec<NamedSyntaxExtension>,
11451190
c: Crate) -> Crate {
11461191
let mut cx = ExtCtxt::new(parse_sess, c.config.clone(), cfg);
1147-
let mut expander = MacroExpander {
1148-
cx: &mut cx,
1149-
};
1192+
let mut expander = MacroExpander::new(&mut cx);
11501193

11511194
for ExportedMacros { crate_name, macros } in imported_macros.into_iter() {
11521195
let name = format!("<{} macros>", token::get_ident(crate_name))

src/test/run-pass/self-impl.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Test that we can use `Self` types in impls in the expected way.
12+
13+
struct Foo;
14+
15+
// Test uses on inherant impl.
16+
impl Foo {
17+
fn foo(_x: Self, _y: &Self, _z: Box<Self>) -> Self {
18+
Foo
19+
}
20+
}
21+
22+
// Test uses when implementing a trait and with a type parameter.
23+
pub struct Baz<X> {
24+
pub f: X,
25+
}
26+
27+
trait Bar<X> {
28+
fn bar(x: Self, y: &Self, z: Box<Self>) -> Self;
29+
}
30+
31+
impl Bar<int> for Box<Baz<int>> {
32+
fn bar(_x: Self, _y: &Self, _z: Box<Self>) -> Self {
33+
box Baz { f: 42 }
34+
}
35+
}
36+
37+
fn main() {
38+
let _: Foo = Foo::foo(Foo, &Foo, box Foo);
39+
let _: Box<Baz<int>> = Bar::bar(box Baz { f: 42 },
40+
&box Baz { f: 42 },
41+
box box Baz { f: 42 });
42+
}

0 commit comments

Comments
 (0)