diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 87d1173c0d486..747895c804697 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -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 diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 698d8f76aaa64..3b72c9802afd3 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -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, +} diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 33913fd351a18..8c560d78c4a4c 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -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>> { 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,26 @@ 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 { - // 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) + fn is_reuse_item(&mut self) -> Option { + self.token + .is_keyword(kw::Reuse) + .then(|| { + // no: `reuse ::path` for compatibility reasons with macro invocations + 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 + } + }) + .flatten() } /// Are we sure this could not possibly be a macro invocation? @@ -560,6 +575,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 +644,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 +719,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>> { + 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 +799,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() { + 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)) + + Ok(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 { + + Ok(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( @@ -2594,7 +2672,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 +2681,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 +2696,7 @@ impl<'a> Parser<'a> { } i += 1; } + self.is_keyword_ahead(i, &[kw::Impl]) } diff --git a/tests/ui/delegation/impl-reuse-bad-path.rs b/tests/ui/delegation/impl-reuse-bad-path.rs new file mode 100644 index 0000000000000..19eb51153468d --- /dev/null +++ b/tests/ui/delegation/impl-reuse-bad-path.rs @@ -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() {} diff --git a/tests/ui/delegation/impl-reuse-bad-path.stderr b/tests/ui/delegation/impl-reuse-bad-path.stderr new file mode 100644 index 0000000000000..5fadd719ae4da --- /dev/null +++ b/tests/ui/delegation/impl-reuse-bad-path.stderr @@ -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`. diff --git a/tests/ui/delegation/impl-reuse-empty-glob.rs b/tests/ui/delegation/impl-reuse-empty-glob.rs new file mode 100644 index 0000000000000..3f1314c47da62 --- /dev/null +++ b/tests/ui/delegation/impl-reuse-empty-glob.rs @@ -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() {} diff --git a/tests/ui/delegation/impl-reuse-empty-glob.stderr b/tests/ui/delegation/impl-reuse-empty-glob.stderr new file mode 100644 index 0000000000000..bf6bb58763519 --- /dev/null +++ b/tests/ui/delegation/impl-reuse-empty-glob.stderr @@ -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 + diff --git a/tests/ui/delegation/impl-reuse-illegal-places.rs b/tests/ui/delegation/impl-reuse-illegal-places.rs new file mode 100644 index 0000000000000..361331d41315d --- /dev/null +++ b/tests/ui/delegation/impl-reuse-illegal-places.rs @@ -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() {} diff --git a/tests/ui/delegation/impl-reuse-illegal-places.stderr b/tests/ui/delegation/impl-reuse-illegal-places.stderr new file mode 100644 index 0000000000000..fb17ebdd6cee1 --- /dev/null +++ b/tests/ui/delegation/impl-reuse-illegal-places.stderr @@ -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 + +error: aborting due to 12 previous errors + diff --git a/tests/ui/delegation/impl-reuse-negative-traits.rs b/tests/ui/delegation/impl-reuse-negative-traits.rs new file mode 100644 index 0000000000000..7bcbc82f03db8 --- /dev/null +++ b/tests/ui/delegation/impl-reuse-negative-traits.rs @@ -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() {} diff --git a/tests/ui/delegation/impl-reuse-negative-traits.stderr b/tests/ui/delegation/impl-reuse-negative-traits.stderr new file mode 100644 index 0000000000000..1be6ef715920d --- /dev/null +++ b/tests/ui/delegation/impl-reuse-negative-traits.stderr @@ -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`. diff --git a/tests/ui/delegation/impl-reuse-non-reuse-items.rs b/tests/ui/delegation/impl-reuse-non-reuse-items.rs new file mode 100644 index 0000000000000..de7c92279218d --- /dev/null +++ b/tests/ui/delegation/impl-reuse-non-reuse-items.rs @@ -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() {} diff --git a/tests/ui/delegation/impl-reuse-non-reuse-items.stderr b/tests/ui/delegation/impl-reuse-non-reuse-items.stderr new file mode 100644 index 0000000000000..9d6b0f6381367 --- /dev/null +++ b/tests/ui/delegation/impl-reuse-non-reuse-items.stderr @@ -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`. diff --git a/tests/ui/delegation/impl-reuse-non-trait-impl.rs b/tests/ui/delegation/impl-reuse-non-trait-impl.rs new file mode 100644 index 0000000000000..c7a9813250db9 --- /dev/null +++ b/tests/ui/delegation/impl-reuse-non-trait-impl.rs @@ -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() {} diff --git a/tests/ui/delegation/impl-reuse-non-trait-impl.stderr b/tests/ui/delegation/impl-reuse-non-trait-impl.stderr new file mode 100644 index 0000000000000..3987042104c38 --- /dev/null +++ b/tests/ui/delegation/impl-reuse-non-trait-impl.stderr @@ -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 + diff --git a/tests/ui/delegation/impl-reuse-pass.rs b/tests/ui/delegation/impl-reuse-pass.rs new file mode 100644 index 0000000000000..90060b03f9efd --- /dev/null +++ b/tests/ui/delegation/impl-reuse-pass.rs @@ -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; + } + + 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{}); + + >::foo(&f, &a); + >::bar(&f, &b); + >::goo(&f, &c); + + let f = F1(S1{}); + >::foo(&f, &123); + >::bar(&f, &b); + >::goo(&f, &"s".to_string()); + + let f = F2(S2{}); + >::foo(&f, &1); + >::bar(&f, &2); + >::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() {}