authorbors <bors@rust-lang.org> 2026-07-07 12:35:23 UTC
committerbors <bors@rust-lang.org> 2026-07-07 12:35:23 UTC
log75770e7d2fd223f28701cc70c5a89399299ce679
treec218272c64d89c8d249d077a2bdba8c93f3bf101
parentf10db292a3733b5c67c8da8c7661195ff4b05774
parent3ed5f56b7d381af42cd7a460a777cd5ea500af85

Auto merge of #156016 - scrabsha:view-types/in-ast, r=oli-obk

view-types: store view types in the AST

30 files changed, 356 insertions(+), 79 deletions(-)

compiler/rustc_ast/src/ast.rs+2
......@@ -2564,6 +2564,8 @@ pub enum TyKind {
25642564 /// Usually not written directly in user code but indirectly via the macro
25652565 /// `core::field::field_of!(...)`.
25662566 FieldOf(Box<Ty>, Option<Ident>, Ident),
2567 /// A view of a type. `T.{ field_1, field_2 }`.
2568 View(Box<Ty>, #[visitable(ignore)] ThinVec<Ident>),
25672569 /// Sometimes we need a dummy value when no error has occurred.
25682570 Dummy,
25692571 /// Placeholder for a kind that has failed to be defined.
compiler/rustc_ast/src/util/classify.rs+2-1
......@@ -302,7 +302,8 @@ fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> {
302302 | ast::TyKind::Pat(..)
303303 | ast::TyKind::FieldOf(..)
304304 | ast::TyKind::Dummy
305 | ast::TyKind::Err(..) => break None,
305 | ast::TyKind::Err(..)
306 | ast::TyKind::View(..) => break None,
306307 }
307308 }
308309}
compiler/rustc_ast_lowering/src/lib.rs+4
......@@ -1711,6 +1711,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
17111711 );
17121712 hir::TyKind::Err(guar)
17131713 }
1714 TyKind::View(ty, _) => {
1715 // FIXME(scrabsha): lower view types to HIR.
1716 return self.lower_ty(ty, itctx);
1717 }
17141718 TyKind::Dummy => panic!("`TyKind::Dummy` should never be lowered"),
17151719 };
17161720
compiler/rustc_ast_passes/src/feature_gate.rs+3
......@@ -285,6 +285,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
285285 ast::TyKind::Pat(..) => {
286286 gate!(self, pattern_types, ty.span, "pattern types are unstable");
287287 }
288 ast::TyKind::View(..) => {
289 gate!(self, view_types, ty.span, "view types are unstable");
290 }
288291 _ => {}
289292 }
290293 visit::walk_ty(self, ty)
compiler/rustc_ast_pretty/src/pprust/state.rs+18
......@@ -1259,6 +1259,20 @@ impl<'a> State<'a> {
12591259 }
12601260 }
12611261
1262 fn print_view(&mut self, fields: &[Ident]) {
1263 self.word(".{");
1264
1265 if !fields.is_empty() {
1266 self.space();
1267 self.commasep(Consistent, fields, |s, field| {
1268 s.print_ident(*field);
1269 });
1270 self.space();
1271 }
1272
1273 self.word("}");
1274 }
1275
12621276 pub fn print_assoc_item_constraint(&mut self, constraint: &ast::AssocItemConstraint) {
12631277 self.print_ident(constraint.ident);
12641278 if let Some(args) = constraint.gen_args.as_ref() {
......@@ -1441,6 +1455,10 @@ impl<'a> State<'a> {
14411455 self.end(ib);
14421456 self.pclose();
14431457 }
1458 ast::TyKind::View(ty, fields) => {
1459 self.print_type(ty);
1460 self.print_view(fields);
1461 }
14441462 }
14451463 self.end(ib);
14461464 }
compiler/rustc_ast_pretty/src/pprust/tests.rs+30-1
......@@ -1,6 +1,6 @@
11use rustc_ast as ast;
22use rustc_span::{DUMMY_SP, Ident, create_default_session_globals_then};
3use thin_vec::ThinVec;
3use thin_vec::{ThinVec, thin_vec};
44
55use super::*;
66
......@@ -22,6 +22,12 @@ fn variant_to_string(var: &ast::Variant) -> String {
2222 to_string(|s| s.print_variant(var))
2323}
2424
25fn ty_to_string(ty: &ast::Ty) -> String {
26 to_string(|s| {
27 s.print_type(ty);
28 })
29}
30
2531#[test]
2632fn test_fun_to_string() {
2733 create_default_session_globals_then(|| {
......@@ -60,3 +66,26 @@ fn test_variant_to_string() {
6066 assert_eq!(varstr, "principal_skinner");
6167 })
6268}
69
70#[test]
71fn test_field_view() {
72 create_default_session_globals_then(|| {
73 let ty = ast::Ty {
74 id: ast::DUMMY_NODE_ID,
75 kind: ast::TyKind::View(
76 Box::new(ast::Ty {
77 id: ast::DUMMY_NODE_ID,
78 kind: ast::TyKind::Dummy,
79 span: DUMMY_SP,
80 tokens: None,
81 }),
82 thin_vec![Ident::from_str("milhouse"), Ident::from_str("apu")],
83 ),
84 span: DUMMY_SP,
85 tokens: None,
86 };
87
88 let ty_str = ty_to_string(&ty);
89 assert_eq!(ty_str, "(/*DUMMY*/).{ milhouse, apu }");
90 });
91}
compiler/rustc_builtin_macros/src/lib.rs+2
......@@ -47,6 +47,7 @@ mod pattern_type;
4747mod source_util;
4848mod test;
4949mod trace_macros;
50mod view_type;
5051
5152pub mod asm;
5253pub mod cmdline_attrs;
......@@ -99,6 +100,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
99100 stringify: source_util::expand_stringify,
100101 trace_macros: trace_macros::expand_trace_macros,
101102 unreachable: edition_panic::expand_unreachable,
103 view_type: view_type::expand,
102104 // tidy-alphabetical-end
103105 }
104106
compiler/rustc_builtin_macros/src/view_type.rs created+47
......@@ -0,0 +1,47 @@
1use rustc_ast::token::TokenKind;
2use rustc_ast::tokenstream::TokenStream;
3use rustc_ast::{Ty, ast};
4use rustc_errors::PResult;
5use rustc_expand::base::{self, DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
6use rustc_parse::parser::{ExpTokenPair, TokenType};
7use rustc_span::{Ident, Span};
8use thin_vec::ThinVec;
9
10pub(crate) fn expand<'cx>(
11 cx: &'cx mut ExtCtxt<'_>,
12 sp: Span,
13 tts: TokenStream,
14) -> MacroExpanderResult<'cx> {
15 let (ty, pat) = match parse_view_ty(cx, tts) {
16 Ok(parsed) => parsed,
17 Err(err) => {
18 return ExpandResult::Ready(DummyResult::any(sp, err.emit()));
19 }
20 };
21
22 ExpandResult::Ready(base::MacEager::ty(cx.ty(sp, ast::TyKind::View(ty, pat))))
23}
24
25fn parse_view_ty<'a>(
26 cx: &mut ExtCtxt<'a>,
27 stream: TokenStream,
28) -> PResult<'a, (Box<Ty>, ThinVec<Ident>)> {
29 let mut parser = cx.new_parser_from_tts(stream);
30
31 let ty = parser.parse_ty()?;
32
33 parser.expect(ExpTokenPair { tok: TokenKind::Dot, token_type: TokenType::Dot })?;
34
35 let fields = match parser.parse_delim_comma_seq(
36 ExpTokenPair { tok: TokenKind::OpenBrace, token_type: TokenType::OpenBrace },
37 ExpTokenPair { tok: TokenKind::CloseBrace, token_type: TokenType::CloseBrace },
38 |p| p.parse_field_name(),
39 ) {
40 Ok((fields, _)) => fields,
41 Err(diag) => {
42 return Err(diag);
43 }
44 };
45
46 Ok((ty, fields))
47}
compiler/rustc_parse/src/parser/mod.rs+2-2
......@@ -1090,7 +1090,7 @@ impl<'a> Parser<'a> {
10901090 /// Parses a comma-separated sequence, including both delimiters.
10911091 /// The function `f` must consume tokens until reaching the next separator or
10921092 /// closing bracket.
1093 fn parse_delim_comma_seq<T>(
1093 pub fn parse_delim_comma_seq<T>(
10941094 &mut self,
10951095 open: ExpTokenPair,
10961096 close: ExpTokenPair,
......@@ -1355,7 +1355,7 @@ impl<'a> Parser<'a> {
13551355 /// ```enbf
13561356 /// FieldName = IntLit | Ident
13571357 /// ```
1358 fn parse_field_name(&mut self) -> PResult<'a, Ident> {
1358 pub fn parse_field_name(&mut self) -> PResult<'a, Ident> {
13591359 if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) = self.token.kind
13601360 {
13611361 if let Some(suffix) = suffix {
compiler/rustc_parse/src/parser/ty.rs+1-20
......@@ -19,7 +19,7 @@ use crate::errors::{
1919 NeedPlusAfterTraitObjectLifetime, NestedCVariadicType, ReturnTypesUseThinArrow,
2020};
2121use crate::parser::item::FrontMatterParsingMode;
22use crate::parser::{ExpTokenPair, FnContext, FnParseMode};
22use crate::parser::{FnContext, FnParseMode};
2323use crate::{exp, maybe_recover_from_interpolated_ty_qpath};
2424
2525/// Signals whether parsing a type should allow `+`.
......@@ -768,25 +768,6 @@ impl<'a> Parser<'a> {
768768 self.bump_with((dyn_tok, dyn_tok_sp));
769769 }
770770 let ty = self.parse_ty_no_plus()?;
771 if self.token == TokenKind::Dot && self.look_ahead(1, |t| t.kind == TokenKind::OpenBrace) {
772 // & [mut] <type> . { <fields> }
773 // ^
774 // we are here
775 let view_start_span = self.token.span;
776 self.bump();
777 let fields = self
778 .parse_delim_comma_seq(
779 ExpTokenPair { tok: TokenKind::OpenBrace, token_type: TokenType::OpenBrace },
780 ExpTokenPair { tok: TokenKind::CloseBrace, token_type: TokenType::CloseBrace },
781 |p| p.parse_ident(),
782 )?
783 .0;
784 // FIXME(scrabsha): actually propagate field view in the AST.
785 let _ = fields;
786 let view_end_span = self.prev_token.span;
787 let span = view_start_span.to(view_end_span);
788 self.psess.gated_spans.gate(sym::view_types, span);
789 }
790771 Ok(match pinned {
791772 Pinnedness::Not => TyKind::Ref(opt_lifetime, MutTy { ty, mutbl }),
792773 Pinnedness::Pinned => TyKind::PinnedRef(opt_lifetime, MutTy { ty, mutbl }),
compiler/rustc_passes/src/input_stats.rs+1
......@@ -690,6 +690,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
690690 CVarArgs,
691691 Dummy,
692692 FieldOf,
693 View,
693694 Err
694695 ]
695696 );
compiler/rustc_span/src/symbol.rs+1
......@@ -2320,6 +2320,7 @@ symbols! {
23202320 vgpr384,
23212321 vgpr512,
23222322 vgpr1024,
2323 view_type,
23232324 view_types,
23242325 vis,
23252326 visible_private_types,
library/core/src/lib.rs+3
......@@ -339,6 +339,9 @@ mod bool;
339339mod escape;
340340mod tuple;
341341mod unit;
342#[cfg_attr(feature = "nightly", not(bootstrap))]
343#[unstable(feature = "view_type_macro", issue = "155938")]
344pub mod view;
342345
343346#[stable(feature = "core_primitive", since = "1.43.0")]
344347pub mod primitive;
library/core/src/view.rs created+21
......@@ -0,0 +1,21 @@
1//! Helpers module for exporting the `view_types` macro.
2
3/// Creates a view type.
4/// ```
5/// #![feature(view_types, view_type_macro)]
6//
7/// struct Foo {
8/// bar: usize,
9/// baz: u32,
10/// }
11///
12/// type FooBar = std::view::view_type!(Foo.{ bar });
13/// ```
14#[macro_export]
15#[rustc_builtin_macro(view_type)]
16#[unstable(feature = "view_type_macro", issue = "155938")]
17macro_rules! view_type {
18 ($($arg:tt)*) => {
19 /* compiler built-in */
20 };
21}
library/std/src/lib.rs+3
......@@ -643,6 +643,9 @@ pub mod process;
643643pub mod random;
644644pub mod sync;
645645pub mod time;
646#[cfg_attr(feature = "nightly", not(bootstrap))]
647#[unstable(feature = "view_type_macro", issue = "155938")]
648pub mod view;
646649
647650// Pull in `std_float` crate into std. The contents of
648651// `std_float` are in a different repository: rust-lang/portable-simd.
library/std/src/view.rs created+3
......@@ -0,0 +1,3 @@
1//! Helper module for exporting the `view_types` macro.
2
3pub use core::view_type;
src/tools/clippy/clippy_utils/src/check_proc_macro.rs+1
......@@ -536,6 +536,7 @@ fn ast_ty_search_pat(ty: &ast::Ty) -> (Pat, Pat) {
536536 // experimental
537537 | TyKind::Pat(..)
538538 | TyKind::FieldOf(..)
539 | TyKind::View(..)
539540
540541 // unused
541542 | TyKind::CVarArgs
src/tools/rustfmt/src/types.rs+8-5
......@@ -1015,11 +1015,6 @@ impl Rewrite for ast::Ty {
10151015 }
10161016 ast::TyKind::CVarArgs => Ok("...".to_owned()),
10171017 ast::TyKind::Dummy | ast::TyKind::Err(_) => Ok(context.snippet(self.span).to_owned()),
1018 ast::TyKind::Pat(ref ty, ref pat) => {
1019 let ty = ty.rewrite_result(context, shape)?;
1020 let pat = pat.rewrite_result(context, shape)?;
1021 Ok(format!("{ty} is {pat}"))
1022 }
10231018 ast::TyKind::FieldOf(ref ty, ref variant, ref field) => {
10241019 let ty = ty.rewrite_result(context, shape)?;
10251020 if let Some(variant) = variant {
......@@ -1054,6 +1049,14 @@ impl Rewrite for ast::Ty {
10541049 result.push_str(&rewrite);
10551050 Ok(result)
10561051 }
1052
1053 ast::TyKind::Pat(..) | ast::TyKind::View(..) => {
1054 // These don't normally occur in the AST because macros aren't expanded. However,
1055 // rustfmt tries to parse macro arguments when formatting macros, so it's not
1056 // totally impossible for rustfmt to come across these nodes when formatting a file.
1057 // Also, rustfmt might get passed the output from `-Zunpretty=expanded`.
1058 Err(RewriteError::Unknown)
1059 }
10571060 }
10581061 }
10591062}
tests/ui/README.md+7
......@@ -1583,6 +1583,13 @@ Tests on `enum` variants.
15831583
15841584**FIXME**: Should be rehomed with `tests/ui/enum/`.
15851585
1586## `tests/ui/view-types`
1587
1588Anything related to view types.
1589
1590See
1591[Tracking Issue for view types](https://github.com/rust-lang/rust/issues/155938).
1592
15861593## `tests/ui/wasm/`
15871594
15881595These tests target the `wasm32` architecture specifically. They are usually regression tests for WASM-specific bugs which were observed in the past.
tests/ui/feature-gates/feature-gate-view-types.rs deleted-17
......@@ -1,17 +0,0 @@
1struct Foo {
2 a: usize,
3 b: usize,
4}
5
6fn bar(a: &mut Foo.{ a }, b: &mut Foo.{ b }) {
7 //~^ ERROR view types are experimental
8 //~| ERROR view types are experimental
9 a.a += 1;
10 b.b += 1;
11}
12
13fn main() {
14 let mut foo = Foo { a: 0, b: 0 };
15 bar(&mut foo, &mut foo);
16 //~^ ERROR cannot borrow `foo` as mutable more than once at a time
17}
tests/ui/feature-gates/feature-gate-view-types.stderr deleted-33
......@@ -1,33 +0,0 @@
1error[E0658]: view types are experimental
2 --> $DIR/feature-gate-view-types.rs:6:19
3 |
4LL | fn bar(a: &mut Foo.{ a }, b: &mut Foo.{ b }) {
5 | ^^^^^^
6 |
7 = note: see issue #155938 <https://github.com/rust-lang/rust/issues/155938> for more information
8 = help: add `#![feature(view_types)]` to the crate attributes to enable
9 = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
10
11error[E0658]: view types are experimental
12 --> $DIR/feature-gate-view-types.rs:6:38
13 |
14LL | fn bar(a: &mut Foo.{ a }, b: &mut Foo.{ b }) {
15 | ^^^^^^
16 |
17 = note: see issue #155938 <https://github.com/rust-lang/rust/issues/155938> for more information
18 = help: add `#![feature(view_types)]` to the crate attributes to enable
19 = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
20
21error[E0499]: cannot borrow `foo` as mutable more than once at a time
22 --> $DIR/feature-gate-view-types.rs:15:19
23 |
24LL | bar(&mut foo, &mut foo);
25 | --- -------- ^^^^^^^^ second mutable borrow occurs here
26 | | |
27 | | first mutable borrow occurs here
28 | first borrow later used by call
29
30error: aborting due to 3 previous errors
31
32Some errors have detailed explanations: E0499, E0658.
33For more information about an error, try `rustc --explain E0499`.
tests/ui/view-types/feature-gate-view-types.rs created+13
......@@ -0,0 +1,13 @@
1//@ compile-flags: -Zno-analysis
2
3use std::view::view_type;
4
5struct Foo {
6 bar: (),
7 baz: (),
8}
9
10type FooBar = view_type!(Foo.{ bar });
11//~^ ERROR use of unstable library feature `view_type_macro`
12type FooBaz = view_type!(Foo.{ baz });
13//~^ ERROR use of unstable library feature `view_type_macro`
tests/ui/view-types/feature-gate-view-types.stderr created+23
......@@ -0,0 +1,23 @@
1error[E0658]: use of unstable library feature `view_type_macro`
2 --> $DIR/feature-gate-view-types.rs:10:15
3 |
4LL | type FooBar = view_type!(Foo.{ bar });
5 | ^^^^^^^^^
6 |
7 = note: see issue #155938 <https://github.com/rust-lang/rust/issues/155938> for more information
8 = help: add `#![feature(view_type_macro)]` to the crate attributes to enable
9 = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
10
11error[E0658]: use of unstable library feature `view_type_macro`
12 --> $DIR/feature-gate-view-types.rs:12:15
13 |
14LL | type FooBaz = view_type!(Foo.{ baz });
15 | ^^^^^^^^^
16 |
17 = note: see issue #155938 <https://github.com/rust-lang/rust/issues/155938> for more information
18 = help: add `#![feature(view_type_macro)]` to the crate attributes to enable
19 = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
20
21error: aborting due to 2 previous errors
22
23For more information about this error, try `rustc --explain E0658`.
tests/ui/view-types/must-be-struct.rs created+19
......@@ -0,0 +1,19 @@
1//@ known-bug: unknown
2//@ run-pass
3
4#![feature(view_types, view_type_macro)]
5#![allow(unused)]
6
7use std::view::view_type;
8
9enum Foo {
10 Bar,
11 Baz,
12}
13
14// The following types are not structs, we expect errors here.
15fn f(_: view_type!(Foo.{})) {}
16fn g(_: view_type!(u8.{})) {}
17fn h(_: view_type!(char.{})) {}
18
19fn main() {}
tests/ui/view-types/must-exist.rs created+17
......@@ -0,0 +1,17 @@
1//@ known-bug: unknown
2//@ run-pass
3
4#![feature(view_types, view_type_macro)]
5#![allow(unused)]
6
7use std::view::view_type;
8
9struct S {
10 foo: (),
11}
12
13// We expect errors here, since `S` has no field `bar`.
14fn f(_: view_type!(S.{ bar })) {}
15fn g(_: view_type!(S.{ foo, bar })) {}
16
17fn main() {}
tests/ui/view-types/must-restrict.rs created+19
......@@ -0,0 +1,19 @@
1//@ known-bug: unknown
2//@ run-pass
3
4#![feature(view_types, view_type_macro)]
5#![allow(unused)]
6
7use std::view::view_type;
8
9struct S {
10 foo: (),
11 bar: (),
12}
13
14// The outermost fields are supersets of the innermost views, we expect this to trigger an error.
15fn f(_: view_type!(view_type!(S.{}).{ foo })) {}
16fn g(_: view_type!(view_type!(S.{ foo }).{ bar })) {}
17fn h(_: view_type!(view_type!(view_type!(S.{ foo }).{}).{ foo })) {}
18
19fn main() {}
tests/ui/view-types/regression-156016.rs created+14
......@@ -0,0 +1,14 @@
1//@ run-pass
2
3// Regression reported in https://github.com/rust-lang/rust/pull/156016#discussion_r3453131612
4
5macro_rules! m {
6 ($ty:ty) => {
7 compile_error!("ty fragment matched a view type");
8 };
9 (&().{}) => {};
10}
11
12m!(&().{});
13
14fn main() {}
tests/ui/view-types/syntax-errors.rs created+25
......@@ -0,0 +1,25 @@
1#![feature(view_types, view_type_macro)]
2#![allow(unused)]
3
4use std::view::view_type;
5
6struct Foo {
7 bar: usize,
8 baz: usize,
9}
10
11impl Foo {
12 fn not_a_field(self: &mut view_type!(Foo.{ _ }), _: &mut view_type!(Foo.{ _ })) {}
13 //~^ ERROR expected identifier
14 //~| ERROR expected identifier
15
16 fn keyword(self: &mut view_type!(Foo.{ where }), _: &mut view_type!(Foo.{ for })) {}
17 //~^ ERROR expected identifier
18 //~| ERROR expected identifier
19
20 fn no_comma(self: &mut view_type!(Foo.{ bar baz }), _: &mut view_type!(Foo.{ bar baz })) {}
21 //~^ ERROR expected one of
22 //~| ERROR expected one of
23}
24
25fn main() {}
tests/ui/view-types/syntax-errors.stderr created+52
......@@ -0,0 +1,52 @@
1error: expected identifier, found reserved identifier `_`
2 --> $DIR/syntax-errors.rs:12:48
3 |
4LL | fn not_a_field(self: &mut view_type!(Foo.{ _ }), _: &mut view_type!(Foo.{ _ })) {}
5 | ^ expected identifier, found reserved identifier
6
7error: expected identifier, found reserved identifier `_`
8 --> $DIR/syntax-errors.rs:12:79
9 |
10LL | fn not_a_field(self: &mut view_type!(Foo.{ _ }), _: &mut view_type!(Foo.{ _ })) {}
11 | ^ expected identifier, found reserved identifier
12
13error: expected identifier, found keyword `where`
14 --> $DIR/syntax-errors.rs:16:44
15 |
16LL | fn keyword(self: &mut view_type!(Foo.{ where }), _: &mut view_type!(Foo.{ for })) {}
17 | ^^^^^ expected identifier, found keyword
18 |
19help: escape `where` to use it as an identifier
20 |
21LL | fn keyword(self: &mut view_type!(Foo.{ r#where }), _: &mut view_type!(Foo.{ for })) {}
22 | ++
23
24error: expected identifier, found keyword `for`
25 --> $DIR/syntax-errors.rs:16:79
26 |
27LL | fn keyword(self: &mut view_type!(Foo.{ where }), _: &mut view_type!(Foo.{ for })) {}
28 | ^^^ expected identifier, found keyword
29 |
30help: escape `for` to use it as an identifier
31 |
32LL | fn keyword(self: &mut view_type!(Foo.{ where }), _: &mut view_type!(Foo.{ r#for })) {}
33 | ++
34
35error: expected one of `,` or `}`, found `baz`
36 --> $DIR/syntax-errors.rs:20:49
37 |
38LL | fn no_comma(self: &mut view_type!(Foo.{ bar baz }), _: &mut view_type!(Foo.{ bar baz })) {}
39 | -^^^ expected one of `,` or `}`
40 | |
41 | help: missing `,`
42
43error: expected one of `,` or `}`, found `baz`
44 --> $DIR/syntax-errors.rs:20:86
45 |
46LL | fn no_comma(self: &mut view_type!(Foo.{ bar baz }), _: &mut view_type!(Foo.{ bar baz })) {}
47 | -^^^ expected one of `,` or `}`
48 | |
49 | help: missing `,`
50
51error: aborting due to 6 previous errors
52
tests/ui/view-types/tuple-structs.rs created+15
......@@ -0,0 +1,15 @@
1//@ run-pass
2
3#![feature(view_types, view_type_macro)]
4#![allow(unused)]
5
6use std::view::view_type;
7
8struct Pair(usize, u32);
9
10impl Pair {
11 fn foo(self: &mut view_type!(Pair.{ 0, 1 })) {}
12 fn bar(_pair: &mut view_type!(Pair.{ 0, 1 })) {}
13}
14
15fn main() {}