Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow Self in impls. #20059

Merged
merged 1 commit into from
Dec 22, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/libsyntax/ext/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,7 @@ impl<'a> ExtCtxt<'a> {

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

pub fn new_parser_from_tts(&self, tts: &[ast::TokenTree])
Expand Down
51 changes: 47 additions & 4 deletions src/libsyntax/ext/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use ast::{ItemMac, MacStmtWithSemicolon, Mrk, Stmt, StmtDecl, StmtMac};
use ast::{StmtExpr, StmtSemi};
use ast::TokenTree;
use ast;
use ast_util::path_to_ident;
use ext::mtwt;
use ext::build::AstBuilder;
use attr;
Expand All @@ -37,6 +38,30 @@ enum Either<L,R> {
Right(R)
}

pub fn expand_type(t: P<ast::Ty>,
fld: &mut MacroExpander,
impl_ty: Option<P<ast::Ty>>)
-> P<ast::Ty> {
debug!("expanding type {} with impl_ty {}", t, impl_ty);
let t = match (t.node.clone(), impl_ty) {
// Expand uses of `Self` in impls to the concrete type.
(ast::Ty_::TyPath(ref path, _), Some(ref impl_ty)) => {
let path_as_ident = path_to_ident(path);
// Note unhygenic comparison here. I think this is correct, since
// even though `Self` is almost just a type parameter, the treatment
// for this expansion is as if it were a keyword.
if path_as_ident.is_some() &&
path_as_ident.unwrap().name == token::special_idents::type_self.name {
impl_ty.clone()
} else {
t
}
}
_ => t
};
fold::noop_fold_ty(t, fld)
}

pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
e.and_then(|ast::Expr {id, node, span}| match node {
// expr_mac should really be expr_ext or something; it's the
Expand Down Expand Up @@ -1059,6 +1084,14 @@ fn expand_and_rename_fn_decl_and_block(fn_decl: P<ast::FnDecl>, block: P<ast::Bl
/// A tree-folder that performs macro expansion
pub struct MacroExpander<'a, 'b:'a> {
pub cx: &'a mut ExtCtxt<'b>,
// The type of the impl currently being expanded.
current_impl_type: Option<P<ast::Ty>>,
}

impl<'a, 'b> MacroExpander<'a, 'b> {
pub fn new(cx: &'a mut ExtCtxt<'b>) -> MacroExpander<'a, 'b> {
MacroExpander { cx: cx, current_impl_type: None }
}
}

impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
Expand All @@ -1071,7 +1104,14 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
}

fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
expand_item(item, self)
let prev_type = self.current_impl_type.clone();
if let ast::Item_::ItemImpl(_, _, _, ref ty, _) = item.node {
self.current_impl_type = Some(ty.clone());
}

let result = expand_item(item, self);
self.current_impl_type = prev_type;
result
}

fn fold_item_underscore(&mut self, item: ast::Item_) -> ast::Item_ {
Expand All @@ -1094,6 +1134,11 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
expand_method(method, self)
}

fn fold_ty(&mut self, t: P<ast::Ty>) -> P<ast::Ty> {
let impl_type = self.current_impl_type.clone();
expand_type(t, self, impl_type)
}

fn new_span(&mut self, span: Span) -> Span {
new_span(self.cx, span)
}
Expand Down Expand Up @@ -1138,9 +1183,7 @@ pub fn expand_crate(parse_sess: &parse::ParseSess,
user_exts: Vec<NamedSyntaxExtension>,
c: Crate) -> Crate {
let mut cx = ExtCtxt::new(parse_sess, c.config.clone(), cfg);
let mut expander = MacroExpander {
cx: &mut cx,
};
let mut expander = MacroExpander::new(&mut cx);

for ExportedMacros { crate_name, macros } in imported_macros.into_iter() {
let name = format!("<{} macros>", token::get_ident(crate_name))
Expand Down
42 changes: 42 additions & 0 deletions src/test/run-pass/self-impl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright 2014 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.

// Test that we can use `Self` types in impls in the expected way.

struct Foo;

// Test uses on inherant impl.
impl Foo {
fn foo(_x: Self, _y: &Self, _z: Box<Self>) -> Self {
Foo
}
}

// Test uses when implementing a trait and with a type parameter.
pub struct Baz<X> {
pub f: X,
}

trait Bar<X> {
fn bar(x: Self, y: &Self, z: Box<Self>) -> Self;
}

impl Bar<int> for Box<Baz<int>> {
fn bar(_x: Self, _y: &Self, _z: Box<Self>) -> Self {
box Baz { f: 42 }
}
}

fn main() {
let _: Foo = Foo::foo(Foo, &Foo, box Foo);
let _: Box<Baz<int>> = Bar::bar(box Baz { f: 42 },
&box Baz { f: 42 },
box box Baz { f: 42 });
}