Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Ty>, Option<Ident>, Ident),
/// A view of a type. `T.{ field_1, field_2 }`.
View(Box<Ty>, #[visitable(ignore)] ThinVec<Ident>),
/// Sometimes we need a dummy value when no error has occurred.
Dummy,
/// Placeholder for a kind that has failed to be defined.
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_ast/src/util/classify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
};

Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_ast_passes/src/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
18 changes: 18 additions & 0 deletions compiler/rustc_ast_pretty/src/pprust/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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("}");
}
Comment thread
scrabsha marked this conversation as resolved.

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() {
Expand Down Expand Up @@ -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);
}
Expand Down
31 changes: 30 additions & 1 deletion compiler/rustc_ast_pretty/src/pprust/tests.rs
Original file line number Diff line number Diff line change
@@ -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::*;

Expand All @@ -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(|| {
Expand Down Expand Up @@ -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 }");
});
}
2 changes: 2 additions & 0 deletions compiler/rustc_builtin_macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
}

Expand Down
47 changes: 47 additions & 0 deletions compiler/rustc_builtin_macros/src/view_type.rs
Original file line number Diff line number Diff line change
@@ -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<Ty>, ThinVec<Ident>)> {
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))
}
4 changes: 2 additions & 2 deletions compiler/rustc_parse/src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T>(
pub fn parse_delim_comma_seq<T>(
&mut self,
open: ExpTokenPair,
close: ExpTokenPair,
Expand Down Expand Up @@ -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 {
Expand Down
21 changes: 1 addition & 20 deletions compiler/rustc_parse/src/parser/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 `+`.
Expand Down Expand Up @@ -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] <type> . { <fields> }
// ^
// 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 }),
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_passes/src/input_stats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -690,6 +690,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
CVarArgs,
Dummy,
FieldOf,
View,
Err
]
);
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2306,6 +2306,7 @@ symbols! {
vgpr384,
vgpr512,
vgpr1024,
view_type,
view_types,
vis,
visible_private_types,
Expand Down
3 changes: 3 additions & 0 deletions library/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
21 changes: 21 additions & 0 deletions library/core/src/view.rs
Original file line number Diff line number Diff line change
@@ -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 */
};
}
3 changes: 3 additions & 0 deletions library/std/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
3 changes: 3 additions & 0 deletions library/std/src/view.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
//! Helper module for exporting the `view_types` macro.

pub use core::view_type;
1 change: 1 addition & 0 deletions src/tools/clippy/clippy_utils/src/check_proc_macro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,7 @@ fn ast_ty_search_pat(ty: &ast::Ty) -> (Pat, Pat) {
// experimental
| TyKind::Pat(..)
| TyKind::FieldOf(..)
| TyKind::View(..)

// unused
| TyKind::CVarArgs
Expand Down
8 changes: 8 additions & 0 deletions src/tools/rustfmt/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
}
}
Expand Down
7 changes: 7 additions & 0 deletions tests/ui/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
17 changes: 0 additions & 17 deletions tests/ui/feature-gates/feature-gate-view-types.rs

@scrabsha scrabsha Jun 22, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this file has been moved to tests/ui/view-types/feature-gate-view-types.rs (which is, AIUI what's done for pattern types)

View changes since the review

This file was deleted.

33 changes: 0 additions & 33 deletions tests/ui/feature-gates/feature-gate-view-types.stderr

This file was deleted.

Loading
Loading