Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
72 changes: 46 additions & 26 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down Expand Up @@ -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()))?
Expand Down Expand Up @@ -2473,7 +2475,8 @@ impl From<Box<Ty>> 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;
}
Expand Down Expand Up @@ -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<Lifetime>, MutTy),
Ref(#[visitable(extra = LifetimeCtxt::Ref)] Option<Lifetime>, 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<Lifetime>, MutTy),
PinnedRef(#[visitable(extra = LifetimeCtxt::Ref)] Option<Lifetime>, MutTy, ViewKind),
/// A function pointer type (e.g., `fn(usize) -> bool`).
FnPtr(Box<FnPtrTy>),
/// An unsafe existential lifetime binder (e.g., `unsafe<'a> &'a ()`).
Expand Down Expand Up @@ -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<Ident>,
},
}

/// 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`.
Expand Down Expand Up @@ -2933,21 +2951,21 @@ pub struct Param {
pub enum SelfKind {
/// `self`, `mut self`
Value(Mutability),
/// `&'lt self`, `&'lt mut self`
Region(Option<Lifetime>, Mutability),
/// `&'lt pin const self`, `&'lt pin mut self`
Pinned(Option<Lifetime>, Mutability),
/// `&'lt self`, `&'lt mut self`, `&'lt mut self.{ a, b }`
Region(Option<Lifetime>, Mutability, ViewKind),
/// `&'lt pin const self`, `&'lt pin mut self`, `&'lt pin mut self.{ a, b }`.
Pinned(Option<Lifetime>, Mutability, ViewKind),
/// `self: TYPE`, `mut self: TYPE`
Explicit(Box<Ty>, Mutability),
}

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")
}
Expand All @@ -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),
Expand Down Expand Up @@ -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,
}),
Expand Down Expand Up @@ -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
}
26 changes: 19 additions & 7 deletions compiler/rustc_ast/src/util/classify.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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 `}`
Expand Down Expand Up @@ -205,7 +208,7 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<TrailingBrace<'_>> {
| 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) => {
Expand Down Expand Up @@ -246,21 +249,30 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<TrailingBrace<'_>> {
}
}

/// 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<TrailingBrace<'_>> {
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;
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_ast/src/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,7 @@ macro_rules! common_visitor_and_walkers {
UnsafeBinderTy,
UnsafeSource,
UseTreeKind,
ViewKind,
VisibilityKind,
WhereBoundPredicate,
WhereClause,
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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 {
Expand Down
32 changes: 23 additions & 9 deletions compiler/rustc_ast_pretty/src/pprust/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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("!");
Expand Down Expand Up @@ -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);
}
}
}
Expand Down
39 changes: 39 additions & 0 deletions compiler/rustc_ast_pretty/src/pprust/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,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 }");
});
}
Loading