Skip to content

Commit b65ae52

Browse files
committed
view-types: store borrows of view types in the AST
1 parent 1d511ce commit b65ae52

30 files changed

Lines changed: 334 additions & 262 deletions

File tree

compiler/rustc_ast/src/ast.rs

Lines changed: 59 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2564,6 +2564,8 @@ pub enum TyKind {
25642564
/// Usually not written directly in user code but indirectly via the macro
25652565
/// `core::field::field_of!(...)`.
25662566
FieldOf(Box<Ty>, Option<Ident>, Ident),
2567+
/// A view of a type. `T.{ field_1, field_2 }`.
2568+
View(Box<Ty>, #[visitable(ignore)] ThinVec<Ident>),
25672569
/// Sometimes we need a dummy value when no error has occurred.
25682570
Dummy,
25692571
/// Placeholder for a kind that has failed to be defined.
@@ -2575,6 +2577,17 @@ impl TyKind {
25752577
matches!(self, TyKind::ImplicitSelf)
25762578
}
25772579

2580+
pub fn as_implicit_self_maybe_wrapped_in_view(&self) -> Option<ViewKind> {
2581+
match self {
2582+
TyKind::ImplicitSelf => Some(ViewKind::Full),
2583+
TyKind::View(ty, fields) if ty.kind.is_implicit_self() => {
2584+
let fields = fields.clone();
2585+
Some(ViewKind::Partial { fields })
2586+
}
2587+
_ => None,
2588+
}
2589+
}
2590+
25782591
pub fn is_unit(&self) -> bool {
25792592
matches!(self, TyKind::Tup(tys) if tys.is_empty())
25802593
}
@@ -2928,6 +2941,12 @@ pub struct Param {
29282941
/// Alternative representation for `Arg`s describing `self` parameter of methods.
29292942
///
29302943
/// E.g., `&mut self` as in `fn foo(&mut self)`.
2944+
#[derive(Clone, Encodable, Decodable, Debug)]
2945+
pub struct SelfParam {
2946+
pub kind: SelfKind,
2947+
pub view: ViewKind,
2948+
}
2949+
29312950
#[derive(Clone, Encodable, Decodable, Debug)]
29322951
pub enum SelfKind {
29332952
/// `self`, `mut self`
@@ -2954,28 +2973,46 @@ impl SelfKind {
29542973
}
29552974
}
29562975

2957-
pub type ExplicitSelf = Spanned<SelfKind>;
2976+
/// Represents how a type is viewed.
2977+
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
2978+
pub enum ViewKind {
2979+
/// `T`. All the fields can be observed.
2980+
Full,
2981+
/// `T.{ foo, bar }`. Only `foo` and `bar` can be observed.
2982+
// FIXME(scrabsha): in the future, we may want to express more complex situations, such as
2983+
// mutably observing some fields while immutably observing others. Something like
2984+
// `T.{ foo, mut bar }`.
2985+
Partial {
2986+
#[visitable(ignore)]
2987+
fields: ThinVec<Ident>,
2988+
},
2989+
}
2990+
2991+
pub type ExplicitSelf = Spanned<SelfParam>;
29582992

29592993
impl Param {
29602994
/// Attempts to cast parameter to `ExplicitSelf`.
29612995
pub fn to_self(&self) -> Option<ExplicitSelf> {
29622996
if let PatKind::Ident(BindingMode(ByRef::No, mutbl), ident, _) = self.pat.kind {
29632997
if ident.name == kw::SelfLower {
2964-
return match self.ty.kind {
2965-
TyKind::ImplicitSelf => Some(respan(self.pat.span, SelfKind::Value(mutbl))),
2966-
TyKind::Ref(lt, MutTy { ref ty, mutbl }) if ty.kind.is_implicit_self() => {
2967-
Some(respan(self.pat.span, SelfKind::Region(lt, mutbl)))
2998+
let (kind, view, span) = match self.ty.kind {
2999+
ref kind if let Some(view) = kind.as_implicit_self_maybe_wrapped_in_view() => {
3000+
(SelfKind::Value(mutbl), view, self.pat.span)
3001+
}
3002+
TyKind::Ref(lt, MutTy { ref ty, mutbl })
3003+
if let Some(view) = ty.kind.as_implicit_self_maybe_wrapped_in_view() =>
3004+
{
3005+
(SelfKind::Region(lt, mutbl), view, self.pat.span)
29683006
}
29693007
TyKind::PinnedRef(lt, MutTy { ref ty, mutbl })
2970-
if ty.kind.is_implicit_self() =>
3008+
if let Some(view) = ty.kind.as_implicit_self_maybe_wrapped_in_view() =>
29713009
{
2972-
Some(respan(self.pat.span, SelfKind::Pinned(lt, mutbl)))
3010+
(SelfKind::Pinned(lt, mutbl), view, self.pat.span)
29733011
}
2974-
_ => Some(respan(
2975-
self.pat.span.to(self.ty.span),
2976-
SelfKind::Explicit(self.ty.clone(), mutbl),
2977-
)),
3012+
_ => (SelfKind::Explicit(self.ty.clone(), mutbl), ViewKind::Full, self.ty.span),
29783013
};
3014+
let param = respan(span, SelfParam { view, kind });
3015+
return Some(param);
29793016
}
29803017
}
29813018
None
@@ -2993,13 +3030,21 @@ impl Param {
29933030
/// Builds a `Param` object from `ExplicitSelf`.
29943031
pub fn from_self(attrs: AttrVec, eself: ExplicitSelf, eself_ident: Ident) -> Param {
29953032
let span = eself.span.to(eself_ident.span);
2996-
let infer_ty = Box::new(Ty {
3033+
let mut infer_ty = Box::new(Ty {
29973034
id: DUMMY_NODE_ID,
29983035
kind: TyKind::ImplicitSelf,
29993036
span: eself_ident.span,
30003037
tokens: None,
30013038
});
3002-
let (mutbl, ty) = match eself.node {
3039+
if let ViewKind::Partial { fields } = eself.node.view {
3040+
infer_ty = Box::new(Ty {
3041+
id: DUMMY_NODE_ID,
3042+
kind: TyKind::View(infer_ty, fields),
3043+
span: eself_ident.span,
3044+
tokens: None,
3045+
});
3046+
}
3047+
let (mutbl, ty) = match eself.node.kind {
30033048
SelfKind::Explicit(ty, mutbl) => (mutbl, ty),
30043049
SelfKind::Value(mutbl) => (mutbl, infer_ty),
30053050
SelfKind::Region(lt, mutbl) => (
@@ -3872,7 +3917,7 @@ impl Fn {
38723917
.inputs
38733918
.first()
38743919
.and_then(|param| param.to_self())
3875-
.is_some_and(|eself| matches!(eself.node, SelfKind::Pinned(None, Mutability::Mut)))
3920+
.is_some_and(|eself| matches!(eself.node.kind, SelfKind::Pinned(None, Mutability::Mut)))
38763921
}
38773922
}
38783923

compiler/rustc_ast/src/util/classify.rs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,8 @@ pub enum TrailingBrace<'a> {
168168
/// Trailing brace in any other expression, such as `a + B {}`. We will
169169
/// suggest wrapping the innermost expression in parentheses: `a + (B {})`.
170170
Expr(&'a ast::Expr),
171+
/// Trailing brace in a type, like the one in `&Foo.{ bar }`
172+
Type(&'a ast::Ty),
171173
}
172174

173175
/// If an expression ends with `}`, returns the innermost expression ending in the `}`
@@ -207,7 +209,7 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<TrailingBrace<'_>> {
207209
| ConstBlock(_) => break Some(TrailingBrace::Expr(expr)),
208210

209211
Cast(_, ty) => {
210-
break type_trailing_braced_mac_call(ty).map(TrailingBrace::MacCall);
212+
break type_trailing_brace(ty);
211213
}
212214

213215
MacCall(mac) => {
@@ -248,13 +250,17 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<TrailingBrace<'_>> {
248250
}
249251
}
250252

251-
/// If the type's last token is `}`, it must be due to a braced macro call, such
252-
/// as in `*const brace! { ... }`. Returns that trailing macro call.
253-
fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> {
253+
/// If a type ends with `}`, return the innermost node ending with the `}`.
254+
///
255+
/// This may be caused by a macro call (`*const brace! { ... }`) or a view type
256+
/// (`&Foo.{ bar }`).
257+
fn type_trailing_brace(mut ty: &ast::Ty) -> Option<TrailingBrace<'_>> {
254258
loop {
255259
match &ty.kind {
256260
ast::TyKind::MacCall(mac) => {
257-
break (mac.args.delim == Delimiter::Brace).then_some(mac);
261+
break (mac.args.delim == Delimiter::Brace)
262+
.then_some(mac.as_ref())
263+
.map(TrailingBrace::MacCall);
258264
}
259265

260266
ast::TyKind::Ptr(mut_ty)
@@ -263,6 +269,8 @@ fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> {
263269
ty = &mut_ty.ty;
264270
}
265271

272+
ast::TyKind::View(..) => break Some(TrailingBrace::Type(ty)),
273+
266274
ast::TyKind::UnsafeBinder(binder) => {
267275
ty = &binder.inner_ty;
268276
}

compiler/rustc_ast/src/visit.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,7 @@ macro_rules! common_visitor_and_walkers {
486486
UnsafeBinderTy,
487487
UnsafeSource,
488488
UseTreeKind,
489+
ViewKind,
489490
VisibilityKind,
490491
WhereBoundPredicate,
491492
WhereClause,

compiler/rustc_ast_lowering/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1611,6 +1611,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
16111611
);
16121612
hir::TyKind::Err(guar)
16131613
}
1614+
TyKind::View(ty, _) => {
1615+
// FIXME(scrabsha): lower view types to HIR.
1616+
return self.lower_ty(ty, itctx);
1617+
}
16141618
TyKind::Dummy => panic!("`TyKind::Dummy` should never be lowered"),
16151619
};
16161620

compiler/rustc_ast_pretty/src/pprust/state.rs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use rustc_ast::util::comments::{Comment, CommentStyle};
1717
use rustc_ast::{
1818
self as ast, AttrArgs, BindingMode, BlockCheckMode, ByRef, DelimArgs, GenericArg, GenericBound,
1919
InlineAsmOperand, InlineAsmOptions, InlineAsmRegOrRegClass, InlineAsmTemplatePiece, PatKind,
20-
RangeEnd, RangeSyntax, Safety, SelfKind, Term, attr,
20+
RangeEnd, RangeSyntax, Safety, SelfKind, Term, ViewKind, attr,
2121
};
2222
use rustc_span::edition::Edition;
2323
use rustc_span::source_map::SourceMap;
@@ -1255,6 +1255,20 @@ impl<'a> State<'a> {
12551255
}
12561256
}
12571257

1258+
fn print_view(&mut self, fields: &[Ident]) {
1259+
self.word(".{");
1260+
1261+
if !fields.is_empty() {
1262+
self.space();
1263+
self.commasep(Consistent, fields, |s, field| {
1264+
s.print_ident(*field);
1265+
});
1266+
self.space();
1267+
}
1268+
1269+
self.word("}");
1270+
}
1271+
12581272
pub fn print_assoc_item_constraint(&mut self, constraint: &ast::AssocItemConstraint) {
12591273
self.print_ident(constraint.ident);
12601274
if let Some(args) = constraint.gen_args.as_ref() {
@@ -1437,6 +1451,10 @@ impl<'a> State<'a> {
14371451
self.end(ib);
14381452
self.pclose();
14391453
}
1454+
ast::TyKind::View(ty, fields) => {
1455+
self.print_type(ty);
1456+
self.print_view(fields);
1457+
}
14401458
}
14411459
self.end(ib);
14421460
}
@@ -2053,7 +2071,7 @@ impl<'a> State<'a> {
20532071
}
20542072

20552073
fn print_explicit_self(&mut self, explicit_self: &ast::ExplicitSelf) {
2056-
match &explicit_self.node {
2074+
match &explicit_self.node.kind {
20572075
SelfKind::Value(m) => {
20582076
self.print_mutability(*m, false);
20592077
self.word("self")
@@ -2078,6 +2096,10 @@ impl<'a> State<'a> {
20782096
self.print_type(typ)
20792097
}
20802098
}
2099+
2100+
if let ViewKind::Partial { fields } = &explicit_self.node.view {
2101+
self.print_view(fields);
2102+
}
20812103
}
20822104

20832105
fn print_coroutine_kind(&mut self, coroutine_kind: ast::CoroutineKind) {

compiler/rustc_ast_pretty/src/pprust/tests.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use rustc_ast as ast;
22
use rustc_span::{DUMMY_SP, Ident, create_default_session_globals_then};
3-
use thin_vec::ThinVec;
3+
use thin_vec::{ThinVec, thin_vec};
44

55
use super::*;
66

@@ -22,6 +22,12 @@ fn variant_to_string(var: &ast::Variant) -> String {
2222
to_string(|s| s.print_variant(var))
2323
}
2424

25+
fn ty_to_string(ty: &ast::Ty) -> String {
26+
to_string(|s| {
27+
s.print_type(ty);
28+
})
29+
}
30+
2531
#[test]
2632
fn test_fun_to_string() {
2733
create_default_session_globals_then(|| {
@@ -60,3 +66,26 @@ fn test_variant_to_string() {
6066
assert_eq!(varstr, "principal_skinner");
6167
})
6268
}
69+
70+
#[test]
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/deriving/generic/ty.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
//! when specifying impls to be derived.
33
44
pub(crate) use Ty::*;
5-
use rustc_ast::{self as ast, Expr, GenericArg, GenericParamKind, Generics, SelfKind, TyKind};
5+
use rustc_ast::{
6+
self as ast, Expr, GenericArg, GenericParamKind, Generics, SelfKind, TyKind, ViewKind,
7+
};
68
use rustc_expand::base::ExtCtxt;
79
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, respan};
810
use thin_vec::ThinVec;
@@ -200,6 +202,8 @@ impl Bounds {
200202
pub(crate) fn get_explicit_self(cx: &ExtCtxt<'_>, span: Span) -> (Box<Expr>, ast::ExplicitSelf) {
201203
// This constructs a fresh `self` path.
202204
let self_path = cx.expr_self(span);
203-
let self_ty = respan(span, SelfKind::Region(None, ast::Mutability::Not));
205+
let kind = SelfKind::Region(None, ast::Mutability::Not);
206+
let view = ViewKind::Full;
207+
let self_ty = respan(span, ast::SelfParam { kind, view });
204208
(self_path, self_ty)
205209
}

compiler/rustc_parse/src/errors.rs

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1058,11 +1058,9 @@ pub(crate) struct LabeledLoopInBreak {
10581058

10591059
#[derive(Subdiagnostic)]
10601060
pub(crate) enum WrapInParentheses {
1061-
#[multipart_suggestion(
1062-
"wrap the expression in parentheses",
1063-
applicability = "machine-applicable"
1064-
)]
1065-
Expression {
1061+
#[multipart_suggestion("wrap the {$kind} in parentheses", applicability = "machine-applicable")]
1062+
NonMacro {
1063+
kind: WrapInParenthesesNodeKind,
10661064
#[suggestion_part(code = "(")]
10671065
left: Span,
10681066
#[suggestion_part(code = ")")]
@@ -1080,6 +1078,22 @@ pub(crate) enum WrapInParentheses {
10801078
},
10811079
}
10821080

1081+
pub(crate) enum WrapInParenthesesNodeKind {
1082+
Expression,
1083+
Type,
1084+
}
1085+
1086+
impl IntoDiagArg for WrapInParenthesesNodeKind {
1087+
fn into_diag_arg(self, _path: &mut Option<PathBuf>) -> DiagArgValue {
1088+
let str = match self {
1089+
WrapInParenthesesNodeKind::Expression => "expression",
1090+
WrapInParenthesesNodeKind::Type => "type",
1091+
};
1092+
1093+
DiagArgValue::Str(Cow::Borrowed(str))
1094+
}
1095+
}
1096+
10831097
#[derive(Diagnostic)]
10841098
#[diag("this is a block expression, not an array")]
10851099
pub(crate) struct ArrayBracketsInsteadOfBraces {

compiler/rustc_parse/src/parser/expr.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1915,7 +1915,8 @@ impl<'a> Parser<'a> {
19151915
let lexpr = self.parse_expr_labeled(label, true)?;
19161916
self.dcx().emit_err(errors::LabeledLoopInBreak {
19171917
span: lexpr.span,
1918-
sub: errors::WrapInParentheses::Expression {
1918+
sub: errors::WrapInParentheses::NonMacro {
1919+
kind: errors::WrapInParenthesesNodeKind::Expression,
19191920
left: lexpr.span.shrink_to_lo(),
19201921
right: lexpr.span.shrink_to_hi(),
19211922
},

0 commit comments

Comments
 (0)