Implement &pin patterns and ref pin bindings
This commit is contained in:
parent
6647be9364
commit
5ef48ed448
62 changed files with 886 additions and 240 deletions
|
|
@ -648,9 +648,10 @@ impl Pat {
|
|||
PatKind::Path(qself, path) => TyKind::Path(qself.clone(), path.clone()),
|
||||
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, mutbl) => {
|
||||
pat.to_ty().map(|ty| TyKind::Ref(None, MutTy { ty, mutbl: *mutbl }))?
|
||||
}
|
||||
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 }),
|
||||
})?,
|
||||
// A slice/array pattern `[P]` can be reparsed as `[T]`, an unsized array,
|
||||
// when `P` can be reparsed as a type `T`.
|
||||
PatKind::Slice(pats) if let [pat] = pats.as_slice() => {
|
||||
|
|
@ -696,7 +697,7 @@ impl Pat {
|
|||
// Trivial wrappers over inner patterns.
|
||||
PatKind::Box(s)
|
||||
| PatKind::Deref(s)
|
||||
| PatKind::Ref(s, _)
|
||||
| PatKind::Ref(s, _, _)
|
||||
| PatKind::Paren(s)
|
||||
| PatKind::Guard(s, _) => s.walk(it),
|
||||
|
||||
|
|
@ -717,7 +718,7 @@ impl Pat {
|
|||
/// Strip off all reference patterns (`&`, `&mut`) and return the inner pattern.
|
||||
pub fn peel_refs(&self) -> &Pat {
|
||||
let mut current = self;
|
||||
while let PatKind::Ref(inner, _) = ¤t.kind {
|
||||
while let PatKind::Ref(inner, _, _) = ¤t.kind {
|
||||
current = inner;
|
||||
}
|
||||
current
|
||||
|
|
@ -765,7 +766,9 @@ impl Pat {
|
|||
PatKind::Missing => unreachable!(),
|
||||
PatKind::Wild => Some("_".to_string()),
|
||||
PatKind::Ident(BindingMode::NONE, ident, None) => Some(format!("{ident}")),
|
||||
PatKind::Ref(pat, mutbl) => pat.descr().map(|d| format!("&{}{d}", mutbl.prefix_str())),
|
||||
PatKind::Ref(pat, pinned, mutbl) => {
|
||||
pat.descr().map(|d| format!("&{}{d}", pinned.prefix_str(*mutbl)))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
@ -913,7 +916,7 @@ pub enum PatKind {
|
|||
Deref(Box<Pat>),
|
||||
|
||||
/// A reference pattern (e.g., `&mut (a, b)`).
|
||||
Ref(Box<Pat>, Mutability),
|
||||
Ref(Box<Pat>, Pinnedness, Mutability),
|
||||
|
||||
/// A literal, const block or path.
|
||||
Expr(Box<Expr>),
|
||||
|
|
|
|||
|
|
@ -317,4 +317,15 @@ impl Pinnedness {
|
|||
pub fn is_pinned(self) -> bool {
|
||||
matches!(self, Self::Pinned)
|
||||
}
|
||||
|
||||
/// Returns `""` (empty string), "mut", `"pin mut "` or `"pin const "` depending
|
||||
/// on the pinnedness and mutability.
|
||||
pub fn prefix_str(self, mutbl: Mutability) -> &'static str {
|
||||
match (self, mutbl) {
|
||||
(Pinnedness::Pinned, Mutability::Mut) => "pin mut ",
|
||||
(Pinnedness::Pinned, Mutability::Not) => "pin const ",
|
||||
(Pinnedness::Not, Mutability::Mut) => "mut ",
|
||||
(Pinnedness::Not, Mutability::Not) => "",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -124,8 +124,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
PatKind::Deref(inner) => {
|
||||
break hir::PatKind::Deref(self.lower_pat(inner));
|
||||
}
|
||||
PatKind::Ref(inner, mutbl) => {
|
||||
break hir::PatKind::Ref(self.lower_pat(inner), *mutbl);
|
||||
PatKind::Ref(inner, pinned, mutbl) => {
|
||||
break hir::PatKind::Ref(self.lower_pat(inner), *pinned, *mutbl);
|
||||
}
|
||||
PatKind::Range(e1, e2, Spanned { node: end, .. }) => {
|
||||
break hir::PatKind::Range(
|
||||
|
|
|
|||
|
|
@ -1807,8 +1807,14 @@ impl<'a> State<'a> {
|
|||
self.print_pat(inner);
|
||||
self.pclose();
|
||||
}
|
||||
PatKind::Ref(inner, mutbl) => {
|
||||
PatKind::Ref(inner, pinned, mutbl) => {
|
||||
self.word("&");
|
||||
if pinned.is_pinned() {
|
||||
self.word("pin ");
|
||||
if mutbl.is_not() {
|
||||
self.word("const ");
|
||||
}
|
||||
}
|
||||
if mutbl.is_mut() {
|
||||
self.word("mut ");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -867,11 +867,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
for (binding_span, opt_ref_pat) in finder.ref_pat_for_binding {
|
||||
if let Some(ref_pat) = opt_ref_pat
|
||||
&& !finder.cannot_remove.contains(&ref_pat.hir_id)
|
||||
&& let hir::PatKind::Ref(subpat, mutbl) = ref_pat.kind
|
||||
&& let hir::PatKind::Ref(subpat, pinned, mutbl) = ref_pat.kind
|
||||
&& let Some(ref_span) = ref_pat.span.trim_end(subpat.span)
|
||||
{
|
||||
let pinned_str = if pinned.is_pinned() { "pinned " } else { "" };
|
||||
let mutable_str = if mutbl.is_mut() { "mutable " } else { "" };
|
||||
let msg = format!("consider removing the {mutable_str}borrow");
|
||||
let msg = format!("consider removing the {pinned_str}{mutable_str}borrow");
|
||||
suggestions.push((ref_span, msg, "".to_string()));
|
||||
} else {
|
||||
let msg = "consider borrowing the pattern binding".to_string();
|
||||
|
|
|
|||
|
|
@ -772,11 +772,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
&& let Some(hir_id) = (BindingFinder { span: pat_span }).visit_body(&body).break_value()
|
||||
&& let node = self.infcx.tcx.hir_node(hir_id)
|
||||
&& let hir::Node::LetStmt(hir::LetStmt {
|
||||
pat: hir::Pat { kind: hir::PatKind::Ref(_, _), .. },
|
||||
pat: hir::Pat { kind: hir::PatKind::Ref(_, _, _), .. },
|
||||
..
|
||||
})
|
||||
| hir::Node::Param(Param {
|
||||
pat: hir::Pat { kind: hir::PatKind::Ref(_, _), .. },
|
||||
pat: hir::Pat { kind: hir::PatKind::Ref(_, _, _), .. },
|
||||
..
|
||||
}) = node
|
||||
{
|
||||
|
|
@ -1494,7 +1494,7 @@ impl<'tcx> Visitor<'tcx> for BindingFinder {
|
|||
}
|
||||
|
||||
fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) -> Self::Result {
|
||||
if let hir::Pat { kind: hir::PatKind::Ref(_, _), span, .. } = param.pat
|
||||
if let hir::Pat { kind: hir::PatKind::Ref(_, _, _), span, .. } = param.pat
|
||||
&& *span == self.span
|
||||
{
|
||||
ControlFlow::Break(param.hir_id)
|
||||
|
|
|
|||
|
|
@ -1722,7 +1722,9 @@ impl<'hir> Pat<'hir> {
|
|||
match self.kind {
|
||||
Missing => unreachable!(),
|
||||
Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Err(_) => true,
|
||||
Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) | Guard(s, _) => s.walk_short_(it),
|
||||
Box(s) | Deref(s) | Ref(s, _, _) | Binding(.., Some(s)) | Guard(s, _) => {
|
||||
s.walk_short_(it)
|
||||
}
|
||||
Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk_short_(it)),
|
||||
TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().all(|p| p.walk_short_(it)),
|
||||
Slice(before, slice, after) => {
|
||||
|
|
@ -1749,7 +1751,7 @@ impl<'hir> Pat<'hir> {
|
|||
use PatKind::*;
|
||||
match self.kind {
|
||||
Missing | Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Err(_) => {}
|
||||
Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) | Guard(s, _) => s.walk_(it),
|
||||
Box(s) | Deref(s) | Ref(s, _, _) | Binding(.., Some(s)) | Guard(s, _) => s.walk_(it),
|
||||
Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk_(it)),
|
||||
TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().for_each(|p| p.walk_(it)),
|
||||
Slice(before, slice, after) => {
|
||||
|
|
@ -1938,7 +1940,7 @@ pub enum PatKind<'hir> {
|
|||
Deref(&'hir Pat<'hir>),
|
||||
|
||||
/// A reference pattern (e.g., `&mut (a, b)`).
|
||||
Ref(&'hir Pat<'hir>, Mutability),
|
||||
Ref(&'hir Pat<'hir>, Pinnedness, Mutability),
|
||||
|
||||
/// A literal, const block or path.
|
||||
Expr(&'hir PatExpr<'hir>),
|
||||
|
|
|
|||
|
|
@ -752,7 +752,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) -> V:
|
|||
}
|
||||
PatKind::Box(ref subpattern)
|
||||
| PatKind::Deref(ref subpattern)
|
||||
| PatKind::Ref(ref subpattern, _) => {
|
||||
| PatKind::Ref(ref subpattern, _, _) => {
|
||||
try_visit!(visitor.visit_pat(subpattern));
|
||||
}
|
||||
PatKind::Binding(_, _hir_id, ident, ref optional_subpattern) => {
|
||||
|
|
|
|||
|
|
@ -593,7 +593,7 @@ fn resolve_local<'tcx>(
|
|||
is_binding_pat(subpat)
|
||||
}
|
||||
|
||||
PatKind::Ref(_, _)
|
||||
PatKind::Ref(_, _, _)
|
||||
| PatKind::Binding(hir::BindingMode(hir::ByRef::No, _), ..)
|
||||
| PatKind::Missing
|
||||
| PatKind::Wild
|
||||
|
|
|
|||
|
|
@ -2028,9 +2028,15 @@ impl<'a> State<'a> {
|
|||
self.print_pat(inner);
|
||||
self.pclose();
|
||||
}
|
||||
PatKind::Ref(inner, mutbl) => {
|
||||
PatKind::Ref(inner, pinned, mutbl) => {
|
||||
let is_range_inner = matches!(inner.kind, PatKind::Range(..));
|
||||
self.word("&");
|
||||
if pinned.is_pinned() {
|
||||
self.word("pin ");
|
||||
if mutbl.is_not() {
|
||||
self.word("const ");
|
||||
}
|
||||
}
|
||||
self.word(mutbl.prefix_str());
|
||||
if is_range_inner {
|
||||
self.popen();
|
||||
|
|
|
|||
|
|
@ -523,7 +523,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
| hir::PatKind::TupleStruct(_, _, _)
|
||||
| hir::PatKind::Tuple(_, _)
|
||||
| hir::PatKind::Box(_)
|
||||
| hir::PatKind::Ref(_, _)
|
||||
| hir::PatKind::Ref(_, _, _)
|
||||
| hir::PatKind::Deref(_)
|
||||
| hir::PatKind::Expr(_)
|
||||
| hir::PatKind::Range(_, _, _)
|
||||
|
|
|
|||
|
|
@ -1231,7 +1231,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
debug!("pat_ty(pat={:?}) found adjustment `{:?}`", pat, first_adjust);
|
||||
return Ok(first_adjust.source);
|
||||
}
|
||||
} else if let PatKind::Ref(subpat, _) = pat.kind
|
||||
} else if let PatKind::Ref(subpat, _, _) = pat.kind
|
||||
&& self.cx.typeck_results().skipped_ref_pats().contains(pat.hir_id)
|
||||
{
|
||||
return self.pat_ty_adjusted(subpat);
|
||||
|
|
@ -1817,13 +1817,13 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
self.cat_pattern(place_with_id, subpat, op)?;
|
||||
}
|
||||
|
||||
PatKind::Ref(subpat, _)
|
||||
PatKind::Ref(subpat, _, _)
|
||||
if self.cx.typeck_results().skipped_ref_pats().contains(pat.hir_id) =>
|
||||
{
|
||||
self.cat_pattern(place_with_id, subpat, op)?;
|
||||
}
|
||||
|
||||
PatKind::Box(subpat) | PatKind::Ref(subpat, _) => {
|
||||
PatKind::Box(subpat) | PatKind::Ref(subpat, _, _) => {
|
||||
// box p1, &p1, &mut p1. we can ignore the mutability of
|
||||
// PatKind::Ref since that information is already contained
|
||||
// in the type.
|
||||
|
|
|
|||
|
|
@ -2610,7 +2610,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let mut current_node = parent_node;
|
||||
|
||||
while let Node::Pat(parent_pat) = current_node {
|
||||
if let hir::PatKind::Ref(_, mutability) = parent_pat.kind {
|
||||
if let hir::PatKind::Ref(_, _, mutability) = parent_pat.kind {
|
||||
ref_muts.push(mutability);
|
||||
current_node = self.tcx.parent_hir_node(parent_pat.hir_id);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@ struct TopInfo<'tcx> {
|
|||
#[derive(Copy, Clone)]
|
||||
struct PatInfo<'tcx> {
|
||||
binding_mode: ByRef,
|
||||
max_pinnedness: PinnednessCap,
|
||||
max_ref_mutbl: MutblCap,
|
||||
top_info: TopInfo<'tcx>,
|
||||
decl_origin: Option<DeclOrigin<'tcx>>,
|
||||
|
|
@ -241,6 +242,19 @@ impl MutblCap {
|
|||
}
|
||||
}
|
||||
|
||||
/// `ref` or `ref mut` bindings (not pinned, explicitly or match-ergonomics) are only allowed behind
|
||||
/// an `&pin` reference if the binding's type is `Unpin`.
|
||||
///
|
||||
/// Normally, the borrow checker enforces this (not implemented yet), but we track it here for better
|
||||
/// diagnostics.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
enum PinnednessCap {
|
||||
/// No restriction on pinnedness.
|
||||
Not,
|
||||
/// Pinnedness restricted to pinned.
|
||||
Pinned,
|
||||
}
|
||||
|
||||
/// Variations on RFC 3627's Rule 4: when do reference patterns match against inherited references?
|
||||
///
|
||||
/// "Inherited reference" designates the `&`/`&mut` types that arise from using match ergonomics, i.e.
|
||||
|
|
@ -374,6 +388,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let top_info = TopInfo { expected, origin_expr, span, hir_id: pat.hir_id };
|
||||
let pat_info = PatInfo {
|
||||
binding_mode: ByRef::No,
|
||||
max_pinnedness: PinnednessCap::Not,
|
||||
max_ref_mutbl: MutblCap::Mut,
|
||||
top_info,
|
||||
decl_origin,
|
||||
|
|
@ -489,22 +504,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let old_pat_info = pat_info;
|
||||
let pat_info = PatInfo { current_depth: old_pat_info.current_depth + 1, ..old_pat_info };
|
||||
|
||||
let adjust_binding_mode = |inner_pinnedness, inner_mutability| {
|
||||
match pat_info.binding_mode {
|
||||
// If default binding mode is by value, make it `ref`, `ref mut`, `ref pin const`
|
||||
// or `ref pin mut` (depending on whether we observe `&`, `&mut`, `&pin const` or
|
||||
// `&pin mut`).
|
||||
ByRef::No => ByRef::Yes(inner_pinnedness, inner_mutability),
|
||||
// When `ref mut`, stay a `ref mut` (on `&mut`) or downgrade to `ref` (on `&`).
|
||||
// Pinnedness is preserved.
|
||||
ByRef::Yes(pinnedness, Mutability::Mut) => ByRef::Yes(pinnedness, inner_mutability),
|
||||
// Once a `ref`, always a `ref`.
|
||||
// This is because a `& &mut` cannot mutate the underlying value.
|
||||
// Pinnedness is preserved.
|
||||
ByRef::Yes(pinnedness, Mutability::Not) => ByRef::Yes(pinnedness, Mutability::Not),
|
||||
}
|
||||
};
|
||||
|
||||
match pat.kind {
|
||||
// Peel off a `&` or `&mut`from the scrutinee type. See the examples in
|
||||
// `tests/ui/rfcs/rfc-2005-default-binding-mode`.
|
||||
|
|
@ -524,19 +523,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
.or_default()
|
||||
.push(PatAdjustment { kind: PatAdjust::BuiltinDeref, source: expected });
|
||||
|
||||
let mut binding_mode = adjust_binding_mode(Pinnedness::Not, inner_mutability);
|
||||
|
||||
let mut max_ref_mutbl = pat_info.max_ref_mutbl;
|
||||
if self.downgrade_mut_inside_shared() {
|
||||
binding_mode = binding_mode.cap_ref_mutability(max_ref_mutbl.as_mutbl());
|
||||
}
|
||||
if matches!(binding_mode, ByRef::Yes(_, Mutability::Not)) {
|
||||
max_ref_mutbl = MutblCap::Not;
|
||||
}
|
||||
debug!("default binding mode is now {:?}", binding_mode);
|
||||
|
||||
// Use the old pat info to keep `current_depth` to its old value.
|
||||
let new_pat_info = PatInfo { binding_mode, max_ref_mutbl, ..old_pat_info };
|
||||
let new_pat_info =
|
||||
self.adjust_pat_info(Pinnedness::Not, inner_mutability, old_pat_info);
|
||||
|
||||
// Recurse with the new expected type.
|
||||
self.check_pat_inner(pat, opt_path_res, adjust_mode, inner_ty, new_pat_info)
|
||||
}
|
||||
|
|
@ -569,20 +559,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
});
|
||||
}
|
||||
|
||||
let binding_mode = adjust_binding_mode(Pinnedness::Pinned, inner_mutability);
|
||||
// If the pinnedness is `Not`, it means the pattern is unpinned
|
||||
// and thus requires an `Unpin` bound.
|
||||
if matches!(binding_mode, ByRef::Yes(Pinnedness::Not, _)) {
|
||||
self.register_bound(
|
||||
inner_ty,
|
||||
self.tcx.require_lang_item(hir::LangItem::Unpin, pat.span),
|
||||
self.misc(pat.span),
|
||||
)
|
||||
}
|
||||
debug!("default binding mode is now {:?}", binding_mode);
|
||||
|
||||
// Use the old pat info to keep `current_depth` to its old value.
|
||||
let new_pat_info = PatInfo { binding_mode, ..old_pat_info };
|
||||
let new_pat_info =
|
||||
self.adjust_pat_info(Pinnedness::Pinned, inner_mutability, old_pat_info);
|
||||
|
||||
self.check_deref_pattern(
|
||||
pat,
|
||||
|
|
@ -689,13 +668,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, pat_info),
|
||||
PatKind::Deref(inner) => self.check_pat_deref(pat.span, inner, expected, pat_info),
|
||||
PatKind::Ref(inner, mutbl) => self.check_pat_ref(pat, inner, mutbl, expected, pat_info),
|
||||
PatKind::Ref(inner, pinned, mutbl) => {
|
||||
self.check_pat_ref(pat, inner, pinned, mutbl, expected, pat_info)
|
||||
}
|
||||
PatKind::Slice(before, slice, after) => {
|
||||
self.check_pat_slice(pat.span, before, slice, after, expected, pat_info)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn adjust_pat_info(
|
||||
&self,
|
||||
inner_pinnedness: Pinnedness,
|
||||
inner_mutability: Mutability,
|
||||
pat_info: PatInfo<'tcx>,
|
||||
) -> PatInfo<'tcx> {
|
||||
let mut binding_mode = match pat_info.binding_mode {
|
||||
// If default binding mode is by value, make it `ref`, `ref mut`, `ref pin const`
|
||||
// or `ref pin mut` (depending on whether we observe `&`, `&mut`, `&pin const` or
|
||||
// `&pin mut`).
|
||||
ByRef::No => ByRef::Yes(inner_pinnedness, inner_mutability),
|
||||
ByRef::Yes(pinnedness, mutability) => {
|
||||
let pinnedness = match pinnedness {
|
||||
// When `ref`, stay a `ref` (on `&`) or downgrade to `ref pin` (on `&pin`).
|
||||
Pinnedness::Not => inner_pinnedness,
|
||||
// When `ref pin`, stay a `ref pin`.
|
||||
// This is because we cannot get an `&mut T` from `&mut &pin mut T` unless `T: Unpin`.
|
||||
// Note that `&T` and `&mut T` are `Unpin`, which implies
|
||||
// `& &pin const T` <-> `&pin const &T` and `&mut &pin mut T` <-> `&pin mut &mut T`
|
||||
// (i.e. mutually coercible).
|
||||
Pinnedness::Pinned => Pinnedness::Pinned,
|
||||
};
|
||||
|
||||
let mutability = match mutability {
|
||||
// When `ref mut`, stay a `ref mut` (on `&mut`) or downgrade to `ref` (on `&`).
|
||||
Mutability::Mut => inner_mutability,
|
||||
// Once a `ref`, always a `ref`.
|
||||
// This is because a `& &mut` cannot mutate the underlying value.
|
||||
Mutability::Not => Mutability::Not,
|
||||
};
|
||||
ByRef::Yes(pinnedness, mutability)
|
||||
}
|
||||
};
|
||||
|
||||
let PatInfo { mut max_ref_mutbl, mut max_pinnedness, .. } = pat_info;
|
||||
if self.downgrade_mut_inside_shared() {
|
||||
binding_mode = binding_mode.cap_ref_mutability(max_ref_mutbl.as_mutbl());
|
||||
}
|
||||
match binding_mode {
|
||||
ByRef::Yes(_, Mutability::Not) => max_ref_mutbl = MutblCap::Not,
|
||||
ByRef::Yes(Pinnedness::Pinned, _) => max_pinnedness = PinnednessCap::Pinned,
|
||||
_ => {}
|
||||
}
|
||||
debug!("default binding mode is now {:?}", binding_mode);
|
||||
PatInfo { binding_mode, max_pinnedness, max_ref_mutbl, ..pat_info }
|
||||
}
|
||||
|
||||
fn check_deref_pattern(
|
||||
&self,
|
||||
pat: &'tcx Pat<'tcx>,
|
||||
|
|
@ -1195,6 +1223,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
};
|
||||
|
||||
// If there exists a pinned reference in the pattern but the binding is not pinned,
|
||||
// it means the binding is unpinned and thus requires an `Unpin` bound.
|
||||
if pat_info.max_pinnedness == PinnednessCap::Pinned
|
||||
&& matches!(bm.0, ByRef::Yes(Pinnedness::Not, _))
|
||||
{
|
||||
self.register_bound(
|
||||
expected,
|
||||
self.tcx.require_lang_item(hir::LangItem::Unpin, pat.span),
|
||||
self.misc(pat.span),
|
||||
)
|
||||
}
|
||||
|
||||
if matches!(bm.0, ByRef::Yes(_, Mutability::Mut))
|
||||
&& let MutblCap::WeaklyNot(and_pat_span) = pat_info.max_ref_mutbl
|
||||
{
|
||||
|
|
@ -1223,22 +1263,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
let local_ty = self.local_ty(pat.span, pat.hir_id);
|
||||
let eq_ty = match bm.0 {
|
||||
ByRef::Yes(Pinnedness::Not, mutbl) => {
|
||||
ByRef::Yes(pinnedness, mutbl) => {
|
||||
// If the binding is like `ref x | ref mut x`,
|
||||
// then `x` is assigned a value of type `&M T` where M is the
|
||||
// mutability and T is the expected type.
|
||||
//
|
||||
// Under pin ergonomics, if the binding is like `ref pin const|mut x`,
|
||||
// then `x` is assigned a value of type `&pin M T` where M is the
|
||||
// mutability and T is the expected type.
|
||||
//
|
||||
// `x` is assigned a value of type `&M T`, hence `&M T <: typeof(x)`
|
||||
// is required. However, we use equality, which is stronger.
|
||||
// See (note_1) for an explanation.
|
||||
self.new_ref_ty(pat.span, mutbl, expected)
|
||||
self.new_ref_ty(pat.span, pinnedness, mutbl, expected)
|
||||
}
|
||||
// Wrapping the type into `Pin` if the binding is like `ref pin const|mut x`
|
||||
ByRef::Yes(Pinnedness::Pinned, mutbl) => Ty::new_adt(
|
||||
self.tcx,
|
||||
self.tcx.adt_def(self.tcx.require_lang_item(hir::LangItem::Pin, pat.span)),
|
||||
self.tcx.mk_args(&[self.new_ref_ty(pat.span, mutbl, expected).into()]),
|
||||
),
|
||||
// Otherwise, the type of x is the expected type `T`.
|
||||
ByRef::No => expected, // As above, `T <: typeof(x)` is required, but we use equality, see (note_1).
|
||||
};
|
||||
|
|
@ -1331,18 +1369,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
/// Precondition: pat is a `Ref(_)` pattern
|
||||
// FIXME(pin_ergonomics): add suggestions for `&pin mut` or `&pin const` patterns
|
||||
fn borrow_pat_suggestion(&self, err: &mut Diag<'_>, pat: &Pat<'_>) {
|
||||
let tcx = self.tcx;
|
||||
if let PatKind::Ref(inner, mutbl) = pat.kind
|
||||
if let PatKind::Ref(inner, pinned, mutbl) = pat.kind
|
||||
&& let PatKind::Binding(_, _, binding, ..) = inner.kind
|
||||
{
|
||||
let binding_parent = tcx.parent_hir_node(pat.hir_id);
|
||||
debug!(?inner, ?pat, ?binding_parent);
|
||||
|
||||
let mutability = match mutbl {
|
||||
ast::Mutability::Mut => "mut",
|
||||
ast::Mutability::Not => "",
|
||||
};
|
||||
let pin_and_mut = pinned.prefix_str(mutbl).trim_end();
|
||||
|
||||
let mut_var_suggestion = 'block: {
|
||||
if mutbl.is_not() {
|
||||
|
|
@ -1392,7 +1428,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// so we don't suggest moving something to the type that does not exist
|
||||
hir::Node::Param(hir::Param { ty_span, pat, .. }) if pat.span != *ty_span => {
|
||||
err.multipart_suggestion_verbose(
|
||||
format!("to take parameter `{binding}` by reference, move `&{mutability}` to the type"),
|
||||
format!("to take parameter `{binding}` by reference, move `&{pin_and_mut}` to the type"),
|
||||
vec![
|
||||
(pat.span.until(inner.span), "".to_owned()),
|
||||
(ty_span.shrink_to_lo(), mutbl.ref_prefix_str().to_owned()),
|
||||
|
|
@ -1406,13 +1442,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
hir::Node::Pat(pt) if let PatKind::TupleStruct(_, pat_arr, _) = pt.kind => {
|
||||
for i in pat_arr.iter() {
|
||||
if let PatKind::Ref(the_ref, _) = i.kind
|
||||
if let PatKind::Ref(the_ref, _, _) = i.kind
|
||||
&& let PatKind::Binding(mt, _, ident, _) = the_ref.kind
|
||||
{
|
||||
let BindingMode(_, mtblty) = mt;
|
||||
err.span_suggestion_verbose(
|
||||
i.span,
|
||||
format!("consider removing `&{mutability}` from the pattern"),
|
||||
format!("consider removing `&{pin_and_mut}` from the pattern"),
|
||||
mtblty.prefix_str().to_string() + &ident.name.to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
|
|
@ -1426,7 +1462,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// rely on match ergonomics or it might be nested `&&pat`
|
||||
err.span_suggestion_verbose(
|
||||
pat.span.until(inner.span),
|
||||
format!("consider removing `&{mutability}` from the pattern"),
|
||||
format!("consider removing `&{pin_and_mut}` from the pattern"),
|
||||
"",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
|
|
@ -2677,6 +2713,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
&self,
|
||||
pat: &'tcx Pat<'tcx>,
|
||||
inner: &'tcx Pat<'tcx>,
|
||||
pat_pinned: Pinnedness,
|
||||
pat_mutbl: Mutability,
|
||||
mut expected: Ty<'tcx>,
|
||||
mut pat_info: PatInfo<'tcx>,
|
||||
|
|
@ -2699,9 +2736,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// Determine whether we're consuming an inherited reference and resetting the default
|
||||
// binding mode, based on edition and enabled experimental features.
|
||||
if let ByRef::Yes(inh_pin, inh_mut) = pat_info.binding_mode
|
||||
// FIXME(pin_ergonomics): since `&pin` pattern is supported, the condition here
|
||||
// should be adjusted to `pat_pin == inh_pin`
|
||||
&& (!self.tcx.features().pin_ergonomics() || inh_pin == Pinnedness::Not)
|
||||
&& pat_pinned == inh_pin
|
||||
{
|
||||
match self.ref_pat_matches_inherited_ref(pat.span.edition()) {
|
||||
InheritedRefMatchRule::EatOuter => {
|
||||
|
|
@ -2821,21 +2856,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// to avoid creating needless variables. This also helps with
|
||||
// the bad interactions of the given hack detailed in (note_1).
|
||||
debug!("check_pat_ref: expected={:?}", expected);
|
||||
match *expected.kind() {
|
||||
ty::Ref(_, r_ty, r_mutbl)
|
||||
if (ref_pat_matches_mut_ref && r_mutbl >= pat_mutbl)
|
||||
|| r_mutbl == pat_mutbl =>
|
||||
match expected.maybe_pinned_ref() {
|
||||
Some((r_ty, r_pinned, r_mutbl))
|
||||
if ((ref_pat_matches_mut_ref && r_mutbl >= pat_mutbl)
|
||||
|| r_mutbl == pat_mutbl)
|
||||
&& pat_pinned == r_pinned =>
|
||||
{
|
||||
if r_mutbl == Mutability::Not {
|
||||
pat_info.max_ref_mutbl = MutblCap::Not;
|
||||
}
|
||||
if r_pinned == Pinnedness::Pinned {
|
||||
pat_info.max_pinnedness = PinnednessCap::Pinned;
|
||||
}
|
||||
|
||||
(expected, r_ty)
|
||||
}
|
||||
|
||||
_ => {
|
||||
let inner_ty = self.next_ty_var(inner.span);
|
||||
let ref_ty = self.new_ref_ty(pat.span, pat_mutbl, inner_ty);
|
||||
let ref_ty = self.new_ref_ty(pat.span, pat_pinned, pat_mutbl, inner_ty);
|
||||
debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty);
|
||||
let err = self.demand_eqtype_pat_diag(
|
||||
pat.span,
|
||||
|
|
@ -2864,10 +2902,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
ref_ty
|
||||
}
|
||||
|
||||
/// Create a reference type with a fresh region variable.
|
||||
fn new_ref_ty(&self, span: Span, mutbl: Mutability, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
/// Create a reference or pinned reference type with a fresh region variable.
|
||||
fn new_ref_ty(
|
||||
&self,
|
||||
span: Span,
|
||||
pinnedness: Pinnedness,
|
||||
mutbl: Mutability,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
let region = self.next_region_var(RegionVariableOrigin::PatternRegion(span));
|
||||
Ty::new_ref(self.tcx, region, ty, mutbl)
|
||||
let ref_ty = Ty::new_ref(self.tcx, region, ty, mutbl);
|
||||
if pinnedness.is_pinned() {
|
||||
return self.new_pinned_ty(span, ref_ty);
|
||||
}
|
||||
ref_ty
|
||||
}
|
||||
|
||||
/// Create a pinned type.
|
||||
fn new_pinned_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
Ty::new_adt(
|
||||
self.tcx,
|
||||
self.tcx.adt_def(self.tcx.require_lang_item(LangItem::Pin, span)),
|
||||
self.tcx.mk_args(&[ty.into()]),
|
||||
)
|
||||
}
|
||||
|
||||
fn error_inherited_ref_mutability_mismatch(
|
||||
|
|
|
|||
|
|
@ -1705,7 +1705,7 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
|
|||
}
|
||||
|
||||
let (parentheses, endpoints) = match &pat.kind {
|
||||
PatKind::Ref(subpat, _) => (true, matches_ellipsis_pat(subpat)),
|
||||
PatKind::Ref(subpat, _, _) => (true, matches_ellipsis_pat(subpat)),
|
||||
_ => (false, matches_ellipsis_pat(pat)),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1307,7 +1307,8 @@ impl EarlyLintPass for UnusedParens {
|
|||
Ident(.., Some(p)) | Box(p) | Deref(p) | Guard(p, _) => self.check_unused_parens_pat(cx, p, true, false, keep_space),
|
||||
// Avoid linting on `&(mut x)` as `&mut x` has a different meaning, #55342.
|
||||
// Also avoid linting on `& mut? (p0 | .. | pn)`, #64106.
|
||||
Ref(p, m) => self.check_unused_parens_pat(cx, p, true, *m == Mutability::Not, keep_space),
|
||||
// FIXME(pin_ergonomics): check pinned patterns
|
||||
Ref(p, _, m) => self.check_unused_parens_pat(cx, p, true, *m == Mutability::Not, keep_space),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ pub use basic_blocks::{BasicBlocks, SwitchTargetValue};
|
|||
use either::Either;
|
||||
use polonius_engine::Atom;
|
||||
use rustc_abi::{FieldIdx, VariantIdx};
|
||||
pub use rustc_ast::Mutability;
|
||||
pub use rustc_ast::{Mutability, Pinnedness};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::graph::dominators::Dominators;
|
||||
use rustc_errors::{DiagArgName, DiagArgValue, DiagMessage, ErrorGuaranteed, IntoDiagArg};
|
||||
|
|
|
|||
|
|
@ -1366,6 +1366,19 @@ impl<'tcx> Ty<'tcx> {
|
|||
None
|
||||
}
|
||||
|
||||
pub fn maybe_pinned_ref(self) -> Option<(Ty<'tcx>, ty::Pinnedness, ty::Mutability)> {
|
||||
match *self.kind() {
|
||||
Adt(def, args)
|
||||
if def.is_pin()
|
||||
&& let ty::Ref(_, ty, mutbl) = *args.type_at(0).kind() =>
|
||||
{
|
||||
Some((ty, ty::Pinnedness::Pinned, mutbl))
|
||||
}
|
||||
ty::Ref(_, ty, mutbl) => Some((ty, ty::Pinnedness::Not, mutbl)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Panics if called on any type other than `Box<T>`.
|
||||
pub fn expect_boxed_ty(self) -> Ty<'tcx> {
|
||||
self.boxed_ty()
|
||||
|
|
|
|||
|
|
@ -284,14 +284,12 @@ impl<'tcx> MatchPairTree<'tcx> {
|
|||
}
|
||||
|
||||
PatKind::Deref { ref subpattern }
|
||||
| PatKind::DerefPattern { ref subpattern, borrow: ByRef::No } => {
|
||||
if cfg!(debug_assertions) && matches!(pattern.kind, PatKind::DerefPattern { .. }) {
|
||||
// Only deref patterns on boxes can be lowered using a built-in deref.
|
||||
debug_assert!(pattern.ty.is_box());
|
||||
}
|
||||
|
||||
| PatKind::DerefPattern { ref subpattern, borrow: ByRef::Yes(Pinnedness::Pinned, _) }
|
||||
if let Some(ref_ty) = pattern.ty.pinned_ty()
|
||||
&& ref_ty.is_ref() =>
|
||||
{
|
||||
MatchPairTree::for_pattern(
|
||||
place_builder.deref(),
|
||||
place_builder.field(FieldIdx::ZERO, ref_ty).deref(),
|
||||
subpattern,
|
||||
cx,
|
||||
&mut subpairs,
|
||||
|
|
@ -300,12 +298,14 @@ impl<'tcx> MatchPairTree<'tcx> {
|
|||
None
|
||||
}
|
||||
|
||||
PatKind::DerefPattern { ref subpattern, borrow: ByRef::Yes(Pinnedness::Pinned, _) } => {
|
||||
let Some(ref_ty) = pattern.ty.pinned_ty() else {
|
||||
rustc_middle::bug!("RefPin pattern on non-`Pin` type {:?}", pattern.ty);
|
||||
};
|
||||
PatKind::DerefPattern { borrow: ByRef::Yes(Pinnedness::Pinned, _), .. } => {
|
||||
rustc_middle::bug!("RefPin pattern on non-`Pin` type {:?}", pattern.ty)
|
||||
}
|
||||
|
||||
PatKind::Deref { ref subpattern }
|
||||
| PatKind::DerefPattern { ref subpattern, borrow: ByRef::No } => {
|
||||
MatchPairTree::for_pattern(
|
||||
place_builder.field(FieldIdx::ZERO, ref_ty).deref(),
|
||||
place_builder.deref(),
|
||||
subpattern,
|
||||
cx,
|
||||
&mut subpairs,
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
// adjustments in *reverse order* (last-in-first-out, so that the last `Deref` inserted
|
||||
// gets the least-dereferenced type).
|
||||
let unadjusted_pat = match pat.kind {
|
||||
hir::PatKind::Ref(inner, _)
|
||||
hir::PatKind::Ref(inner, _, _)
|
||||
if self.typeck_results.skipped_ref_pats().contains(pat.hir_id) =>
|
||||
{
|
||||
self.lower_pattern(inner)
|
||||
|
|
@ -319,7 +319,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
let borrow = self.typeck_results.deref_pat_borrow_mode(ty, subpattern);
|
||||
PatKind::DerefPattern { subpattern: self.lower_pattern(subpattern), borrow }
|
||||
}
|
||||
hir::PatKind::Ref(subpattern, _) => {
|
||||
hir::PatKind::Ref(subpattern, _, _) => {
|
||||
// Track the default binding mode for the Rust 2024 migration suggestion.
|
||||
let opt_old_mode_span =
|
||||
self.rust_2024_migration.as_mut().and_then(|s| s.visit_explicit_deref());
|
||||
|
|
@ -370,10 +370,6 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
if let Some(pty) = ty.pinned_ty()
|
||||
&& let &ty::Ref(_, rty, _) = pty.kind() =>
|
||||
{
|
||||
debug_assert!(
|
||||
self.tcx.features().pin_ergonomics(),
|
||||
"`pin_ergonomics` must be enabled to have a by-pin-ref binding"
|
||||
);
|
||||
ty = rty;
|
||||
}
|
||||
hir::Pinnedness::Not if let &ty::Ref(_, rty, _) = ty.kind() => {
|
||||
|
|
|
|||
|
|
@ -2301,10 +2301,10 @@ impl<'a> Parser<'a> {
|
|||
pat.span.shrink_to_hi(),
|
||||
pat.span.shrink_to_lo(),
|
||||
),
|
||||
PatKind::Ref(ref inner_pat, _)
|
||||
PatKind::Ref(ref inner_pat, _, _)
|
||||
// Fix suggestions for multi-reference `self` parameters (e.g. `&&&self`)
|
||||
// cc: https://github.com/rust-lang/rust/pull/146305
|
||||
if let PatKind::Ref(_, _) = &inner_pat.kind
|
||||
if let PatKind::Ref(_, _, _) = &inner_pat.kind
|
||||
&& let PatKind::Path(_, path) = &pat.peel_refs().kind
|
||||
&& let [a, ..] = path.segments.as_slice()
|
||||
&& a.ident.name == kw::SelfLower =>
|
||||
|
|
@ -2312,7 +2312,7 @@ impl<'a> Parser<'a> {
|
|||
let mut inner = inner_pat;
|
||||
let mut span_vec = vec![pat.span];
|
||||
|
||||
while let PatKind::Ref(ref inner_type, _) = inner.kind {
|
||||
while let PatKind::Ref(ref inner_type, _, _) = inner.kind {
|
||||
inner = inner_type;
|
||||
span_vec.push(inner.span.shrink_to_lo());
|
||||
}
|
||||
|
|
@ -2334,10 +2334,10 @@ impl<'a> Parser<'a> {
|
|||
return None;
|
||||
}
|
||||
// Also catches `fn foo(&a)`.
|
||||
PatKind::Ref(ref inner_pat, mutab)
|
||||
PatKind::Ref(ref inner_pat, pinned, mutab)
|
||||
if let PatKind::Ident(_, ident, _) = inner_pat.clone().kind =>
|
||||
{
|
||||
let mutab = mutab.prefix_str();
|
||||
let mutab = pinned.prefix_str(mutab);
|
||||
(
|
||||
ident,
|
||||
"self: ",
|
||||
|
|
|
|||
|
|
@ -863,14 +863,15 @@ impl<'a> Parser<'a> {
|
|||
assert!(found_raw);
|
||||
let mutability = self.parse_const_or_mut().unwrap();
|
||||
(ast::BorrowKind::Raw, mutability)
|
||||
} else if let Some((ast::Pinnedness::Pinned, mutbl)) = self.parse_pin_and_mut() {
|
||||
// `pin [ const | mut ]`.
|
||||
// `pin` has been gated in `self.parse_pin_and_mut()` so we don't
|
||||
// need to gate it here.
|
||||
(ast::BorrowKind::Pin, mutbl)
|
||||
} else {
|
||||
// `mut?`
|
||||
(ast::BorrowKind::Ref, self.parse_mutability())
|
||||
match self.parse_pin_and_mut() {
|
||||
// `mut?`
|
||||
(ast::Pinnedness::Not, mutbl) => (ast::BorrowKind::Ref, mutbl),
|
||||
// `pin [ const | mut ]`.
|
||||
// `pin` has been gated in `self.parse_pin_and_mut()` so we don't
|
||||
// need to gate it here.
|
||||
(ast::Pinnedness::Pinned, mutbl) => (ast::BorrowKind::Pin, mutbl),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,8 +36,8 @@ use rustc_ast::tokenstream::{
|
|||
use rustc_ast::util::case::Case;
|
||||
use rustc_ast::{
|
||||
self as ast, AnonConst, AttrArgs, AttrId, ByRef, Const, CoroutineKind, DUMMY_NODE_ID,
|
||||
DelimArgs, Expr, ExprKind, Extern, HasAttrs, HasTokens, Mutability, Pinnedness, Recovered,
|
||||
Safety, StrLit, Visibility, VisibilityKind,
|
||||
DelimArgs, Expr, ExprKind, Extern, HasAttrs, HasTokens, Mutability, Recovered, Safety, StrLit,
|
||||
Visibility, VisibilityKind,
|
||||
};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
|
|
@ -1315,11 +1315,11 @@ impl<'a> Parser<'a> {
|
|||
if self.eat_keyword(exp!(Mut)) { Mutability::Mut } else { Mutability::Not }
|
||||
}
|
||||
|
||||
/// Parses reference binding mode (`ref`, `ref mut`, or nothing).
|
||||
/// Parses reference binding mode (`ref`, `ref mut`, `ref pin const`, `ref pin mut`, or nothing).
|
||||
fn parse_byref(&mut self) -> ByRef {
|
||||
if self.eat_keyword(exp!(Ref)) {
|
||||
// FIXME(pin_ergonomics): support `ref pin const|mut` bindings
|
||||
ByRef::Yes(Pinnedness::Not, self.parse_mutability())
|
||||
let (pinnedness, mutability) = self.parse_pin_and_mut();
|
||||
ByRef::Yes(pinnedness, mutability)
|
||||
} else {
|
||||
ByRef::No
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,8 +7,7 @@ use rustc_ast::util::parser::ExprPrecedence;
|
|||
use rustc_ast::visit::{self, Visitor};
|
||||
use rustc_ast::{
|
||||
self as ast, Arm, AttrVec, BindingMode, ByRef, Expr, ExprKind, LocalKind, MacCall, Mutability,
|
||||
Pat, PatField, PatFieldsRest, PatKind, Path, Pinnedness, QSelf, RangeEnd, RangeSyntax, Stmt,
|
||||
StmtKind,
|
||||
Pat, PatField, PatFieldsRest, PatKind, Path, QSelf, RangeEnd, RangeSyntax, Stmt, StmtKind,
|
||||
};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_errors::{Applicability, Diag, DiagArgValue, PResult, StashKey};
|
||||
|
|
@ -661,7 +660,7 @@ impl<'a> Parser<'a> {
|
|||
|
||||
// Sub-patterns
|
||||
// FIXME: this doesn't work with recursive subpats (`&mut &mut <err>`)
|
||||
PatKind::Box(subpat) | PatKind::Ref(subpat, _)
|
||||
PatKind::Box(subpat) | PatKind::Ref(subpat, _, _)
|
||||
if matches!(subpat.kind, PatKind::Err(_) | PatKind::Expr(_)) =>
|
||||
{
|
||||
self.maybe_add_suggestions_then_emit(subpat.span, p.span, false)
|
||||
|
|
@ -777,11 +776,10 @@ impl<'a> Parser<'a> {
|
|||
self.bump();
|
||||
self.dcx().emit_err(SwitchRefBoxOrder { span });
|
||||
}
|
||||
// Parse ref ident @ pat / ref mut ident @ pat
|
||||
let mutbl = self.parse_mutability();
|
||||
// Parse ref ident @ pat / ref mut ident @ pat / ref pin const|mut ident @ pat
|
||||
let (pinned, mutbl) = self.parse_pin_and_mut();
|
||||
self.parse_pat_ident(
|
||||
// FIXME(pin_ergonomics): support `ref pin const|mut` bindings
|
||||
BindingMode(ByRef::Yes(Pinnedness::Not, mutbl), Mutability::Not),
|
||||
BindingMode(ByRef::Yes(pinned, mutbl), Mutability::Not),
|
||||
syntax_loc,
|
||||
)?
|
||||
} else if self.eat_keyword(exp!(Box)) {
|
||||
|
|
@ -982,7 +980,7 @@ impl<'a> Parser<'a> {
|
|||
});
|
||||
}
|
||||
|
||||
/// Parse `&pat` / `&mut pat`.
|
||||
/// Parse `&pat` / `&mut pat` / `&pin const pat` / `&pin mut pat`.
|
||||
fn parse_pat_deref(&mut self, expected: Option<Expected>) -> PResult<'a, PatKind> {
|
||||
self.expect_and()?;
|
||||
if let Some((lifetime, _)) = self.token.lifetime() {
|
||||
|
|
@ -995,9 +993,9 @@ impl<'a> Parser<'a> {
|
|||
});
|
||||
}
|
||||
|
||||
let mutbl = self.parse_mutability();
|
||||
let (pinned, mutbl) = self.parse_pin_and_mut();
|
||||
let subpat = self.parse_pat_with_range_pat(false, expected, None)?;
|
||||
Ok(PatKind::Ref(Box::new(subpat), mutbl))
|
||||
Ok(PatKind::Ref(Box::new(subpat), pinned, mutbl))
|
||||
}
|
||||
|
||||
/// Parse a tuple or parenthesis pattern.
|
||||
|
|
|
|||
|
|
@ -142,6 +142,7 @@ pub enum TokenType {
|
|||
SymNull,
|
||||
SymOptions,
|
||||
SymOut,
|
||||
SymPin,
|
||||
SymPreservesFlags,
|
||||
SymPure,
|
||||
SymReadonly,
|
||||
|
|
@ -568,6 +569,7 @@ macro_rules! exp {
|
|||
(Null) => { exp!(@sym, null, SymNull) };
|
||||
(Options) => { exp!(@sym, options, SymOptions) };
|
||||
(Out) => { exp!(@sym, out, SymOut) };
|
||||
(Pin) => { exp!(@sym, pin, SymPin) };
|
||||
(PreservesFlags) => { exp!(@sym, preserves_flags, SymPreservesFlags) };
|
||||
(Pure) => { exp!(@sym, pure, SymPure) };
|
||||
(Readonly) => { exp!(@sym, readonly, SymReadonly) };
|
||||
|
|
|
|||
|
|
@ -728,10 +728,7 @@ impl<'a> Parser<'a> {
|
|||
fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> {
|
||||
let and_span = self.prev_token.span;
|
||||
let mut opt_lifetime = self.check_lifetime().then(|| self.expect_lifetime());
|
||||
let (pinned, mut mutbl) = match self.parse_pin_and_mut() {
|
||||
Some(pin_mut) => pin_mut,
|
||||
None => (Pinnedness::Not, self.parse_mutability()),
|
||||
};
|
||||
let (pinned, mut mutbl) = self.parse_pin_and_mut();
|
||||
if self.token.is_lifetime() && mutbl == Mutability::Mut && opt_lifetime.is_none() {
|
||||
// A lifetime is invalid here: it would be part of a bare trait bound, which requires
|
||||
// it to be followed by a plus, but we disallow plus in the pointee type.
|
||||
|
|
@ -773,28 +770,17 @@ impl<'a> Parser<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
/// Parses `pin` and `mut` annotations on references.
|
||||
/// Parses `pin` and `mut` annotations on references, patterns, or borrow modifiers.
|
||||
///
|
||||
/// It must be either `pin const` or `pin mut`.
|
||||
pub(crate) fn parse_pin_and_mut(&mut self) -> Option<(Pinnedness, Mutability)> {
|
||||
if self.token.is_ident_named(sym::pin) {
|
||||
let result = self.look_ahead(1, |token| {
|
||||
if token.is_keyword(kw::Const) {
|
||||
Some((Pinnedness::Pinned, Mutability::Not))
|
||||
} else if token.is_keyword(kw::Mut) {
|
||||
Some((Pinnedness::Pinned, Mutability::Mut))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
if result.is_some() {
|
||||
self.psess.gated_spans.gate(sym::pin_ergonomics, self.token.span);
|
||||
self.bump();
|
||||
self.bump();
|
||||
}
|
||||
result
|
||||
/// It must be either `pin const`, `pin mut`, `mut`, or nothing (immutable).
|
||||
pub(crate) fn parse_pin_and_mut(&mut self) -> (Pinnedness, Mutability) {
|
||||
if self.token.is_ident_named(sym::pin) && self.look_ahead(1, Token::is_mutability) {
|
||||
self.psess.gated_spans.gate(sym::pin_ergonomics, self.token.span);
|
||||
assert!(self.eat_keyword(exp!(Pin)));
|
||||
let mutbl = self.parse_const_or_mut().unwrap();
|
||||
(Pinnedness::Pinned, mutbl)
|
||||
} else {
|
||||
None
|
||||
(Pinnedness::Not, self.parse_mutability())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -462,8 +462,12 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
|
|||
PatKind::Deref { subpattern } => {
|
||||
fields = vec![self.lower_pat(subpattern).at_index(0)];
|
||||
arity = 1;
|
||||
ctor = match ty.kind() {
|
||||
ty::Ref(..) => Ref,
|
||||
ctor = match ty.pinned_ref() {
|
||||
None if ty.is_ref() => Ref,
|
||||
Some((inner_ty, _)) => {
|
||||
self.internal_state.has_lowered_deref_pat.set(true);
|
||||
DerefPattern(RevealedTy(inner_ty))
|
||||
}
|
||||
_ => span_bug!(
|
||||
pat.span,
|
||||
"pattern has unexpected type: pat: {:?}, ty: {:?}",
|
||||
|
|
|
|||
|
|
@ -303,7 +303,7 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol {
|
|||
return kw::Underscore;
|
||||
}
|
||||
PatKind::Binding(_, _, ident, _) => return ident.name,
|
||||
PatKind::Box(p) | PatKind::Ref(p, _) | PatKind::Guard(p, _) => return name_from_pat(p),
|
||||
PatKind::Box(p) | PatKind::Ref(p, _, _) | PatKind::Guard(p, _) => return name_from_pat(p),
|
||||
PatKind::TupleStruct(p, ..) | PatKind::Expr(PatExpr { kind: PatExprKind::Path(p), .. }) => {
|
||||
qpath_to_string(p)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ fn unary_pattern(pat: &Pat<'_>) -> bool {
|
|||
| PatKind::Err(_) => false,
|
||||
PatKind::Struct(_, a, etc) => etc.is_none() && a.iter().all(|x| unary_pattern(x.pat)),
|
||||
PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => etc.as_opt_usize().is_none() && array_rec(a),
|
||||
PatKind::Ref(x, _) | PatKind::Box(x) | PatKind::Deref(x) | PatKind::Guard(x, _) => unary_pattern(x),
|
||||
PatKind::Ref(x, _, _) | PatKind::Box(x) | PatKind::Deref(x) | PatKind::Guard(x, _) => unary_pattern(x),
|
||||
PatKind::Expr(_) => true,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ pub(super) fn check<'tcx>(
|
|||
let mut snippet = make_iterator_snippet(cx, arg, &mut applicability);
|
||||
// Checks if `pat` is a single reference to a binding (`&x`)
|
||||
let is_ref_to_binding =
|
||||
matches!(pat.kind, PatKind::Ref(inner, _) if matches!(inner.kind, PatKind::Binding(..)));
|
||||
matches!(pat.kind, PatKind::Ref(inner, _, _) if matches!(inner.kind, PatKind::Binding(..)));
|
||||
// If `pat` is not a binding or a reference to a binding (`x` or `&x`)
|
||||
// we need to map it to the binding returned by the function (i.e. `.map(|(x, _)| x)`)
|
||||
if !(matches!(pat.kind, PatKind::Binding(..)) || is_ref_to_binding) {
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ fn check_iter(
|
|||
),
|
||||
);
|
||||
},
|
||||
hir::PatKind::Ref(pat, _) => make_span_lint_and_sugg(
|
||||
hir::PatKind::Ref(pat, _, _) => make_span_lint_and_sugg(
|
||||
cx,
|
||||
parent_expr_span,
|
||||
format!(
|
||||
|
|
@ -196,7 +196,7 @@ fn check_to_owned(
|
|||
&& let filter_body = cx.tcx.hir_body(closure.body)
|
||||
&& let [filter_params] = filter_body.params
|
||||
&& msrv.meets(cx, msrvs::STRING_RETAIN)
|
||||
&& let hir::PatKind::Ref(pat, _) = filter_params.pat.kind
|
||||
&& let hir::PatKind::Ref(pat, _, _) = filter_params.pat.kind
|
||||
{
|
||||
make_span_lint_and_sugg(
|
||||
cx,
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ fn is_variant_or_wildcard(cx: &LateContext<'_>, pat: &Pat<'_>, can_be_wild: bool
|
|||
.is_lang_item(cx, ResultErr)
|
||||
== must_match_err
|
||||
},
|
||||
PatKind::Binding(_, _, _, Some(pat)) | PatKind::Ref(pat, _) => {
|
||||
PatKind::Binding(_, _, _, Some(pat)) | PatKind::Ref(pat, _, _) => {
|
||||
is_variant_or_wildcard(cx, pat, can_be_wild, must_match_err)
|
||||
},
|
||||
_ => false,
|
||||
|
|
|
|||
|
|
@ -254,7 +254,7 @@ pub(super) fn try_parse_pattern<'tcx>(
|
|||
) -> Option<OptionPat<'tcx>> {
|
||||
match pat.kind {
|
||||
PatKind::Wild => Some(OptionPat::Wild),
|
||||
PatKind::Ref(pat, _) => f(cx, pat, ref_count + 1, ctxt),
|
||||
PatKind::Ref(pat, _, _) => f(cx, pat, ref_count + 1, ctxt),
|
||||
PatKind::Expr(PatExpr {
|
||||
kind: PatExprKind::Path(qpath),
|
||||
hir_id,
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ where
|
|||
}
|
||||
|
||||
let remaining_suggs = pats.filter_map(|pat| {
|
||||
if let PatKind::Ref(refp, _) = pat.kind {
|
||||
if let PatKind::Ref(refp, _, _) = pat.kind {
|
||||
Some((pat.span, snippet(cx, refp.span, "..").to_string()))
|
||||
} else {
|
||||
None
|
||||
|
|
|
|||
|
|
@ -264,7 +264,7 @@ impl<'a> NormalizedPat<'a> {
|
|||
PatKind::Binding(.., Some(pat))
|
||||
| PatKind::Box(pat)
|
||||
| PatKind::Deref(pat)
|
||||
| PatKind::Ref(pat, _)
|
||||
| PatKind::Ref(pat, _, _)
|
||||
| PatKind::Guard(pat, _) => Self::from_pat(cx, arena, pat),
|
||||
PatKind::Never => Self::Never,
|
||||
PatKind::Struct(ref path, fields, _) => {
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>], msrv:
|
|||
&& !pat_contains_disallowed_or(cx, arm.pat, msrv)
|
||||
{
|
||||
let pat_span = match (arm.pat.kind, binding.byref_ident) {
|
||||
(PatKind::Ref(pat, _), Some(_)) => pat.span,
|
||||
(PatKind::Ref(pat, _, _), Some(_)) => pat.span,
|
||||
(PatKind::Ref(..), None) | (_, Some(_)) => continue,
|
||||
_ => arm.pat.span,
|
||||
};
|
||||
|
|
@ -49,7 +49,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>], msrv:
|
|||
&& !pat_contains_disallowed_or(cx, let_expr.pat, msrv)
|
||||
{
|
||||
let pat_span = match (let_expr.pat.kind, binding.byref_ident) {
|
||||
(PatKind::Ref(pat, _), Some(_)) => pat.span,
|
||||
(PatKind::Ref(pat, _, _), Some(_)) => pat.span,
|
||||
(PatKind::Ref(..), None) | (_, Some(_)) => continue,
|
||||
_ => let_expr.pat.span,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -186,7 +186,7 @@ fn find_method_sugg_for_if_let<'tcx>(
|
|||
// also look inside refs
|
||||
// if we have &None for example, peel it so we can detect "if let None = x"
|
||||
let check_pat = match let_pat.kind {
|
||||
PatKind::Ref(inner, _mutability) => inner,
|
||||
PatKind::Ref(inner, _pinnedness, _mutability) => inner,
|
||||
_ => let_pat,
|
||||
};
|
||||
let op_ty = cx.typeck_results().expr_ty(let_expr);
|
||||
|
|
|
|||
|
|
@ -373,7 +373,7 @@ impl<'a> PatState<'a> {
|
|||
},
|
||||
|
||||
// Patterns for things which can only contain a single sub-pattern.
|
||||
PatKind::Binding(_, _, _, Some(pat)) | PatKind::Ref(pat, _) | PatKind::Box(pat) | PatKind::Deref(pat) => {
|
||||
PatKind::Binding(_, _, _, Some(pat)) | PatKind::Ref(pat, _, _) | PatKind::Box(pat) | PatKind::Deref(pat) => {
|
||||
self.add_pat(cx, pat)
|
||||
},
|
||||
PatKind::Tuple([sub_pat], pos)
|
||||
|
|
|
|||
|
|
@ -404,7 +404,7 @@ fn is_find_or_filter<'a>(
|
|||
&& let filter_body = cx.tcx.hir_body(filter_body_id)
|
||||
&& let [filter_param] = filter_body.params
|
||||
// optional ref pattern: `filter(|&x| ..)`
|
||||
&& let (filter_pat, is_filter_param_ref) = if let PatKind::Ref(ref_pat, _) = filter_param.pat.kind {
|
||||
&& let (filter_pat, is_filter_param_ref) = if let PatKind::Ref(ref_pat, _, _) = filter_param.pat.kind {
|
||||
(ref_pat, true)
|
||||
} else {
|
||||
(filter_param.pat, false)
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ fn is_method(
|
|||
fn pat_is_recv(ident: Ident, param: &hir::Pat<'_>) -> bool {
|
||||
match param.kind {
|
||||
hir::PatKind::Binding(_, _, other, _) => ident == other,
|
||||
hir::PatKind::Ref(pat, _) => pat_is_recv(ident, pat),
|
||||
hir::PatKind::Ref(pat, _, _) => pat_is_recv(ident, pat),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ pub(super) fn check<'tcx>(
|
|||
}
|
||||
|
||||
match it.kind {
|
||||
PatKind::Binding(BindingMode(_, Mutability::Mut), _, _, _) | PatKind::Ref(_, Mutability::Mut) => {
|
||||
PatKind::Binding(BindingMode(_, Mutability::Mut), _, _, _) | PatKind::Ref(_, _, Mutability::Mut) => {
|
||||
to_be_discarded = true;
|
||||
false
|
||||
},
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use rustc_errors::Applicability;
|
|||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{self as hir, LangItem};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::mir::Mutability;
|
||||
use rustc_middle::mir::{Mutability, Pinnedness};
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::adjustment::Adjust;
|
||||
use rustc_span::symbol::Ident;
|
||||
|
|
@ -50,7 +50,7 @@ pub(super) fn check(cx: &LateContext<'_>, e: &hir::Expr<'_>, recv: &hir::Expr<'_
|
|||
let closure_body = cx.tcx.hir_body(body);
|
||||
let closure_expr = peel_blocks(closure_body.value);
|
||||
match closure_body.params[0].pat.kind {
|
||||
hir::PatKind::Ref(inner, Mutability::Not) => {
|
||||
hir::PatKind::Ref(inner, Pinnedness::Not, Mutability::Not) => {
|
||||
if let hir::PatKind::Binding(hir::BindingMode::NONE, .., name, None) = inner.kind
|
||||
&& ident_eq(name, closure_expr)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BindingMode, Mutability, Node, Pat, PatKind};
|
||||
use rustc_hir::{BindingMode, Mutability, Node, Pat, PatKind, Pinnedness};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::declare_lint_pass;
|
||||
|
||||
|
|
@ -37,7 +37,7 @@ declare_lint_pass!(NeedlessBorrowedRef => [NEEDLESS_BORROWED_REFERENCE]);
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowedRef {
|
||||
fn check_pat(&mut self, cx: &LateContext<'tcx>, ref_pat: &'tcx Pat<'_>) {
|
||||
if let PatKind::Ref(pat, Mutability::Not) = ref_pat.kind
|
||||
if let PatKind::Ref(pat, Pinnedness::Not, Mutability::Not) = ref_pat.kind
|
||||
&& !ref_pat.span.from_expansion()
|
||||
&& cx
|
||||
.tcx
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use clippy_utils::msrvs::{self, MsrvStack};
|
|||
use clippy_utils::over;
|
||||
use rustc_ast::PatKind::*;
|
||||
use rustc_ast::mut_visit::*;
|
||||
use rustc_ast::{self as ast, DUMMY_NODE_ID, Mutability, Pat, PatKind};
|
||||
use rustc_ast::{self as ast, DUMMY_NODE_ID, Mutability, Pat, PatKind, Pinnedness};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_data_structures::thin_vec::{ThinVec, thin_vec};
|
||||
use rustc_errors::Applicability;
|
||||
|
|
@ -151,8 +151,8 @@ fn insert_necessary_parens(pat: &mut Box<Pat>) {
|
|||
walk_pat(self, pat);
|
||||
let target = match &mut pat.kind {
|
||||
// `i @ a | b`, `box a | b`, and `& mut? a | b`.
|
||||
Ident(.., Some(p)) | Box(p) | Ref(p, _) if matches!(&p.kind, Or(ps) if ps.len() > 1) => p,
|
||||
Ref(p, Mutability::Not) if matches!(p.kind, Ident(BindingMode::MUT, ..)) => p, // `&(mut x)`
|
||||
Ident(.., Some(p)) | Box(p) | Ref(p, _, _) if matches!(&p.kind, Or(ps) if ps.len() > 1) => p,
|
||||
Ref(p, Pinnedness::Not, Mutability::Not) if matches!(p.kind, Ident(BindingMode::MUT, ..)) => p, // `&(mut x)`
|
||||
_ => return,
|
||||
};
|
||||
target.kind = Paren(Box::new(take_pat(target)));
|
||||
|
|
@ -241,7 +241,8 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<Pat>, focus_idx: usize
|
|||
// Skip immutable refs, as grouping them saves few characters,
|
||||
// and almost always requires adding parens (increasing noisiness).
|
||||
// In the case of only two patterns, replacement adds net characters.
|
||||
| Ref(_, Mutability::Not)
|
||||
// FIXME(pin_ergonomics): handle pinned patterns
|
||||
| Ref(_, _, Mutability::Not)
|
||||
// Dealt with elsewhere.
|
||||
| Or(_) | Paren(_) | Deref(_) | Guard(..) => false,
|
||||
// Transform `box x | ... | box y` into `box (x | y)`.
|
||||
|
|
@ -254,10 +255,10 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<Pat>, focus_idx: usize
|
|||
|k| always_pat!(k, Box(p) => *p),
|
||||
),
|
||||
// Transform `&mut x | ... | &mut y` into `&mut (x | y)`.
|
||||
Ref(target, Mutability::Mut) => extend_with_matching(
|
||||
Ref(target, _, Mutability::Mut) => extend_with_matching(
|
||||
target, start, alternatives,
|
||||
|k| matches!(k, Ref(_, Mutability::Mut)),
|
||||
|k| always_pat!(k, Ref(p, _) => *p),
|
||||
|k| matches!(k, Ref(_, _, Mutability::Mut)),
|
||||
|k| always_pat!(k, Ref(p, _, _) => *p),
|
||||
),
|
||||
// Transform `b @ p0 | ... b @ p1` into `b @ (p0 | p1)`.
|
||||
Ident(b1, i1, Some(target)) => extend_with_matching(
|
||||
|
|
|
|||
|
|
@ -793,9 +793,9 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
|
|||
kind!("Deref({pat})");
|
||||
self.pat(pat);
|
||||
},
|
||||
PatKind::Ref(pat, muta) => {
|
||||
PatKind::Ref(pat, pinn, muta) => {
|
||||
bind!(self, pat);
|
||||
kind!("Ref({pat}, Mutability::{muta:?})");
|
||||
kind!("Ref({pat}, Pinning::{pinn:?}, Mutability::{muta:?})");
|
||||
self.pat(pat);
|
||||
},
|
||||
PatKind::Guard(pat, cond) => {
|
||||
|
|
|
|||
|
|
@ -45,9 +45,8 @@ pub fn eq_pat(l: &Pat, r: &Pat) -> bool {
|
|||
&& eq_expr_opt(lt.as_deref(), rt.as_deref())
|
||||
&& eq_range_end(&le.node, &re.node)
|
||||
},
|
||||
(Box(l), Box(r))
|
||||
| (Ref(l, Mutability::Not), Ref(r, Mutability::Not))
|
||||
| (Ref(l, Mutability::Mut), Ref(r, Mutability::Mut)) => eq_pat(l, r),
|
||||
(Box(l), Box(r)) => eq_pat(l, r),
|
||||
(Ref(l, l_pin, l_mut), Ref(r, r_pin, r_mut)) => l_pin == r_pin && l_mut == r_mut && eq_pat(l, r),
|
||||
(Tuple(l), Tuple(r)) | (Slice(l), Slice(r)) => over(l, r, eq_pat),
|
||||
(Path(lq, lp), Path(rq, rp)) => both(lq.as_deref(), rq.as_deref(), eq_qself) && eq_path(lp, rp),
|
||||
(TupleStruct(lqself, lp, lfs), TupleStruct(rqself, rp, rfs)) => {
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@ use rustc_data_structures::fx::FxHasher;
|
|||
use rustc_hir::MatchSource::TryDesugar;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::{
|
||||
AssocItemConstraint, BinOpKind, BindingMode, Block, BodyId, Closure, ConstArg, ConstArgKind, Expr, ExprField,
|
||||
ExprKind, FnRetTy, GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, LifetimeKind,
|
||||
Node, Pat, PatExpr, PatExprKind, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind,
|
||||
AssocItemConstraint, BinOpKind, BindingMode, Block, BodyId, ByRef, Closure, ConstArg, ConstArgKind, Expr,
|
||||
ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime,
|
||||
LifetimeKind, Node, Pat, PatExpr, PatExprKind, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind,
|
||||
StructTailExpr, TraitBoundModifiers, Ty, TyKind, TyPat, TyPatKind,
|
||||
};
|
||||
use rustc_lexer::{FrontmatterAllowed, TokenKind, tokenize};
|
||||
|
|
@ -538,7 +538,7 @@ impl HirEqInterExpr<'_, '_, '_> {
|
|||
&& both(le.as_ref(), re.as_ref(), |a, b| self.eq_pat_expr(a, b))
|
||||
&& (li == ri)
|
||||
},
|
||||
(PatKind::Ref(le, lm), PatKind::Ref(re, rm)) => lm == rm && self.eq_pat(le, re),
|
||||
(PatKind::Ref(le, lp, lm), PatKind::Ref(re, rp, rm)) => lp == rp && lm == rm && self.eq_pat(le, re),
|
||||
(PatKind::Slice(ls, li, le), PatKind::Slice(rs, ri, re)) => {
|
||||
over(ls, rs, |l, r| self.eq_pat(l, r))
|
||||
&& over(le, re, |l, r| self.eq_pat(l, r))
|
||||
|
|
@ -1131,6 +1131,10 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
|||
PatKind::Missing => unreachable!(),
|
||||
PatKind::Binding(BindingMode(by_ref, mutability), _, _, pat) => {
|
||||
std::mem::discriminant(by_ref).hash(&mut self.s);
|
||||
if let ByRef::Yes(pi, mu) = by_ref {
|
||||
std::mem::discriminant(pi).hash(&mut self.s);
|
||||
std::mem::discriminant(mu).hash(&mut self.s);
|
||||
}
|
||||
std::mem::discriminant(mutability).hash(&mut self.s);
|
||||
if let Some(pat) = pat {
|
||||
self.hash_pat(pat);
|
||||
|
|
@ -1152,8 +1156,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
|||
}
|
||||
std::mem::discriminant(i).hash(&mut self.s);
|
||||
},
|
||||
PatKind::Ref(pat, mu) => {
|
||||
PatKind::Ref(pat, pi, mu) => {
|
||||
self.hash_pat(pat);
|
||||
std::mem::discriminant(pi).hash(&mut self.s);
|
||||
std::mem::discriminant(mu).hash(&mut self.s);
|
||||
},
|
||||
PatKind::Guard(pat, guard) => {
|
||||
|
|
|
|||
|
|
@ -1462,7 +1462,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
|
|||
PatKind::Missing => unreachable!(),
|
||||
PatKind::Wild | PatKind::Never => false, // If `!` typechecked then the type is empty, so not refutable.
|
||||
PatKind::Binding(_, _, _, pat) => pat.is_some_and(|pat| is_refutable(cx, pat)),
|
||||
PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat),
|
||||
PatKind::Box(pat) | PatKind::Ref(pat, _, _) => is_refutable(cx, pat),
|
||||
PatKind::Expr(PatExpr {
|
||||
kind: PatExprKind::Path(qpath),
|
||||
hir_id,
|
||||
|
|
@ -1612,7 +1612,7 @@ pub fn is_lint_allowed(cx: &LateContext<'_>, lint: &'static Lint, id: HirId) ->
|
|||
}
|
||||
|
||||
pub fn strip_pat_refs<'hir>(mut pat: &'hir Pat<'hir>) -> &'hir Pat<'hir> {
|
||||
while let PatKind::Ref(subpat, _) = pat.kind {
|
||||
while let PatKind::Ref(subpat, _, _) = pat.kind {
|
||||
pat = subpat;
|
||||
}
|
||||
pat
|
||||
|
|
@ -2157,7 +2157,7 @@ where
|
|||
/// references removed.
|
||||
pub fn peel_hir_pat_refs<'a>(pat: &'a Pat<'a>) -> (&'a Pat<'a>, usize) {
|
||||
fn peel<'a>(pat: &'a Pat<'a>, count: usize) -> (&'a Pat<'a>, usize) {
|
||||
if let PatKind::Ref(pat, _) = pat.kind {
|
||||
if let PatKind::Ref(pat, _, _) = pat.kind {
|
||||
peel(pat, count + 1)
|
||||
} else {
|
||||
(pat, count)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,9 @@ use crate::shape::Shape;
|
|||
use crate::source_map::SpanUtils;
|
||||
use crate::spanned::Spanned;
|
||||
use crate::types::{PathContext, rewrite_path};
|
||||
use crate::utils::{format_mutability, mk_sp, mk_sp_lo_plus_one, rewrite_ident};
|
||||
use crate::utils::{
|
||||
format_mutability, format_pinnedness_and_mutability, mk_sp, mk_sp_lo_plus_one, rewrite_ident,
|
||||
};
|
||||
|
||||
/// Returns `true` if the given pattern is "short".
|
||||
/// A short pattern is defined by the following grammar:
|
||||
|
|
@ -69,7 +71,7 @@ fn is_short_pattern_inner(context: &RewriteContext<'_>, pat: &ast::Pat) -> bool
|
|||
}
|
||||
ast::PatKind::Box(ref p)
|
||||
| PatKind::Deref(ref p)
|
||||
| ast::PatKind::Ref(ref p, _)
|
||||
| ast::PatKind::Ref(ref p, _, _)
|
||||
| ast::PatKind::Paren(ref p) => is_short_pattern_inner(context, &*p),
|
||||
PatKind::Or(ref pats) => pats.iter().all(|p| is_short_pattern_inner(context, p)),
|
||||
}
|
||||
|
|
@ -133,10 +135,13 @@ impl Rewrite for Pat {
|
|||
PatKind::Ident(BindingMode(by_ref, mutability), ident, ref sub_pat) => {
|
||||
let mut_prefix = format_mutability(mutability).trim();
|
||||
|
||||
let (ref_kw, mut_infix) = match by_ref {
|
||||
// FIXME(pin_ergonomics): format the pinnedness
|
||||
ByRef::Yes(_, rmutbl) => ("ref", format_mutability(rmutbl).trim()),
|
||||
ByRef::No => ("", ""),
|
||||
let (ref_kw, pin_infix, mut_infix) = match by_ref {
|
||||
ByRef::Yes(pinnedness, rmutbl) => {
|
||||
let (pin_infix, mut_infix) =
|
||||
format_pinnedness_and_mutability(pinnedness, rmutbl);
|
||||
("ref", pin_infix.trim(), mut_infix.trim())
|
||||
}
|
||||
ByRef::No => ("", "", ""),
|
||||
};
|
||||
let id_str = rewrite_ident(context, ident);
|
||||
let sub_pat = match *sub_pat {
|
||||
|
|
@ -147,6 +152,7 @@ impl Rewrite for Pat {
|
|||
.checked_sub(
|
||||
mut_prefix.len()
|
||||
+ ref_kw.len()
|
||||
+ pin_infix.len()
|
||||
+ mut_infix.len()
|
||||
+ id_str.len()
|
||||
+ 2,
|
||||
|
|
@ -193,18 +199,17 @@ impl Rewrite for Pat {
|
|||
(true, true) => (self.span.lo(), "".to_owned()),
|
||||
};
|
||||
|
||||
// combine result of above and mut
|
||||
let (second_lo, second) = match (first.is_empty(), mut_infix.is_empty()) {
|
||||
// combine result of above and pin
|
||||
let (second_lo, second) = match (first.is_empty(), pin_infix.is_empty()) {
|
||||
(false, false) => {
|
||||
let lo = context.snippet_provider.span_after(self.span, "ref");
|
||||
let end_span = mk_sp(first_lo, self.span.hi());
|
||||
let hi = context.snippet_provider.span_before(end_span, "mut");
|
||||
let hi = context.snippet_provider.span_before(self.span, "pin");
|
||||
(
|
||||
context.snippet_provider.span_after(end_span, "mut"),
|
||||
context.snippet_provider.span_after(self.span, "pin"),
|
||||
combine_strs_with_missing_comments(
|
||||
context,
|
||||
&first,
|
||||
mut_infix,
|
||||
pin_infix,
|
||||
mk_sp(lo, hi),
|
||||
shape,
|
||||
true,
|
||||
|
|
@ -212,7 +217,33 @@ impl Rewrite for Pat {
|
|||
)
|
||||
}
|
||||
(false, true) => (first_lo, first),
|
||||
(true, false) => unreachable!("mut_infix necessarily follows a ref"),
|
||||
(true, false) => unreachable!("pin_infix necessarily follows a ref"),
|
||||
(true, true) => (self.span.lo(), "".to_owned()),
|
||||
};
|
||||
|
||||
// combine result of above and const|mut
|
||||
let (third_lo, third) = match (second.is_empty(), mut_infix.is_empty()) {
|
||||
(false, false) => {
|
||||
let lo = context.snippet_provider.span_after(
|
||||
self.span,
|
||||
if pin_infix.is_empty() { "ref" } else { "pin" },
|
||||
);
|
||||
let end_span = mk_sp(second_lo, self.span.hi());
|
||||
let hi = context.snippet_provider.span_before(end_span, mut_infix);
|
||||
(
|
||||
context.snippet_provider.span_after(end_span, mut_infix),
|
||||
combine_strs_with_missing_comments(
|
||||
context,
|
||||
&second,
|
||||
mut_infix,
|
||||
mk_sp(lo, hi),
|
||||
shape,
|
||||
true,
|
||||
)?,
|
||||
)
|
||||
}
|
||||
(false, true) => (second_lo, second),
|
||||
(true, false) => unreachable!("mut_infix necessarily follows a pin or ref"),
|
||||
(true, true) => (self.span.lo(), "".to_owned()),
|
||||
};
|
||||
|
||||
|
|
@ -232,9 +263,9 @@ impl Rewrite for Pat {
|
|||
|
||||
combine_strs_with_missing_comments(
|
||||
context,
|
||||
&second,
|
||||
&third,
|
||||
&next,
|
||||
mk_sp(second_lo, ident.span.lo()),
|
||||
mk_sp(third_lo, ident.span.lo()),
|
||||
shape,
|
||||
true,
|
||||
)
|
||||
|
|
@ -263,8 +294,10 @@ impl Rewrite for Pat {
|
|||
PatKind::Range(ref lhs, ref rhs, ref end_kind) => {
|
||||
rewrite_range_pat(context, shape, lhs, rhs, end_kind, self.span)
|
||||
}
|
||||
PatKind::Ref(ref pat, mutability) => {
|
||||
let prefix = format!("&{}", format_mutability(mutability));
|
||||
PatKind::Ref(ref pat, pinnedness, mutability) => {
|
||||
let (pin_prefix, mut_prefix) =
|
||||
format_pinnedness_and_mutability(pinnedness, mutability);
|
||||
let prefix = format!("&{}{}", pin_prefix, mut_prefix);
|
||||
rewrite_unary_prefix(context, &prefix, &**pat, shape)
|
||||
}
|
||||
PatKind::Tuple(ref items) => rewrite_tuple_pat(items, None, self.span, context, shape),
|
||||
|
|
@ -551,7 +584,7 @@ pub(crate) fn can_be_overflowed_pat(
|
|||
| ast::PatKind::Tuple(..)
|
||||
| ast::PatKind::Struct(..)
|
||||
| ast::PatKind::TupleStruct(..) => context.use_block_indent() && len == 1,
|
||||
ast::PatKind::Ref(ref p, _) | ast::PatKind::Box(ref p) => {
|
||||
ast::PatKind::Ref(ref p, _, _) | ast::PatKind::Box(ref p) => {
|
||||
can_be_overflowed_pat(context, &TuplePatField::Pat(p), len)
|
||||
}
|
||||
ast::PatKind::Expr(ref expr) => can_be_overflowed_expr(context, expr, len),
|
||||
|
|
|
|||
|
|
@ -132,6 +132,19 @@ pub(crate) fn format_mutability(mutability: ast::Mutability) -> &'static str {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn format_pinnedness_and_mutability(
|
||||
pinnedness: ast::Pinnedness,
|
||||
mutability: ast::Mutability,
|
||||
) -> (&'static str, &'static str) {
|
||||
match (pinnedness, mutability) {
|
||||
(ast::Pinnedness::Pinned, ast::Mutability::Mut) => ("pin ", "mut "),
|
||||
(ast::Pinnedness::Pinned, ast::Mutability::Not) => ("pin ", "const "),
|
||||
(ast::Pinnedness::Not, ast::Mutability::Mut) => ("", "mut "),
|
||||
(ast::Pinnedness::Not, ast::Mutability::Not) => ("", ""),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn format_extern(ext: ast::Extern, explicit_abi: bool) -> Cow<'static, str> {
|
||||
match ext {
|
||||
|
|
|
|||
|
|
@ -28,3 +28,22 @@ fn borrows() {
|
|||
pin const
|
||||
foo;
|
||||
}
|
||||
|
||||
fn patterns<'a>(
|
||||
&pin mut x: &pin
|
||||
mut
|
||||
i32,
|
||||
&
|
||||
pin
|
||||
const
|
||||
y: &
|
||||
'a pin
|
||||
const
|
||||
i32,
|
||||
ref pin mut z: i32,
|
||||
mut
|
||||
ref
|
||||
pin
|
||||
const
|
||||
w: i32,
|
||||
) {}
|
||||
|
|
|
|||
|
|
@ -23,3 +23,11 @@ fn borrows() {
|
|||
|
||||
let x: Pin<&_> = &pin const foo;
|
||||
}
|
||||
|
||||
fn patterns<'a>(
|
||||
&pin mut x: &pin mut i32,
|
||||
&pin const y: &'a pin const i32,
|
||||
ref pin mut z: i32,
|
||||
mut ref pin const w: i32,
|
||||
) {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,4 +41,7 @@ fn bar() {
|
|||
foo_const(x);
|
||||
}
|
||||
|
||||
fn patterns<'a>(&pin mut x: Pin<&'_ mut i32>, &pin const y: Pin<&'a i32>,
|
||||
ref pin mut z: i32, ref pin const w: i32) { }
|
||||
|
||||
fn main() { }
|
||||
|
|
|
|||
|
|
@ -37,4 +37,11 @@ fn bar() {
|
|||
foo_const(x);
|
||||
}
|
||||
|
||||
fn patterns<'a>(
|
||||
&pin mut x: Pin<&mut i32>,
|
||||
&pin const y: Pin<&'a i32>,
|
||||
ref pin mut z: i32,
|
||||
ref pin const w: i32,
|
||||
) {}
|
||||
|
||||
fn main() { }
|
||||
|
|
|
|||
|
|
@ -34,4 +34,7 @@ fn bar() {
|
|||
foo_const(x);
|
||||
}
|
||||
|
||||
fn patterns<'a>(&pin mut x: &pin mut i32, &pin const y: &'a pin const i32,
|
||||
ref pin mut z: i32, ref pin const w: i32) {}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -47,6 +47,17 @@ fn borrows() {
|
|||
foo_const(x);
|
||||
}
|
||||
|
||||
fn patterns<'a>(
|
||||
&pin mut x: &pin mut i32,
|
||||
//~^ ERROR pinned reference syntax is experimental
|
||||
//~| ERROR pinned reference syntax is experimental
|
||||
&pin const y: &'a pin const i32,
|
||||
//~^ ERROR pinned reference syntax is experimental
|
||||
//~| ERROR pinned reference syntax is experimental
|
||||
ref pin mut z: i32, //~ ERROR pinned reference syntax is experimental
|
||||
ref pin const w: i32, //~ ERROR pinned reference syntax is experimental
|
||||
) {}
|
||||
|
||||
#[cfg(any())]
|
||||
mod not_compiled {
|
||||
use std::pin::Pin;
|
||||
|
|
@ -91,6 +102,17 @@ mod not_compiled {
|
|||
foo_const(x);
|
||||
foo_const(x);
|
||||
}
|
||||
|
||||
fn patterns<'a>(
|
||||
&pin mut x: &pin mut i32,
|
||||
//~^ ERROR pinned reference syntax is experimental
|
||||
//~| ERROR pinned reference syntax is experimental
|
||||
&pin const y: &'a pin const i32,
|
||||
//~^ ERROR pinned reference syntax is experimental
|
||||
//~| ERROR pinned reference syntax is experimental
|
||||
ref pin mut z: i32, //~ ERROR pinned reference syntax is experimental
|
||||
ref pin const w: i32, //~ ERROR pinned reference syntax is experimental
|
||||
) {}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -79,7 +79,67 @@ LL | let x: Pin<&_> = &pin const Foo;
|
|||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: pinned reference syntax is experimental
|
||||
--> $DIR/feature-gate-pin_ergonomics.rs:59:23
|
||||
--> $DIR/feature-gate-pin_ergonomics.rs:51:6
|
||||
|
|
||||
LL | &pin mut x: &pin mut i32,
|
||||
| ^^^
|
||||
|
|
||||
= note: see issue #130494 <https://github.com/rust-lang/rust/issues/130494> for more information
|
||||
= help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: pinned reference syntax is experimental
|
||||
--> $DIR/feature-gate-pin_ergonomics.rs:51:18
|
||||
|
|
||||
LL | &pin mut x: &pin mut i32,
|
||||
| ^^^
|
||||
|
|
||||
= note: see issue #130494 <https://github.com/rust-lang/rust/issues/130494> for more information
|
||||
= help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: pinned reference syntax is experimental
|
||||
--> $DIR/feature-gate-pin_ergonomics.rs:54:6
|
||||
|
|
||||
LL | &pin const y: &'a pin const i32,
|
||||
| ^^^
|
||||
|
|
||||
= note: see issue #130494 <https://github.com/rust-lang/rust/issues/130494> for more information
|
||||
= help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: pinned reference syntax is experimental
|
||||
--> $DIR/feature-gate-pin_ergonomics.rs:54:23
|
||||
|
|
||||
LL | &pin const y: &'a pin const i32,
|
||||
| ^^^
|
||||
|
|
||||
= note: see issue #130494 <https://github.com/rust-lang/rust/issues/130494> for more information
|
||||
= help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: pinned reference syntax is experimental
|
||||
--> $DIR/feature-gate-pin_ergonomics.rs:57:9
|
||||
|
|
||||
LL | ref pin mut z: i32,
|
||||
| ^^^
|
||||
|
|
||||
= note: see issue #130494 <https://github.com/rust-lang/rust/issues/130494> for more information
|
||||
= help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: pinned reference syntax is experimental
|
||||
--> $DIR/feature-gate-pin_ergonomics.rs:58:9
|
||||
|
|
||||
LL | ref pin const w: i32,
|
||||
| ^^^
|
||||
|
|
||||
= note: see issue #130494 <https://github.com/rust-lang/rust/issues/130494> for more information
|
||||
= help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: pinned reference syntax is experimental
|
||||
--> $DIR/feature-gate-pin_ergonomics.rs:70:23
|
||||
|
|
||||
LL | fn foo_sugar(&pin mut self) {}
|
||||
| ^^^
|
||||
|
|
@ -89,7 +149,7 @@ LL | fn foo_sugar(&pin mut self) {}
|
|||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: pinned reference syntax is experimental
|
||||
--> $DIR/feature-gate-pin_ergonomics.rs:60:29
|
||||
--> $DIR/feature-gate-pin_ergonomics.rs:71:29
|
||||
|
|
||||
LL | fn foo_sugar_const(&pin const self) {}
|
||||
| ^^^
|
||||
|
|
@ -99,7 +159,7 @@ LL | fn foo_sugar_const(&pin const self) {}
|
|||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: pinned reference syntax is experimental
|
||||
--> $DIR/feature-gate-pin_ergonomics.rs:66:18
|
||||
--> $DIR/feature-gate-pin_ergonomics.rs:77:18
|
||||
|
|
||||
LL | let _y: &pin mut Foo = x;
|
||||
| ^^^
|
||||
|
|
@ -109,7 +169,7 @@ LL | let _y: &pin mut Foo = x;
|
|||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: pinned reference syntax is experimental
|
||||
--> $DIR/feature-gate-pin_ergonomics.rs:69:22
|
||||
--> $DIR/feature-gate-pin_ergonomics.rs:80:22
|
||||
|
|
||||
LL | fn foo_sugar(_: &pin mut Foo) {}
|
||||
| ^^^
|
||||
|
|
@ -119,7 +179,7 @@ LL | fn foo_sugar(_: &pin mut Foo) {}
|
|||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: pinned reference syntax is experimental
|
||||
--> $DIR/feature-gate-pin_ergonomics.rs:81:22
|
||||
--> $DIR/feature-gate-pin_ergonomics.rs:92:22
|
||||
|
|
||||
LL | fn baz_sugar(_: &pin const Foo) {}
|
||||
| ^^^
|
||||
|
|
@ -129,7 +189,7 @@ LL | fn baz_sugar(_: &pin const Foo) {}
|
|||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: pinned reference syntax is experimental
|
||||
--> $DIR/feature-gate-pin_ergonomics.rs:84:35
|
||||
--> $DIR/feature-gate-pin_ergonomics.rs:95:35
|
||||
|
|
||||
LL | let mut x: Pin<&mut _> = &pin mut Foo;
|
||||
| ^^^
|
||||
|
|
@ -139,7 +199,7 @@ LL | let mut x: Pin<&mut _> = &pin mut Foo;
|
|||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: pinned reference syntax is experimental
|
||||
--> $DIR/feature-gate-pin_ergonomics.rs:89:27
|
||||
--> $DIR/feature-gate-pin_ergonomics.rs:100:27
|
||||
|
|
||||
LL | let x: Pin<&_> = &pin const Foo;
|
||||
| ^^^
|
||||
|
|
@ -148,6 +208,66 @@ LL | let x: Pin<&_> = &pin const Foo;
|
|||
= help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: pinned reference syntax is experimental
|
||||
--> $DIR/feature-gate-pin_ergonomics.rs:107:10
|
||||
|
|
||||
LL | &pin mut x: &pin mut i32,
|
||||
| ^^^
|
||||
|
|
||||
= note: see issue #130494 <https://github.com/rust-lang/rust/issues/130494> for more information
|
||||
= help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: pinned reference syntax is experimental
|
||||
--> $DIR/feature-gate-pin_ergonomics.rs:107:22
|
||||
|
|
||||
LL | &pin mut x: &pin mut i32,
|
||||
| ^^^
|
||||
|
|
||||
= note: see issue #130494 <https://github.com/rust-lang/rust/issues/130494> for more information
|
||||
= help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: pinned reference syntax is experimental
|
||||
--> $DIR/feature-gate-pin_ergonomics.rs:110:10
|
||||
|
|
||||
LL | &pin const y: &'a pin const i32,
|
||||
| ^^^
|
||||
|
|
||||
= note: see issue #130494 <https://github.com/rust-lang/rust/issues/130494> for more information
|
||||
= help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: pinned reference syntax is experimental
|
||||
--> $DIR/feature-gate-pin_ergonomics.rs:110:27
|
||||
|
|
||||
LL | &pin const y: &'a pin const i32,
|
||||
| ^^^
|
||||
|
|
||||
= note: see issue #130494 <https://github.com/rust-lang/rust/issues/130494> for more information
|
||||
= help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: pinned reference syntax is experimental
|
||||
--> $DIR/feature-gate-pin_ergonomics.rs:113:13
|
||||
|
|
||||
LL | ref pin mut z: i32,
|
||||
| ^^^
|
||||
|
|
||||
= note: see issue #130494 <https://github.com/rust-lang/rust/issues/130494> for more information
|
||||
= help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: pinned reference syntax is experimental
|
||||
--> $DIR/feature-gate-pin_ergonomics.rs:114:13
|
||||
|
|
||||
LL | ref pin const w: i32,
|
||||
| ^^^
|
||||
|
|
||||
= note: see issue #130494 <https://github.com/rust-lang/rust/issues/130494> for more information
|
||||
= help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: the `#[pin_v2]` attribute is an experimental feature
|
||||
--> $DIR/feature-gate-pin_ergonomics.rs:5:1
|
||||
|
|
||||
|
|
@ -196,7 +316,7 @@ help: consider reborrowing the `Pin` instead of moving it
|
|||
LL | x.as_mut().foo();
|
||||
| +++++++++
|
||||
|
||||
error: aborting due to 18 previous errors
|
||||
error: aborting due to 30 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0382, E0658.
|
||||
For more information about an error, try `rustc --explain E0382`.
|
||||
|
|
|
|||
114
tests/ui/pin-ergonomics/pin-pattern.rs
Normal file
114
tests/ui/pin-ergonomics/pin-pattern.rs
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
//@ edition:2024
|
||||
#![feature(pin_ergonomics)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
// This test verifies:
|
||||
// - a `&pin mut $pat` can be used to match on a pinned reference type `&pin mut T`;
|
||||
// - the subpattern can only convert the binding mode `&pin mut` to `&mut` when `T: Unpin`;
|
||||
// - the subpattern can only remove the binding mode `&pin mut` when `T: Copy`;
|
||||
|
||||
#[pin_v2]
|
||||
struct Foo<T>(T);
|
||||
|
||||
trait IsPinMut {}
|
||||
trait IsPinConst {}
|
||||
trait IsMut {}
|
||||
trait IsRef {}
|
||||
impl<T: ?Sized> IsPinMut for &pin mut T {}
|
||||
impl<T: ?Sized> IsPinConst for &pin const T {}
|
||||
impl<T: ?Sized> IsMut for &mut T {}
|
||||
impl<T: ?Sized> IsRef for &T {}
|
||||
|
||||
fn assert_pin_mut<T: IsPinMut>(_: T) {}
|
||||
fn assert_pin_const<T: IsPinConst>(_: T) {}
|
||||
fn assert_mut<T: IsMut>(_: T) {}
|
||||
fn assert_ref<T: IsRef>(_: T) {}
|
||||
fn assert_ty<T>(_: T) {}
|
||||
|
||||
fn normal<T>(foo_mut: &pin mut Foo<T>, foo_const: &pin const Foo<T>) {
|
||||
let &pin mut Foo(ref pin mut x) = foo_mut; // ok
|
||||
assert_pin_mut(x);
|
||||
|
||||
let &pin const Foo(ref pin const x) = foo_const; // ok
|
||||
assert_pin_const(x);
|
||||
}
|
||||
|
||||
fn by_value_copy<T: Copy>(foo_mut: &pin mut Foo<T>, foo_const: &pin const Foo<T>) {
|
||||
let &pin mut Foo(x) = foo_mut;
|
||||
assert_ty::<T>(x);
|
||||
|
||||
let &pin const Foo(x) = foo_const;
|
||||
assert_ty::<T>(x);
|
||||
}
|
||||
|
||||
fn by_value_non_copy<T>(foo_mut: &pin mut Foo<T>, foo_const: &pin const Foo<T>) {
|
||||
let &pin mut Foo(x) = foo_mut;
|
||||
//~^ ERROR cannot move out of `foo_mut.pointer` which is behind a mutable reference
|
||||
assert_ty::<T>(x);
|
||||
|
||||
let &pin const Foo(x) = foo_const;
|
||||
//~^ ERROR cannot move out of `foo_const.pointer` which is behind a shared reference
|
||||
assert_ty::<T>(x);
|
||||
}
|
||||
|
||||
fn by_ref_non_pinned_unpin<T: Unpin>(foo_mut: &pin mut Foo<T>, foo_const: &pin const Foo<T>) {
|
||||
let &pin mut Foo(ref mut x) = foo_mut;
|
||||
assert_mut(x);
|
||||
|
||||
let &pin const Foo(ref x) = foo_const;
|
||||
assert_ref(x);
|
||||
}
|
||||
|
||||
fn by_ref_non_pinned_non_unpin<T>(foo_mut: &pin mut Foo<T>, foo_const: &pin const Foo<T>) {
|
||||
let &pin mut Foo(ref mut x) = foo_mut;
|
||||
//~^ ERROR `T` cannot be unpinned
|
||||
assert_mut(x);
|
||||
|
||||
let &pin const Foo(ref x) = foo_const;
|
||||
//~^ ERROR `T` cannot be unpinned
|
||||
assert_ref(x);
|
||||
}
|
||||
|
||||
// Makes sure that `ref pin` binding mode cannot be changed to a `ref` binding mode.
|
||||
//
|
||||
// This mimics the following code:
|
||||
// ```
|
||||
// fn f<'a, T>(
|
||||
// ((&x,),): &'a (&'a mut (&'a T,),),
|
||||
// ) -> T {
|
||||
// x
|
||||
// }
|
||||
// ```
|
||||
fn tuple_tuple_ref_pin_mut_pat_and_pin_mut_of_tuple_mut_of_tuple_pin_mut_ty<'a, T>(
|
||||
((&pin mut x,),): &'a pin mut (&'a mut (&'a pin mut Foo<T>,),),
|
||||
//~^ ERROR cannot explicitly dereference within an implicitly-borrowing pattern
|
||||
//~| ERROR cannot move out of a mutable reference
|
||||
) -> Foo<T> {
|
||||
x
|
||||
}
|
||||
|
||||
fn tuple_ref_pin_mut_pat_and_mut_of_tuple_pin_mut_ty<'a, T>(
|
||||
(&pin mut x,): &'a mut (&'a pin mut Foo<T>,), //~ ERROR `T` cannot be unpinned
|
||||
) -> &'a mut Foo<T> {
|
||||
x
|
||||
}
|
||||
|
||||
fn tuple_ref_pin_mut_pat_and_mut_of_mut_tuple_pin_mut_ty<'a, T>(
|
||||
(&pin mut x,): &'a mut &'a pin mut (Foo<T>,), //~ ERROR mismatched type
|
||||
) -> &'a mut Foo<T> {
|
||||
x
|
||||
}
|
||||
|
||||
fn ref_pin_mut_tuple_pat_and_mut_of_tuple_pin_mut_ty<'a, T>(
|
||||
&pin mut (x,): &'a mut (&'a pin mut Foo<T>,), //~ ERROR mismatched type
|
||||
) -> &'a mut Foo<T> {
|
||||
x
|
||||
}
|
||||
|
||||
fn ref_pin_mut_tuple_pat_and_mut_of_mut_tuple_pin_mut_ty<'a, T>(
|
||||
&pin mut (x,): &'a mut &'a pin mut (Foo<T>,), //~ ERROR mismatched type
|
||||
) -> &'a mut Foo<T> {
|
||||
x
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
152
tests/ui/pin-ergonomics/pin-pattern.stderr
Normal file
152
tests/ui/pin-ergonomics/pin-pattern.stderr
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
error[E0277]: `T` cannot be unpinned
|
||||
--> $DIR/pin-pattern.rs:63:22
|
||||
|
|
||||
LL | let &pin mut Foo(ref mut x) = foo_mut;
|
||||
| ^^^^^^^^^ the trait `Unpin` is not implemented for `T`
|
||||
|
|
||||
= note: consider using the `pin!` macro
|
||||
consider using `Box::pin` if you need to access the pinned value outside of the current scope
|
||||
help: consider restricting type parameter `T` with trait `Unpin`
|
||||
|
|
||||
LL | fn by_ref_non_pinned_non_unpin<T: std::marker::Unpin>(foo_mut: &pin mut Foo<T>, foo_const: &pin const Foo<T>) {
|
||||
| ++++++++++++++++++++
|
||||
|
||||
error[E0277]: `T` cannot be unpinned
|
||||
--> $DIR/pin-pattern.rs:67:24
|
||||
|
|
||||
LL | let &pin const Foo(ref x) = foo_const;
|
||||
| ^^^^^ the trait `Unpin` is not implemented for `T`
|
||||
|
|
||||
= note: consider using the `pin!` macro
|
||||
consider using `Box::pin` if you need to access the pinned value outside of the current scope
|
||||
help: consider restricting type parameter `T` with trait `Unpin`
|
||||
|
|
||||
LL | fn by_ref_non_pinned_non_unpin<T: std::marker::Unpin>(foo_mut: &pin mut Foo<T>, foo_const: &pin const Foo<T>) {
|
||||
| ++++++++++++++++++++
|
||||
|
||||
error[E0277]: `T` cannot be unpinned
|
||||
--> $DIR/pin-pattern.rs:91:15
|
||||
|
|
||||
LL | (&pin mut x,): &'a mut (&'a pin mut Foo<T>,),
|
||||
| ^ within `Foo<T>`, the trait `Unpin` is not implemented for `T`
|
||||
|
|
||||
= note: consider using the `pin!` macro
|
||||
consider using `Box::pin` if you need to access the pinned value outside of the current scope
|
||||
note: required because it appears within the type `Foo<T>`
|
||||
--> $DIR/pin-pattern.rs:11:8
|
||||
|
|
||||
LL | struct Foo<T>(T);
|
||||
| ^^^
|
||||
help: consider restricting type parameter `T` with trait `Unpin`
|
||||
|
|
||||
LL | fn tuple_ref_pin_mut_pat_and_mut_of_tuple_pin_mut_ty<'a, T: std::marker::Unpin>(
|
||||
| ++++++++++++++++++++
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/pin-pattern.rs:97:6
|
||||
|
|
||||
LL | (&pin mut x,): &'a mut &'a pin mut (Foo<T>,),
|
||||
| ^^^^^^^^^^ ----------------------------- expected due to this
|
||||
| |
|
||||
| expected `Foo<T>`, found `Pin<&mut _>`
|
||||
|
|
||||
= note: expected struct `Foo<T>`
|
||||
found struct `Pin<&mut _>`
|
||||
note: to declare a mutable binding use: `mut x`
|
||||
--> $DIR/pin-pattern.rs:97:6
|
||||
|
|
||||
LL | (&pin mut x,): &'a mut &'a pin mut (Foo<T>,),
|
||||
| ^^^^^^^^^^
|
||||
help: consider removing `&pin mut` from the pattern
|
||||
|
|
||||
LL - (&pin mut x,): &'a mut &'a pin mut (Foo<T>,),
|
||||
LL + (x,): &'a mut &'a pin mut (Foo<T>,),
|
||||
|
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/pin-pattern.rs:103:5
|
||||
|
|
||||
LL | &pin mut (x,): &'a mut (&'a pin mut Foo<T>,),
|
||||
| ^^^^^^^^^^^^^ ----------------------------- expected due to this
|
||||
| |
|
||||
| expected `&mut (Pin<&mut Foo<T>>,)`, found `Pin<&mut _>`
|
||||
|
|
||||
= note: expected mutable reference `&'a mut (Pin<&'a mut Foo<T>>,)`
|
||||
found struct `Pin<&mut _>`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/pin-pattern.rs:109:5
|
||||
|
|
||||
LL | &pin mut (x,): &'a mut &'a pin mut (Foo<T>,),
|
||||
| ^^^^^^^^^^^^^ ----------------------------- expected due to this
|
||||
| |
|
||||
| expected `&mut Pin<&mut (Foo<T>,)>`, found `Pin<&mut _>`
|
||||
|
|
||||
= note: expected mutable reference `&'a mut Pin<&'a mut (Foo<T>,)>`
|
||||
found struct `Pin<&mut _>`
|
||||
|
||||
error[E0507]: cannot move out of `foo_mut.pointer` which is behind a mutable reference
|
||||
--> $DIR/pin-pattern.rs:45:27
|
||||
|
|
||||
LL | let &pin mut Foo(x) = foo_mut;
|
||||
| - ^^^^^^^
|
||||
| |
|
||||
| data moved here
|
||||
| move occurs because `x` has type `T`, which does not implement the `Copy` trait
|
||||
|
|
||||
help: consider removing the pinned mutable borrow
|
||||
|
|
||||
LL - let &pin mut Foo(x) = foo_mut;
|
||||
LL + let Foo(x) = foo_mut;
|
||||
|
|
||||
|
||||
error[E0507]: cannot move out of `foo_const.pointer` which is behind a shared reference
|
||||
--> $DIR/pin-pattern.rs:49:29
|
||||
|
|
||||
LL | let &pin const Foo(x) = foo_const;
|
||||
| - ^^^^^^^^^
|
||||
| |
|
||||
| data moved here
|
||||
| move occurs because `x` has type `T`, which does not implement the `Copy` trait
|
||||
|
|
||||
help: consider removing the pinned borrow
|
||||
|
|
||||
LL - let &pin const Foo(x) = foo_const;
|
||||
LL + let Foo(x) = foo_const;
|
||||
|
|
||||
|
||||
error: cannot explicitly dereference within an implicitly-borrowing pattern
|
||||
--> $DIR/pin-pattern.rs:83:7
|
||||
|
|
||||
LL | ((&pin mut x,),): &'a pin mut (&'a mut (&'a pin mut Foo<T>,),),
|
||||
| ^^^^^^^^ reference pattern not allowed when implicitly borrowing
|
||||
|
|
||||
= note: for more information, see <https://doc.rust-lang.org/reference/patterns.html#binding-modes>
|
||||
note: matching on a reference type with a non-reference pattern implicitly borrows the contents
|
||||
--> $DIR/pin-pattern.rs:83:6
|
||||
|
|
||||
LL | ((&pin mut x,),): &'a pin mut (&'a mut (&'a pin mut Foo<T>,),),
|
||||
| ^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&mut _`
|
||||
help: match on the reference with a reference pattern to avoid implicitly borrowing
|
||||
|
|
||||
LL | (&mut (&pin mut x,),): &'a pin mut (&'a mut (&'a pin mut Foo<T>,),),
|
||||
| ++++
|
||||
|
||||
error[E0507]: cannot move out of a mutable reference
|
||||
--> $DIR/pin-pattern.rs:83:5
|
||||
|
|
||||
LL | ((&pin mut x,),): &'a pin mut (&'a mut (&'a pin mut Foo<T>,),),
|
||||
| ^^^^^^^^^^^-^^^^
|
||||
| |
|
||||
| data moved here
|
||||
| move occurs because `x` has type `Foo<T>`, which does not implement the `Copy` trait
|
||||
|
|
||||
help: consider borrowing the pattern binding
|
||||
|
|
||||
LL | ((&pin mut ref x,),): &'a pin mut (&'a mut (&'a pin mut Foo<T>,),),
|
||||
| +++
|
||||
|
||||
error: aborting due to 10 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0277, E0308, E0507.
|
||||
For more information about an error, try `rustc --explain E0277`.
|
||||
|
|
@ -8,8 +8,16 @@ struct Foo;
|
|||
|
||||
mod pin {
|
||||
pub struct Foo;
|
||||
#[expect(non_camel_case_types)]
|
||||
pub struct pin;
|
||||
|
||||
fn foo() {
|
||||
let _x: &pin = &pin;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _x: &pin ::Foo = &pin::Foo;
|
||||
let _x: &pin::Foo = &pin::Foo;
|
||||
let &pin: &i32 = &0;
|
||||
let ref pin: i32 = 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,22 @@
|
|||
|
||||
// Makes sure we don't accidentally accept `&pin Foo` without the `const` keyword.
|
||||
|
||||
fn main() {
|
||||
fn ty() {
|
||||
let _x: &pin i32 = todo!(); //~ ERROR found `i32`
|
||||
}
|
||||
|
||||
fn expr() {
|
||||
let x = 0_i32;
|
||||
let _x = &pin x; //~ ERROR found `x`
|
||||
}
|
||||
|
||||
fn pat() {
|
||||
let &pin _x: &pin i32 = todo!(); //~ ERROR found `_x`
|
||||
}
|
||||
|
||||
fn binding() {
|
||||
let ref pin _x: i32 = todo!(); //~ ERROR found `_x`
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,5 +12,41 @@ LL - let _x: &pin i32 = todo!();
|
|||
LL + let _x: &in i32 = todo!();
|
||||
|
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
error: expected one of `!`, `.`, `::`, `;`, `?`, `else`, `{`, or an operator, found `x`
|
||||
--> $DIR/sugar-no-const.rs:12:19
|
||||
|
|
||||
LL | let _x = &pin x;
|
||||
| ^ expected one of 8 possible tokens
|
||||
|
|
||||
help: there is a keyword `in` with a similar name
|
||||
|
|
||||
LL - let _x = &pin x;
|
||||
LL + let _x = &in x;
|
||||
|
|
||||
|
||||
error: expected one of `:`, `;`, `=`, `@`, or `|`, found `_x`
|
||||
--> $DIR/sugar-no-const.rs:16:14
|
||||
|
|
||||
LL | let &pin _x: &pin i32 = todo!();
|
||||
| ^^ expected one of `:`, `;`, `=`, `@`, or `|`
|
||||
|
|
||||
help: there is a keyword `in` with a similar name
|
||||
|
|
||||
LL - let &pin _x: &pin i32 = todo!();
|
||||
LL + let &in _x: &pin i32 = todo!();
|
||||
|
|
||||
|
||||
error: expected one of `:`, `;`, `=`, `@`, or `|`, found `_x`
|
||||
--> $DIR/sugar-no-const.rs:20:17
|
||||
|
|
||||
LL | let ref pin _x: i32 = todo!();
|
||||
| ^^ expected one of `:`, `;`, `=`, `@`, or `|`
|
||||
|
|
||||
help: there is a keyword `in` with a similar name
|
||||
|
|
||||
LL - let ref pin _x: i32 = todo!();
|
||||
LL + let ref in _x: i32 = todo!();
|
||||
|
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue