diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 11a531353eba0..bfb005046f841 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2564,6 +2564,8 @@ pub enum TyKind { /// Usually not written directly in user code but indirectly via the macro /// `core::field::field_of!(...)`. FieldOf(Box, Option, Ident), + /// A view of a type. `T.{ field_1, field_2 }`. + View(Box, #[visitable(ignore)] ThinVec), /// Sometimes we need a dummy value when no error has occurred. Dummy, /// Placeholder for a kind that has failed to be defined. diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs index 0c98b0e5e7b4f..56f96f9a8a279 100644 --- a/compiler/rustc_ast/src/util/classify.rs +++ b/compiler/rustc_ast/src/util/classify.rs @@ -302,7 +302,8 @@ fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> { | ast::TyKind::Pat(..) | ast::TyKind::FieldOf(..) | ast::TyKind::Dummy - | ast::TyKind::Err(..) => break None, + | ast::TyKind::Err(..) + | ast::TyKind::View(..) => break None, } } } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index b8d708d42ff10..8d6a22813999e 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1707,6 +1707,10 @@ impl<'hir> LoweringContext<'_, 'hir> { ); hir::TyKind::Err(guar) } + TyKind::View(ty, _) => { + // FIXME(scrabsha): lower view types to HIR. + return self.lower_ty(ty, itctx); + } TyKind::Dummy => panic!("`TyKind::Dummy` should never be lowered"), }; diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index d2e3c00bb0c07..aff6dc1b33032 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -285,6 +285,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ast::TyKind::Pat(..) => { gate!(self, pattern_types, ty.span, "pattern types are unstable"); } + ast::TyKind::View(..) => { + gate!(self, view_types, ty.span, "view types are unstable"); + } _ => {} } visit::walk_ty(self, ty) diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 8b2da2acaa520..106606877e110 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1259,6 +1259,20 @@ impl<'a> State<'a> { } } + fn print_view(&mut self, fields: &[Ident]) { + self.word(".{"); + + if !fields.is_empty() { + self.space(); + self.commasep(Consistent, fields, |s, field| { + s.print_ident(*field); + }); + self.space(); + } + + self.word("}"); + } + pub fn print_assoc_item_constraint(&mut self, constraint: &ast::AssocItemConstraint) { self.print_ident(constraint.ident); if let Some(args) = constraint.gen_args.as_ref() { @@ -1441,6 +1455,10 @@ impl<'a> State<'a> { self.end(ib); self.pclose(); } + ast::TyKind::View(ty, fields) => { + self.print_type(ty); + self.print_view(fields); + } } self.end(ib); } diff --git a/compiler/rustc_ast_pretty/src/pprust/tests.rs b/compiler/rustc_ast_pretty/src/pprust/tests.rs index 786de529c5b89..4ef42ae8e4c3b 100644 --- a/compiler/rustc_ast_pretty/src/pprust/tests.rs +++ b/compiler/rustc_ast_pretty/src/pprust/tests.rs @@ -1,6 +1,6 @@ use rustc_ast as ast; use rustc_span::{DUMMY_SP, Ident, create_default_session_globals_then}; -use thin_vec::ThinVec; +use thin_vec::{ThinVec, thin_vec}; use super::*; @@ -22,6 +22,12 @@ fn variant_to_string(var: &ast::Variant) -> String { to_string(|s| s.print_variant(var)) } +fn ty_to_string(ty: &ast::Ty) -> String { + to_string(|s| { + s.print_type(ty); + }) +} + #[test] fn test_fun_to_string() { create_default_session_globals_then(|| { @@ -60,3 +66,26 @@ fn test_variant_to_string() { assert_eq!(varstr, "principal_skinner"); }) } + +#[test] +fn test_field_view() { + create_default_session_globals_then(|| { + let ty = ast::Ty { + id: ast::DUMMY_NODE_ID, + kind: ast::TyKind::View( + Box::new(ast::Ty { + id: ast::DUMMY_NODE_ID, + kind: ast::TyKind::Dummy, + span: DUMMY_SP, + tokens: None, + }), + thin_vec![Ident::from_str("milhouse"), Ident::from_str("apu")], + ), + span: DUMMY_SP, + tokens: None, + }; + + let ty_str = ty_to_string(&ty); + assert_eq!(ty_str, "(/*DUMMY*/).{ milhouse, apu }"); + }); +} diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 4a5ff44c402ab..bd99b269ef5b6 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -47,6 +47,7 @@ mod pattern_type; mod source_util; mod test; mod trace_macros; +mod view_type; pub mod asm; pub mod cmdline_attrs; @@ -99,6 +100,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { stringify: source_util::expand_stringify, trace_macros: trace_macros::expand_trace_macros, unreachable: edition_panic::expand_unreachable, + view_type: view_type::expand, // tidy-alphabetical-end } diff --git a/compiler/rustc_builtin_macros/src/view_type.rs b/compiler/rustc_builtin_macros/src/view_type.rs new file mode 100644 index 0000000000000..090603f4f1253 --- /dev/null +++ b/compiler/rustc_builtin_macros/src/view_type.rs @@ -0,0 +1,47 @@ +use rustc_ast::token::TokenKind; +use rustc_ast::tokenstream::TokenStream; +use rustc_ast::{Ty, ast}; +use rustc_errors::PResult; +use rustc_expand::base::{self, DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult}; +use rustc_parse::parser::{ExpTokenPair, TokenType}; +use rustc_span::{Ident, Span}; +use thin_vec::ThinVec; + +pub(crate) fn expand<'cx>( + cx: &'cx mut ExtCtxt<'_>, + sp: Span, + tts: TokenStream, +) -> MacroExpanderResult<'cx> { + let (ty, pat) = match parse_view_ty(cx, tts) { + Ok(parsed) => parsed, + Err(err) => { + return ExpandResult::Ready(DummyResult::any(sp, err.emit())); + } + }; + + ExpandResult::Ready(base::MacEager::ty(cx.ty(sp, ast::TyKind::View(ty, pat)))) +} + +fn parse_view_ty<'a>( + cx: &mut ExtCtxt<'a>, + stream: TokenStream, +) -> PResult<'a, (Box, ThinVec)> { + let mut parser = cx.new_parser_from_tts(stream); + + let ty = parser.parse_ty()?; + + parser.expect(ExpTokenPair { tok: TokenKind::Dot, token_type: TokenType::Dot })?; + + let fields = match parser.parse_delim_comma_seq( + ExpTokenPair { tok: TokenKind::OpenBrace, token_type: TokenType::OpenBrace }, + ExpTokenPair { tok: TokenKind::CloseBrace, token_type: TokenType::CloseBrace }, + |p| p.parse_field_name(), + ) { + Ok((fields, _)) => fields, + Err(diag) => { + return Err(diag); + } + }; + + Ok((ty, fields)) +} diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 64255d51a7c69..04a9b1ff212a7 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1090,7 +1090,7 @@ impl<'a> Parser<'a> { /// Parses a comma-separated sequence, including both delimiters. /// The function `f` must consume tokens until reaching the next separator or /// closing bracket. - fn parse_delim_comma_seq( + pub fn parse_delim_comma_seq( &mut self, open: ExpTokenPair, close: ExpTokenPair, @@ -1355,7 +1355,7 @@ impl<'a> Parser<'a> { /// ```enbf /// FieldName = IntLit | Ident /// ``` - fn parse_field_name(&mut self) -> PResult<'a, Ident> { + pub fn parse_field_name(&mut self) -> PResult<'a, Ident> { if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) = self.token.kind { if let Some(suffix) = suffix { diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 8a881c6f8b568..e4996a4202d03 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -19,7 +19,7 @@ use crate::errors::{ NeedPlusAfterTraitObjectLifetime, NestedCVariadicType, ReturnTypesUseThinArrow, }; use crate::parser::item::FrontMatterParsingMode; -use crate::parser::{ExpTokenPair, FnContext, FnParseMode}; +use crate::parser::{FnContext, FnParseMode}; use crate::{exp, maybe_recover_from_interpolated_ty_qpath}; /// Signals whether parsing a type should allow `+`. @@ -768,25 +768,6 @@ impl<'a> Parser<'a> { self.bump_with((dyn_tok, dyn_tok_sp)); } let ty = self.parse_ty_no_plus()?; - if self.token == TokenKind::Dot && self.look_ahead(1, |t| t.kind == TokenKind::OpenBrace) { - // & [mut] . { } - // ^ - // we are here - let view_start_span = self.token.span; - self.bump(); - let fields = self - .parse_delim_comma_seq( - ExpTokenPair { tok: TokenKind::OpenBrace, token_type: TokenType::OpenBrace }, - ExpTokenPair { tok: TokenKind::CloseBrace, token_type: TokenType::CloseBrace }, - |p| p.parse_ident(), - )? - .0; - // FIXME(scrabsha): actually propagate field view in the AST. - let _ = fields; - let view_end_span = self.prev_token.span; - let span = view_start_span.to(view_end_span); - self.psess.gated_spans.gate(sym::view_types, span); - } Ok(match pinned { Pinnedness::Not => TyKind::Ref(opt_lifetime, MutTy { ty, mutbl }), Pinnedness::Pinned => TyKind::PinnedRef(opt_lifetime, MutTy { ty, mutbl }), diff --git a/compiler/rustc_passes/src/input_stats.rs b/compiler/rustc_passes/src/input_stats.rs index 2f3fbc28ad49d..d2bcf0359342c 100644 --- a/compiler/rustc_passes/src/input_stats.rs +++ b/compiler/rustc_passes/src/input_stats.rs @@ -690,6 +690,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { CVarArgs, Dummy, FieldOf, + View, Err ] ); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 827e33dcd6632..ad4c161d05576 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2306,6 +2306,7 @@ symbols! { vgpr384, vgpr512, vgpr1024, + view_type, view_types, vis, visible_private_types, diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index a26304c46ecea..216265c2915ff 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -350,6 +350,9 @@ mod bool; mod escape; mod tuple; mod unit; +#[cfg_attr(feature = "nightly", not(bootstrap))] +#[unstable(feature = "view_type_macro", issue = "155938")] +pub mod view; #[stable(feature = "core_primitive", since = "1.43.0")] pub mod primitive; diff --git a/library/core/src/view.rs b/library/core/src/view.rs new file mode 100644 index 0000000000000..68eca3f3598d2 --- /dev/null +++ b/library/core/src/view.rs @@ -0,0 +1,21 @@ +//! Helpers module for exporting the `view_types` macro. + +/// Creates a view type. +/// ``` +/// #![feature(view_types, view_type_macro)] +// +/// struct Foo { +/// bar: usize, +/// baz: u32, +/// } +/// +/// type FooBar = std::view::view_type!(Foo.{ bar }); +/// ``` +#[macro_export] +#[rustc_builtin_macro(view_type)] +#[unstable(feature = "view_type_macro", issue = "155938")] +macro_rules! view_type { + ($($arg:tt)*) => { + /* compiler built-in */ + }; +} diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index c9e884d89c85e..14852bfc000b9 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -639,6 +639,9 @@ pub mod process; pub mod random; pub mod sync; pub mod time; +#[cfg_attr(feature = "nightly", not(bootstrap))] +#[unstable(feature = "view_type_macro", issue = "155938")] +pub mod view; // Pull in `std_float` crate into std. The contents of // `std_float` are in a different repository: rust-lang/portable-simd. diff --git a/library/std/src/view.rs b/library/std/src/view.rs new file mode 100644 index 0000000000000..5806cf27c2cc8 --- /dev/null +++ b/library/std/src/view.rs @@ -0,0 +1,3 @@ +//! Helper module for exporting the `view_types` macro. + +pub use core::view_type; diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs index 7b642fcd4ff9a..7400891f75b58 100644 --- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs +++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs @@ -536,6 +536,7 @@ fn ast_ty_search_pat(ty: &ast::Ty) -> (Pat, Pat) { // experimental | TyKind::Pat(..) | TyKind::FieldOf(..) + | TyKind::View(..) // unused | TyKind::CVarArgs diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs index 2dfb5e5b28f61..cdba2ddc36e22 100644 --- a/src/tools/rustfmt/src/types.rs +++ b/src/tools/rustfmt/src/types.rs @@ -1054,6 +1054,14 @@ impl Rewrite for ast::Ty { result.push_str(&rewrite); Ok(result) } + + ast::TyKind::View(..) => { + // This doesn't normally occur in the AST because macros aren't expanded. However, + // rustfmt tries to parse macro arguments when formatting macros, so it's not + // totally impossible for rustfmt to come across this node when formatting a file. + // Also, rustfmt might get passed the output from `-Zunpretty=expanded`. + Err(RewriteError::Unknown) + } } } } diff --git a/tests/ui/README.md b/tests/ui/README.md index 6ffef1a1cd699..eb6a790b12b1f 100644 --- a/tests/ui/README.md +++ b/tests/ui/README.md @@ -1579,6 +1579,13 @@ Tests on `enum` variants. **FIXME**: Should be rehomed with `tests/ui/enum/`. +## `tests/ui/view-types` + +Anything related to view types. + +See +[Tracking Issue for view types](https://github.com/rust-lang/rust/issues/155938). + ## `tests/ui/wasm/` These tests target the `wasm32` architecture specifically. They are usually regression tests for WASM-specific bugs which were observed in the past. diff --git a/tests/ui/feature-gates/feature-gate-view-types.rs b/tests/ui/feature-gates/feature-gate-view-types.rs deleted file mode 100644 index eb0c26d61db4a..0000000000000 --- a/tests/ui/feature-gates/feature-gate-view-types.rs +++ /dev/null @@ -1,17 +0,0 @@ -struct Foo { - a: usize, - b: usize, -} - -fn bar(a: &mut Foo.{ a }, b: &mut Foo.{ b }) { - //~^ ERROR view types are experimental - //~| ERROR view types are experimental - a.a += 1; - b.b += 1; -} - -fn main() { - let mut foo = Foo { a: 0, b: 0 }; - bar(&mut foo, &mut foo); - //~^ ERROR cannot borrow `foo` as mutable more than once at a time -} diff --git a/tests/ui/feature-gates/feature-gate-view-types.stderr b/tests/ui/feature-gates/feature-gate-view-types.stderr deleted file mode 100644 index 661783ec59202..0000000000000 --- a/tests/ui/feature-gates/feature-gate-view-types.stderr +++ /dev/null @@ -1,33 +0,0 @@ -error[E0658]: view types are experimental - --> $DIR/feature-gate-view-types.rs:6:19 - | -LL | fn bar(a: &mut Foo.{ a }, b: &mut Foo.{ b }) { - | ^^^^^^ - | - = note: see issue #155938 for more information - = help: add `#![feature(view_types)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: view types are experimental - --> $DIR/feature-gate-view-types.rs:6:38 - | -LL | fn bar(a: &mut Foo.{ a }, b: &mut Foo.{ b }) { - | ^^^^^^ - | - = note: see issue #155938 for more information - = help: add `#![feature(view_types)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0499]: cannot borrow `foo` as mutable more than once at a time - --> $DIR/feature-gate-view-types.rs:15:19 - | -LL | bar(&mut foo, &mut foo); - | --- -------- ^^^^^^^^ second mutable borrow occurs here - | | | - | | first mutable borrow occurs here - | first borrow later used by call - -error: aborting due to 3 previous errors - -Some errors have detailed explanations: E0499, E0658. -For more information about an error, try `rustc --explain E0499`. diff --git a/tests/ui/view-types/feature-gate-view-types.rs b/tests/ui/view-types/feature-gate-view-types.rs new file mode 100644 index 0000000000000..961f96e18bb99 --- /dev/null +++ b/tests/ui/view-types/feature-gate-view-types.rs @@ -0,0 +1,13 @@ +//@ compile-flags: -Zno-analysis + +use std::view::view_type; + +struct Foo { + bar: (), + baz: (), +} + +type FooBar = view_type!(Foo.{ bar }); +//~^ ERROR use of unstable library feature `view_type_macro` +type FooBaz = view_type!(Foo.{ baz }); +//~^ ERROR use of unstable library feature `view_type_macro` diff --git a/tests/ui/view-types/feature-gate-view-types.stderr b/tests/ui/view-types/feature-gate-view-types.stderr new file mode 100644 index 0000000000000..407bf343ca13b --- /dev/null +++ b/tests/ui/view-types/feature-gate-view-types.stderr @@ -0,0 +1,23 @@ +error[E0658]: use of unstable library feature `view_type_macro` + --> $DIR/feature-gate-view-types.rs:10:15 + | +LL | type FooBar = view_type!(Foo.{ bar }); + | ^^^^^^^^^ + | + = note: see issue #155938 for more information + = help: add `#![feature(view_type_macro)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: use of unstable library feature `view_type_macro` + --> $DIR/feature-gate-view-types.rs:12:15 + | +LL | type FooBaz = view_type!(Foo.{ baz }); + | ^^^^^^^^^ + | + = note: see issue #155938 for more information + = help: add `#![feature(view_type_macro)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/view-types/must-be-struct.rs b/tests/ui/view-types/must-be-struct.rs new file mode 100644 index 0000000000000..43dbae587e4ab --- /dev/null +++ b/tests/ui/view-types/must-be-struct.rs @@ -0,0 +1,19 @@ +//@ known-bug: unknown +//@ run-pass + +#![feature(view_types, view_type_macro)] +#![allow(unused)] + +use std::view::view_type; + +enum Foo { + Bar, + Baz, +} + +// The following types are not structs, we expect errors here. +fn f(_: view_type!(Foo.{})) {} +fn g(_: view_type!(u8.{})) {} +fn h(_: view_type!(char.{})) {} + +fn main() {} diff --git a/tests/ui/view-types/must-exist.rs b/tests/ui/view-types/must-exist.rs new file mode 100644 index 0000000000000..05792b01b3265 --- /dev/null +++ b/tests/ui/view-types/must-exist.rs @@ -0,0 +1,17 @@ +//@ known-bug: unknown +//@ run-pass + +#![feature(view_types, view_type_macro)] +#![allow(unused)] + +use std::view::view_type; + +struct S { + foo: (), +} + +// We expect errors here, since `S` has no field `bar`. +fn f(_: view_type!(S.{ bar })) {} +fn g(_: view_type!(S.{ foo, bar })) {} + +fn main() {} diff --git a/tests/ui/view-types/must-restrict.rs b/tests/ui/view-types/must-restrict.rs new file mode 100644 index 0000000000000..c0e1f5115d27c --- /dev/null +++ b/tests/ui/view-types/must-restrict.rs @@ -0,0 +1,19 @@ +//@ known-bug: unknown +//@ run-pass + +#![feature(view_types, view_type_macro)] +#![allow(unused)] + +use std::view::view_type; + +struct S { + foo: (), + bar: (), +} + +// The outermost fields are supersets of the innermost views, we expect this to trigger an error. +fn f(_: view_type!(view_type!(S.{}).{ foo })) {} +fn g(_: view_type!(view_type!(S.{ foo }).{ bar })) {} +fn h(_: view_type!(view_type!(view_type!(S.{ foo }).{}).{ foo })) {} + +fn main() {} diff --git a/tests/ui/view-types/regression-156016.rs b/tests/ui/view-types/regression-156016.rs new file mode 100644 index 0000000000000..a39a94a8752f0 --- /dev/null +++ b/tests/ui/view-types/regression-156016.rs @@ -0,0 +1,14 @@ +//@ run-pass + +// Regression reported in https://github.com/rust-lang/rust/pull/156016#discussion_r3453131612 + +macro_rules! m { + ($ty:ty) => { + compile_error!("ty fragment matched a view type"); + }; + (&().{}) => {}; +} + +m!(&().{}); + +fn main() {} diff --git a/tests/ui/view-types/syntax-errors.rs b/tests/ui/view-types/syntax-errors.rs new file mode 100644 index 0000000000000..19f5061cf820a --- /dev/null +++ b/tests/ui/view-types/syntax-errors.rs @@ -0,0 +1,25 @@ +#![feature(view_types, view_type_macro)] +#![allow(unused)] + +use std::view::view_type; + +struct Foo { + bar: usize, + baz: usize, +} + +impl Foo { + fn not_a_field(self: &mut view_type!(Foo.{ _ }), _: &mut view_type!(Foo.{ _ })) {} + //~^ ERROR expected identifier + //~| ERROR expected identifier + + fn keyword(self: &mut view_type!(Foo.{ where }), _: &mut view_type!(Foo.{ for })) {} + //~^ ERROR expected identifier + //~| ERROR expected identifier + + fn no_comma(self: &mut view_type!(Foo.{ bar baz }), _: &mut view_type!(Foo.{ bar baz })) {} + //~^ ERROR expected one of + //~| ERROR expected one of +} + +fn main() {} diff --git a/tests/ui/view-types/syntax-errors.stderr b/tests/ui/view-types/syntax-errors.stderr new file mode 100644 index 0000000000000..86c167ca9a879 --- /dev/null +++ b/tests/ui/view-types/syntax-errors.stderr @@ -0,0 +1,52 @@ +error: expected identifier, found reserved identifier `_` + --> $DIR/syntax-errors.rs:12:48 + | +LL | fn not_a_field(self: &mut view_type!(Foo.{ _ }), _: &mut view_type!(Foo.{ _ })) {} + | ^ expected identifier, found reserved identifier + +error: expected identifier, found reserved identifier `_` + --> $DIR/syntax-errors.rs:12:79 + | +LL | fn not_a_field(self: &mut view_type!(Foo.{ _ }), _: &mut view_type!(Foo.{ _ })) {} + | ^ expected identifier, found reserved identifier + +error: expected identifier, found keyword `where` + --> $DIR/syntax-errors.rs:16:44 + | +LL | fn keyword(self: &mut view_type!(Foo.{ where }), _: &mut view_type!(Foo.{ for })) {} + | ^^^^^ expected identifier, found keyword + | +help: escape `where` to use it as an identifier + | +LL | fn keyword(self: &mut view_type!(Foo.{ r#where }), _: &mut view_type!(Foo.{ for })) {} + | ++ + +error: expected identifier, found keyword `for` + --> $DIR/syntax-errors.rs:16:79 + | +LL | fn keyword(self: &mut view_type!(Foo.{ where }), _: &mut view_type!(Foo.{ for })) {} + | ^^^ expected identifier, found keyword + | +help: escape `for` to use it as an identifier + | +LL | fn keyword(self: &mut view_type!(Foo.{ where }), _: &mut view_type!(Foo.{ r#for })) {} + | ++ + +error: expected one of `,` or `}`, found `baz` + --> $DIR/syntax-errors.rs:20:49 + | +LL | fn no_comma(self: &mut view_type!(Foo.{ bar baz }), _: &mut view_type!(Foo.{ bar baz })) {} + | -^^^ expected one of `,` or `}` + | | + | help: missing `,` + +error: expected one of `,` or `}`, found `baz` + --> $DIR/syntax-errors.rs:20:86 + | +LL | fn no_comma(self: &mut view_type!(Foo.{ bar baz }), _: &mut view_type!(Foo.{ bar baz })) {} + | -^^^ expected one of `,` or `}` + | | + | help: missing `,` + +error: aborting due to 6 previous errors + diff --git a/tests/ui/view-types/tuple-structs.rs b/tests/ui/view-types/tuple-structs.rs new file mode 100644 index 0000000000000..f0442d4e308fb --- /dev/null +++ b/tests/ui/view-types/tuple-structs.rs @@ -0,0 +1,15 @@ +//@ run-pass + +#![feature(view_types, view_type_macro)] +#![allow(unused)] + +use std::view::view_type; + +struct Pair(usize, u32); + +impl Pair { + fn foo(self: &mut view_type!(Pair.{ 0, 1 })) {} + fn bar(_pair: &mut view_type!(Pair.{ 0, 1 })) {} +} + +fn main() {}