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:
commit
e156286fa5
20 changed files with 879 additions and 33 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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])
|
||||
}
|
||||
|
||||
|
|
|
|||
46
tests/pretty/delegation-impl-reuse.pp
Normal file
46
tests/pretty/delegation-impl-reuse.pp
Normal 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() {}
|
||||
18
tests/pretty/delegation-impl-reuse.rs
Normal file
18
tests/pretty/delegation-impl-reuse.rs
Normal 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() {}
|
||||
31
tests/ui/delegation/impl-reuse-bad-path.rs
Normal file
31
tests/ui/delegation/impl-reuse-bad-path.rs
Normal 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() {}
|
||||
52
tests/ui/delegation/impl-reuse-bad-path.stderr
Normal file
52
tests/ui/delegation/impl-reuse-bad-path.stderr
Normal 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`.
|
||||
14
tests/ui/delegation/impl-reuse-empty-glob.rs
Normal file
14
tests/ui/delegation/impl-reuse-empty-glob.rs
Normal 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() {}
|
||||
8
tests/ui/delegation/impl-reuse-empty-glob.stderr
Normal file
8
tests/ui/delegation/impl-reuse-empty-glob.stderr
Normal 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
|
||||
|
||||
51
tests/ui/delegation/impl-reuse-illegal-places.rs
Normal file
51
tests/ui/delegation/impl-reuse-illegal-places.rs
Normal 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() {}
|
||||
92
tests/ui/delegation/impl-reuse-illegal-places.stderr
Normal file
92
tests/ui/delegation/impl-reuse-illegal-places.stderr
Normal 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
|
||||
|
||||
19
tests/ui/delegation/impl-reuse-negative-traits.rs
Normal file
19
tests/ui/delegation/impl-reuse-negative-traits.rs
Normal 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() {}
|
||||
9
tests/ui/delegation/impl-reuse-negative-traits.stderr
Normal file
9
tests/ui/delegation/impl-reuse-negative-traits.stderr
Normal 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`.
|
||||
32
tests/ui/delegation/impl-reuse-non-reuse-items.rs
Normal file
32
tests/ui/delegation/impl-reuse-non-reuse-items.rs
Normal 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() {}
|
||||
60
tests/ui/delegation/impl-reuse-non-reuse-items.stderr
Normal file
60
tests/ui/delegation/impl-reuse-non-reuse-items.stderr
Normal 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`.
|
||||
10
tests/ui/delegation/impl-reuse-non-trait-impl-cfg-false.rs
Normal file
10
tests/ui/delegation/impl-reuse-non-trait-impl-cfg-false.rs
Normal 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() {}
|
||||
|
|
@ -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
|
||||
|
||||
9
tests/ui/delegation/impl-reuse-non-trait-impl.rs
Normal file
9
tests/ui/delegation/impl-reuse-non-trait-impl.rs
Normal 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() {}
|
||||
8
tests/ui/delegation/impl-reuse-non-trait-impl.stderr
Normal file
8
tests/ui/delegation/impl-reuse-non-trait-impl.stderr
Normal 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
|
||||
|
||||
292
tests/ui/delegation/impl-reuse-pass.rs
Normal file
292
tests/ui/delegation/impl-reuse-pass.rs
Normal 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() {}
|
||||
Loading…
Add table
Add a link
Reference in a new issue