Rollup merge of #150130 - aerooneqq:delegation-one-line-trait-impl, r=petrochenkov

Support syntax for one-line trait reuse

This PR adds support for reusing the whole trait with a one-line reuse syntax and is part of the delegation feature rust-lang/rust#118212:
```rust
trait T {
  fn foo(&self);
}

struct S;
impl T for S { ... }

struct Wrapper(S);
reuse impl T for Wrapper { self.0 }
```

The core idea is that we already have support for glob reuse, so in this scenario we want to transform one-line reuse into a trait impl block with a glob reuse in the following way:
```rust
//Before
reuse impl T for Wrapper { self.0 }

//After
impl T for Wrapper {
  reuse T::* { self.0 }
}
```

It seems like this task can be solved during parsing stage, when we encountered a one-line trait reuse, we can expand into this impl block right away, and the code which was already written to expand glob delegations will take care about the rest. We will copy trait path into glob reuse path.

The implementation of the transformation reuses already existing methods for `impl` parsing, however, we do not parse inner `impl` items, instead we parse "inner items" as delegation body. Thus, we do not have to deal with generics, consts, unsafe and other `impl` related features.

Other syntax possibility is trying to shorten one-line reuse by replacing `impl` keyword with `reuse` keyword:
```rust
reuse T for Wrapper { self.0 }
```
In this case implementation may become more complicated, and the syntax more confusing, as keywords such as `const` or `unsafe` will precede `reuse`, and there are also generics:
```rust
unsafe reuse<T1, T2> T for Wrapper { self.0 }
```

In the first (currently implemented) version reuse is placed in the beginning of the item, and it is clear that we will reuse trait implementation, while in the second, shorter version, the `reuse` keyword may be lost in generics and keywords that may precede `impl`.

r? ``@petrochenkov``
This commit is contained in:
Jonathan Brouwer 2025-12-23 12:01:01 +01:00 committed by GitHub
commit e156286fa5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 879 additions and 33 deletions

View file

@ -162,6 +162,8 @@ parse_default_not_followed_by_item = `default` is not followed by an item
.label = the `default` qualifier
.note = only `fn`, `const`, `type`, or `impl` items may be prefixed by `default`
parse_delegation_non_trait_impl_reuse = only trait impls can be reused
parse_do_catch_syntax_removed = found removed `do catch` syntax
.note = following RFC #2388, the new non-placeholder syntax is `try`
.suggestion = replace with the new syntax

View file

@ -3671,3 +3671,10 @@ pub(crate) struct VarargsWithoutPattern {
#[suggestion(code = "_: ...", applicability = "machine-applicable")]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(parse_delegation_non_trait_impl_reuse)]
pub(crate) struct ImplReuseInherentImpl {
#[primary_span]
pub span: Span,
}

View file

@ -117,6 +117,11 @@ impl<'a> Parser<'a> {
}
}
enum ReuseKind {
Path,
Impl,
}
impl<'a> Parser<'a> {
pub fn parse_item(&mut self, force_collect: ForceCollect) -> PResult<'a, Option<Box<Item>>> {
let fn_parse_mode =
@ -249,9 +254,9 @@ impl<'a> Parser<'a> {
} else if self.check_keyword_case(exp!(Trait), case) || self.check_trait_front_matter() {
// TRAIT ITEM
self.parse_item_trait(attrs, lo)?
} else if self.check_impl_frontmatter() {
} else if self.check_impl_frontmatter(0) {
// IMPL ITEM
self.parse_item_impl(attrs, def_())?
self.parse_item_impl(attrs, def_(), false)?
} else if let Const::Yes(const_span) = self.parse_constness(case) {
// CONST ITEM
self.recover_const_mut(const_span);
@ -265,8 +270,8 @@ impl<'a> Parser<'a> {
rhs,
define_opaque: None,
}))
} else if self.is_reuse_path_item() {
self.parse_item_delegation()?
} else if let Some(kind) = self.is_reuse_item() {
self.parse_item_delegation(attrs, def_(), kind)?
} else if self.check_keyword_case(exp!(Mod), case)
|| self.check_keyword_case(exp!(Unsafe), case) && self.is_keyword_ahead(1, &[kw::Mod])
{
@ -367,16 +372,25 @@ impl<'a> Parser<'a> {
/// When parsing a statement, would the start of a path be an item?
pub(super) fn is_path_start_item(&mut self) -> bool {
self.is_kw_followed_by_ident(kw::Union) // no: `union::b`, yes: `union U { .. }`
|| self.is_reuse_path_item()
|| self.is_reuse_item().is_some() // yes: `reuse impl Trait for Struct { self.0 }`, yes: `reuse some_path::foo;`
|| self.check_trait_front_matter() // no: `auto::b`, yes: `auto trait X { .. }`
|| self.is_async_fn() // no(2015): `async::b`, yes: `async fn`
|| matches!(self.is_macro_rules_item(), IsMacroRulesItem::Yes{..}) // no: `macro_rules::b`, yes: `macro_rules! mac`
}
fn is_reuse_path_item(&mut self) -> bool {
fn is_reuse_item(&mut self) -> Option<ReuseKind> {
if !self.token.is_keyword(kw::Reuse) {
return None;
}
// no: `reuse ::path` for compatibility reasons with macro invocations
self.token.is_keyword(kw::Reuse)
&& self.look_ahead(1, |t| t.is_path_start() && *t != token::PathSep)
if self.look_ahead(1, |t| t.is_path_start() && *t != token::PathSep) {
Some(ReuseKind::Path)
} else if self.check_impl_frontmatter(1) {
Some(ReuseKind::Impl)
} else {
None
}
}
/// Are we sure this could not possibly be a macro invocation?
@ -560,6 +574,7 @@ impl<'a> Parser<'a> {
&mut self,
attrs: &mut AttrVec,
defaultness: Defaultness,
is_reuse: bool,
) -> PResult<'a, ItemKind> {
let mut constness = self.parse_constness(Case::Sensitive);
let safety = self.parse_safety(Case::Sensitive);
@ -628,7 +643,11 @@ impl<'a> Parser<'a> {
generics.where_clause = self.parse_where_clause()?;
let impl_items = self.parse_item_list(attrs, |p| p.parse_impl_item(ForceCollect::No))?;
let impl_items = if is_reuse {
Default::default()
} else {
self.parse_item_list(attrs, |p| p.parse_impl_item(ForceCollect::No))?
};
let (of_trait, self_ty) = match ty_second {
Some(ty_second) => {
@ -699,10 +718,76 @@ impl<'a> Parser<'a> {
Ok(ItemKind::Impl(Impl { generics, of_trait, self_ty, items: impl_items, constness }))
}
fn parse_item_delegation(&mut self) -> PResult<'a, ItemKind> {
fn parse_item_delegation(
&mut self,
attrs: &mut AttrVec,
defaultness: Defaultness,
kind: ReuseKind,
) -> PResult<'a, ItemKind> {
let span = self.token.span;
self.expect_keyword(exp!(Reuse))?;
let item_kind = match kind {
ReuseKind::Path => self.parse_path_like_delegation(),
ReuseKind::Impl => self.parse_impl_delegation(span, attrs, defaultness),
}?;
self.psess.gated_spans.gate(sym::fn_delegation, span.to(self.prev_token.span));
Ok(item_kind)
}
fn parse_delegation_body(&mut self) -> PResult<'a, Option<Box<Block>>> {
Ok(if self.check(exp!(OpenBrace)) {
Some(self.parse_block()?)
} else {
self.expect(exp!(Semi))?;
None
})
}
fn parse_impl_delegation(
&mut self,
span: Span,
attrs: &mut AttrVec,
defaultness: Defaultness,
) -> PResult<'a, ItemKind> {
let mut impl_item = self.parse_item_impl(attrs, defaultness, true)?;
let ItemKind::Impl(Impl { items, of_trait, .. }) = &mut impl_item else { unreachable!() };
let until_expr_span = span.to(self.prev_token.span);
let Some(of_trait) = of_trait else {
return Err(self
.dcx()
.create_err(errors::ImplReuseInherentImpl { span: until_expr_span }));
};
let body = self.parse_delegation_body()?;
let whole_reuse_span = span.to(self.prev_token.span);
items.push(Box::new(AssocItem {
id: DUMMY_NODE_ID,
attrs: Default::default(),
span: whole_reuse_span,
tokens: None,
vis: Visibility {
kind: VisibilityKind::Inherited,
span: whole_reuse_span,
tokens: None,
},
kind: AssocItemKind::DelegationMac(Box::new(DelegationMac {
qself: None,
prefix: of_trait.trait_ref.path.clone(),
suffixes: None,
body,
})),
}));
Ok(impl_item)
}
fn parse_path_like_delegation(&mut self) -> PResult<'a, ItemKind> {
let (qself, path) = if self.eat_lt() {
let (qself, path) = self.parse_qpath(PathStyle::Expr)?;
(Some(qself), path)
@ -713,43 +798,35 @@ impl<'a> Parser<'a> {
let rename = |this: &mut Self| {
Ok(if this.eat_keyword(exp!(As)) { Some(this.parse_ident()?) } else { None })
};
let body = |this: &mut Self| {
Ok(if this.check(exp!(OpenBrace)) {
Some(this.parse_block()?)
} else {
this.expect(exp!(Semi))?;
None
})
};
let item_kind = if self.eat_path_sep() {
Ok(if self.eat_path_sep() {
let suffixes = if self.eat(exp!(Star)) {
None
} else {
let parse_suffix = |p: &mut Self| Ok((p.parse_path_segment_ident()?, rename(p)?));
Some(self.parse_delim_comma_seq(exp!(OpenBrace), exp!(CloseBrace), parse_suffix)?.0)
};
let deleg = DelegationMac { qself, prefix: path, suffixes, body: body(self)? };
ItemKind::DelegationMac(Box::new(deleg))
ItemKind::DelegationMac(Box::new(DelegationMac {
qself,
prefix: path,
suffixes,
body: self.parse_delegation_body()?,
}))
} else {
let rename = rename(self)?;
let ident = rename.unwrap_or_else(|| path.segments.last().unwrap().ident);
let deleg = Delegation {
ItemKind::Delegation(Box::new(Delegation {
id: DUMMY_NODE_ID,
qself,
path,
ident,
rename,
body: body(self)?,
body: self.parse_delegation_body()?,
from_glob: false,
};
ItemKind::Delegation(Box::new(deleg))
};
let span = span.to(self.prev_token.span);
self.psess.gated_spans.gate(sym::fn_delegation, span);
Ok(item_kind)
}))
})
}
fn parse_item_list<T>(
@ -2594,7 +2671,7 @@ impl<'a> Parser<'a> {
Ok(body)
}
fn check_impl_frontmatter(&mut self) -> bool {
fn check_impl_frontmatter(&mut self, look_ahead: usize) -> bool {
const ALL_QUALS: &[Symbol] = &[kw::Const, kw::Unsafe];
// In contrast to the loop below, this call inserts `impl` into the
// list of expected tokens shown in diagnostics.
@ -2603,7 +2680,7 @@ impl<'a> Parser<'a> {
}
let mut i = 0;
while i < ALL_QUALS.len() {
let action = self.look_ahead(i, |token| {
let action = self.look_ahead(i + look_ahead, |token| {
if token.is_keyword(kw::Impl) {
return Some(true);
}
@ -2618,6 +2695,7 @@ impl<'a> Parser<'a> {
}
i += 1;
}
self.is_keyword_ahead(i, &[kw::Impl])
}

View file

@ -0,0 +1,46 @@
#![feature(prelude_import)]
#![no_std]
//@ pretty-compare-only
//@ pretty-mode:expanded
//@ pp-exact:delegation-impl-reuse.pp
#![allow(incomplete_features)]
#![feature(fn_delegation)]
#[macro_use]
extern crate std;
#[prelude_import]
use ::std::prelude::rust_2015::*;
trait Trait<T> {
fn foo(&self) {}
fn bar(&self) {}
fn baz(&self) {}
}
struct S;
impl Trait<{
struct S;
0
}> for S {
reuse Trait<{
struct S;
0
}>::foo {
self.0
}
reuse Trait<{
struct S;
0
}>::bar {
self.0
}
reuse Trait<{
struct S;
0
}>::baz {
self.0
}
}
fn main() {}

View file

@ -0,0 +1,18 @@
//@ pretty-compare-only
//@ pretty-mode:expanded
//@ pp-exact:delegation-impl-reuse.pp
#![allow(incomplete_features)]
#![feature(fn_delegation)]
trait Trait<T> {
fn foo(&self) {}
fn bar(&self) {}
fn baz(&self) {}
}
struct S;
reuse impl Trait<{ struct S; 0 }> for S { self.0 }
fn main() {}

View file

@ -0,0 +1,31 @@
#![allow(incomplete_features)]
#![feature(fn_delegation)]
mod unresolved {
struct S;
reuse impl unresolved for S { self.0 }
//~^ ERROR failed to resolve: use of unresolved module or unlinked crate `unresolved`
//~| ERROR cannot find trait `unresolved` in this scope
trait T {}
reuse impl T for unresolved { self.0 }
//~^ ERROR empty glob delegation is not supported
//~| ERROR cannot find type `unresolved` in this scope
}
mod wrong_entities {
trait T {}
struct Trait;
struct S;
reuse impl Trait for S { self.0 }
//~^ ERROR expected trait, found struct `Trait`
//~| ERROR expected trait, found struct `Trait`
mod TraitModule {}
reuse impl TraitModule for S { self.0 }
//~^ ERROR expected trait, found module `TraitModule`
//~| ERROR expected trait, found module `TraitModule`
}
fn main() {}

View file

@ -0,0 +1,52 @@
error: empty glob delegation is not supported
--> $DIR/impl-reuse-bad-path.rs:11:5
|
LL | reuse impl T for unresolved { self.0 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: expected trait, found struct `Trait`
--> $DIR/impl-reuse-bad-path.rs:21:16
|
LL | reuse impl Trait for S { self.0 }
| ^^^^^ not a trait
error: expected trait, found module `TraitModule`
--> $DIR/impl-reuse-bad-path.rs:26:16
|
LL | reuse impl TraitModule for S { self.0 }
| ^^^^^^^^^^^ not a trait
error[E0433]: failed to resolve: use of unresolved module or unlinked crate `unresolved`
--> $DIR/impl-reuse-bad-path.rs:6:16
|
LL | reuse impl unresolved for S { self.0 }
| ^^^^^^^^^^ use of unresolved module or unlinked crate `unresolved`
error[E0405]: cannot find trait `unresolved` in this scope
--> $DIR/impl-reuse-bad-path.rs:6:16
|
LL | reuse impl unresolved for S { self.0 }
| ^^^^^^^^^^ not found in this scope
error[E0425]: cannot find type `unresolved` in this scope
--> $DIR/impl-reuse-bad-path.rs:11:22
|
LL | reuse impl T for unresolved { self.0 }
| ^^^^^^^^^^ not found in this scope
error[E0404]: expected trait, found struct `Trait`
--> $DIR/impl-reuse-bad-path.rs:21:16
|
LL | reuse impl Trait for S { self.0 }
| ^^^^^ not a trait
error[E0404]: expected trait, found module `TraitModule`
--> $DIR/impl-reuse-bad-path.rs:26:16
|
LL | reuse impl TraitModule for S { self.0 }
| ^^^^^^^^^^^ not a trait
error: aborting due to 8 previous errors
Some errors have detailed explanations: E0404, E0405, E0425, E0433.
For more information about an error, try `rustc --explain E0404`.

View file

@ -0,0 +1,14 @@
#![allow(incomplete_features)]
#![feature(fn_delegation)]
mod empty_glob {
trait T {}
struct S;
reuse impl T for S { self.0 }
//~^ ERROR empty glob delegation is not supported
}
fn main() {}

View file

@ -0,0 +1,8 @@
error: empty glob delegation is not supported
--> $DIR/impl-reuse-empty-glob.rs:9:5
|
LL | reuse impl T for S { self.0 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error

View file

@ -0,0 +1,51 @@
#![allow(incomplete_features)]
#![feature(fn_delegation)]
trait T {
fn f(&self) {}
}
struct S;
impl T for S {}
struct F(S);
struct X {
reuse impl T for F { self.0 }
//~^ ERROR expected `:`, found keyword `impl`
}
impl X {
reuse impl T for F { self.0 }
//~^ ERROR implementation is not supported in `trait`s or `impl`s
}
trait Trait {
reuse impl T for F { self.0 }
//~^ ERROR implementation is not supported in `trait`s or `impl`s
}
extern "C" {
reuse impl T for F { self.0 }
//~^ ERROR implementation is not supported in `extern` blocks
}
mod m {
mod inner {
pub fn foo() {}
}
reuse inner::{
reuse impl T for F { self.0 }
//~^ ERROR expected identifier, found keyword `impl`
//~| ERROR expected one of `,`, `as`, or `}`, found keyword `impl`
//~| ERROR expected one of `,`, `as`, or `}`, found `T`
//~| ERROR expected identifier, found keyword `for`
//~| ERROR expected one of `,`, `as`, or `}`, found keyword `for`
//~| ERROR expected one of `,`, `as`, or `}`, found `F`
//~| ERROR expected one of `,`, `as`, or `}`, found `{`
}
}
//~^ ERROR expected item, found `}`
fn main() {}

View file

@ -0,0 +1,92 @@
error: expected `:`, found keyword `impl`
--> $DIR/impl-reuse-illegal-places.rs:14:11
|
LL | struct X {
| - while parsing this struct
LL | reuse impl T for F { self.0 }
| ^^^^ expected `:`
error: implementation is not supported in `trait`s or `impl`s
--> $DIR/impl-reuse-illegal-places.rs:19:5
|
LL | reuse impl T for F { self.0 }
| ^^^^^^^^^^^^^^^^^^
|
= help: consider moving the implementation out to a nearby module scope
error: implementation is not supported in `trait`s or `impl`s
--> $DIR/impl-reuse-illegal-places.rs:24:5
|
LL | reuse impl T for F { self.0 }
| ^^^^^^^^^^^^^^^^^^
|
= help: consider moving the implementation out to a nearby module scope
error: implementation is not supported in `extern` blocks
--> $DIR/impl-reuse-illegal-places.rs:29:5
|
LL | reuse impl T for F { self.0 }
| ^^^^^^^^^^^^^^^^^^
|
= help: consider moving the implementation out to a nearby module scope
error: expected identifier, found keyword `impl`
--> $DIR/impl-reuse-illegal-places.rs:39:15
|
LL | reuse impl T for F { self.0 }
| ^^^^ expected identifier, found keyword
error: expected one of `,`, `as`, or `}`, found keyword `impl`
--> $DIR/impl-reuse-illegal-places.rs:39:15
|
LL | reuse impl T for F { self.0 }
| -^^^^ expected one of `,`, `as`, or `}`
| |
| help: missing `,`
error: expected one of `,`, `as`, or `}`, found `T`
--> $DIR/impl-reuse-illegal-places.rs:39:20
|
LL | reuse impl T for F { self.0 }
| -^ expected one of `,`, `as`, or `}`
| |
| help: missing `,`
error: expected identifier, found keyword `for`
--> $DIR/impl-reuse-illegal-places.rs:39:22
|
LL | reuse impl T for F { self.0 }
| ^^^ expected identifier, found keyword
error: expected one of `,`, `as`, or `}`, found keyword `for`
--> $DIR/impl-reuse-illegal-places.rs:39:22
|
LL | reuse impl T for F { self.0 }
| -^^^ expected one of `,`, `as`, or `}`
| |
| help: missing `,`
error: expected one of `,`, `as`, or `}`, found `F`
--> $DIR/impl-reuse-illegal-places.rs:39:26
|
LL | reuse impl T for F { self.0 }
| -^ expected one of `,`, `as`, or `}`
| |
| help: missing `,`
error: expected one of `,`, `as`, or `}`, found `{`
--> $DIR/impl-reuse-illegal-places.rs:39:28
|
LL | reuse impl T for F { self.0 }
| ^ expected one of `,`, `as`, or `}`
error: expected item, found `}`
--> $DIR/impl-reuse-illegal-places.rs:48:1
|
LL | }
| ^ expected item
|
= note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>
error: aborting due to 12 previous errors

View file

@ -0,0 +1,19 @@
#![allow(incomplete_features)]
#![feature(fn_delegation)]
#![feature(negative_impls)]
trait Trait {
fn foo(&self);
//~^ ERROR negative impls cannot have any items [E0749]
}
struct S;
impl Trait for S {
fn foo(&self) {}
}
struct F(S);
reuse impl !Trait for F { &self.0 }
fn main() {}

View file

@ -0,0 +1,9 @@
error[E0749]: negative impls cannot have any items
--> $DIR/impl-reuse-negative-traits.rs:6:8
|
LL | fn foo(&self);
| ^^^
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0749`.

View file

@ -0,0 +1,32 @@
#![allow(incomplete_features)]
#![feature(fn_delegation)]
mod non_delegatable_items {
trait Trait {
fn method(&self);
const CONST: u8;
type Type;
#[allow(non_camel_case_types)]
type method;
}
struct F;
impl Trait for F {
fn method(&self) {}
const CONST: u8 = 0;
type Type = u8;
type method = u8;
}
struct S(F);
reuse impl Trait for S { &self.0 }
//~^ ERROR item `CONST` is an associated method, which doesn't match its trait `Trait`
//~| ERROR item `Type` is an associated method, which doesn't match its trait `Trait`
//~| ERROR duplicate definitions with name `method`
//~| ERROR expected function, found associated constant `Trait::CONST`
//~| ERROR expected function, found associated type `Trait::Type`
//~| ERROR not all trait items implemented, missing: `CONST`, `Type`, `method`
}
fn main() {}

View file

@ -0,0 +1,60 @@
error[E0324]: item `CONST` is an associated method, which doesn't match its trait `Trait`
--> $DIR/impl-reuse-non-reuse-items.rs:23:5
|
LL | const CONST: u8;
| ---------------- item in trait
...
LL | reuse impl Trait for S { &self.0 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ does not match trait
error[E0324]: item `Type` is an associated method, which doesn't match its trait `Trait`
--> $DIR/impl-reuse-non-reuse-items.rs:23:5
|
LL | type Type;
| ---------- item in trait
...
LL | reuse impl Trait for S { &self.0 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ does not match trait
error[E0201]: duplicate definitions with name `method`:
--> $DIR/impl-reuse-non-reuse-items.rs:23:5
|
LL | fn method(&self);
| ----------------- item in trait
...
LL | reuse impl Trait for S { &self.0 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| duplicate definition
| previous definition here
error[E0423]: expected function, found associated constant `Trait::CONST`
--> $DIR/impl-reuse-non-reuse-items.rs:23:16
|
LL | reuse impl Trait for S { &self.0 }
| ^^^^^ not a function
error[E0423]: expected function, found associated type `Trait::Type`
--> $DIR/impl-reuse-non-reuse-items.rs:23:16
|
LL | reuse impl Trait for S { &self.0 }
| ^^^^^ not a function
error[E0046]: not all trait items implemented, missing: `CONST`, `Type`, `method`
--> $DIR/impl-reuse-non-reuse-items.rs:23:5
|
LL | const CONST: u8;
| --------------- `CONST` from trait
LL | type Type;
| --------- `Type` from trait
LL | #[allow(non_camel_case_types)]
LL | type method;
| ----------- `method` from trait
...
LL | reuse impl Trait for S { &self.0 }
| ^^^^^^^^^^^^^^^^^^^^^^ missing `CONST`, `Type`, `method` in implementation
error: aborting due to 6 previous errors
Some errors have detailed explanations: E0046, E0201, E0324, E0423.
For more information about an error, try `rustc --explain E0046`.

View file

@ -0,0 +1,10 @@
#![allow(incomplete_features)]
#![feature(fn_delegation)]
struct Trait(usize);
#[cfg(false)]
reuse impl Trait { self.0 }
//~^ ERROR only trait impls can be reused
fn main() {}

View file

@ -0,0 +1,8 @@
error: only trait impls can be reused
--> $DIR/impl-reuse-non-trait-impl-cfg-false.rs:7:1
|
LL | reuse impl Trait { self.0 }
| ^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error

View file

@ -0,0 +1,9 @@
#![allow(incomplete_features)]
#![feature(fn_delegation)]
struct Trait(usize);
reuse impl Trait { self.0 }
//~^ ERROR only trait impls can be reused
fn main() {}

View file

@ -0,0 +1,8 @@
error: only trait impls can be reused
--> $DIR/impl-reuse-non-trait-impl.rs:6:1
|
LL | reuse impl Trait { self.0 }
| ^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error

View file

@ -0,0 +1,292 @@
//@ check-pass
#![allow(incomplete_features)]
#![feature(fn_delegation)]
#![feature(const_trait_impl)]
#![allow(warnings)]
mod default {
trait T {
fn foo(&self) {}
fn bar(&self) {}
fn goo(&self) {}
}
struct S;
impl T for S {}
struct F(S);
reuse impl T for F { self.0 }
fn f() {
let f = F(S{});
f.foo();
f.bar();
f.goo();
}
}
mod dyn_traits {
trait T {
fn foo(&self) -> Box<dyn T>;
}
trait SecondTrait {
fn bar(&self);
}
reuse impl SecondTrait for dyn T { self.foo().as_ref() }
}
mod complex_path {
pub mod first {
pub mod second {
pub trait T {
fn foo(&self, x: usize);
}
}
}
struct S;
impl first::second::T for S {
fn foo(&self, x: usize) { }
}
struct F(S);
reuse impl first::second::T for F { self.0 }
fn f() {
use complex_path::first::second::T;
let f = F(S{});
f.foo(1);
}
}
mod no_body_reuse {
trait T {
fn foo(&self) {}
fn bar(&mut self) {}
}
struct F;
reuse impl T for F;
fn foo() {
let mut f = F{};
f.foo();
f.bar();
}
}
mod unsafe_trait {
unsafe trait UnsafeTrait {
fn foo(&self) {}
fn bar(&self) {}
fn goo(&self) {}
}
struct S;
unsafe impl UnsafeTrait for S {}
struct F(S);
reuse unsafe impl UnsafeTrait for F { self.0 }
fn f() {
let f = F(S{});
f.foo();
f.bar();
f.goo();
}
}
mod const_trait {
const trait ConstTrait {
fn foo(&self) -> usize { 0 }
fn bar(&self) -> usize { 1 }
}
struct S;
const impl ConstTrait for S {}
struct F(S);
reuse const impl ConstTrait for F { self.0 }
fn f() {
let f = F(S{});
f.foo();
f.bar();
}
}
mod different_selves {
trait T: Sized {
fn foo(&self) {}
fn boo(self) {}
fn goo(&mut self) {}
}
struct S;
impl T for S {}
struct F(S);
reuse impl T for F { self.0 }
struct D(S);
macro_rules! self_0 { ($self:ident) => { $self.0 } }
reuse impl T for D { self_0!(self) }
fn f() {
let mut f = F(S{});
f.foo();
f.goo();
f.boo();
let mut d = D(S{});
d.foo();
d.goo();
d.boo();
}
}
mod macros {
trait Trait {
fn foo(&self) -> u8 { 0 }
fn bar(&self) -> u8 { 1 }
}
impl Trait for u8 {}
struct S(u8);
macro_rules! self_0_ref { ($self:ident) => { &$self.0 } }
reuse impl Trait for S { self_0_ref!(self) }
struct M(u8);
macro_rules! m { () => { M } }
reuse impl Trait for m!() { self_0_ref!(self) }
struct S1(u8);
macro_rules! one_line_reuse { ($self:ident) => { reuse impl Trait for S1 { $self.0 } } }
one_line_reuse!(self);
struct S2(u8);
macro_rules! one_line_reuse_expr { ($x:expr) => { reuse impl Trait for S2 { $x } } }
one_line_reuse_expr!(self.0);
struct S3(u8);
macro_rules! s3 { () => { S3 } }
macro_rules! one_line_reuse_expr2 { ($x:expr) => { reuse impl Trait for s3!() { $x } } }
one_line_reuse_expr2!(self.0);
fn f() {
let s = S(1);
s.foo();
s.bar();
let m = M(41);
m.foo();
m.bar();
let s1 = S1(2);
s1.foo();
s1.bar();
let s2 = S2(4);
s2.foo();
s2.bar();
let s3 = S3(5);
s3.foo();
s3.bar();
}
}
mod generics {
trait Trait<'a, 'b, A, B, C> {
fn foo(&self, a: &A) {}
fn bar(&self, b: &B) {}
fn goo(&self, c: &C) {}
}
struct S;
impl<'a, 'b, A, B, C> Trait<'a, 'b, A, B, C> for S {}
struct F(S);
reuse impl<'a, 'b, A, B, C> Trait<'a, 'b, A, B, C> for F { &self.0 }
struct S1;
struct F1(S1);
impl<'c, B> Trait<'static, 'c, usize, B, String> for S1 {}
reuse impl<'d, B> Trait<'static, 'd, usize, B, String> for F1 { &self.0 }
struct S2;
struct F2(S2);
impl Trait<'static, 'static, u8, u16, u32> for S2 {}
reuse impl Trait<'static, 'static, u8, u16, u32> for F2 { &self.0 }
fn f<'a, 'b, 'c, A, B, C>(a: A, b: B, c: C) {
let f = F(S{});
<F as Trait<'a, 'b, A, B, C>>::foo(&f, &a);
<F as Trait<'a, 'b, A, B, C>>::bar(&f, &b);
<F as Trait<'a, 'b, A, B, C>>::goo(&f, &c);
let f = F1(S1{});
<F1 as Trait<'static, 'c, usize, B, String>>::foo(&f, &123);
<F1 as Trait<'static, 'c, usize, B, String>>::bar(&f, &b);
<F1 as Trait<'static, 'c, usize, B, String>>::goo(&f, &"s".to_string());
let f = F2(S2{});
<F2 as Trait<'static, 'static, u8, u16, u32>>::foo(&f, &1);
<F2 as Trait<'static, 'static, u8, u16, u32>>::bar(&f, &2);
<F2 as Trait<'static, 'static, u8, u16, u32>>::goo(&f, &3);
}
}
mod reuse_in_different_places {
trait T {
fn foo(&self, x: usize) {}
}
struct S;
impl T for S {}
struct F1(S);
reuse impl T for F1 {
struct F2(S, S, S);
reuse impl T for F2 { self.1 }
let f2 = F2(S{}, S{}, S{});
f2.foo(123);
&self.0
}
fn foo() {
struct F(S);
reuse impl T for F { self.0 }
let f = F(S{});
f.foo(1);
}
fn bar() {
|| {
struct F(S);
reuse impl T for F { self.0 }
let f = F(S{});
f.foo(1);
};
}
}
fn main() {}