From 82a8e58c43e3c2ef4f204064fb8dce0dec93e292 Mon Sep 17 00:00:00 2001 From: Sasha Pourcelot Date: Thu, 30 Apr 2026 16:11:57 +0000 Subject: [PATCH 1/2] view types: add parsing tests --- tests/ui/README.md | 7 +++ tests/ui/view-types/delim-check.rs | 16 ++++++ tests/ui/view-types/syntax-errors.rs | 26 +++++++++ tests/ui/view-types/syntax-errors.stderr | 72 ++++++++++++++++++++++++ 4 files changed, 121 insertions(+) create mode 100644 tests/ui/view-types/delim-check.rs create mode 100644 tests/ui/view-types/syntax-errors.rs create mode 100644 tests/ui/view-types/syntax-errors.stderr diff --git a/tests/ui/README.md b/tests/ui/README.md index 2fe1657e7ecf2..1fd522fb1ce22 100644 --- a/tests/ui/README.md +++ b/tests/ui/README.md @@ -1550,6 +1550,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/view-types/delim-check.rs b/tests/ui/view-types/delim-check.rs new file mode 100644 index 0000000000000..e32136061a3a2 --- /dev/null +++ b/tests/ui/view-types/delim-check.rs @@ -0,0 +1,16 @@ +//@ build-pass + +#![feature(view_types)] +#![allow(irrefutable_let_patterns)] +#![deny(unused_parens)] + +struct Foo { + bar: usize, +} + +fn main() { + let foo = Foo { bar: 42 }; + let a = &foo as &Foo.{ bar } else { + return; + }; +} diff --git a/tests/ui/view-types/syntax-errors.rs b/tests/ui/view-types/syntax-errors.rs new file mode 100644 index 0000000000000..0a57acaf677dc --- /dev/null +++ b/tests/ui/view-types/syntax-errors.rs @@ -0,0 +1,26 @@ +#![feature(view_types)] +#![allow(unused)] + +struct Foo { + bar: usize, + baz: usize, +} + +impl Foo { + fn not_a_field(&mut self.{ _ }, _: &mut Foo.{ _ }) {} + //~^ ERROR expected parameter name + //~| ERROR expected one of + //~| ERROR expected identifier + + fn keyword(&mut self.{ where }, _: &mut Foo.{ for }) {} + //~^ ERROR expected parameter name + //~| ERROR expected one of + //~| ERROR expected identifier + + fn no_comma(&mut self.{ bar baz }, _: &mut Foo.{ bar baz }) {} + //~^ ERROR expected parameter name + //~| 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..bc9ffb8e3ec51 --- /dev/null +++ b/tests/ui/view-types/syntax-errors.stderr @@ -0,0 +1,72 @@ +error: expected parameter name, found `{` + --> $DIR/syntax-errors.rs:10:30 + | +LL | fn not_a_field(&mut self.{ _ }, _: &mut Foo.{ _ }) {} + | ^ expected parameter name + +error: expected one of `)` or `,`, found `.` + --> $DIR/syntax-errors.rs:10:29 + | +LL | fn not_a_field(&mut self.{ _ }, _: &mut Foo.{ _ }) {} + | ^ + | | + | expected one of `)` or `,` + | help: missing `,` + +error: expected identifier, found reserved identifier `_` + --> $DIR/syntax-errors.rs:10:51 + | +LL | fn not_a_field(&mut self.{ _ }, _: &mut Foo.{ _ }) {} + | ^ expected identifier, found reserved identifier + +error: expected parameter name, found `{` + --> $DIR/syntax-errors.rs:15:26 + | +LL | fn keyword(&mut self.{ where }, _: &mut Foo.{ for }) {} + | ^ expected parameter name + +error: expected one of `)` or `,`, found `.` + --> $DIR/syntax-errors.rs:15:25 + | +LL | fn keyword(&mut self.{ where }, _: &mut Foo.{ for }) {} + | ^ + | | + | expected one of `)` or `,` + | help: missing `,` + +error: expected identifier, found keyword `for` + --> $DIR/syntax-errors.rs:15:51 + | +LL | fn keyword(&mut self.{ where }, _: &mut Foo.{ for }) {} + | ^^^ expected identifier, found keyword + | +help: escape `for` to use it as an identifier + | +LL | fn keyword(&mut self.{ where }, _: &mut Foo.{ r#for }) {} + | ++ + +error: expected parameter name, found `{` + --> $DIR/syntax-errors.rs:20:27 + | +LL | fn no_comma(&mut self.{ bar baz }, _: &mut Foo.{ bar baz }) {} + | ^ expected parameter name + +error: expected one of `)` or `,`, found `.` + --> $DIR/syntax-errors.rs:20:26 + | +LL | fn no_comma(&mut self.{ bar baz }, _: &mut Foo.{ bar baz }) {} + | ^ + | | + | expected one of `)` or `,` + | help: missing `,` + +error: expected one of `,` or `}`, found `baz` + --> $DIR/syntax-errors.rs:20:58 + | +LL | fn no_comma(&mut self.{ bar baz }, _: &mut Foo.{ bar baz }) {} + | -^^^ expected one of `,` or `}` + | | + | help: missing `,` + +error: aborting due to 9 previous errors + From ec789ac8cc2e686f2b421ed7a0ba6d8c54d2be3d Mon Sep 17 00:00:00 2001 From: Sasha Pourcelot Date: Tue, 28 Apr 2026 21:10:29 +0000 Subject: [PATCH 2/2] view-types: store borrows of view types in the AST --- compiler/rustc_ast/src/ast.rs | 72 ++++++++++++------- compiler/rustc_ast/src/util/classify.rs | 26 +++++-- compiler/rustc_ast/src/visit.rs | 1 + compiler/rustc_ast_lowering/src/lib.rs | 6 +- compiler/rustc_ast_pretty/src/pprust/state.rs | 32 ++++++--- compiler/rustc_ast_pretty/src/pprust/tests.rs | 39 ++++++++++ compiler/rustc_builtin_macros/src/autodiff.rs | 15 ++-- .../src/deriving/debug.rs | 15 ++-- .../src/deriving/generic/ty.rs | 8 ++- compiler/rustc_builtin_macros/src/env.rs | 3 +- .../src/proc_macro_harness.rs | 3 +- compiler/rustc_expand/src/build.rs | 5 +- compiler/rustc_lint/src/unused.rs | 2 +- compiler/rustc_parse/src/errors.rs | 19 ++++- .../rustc_parse/src/parser/diagnostics.rs | 3 +- compiler/rustc_parse/src/parser/expr.rs | 3 +- compiler/rustc_parse/src/parser/item.rs | 26 +++++-- compiler/rustc_parse/src/parser/stmt.rs | 14 +++- compiler/rustc_parse/src/parser/ty.rs | 49 ++++++++----- compiler/rustc_resolve/src/late.rs | 6 +- .../rustc_resolve/src/late/diagnostics.rs | 10 +-- .../src/needless_arbitrary_self_type.rs | 39 +++++++--- .../src/redundant_static_lifetimes.rs | 2 +- .../clippy/clippy_utils/src/ast_utils/mod.rs | 26 +++++-- .../clippy_utils/src/check_proc_macro.rs | 15 ++-- .../ui/needless_arbitrary_self_type.fixed | 6 ++ .../tests/ui/needless_arbitrary_self_type.rs | 6 ++ .../ui/needless_arbitrary_self_type.stderr | 30 +++++--- src/tools/rustfmt/src/items.rs | 12 ++-- src/tools/rustfmt/src/types.rs | 27 +++++-- src/tools/rustfmt/tests/source/view-types.rs | 13 ++++ src/tools/rustfmt/tests/target/view-types.rs | 13 ++++ tests/ui/stats/input-stats.stderr | 12 ++-- tests/ui/view-types/delim-check.rs | 4 +- tests/ui/view-types/delim-check.stderr | 13 ++++ tests/ui/view-types/syntax-errors.rs | 15 ++-- tests/ui/view-types/syntax-errors.stderr | 56 +++++---------- 37 files changed, 455 insertions(+), 191 deletions(-) create mode 100644 src/tools/rustfmt/tests/source/view-types.rs create mode 100644 src/tools/rustfmt/tests/target/view-types.rs create mode 100644 tests/ui/view-types/delim-check.stderr diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index a768beedba31c..db0b8863fcddf 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -646,8 +646,10 @@ impl Pat { PatKind::MacCall(mac) => TyKind::MacCall(mac.clone()), // `&mut? P` can be reinterpreted as `&mut? T` where `T` is `P` reparsed as a type. PatKind::Ref(pat, pinned, mutbl) => pat.to_ty().map(|ty| match pinned { - Pinnedness::Not => TyKind::Ref(None, MutTy { ty, mutbl: *mutbl }), - Pinnedness::Pinned => TyKind::PinnedRef(None, MutTy { ty, mutbl: *mutbl }), + Pinnedness::Not => TyKind::Ref(None, MutTy { ty, mutbl: *mutbl }, ViewKind::Full), + Pinnedness::Pinned => { + TyKind::PinnedRef(None, MutTy { ty, mutbl: *mutbl }, ViewKind::Full) + } })?, // A slice/array pattern `[P]` can be reparsed as `[T]`, an unsized array, // when `P` can be reparsed as a type `T`. @@ -1510,9 +1512,9 @@ impl Expr { ExprKind::Paren(expr) => expr.to_ty().map(TyKind::Paren)?, - ExprKind::AddrOf(BorrowKind::Ref, mutbl, expr) => { - expr.to_ty().map(|ty| TyKind::Ref(None, MutTy { ty, mutbl: *mutbl }))? - } + ExprKind::AddrOf(BorrowKind::Ref, mutbl, expr) => expr + .to_ty() + .map(|ty| TyKind::Ref(None, MutTy { ty, mutbl: *mutbl }, ViewKind::Full))?, ExprKind::Repeat(expr, expr_len) => { expr.to_ty().map(|ty| TyKind::Array(ty, expr_len.clone()))? @@ -2473,7 +2475,8 @@ impl From> for Ty { impl Ty { pub fn peel_refs(&self) -> &Self { let mut final_ty = self; - while let TyKind::Ref(_, MutTy { ty, .. }) | TyKind::Ptr(MutTy { ty, .. }) = &final_ty.kind + while let TyKind::Ref(_, MutTy { ty, .. }, _) | TyKind::Ptr(MutTy { ty, .. }) = + &final_ty.kind { final_ty = ty; } @@ -2518,11 +2521,11 @@ pub enum TyKind { /// A raw pointer (`*const T` or `*mut T`). Ptr(MutTy), /// A reference (`&'a T` or `&'a mut T`). - Ref(#[visitable(extra = LifetimeCtxt::Ref)] Option, MutTy), + Ref(#[visitable(extra = LifetimeCtxt::Ref)] Option, MutTy, ViewKind), /// A pinned reference (`&'a pin const T` or `&'a pin mut T`). /// /// Desugars into `Pin<&'a T>` or `Pin<&'a mut T>`. - PinnedRef(#[visitable(extra = LifetimeCtxt::Ref)] Option, MutTy), + PinnedRef(#[visitable(extra = LifetimeCtxt::Ref)] Option, MutTy, ViewKind), /// A function pointer type (e.g., `fn(usize) -> bool`). FnPtr(Box), /// An unsafe existential lifetime binder (e.g., `unsafe<'a> &'a ()`). @@ -2660,6 +2663,21 @@ pub enum TraitObjectSyntax { None = 1, } +/// Represents how a reference is viewed. +// FIXME(scrabsha): move this to a new variant of `Mutabiliy` when viewing of non-reference types +// is implemented. +#[derive(Clone, Encodable, Decodable, Debug, Walkable)] +pub enum ViewKind { + /// `&mut T`. All the fields can be observed. + Full, + /// `&mut T.{ foo, bar }`. Only `foo` and `bar` can be observed. + Partial { + span: Span, + #[visitable(ignore)] + fields: ThinVec, + }, +} + /// SAFETY: `TraitObjectSyntax` only has 3 data-less variants which means /// it can be represented with a `u2`. We use `repr(u8)` to guarantee the /// discriminants of the variants are no greater than `3`. @@ -2933,10 +2951,10 @@ pub struct Param { pub enum SelfKind { /// `self`, `mut self` Value(Mutability), - /// `&'lt self`, `&'lt mut self` - Region(Option, Mutability), - /// `&'lt pin const self`, `&'lt pin mut self` - Pinned(Option, Mutability), + /// `&'lt self`, `&'lt mut self`, `&'lt mut self.{ a, b }` + Region(Option, Mutability, ViewKind), + /// `&'lt pin const self`, `&'lt pin mut self`, `&'lt pin mut self.{ a, b }`. + Pinned(Option, Mutability, ViewKind), /// `self: TYPE`, `mut self: TYPE` Explicit(Box, Mutability), } @@ -2944,10 +2962,10 @@ pub enum SelfKind { impl SelfKind { pub fn to_ref_suggestion(&self) -> String { match self { - SelfKind::Region(None, mutbl) => mutbl.ref_prefix_str().to_string(), - SelfKind::Region(Some(lt), mutbl) => format!("&{lt} {}", mutbl.prefix_str()), - SelfKind::Pinned(None, mutbl) => format!("&pin {}", mutbl.ptr_str()), - SelfKind::Pinned(Some(lt), mutbl) => format!("&{lt} pin {}", mutbl.ptr_str()), + SelfKind::Region(None, mutbl, _) => mutbl.ref_prefix_str().to_string(), + SelfKind::Region(Some(lt), mutbl, _) => format!("&{lt} {}", mutbl.prefix_str()), + SelfKind::Pinned(None, mutbl, _) => format!("&pin {}", mutbl.ptr_str()), + SelfKind::Pinned(Some(lt), mutbl, _) => format!("&{lt} pin {}", mutbl.ptr_str()), SelfKind::Value(_) | SelfKind::Explicit(_, _) => { unreachable!("if we had an explicit self, we wouldn't be here") } @@ -2964,13 +2982,15 @@ impl Param { if ident.name == kw::SelfLower { return match self.ty.kind { TyKind::ImplicitSelf => Some(respan(self.pat.span, SelfKind::Value(mutbl))), - TyKind::Ref(lt, MutTy { ref ty, mutbl }) if ty.kind.is_implicit_self() => { - Some(respan(self.pat.span, SelfKind::Region(lt, mutbl))) + TyKind::Ref(lt, MutTy { ref ty, mutbl }, ref view) + if ty.kind.is_implicit_self() => + { + Some(respan(self.pat.span, SelfKind::Region(lt, mutbl, view.clone()))) } - TyKind::PinnedRef(lt, MutTy { ref ty, mutbl }) + TyKind::PinnedRef(lt, MutTy { ref ty, mutbl }, ref view) if ty.kind.is_implicit_self() => { - Some(respan(self.pat.span, SelfKind::Pinned(lt, mutbl))) + Some(respan(self.pat.span, SelfKind::Pinned(lt, mutbl, view.clone()))) } _ => Some(respan( self.pat.span.to(self.ty.span), @@ -3003,20 +3023,20 @@ impl Param { let (mutbl, ty) = match eself.node { SelfKind::Explicit(ty, mutbl) => (mutbl, ty), SelfKind::Value(mutbl) => (mutbl, infer_ty), - SelfKind::Region(lt, mutbl) => ( + SelfKind::Region(lt, mutbl, views) => ( Mutability::Not, Box::new(Ty { id: DUMMY_NODE_ID, - kind: TyKind::Ref(lt, MutTy { ty: infer_ty, mutbl }), + kind: TyKind::Ref(lt, MutTy { ty: infer_ty, mutbl }, views), span, tokens: None, }), ), - SelfKind::Pinned(lt, mutbl) => ( + SelfKind::Pinned(lt, mutbl, view) => ( mutbl, Box::new(Ty { id: DUMMY_NODE_ID, - kind: TyKind::PinnedRef(lt, MutTy { ty: infer_ty, mutbl }), + kind: TyKind::PinnedRef(lt, MutTy { ty: infer_ty, mutbl }, view), span, tokens: None, }), @@ -4340,7 +4360,7 @@ mod size_asserts { static_assert_size!(Stmt, 32); static_assert_size!(StmtKind, 16); static_assert_size!(TraitImplHeader, 72); - static_assert_size!(Ty, 64); - static_assert_size!(TyKind, 40); + static_assert_size!(Ty, 80); + static_assert_size!(TyKind, 56); // tidy-alphabetical-end } diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs index 43ef6897b79cf..bef37a7e500eb 100644 --- a/compiler/rustc_ast/src/util/classify.rs +++ b/compiler/rustc_ast/src/util/classify.rs @@ -1,5 +1,6 @@ //! Routines the parser and pretty-printer use to classify AST nodes. +use crate::ViewKind; use crate::ast::ExprKind::*; use crate::ast::{self, MatchKind}; use crate::token::Delimiter; @@ -167,6 +168,8 @@ pub enum TrailingBrace<'a> { /// Trailing brace in any other expression, such as `a + B {}`. We will /// suggest wrapping the innermost expression in parentheses: `a + (B {})`. Expr(&'a ast::Expr), + /// Trailing brace in a type, like the one in `&Foo.{ bar }` + Type(&'a ast::Ty), } /// If an expression ends with `}`, returns the innermost expression ending in the `}` @@ -205,7 +208,7 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option> { | ConstBlock(_) => break Some(TrailingBrace::Expr(expr)), Cast(_, ty) => { - break type_trailing_braced_mac_call(ty).map(TrailingBrace::MacCall); + break type_trailing_brace(ty); } MacCall(mac) => { @@ -246,21 +249,30 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option> { } } -/// If the type's last token is `}`, it must be due to a braced macro call, such -/// as in `*const brace! { ... }`. Returns that trailing macro call. -fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> { +/// If a type ends with `}`, return the innermost node ending with the `}`. +/// +/// This may be caused by a macro call (`*const brace! { ... }`) or a view type +/// (`&Foo.{ bar }`). +fn type_trailing_brace(mut ty: &ast::Ty) -> Option> { loop { match &ty.kind { ast::TyKind::MacCall(mac) => { - break (mac.args.delim == Delimiter::Brace).then_some(mac); + break (mac.args.delim == Delimiter::Brace) + .then_some(mac.as_ref()) + .map(TrailingBrace::MacCall); } ast::TyKind::Ptr(mut_ty) - | ast::TyKind::Ref(_, mut_ty) - | ast::TyKind::PinnedRef(_, mut_ty) => { + | ast::TyKind::Ref(_, mut_ty, ViewKind::Full) + | ast::TyKind::PinnedRef(_, mut_ty, ViewKind::Full) => { ty = &mut_ty.ty; } + ast::TyKind::Ref(_, _, ViewKind::Partial { .. }) + | ast::TyKind::PinnedRef(_, _, ViewKind::Partial { .. }) => { + break Some(TrailingBrace::Type(ty)); + } + ast::TyKind::UnsafeBinder(binder) => { ty = &binder.inner_ty; } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index ee4b1d1354300..75f8aa76d1921 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -486,6 +486,7 @@ macro_rules! common_visitor_and_walkers { UnsafeBinderTy, UnsafeSource, UseTreeKind, + ViewKind, VisibilityKind, WhereBoundPredicate, WhereClause, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 49790c2da6de4..54902a37db358 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1413,11 +1413,11 @@ impl<'hir> LoweringContext<'_, 'hir> { TyKind::Err(guar) => hir::TyKind::Err(*guar), TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty_alloc(ty, itctx)), TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)), - TyKind::Ref(region, mt) => { + TyKind::Ref(region, mt, _) => { let lifetime = self.lower_ty_direct_lifetime(t, *region); hir::TyKind::Ref(lifetime, self.lower_mt(mt, itctx)) } - TyKind::PinnedRef(region, mt) => { + TyKind::PinnedRef(region, mt, _) => { let lifetime = self.lower_ty_direct_lifetime(t, *region); let kind = hir::TyKind::Ref(lifetime, self.lower_mt(mt, itctx)); let span = self.lower_span(t.span); @@ -1841,7 +1841,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // Given we are only considering `ImplicitSelf` types, we needn't consider // the case where we have a mutable pattern to a reference as that would // no longer be an `ImplicitSelf`. - TyKind::Ref(_, mt) | TyKind::PinnedRef(_, mt) + TyKind::Ref(_, mt, _) | TyKind::PinnedRef(_, mt, _) if mt.ty.kind.is_implicit_self() => { match mt.mutbl { diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index f46ce8fd76865..ef37ec54c8fbf 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -17,7 +17,7 @@ use rustc_ast::util::comments::{Comment, CommentStyle}; use rustc_ast::{ self as ast, AttrArgs, BindingMode, BlockCheckMode, ByRef, DelimArgs, GenericArg, GenericBound, InlineAsmOperand, InlineAsmOptions, InlineAsmRegOrRegClass, InlineAsmTemplatePiece, PatKind, - RangeEnd, RangeSyntax, Safety, SelfKind, Term, attr, + RangeEnd, RangeSyntax, Safety, SelfKind, Term, ViewKind, attr, }; use rustc_span::edition::Edition; use rustc_span::source_map::SourceMap; @@ -1255,6 +1255,16 @@ impl<'a> State<'a> { } } + fn print_view(&mut self, view: &ViewKind) { + if let ViewKind::Partial { fields, .. } = view { + self.word_space(".{"); + self.commasep(Breaks::Inconsistent, fields, |s, field| { + s.print_ident(*field); + }); + self.word_space(" }"); + } + } + 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() { @@ -1333,16 +1343,18 @@ impl<'a> State<'a> { self.word("*"); self.print_mt(mt, true); } - ast::TyKind::Ref(lifetime, mt) => { + ast::TyKind::Ref(lifetime, mt, view) => { self.word("&"); self.print_opt_lifetime(lifetime); self.print_mt(mt, false); + self.print_view(view); } - ast::TyKind::PinnedRef(lifetime, mt) => { + ast::TyKind::PinnedRef(lifetime, mt, view) => { self.word("&"); self.print_opt_lifetime(lifetime); self.word("pin "); self.print_mt(mt, true); + self.print_view(view); } ast::TyKind::Never => { self.word("!"); @@ -2056,26 +2068,28 @@ impl<'a> State<'a> { match &explicit_self.node { SelfKind::Value(m) => { self.print_mutability(*m, false); - self.word("self") + self.word("self"); } - SelfKind::Region(lt, m) => { + SelfKind::Region(lt, m, view) => { self.word("&"); self.print_opt_lifetime(lt); self.print_mutability(*m, false); - self.word("self") + self.word("self"); + self.print_view(view); } - SelfKind::Pinned(lt, m) => { + SelfKind::Pinned(lt, m, view) => { self.word("&"); self.print_opt_lifetime(lt); self.word("pin "); self.print_mutability(*m, true); - self.word("self") + self.word("self"); + self.print_view(view); } SelfKind::Explicit(typ, m) => { self.print_mutability(*m, false); self.word("self"); self.word_space(":"); - self.print_type(typ) + self.print_type(typ); } } } diff --git a/compiler/rustc_ast_pretty/src/pprust/tests.rs b/compiler/rustc_ast_pretty/src/pprust/tests.rs index 786de529c5b89..1c4667102ccd9 100644 --- a/compiler/rustc_ast_pretty/src/pprust/tests.rs +++ b/compiler/rustc_ast_pretty/src/pprust/tests.rs @@ -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,36 @@ 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::Ref( + None, + ast::MutTy { + ty: Box::new(ast::Ty { + id: ast::DUMMY_NODE_ID, + kind: ast::TyKind::Dummy, + span: DUMMY_SP, + tokens: None, + }), + mutbl: ast::Mutability::Mut, + }, + ast::ViewKind::Partial { + span: DUMMY_SP, + fields: thin_vec::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, "&mut (/*DUMMY*/).{ milhouse, apu }"); + }); +} diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index afa393a545cd4..043c496460cfb 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -487,7 +487,7 @@ mod llvm_enzyme { TyKind::Ptr(ref mut mut_ty) => { mut_ty.mutbl = ast::Mutability::Mut; } - TyKind::Ref(_, ref mut mut_ty) => { + TyKind::Ref(_, ref mut mut_ty, _) => { mut_ty.mutbl = ast::Mutability::Mut; } _ => { @@ -521,10 +521,15 @@ mod llvm_enzyme { .map(|param| { let ty = match ¶m.ty.kind { TyKind::ImplicitSelf => self_ty(), - TyKind::Ref(lt, mt) if matches!(mt.ty.kind, TyKind::ImplicitSelf) => ecx.ty( - span, - TyKind::Ref(lt.clone(), ast::MutTy { ty: self_ty(), mutbl: mt.mutbl }), - ), + TyKind::Ref(lt, mt, view) if matches!(mt.ty.kind, TyKind::ImplicitSelf) => ecx + .ty( + span, + TyKind::Ref( + lt.clone(), + ast::MutTy { ty: self_ty(), mutbl: mt.mutbl }, + view.clone(), + ), + ), TyKind::Ptr(mt) if matches!(mt.ty.kind, TyKind::ImplicitSelf) => { ecx.ty(span, TyKind::Ptr(ast::MutTy { ty: self_ty(), mutbl: mt.mutbl })) } diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs index 004b13bcc333d..b49706cc6742f 100644 --- a/compiler/rustc_builtin_macros/src/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -1,4 +1,4 @@ -use rustc_ast::{self as ast, EnumDef, MetaItem, Safety}; +use rustc_ast::{self as ast, EnumDef, MetaItem, Safety, ViewKind}; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_session::config::FmtDebug; use rustc_span::{Ident, Span, Symbol, sym}; @@ -152,7 +152,8 @@ fn show_substructure(cx: &ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> // `let names: &'static _ = &["field1", "field2"];` let names_let = is_struct.then(|| { let lt_static = Some(cx.lifetime_static(span)); - let ty_static_ref = cx.ty_ref(span, cx.ty_infer(span), lt_static, ast::Mutability::Not); + let ty_static_ref = + cx.ty_ref(span, cx.ty_infer(span), lt_static, ast::Mutability::Not, ViewKind::Full); cx.stmt_let_ty( span, false, @@ -173,13 +174,19 @@ fn show_substructure(cx: &ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> ); let ty_slice = cx.ty( span, - ast::TyKind::Slice(cx.ty_ref(span, ty_dyn_debug, None, ast::Mutability::Not)), + ast::TyKind::Slice(cx.ty_ref( + span, + ty_dyn_debug, + None, + ast::Mutability::Not, + ViewKind::Full, + )), ); let values_let = cx.stmt_let_ty( span, false, Ident::new(sym::values, span), - Some(cx.ty_ref(span, ty_slice, None, ast::Mutability::Not)), + Some(cx.ty_ref(span, ty_slice, None, ast::Mutability::Not, ViewKind::Full)), cx.expr_array_ref(span, value_exprs), ); diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs index e7972c5436e13..54bcc5e3a3e2b 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs @@ -2,7 +2,9 @@ //! when specifying impls to be derived. pub(crate) use Ty::*; -use rustc_ast::{self as ast, Expr, GenericArg, GenericParamKind, Generics, SelfKind, TyKind}; +use rustc_ast::{ + self as ast, Expr, GenericArg, GenericParamKind, Generics, SelfKind, TyKind, ViewKind, +}; use rustc_expand::base::ExtCtxt; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, respan}; use thin_vec::ThinVec; @@ -94,7 +96,7 @@ impl Ty { match self { Ref(ty, mutbl) => { let raw_ty = ty.to_ty(cx, span, self_ty, self_generics); - cx.ty_ref(span, raw_ty, None, *mutbl) + cx.ty_ref(span, raw_ty, None, *mutbl, ViewKind::Full) } Path(p) => p.to_ty(cx, span, self_ty, self_generics), Self_ => cx.ty_path(self.to_path(cx, span, self_ty, self_generics)), @@ -200,6 +202,6 @@ impl Bounds { pub(crate) fn get_explicit_self(cx: &ExtCtxt<'_>, span: Span) -> (Box, ast::ExplicitSelf) { // This constructs a fresh `self` path. let self_path = cx.expr_self(span); - let self_ty = respan(span, SelfKind::Region(None, ast::Mutability::Not)); + let self_ty = respan(span, SelfKind::Region(None, ast::Mutability::Not, ViewKind::Full)); (self_path, self_ty) } diff --git a/compiler/rustc_builtin_macros/src/env.rs b/compiler/rustc_builtin_macros/src/env.rs index d9af43fcd1c3d..0b06ed62c702d 100644 --- a/compiler/rustc_builtin_macros/src/env.rs +++ b/compiler/rustc_builtin_macros/src/env.rs @@ -8,7 +8,7 @@ use std::env::VarError; use rustc_ast::token::{self, LitKind}; use rustc_ast::tokenstream::TokenStream; -use rustc_ast::{ExprKind, GenericArg, Mutability}; +use rustc_ast::{ExprKind, GenericArg, Mutability, ViewKind}; use rustc_ast_pretty::pprust; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult}; use rustc_span::edit_distance::edit_distance; @@ -65,6 +65,7 @@ pub(crate) fn expand_option_env<'cx>( cx.ty_ident(sp, Ident::new(sym::str, sp)), Some(lt), Mutability::Not, + ViewKind::Full, ))], )) } diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index aa936b46eec20..0614ffa5905fc 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -1,7 +1,7 @@ use std::{mem, slice}; use rustc_ast::visit::{self, Visitor}; -use rustc_ast::{self as ast, NodeId, attr}; +use rustc_ast::{self as ast, NodeId, ViewKind, attr}; use rustc_ast_pretty::pprust; use rustc_attr_parsing::AttributeParser; use rustc_errors::DiagCtxtHandle; @@ -372,6 +372,7 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> Box { ), None, ast::Mutability::Not, + ViewKind::Full, ), ast::Mutability::Not, cx.expr_array_ref(span, decls), diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 01886a97f55a2..8bbb10cd337ef 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -3,7 +3,7 @@ use rustc_ast::tokenstream::TokenStream; use rustc_ast::util::literal; use rustc_ast::{ self as ast, AnonConst, AttrItem, AttrVec, BlockCheckMode, Expr, LocalKind, MatchKind, - MgcaDisambiguation, PatKind, UnOp, attr, token, tokenstream, + MgcaDisambiguation, PatKind, UnOp, ViewKind, attr, token, tokenstream, }; use rustc_span::{DUMMY_SP, Ident, Span, Spanned, Symbol, kw, sym}; use thin_vec::{ThinVec, thin_vec}; @@ -118,8 +118,9 @@ impl<'a> ExtCtxt<'a> { ty: Box, lifetime: Option, mutbl: ast::Mutability, + view: ViewKind, ) -> Box { - self.ty(span, ast::TyKind::Ref(lifetime, self.ty_mt(ty, mutbl))) + self.ty(span, ast::TyKind::Ref(lifetime, self.ty_mt(ty, mutbl), view)) } pub fn ty_ptr(&self, span: Span, ty: Box, mutbl: ast::Mutability) -> Box { diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 9f15f41955d86..6d69c83611685 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -844,7 +844,7 @@ impl EarlyLintPass for UnusedParens { self.with_self_ty_parens = false; } - ast::TyKind::Ref(_, mut_ty) | ast::TyKind::Ptr(mut_ty) => { + ast::TyKind::Ref(_, mut_ty, _) | ast::TyKind::Ptr(mut_ty) => { // If this type itself appears in no-bounds position, we propagate its // potentially tighter constraint or risk a false posive (issue 143653). let own_constraint = self.in_no_bounds_pos.get(&ty.id); diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 4043b9bca61c5..35ac1ce7c6020 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1062,7 +1062,8 @@ pub(crate) enum WrapInParentheses { "wrap the expression in parentheses", applicability = "machine-applicable" )] - Expression { + NonMacro { + kind: WrapInParenthesesNodeKind, #[suggestion_part(code = "(")] left: Span, #[suggestion_part(code = ")")] @@ -1080,6 +1081,22 @@ pub(crate) enum WrapInParentheses { }, } +pub(crate) enum WrapInParenthesesNodeKind { + Expression, + Type, +} + +impl IntoDiagArg for WrapInParenthesesNodeKind { + fn into_diag_arg(self, _path: &mut Option) -> DiagArgValue { + let str = match self { + WrapInParenthesesNodeKind::Expression => "expression", + WrapInParenthesesNodeKind::Type => "type", + }; + + DiagArgValue::Str(Cow::Borrowed(str)) + } +} + #[derive(Diagnostic)] #[diag("this is a block expression, not an array")] pub(crate) struct ArrayBracketsInsteadOfBraces { diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 47ac91feefd4b..da1f20157719a 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -8,6 +8,7 @@ use rustc_ast::{ self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode, Block, BlockCheckMode, Expr, ExprKind, GenericArg, Generics, Item, ItemKind, MgcaDisambiguation, Param, Pat, PatKind, Path, PathSegment, QSelf, Recovered, Ty, TyKind, + ViewKind, }; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; @@ -1662,7 +1663,7 @@ impl<'a> Parser<'a> { self.bump(); // `+` let _bounds = self.parse_generic_bounds()?; let sub = match &ty.kind { - TyKind::Ref(_lifetime, mut_ty) => { + TyKind::Ref(_lifetime, mut_ty, ViewKind::Full) => { let lo = mut_ty.ty.span.shrink_to_lo(); let hi = self.prev_token.span.shrink_to_hi(); BadTypePlusSub::AddParen { suggestion: AddParen { lo, hi } } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 35c271cb70204..20b7be8db3ca4 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1900,7 +1900,8 @@ impl<'a> Parser<'a> { let lexpr = self.parse_expr_labeled(label, true)?; self.dcx().emit_err(errors::LabeledLoopInBreak { span: lexpr.span, - sub: errors::WrapInParentheses::Expression { + sub: errors::WrapInParentheses::NonMacro { + kind: errors::WrapInParenthesesNodeKind::Expression, left: lexpr.span.shrink_to_lo(), right: lexpr.span.shrink_to_hi(), }, diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index bd45bbb6a8582..c956361f1ce08 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -3526,17 +3526,20 @@ impl<'a> Parser<'a> { token::And => { let has_lifetime = is_lifetime(self, 1); let skip_lifetime_count = has_lifetime as usize; - let eself = if is_isolated_self(self, skip_lifetime_count + 1) { + // HACK: we temporarily initialize the view kind of the returned `SelfKind` as + // `Full` and replace it with a `Partial` if necessary once we have advanced past + // the `self` token. + let mut eself = if is_isolated_self(self, skip_lifetime_count + 1) { // `&{'lt} self` self.bump(); // & let lifetime = has_lifetime.then(|| self.expect_lifetime()); - SelfKind::Region(lifetime, Mutability::Not) + SelfKind::Region(lifetime, Mutability::Not, ViewKind::Full) } else if is_isolated_mut_self(self, skip_lifetime_count + 1) { // `&{'lt} mut self` self.bump(); // & let lifetime = has_lifetime.then(|| self.expect_lifetime()); self.bump(); // mut - SelfKind::Region(lifetime, Mutability::Mut) + SelfKind::Region(lifetime, Mutability::Mut, ViewKind::Full) } else if is_isolated_pin_const_self(self, skip_lifetime_count + 1) { // `&{'lt} pin const self` self.bump(); // & @@ -3544,7 +3547,7 @@ impl<'a> Parser<'a> { self.psess.gated_spans.gate(sym::pin_ergonomics, self.token.span); self.bump(); // pin self.bump(); // const - SelfKind::Pinned(lifetime, Mutability::Not) + SelfKind::Pinned(lifetime, Mutability::Not, ViewKind::Full) } else if is_isolated_pin_mut_self(self, skip_lifetime_count + 1) { // `&{'lt} pin mut self` self.bump(); // & @@ -3552,13 +3555,26 @@ impl<'a> Parser<'a> { self.psess.gated_spans.gate(sym::pin_ergonomics, self.token.span); self.bump(); // pin self.bump(); // mut - SelfKind::Pinned(lifetime, Mutability::Mut) + SelfKind::Pinned(lifetime, Mutability::Mut, ViewKind::Full) } else { // `¬_self` return Ok(None); }; let hi = self.token.span; let self_ident = expect_self_ident_not_typed(self, &eself, eself_lo.until(hi)); + if let view @ ViewKind::Partial { .. } = self.maybe_parse_view() { + match eself { + SelfKind::Region(_, _, ref mut view_ @ ViewKind::Full) + | SelfKind::Pinned(_, _, ref mut view_ @ ViewKind::Full) => { + *view_ = view; + } + + SelfKind::Region(_, _, ViewKind::Partial { .. }) + | SelfKind::Pinned(_, _, ViewKind::Partial { .. }) + | SelfKind::Value(..) + | SelfKind::Explicit(..) => unreachable!(), + } + } (eself, self_ident, hi) } // `*self` diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 5bd2ca3139228..afc7652dd847c 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -429,7 +429,8 @@ impl<'a> Parser<'a> { self.dcx().emit_err(errors::InvalidExpressionInLetElse { span: init.span, operator: op.node.as_str(), - sugg: errors::WrapInParentheses::Expression { + sugg: errors::WrapInParentheses::NonMacro { + kind: errors::WrapInParenthesesNodeKind::Expression, left: init.span.shrink_to_lo(), right: init.span.shrink_to_hi(), }, @@ -450,11 +451,20 @@ impl<'a> Parser<'a> { ), TrailingBrace::Expr(expr) => ( expr.span, - errors::WrapInParentheses::Expression { + errors::WrapInParentheses::NonMacro { + kind: errors::WrapInParenthesesNodeKind::Expression, left: expr.span.shrink_to_lo(), right: expr.span.shrink_to_hi(), }, ), + TrailingBrace::Type(ty) => ( + ty.span, + errors::WrapInParentheses::NonMacro { + kind: errors::WrapInParenthesesNodeKind::Type, + left: ty.span.shrink_to_lo(), + right: ty.span.shrink_to_hi(), + }, + ), }; self.dcx().emit_err(errors::InvalidCurlyInLetElse { span: span.with_lo(span.hi() - BytePos(1)), diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index b5151cf20ab02..70ccf57e1fb7b 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -4,7 +4,7 @@ use rustc_ast::{ self as ast, BoundAsyncness, BoundConstness, BoundPolarity, DUMMY_NODE_ID, FnPtrTy, FnRetTy, GenericBound, GenericBounds, GenericParam, Generics, Lifetime, MacCall, MgcaDisambiguation, MutTy, Mutability, Pinnedness, PolyTraitRef, PreciseCapturingArg, TraitBoundModifiers, - TraitObjectSyntax, Ty, TyKind, UnsafeBinderTy, + TraitObjectSyntax, Ty, TyKind, UnsafeBinderTy, ViewKind, }; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{Applicability, Diag, E0516, PResult}; @@ -551,7 +551,8 @@ impl<'a> Parser<'a> { Applicability::MaybeIncorrect, ); err.emit(); - Ok(TyKind::Ref(Some(lt), MutTy { ty, mutbl })) + let view = self.maybe_parse_view(); + Ok(TyKind::Ref(Some(lt), MutTy { ty, mutbl }, view)) } Err(diag) => { diag.cancel(); @@ -768,29 +769,41 @@ impl<'a> Parser<'a> { self.bump_with((dyn_tok, dyn_tok_sp)); } let ty = self.parse_ty_no_plus()?; + let view = self.maybe_parse_view(); + Ok(match pinned { + Pinnedness::Not => TyKind::Ref(opt_lifetime, MutTy { ty, mutbl }, view), + Pinnedness::Pinned => TyKind::PinnedRef(opt_lifetime, MutTy { ty, mutbl }, view), + }) + } + + pub(crate) fn maybe_parse_view(&mut self) -> ViewKind { if self.token == TokenKind::Dot && self.look_ahead(1, |t| t.kind == TokenKind::OpenBrace) { - // & [mut] . { } - // ^ - // we are here + // & [pin] [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 fields = match 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(), + ) { + Ok((fields, _)) => fields, + Err(diag) => { + diag.emit(); + return ViewKind::Full; + } + }; + 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); + + ViewKind::Partial { span, fields } + } else { + ViewKind::Full } - Ok(match pinned { - Pinnedness::Not => TyKind::Ref(opt_lifetime, MutTy { ty, mutbl }), - Pinnedness::Pinned => TyKind::PinnedRef(opt_lifetime, MutTy { ty, mutbl }), - }) } /// Parse nothing, mutability or `pin` followed by "explicit" mutability. diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 014a472c2c1bb..79f99578e91b0 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -882,7 +882,7 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc let prev = self.diag_metadata.current_trait_object; let prev_ty = self.diag_metadata.current_type_path; match &ty.kind { - TyKind::Ref(None, _) | TyKind::PinnedRef(None, _) => { + TyKind::Ref(None, _, _) | TyKind::PinnedRef(None, _, _) => { // Elided lifetime in reference: we resolve as if there was some lifetime `'_` with // NodeId `ty.id`. // This span will be used in case of elision failure. @@ -2061,7 +2061,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { type Result = ControlFlow; fn visit_ty(&mut self, ty: &'ast ast::Ty) -> Self::Result { - if let ast::TyKind::Ref(None, mut_ty) = &ty.kind { + if let ast::TyKind::Ref(None, mut_ty, _) = &ty.kind { return ControlFlow::Break(mut_ty.ty.span.shrink_to_lo()); } visit::walk_ty(self, ty) @@ -2596,7 +2596,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { impl<'ra> Visitor<'ra> for FindReferenceVisitor<'_, '_, '_> { fn visit_ty(&mut self, ty: &'ra Ty) { trace!("FindReferenceVisitor considering ty={:?}", ty); - if let TyKind::Ref(lt, _) | TyKind::PinnedRef(lt, _) = ty.kind { + if let TyKind::Ref(lt, _, _) | TyKind::PinnedRef(lt, _, ViewKind::Full) = ty.kind { // See if anything inside the &thing contains Self let mut visitor = SelfVisitor { r: self.r, impl_self: self.impl_self, self_found: false }; diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 6f86759d46c5f..9a3b2c4906656 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -2739,7 +2739,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { fn extract_node_id(t: &Ty) -> Option { match t.kind { TyKind::Path(None, _) => Some(t.id), - TyKind::Ref(_, ref mut_ty) => extract_node_id(&mut_ty.ty), + TyKind::Ref(_, ref mut_ty, _) => extract_node_id(&mut_ty.ty), // This doesn't handle the remaining `Ty` variants as they are not // that commonly the self_type, it might be interesting to provide // support for those in future. @@ -4241,7 +4241,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { .seen .iter() .filter_map(|ty| match &ty.kind { - TyKind::Ref(_, mut_ty) => { + TyKind::Ref(_, mut_ty, _) => { let span = ty.span.with_hi(mut_ty.ty.span.lo()); Some((span, "&'a ".to_string())) } @@ -4282,7 +4282,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { let mut ret_lt_finder = LifetimeFinder { lifetime: lt.span, found: None, seen: vec![] }; ret_lt_finder.visit_ty(ret_ty); - if let [Ty { span, kind: TyKind::Ref(_, mut_ty), .. }] = + if let [Ty { span, kind: TyKind::Ref(_, mut_ty, _), .. }] = &ret_lt_finder.seen[..] { // We might have a situation like @@ -4514,7 +4514,7 @@ struct LifetimeFinder<'ast> { impl<'ast> Visitor<'ast> for LifetimeFinder<'ast> { fn visit_ty(&mut self, t: &'ast Ty) { - if let TyKind::Ref(_, mut_ty) | TyKind::PinnedRef(_, mut_ty) = &t.kind { + if let TyKind::Ref(_, mut_ty, _) | TyKind::PinnedRef(_, mut_ty, _) = &t.kind { self.seen.push(t); if t.span.lo() == self.lifetime.lo() { self.found = Some(&mut_ty.ty); @@ -4534,7 +4534,7 @@ impl<'ast> Visitor<'ast> for RefPrefixSpanFinder { if self.span.is_some() { return; } - if let TyKind::Ref(_, mut_ty) | TyKind::PinnedRef(_, mut_ty) = &t.kind + if let TyKind::Ref(_, mut_ty, _) | TyKind::PinnedRef(_, mut_ty, _) = &t.kind && t.span.lo() == self.lifetime.lo() { self.span = Some(t.span.with_hi(mut_ty.ty.span.lo())); diff --git a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs index 0d9e0bcff48e0..25777b59e2619 100644 --- a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs +++ b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs @@ -1,6 +1,9 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet_with_applicability; -use rustc_ast::ast::{BindingMode, ByRef, Lifetime, Param, PatKind, TyKind}; +use rustc_ast::{ + ViewKind, + ast::{BindingMode, ByRef, Lifetime, Param, PatKind, TyKind}, +}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; @@ -66,20 +69,20 @@ enum Mode { impl EarlyLintPass for NeedlessArbitrarySelfType { fn check_param(&mut self, cx: &EarlyContext<'_>, p: &Param) { - // Bail out if the parameter it's not a receiver or was not written by the user + // Bail out if the parameter is not a receiver or was not written by the user if !p.is_self() || p.span.from_expansion() { return; } - let (path, binding_mode, mutbl) = match &p.ty.kind { + let (path, binding_mode, mutbl, view) = match &p.ty.kind { TyKind::Path(None, path) if let PatKind::Ident(BindingMode(ByRef::No, mutbl), _, _) = p.pat.kind => { - (path, Mode::Value, mutbl) + (path, Mode::Value, mutbl, &ViewKind::Full) }, - TyKind::Ref(lifetime, mut_ty) + TyKind::Ref(lifetime, mut_ty, view) if let TyKind::Path(None, path) = &mut_ty.ty.kind && let PatKind::Ident(BindingMode::NONE, _, _) = p.pat.kind => { - (path, Mode::Ref(*lifetime), mut_ty.mutbl) + (path, Mode::Ref(*lifetime), mut_ty.mutbl, view) }, _ => return, }; @@ -95,7 +98,7 @@ impl EarlyLintPass for NeedlessArbitrarySelfType { "the type of the `self` parameter does not need to be arbitrary", |diag| { let mut applicability = Applicability::MachineApplicable; - let add = match binding_mode { + let before_self = match binding_mode { Mode::Value => String::new(), Mode::Ref(None) => mutbl.ref_prefix_str().to_string(), Mode::Ref(Some(lifetime)) => { @@ -113,10 +116,26 @@ impl EarlyLintPass for NeedlessArbitrarySelfType { }, }; - let mut sugg = vec![(p.ty.span.with_lo(p.span.hi()), String::new())]; - if !add.is_empty() { - sugg.push((p.span.shrink_to_lo(), add)); + let after_self = match view { + ViewKind::Full => String::new(), + ViewKind::Partial { fields, .. } if fields.is_empty() => { + ".{}".to_string() + } + ViewKind::Partial { fields, .. } => { + let fields = fields + .iter() + .map(|field| field.name.as_str()) + .collect::>() + .join(", "); + format!(".{{ {fields} }}") + }, + }; + + let mut sugg = Vec::new(); + if !before_self.is_empty() { + sugg.push((p.span.shrink_to_lo(), before_self)); } + sugg.push((p.ty.span.with_lo(p.span.hi()), after_self)); diag.multipart_suggestion("remove the type", sugg, applicability); }, ); diff --git a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs index 35cfc37b133b2..2d480dca5d3c2 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs @@ -62,7 +62,7 @@ impl RedundantStaticLifetimes { } }, // This is what we are looking for ! - TyKind::Ref(ref optional_lifetime, ref borrow_type) => { + TyKind::Ref(ref optional_lifetime, ref borrow_type, _) => { // Match the 'static lifetime if let Some(lifetime) = *optional_lifetime { match borrow_type.ty.kind { diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index 82142d55e21d8..4aa3913483dce 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -6,6 +6,7 @@ use crate::{both, over}; use rustc_ast::{self as ast, *}; +use rustc_data_structures::fx::FxHashSet; use rustc_span::symbol::Ident; use std::mem; @@ -903,11 +904,14 @@ pub fn eq_ty(l: &Ty, r: &Ty) -> bool { (Slice(l), Slice(r)) => eq_ty(l, r), (Array(le, ls), Array(re, rs)) => eq_ty(le, re) && eq_expr(&ls.value, &rs.value), (Ptr(l), Ptr(r)) => l.mutbl == r.mutbl && eq_ty(&l.ty, &r.ty), - (Ref(ll, l), Ref(rl, r)) => { - both(ll.as_ref(), rl.as_ref(), |l, r| eq_id(l.ident, r.ident)) && l.mutbl == r.mutbl && eq_ty(&l.ty, &r.ty) + (Ref(ll, l, lv), Ref(rl, r, rv)) => { + both(ll.as_ref(), rl.as_ref(), |l, r| eq_id(l.ident, r.ident)) && l.mutbl == r.mutbl && eq_ty(&l.ty, &r.ty) && eq_view(lv, rv) }, - (PinnedRef(ll, l), PinnedRef(rl, r)) => { - both(ll.as_ref(), rl.as_ref(), |l, r| eq_id(l.ident, r.ident)) && l.mutbl == r.mutbl && eq_ty(&l.ty, &r.ty) + (PinnedRef(ll, l, lv), PinnedRef(rl, r, rv)) => { + both(ll.as_ref(), rl.as_ref(), |l, r| eq_id(l.ident, r.ident)) + && l.mutbl == r.mutbl + && eq_ty(&l.ty, &r.ty) + && eq_view(lv, rv) }, (FnPtr(l), FnPtr(r)) => { l.safety == r.safety @@ -924,6 +928,20 @@ pub fn eq_ty(l: &Ty, r: &Ty) -> bool { } } +fn eq_view(lv: &ViewKind, rv: &ViewKind) -> bool { + match (lv, rv) { + (ViewKind::Full, ViewKind::Full) => true, + (ViewKind::Partial { fields: lf, .. }, ViewKind::Partial { fields: rf, .. }) if lf.len() != rf.len() => false, + + (ViewKind::Partial { fields: lf, .. }, ViewKind::Partial { fields: rf, .. }) => { + let lf = lf.iter().copied().collect::>(); + rf.iter().all(|field| lf.contains(field)) + }, + + _ => false, + } +} + pub fn eq_ext(l: &Extern, r: &Extern) -> bool { use Extern::*; match (l, r) { 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 e1382f5b706c0..0ce5869bca71b 100644 --- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs +++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs @@ -265,14 +265,18 @@ fn item_search_pat(item: &Item<'_>) -> (Pat, Pat) { ItemKind::Struct(_, _, VariantData::Struct { .. }) => (Pat::Str("struct"), Pat::Str("}")), ItemKind::Struct(..) => (Pat::Str("struct"), Pat::Str(";")), ItemKind::Union(..) => (Pat::Str("union"), Pat::Str("}")), - ItemKind::Trait { safety: Safety::Unsafe, .. } + ItemKind::Trait { + safety: Safety::Unsafe, .. + } | ItemKind::Impl(Impl { of_trait: Some(TraitImplHeader { safety: Safety::Unsafe, .. }), .. }) => (Pat::Str("unsafe"), Pat::Str("}")), - ItemKind::Trait { is_auto: IsAuto::Yes, .. } => (Pat::Str("auto"), Pat::Str("}")), + ItemKind::Trait { + is_auto: IsAuto::Yes, .. + } => (Pat::Str("auto"), Pat::Str("}")), ItemKind::Trait { .. } => (Pat::Str("trait"), Pat::Str("}")), ItemKind::Impl(_) => (Pat::Str("impl"), Pat::Str("}")), ItemKind::Mod(..) => (Pat::Str("mod"), Pat::Str("")), @@ -425,14 +429,17 @@ fn ty_search_pat(ty: &Ty<'_>) -> (Pat, Pat) { } fn ast_ty_search_pat(ty: &ast::Ty) -> (Pat, Pat) { - use ast::{Extern, FnRetTy, MutTy, Safety, TraitObjectSyntax, TyKind}; + use ast::{Extern, FnRetTy, MutTy, Safety, TraitObjectSyntax, TyKind, ViewKind}; match &ty.kind { TyKind::Slice(..) | TyKind::Array(..) => (Pat::Str("["), Pat::Str("]")), TyKind::Ptr(MutTy { ty, .. }) => (Pat::Str("*"), ast_ty_search_pat(ty).1), - TyKind::Ref(_, MutTy { ty, .. }) | TyKind::PinnedRef(_, MutTy { ty, .. }) => { + TyKind::Ref(_, MutTy { ty, .. }, ViewKind::Full) | TyKind::PinnedRef(_, MutTy { ty, .. }, ViewKind::Full) => { (Pat::Str("&"), ast_ty_search_pat(ty).1) }, + TyKind::Ref(_, MutTy { .. }, ViewKind::Partial { .. }) | TyKind::PinnedRef(_, MutTy { .. }, ViewKind::Partial { .. }) => { + (Pat::Str("&"), Pat::Str("}")) + }, TyKind::FnPtr(fn_ptr) => ( if let Safety::Unsafe(_) = fn_ptr.safety { Pat::Str("unsafe") diff --git a/src/tools/clippy/tests/ui/needless_arbitrary_self_type.fixed b/src/tools/clippy/tests/ui/needless_arbitrary_self_type.fixed index adb9096c9f242..a83505eaba1a9 100644 --- a/src/tools/clippy/tests/ui/needless_arbitrary_self_type.fixed +++ b/src/tools/clippy/tests/ui/needless_arbitrary_self_type.fixed @@ -1,3 +1,4 @@ +#![feature(view_types)] #![warn(clippy::needless_arbitrary_self_type)] #![allow(unused_mut, clippy::needless_lifetimes)] @@ -68,6 +69,11 @@ impl ValType { pub fn mut_ref_mut_ref_good(self: &&mut &mut Self) { unimplemented!(); } + + pub fn view_type(&mut self.{}) { + //~^ needless_arbitrary_self_type + unimplemented!(); + } } trait Foo<'r#struct> { diff --git a/src/tools/clippy/tests/ui/needless_arbitrary_self_type.rs b/src/tools/clippy/tests/ui/needless_arbitrary_self_type.rs index 550546ed24fd7..4154b8b997c5a 100644 --- a/src/tools/clippy/tests/ui/needless_arbitrary_self_type.rs +++ b/src/tools/clippy/tests/ui/needless_arbitrary_self_type.rs @@ -1,3 +1,4 @@ +#![feature(view_types)] #![warn(clippy::needless_arbitrary_self_type)] #![allow(unused_mut, clippy::needless_lifetimes)] @@ -68,6 +69,11 @@ impl ValType { pub fn mut_ref_mut_ref_good(self: &&mut &mut Self) { unimplemented!(); } + + pub fn view_type(self: &mut Self.{}) { + //~^ needless_arbitrary_self_type + unimplemented!(); + } } trait Foo<'r#struct> { diff --git a/src/tools/clippy/tests/ui/needless_arbitrary_self_type.stderr b/src/tools/clippy/tests/ui/needless_arbitrary_self_type.stderr index bb42e5ea63f51..6e50bd0a99382 100644 --- a/src/tools/clippy/tests/ui/needless_arbitrary_self_type.stderr +++ b/src/tools/clippy/tests/ui/needless_arbitrary_self_type.stderr @@ -1,5 +1,5 @@ error: the type of the `self` parameter does not need to be arbitrary - --> tests/ui/needless_arbitrary_self_type.rs:10:16 + --> tests/ui/needless_arbitrary_self_type.rs:11:16 | LL | pub fn bad(self: Self) { | ^^^^^^^^^^ @@ -13,7 +13,7 @@ LL + pub fn bad(self) { | error: the type of the `self` parameter does not need to be arbitrary - --> tests/ui/needless_arbitrary_self_type.rs:19:20 + --> tests/ui/needless_arbitrary_self_type.rs:20:20 | LL | pub fn mut_bad(mut self: Self) { | ^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + pub fn mut_bad(mut self) { | error: the type of the `self` parameter does not need to be arbitrary - --> tests/ui/needless_arbitrary_self_type.rs:28:20 + --> tests/ui/needless_arbitrary_self_type.rs:29:20 | LL | pub fn ref_bad(self: &Self) { | ^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + pub fn ref_bad(&self) { | error: the type of the `self` parameter does not need to be arbitrary - --> tests/ui/needless_arbitrary_self_type.rs:37:38 + --> tests/ui/needless_arbitrary_self_type.rs:38:38 | LL | pub fn ref_bad_with_lifetime<'a>(self: &'a Self) { | ^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + pub fn ref_bad_with_lifetime<'a>(&'a self) { | error: the type of the `self` parameter does not need to be arbitrary - --> tests/ui/needless_arbitrary_self_type.rs:46:24 + --> tests/ui/needless_arbitrary_self_type.rs:47:24 | LL | pub fn mut_ref_bad(self: &mut Self) { | ^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + pub fn mut_ref_bad(&mut self) { | error: the type of the `self` parameter does not need to be arbitrary - --> tests/ui/needless_arbitrary_self_type.rs:55:42 + --> tests/ui/needless_arbitrary_self_type.rs:56:42 | LL | pub fn mut_ref_bad_with_lifetime<'a>(self: &'a mut Self) { | ^^^^^^^^^^^^^^^^^^ @@ -73,7 +73,19 @@ LL + pub fn mut_ref_bad_with_lifetime<'a>(&'a mut self) { | error: the type of the `self` parameter does not need to be arbitrary - --> tests/ui/needless_arbitrary_self_type.rs:74:11 + --> tests/ui/needless_arbitrary_self_type.rs:73:22 + | +LL | pub fn view_type(self: &mut Self.{}) { + | ^^^^^^^^^^^^^^^^^^ + | +help: remove the type + | +LL - pub fn view_type(self: &mut Self.{}) { +LL + pub fn view_type(&mut self.{}) { + | + +error: the type of the `self` parameter does not need to be arbitrary + --> tests/ui/needless_arbitrary_self_type.rs:80:11 | LL | fn f1(self: &'r#struct Self) {} | ^^^^^^^^^^^^^^^^^^^^^ @@ -85,7 +97,7 @@ LL + fn f1(&'r#struct self) {} | error: the type of the `self` parameter does not need to be arbitrary - --> tests/ui/needless_arbitrary_self_type.rs:76:11 + --> tests/ui/needless_arbitrary_self_type.rs:82:11 | LL | fn f2(self: &'r#struct mut Self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -96,5 +108,5 @@ LL - fn f2(self: &'r#struct mut Self) {} LL + fn f2(&'r#struct mut self) {} | -error: aborting due to 8 previous errors +error: aborting due to 9 previous errors diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index 32f71703e019f..f9315de096b53 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -31,7 +31,7 @@ use crate::shape::{Indent, Shape}; use crate::source_map::{LineRangeUtils, SpanUtils}; use crate::spanned::Spanned; use crate::stmt::Stmt; -use crate::types::opaque_ty; +use crate::types::{opaque_ty, rewrite_view}; use crate::utils::*; use crate::vertical::rewrite_with_alignment; use crate::visitor::FmtVisitor; @@ -2393,15 +2393,17 @@ fn rewrite_explicit_self( has_multiple_attr_lines: bool, ) -> RewriteResult { let self_str = match explicit_self.node { - ast::SelfKind::Region(lt, m) => { + ast::SelfKind::Region(lt, m, ref v) => { let mut_str = format_mutability(m); let lifetime_str = rewrite_opt_lifetime(context, lt)?; - format!("&{lifetime_str}{mut_str}self") + let view_str = rewrite_view(v); + format!("&{lifetime_str}{mut_str}self{view_str}") } - ast::SelfKind::Pinned(lt, m) => { + ast::SelfKind::Pinned(lt, m, ref v) => { let mut_str = m.ptr_str(); let lifetime_str = rewrite_opt_lifetime(context, lt)?; - format!("&{lifetime_str}pin {mut_str} self") + let view_str = rewrite_view(v); + format!("&{lifetime_str}pin {mut_str} self{view_str}") } ast::SelfKind::Explicit(ref ty, mutability) => { let type_str = ty.rewrite_result( diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs index e574a9d278265..4f7110e47c51e 100644 --- a/src/tools/rustfmt/src/types.rs +++ b/src/tools/rustfmt/src/types.rs @@ -844,8 +844,8 @@ impl Rewrite for ast::Ty { rewrite_unary_prefix(context, prefix, &*mt.ty, shape) } - ast::TyKind::Ref(ref lifetime, ref mt) - | ast::TyKind::PinnedRef(ref lifetime, ref mt) => { + ast::TyKind::Ref(ref lifetime, ref mt, ref view) + | ast::TyKind::PinnedRef(ref lifetime, ref mt, ref view) => { let mut_str = format_mutability(mt.mutbl); let mut_len = mut_str.len(); let mut result = String::with_capacity(128); @@ -926,6 +926,8 @@ impl Rewrite for ast::Ty { )?; result.push_str(&ty_str); } + let view_str = rewrite_view(view); + result.push_str(&view_str); Ok(result) } @@ -1342,8 +1344,8 @@ pub(crate) fn can_be_overflowed_type( ) -> bool { match ty.kind { ast::TyKind::Tup(..) => context.use_block_indent() && len == 1, - ast::TyKind::Ref(_, ref mutty) - | ast::TyKind::PinnedRef(_, ref mutty) + ast::TyKind::Ref(_, ref mutty, _) + | ast::TyKind::PinnedRef(_, ref mutty, _) | ast::TyKind::Ptr(ref mutty) => can_be_overflowed_type(context, &*mutty.ty, len), _ => false, } @@ -1366,3 +1368,20 @@ pub(crate) fn rewrite_bound_params( Some(result) } } + +pub(crate) fn rewrite_view(v: &ast::ViewKind) -> String { + // FIXME: how should views be formatted? + // FIXME: handle comments. + match v { + ast::ViewKind::Full => String::new(), + ast::ViewKind::Partial { fields, .. } if fields.is_empty() => ".{}".to_string(), + ast::ViewKind::Partial { fields, .. } => { + let fields = fields + .iter() + .map(|field| field.name.as_str()) + .collect::>() + .join(", "); + format!(".{{ {fields} }}") + } + } +} diff --git a/src/tools/rustfmt/tests/source/view-types.rs b/src/tools/rustfmt/tests/source/view-types.rs new file mode 100644 index 0000000000000..161b84ab3082d --- /dev/null +++ b/src/tools/rustfmt/tests/source/view-types.rs @@ -0,0 +1,13 @@ +// Check that `rustfmt` does not remove view type syntax. + +struct Foo { + bar: u8, +} + +impl Foo { + fn a(&mut self.{ bar }) {} + fn c(&mut self.{}) {} + + fn d(a: &mut Self.{ bar }) {} + fn d(a: &mut Self.{}) {} +} diff --git a/src/tools/rustfmt/tests/target/view-types.rs b/src/tools/rustfmt/tests/target/view-types.rs new file mode 100644 index 0000000000000..161b84ab3082d --- /dev/null +++ b/src/tools/rustfmt/tests/target/view-types.rs @@ -0,0 +1,13 @@ +// Check that `rustfmt` does not remove view type syntax. + +struct Foo { + bar: u8, +} + +impl Foo { + fn a(&mut self.{ bar }) {} + fn c(&mut self.{}) {} + + fn d(a: &mut Self.{ bar }) {} + fn d(a: &mut Self.{}) {} +} diff --git a/tests/ui/stats/input-stats.stderr b/tests/ui/stats/input-stats.stderr index a91a15bc63dff..b21ab6cc870d1 100644 --- a/tests/ui/stats/input-stats.stderr +++ b/tests/ui/stats/input-stats.stderr @@ -10,11 +10,11 @@ ast-stats - Impl 152 (NN.N%) 1 ast-stats - Trait 152 (NN.N%) 1 ast-stats - Fn 304 (NN.N%) 2 ast-stats - Use 608 (NN.N%) 4 -ast-stats Ty 896 (NN.N%) 14 64 -ast-stats - Ptr 64 (NN.N%) 1 -ast-stats - Ref 64 (NN.N%) 1 -ast-stats - ImplicitSelf 128 (NN.N%) 2 -ast-stats - Path 640 (NN.N%) 10 +ast-stats Ty 1_120 (NN.N%) 14 80 +ast-stats - Ptr 80 (NN.N%) 1 +ast-stats - Ref 80 (NN.N%) 1 +ast-stats - ImplicitSelf 160 (NN.N%) 2 +ast-stats - Path 800 (NN.N%) 10 ast-stats PathSegment 864 (NN.N%) 36 24 ast-stats Expr 648 (NN.N%) 9 72 ast-stats - InlineAsm 72 (NN.N%) 1 @@ -57,7 +57,7 @@ ast-stats GenericArgs 40 (NN.N%) 1 40 ast-stats - AngleBracketed 40 (NN.N%) 1 ast-stats Crate 40 (NN.N%) 1 40 ast-stats ---------------------------------------------------------------- -ast-stats Total 7_560 127 +ast-stats Total 7_784 127 ast-stats ================================================================ hir-stats ================================================================ hir-stats HIR STATS: input_stats diff --git a/tests/ui/view-types/delim-check.rs b/tests/ui/view-types/delim-check.rs index e32136061a3a2..c7dce971eac70 100644 --- a/tests/ui/view-types/delim-check.rs +++ b/tests/ui/view-types/delim-check.rs @@ -1,8 +1,5 @@ -//@ build-pass - #![feature(view_types)] #![allow(irrefutable_let_patterns)] -#![deny(unused_parens)] struct Foo { bar: usize, @@ -11,6 +8,7 @@ struct Foo { fn main() { let foo = Foo { bar: 42 }; let a = &foo as &Foo.{ bar } else { + //~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed return; }; } diff --git a/tests/ui/view-types/delim-check.stderr b/tests/ui/view-types/delim-check.stderr new file mode 100644 index 0000000000000..a60b7052aaa4d --- /dev/null +++ b/tests/ui/view-types/delim-check.stderr @@ -0,0 +1,13 @@ +error: right curly brace `}` before `else` in a `let...else` statement not allowed + --> $DIR/delim-check.rs:10:32 + | +LL | let a = &foo as &Foo.{ bar } else { + | ^ + | +help: wrap the expression in parentheses + | +LL | let a = &foo as (&Foo.{ bar }) else { + | + + + +error: aborting due to 1 previous error + diff --git a/tests/ui/view-types/syntax-errors.rs b/tests/ui/view-types/syntax-errors.rs index 0a57acaf677dc..d32eb4796157b 100644 --- a/tests/ui/view-types/syntax-errors.rs +++ b/tests/ui/view-types/syntax-errors.rs @@ -8,19 +8,16 @@ struct Foo { impl Foo { fn not_a_field(&mut self.{ _ }, _: &mut Foo.{ _ }) {} - //~^ ERROR expected parameter name - //~| ERROR expected one of - //~| ERROR expected identifier + //~^ ERROR expected identifier, found reserved identifier + //~| ERROR expected identifier, found reserved identifier fn keyword(&mut self.{ where }, _: &mut Foo.{ for }) {} - //~^ ERROR expected parameter name - //~| ERROR expected one of - //~| ERROR expected identifier + //~^ ERROR expected identifier, found keyword + //~| ERROR expected identifier, found keyword fn no_comma(&mut self.{ bar baz }, _: &mut Foo.{ bar baz }) {} - //~^ ERROR expected parameter name - //~| ERROR expected one of - //~| ERROR expected one of + //~^ ERROR expected one of `,` or `}`, found `baz` + //~| ERROR expected one of `,` or `}`, found `baz` } fn main() {} diff --git a/tests/ui/view-types/syntax-errors.stderr b/tests/ui/view-types/syntax-errors.stderr index bc9ffb8e3ec51..a0521b1cf07c0 100644 --- a/tests/ui/view-types/syntax-errors.stderr +++ b/tests/ui/view-types/syntax-errors.stderr @@ -1,17 +1,8 @@ -error: expected parameter name, found `{` - --> $DIR/syntax-errors.rs:10:30 - | -LL | fn not_a_field(&mut self.{ _ }, _: &mut Foo.{ _ }) {} - | ^ expected parameter name - -error: expected one of `)` or `,`, found `.` - --> $DIR/syntax-errors.rs:10:29 +error: expected identifier, found reserved identifier `_` + --> $DIR/syntax-errors.rs:10:32 | LL | fn not_a_field(&mut self.{ _ }, _: &mut Foo.{ _ }) {} - | ^ - | | - | expected one of `)` or `,` - | help: missing `,` + | ^ expected identifier, found reserved identifier error: expected identifier, found reserved identifier `_` --> $DIR/syntax-errors.rs:10:51 @@ -19,23 +10,19 @@ error: expected identifier, found reserved identifier `_` LL | fn not_a_field(&mut self.{ _ }, _: &mut Foo.{ _ }) {} | ^ expected identifier, found reserved identifier -error: expected parameter name, found `{` - --> $DIR/syntax-errors.rs:15:26 +error: expected identifier, found keyword `where` + --> $DIR/syntax-errors.rs:14:28 | LL | fn keyword(&mut self.{ where }, _: &mut Foo.{ for }) {} - | ^ expected parameter name - -error: expected one of `)` or `,`, found `.` - --> $DIR/syntax-errors.rs:15:25 + | ^^^^^ expected identifier, found keyword | -LL | fn keyword(&mut self.{ where }, _: &mut Foo.{ for }) {} - | ^ - | | - | expected one of `)` or `,` - | help: missing `,` +help: escape `where` to use it as an identifier + | +LL | fn keyword(&mut self.{ r#where }, _: &mut Foo.{ for }) {} + | ++ error: expected identifier, found keyword `for` - --> $DIR/syntax-errors.rs:15:51 + --> $DIR/syntax-errors.rs:14:51 | LL | fn keyword(&mut self.{ where }, _: &mut Foo.{ for }) {} | ^^^ expected identifier, found keyword @@ -45,28 +32,21 @@ help: escape `for` to use it as an identifier LL | fn keyword(&mut self.{ where }, _: &mut Foo.{ r#for }) {} | ++ -error: expected parameter name, found `{` - --> $DIR/syntax-errors.rs:20:27 - | -LL | fn no_comma(&mut self.{ bar baz }, _: &mut Foo.{ bar baz }) {} - | ^ expected parameter name - -error: expected one of `)` or `,`, found `.` - --> $DIR/syntax-errors.rs:20:26 +error: expected one of `,` or `}`, found `baz` + --> $DIR/syntax-errors.rs:18:33 | LL | fn no_comma(&mut self.{ bar baz }, _: &mut Foo.{ bar baz }) {} - | ^ - | | - | expected one of `)` or `,` - | help: missing `,` + | -^^^ expected one of `,` or `}` + | | + | help: missing `,` error: expected one of `,` or `}`, found `baz` - --> $DIR/syntax-errors.rs:20:58 + --> $DIR/syntax-errors.rs:18:58 | LL | fn no_comma(&mut self.{ bar baz }, _: &mut Foo.{ bar baz }) {} | -^^^ expected one of `,` or `}` | | | help: missing `,` -error: aborting due to 9 previous errors +error: aborting due to 6 previous errors