Allow Self in impls.
This commit is contained in:
@@ -490,7 +490,7 @@ impl<'a> ExtCtxt<'a> {
|
|||||||
|
|
||||||
/// Returns a `Folder` for deeply expanding all macros in a AST node.
|
/// Returns a `Folder` for deeply expanding all macros in a AST node.
|
||||||
pub fn expander<'b>(&'b mut self) -> expand::MacroExpander<'b, 'a> {
|
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])
|
pub fn new_parser_from_tts(&self, tts: &[ast::TokenTree])
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ use ast::{ItemMac, MacStmtWithSemicolon, Mrk, Stmt, StmtDecl, StmtMac};
|
|||||||
use ast::{StmtExpr, StmtSemi};
|
use ast::{StmtExpr, StmtSemi};
|
||||||
use ast::TokenTree;
|
use ast::TokenTree;
|
||||||
use ast;
|
use ast;
|
||||||
|
use ast_util::path_to_ident;
|
||||||
use ext::mtwt;
|
use ext::mtwt;
|
||||||
use ext::build::AstBuilder;
|
use ext::build::AstBuilder;
|
||||||
use attr;
|
use attr;
|
||||||
@@ -37,6 +38,30 @@ enum Either<L,R> {
|
|||||||
Right(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> {
|
pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
|
||||||
e.and_then(|ast::Expr {id, node, span}| match node {
|
e.and_then(|ast::Expr {id, node, span}| match node {
|
||||||
// expr_mac should really be expr_ext or something; it's the
|
// expr_mac should really be expr_ext or something; it's the
|
||||||
@@ -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
|
/// A tree-folder that performs macro expansion
|
||||||
pub struct MacroExpander<'a, 'b:'a> {
|
pub struct MacroExpander<'a, 'b:'a> {
|
||||||
pub cx: &'a mut ExtCtxt<'b>,
|
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> {
|
impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
|
||||||
@@ -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>> {
|
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_ {
|
fn fold_item_underscore(&mut self, item: ast::Item_) -> ast::Item_ {
|
||||||
@@ -1094,6 +1134,11 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
|
|||||||
expand_method(method, self)
|
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 {
|
fn new_span(&mut self, span: Span) -> Span {
|
||||||
new_span(self.cx, span)
|
new_span(self.cx, span)
|
||||||
}
|
}
|
||||||
@@ -1138,9 +1183,7 @@ pub fn expand_crate(parse_sess: &parse::ParseSess,
|
|||||||
user_exts: Vec<NamedSyntaxExtension>,
|
user_exts: Vec<NamedSyntaxExtension>,
|
||||||
c: Crate) -> Crate {
|
c: Crate) -> Crate {
|
||||||
let mut cx = ExtCtxt::new(parse_sess, c.config.clone(), cfg);
|
let mut cx = ExtCtxt::new(parse_sess, c.config.clone(), cfg);
|
||||||
let mut expander = MacroExpander {
|
let mut expander = MacroExpander::new(&mut cx);
|
||||||
cx: &mut cx,
|
|
||||||
};
|
|
||||||
|
|
||||||
for ExportedMacros { crate_name, macros } in imported_macros.into_iter() {
|
for ExportedMacros { crate_name, macros } in imported_macros.into_iter() {
|
||||||
let name = format!("<{} macros>", token::get_ident(crate_name))
|
let name = format!("<{} macros>", token::get_ident(crate_name))
|
||||||
|
|||||||
42
src/test/run-pass/self-impl.rs
Normal file
42
src/test/run-pass/self-impl.rs
Normal file
@@ -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 });
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user