| author | bors <bors@rust-lang.org> 2026-07-07 12:35:22 UTC |
| committer | GitHub <noreply@github.com> 2026-07-07 12:35:22 UTC |
| log | b9159a13a80b18a4dfd56794fa469e75020671b6 |
| tree | c218272c64d89c8d249d077a2bdba8c93f3bf101 |
| parent | f10db292a3733b5c67c8da8c7661195ff4b05774 |
| parent | 3ed5f56b7d381af42cd7a460a777cd5ea500af85 |
30 files changed, 356 insertions(+), 79 deletions(-)
compiler/rustc_ast/src/ast.rs+2| ... | ... | @@ -2564,6 +2564,8 @@ pub enum TyKind { |
| 2564 | 2564 | /// Usually not written directly in user code but indirectly via the macro |
| 2565 | 2565 | /// `core::field::field_of!(...)`. |
| 2566 | 2566 | 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>), | |
| 2567 | 2569 | /// Sometimes we need a dummy value when no error has occurred. |
| 2568 | 2570 | Dummy, |
| 2569 | 2571 | /// 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> { |
| 302 | 302 | | ast::TyKind::Pat(..) |
| 303 | 303 | | ast::TyKind::FieldOf(..) |
| 304 | 304 | | ast::TyKind::Dummy |
| 305 | | ast::TyKind::Err(..) => break None, | |
| 305 | | ast::TyKind::Err(..) | |
| 306 | | ast::TyKind::View(..) => break None, | |
| 306 | 307 | } |
| 307 | 308 | } |
| 308 | 309 | } |
compiler/rustc_ast_lowering/src/lib.rs+4| ... | ... | @@ -1711,6 +1711,10 @@ impl<'hir> LoweringContext<'_, 'hir> { |
| 1711 | 1711 | ); |
| 1712 | 1712 | hir::TyKind::Err(guar) |
| 1713 | 1713 | } |
| 1714 | TyKind::View(ty, _) => { | |
| 1715 | // FIXME(scrabsha): lower view types to HIR. | |
| 1716 | return self.lower_ty(ty, itctx); | |
| 1717 | } | |
| 1714 | 1718 | TyKind::Dummy => panic!("`TyKind::Dummy` should never be lowered"), |
| 1715 | 1719 | }; |
| 1716 | 1720 |
compiler/rustc_ast_passes/src/feature_gate.rs+3| ... | ... | @@ -285,6 +285,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { |
| 285 | 285 | ast::TyKind::Pat(..) => { |
| 286 | 286 | gate!(self, pattern_types, ty.span, "pattern types are unstable"); |
| 287 | 287 | } |
| 288 | ast::TyKind::View(..) => { | |
| 289 | gate!(self, view_types, ty.span, "view types are unstable"); | |
| 290 | } | |
| 288 | 291 | _ => {} |
| 289 | 292 | } |
| 290 | 293 | visit::walk_ty(self, ty) |
compiler/rustc_ast_pretty/src/pprust/state.rs+18| ... | ... | @@ -1259,6 +1259,20 @@ impl<'a> State<'a> { |
| 1259 | 1259 | } |
| 1260 | 1260 | } |
| 1261 | 1261 | |
| 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 | ||
| 1262 | 1276 | pub fn print_assoc_item_constraint(&mut self, constraint: &ast::AssocItemConstraint) { |
| 1263 | 1277 | self.print_ident(constraint.ident); |
| 1264 | 1278 | if let Some(args) = constraint.gen_args.as_ref() { |
| ... | ... | @@ -1441,6 +1455,10 @@ impl<'a> State<'a> { |
| 1441 | 1455 | self.end(ib); |
| 1442 | 1456 | self.pclose(); |
| 1443 | 1457 | } |
| 1458 | ast::TyKind::View(ty, fields) => { | |
| 1459 | self.print_type(ty); | |
| 1460 | self.print_view(fields); | |
| 1461 | } | |
| 1444 | 1462 | } |
| 1445 | 1463 | self.end(ib); |
| 1446 | 1464 | } |
compiler/rustc_ast_pretty/src/pprust/tests.rs+30-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | use rustc_ast as ast; |
| 2 | 2 | use rustc_span::{DUMMY_SP, Ident, create_default_session_globals_then}; |
| 3 | use thin_vec::ThinVec; | |
| 3 | use thin_vec::{ThinVec, thin_vec}; | |
| 4 | 4 | |
| 5 | 5 | use super::*; |
| 6 | 6 | |
| ... | ... | @@ -22,6 +22,12 @@ fn variant_to_string(var: &ast::Variant) -> String { |
| 22 | 22 | to_string(|s| s.print_variant(var)) |
| 23 | 23 | } |
| 24 | 24 | |
| 25 | fn ty_to_string(ty: &ast::Ty) -> String { | |
| 26 | to_string(|s| { | |
| 27 | s.print_type(ty); | |
| 28 | }) | |
| 29 | } | |
| 30 | ||
| 25 | 31 | #[test] |
| 26 | 32 | fn test_fun_to_string() { |
| 27 | 33 | create_default_session_globals_then(|| { |
| ... | ... | @@ -60,3 +66,26 @@ fn test_variant_to_string() { |
| 60 | 66 | assert_eq!(varstr, "principal_skinner"); |
| 61 | 67 | }) |
| 62 | 68 | } |
| 69 | ||
| 70 | #[test] | |
| 71 | fn 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; |
| 47 | 47 | mod source_util; |
| 48 | 48 | mod test; |
| 49 | 49 | mod trace_macros; |
| 50 | mod view_type; | |
| 50 | 51 | |
| 51 | 52 | pub mod asm; |
| 52 | 53 | pub mod cmdline_attrs; |
| ... | ... | @@ -99,6 +100,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { |
| 99 | 100 | stringify: source_util::expand_stringify, |
| 100 | 101 | trace_macros: trace_macros::expand_trace_macros, |
| 101 | 102 | unreachable: edition_panic::expand_unreachable, |
| 103 | view_type: view_type::expand, | |
| 102 | 104 | // tidy-alphabetical-end |
| 103 | 105 | } |
| 104 | 106 |
compiler/rustc_builtin_macros/src/view_type.rs created+47| ... | ... | @@ -0,0 +1,47 @@ |
| 1 | use rustc_ast::token::TokenKind; | |
| 2 | use rustc_ast::tokenstream::TokenStream; | |
| 3 | use rustc_ast::{Ty, ast}; | |
| 4 | use rustc_errors::PResult; | |
| 5 | use rustc_expand::base::{self, DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult}; | |
| 6 | use rustc_parse::parser::{ExpTokenPair, TokenType}; | |
| 7 | use rustc_span::{Ident, Span}; | |
| 8 | use thin_vec::ThinVec; | |
| 9 | ||
| 10 | pub(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 | ||
| 25 | fn 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> { |
| 1090 | 1090 | /// Parses a comma-separated sequence, including both delimiters. |
| 1091 | 1091 | /// The function `f` must consume tokens until reaching the next separator or |
| 1092 | 1092 | /// closing bracket. |
| 1093 | fn parse_delim_comma_seq<T>( | |
| 1093 | pub fn parse_delim_comma_seq<T>( | |
| 1094 | 1094 | &mut self, |
| 1095 | 1095 | open: ExpTokenPair, |
| 1096 | 1096 | close: ExpTokenPair, |
| ... | ... | @@ -1355,7 +1355,7 @@ impl<'a> Parser<'a> { |
| 1355 | 1355 | /// ```enbf |
| 1356 | 1356 | /// FieldName = IntLit | Ident |
| 1357 | 1357 | /// ``` |
| 1358 | fn parse_field_name(&mut self) -> PResult<'a, Ident> { | |
| 1358 | pub fn parse_field_name(&mut self) -> PResult<'a, Ident> { | |
| 1359 | 1359 | if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) = self.token.kind |
| 1360 | 1360 | { |
| 1361 | 1361 | if let Some(suffix) = suffix { |
compiler/rustc_parse/src/parser/ty.rs+1-20| ... | ... | @@ -19,7 +19,7 @@ use crate::errors::{ |
| 19 | 19 | NeedPlusAfterTraitObjectLifetime, NestedCVariadicType, ReturnTypesUseThinArrow, |
| 20 | 20 | }; |
| 21 | 21 | use crate::parser::item::FrontMatterParsingMode; |
| 22 | use crate::parser::{ExpTokenPair, FnContext, FnParseMode}; | |
| 22 | use crate::parser::{FnContext, FnParseMode}; | |
| 23 | 23 | use crate::{exp, maybe_recover_from_interpolated_ty_qpath}; |
| 24 | 24 | |
| 25 | 25 | /// Signals whether parsing a type should allow `+`. |
| ... | ... | @@ -768,25 +768,6 @@ impl<'a> Parser<'a> { |
| 768 | 768 | self.bump_with((dyn_tok, dyn_tok_sp)); |
| 769 | 769 | } |
| 770 | 770 | 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 | } | |
| 790 | 771 | Ok(match pinned { |
| 791 | 772 | Pinnedness::Not => TyKind::Ref(opt_lifetime, MutTy { ty, mutbl }), |
| 792 | 773 | 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> { |
| 690 | 690 | CVarArgs, |
| 691 | 691 | Dummy, |
| 692 | 692 | FieldOf, |
| 693 | View, | |
| 693 | 694 | Err |
| 694 | 695 | ] |
| 695 | 696 | ); |
compiler/rustc_span/src/symbol.rs+1| ... | ... | @@ -2320,6 +2320,7 @@ symbols! { |
| 2320 | 2320 | vgpr384, |
| 2321 | 2321 | vgpr512, |
| 2322 | 2322 | vgpr1024, |
| 2323 | view_type, | |
| 2323 | 2324 | view_types, |
| 2324 | 2325 | vis, |
| 2325 | 2326 | visible_private_types, |
library/core/src/lib.rs+3| ... | ... | @@ -339,6 +339,9 @@ mod bool; |
| 339 | 339 | mod escape; |
| 340 | 340 | mod tuple; |
| 341 | 341 | mod unit; |
| 342 | #[cfg_attr(feature = "nightly", not(bootstrap))] | |
| 343 | #[unstable(feature = "view_type_macro", issue = "155938")] | |
| 344 | pub mod view; | |
| 342 | 345 | |
| 343 | 346 | #[stable(feature = "core_primitive", since = "1.43.0")] |
| 344 | 347 | pub 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")] | |
| 17 | macro_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; |
| 643 | 643 | pub mod random; |
| 644 | 644 | pub mod sync; |
| 645 | 645 | pub mod time; |
| 646 | #[cfg_attr(feature = "nightly", not(bootstrap))] | |
| 647 | #[unstable(feature = "view_type_macro", issue = "155938")] | |
| 648 | pub mod view; | |
| 646 | 649 | |
| 647 | 650 | // Pull in `std_float` crate into std. The contents of |
| 648 | 651 | // `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 | ||
| 3 | pub 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) { |
| 536 | 536 | // experimental |
| 537 | 537 | | TyKind::Pat(..) |
| 538 | 538 | | TyKind::FieldOf(..) |
| 539 | | TyKind::View(..) | |
| 539 | 540 | |
| 540 | 541 | // unused |
| 541 | 542 | | TyKind::CVarArgs |
src/tools/rustfmt/src/types.rs+8-5| ... | ... | @@ -1015,11 +1015,6 @@ impl Rewrite for ast::Ty { |
| 1015 | 1015 | } |
| 1016 | 1016 | ast::TyKind::CVarArgs => Ok("...".to_owned()), |
| 1017 | 1017 | 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 | } | |
| 1023 | 1018 | ast::TyKind::FieldOf(ref ty, ref variant, ref field) => { |
| 1024 | 1019 | let ty = ty.rewrite_result(context, shape)?; |
| 1025 | 1020 | if let Some(variant) = variant { |
| ... | ... | @@ -1054,6 +1049,14 @@ impl Rewrite for ast::Ty { |
| 1054 | 1049 | result.push_str(&rewrite); |
| 1055 | 1050 | Ok(result) |
| 1056 | 1051 | } |
| 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 | } | |
| 1057 | 1060 | } |
| 1058 | 1061 | } |
| 1059 | 1062 | } |
tests/ui/README.md+7| ... | ... | @@ -1583,6 +1583,13 @@ Tests on `enum` variants. |
| 1583 | 1583 | |
| 1584 | 1584 | **FIXME**: Should be rehomed with `tests/ui/enum/`. |
| 1585 | 1585 | |
| 1586 | ## `tests/ui/view-types` | |
| 1587 | ||
| 1588 | Anything related to view types. | |
| 1589 | ||
| 1590 | See | |
| 1591 | [Tracking Issue for view types](https://github.com/rust-lang/rust/issues/155938). | |
| 1592 | ||
| 1586 | 1593 | ## `tests/ui/wasm/` |
| 1587 | 1594 | |
| 1588 | 1595 | These 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 @@ |
| 1 | struct Foo { | |
| 2 | a: usize, | |
| 3 | b: usize, | |
| 4 | } | |
| 5 | ||
| 6 | fn 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 | ||
| 13 | fn 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 @@ |
| 1 | error[E0658]: view types are experimental | |
| 2 | --> $DIR/feature-gate-view-types.rs:6:19 | |
| 3 | | | |
| 4 | LL | 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 | ||
| 11 | error[E0658]: view types are experimental | |
| 12 | --> $DIR/feature-gate-view-types.rs:6:38 | |
| 13 | | | |
| 14 | LL | 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 | ||
| 21 | error[E0499]: cannot borrow `foo` as mutable more than once at a time | |
| 22 | --> $DIR/feature-gate-view-types.rs:15:19 | |
| 23 | | | |
| 24 | LL | 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 | ||
| 30 | error: aborting due to 3 previous errors | |
| 31 | ||
| 32 | Some errors have detailed explanations: E0499, E0658. | |
| 33 | For 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 | ||
| 3 | use std::view::view_type; | |
| 4 | ||
| 5 | struct Foo { | |
| 6 | bar: (), | |
| 7 | baz: (), | |
| 8 | } | |
| 9 | ||
| 10 | type FooBar = view_type!(Foo.{ bar }); | |
| 11 | //~^ ERROR use of unstable library feature `view_type_macro` | |
| 12 | type 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 @@ |
| 1 | error[E0658]: use of unstable library feature `view_type_macro` | |
| 2 | --> $DIR/feature-gate-view-types.rs:10:15 | |
| 3 | | | |
| 4 | LL | 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 | ||
| 11 | error[E0658]: use of unstable library feature `view_type_macro` | |
| 12 | --> $DIR/feature-gate-view-types.rs:12:15 | |
| 13 | | | |
| 14 | LL | 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 | ||
| 21 | error: aborting due to 2 previous errors | |
| 22 | ||
| 23 | For 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 | ||
| 7 | use std::view::view_type; | |
| 8 | ||
| 9 | enum Foo { | |
| 10 | Bar, | |
| 11 | Baz, | |
| 12 | } | |
| 13 | ||
| 14 | // The following types are not structs, we expect errors here. | |
| 15 | fn f(_: view_type!(Foo.{})) {} | |
| 16 | fn g(_: view_type!(u8.{})) {} | |
| 17 | fn h(_: view_type!(char.{})) {} | |
| 18 | ||
| 19 | fn 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 | ||
| 7 | use std::view::view_type; | |
| 8 | ||
| 9 | struct S { | |
| 10 | foo: (), | |
| 11 | } | |
| 12 | ||
| 13 | // We expect errors here, since `S` has no field `bar`. | |
| 14 | fn f(_: view_type!(S.{ bar })) {} | |
| 15 | fn g(_: view_type!(S.{ foo, bar })) {} | |
| 16 | ||
| 17 | fn 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 | ||
| 7 | use std::view::view_type; | |
| 8 | ||
| 9 | struct S { | |
| 10 | foo: (), | |
| 11 | bar: (), | |
| 12 | } | |
| 13 | ||
| 14 | // The outermost fields are supersets of the innermost views, we expect this to trigger an error. | |
| 15 | fn f(_: view_type!(view_type!(S.{}).{ foo })) {} | |
| 16 | fn g(_: view_type!(view_type!(S.{ foo }).{ bar })) {} | |
| 17 | fn h(_: view_type!(view_type!(view_type!(S.{ foo }).{}).{ foo })) {} | |
| 18 | ||
| 19 | fn 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 | ||
| 5 | macro_rules! m { | |
| 6 | ($ty:ty) => { | |
| 7 | compile_error!("ty fragment matched a view type"); | |
| 8 | }; | |
| 9 | (&().{}) => {}; | |
| 10 | } | |
| 11 | ||
| 12 | m!(&().{}); | |
| 13 | ||
| 14 | fn 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 | ||
| 4 | use std::view::view_type; | |
| 5 | ||
| 6 | struct Foo { | |
| 7 | bar: usize, | |
| 8 | baz: usize, | |
| 9 | } | |
| 10 | ||
| 11 | impl 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 | ||
| 25 | fn main() {} |
tests/ui/view-types/syntax-errors.stderr created+52| ... | ... | @@ -0,0 +1,52 @@ |
| 1 | error: expected identifier, found reserved identifier `_` | |
| 2 | --> $DIR/syntax-errors.rs:12:48 | |
| 3 | | | |
| 4 | LL | fn not_a_field(self: &mut view_type!(Foo.{ _ }), _: &mut view_type!(Foo.{ _ })) {} | |
| 5 | | ^ expected identifier, found reserved identifier | |
| 6 | ||
| 7 | error: expected identifier, found reserved identifier `_` | |
| 8 | --> $DIR/syntax-errors.rs:12:79 | |
| 9 | | | |
| 10 | LL | fn not_a_field(self: &mut view_type!(Foo.{ _ }), _: &mut view_type!(Foo.{ _ })) {} | |
| 11 | | ^ expected identifier, found reserved identifier | |
| 12 | ||
| 13 | error: expected identifier, found keyword `where` | |
| 14 | --> $DIR/syntax-errors.rs:16:44 | |
| 15 | | | |
| 16 | LL | fn keyword(self: &mut view_type!(Foo.{ where }), _: &mut view_type!(Foo.{ for })) {} | |
| 17 | | ^^^^^ expected identifier, found keyword | |
| 18 | | | |
| 19 | help: escape `where` to use it as an identifier | |
| 20 | | | |
| 21 | LL | fn keyword(self: &mut view_type!(Foo.{ r#where }), _: &mut view_type!(Foo.{ for })) {} | |
| 22 | | ++ | |
| 23 | ||
| 24 | error: expected identifier, found keyword `for` | |
| 25 | --> $DIR/syntax-errors.rs:16:79 | |
| 26 | | | |
| 27 | LL | fn keyword(self: &mut view_type!(Foo.{ where }), _: &mut view_type!(Foo.{ for })) {} | |
| 28 | | ^^^ expected identifier, found keyword | |
| 29 | | | |
| 30 | help: escape `for` to use it as an identifier | |
| 31 | | | |
| 32 | LL | fn keyword(self: &mut view_type!(Foo.{ where }), _: &mut view_type!(Foo.{ r#for })) {} | |
| 33 | | ++ | |
| 34 | ||
| 35 | error: expected one of `,` or `}`, found `baz` | |
| 36 | --> $DIR/syntax-errors.rs:20:49 | |
| 37 | | | |
| 38 | LL | 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 | ||
| 43 | error: expected one of `,` or `}`, found `baz` | |
| 44 | --> $DIR/syntax-errors.rs:20:86 | |
| 45 | | | |
| 46 | LL | 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 | ||
| 51 | error: 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 | ||
| 6 | use std::view::view_type; | |
| 7 | ||
| 8 | struct Pair(usize, u32); | |
| 9 | ||
| 10 | impl Pair { | |
| 11 | fn foo(self: &mut view_type!(Pair.{ 0, 1 })) {} | |
| 12 | fn bar(_pair: &mut view_type!(Pair.{ 0, 1 })) {} | |
| 13 | } | |
| 14 | ||
| 15 | fn main() {} |