mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 00:03:43 +00:00
Implement mut ref
/mut ref mut
This commit is contained in:
parent
10a7aa14fe
commit
e0da13f25f
@ -702,19 +702,10 @@ pub struct PatField {
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
#[derive(Encodable, Decodable, HashStable_Generic)]
|
||||
pub enum ByRef {
|
||||
Yes,
|
||||
Yes(Mutability),
|
||||
No,
|
||||
}
|
||||
|
||||
impl From<bool> for ByRef {
|
||||
fn from(b: bool) -> ByRef {
|
||||
match b {
|
||||
false => ByRef::No,
|
||||
true => ByRef::Yes,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Explicit binding annotations given in the HIR for a binding. Note
|
||||
/// that this is not the final binding *mode* that we infer after type
|
||||
/// inference.
|
||||
@ -724,9 +715,11 @@ pub struct BindingAnnotation(pub ByRef, pub Mutability);
|
||||
|
||||
impl BindingAnnotation {
|
||||
pub const NONE: Self = Self(ByRef::No, Mutability::Not);
|
||||
pub const REF: Self = Self(ByRef::Yes, Mutability::Not);
|
||||
pub const REF: Self = Self(ByRef::Yes(Mutability::Not), Mutability::Not);
|
||||
pub const MUT: Self = Self(ByRef::No, Mutability::Mut);
|
||||
pub const REF_MUT: Self = Self(ByRef::Yes, Mutability::Mut);
|
||||
pub const REF_MUT: Self = Self(ByRef::Yes(Mutability::Mut), Mutability::Not);
|
||||
pub const MUT_REF: Self = Self(ByRef::Yes(Mutability::Not), Mutability::Mut);
|
||||
pub const MUT_REF_MUT: Self = Self(ByRef::Yes(Mutability::Mut), Mutability::Mut);
|
||||
|
||||
pub fn prefix_str(self) -> &'static str {
|
||||
match self {
|
||||
@ -734,6 +727,8 @@ impl BindingAnnotation {
|
||||
Self::REF => "ref ",
|
||||
Self::MUT => "mut ",
|
||||
Self::REF_MUT => "ref mut ",
|
||||
Self::MUT_REF => "mut ref ",
|
||||
Self::MUT_REF_MUT => "mut ref mut ",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1847,8 +1847,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
// the case where we have a mutable pattern to a reference as that would
|
||||
// no longer be an `ImplicitSelf`.
|
||||
TyKind::Ref(_, mt) if mt.ty.kind.is_implicit_self() => match mt.mutbl {
|
||||
hir::Mutability::Not => hir::ImplicitSelfKind::ImmRef,
|
||||
hir::Mutability::Mut => hir::ImplicitSelfKind::MutRef,
|
||||
hir::Mutability::Not => hir::ImplicitSelfKind::RefImm,
|
||||
hir::Mutability::Mut => hir::ImplicitSelfKind::RefMut,
|
||||
},
|
||||
_ => hir::ImplicitSelfKind::None,
|
||||
}
|
||||
|
@ -1545,12 +1545,15 @@ impl<'a> State<'a> {
|
||||
PatKind::Wild => self.word("_"),
|
||||
PatKind::Never => self.word("!"),
|
||||
PatKind::Ident(BindingAnnotation(by_ref, mutbl), ident, sub) => {
|
||||
if *by_ref == ByRef::Yes {
|
||||
self.word_nbsp("ref");
|
||||
}
|
||||
if mutbl.is_mut() {
|
||||
self.word_nbsp("mut");
|
||||
}
|
||||
if let ByRef::Yes(rmutbl) = by_ref {
|
||||
self.word_nbsp("ref");
|
||||
if rmutbl.is_mut() {
|
||||
self.word_nbsp("mut");
|
||||
}
|
||||
}
|
||||
self.print_ident(*ident);
|
||||
if let Some(p) = sub {
|
||||
self.space();
|
||||
|
@ -4,9 +4,8 @@
|
||||
use core::ops::ControlFlow;
|
||||
use hir::{ExprKind, Param};
|
||||
use rustc_errors::{Applicability, Diag};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::Node;
|
||||
use rustc_hir::{self as hir, BindingAnnotation, ByRef, Node};
|
||||
use rustc_infer::traits;
|
||||
use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
|
||||
use rustc_middle::ty::{self, InstanceDef, ToPredicate, Ty, TyCtxt};
|
||||
@ -304,7 +303,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
{
|
||||
match *decl.local_info() {
|
||||
LocalInfo::User(BindingForm::Var(mir::VarBindingForm {
|
||||
binding_mode: ty::BindingMode::BindByValue(Mutability::Not),
|
||||
binding_mode: BindingAnnotation(ByRef::No, Mutability::Not),
|
||||
opt_ty_info: Some(sp),
|
||||
opt_match_place: _,
|
||||
pat_span: _,
|
||||
@ -342,7 +341,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
} else if decl.mutability.is_not() {
|
||||
if matches!(
|
||||
decl.local_info(),
|
||||
LocalInfo::User(BindingForm::ImplicitSelf(hir::ImplicitSelfKind::MutRef))
|
||||
LocalInfo::User(BindingForm::ImplicitSelf(hir::ImplicitSelfKind::RefMut))
|
||||
) {
|
||||
err.note(
|
||||
"as `Self` may be unsized, this call attempts to take `&mut &mut self`",
|
||||
@ -407,7 +406,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
if let Some(fn_decl) = node.fn_decl() {
|
||||
if !matches!(
|
||||
fn_decl.implicit_self,
|
||||
hir::ImplicitSelfKind::ImmRef | hir::ImplicitSelfKind::MutRef
|
||||
hir::ImplicitSelfKind::RefImm | hir::ImplicitSelfKind::RefMut
|
||||
) {
|
||||
err.span_suggestion(
|
||||
upvar_ident.span,
|
||||
@ -717,7 +716,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
debug!("local_decl: {:?}", local_decl);
|
||||
let pat_span = match *local_decl.local_info() {
|
||||
LocalInfo::User(BindingForm::Var(mir::VarBindingForm {
|
||||
binding_mode: ty::BindingMode::BindByValue(Mutability::Not),
|
||||
binding_mode: BindingAnnotation(ByRef::No, Mutability::Not),
|
||||
opt_ty_info: _,
|
||||
opt_match_place: _,
|
||||
pat_span,
|
||||
@ -1070,7 +1069,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
}
|
||||
|
||||
LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
|
||||
binding_mode: ty::BindingMode::BindByValue(_),
|
||||
binding_mode: BindingAnnotation(ByRef::No, _),
|
||||
opt_ty_info,
|
||||
..
|
||||
})) => {
|
||||
@ -1138,7 +1137,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
}
|
||||
|
||||
LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
|
||||
binding_mode: ty::BindingMode::BindByReference(_),
|
||||
binding_mode: BindingAnnotation(ByRef::Yes(_), _),
|
||||
..
|
||||
})) => {
|
||||
let pattern_span: Span = local_decl.source_info.span;
|
||||
@ -1329,7 +1328,7 @@ pub fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<
|
||||
match *local_decl.local_info() {
|
||||
// Check if mutably borrowing a mutable reference.
|
||||
LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
|
||||
binding_mode: ty::BindingMode::BindByValue(Mutability::Not),
|
||||
binding_mode: BindingAnnotation(ByRef::No, Mutability::Not),
|
||||
..
|
||||
})) => matches!(local_decl.ty.kind(), ty::Ref(_, _, hir::Mutability::Mut)),
|
||||
LocalInfo::User(mir::BindingForm::ImplicitSelf(kind)) => {
|
||||
@ -1338,7 +1337,7 @@ pub fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<
|
||||
//
|
||||
// Deliberately fall into this case for all implicit self types,
|
||||
// so that we don't fall into the next case with them.
|
||||
kind == hir::ImplicitSelfKind::MutRef
|
||||
kind == hir::ImplicitSelfKind::RefMut
|
||||
}
|
||||
_ if Some(kw::SelfLower) == local_name => {
|
||||
// Otherwise, check if the name is the `self` keyword - in which case
|
||||
|
@ -2733,9 +2733,9 @@ pub enum ImplicitSelfKind {
|
||||
/// Represents a `fn x(mut self);`.
|
||||
Mut,
|
||||
/// Represents a `fn x(&self);`.
|
||||
ImmRef,
|
||||
RefImm,
|
||||
/// Represents a `fn x(&mut self);`.
|
||||
MutRef,
|
||||
RefMut,
|
||||
/// Represents when a function does not have a self argument or
|
||||
/// when a function has a `self: X` argument.
|
||||
None,
|
||||
|
@ -14,14 +14,7 @@ pub fn maybe_expr_static_mut(tcx: TyCtxt<'_>, expr: hir::Expr<'_>) {
|
||||
&& matches!(borrow_kind, hir::BorrowKind::Ref)
|
||||
&& let Some(var) = is_path_static_mut(*expr)
|
||||
{
|
||||
handle_static_mut_ref(
|
||||
tcx,
|
||||
span,
|
||||
var,
|
||||
span.edition().at_least_rust_2024(),
|
||||
matches!(m, Mutability::Mut),
|
||||
hir_id,
|
||||
);
|
||||
handle_static_mut_ref(tcx, span, var, span.edition().at_least_rust_2024(), m, hir_id);
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,7 +22,7 @@ pub fn maybe_expr_static_mut(tcx: TyCtxt<'_>, expr: hir::Expr<'_>) {
|
||||
pub fn maybe_stmt_static_mut(tcx: TyCtxt<'_>, stmt: hir::Stmt<'_>) {
|
||||
if let hir::StmtKind::Let(loc) = stmt.kind
|
||||
&& let hir::PatKind::Binding(ba, _, _, _) = loc.pat.kind
|
||||
&& matches!(ba.0, rustc_ast::ByRef::Yes)
|
||||
&& let hir::ByRef::Yes(rmutbl) = ba.0
|
||||
&& let Some(init) = loc.init
|
||||
&& let Some(var) = is_path_static_mut(*init)
|
||||
{
|
||||
@ -38,7 +31,7 @@ pub fn maybe_stmt_static_mut(tcx: TyCtxt<'_>, stmt: hir::Stmt<'_>) {
|
||||
init.span,
|
||||
var,
|
||||
loc.span.edition().at_least_rust_2024(),
|
||||
matches!(ba.1, Mutability::Mut),
|
||||
rmutbl,
|
||||
stmt.hir_id,
|
||||
);
|
||||
}
|
||||
@ -60,28 +53,27 @@ fn handle_static_mut_ref(
|
||||
span: Span,
|
||||
var: String,
|
||||
e2024: bool,
|
||||
mutable: bool,
|
||||
mutable: Mutability,
|
||||
hir_id: hir::HirId,
|
||||
) {
|
||||
if e2024 {
|
||||
let (sugg, shared) = if mutable {
|
||||
let (sugg, shared) = if mutable == Mutability::Mut {
|
||||
(errors::StaticMutRefSugg::Mut { span, var }, "mutable")
|
||||
} else {
|
||||
(errors::StaticMutRefSugg::Shared { span, var }, "shared")
|
||||
};
|
||||
tcx.sess.psess.dcx.emit_err(errors::StaticMutRef { span, sugg, shared });
|
||||
return;
|
||||
}
|
||||
|
||||
let (sugg, shared) = if mutable {
|
||||
(errors::RefOfMutStaticSugg::Mut { span, var }, "mutable")
|
||||
} else {
|
||||
(errors::RefOfMutStaticSugg::Shared { span, var }, "shared")
|
||||
};
|
||||
tcx.emit_node_span_lint(
|
||||
STATIC_MUT_REFS,
|
||||
hir_id,
|
||||
span,
|
||||
errors::RefOfMutStatic { span, sugg, shared },
|
||||
);
|
||||
let (sugg, shared) = if mutable == Mutability::Mut {
|
||||
(errors::RefOfMutStaticSugg::Mut { span, var }, "mutable")
|
||||
} else {
|
||||
(errors::RefOfMutStaticSugg::Shared { span, var }, "shared")
|
||||
};
|
||||
tcx.emit_node_span_lint(
|
||||
STATIC_MUT_REFS,
|
||||
hir_id,
|
||||
span,
|
||||
errors::RefOfMutStatic { span, sugg, shared },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -654,7 +654,7 @@ fn resolve_local<'tcx>(
|
||||
// & expression, and its lifetime would be extended to the end of the block (due
|
||||
// to a different rule, not the below code).
|
||||
match pat.kind {
|
||||
PatKind::Binding(hir::BindingAnnotation(hir::ByRef::Yes, _), ..) => true,
|
||||
PatKind::Binding(hir::BindingAnnotation(hir::ByRef::Yes(_), _), ..) => true,
|
||||
|
||||
PatKind::Struct(_, field_pats, _) => field_pats.iter().any(|fp| is_binding_pat(fp.pat)),
|
||||
|
||||
|
@ -1721,12 +1721,15 @@ impl<'a> State<'a> {
|
||||
PatKind::Wild => self.word("_"),
|
||||
PatKind::Never => self.word("!"),
|
||||
PatKind::Binding(BindingAnnotation(by_ref, mutbl), _, ident, sub) => {
|
||||
if by_ref == ByRef::Yes {
|
||||
self.word_nbsp("ref");
|
||||
}
|
||||
if mutbl.is_mut() {
|
||||
self.word_nbsp("mut");
|
||||
}
|
||||
if let ByRef::Yes(rmutbl) = by_ref {
|
||||
self.word_nbsp("ref");
|
||||
if rmutbl.is_mut() {
|
||||
self.word_nbsp("mut");
|
||||
}
|
||||
}
|
||||
self.print_ident(ident);
|
||||
if let Some(p) = sub {
|
||||
self.word("@");
|
||||
|
@ -739,12 +739,12 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
|
||||
// In a cases of pattern like `let pat = upvar`, don't use the span
|
||||
// of the pattern, as this just looks confusing, instead use the span
|
||||
// of the discriminant.
|
||||
match bm {
|
||||
ty::BindByReference(m) => {
|
||||
match bm.0 {
|
||||
hir::ByRef::Yes(m) => {
|
||||
let bk = ty::BorrowKind::from_mutbl(m);
|
||||
delegate.borrow(place, discr_place.hir_id, bk);
|
||||
}
|
||||
ty::BindByValue(..) => {
|
||||
hir::ByRef::No => {
|
||||
debug!("walk_pat binding consuming pat");
|
||||
delegate_consume(mc, *delegate, place, discr_place.hir_id);
|
||||
}
|
||||
|
@ -206,7 +206,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
|
||||
.get(pat.hir_id)
|
||||
.expect("missing binding mode");
|
||||
|
||||
if let ty::BindByReference(_) = bm {
|
||||
if matches!(bm.0, hir::ByRef::Yes(_)) {
|
||||
// a bind-by-ref means that the base_ty will be the type of the ident itself,
|
||||
// but what we want here is the type of the underlying value being borrowed.
|
||||
// So peel off one-level, turning the &T into T.
|
||||
|
@ -5,14 +5,13 @@ use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::{
|
||||
codes::*, pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, MultiSpan,
|
||||
};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorKind, DefKind, Res};
|
||||
use rustc_hir::pat_util::EnumerateAndAdjustIterator;
|
||||
use rustc_hir::{HirId, Pat, PatKind};
|
||||
use rustc_hir::{self as hir, BindingAnnotation, ByRef, HirId, Mutability, Pat, PatKind};
|
||||
use rustc_infer::infer;
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_middle::mir::interpret::ErrorHandled;
|
||||
use rustc_middle::ty::{self, Adt, BindingMode, Ty, TypeVisitableExt};
|
||||
use rustc_middle::ty::{self, Adt, Ty, TypeVisitableExt};
|
||||
use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
|
||||
use rustc_span::edit_distance::find_best_match_for_name;
|
||||
use rustc_span::hygiene::DesugaringKind;
|
||||
@ -79,7 +78,7 @@ struct TopInfo<'tcx> {
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct PatInfo<'tcx, 'a> {
|
||||
binding_mode: BindingMode,
|
||||
binding_mode: BindingAnnotation,
|
||||
top_info: TopInfo<'tcx>,
|
||||
decl_origin: Option<DeclOrigin<'a>>,
|
||||
|
||||
@ -124,7 +123,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
const INITIAL_BM: BindingMode = BindingMode::BindByValue(hir::Mutability::Not);
|
||||
const INITIAL_BM: BindingAnnotation = BindingAnnotation(ByRef::No, Mutability::Not);
|
||||
|
||||
/// Mode for adjusting the expected type and binding mode.
|
||||
enum AdjustMode {
|
||||
@ -269,9 +268,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
&self,
|
||||
pat: &'tcx Pat<'tcx>,
|
||||
expected: Ty<'tcx>,
|
||||
def_bm: BindingMode,
|
||||
def_bm: BindingAnnotation,
|
||||
adjust_mode: AdjustMode,
|
||||
) -> (Ty<'tcx>, BindingMode) {
|
||||
) -> (Ty<'tcx>, BindingAnnotation) {
|
||||
match adjust_mode {
|
||||
AdjustMode::Pass => (expected, def_bm),
|
||||
AdjustMode::Reset => (expected, INITIAL_BM),
|
||||
@ -354,8 +353,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
&self,
|
||||
pat: &'tcx Pat<'tcx>,
|
||||
expected: Ty<'tcx>,
|
||||
mut def_bm: BindingMode,
|
||||
) -> (Ty<'tcx>, BindingMode) {
|
||||
mut def_bm: BindingAnnotation,
|
||||
) -> (Ty<'tcx>, BindingAnnotation) {
|
||||
let mut expected = self.try_structurally_resolve_type(pat.span, expected);
|
||||
// Peel off as many `&` or `&mut` from the scrutinee type as possible. For example,
|
||||
// for `match &&&mut Some(5)` the loop runs three times, aborting when it reaches
|
||||
@ -374,15 +373,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
pat_adjustments.push(expected);
|
||||
|
||||
expected = self.try_structurally_resolve_type(pat.span, inner_ty);
|
||||
def_bm = ty::BindByReference(match def_bm {
|
||||
def_bm.0 = ByRef::Yes(match def_bm.0 {
|
||||
// If default binding mode is by value, make it `ref` or `ref mut`
|
||||
// (depending on whether we observe `&` or `&mut`).
|
||||
ty::BindByValue(_) |
|
||||
ByRef::No |
|
||||
// When `ref mut`, stay a `ref mut` (on `&mut`) or downgrade to `ref` (on `&`).
|
||||
ty::BindByReference(hir::Mutability::Mut) => inner_mutability,
|
||||
ByRef::Yes(Mutability::Mut) => inner_mutability,
|
||||
// Once a `ref`, always a `ref`.
|
||||
// This is because a `& &mut` cannot mutate the underlying value.
|
||||
ty::BindByReference(m @ hir::Mutability::Not) => m,
|
||||
ByRef::Yes(Mutability::Not) => Mutability::Not,
|
||||
});
|
||||
}
|
||||
|
||||
@ -599,7 +598,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
fn check_pat_ident(
|
||||
&self,
|
||||
pat: &'tcx Pat<'tcx>,
|
||||
ba: hir::BindingAnnotation,
|
||||
ba: BindingAnnotation,
|
||||
var_id: HirId,
|
||||
sub: Option<&'tcx Pat<'tcx>>,
|
||||
expected: Ty<'tcx>,
|
||||
@ -609,8 +608,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
// Determine the binding mode...
|
||||
let bm = match ba {
|
||||
hir::BindingAnnotation::NONE => def_bm,
|
||||
_ => BindingMode::convert(ba),
|
||||
BindingAnnotation(ByRef::No, Mutability::Not) => def_bm,
|
||||
_ => ba,
|
||||
};
|
||||
// ...and store it in a side table:
|
||||
self.typeck_results.borrow_mut().pat_binding_modes_mut().insert(pat.hir_id, bm);
|
||||
@ -618,8 +617,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
debug!("check_pat_ident: pat.hir_id={:?} bm={:?}", pat.hir_id, bm);
|
||||
|
||||
let local_ty = self.local_ty(pat.span, pat.hir_id);
|
||||
let eq_ty = match bm {
|
||||
ty::BindByReference(mutbl) => {
|
||||
let eq_ty = match bm.0 {
|
||||
ByRef::Yes(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.
|
||||
@ -630,10 +629,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
self.new_ref_ty(pat.span, mutbl, expected)
|
||||
}
|
||||
// Otherwise, the type of x is the expected type `T`.
|
||||
ty::BindByValue(_) => {
|
||||
// As above, `T <: typeof(x)` is required, but we use equality, see (note_1).
|
||||
expected
|
||||
}
|
||||
ByRef::No => expected, // As above, `T <: typeof(x)` is required, but we use equality, see (note_1).
|
||||
};
|
||||
self.demand_eqtype_pat(pat.span, eq_ty, local_ty, ti);
|
||||
|
||||
@ -655,7 +651,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
/// bindings have the same type by comparing them all against the type of that first pat.
|
||||
fn check_binding_alt_eq_ty(
|
||||
&self,
|
||||
ba: hir::BindingAnnotation,
|
||||
ba: BindingAnnotation,
|
||||
span: Span,
|
||||
var_id: HirId,
|
||||
ty: Ty<'tcx>,
|
||||
@ -695,10 +691,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
span: Span,
|
||||
expected: Ty<'tcx>,
|
||||
actual: Ty<'tcx>,
|
||||
ba: hir::BindingAnnotation,
|
||||
ba: BindingAnnotation,
|
||||
) {
|
||||
match (expected.kind(), actual.kind(), ba) {
|
||||
(ty::Ref(_, inner_ty, _), _, hir::BindingAnnotation::NONE)
|
||||
(ty::Ref(_, inner_ty, _), _, BindingAnnotation::NONE)
|
||||
if self.can_eq(self.param_env, *inner_ty, actual) =>
|
||||
{
|
||||
err.span_suggestion_verbose(
|
||||
@ -708,7 +704,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
(_, ty::Ref(_, inner_ty, _), hir::BindingAnnotation::REF)
|
||||
(_, ty::Ref(_, inner_ty, _), BindingAnnotation::REF)
|
||||
if self.can_eq(self.param_env, expected, *inner_ty) =>
|
||||
{
|
||||
err.span_suggestion_verbose(
|
||||
@ -800,7 +796,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
if let PatKind::Ref(the_ref, _) = i.kind
|
||||
&& let PatKind::Binding(mt, _, ident, _) = the_ref.kind
|
||||
{
|
||||
let hir::BindingAnnotation(_, mtblty) = mt;
|
||||
let BindingAnnotation(_, mtblty) = mt;
|
||||
err.span_suggestion_verbose(
|
||||
i.span,
|
||||
format!("consider removing `&{mutability}` from the pattern"),
|
||||
@ -2037,7 +2033,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
&self,
|
||||
pat: &'tcx Pat<'tcx>,
|
||||
inner: &'tcx Pat<'tcx>,
|
||||
mutbl: hir::Mutability,
|
||||
mutbl: Mutability,
|
||||
expected: Ty<'tcx>,
|
||||
pat_info: PatInfo<'tcx, '_>,
|
||||
) -> Ty<'tcx> {
|
||||
@ -2088,7 +2084,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
|
||||
/// Create a reference type with a fresh region variable.
|
||||
fn new_ref_ty(&self, span: Span, mutbl: hir::Mutability, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
fn new_ref_ty(&self, span: Span, mutbl: Mutability, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
let region = self.next_region_var(infer::PatternRegion(span));
|
||||
Ty::new_ref(self.tcx, region, ty, mutbl)
|
||||
}
|
||||
|
@ -1711,10 +1711,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
let bm = *typeck_results.pat_binding_modes().get(var_hir_id).expect("missing binding mode");
|
||||
|
||||
let mut is_mutbl = match bm {
|
||||
ty::BindByValue(mutability) => mutability,
|
||||
ty::BindByReference(_) => hir::Mutability::Not,
|
||||
};
|
||||
let mut is_mutbl = bm.1;
|
||||
|
||||
for pointer_ty in place.deref_tys() {
|
||||
match pointer_ty.kind() {
|
||||
|
@ -17,8 +17,10 @@ use rustc_data_structures::captures::Captures;
|
||||
use rustc_errors::{DiagArgName, DiagArgValue, DiagMessage, ErrorGuaranteed, IntoDiagArg};
|
||||
use rustc_hir::def::{CtorKind, Namespace};
|
||||
use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
|
||||
use rustc_hir::{self, CoroutineDesugaring, CoroutineKind, ImplicitSelfKind};
|
||||
use rustc_hir::{self as hir, HirId};
|
||||
use rustc_hir::{
|
||||
self as hir, BindingAnnotation, ByRef, CoroutineDesugaring, CoroutineKind, HirId,
|
||||
ImplicitSelfKind,
|
||||
};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_target::abi::{FieldIdx, VariantIdx};
|
||||
@ -992,8 +994,8 @@ pub enum LocalKind {
|
||||
|
||||
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
|
||||
pub struct VarBindingForm<'tcx> {
|
||||
/// Is variable bound via `x`, `mut x`, `ref x`, or `ref mut x`?
|
||||
pub binding_mode: ty::BindingMode,
|
||||
/// Is variable bound via `x`, `mut x`, `ref x`, `ref mut x`, `mut ref x`, or `mut ref mut x`?
|
||||
pub binding_mode: BindingAnnotation,
|
||||
/// If an explicit type was provided for this variable binding,
|
||||
/// this holds the source Span of that type.
|
||||
///
|
||||
@ -1218,7 +1220,7 @@ impl<'tcx> LocalDecl<'tcx> {
|
||||
self.local_info(),
|
||||
LocalInfo::User(
|
||||
BindingForm::Var(VarBindingForm {
|
||||
binding_mode: ty::BindingMode::BindByValue(_),
|
||||
binding_mode: BindingAnnotation(ByRef::No, _),
|
||||
opt_ty_info: _,
|
||||
opt_match_place: _,
|
||||
pat_span: _,
|
||||
@ -1235,7 +1237,7 @@ impl<'tcx> LocalDecl<'tcx> {
|
||||
self.local_info(),
|
||||
LocalInfo::User(
|
||||
BindingForm::Var(VarBindingForm {
|
||||
binding_mode: ty::BindingMode::BindByValue(_),
|
||||
binding_mode: BindingAnnotation(ByRef::No, _),
|
||||
opt_ty_info: _,
|
||||
opt_match_place: _,
|
||||
pat_span: _,
|
||||
|
@ -12,12 +12,12 @@ use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
||||
use rustc_errors::{DiagArgValue, IntoDiagArg};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::RangeEnd;
|
||||
use rustc_hir::{BindingAnnotation, ByRef, RangeEnd};
|
||||
use rustc_index::newtype_index;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_middle::middle::region;
|
||||
use rustc_middle::mir::interpret::{AllocId, Scalar};
|
||||
use rustc_middle::mir::{self, BinOp, BorrowKind, FakeReadCause, Mutability, UnOp};
|
||||
use rustc_middle::mir::{self, BinOp, BorrowKind, FakeReadCause, UnOp};
|
||||
use rustc_middle::ty::adjustment::PointerCoercion;
|
||||
use rustc_middle::ty::layout::IntegerExt;
|
||||
use rustc_middle::ty::{
|
||||
@ -581,12 +581,6 @@ pub enum InlineAsmOperand<'tcx> {
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, HashStable)]
|
||||
pub enum BindingMode {
|
||||
ByValue,
|
||||
ByRef(BorrowKind),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, HashStable, TypeVisitable)]
|
||||
pub struct FieldPat<'tcx> {
|
||||
pub field: FieldIdx,
|
||||
@ -607,19 +601,22 @@ impl<'tcx> Pat<'tcx> {
|
||||
|
||||
pub fn simple_ident(&self) -> Option<Symbol> {
|
||||
match self.kind {
|
||||
PatKind::Binding { name, mode: BindingMode::ByValue, subpattern: None, .. } => {
|
||||
Some(name)
|
||||
}
|
||||
PatKind::Binding {
|
||||
name,
|
||||
mode: BindingAnnotation(ByRef::No, _),
|
||||
subpattern: None,
|
||||
..
|
||||
} => Some(name),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Call `f` on every "binding" in a pattern, e.g., on `a` in
|
||||
/// `match foo() { Some(a) => (), None => () }`
|
||||
pub fn each_binding(&self, mut f: impl FnMut(Symbol, BindingMode, Ty<'tcx>, Span)) {
|
||||
pub fn each_binding(&self, mut f: impl FnMut(Symbol, ByRef, Ty<'tcx>, Span)) {
|
||||
self.walk_always(|p| {
|
||||
if let PatKind::Binding { name, mode, ty, .. } = p.kind {
|
||||
f(name, mode, ty, p.span);
|
||||
f(name, mode.0, ty, p.span);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -730,10 +727,9 @@ pub enum PatKind<'tcx> {
|
||||
|
||||
/// `x`, `ref x`, `x @ P`, etc.
|
||||
Binding {
|
||||
mutability: Mutability,
|
||||
name: Symbol,
|
||||
#[type_visitable(ignore)]
|
||||
mode: BindingMode,
|
||||
mode: BindingAnnotation,
|
||||
#[type_visitable(ignore)]
|
||||
var: LocalVarId,
|
||||
ty: Ty<'tcx>,
|
||||
@ -1073,17 +1069,8 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
|
||||
PatKind::Wild => write!(f, "_"),
|
||||
PatKind::Never => write!(f, "!"),
|
||||
PatKind::AscribeUserType { ref subpattern, .. } => write!(f, "{subpattern}: _"),
|
||||
PatKind::Binding { mutability, name, mode, ref subpattern, .. } => {
|
||||
let is_mut = match mode {
|
||||
BindingMode::ByValue => mutability == Mutability::Mut,
|
||||
BindingMode::ByRef(bk) => {
|
||||
write!(f, "ref ")?;
|
||||
matches!(bk, BorrowKind::Mut { .. })
|
||||
}
|
||||
};
|
||||
if is_mut {
|
||||
write!(f, "mut ")?;
|
||||
}
|
||||
PatKind::Binding { name, mode, ref subpattern, .. } => {
|
||||
f.write_str(mode.prefix_str())?;
|
||||
write!(f, "{name}")?;
|
||||
if let Some(ref subpattern) = *subpattern {
|
||||
write!(f, " @ {subpattern}")?;
|
||||
|
@ -230,15 +230,7 @@ pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
|
||||
AscribeUserType { subpattern, ascription: _ }
|
||||
| Deref { subpattern }
|
||||
| DerefPattern { subpattern }
|
||||
| Binding {
|
||||
subpattern: Some(subpattern),
|
||||
mutability: _,
|
||||
mode: _,
|
||||
var: _,
|
||||
ty: _,
|
||||
is_primary: _,
|
||||
name: _,
|
||||
} => visitor.visit_pat(subpattern),
|
||||
| Binding { subpattern: Some(subpattern), .. } => visitor.visit_pat(subpattern),
|
||||
Binding { .. } | Wild | Never | Error(_) => {}
|
||||
Variant { subpatterns, adt_def: _, args: _, variant_index: _ } | Leaf { subpatterns } => {
|
||||
for subpattern in subpatterns {
|
||||
|
@ -1,18 +0,0 @@
|
||||
use rustc_hir::{BindingAnnotation, ByRef, Mutability};
|
||||
|
||||
#[derive(Clone, PartialEq, TyEncodable, TyDecodable, Debug, Copy, HashStable)]
|
||||
pub enum BindingMode {
|
||||
BindByReference(Mutability),
|
||||
BindByValue(Mutability),
|
||||
}
|
||||
|
||||
TrivialTypeTraversalImpls! { BindingMode }
|
||||
|
||||
impl BindingMode {
|
||||
pub fn convert(BindingAnnotation(by_ref, mutbl): BindingAnnotation) -> BindingMode {
|
||||
match by_ref {
|
||||
ByRef::No => BindingMode::BindByValue(mutbl),
|
||||
ByRef::Yes => BindingMode::BindByReference(mutbl),
|
||||
}
|
||||
}
|
||||
}
|
@ -76,8 +76,6 @@ pub use rustc_type_ir::ConstKind::{
|
||||
};
|
||||
pub use rustc_type_ir::*;
|
||||
|
||||
pub use self::binding::BindingMode;
|
||||
pub use self::binding::BindingMode::*;
|
||||
pub use self::closure::{
|
||||
is_ancestor_or_same_capture, place_to_string_for_capture, BorrowKind, CaptureInfo,
|
||||
CapturedPlace, ClosureTypeInfo, MinCaptureInformationMap, MinCaptureList,
|
||||
@ -123,7 +121,6 @@ pub use self::typeck_results::{
|
||||
pub mod _match;
|
||||
pub mod abstract_const;
|
||||
pub mod adjustment;
|
||||
pub mod binding;
|
||||
pub mod cast;
|
||||
pub mod codec;
|
||||
pub mod error;
|
||||
|
@ -402,6 +402,7 @@ TrivialTypeTraversalImpls! {
|
||||
::rustc_span::symbol::Symbol,
|
||||
::rustc_hir::def::Res,
|
||||
::rustc_hir::def_id::LocalDefId,
|
||||
::rustc_hir::ByRef,
|
||||
::rustc_hir::HirId,
|
||||
::rustc_hir::MatchSource,
|
||||
::rustc_target::asm::InlineAsmRegOrRegClass,
|
||||
|
@ -3,8 +3,8 @@ use crate::{
|
||||
infer::canonical::Canonical,
|
||||
traits::ObligationCause,
|
||||
ty::{
|
||||
self, tls, BindingMode, BoundVar, CanonicalPolyFnSig, ClosureSizeProfileData,
|
||||
GenericArgKind, GenericArgs, GenericArgsRef, Ty, UserArgs,
|
||||
self, tls, BoundVar, CanonicalPolyFnSig, ClosureSizeProfileData, GenericArgKind,
|
||||
GenericArgs, GenericArgsRef, Ty, UserArgs,
|
||||
},
|
||||
};
|
||||
use rustc_data_structures::{
|
||||
@ -12,12 +12,12 @@ use rustc_data_structures::{
|
||||
unord::{ExtendUnord, UnordItems, UnordSet},
|
||||
};
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::{
|
||||
self as hir,
|
||||
def::{DefKind, Res},
|
||||
def_id::{DefId, LocalDefId, LocalDefIdMap},
|
||||
hir_id::OwnerId,
|
||||
HirId, ItemLocalId, ItemLocalMap, ItemLocalSet,
|
||||
BindingAnnotation, ByRef, HirId, ItemLocalId, ItemLocalMap, ItemLocalSet, Mutability,
|
||||
};
|
||||
use rustc_index::{Idx, IndexVec};
|
||||
use rustc_macros::HashStable;
|
||||
@ -78,8 +78,8 @@ pub struct TypeckResults<'tcx> {
|
||||
|
||||
adjustments: ItemLocalMap<Vec<ty::adjustment::Adjustment<'tcx>>>,
|
||||
|
||||
/// Stores the actual binding mode for all instances of hir::BindingAnnotation.
|
||||
pat_binding_modes: ItemLocalMap<BindingMode>,
|
||||
/// Stores the actual binding mode for all instances of [`BindingAnnotation`].
|
||||
pat_binding_modes: ItemLocalMap<BindingAnnotation>,
|
||||
|
||||
/// Stores the types which were implicitly dereferenced in pattern binding modes
|
||||
/// for later usage in THIR lowering. For example,
|
||||
@ -408,17 +408,22 @@ impl<'tcx> TypeckResults<'tcx> {
|
||||
matches!(self.type_dependent_defs().get(expr.hir_id), Some(Ok((DefKind::AssocFn, _))))
|
||||
}
|
||||
|
||||
pub fn extract_binding_mode(&self, s: &Session, id: HirId, sp: Span) -> Option<BindingMode> {
|
||||
pub fn extract_binding_mode(
|
||||
&self,
|
||||
s: &Session,
|
||||
id: HirId,
|
||||
sp: Span,
|
||||
) -> Option<BindingAnnotation> {
|
||||
self.pat_binding_modes().get(id).copied().or_else(|| {
|
||||
s.dcx().span_bug(sp, "missing binding mode");
|
||||
})
|
||||
}
|
||||
|
||||
pub fn pat_binding_modes(&self) -> LocalTableInContext<'_, BindingMode> {
|
||||
pub fn pat_binding_modes(&self) -> LocalTableInContext<'_, BindingAnnotation> {
|
||||
LocalTableInContext { hir_owner: self.hir_owner, data: &self.pat_binding_modes }
|
||||
}
|
||||
|
||||
pub fn pat_binding_modes_mut(&mut self) -> LocalTableInContextMut<'_, BindingMode> {
|
||||
pub fn pat_binding_modes_mut(&mut self) -> LocalTableInContextMut<'_, BindingAnnotation> {
|
||||
LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_binding_modes }
|
||||
}
|
||||
|
||||
@ -442,7 +447,7 @@ impl<'tcx> TypeckResults<'tcx> {
|
||||
let mut has_ref_mut = false;
|
||||
pat.walk(|pat| {
|
||||
if let hir::PatKind::Binding(_, id, _, _) = pat.kind
|
||||
&& let Some(ty::BindByReference(ty::Mutability::Mut)) =
|
||||
&& let Some(BindingAnnotation(ByRef::Yes(Mutability::Mut), _)) =
|
||||
self.pat_binding_modes().get(id)
|
||||
{
|
||||
has_ref_mut = true;
|
||||
|
@ -218,7 +218,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
this.visit_primary_bindings(
|
||||
pattern,
|
||||
UserTypeProjections::none(),
|
||||
&mut |this, _, _, _, node, span, _, _| {
|
||||
&mut |this, _, _, node, span, _, _| {
|
||||
this.storage_live_binding(
|
||||
block,
|
||||
node,
|
||||
@ -308,7 +308,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
this.visit_primary_bindings(
|
||||
pattern,
|
||||
UserTypeProjections::none(),
|
||||
&mut |this, _, _, _, node, span, _, _| {
|
||||
&mut |this, _, _, node, span, _, _| {
|
||||
this.storage_live_binding(block, node, span, OutsideGuard, true);
|
||||
this.schedule_drop_for_binding(node, span, OutsideGuard);
|
||||
},
|
||||
|
@ -14,6 +14,7 @@ use rustc_data_structures::{
|
||||
fx::{FxHashSet, FxIndexMap, FxIndexSet},
|
||||
stack::ensure_sufficient_stack,
|
||||
};
|
||||
use rustc_hir::{BindingAnnotation, ByRef};
|
||||
use rustc_middle::middle::region;
|
||||
use rustc_middle::mir::{self, *};
|
||||
use rustc_middle::thir::{self, *};
|
||||
@ -554,7 +555,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
) -> BlockAnd<()> {
|
||||
match irrefutable_pat.kind {
|
||||
// Optimize the case of `let x = ...` to write directly into `x`
|
||||
PatKind::Binding { mode: BindingMode::ByValue, var, subpattern: None, .. } => {
|
||||
PatKind::Binding {
|
||||
mode: BindingAnnotation(ByRef::No, _),
|
||||
var,
|
||||
subpattern: None,
|
||||
..
|
||||
} => {
|
||||
let place =
|
||||
self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true);
|
||||
unpack!(block = self.expr_into_dest(place, block, initializer_id));
|
||||
@ -580,7 +586,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
box Pat {
|
||||
kind:
|
||||
PatKind::Binding {
|
||||
mode: BindingMode::ByValue, var, subpattern: None, ..
|
||||
mode: BindingAnnotation(ByRef::No, _),
|
||||
var,
|
||||
subpattern: None,
|
||||
..
|
||||
},
|
||||
..
|
||||
},
|
||||
@ -720,7 +729,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
self.visit_primary_bindings(
|
||||
pattern,
|
||||
UserTypeProjections::none(),
|
||||
&mut |this, mutability, name, mode, var, span, ty, user_ty| {
|
||||
&mut |this, name, mode, var, span, ty, user_ty| {
|
||||
if visibility_scope.is_none() {
|
||||
visibility_scope =
|
||||
Some(this.new_source_scope(scope_span, LintLevel::Inherited, None));
|
||||
@ -730,7 +739,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
this.declare_binding(
|
||||
source_info,
|
||||
visibility_scope,
|
||||
mutability,
|
||||
name,
|
||||
mode,
|
||||
var,
|
||||
@ -818,9 +826,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
pattern_user_ty: UserTypeProjections,
|
||||
f: &mut impl FnMut(
|
||||
&mut Self,
|
||||
Mutability,
|
||||
Symbol,
|
||||
BindingMode,
|
||||
BindingAnnotation,
|
||||
LocalVarId,
|
||||
Span,
|
||||
Ty<'tcx>,
|
||||
@ -832,18 +839,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
pattern, pattern_user_ty
|
||||
);
|
||||
match pattern.kind {
|
||||
PatKind::Binding {
|
||||
mutability,
|
||||
name,
|
||||
mode,
|
||||
var,
|
||||
ty,
|
||||
ref subpattern,
|
||||
is_primary,
|
||||
..
|
||||
} => {
|
||||
PatKind::Binding { name, mode, var, ty, ref subpattern, is_primary, .. } => {
|
||||
if is_primary {
|
||||
f(self, mutability, name, mode, var, pattern.span, ty, pattern_user_ty.clone());
|
||||
f(self, name, mode, var, pattern.span, ty, pattern_user_ty.clone());
|
||||
}
|
||||
if let Some(subpattern) = subpattern.as_ref() {
|
||||
self.visit_primary_bindings(subpattern, pattern_user_ty, f);
|
||||
@ -1079,7 +1077,7 @@ struct Binding<'tcx> {
|
||||
span: Span,
|
||||
source: Place<'tcx>,
|
||||
var_id: LocalVarId,
|
||||
binding_mode: BindingMode,
|
||||
binding_mode: BindingAnnotation,
|
||||
}
|
||||
|
||||
/// Indicates that the type of `source` must be a subtype of the
|
||||
@ -2097,9 +2095,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
parent_data.iter().flat_map(|d| &d.bindings).chain(&candidate.extra_data.bindings);
|
||||
|
||||
self.bind_matched_candidate_for_guard(block, schedule_drops, bindings.clone());
|
||||
let guard_frame = GuardFrame {
|
||||
locals: bindings.map(|b| GuardFrameLocal::new(b.var_id, b.binding_mode)).collect(),
|
||||
};
|
||||
let guard_frame =
|
||||
GuardFrame { locals: bindings.map(|b| GuardFrameLocal::new(b.var_id)).collect() };
|
||||
debug!("entering guard building context: {:?}", guard_frame);
|
||||
self.guard_context.push(guard_frame);
|
||||
|
||||
@ -2176,7 +2173,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
.iter()
|
||||
.flat_map(|d| &d.bindings)
|
||||
.chain(&candidate.extra_data.bindings)
|
||||
.filter(|binding| matches!(binding.binding_mode, BindingMode::ByValue));
|
||||
.filter(|binding| matches!(binding.binding_mode.0, ByRef::No));
|
||||
// Read all of the by reference bindings to ensure that the
|
||||
// place they refer to can't be modified by the guard.
|
||||
for binding in by_value_bindings.clone() {
|
||||
@ -2263,12 +2260,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
RefWithinGuard,
|
||||
schedule_drops,
|
||||
);
|
||||
match binding.binding_mode {
|
||||
BindingMode::ByValue => {
|
||||
match binding.binding_mode.0 {
|
||||
ByRef::No => {
|
||||
let rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, binding.source);
|
||||
self.cfg.push_assign(block, source_info, ref_for_guard, rvalue);
|
||||
}
|
||||
BindingMode::ByRef(borrow_kind) => {
|
||||
ByRef::Yes(mutbl) => {
|
||||
let value_for_arm = self.storage_live_binding(
|
||||
block,
|
||||
binding.var_id,
|
||||
@ -2277,7 +2274,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
schedule_drops,
|
||||
);
|
||||
|
||||
let rvalue = Rvalue::Ref(re_erased, borrow_kind, binding.source);
|
||||
let rvalue =
|
||||
Rvalue::Ref(re_erased, util::ref_pat_borrow_kind(mutbl), binding.source);
|
||||
self.cfg.push_assign(block, source_info, value_for_arm, rvalue);
|
||||
let rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, value_for_arm);
|
||||
self.cfg.push_assign(block, source_info, ref_for_guard, rvalue);
|
||||
@ -2318,10 +2316,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
if schedule_drops {
|
||||
self.schedule_drop_for_binding(binding.var_id, binding.span, OutsideGuard);
|
||||
}
|
||||
let rvalue = match binding.binding_mode {
|
||||
BindingMode::ByValue => Rvalue::Use(self.consume_by_copy_or_move(binding.source)),
|
||||
BindingMode::ByRef(borrow_kind) => {
|
||||
Rvalue::Ref(re_erased, borrow_kind, binding.source)
|
||||
let rvalue = match binding.binding_mode.0 {
|
||||
ByRef::No => Rvalue::Use(self.consume_by_copy_or_move(binding.source)),
|
||||
ByRef::Yes(mutbl) => {
|
||||
Rvalue::Ref(re_erased, util::ref_pat_borrow_kind(mutbl), binding.source)
|
||||
}
|
||||
};
|
||||
self.cfg.push_assign(block, source_info, local, rvalue);
|
||||
@ -2338,9 +2336,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
&mut self,
|
||||
source_info: SourceInfo,
|
||||
visibility_scope: SourceScope,
|
||||
mutability: Mutability,
|
||||
name: Symbol,
|
||||
mode: BindingMode,
|
||||
mode: BindingAnnotation,
|
||||
var_id: LocalVarId,
|
||||
var_ty: Ty<'tcx>,
|
||||
user_ty: UserTypeProjections,
|
||||
@ -2350,18 +2347,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
) {
|
||||
let tcx = self.tcx;
|
||||
let debug_source_info = SourceInfo { span: source_info.span, scope: visibility_scope };
|
||||
let binding_mode = match mode {
|
||||
BindingMode::ByValue => ty::BindingMode::BindByValue(mutability),
|
||||
BindingMode::ByRef(_) => ty::BindingMode::BindByReference(mutability),
|
||||
};
|
||||
let local = LocalDecl {
|
||||
mutability,
|
||||
mutability: mode.1,
|
||||
ty: var_ty,
|
||||
user_ty: if user_ty.is_empty() { None } else { Some(Box::new(user_ty)) },
|
||||
source_info,
|
||||
local_info: ClearCrossCrate::Set(Box::new(LocalInfo::User(BindingForm::Var(
|
||||
VarBindingForm {
|
||||
binding_mode,
|
||||
binding_mode: mode,
|
||||
// hypothetically, `visit_primary_bindings` could try to unzip
|
||||
// an outermost hir::Ty as we descend, matching up
|
||||
// idents in pat; but complex w/ unclear UI payoff.
|
||||
|
@ -154,15 +154,7 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
|
||||
TestCase::Irrefutable { ascription, binding: None }
|
||||
}
|
||||
|
||||
PatKind::Binding {
|
||||
name: _,
|
||||
mutability: _,
|
||||
mode,
|
||||
var,
|
||||
ty: _,
|
||||
ref subpattern,
|
||||
is_primary: _,
|
||||
} => {
|
||||
PatKind::Binding { mode, var, ref subpattern, .. } => {
|
||||
let binding = place.map(|source| super::Binding {
|
||||
span: pattern.span,
|
||||
source,
|
||||
@ -347,3 +339,11 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn ref_pat_borrow_kind(ref_mutability: Mutability) -> BorrowKind {
|
||||
match ref_mutability {
|
||||
Mutability::Mut => BorrowKind::Mut { kind: MutBorrowKind::Default },
|
||||
Mutability::Not => BorrowKind::Shared,
|
||||
}
|
||||
}
|
||||
|
@ -7,10 +7,9 @@ use rustc_ast::attr;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::sorted_map::SortedIndexMultiMap;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::Node;
|
||||
use rustc_hir::{self as hir, BindingAnnotation, ByRef, Node};
|
||||
use rustc_index::bit_set::GrowableBitSet;
|
||||
use rustc_index::{Idx, IndexSlice, IndexVec};
|
||||
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
|
||||
@ -19,9 +18,7 @@ use rustc_middle::middle::region;
|
||||
use rustc_middle::mir::interpret::Scalar;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::query::TyCtxtAt;
|
||||
use rustc_middle::thir::{
|
||||
self, BindingMode, ExprId, LintLevel, LocalVarId, Param, ParamId, PatKind, Thir,
|
||||
};
|
||||
use rustc_middle::thir::{self, ExprId, LintLevel, LocalVarId, Param, ParamId, PatKind, Thir};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Span;
|
||||
@ -337,7 +334,7 @@ struct GuardFrameLocal {
|
||||
}
|
||||
|
||||
impl GuardFrameLocal {
|
||||
fn new(id: LocalVarId, _binding_mode: BindingMode) -> Self {
|
||||
fn new(id: LocalVarId) -> Self {
|
||||
GuardFrameLocal { id }
|
||||
}
|
||||
}
|
||||
@ -967,9 +964,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
match pat.kind {
|
||||
// Don't introduce extra copies for simple bindings
|
||||
PatKind::Binding {
|
||||
mutability,
|
||||
var,
|
||||
mode: BindingMode::ByValue,
|
||||
mode: BindingAnnotation(ByRef::No, mutability),
|
||||
subpattern: None,
|
||||
..
|
||||
} => {
|
||||
@ -979,7 +975,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
if let Some(kind) = param.self_kind {
|
||||
LocalInfo::User(BindingForm::ImplicitSelf(kind))
|
||||
} else {
|
||||
let binding_mode = ty::BindingMode::BindByValue(mutability);
|
||||
let binding_mode = BindingAnnotation(ByRef::No, mutability);
|
||||
LocalInfo::User(BindingForm::Var(VarBindingForm {
|
||||
binding_mode,
|
||||
opt_ty_info: param.ty_span,
|
||||
|
@ -2,11 +2,11 @@ use std::borrow::Cow;
|
||||
|
||||
use crate::build::ExprCategory;
|
||||
use crate::errors::*;
|
||||
use rustc_middle::thir::visit::Visitor;
|
||||
|
||||
use rustc_errors::DiagArgValue;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::{self as hir, BindingAnnotation, ByRef, Mutability};
|
||||
use rustc_middle::mir::BorrowKind;
|
||||
use rustc_middle::thir::visit::Visitor;
|
||||
use rustc_middle::thir::*;
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt};
|
||||
@ -289,22 +289,22 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
||||
visit::walk_pat(self, pat);
|
||||
}
|
||||
}
|
||||
PatKind::Binding { mode: BindingMode::ByRef(borrow_kind), ty, .. } => {
|
||||
PatKind::Binding { mode: BindingAnnotation(ByRef::Yes(rm), _), ty, .. } => {
|
||||
if self.inside_adt {
|
||||
let ty::Ref(_, ty, _) = ty.kind() else {
|
||||
span_bug!(
|
||||
pat.span,
|
||||
"BindingMode::ByRef in pattern, but found non-reference type {}",
|
||||
"ByRef::Yes in pattern, but found non-reference type {}",
|
||||
ty
|
||||
);
|
||||
};
|
||||
match borrow_kind {
|
||||
BorrowKind::Fake | BorrowKind::Shared => {
|
||||
match rm {
|
||||
Mutability::Not => {
|
||||
if !ty.is_freeze(self.tcx, self.param_env) {
|
||||
self.requires_unsafe(pat.span, BorrowOfLayoutConstrainedField);
|
||||
}
|
||||
}
|
||||
BorrowKind::Mut { .. } => {
|
||||
Mutability::Mut { .. } => {
|
||||
self.requires_unsafe(pat.span, MutationOfLayoutConstrainedField);
|
||||
}
|
||||
}
|
||||
|
@ -13,10 +13,9 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_errors::{
|
||||
codes::*, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, MultiSpan,
|
||||
};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::*;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::HirId;
|
||||
use rustc_hir::{self as hir, BindingAnnotation, ByRef, HirId};
|
||||
use rustc_middle::middle::limits::get_limit_size;
|
||||
use rustc_middle::thir::visit::Visitor;
|
||||
use rustc_middle::thir::*;
|
||||
@ -723,13 +722,14 @@ fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, 'tcx>, pat:
|
||||
let sess = cx.tcx.sess;
|
||||
|
||||
// Get the binding move, extract the mutability if by-ref.
|
||||
let mut_outer = match mode {
|
||||
BindingMode::ByValue if is_binding_by_move(ty) => {
|
||||
let mut_outer = match mode.0 {
|
||||
ByRef::No if is_binding_by_move(ty) => {
|
||||
// We have `x @ pat` where `x` is by-move. Reject all borrows in `pat`.
|
||||
let mut conflicts_ref = Vec::new();
|
||||
sub.each_binding(|_, mode, _, span| match mode {
|
||||
BindingMode::ByValue => {}
|
||||
BindingMode::ByRef(_) => conflicts_ref.push(span),
|
||||
sub.each_binding(|_, mode, _, span| {
|
||||
if matches!(mode, ByRef::Yes(_)) {
|
||||
conflicts_ref.push(span)
|
||||
}
|
||||
});
|
||||
if !conflicts_ref.is_empty() {
|
||||
sess.dcx().emit_err(BorrowOfMovedValue {
|
||||
@ -742,8 +742,8 @@ fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, 'tcx>, pat:
|
||||
}
|
||||
return;
|
||||
}
|
||||
BindingMode::ByValue => return,
|
||||
BindingMode::ByRef(m) => m.mutability(),
|
||||
ByRef::No => return,
|
||||
ByRef::Yes(m) => m,
|
||||
};
|
||||
|
||||
// We now have `ref $mut_outer binding @ sub` (semantically).
|
||||
@ -753,7 +753,7 @@ fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, 'tcx>, pat:
|
||||
let mut conflicts_mut_ref = Vec::new();
|
||||
sub.each_binding(|name, mode, ty, span| {
|
||||
match mode {
|
||||
BindingMode::ByRef(mut_inner) => match (mut_outer, mut_inner.mutability()) {
|
||||
ByRef::Yes(mut_inner) => match (mut_outer, mut_inner) {
|
||||
// Both sides are `ref`.
|
||||
(Mutability::Not, Mutability::Not) => {}
|
||||
// 2x `ref mut`.
|
||||
@ -767,10 +767,10 @@ fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, 'tcx>, pat:
|
||||
conflicts_mut_ref.push(Conflict::Ref { span, name })
|
||||
}
|
||||
},
|
||||
BindingMode::ByValue if is_binding_by_move(ty) => {
|
||||
ByRef::No if is_binding_by_move(ty) => {
|
||||
conflicts_move.push(Conflict::Moved { span, name }) // `ref mut?` + by-move conflict.
|
||||
}
|
||||
BindingMode::ByValue => {} // `ref mut?` + by-copy is fine.
|
||||
ByRef::No => {} // `ref mut?` + by-copy is fine.
|
||||
}
|
||||
});
|
||||
|
||||
@ -813,8 +813,7 @@ fn check_for_bindings_named_same_as_variants(
|
||||
) {
|
||||
if let PatKind::Binding {
|
||||
name,
|
||||
mode: BindingMode::ByValue,
|
||||
mutability: Mutability::Not,
|
||||
mode: BindingAnnotation(ByRef::No, Mutability::Not),
|
||||
subpattern: None,
|
||||
ty,
|
||||
..
|
||||
|
@ -9,15 +9,14 @@ use crate::errors::*;
|
||||
use crate::thir::util::UserAnnotatedTyHelpers;
|
||||
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorOf, DefKind, Res};
|
||||
use rustc_hir::pat_util::EnumerateAndAdjustIterator;
|
||||
use rustc_hir::RangeEnd;
|
||||
use rustc_hir::{self as hir, RangeEnd};
|
||||
use rustc_index::Idx;
|
||||
use rustc_middle::mir::interpret::{ErrorHandled, GlobalId, LitToConstError, LitToConstInput};
|
||||
use rustc_middle::mir::{self, BorrowKind, Const, Mutability};
|
||||
use rustc_middle::mir::{self, Const};
|
||||
use rustc_middle::thir::{
|
||||
Ascription, BindingMode, FieldPat, LocalVarId, Pat, PatKind, PatRange, PatRangeBoundary,
|
||||
Ascription, FieldPat, LocalVarId, Pat, PatKind, PatRange, PatRangeBoundary,
|
||||
};
|
||||
use rustc_middle::ty::layout::IntegerExt;
|
||||
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, TypeVisitableExt};
|
||||
@ -281,26 +280,16 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
span = span.with_hi(ident_span.hi());
|
||||
}
|
||||
|
||||
let bm = *self
|
||||
let mode = *self
|
||||
.typeck_results
|
||||
.pat_binding_modes()
|
||||
.get(pat.hir_id)
|
||||
.expect("missing binding mode");
|
||||
let (mutability, mode) = match bm {
|
||||
ty::BindByValue(mutbl) => (mutbl, BindingMode::ByValue),
|
||||
ty::BindByReference(hir::Mutability::Mut) => (
|
||||
Mutability::Not,
|
||||
BindingMode::ByRef(BorrowKind::Mut { kind: mir::MutBorrowKind::Default }),
|
||||
),
|
||||
ty::BindByReference(hir::Mutability::Not) => {
|
||||
(Mutability::Not, BindingMode::ByRef(BorrowKind::Shared))
|
||||
}
|
||||
};
|
||||
|
||||
// A ref x pattern is the same node used for x, and as such it has
|
||||
// x's type, which is &T, where we want T (the type being matched).
|
||||
let var_ty = ty;
|
||||
if let ty::BindByReference(_) = bm {
|
||||
if let hir::ByRef::Yes(_) = mode.0 {
|
||||
if let ty::Ref(_, rty, _) = ty.kind() {
|
||||
ty = *rty;
|
||||
} else {
|
||||
@ -309,7 +298,6 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
};
|
||||
|
||||
PatKind::Binding {
|
||||
mutability,
|
||||
mode,
|
||||
name: ident.name,
|
||||
var: LocalVarId(id),
|
||||
|
@ -635,9 +635,8 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
|
||||
self.print_pat(subpattern, depth_lvl + 3);
|
||||
print_indented!(self, "}", depth_lvl + 1);
|
||||
}
|
||||
PatKind::Binding { mutability, name, mode, var, ty, subpattern, is_primary } => {
|
||||
PatKind::Binding { name, mode, var, ty, subpattern, is_primary } => {
|
||||
print_indented!(self, "Binding {", depth_lvl + 1);
|
||||
print_indented!(self, format!("mutability: {:?}", mutability), depth_lvl + 2);
|
||||
print_indented!(self, format!("name: {:?}", name), depth_lvl + 2);
|
||||
print_indented!(self, format!("mode: {:?}", mode), depth_lvl + 2);
|
||||
print_indented!(self, format!("var: {:?}", var), depth_lvl + 2);
|
||||
|
@ -655,9 +655,6 @@ parse_question_mark_in_type = invalid `?` in type
|
||||
parse_recover_import_as_use = expected item, found {$token_name}
|
||||
.suggestion = items are imported using the `use` keyword
|
||||
|
||||
parse_ref_mut_order_incorrect = the order of `mut` and `ref` is incorrect
|
||||
.suggestion = try switching the order
|
||||
|
||||
parse_remove_let = expected pattern, found `let`
|
||||
.suggestion = remove the unnecessary `let` keyword
|
||||
|
||||
|
@ -2364,14 +2364,6 @@ pub(crate) struct UnexpectedLifetimeInPattern {
|
||||
pub symbol: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_ref_mut_order_incorrect)]
|
||||
pub(crate) struct RefMutOrderIncorrect {
|
||||
#[primary_span]
|
||||
#[suggestion(code = "ref mut", applicability = "machine-applicable")]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
pub(crate) enum InvalidMutInPattern {
|
||||
#[diag(parse_mut_on_nested_ident_pattern)]
|
||||
|
@ -24,12 +24,11 @@ use rustc_ast::token::{self, Delimiter, Token, TokenKind};
|
||||
use rustc_ast::tokenstream::{AttributesData, DelimSpacing, DelimSpan, Spacing};
|
||||
use rustc_ast::tokenstream::{TokenStream, TokenTree, TokenTreeCursor};
|
||||
use rustc_ast::util::case::Case;
|
||||
use rustc_ast::AttrId;
|
||||
use rustc_ast::CoroutineKind;
|
||||
use rustc_ast::DUMMY_NODE_ID;
|
||||
use rustc_ast::{self as ast, AnonConst, Const, DelimArgs, Extern};
|
||||
use rustc_ast::{AttrArgs, AttrArgsEq, Expr, ExprKind, Mutability, StrLit};
|
||||
use rustc_ast::{HasAttrs, HasTokens, Unsafe, Visibility, VisibilityKind};
|
||||
use rustc_ast::{
|
||||
self as ast, AnonConst, AttrArgs, AttrArgsEq, AttrId, ByRef, Const, CoroutineKind, DelimArgs,
|
||||
Expr, ExprKind, Extern, HasAttrs, HasTokens, Mutability, StrLit, Unsafe, Visibility,
|
||||
VisibilityKind, DUMMY_NODE_ID,
|
||||
};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::PResult;
|
||||
@ -1273,6 +1272,11 @@ impl<'a> Parser<'a> {
|
||||
if self.eat_keyword(kw::Mut) { Mutability::Mut } else { Mutability::Not }
|
||||
}
|
||||
|
||||
/// Parses reference binding mode (`ref`, `ref mut`, or nothing).
|
||||
fn parse_byref(&mut self) -> ByRef {
|
||||
if self.eat_keyword(kw::Ref) { ByRef::Yes(self.parse_mutability()) } else { ByRef::No }
|
||||
}
|
||||
|
||||
/// Possibly parses mutability (`const` or `mut`).
|
||||
fn parse_const_or_mut(&mut self) -> Option<Mutability> {
|
||||
if self.eat_keyword(kw::Mut) {
|
||||
|
@ -4,11 +4,11 @@ use crate::errors::{
|
||||
DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt,
|
||||
ExpectedCommaAfterPatternField, GenericArgsInPatRequireTurbofishSyntax,
|
||||
InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, InvalidMutInPattern,
|
||||
PatternOnWrongSideOfAt, RefMutOrderIncorrect, RemoveLet, RepeatedMutInPattern,
|
||||
SwitchRefBoxOrder, TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg,
|
||||
TrailingVertNotAllowed, UnexpectedExpressionInPattern, UnexpectedLifetimeInPattern,
|
||||
UnexpectedParenInRangePat, UnexpectedParenInRangePatSugg,
|
||||
UnexpectedVertVertBeforeFunctionParam, UnexpectedVertVertInPattern,
|
||||
PatternOnWrongSideOfAt, RemoveLet, RepeatedMutInPattern, SwitchRefBoxOrder,
|
||||
TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg, TrailingVertNotAllowed,
|
||||
UnexpectedExpressionInPattern, UnexpectedLifetimeInPattern, UnexpectedParenInRangePat,
|
||||
UnexpectedParenInRangePatSugg, UnexpectedVertVertBeforeFunctionParam,
|
||||
UnexpectedVertVertInPattern,
|
||||
};
|
||||
use crate::parser::expr::could_be_unclosed_char_literal;
|
||||
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
|
||||
@ -476,7 +476,7 @@ impl<'a> Parser<'a> {
|
||||
// Parse `_`
|
||||
PatKind::Wild
|
||||
} else if self.eat_keyword(kw::Mut) {
|
||||
self.parse_pat_ident_mut(syntax_loc)?
|
||||
self.parse_pat_ident_mut()?
|
||||
} else if self.eat_keyword(kw::Ref) {
|
||||
if self.check_keyword(kw::Box) {
|
||||
// Suggest `box ref`.
|
||||
@ -486,7 +486,7 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
// Parse ref ident @ pat / ref mut ident @ pat
|
||||
let mutbl = self.parse_mutability();
|
||||
self.parse_pat_ident(BindingAnnotation(ByRef::Yes, mutbl), syntax_loc)?
|
||||
self.parse_pat_ident(BindingAnnotation(ByRef::Yes(mutbl), Mutability::Not), syntax_loc)?
|
||||
} else if self.eat_keyword(kw::Box) {
|
||||
self.parse_pat_box()?
|
||||
} else if self.check_inline_const(0) {
|
||||
@ -746,13 +746,12 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
|
||||
/// Parse a mutable binding with the `mut` token already eaten.
|
||||
fn parse_pat_ident_mut(&mut self, syntax_loc: Option<PatternLocation>) -> PResult<'a, PatKind> {
|
||||
fn parse_pat_ident_mut(&mut self) -> PResult<'a, PatKind> {
|
||||
let mut_span = self.prev_token.span;
|
||||
|
||||
if self.eat_keyword(kw::Ref) {
|
||||
self.dcx().emit_err(RefMutOrderIncorrect { span: mut_span.to(self.prev_token.span) });
|
||||
return self.parse_pat_ident(BindingAnnotation::REF_MUT, syntax_loc);
|
||||
}
|
||||
self.recover_additional_muts();
|
||||
|
||||
let byref = self.parse_byref();
|
||||
|
||||
self.recover_additional_muts();
|
||||
|
||||
@ -767,10 +766,12 @@ impl<'a> Parser<'a> {
|
||||
let mut pat = self.parse_pat_no_top_alt(Some(Expected::Identifier), None)?;
|
||||
|
||||
// If we don't have `mut $ident (@ pat)?`, error.
|
||||
if let PatKind::Ident(BindingAnnotation(ByRef::No, m @ Mutability::Not), ..) = &mut pat.kind
|
||||
if let PatKind::Ident(BindingAnnotation(br @ ByRef::No, m @ Mutability::Not), ..) =
|
||||
&mut pat.kind
|
||||
{
|
||||
// Don't recurse into the subpattern.
|
||||
// `mut` on the outer binding doesn't affect the inner bindings.
|
||||
*br = byref;
|
||||
*m = Mutability::Mut;
|
||||
} else {
|
||||
// Add `mut` to any binding in the parsed pattern.
|
||||
@ -1390,16 +1391,12 @@ impl<'a> Parser<'a> {
|
||||
// Parsing a pattern of the form `(box) (ref) (mut) fieldname`.
|
||||
let is_box = self.eat_keyword(kw::Box);
|
||||
let boxed_span = self.token.span;
|
||||
let is_ref = self.eat_keyword(kw::Ref);
|
||||
let is_mut = self.eat_keyword(kw::Mut);
|
||||
let mutability = self.parse_mutability();
|
||||
let by_ref = self.parse_byref();
|
||||
|
||||
let fieldname = self.parse_field_name()?;
|
||||
hi = self.prev_token.span;
|
||||
|
||||
let mutability = match is_mut {
|
||||
false => Mutability::Not,
|
||||
true => Mutability::Mut,
|
||||
};
|
||||
let ann = BindingAnnotation(ByRef::from(is_ref), mutability);
|
||||
let ann = BindingAnnotation(by_ref, mutability);
|
||||
let fieldpat = self.mk_pat_ident(boxed_span.to(hi), ann, fieldname);
|
||||
let subpat =
|
||||
if is_box { self.mk_pat(lo.to(hi), PatKind::Box(fieldpat)) } else { fieldpat };
|
||||
|
@ -24,13 +24,13 @@ pub fn check_fn(cx: &LateContext<'_>, kind: FnKind<'_>, decl: &FnDecl<'_>, body:
|
||||
let name = ident.name.as_str();
|
||||
|
||||
let name = match decl.implicit_self {
|
||||
ImplicitSelfKind::MutRef => {
|
||||
ImplicitSelfKind::RefMut => {
|
||||
let Some(name) = name.strip_suffix("_mut") else {
|
||||
return;
|
||||
};
|
||||
name
|
||||
},
|
||||
ImplicitSelfKind::Imm | ImplicitSelfKind::Mut | ImplicitSelfKind::ImmRef => name,
|
||||
ImplicitSelfKind::Imm | ImplicitSelfKind::Mut | ImplicitSelfKind::RefImm => name,
|
||||
ImplicitSelfKind::None => return,
|
||||
};
|
||||
|
||||
|
@ -97,7 +97,7 @@ fn find_slice_values(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> FxIndexMap<hir
|
||||
value_hir_id,
|
||||
ident,
|
||||
sub_pat,
|
||||
) = pat.kind
|
||||
) = pat.kind && by_ref != hir::ByRef::Yes(hir::Mutability::Mut)
|
||||
{
|
||||
// This block catches bindings with sub patterns. It would be hard to build a correct suggestion
|
||||
// for them and it's likely that the user knows what they are doing in such a case.
|
||||
@ -115,7 +115,7 @@ fn find_slice_values(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> FxIndexMap<hir
|
||||
if let ty::Slice(inner_ty) | ty::Array(inner_ty, _) = bound_ty.peel_refs().kind() {
|
||||
// The values need to use the `ref` keyword if they can't be copied.
|
||||
// This will need to be adjusted if the lint want to support mutable access in the future
|
||||
let src_is_ref = bound_ty.is_ref() && by_ref != hir::ByRef::Yes;
|
||||
let src_is_ref = bound_ty.is_ref() && by_ref == hir::ByRef::No;
|
||||
let needs_ref = !(src_is_ref || is_copy(cx, *inner_ty));
|
||||
|
||||
let slice_info = slices
|
||||
|
@ -216,8 +216,8 @@ impl {self_ty_without_ref} {{
|
||||
fn check_impl_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::ImplItem<'_>) {
|
||||
let item_did = item.owner_id.to_def_id();
|
||||
let (borrow_prefix, expected_implicit_self) = match item.ident.name {
|
||||
sym::iter => ("&", ImplicitSelfKind::ImmRef),
|
||||
sym::iter_mut => ("&mut ", ImplicitSelfKind::MutRef),
|
||||
sym::iter => ("&", ImplicitSelfKind::RefImm),
|
||||
sym::iter_mut => ("&mut ", ImplicitSelfKind::RefMut),
|
||||
_ => return,
|
||||
};
|
||||
|
||||
|
@ -384,8 +384,8 @@ impl LenOutput {
|
||||
|
||||
fn expected_sig(self, self_kind: ImplicitSelfKind) -> String {
|
||||
let self_ref = match self_kind {
|
||||
ImplicitSelfKind::ImmRef => "&",
|
||||
ImplicitSelfKind::MutRef => "&mut ",
|
||||
ImplicitSelfKind::RefImm => "&",
|
||||
ImplicitSelfKind::RefMut => "&mut ",
|
||||
_ => "",
|
||||
};
|
||||
match self {
|
||||
@ -411,8 +411,8 @@ fn check_is_empty_sig<'tcx>(
|
||||
[arg, res] if len_output.matches_is_empty_output(cx, *res) => {
|
||||
matches!(
|
||||
(arg.kind(), self_kind),
|
||||
(ty::Ref(_, _, Mutability::Not), ImplicitSelfKind::ImmRef)
|
||||
| (ty::Ref(_, _, Mutability::Mut), ImplicitSelfKind::MutRef)
|
||||
(ty::Ref(_, _, Mutability::Not), ImplicitSelfKind::RefImm)
|
||||
| (ty::Ref(_, _, Mutability::Mut), ImplicitSelfKind::RefMut)
|
||||
) || (!arg.is_ref() && matches!(self_kind, ImplicitSelfKind::Imm | ImplicitSelfKind::Mut))
|
||||
},
|
||||
_ => false,
|
||||
|
@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::{path_to_local_id, peel_blocks, strip_pat_refs};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{ByRef, ExprKind, LetStmt, MatchSource, PatKind, QPath};
|
||||
use rustc_hir::{ExprKind, LetStmt, MatchSource, PatKind, QPath};
|
||||
use rustc_lint::LateContext;
|
||||
|
||||
use super::INFALLIBLE_DESTRUCTURING_MATCH;
|
||||
@ -30,7 +30,7 @@ pub(crate) fn check(cx: &LateContext<'_>, local: &LetStmt<'_>) -> bool {
|
||||
format!(
|
||||
"let {}({}{}) = {};",
|
||||
snippet_with_applicability(cx, variant_name.span, "..", &mut applicability),
|
||||
if binding.0 == ByRef::Yes { "ref " } else { "" },
|
||||
binding.prefix_str(),
|
||||
snippet_with_applicability(cx, local.pat.span, "..", &mut applicability),
|
||||
snippet_with_applicability(cx, target.span, "..", &mut applicability),
|
||||
),
|
||||
|
@ -67,7 +67,7 @@ fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
|
||||
fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option<Mutability> {
|
||||
if let PatKind::TupleStruct(ref qpath, [first_pat, ..], _) = arm.pat.kind
|
||||
&& is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), LangItem::OptionSome)
|
||||
&& let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., ident, _) = first_pat.kind
|
||||
&& let PatKind::Binding(BindingAnnotation(ByRef::Yes(mutabl), _), .., ident, _) = first_pat.kind
|
||||
&& let ExprKind::Call(e, [arg]) = peel_blocks(arm.body).kind
|
||||
&& is_res_lang_ctor(cx, path_res(cx, e), LangItem::OptionSome)
|
||||
&& let ExprKind::Path(QPath::Resolved(_, path2)) = arg.kind
|
||||
|
@ -178,7 +178,7 @@ fn pat_same_as_expr(pat: &Pat<'_>, expr: &Expr<'_>) -> bool {
|
||||
},
|
||||
)),
|
||||
) => {
|
||||
return !matches!(annot, BindingAnnotation(ByRef::Yes, _)) && pat_ident.name == first_seg.ident.name;
|
||||
return !matches!(annot, BindingAnnotation(ByRef::Yes(_), _)) && pat_ident.name == first_seg.ident.name;
|
||||
},
|
||||
// Example: `Custom::TypeA => Custom::TypeB`, or `None => None`
|
||||
(PatKind::Path(QPath::Resolved(_, p_path)), ExprKind::Path(QPath::Resolved(_, e_path))) => {
|
||||
|
@ -182,7 +182,7 @@ fn get_pat_binding<'tcx>(
|
||||
if let PatKind::Binding(bind_annot, hir_id, ident, _) = pat.kind
|
||||
&& hir_id == local
|
||||
{
|
||||
if matches!(bind_annot.0, rustc_ast::ByRef::Yes) {
|
||||
if matches!(bind_annot.0, rustc_ast::ByRef::Yes(_)) {
|
||||
let _ = byref_ident.insert(ident);
|
||||
}
|
||||
// the second call of `replace()` returns a `Some(span)`, meaning a multi-binding pattern
|
||||
|
@ -69,7 +69,7 @@ pub(super) fn check(
|
||||
_ => false,
|
||||
},
|
||||
// local binding capturing a reference
|
||||
Node::LetStmt(l) if matches!(l.pat.kind, PatKind::Binding(BindingAnnotation(ByRef::Yes, _), ..)) => {
|
||||
Node::LetStmt(l) if matches!(l.pat.kind, PatKind::Binding(BindingAnnotation(ByRef::Yes(_), _), ..)) => {
|
||||
return;
|
||||
},
|
||||
_ => false,
|
||||
|
@ -60,8 +60,6 @@ pub(super) fn check<'tcx>(
|
||||
applicability,
|
||||
);
|
||||
} else {
|
||||
let ref_annotation = if annotation.0 == ByRef::Yes { "ref " } else { "" };
|
||||
let mut_annotation = if annotation.1 == Mutability::Mut { "mut " } else { "" };
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
ITER_KV_MAP,
|
||||
@ -69,7 +67,8 @@ pub(super) fn check<'tcx>(
|
||||
&format!("iterating on a map's {replacement_kind}s"),
|
||||
"try",
|
||||
format!(
|
||||
"{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{ref_annotation}{mut_annotation}{bound_ident}| {})",
|
||||
"{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{}{bound_ident}| {})",
|
||||
annotation.prefix_str(),
|
||||
snippet_with_applicability(cx, body_expr.span, "/* body */", &mut applicability)
|
||||
),
|
||||
applicability,
|
||||
|
@ -129,7 +129,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass {
|
||||
if !is_lint_allowed(cx, REF_PATTERNS, arg.pat.hir_id) {
|
||||
return;
|
||||
}
|
||||
if let PatKind::Binding(BindingAnnotation(ByRef::Yes, _), ..) = arg.pat.kind {
|
||||
if let PatKind::Binding(BindingAnnotation(ByRef::Yes(_), _), ..) = arg.pat.kind {
|
||||
span_lint(
|
||||
cx,
|
||||
TOPLEVEL_REF_ARG,
|
||||
@ -144,7 +144,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass {
|
||||
fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
|
||||
if !in_external_macro(cx.tcx.sess, stmt.span)
|
||||
&& let StmtKind::Let(local) = stmt.kind
|
||||
&& let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., name, None) = local.pat.kind
|
||||
&& let PatKind::Binding(BindingAnnotation(ByRef::Yes(mutabl), _), .., name, None) = local.pat.kind
|
||||
&& let Some(init) = local.init
|
||||
// Do not emit if clippy::ref_patterns is not allowed to avoid having two lints for the same issue.
|
||||
&& is_lint_allowed(cx, REF_PATTERNS, local.pat.hir_id)
|
||||
|
@ -14,7 +14,7 @@ use rustc_errors::Applicability;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::LangItem::{self, OptionNone, OptionSome, ResultErr, ResultOk};
|
||||
use rustc_hir::{
|
||||
BindingAnnotation, Block, ByRef, Expr, ExprKind, LetStmt, Node, PatKind, PathSegment, QPath, Stmt, StmtKind,
|
||||
BindingAnnotation, Block, ByRef, Expr, ExprKind, LetStmt, Mutability, Node, PatKind, PathSegment, QPath, Stmt, StmtKind,
|
||||
};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::Ty;
|
||||
@ -283,9 +283,13 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr:
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let receiver_str = snippet_with_applicability(cx, let_expr.span, "..", &mut applicability);
|
||||
let requires_semi = matches!(cx.tcx.parent_hir_node(expr.hir_id), Node::Stmt(_));
|
||||
let method_call_str = match by_ref {
|
||||
ByRef::Yes(Mutability::Mut) => ".as_mut()",
|
||||
ByRef::Yes(Mutability::Not) => ".as_ref()",
|
||||
ByRef::No => "",
|
||||
};
|
||||
let sugg = format!(
|
||||
"{receiver_str}{}?{}",
|
||||
if by_ref == ByRef::Yes { ".as_ref()" } else { "" },
|
||||
"{receiver_str}{method_call_str}?{}",
|
||||
if requires_semi { ";" } else { "" }
|
||||
);
|
||||
span_lint_and_sugg(
|
||||
|
@ -649,6 +649,8 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
|
||||
BindingAnnotation::REF => "REF",
|
||||
BindingAnnotation::MUT => "MUT",
|
||||
BindingAnnotation::REF_MUT => "REF_MUT",
|
||||
BindingAnnotation::MUT_REF => "MUT_REF",
|
||||
BindingAnnotation::MUT_REF_MUT => "MUT_REF_MUT",
|
||||
};
|
||||
kind!("Binding(BindingAnnotation::{ann}, _, {name}, {sub})");
|
||||
self.ident(name);
|
||||
|
@ -97,7 +97,7 @@ use rustc_hir::hir_id::{HirIdMap, HirIdSet};
|
||||
use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
|
||||
use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
|
||||
use rustc_hir::{
|
||||
self as hir, def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Closure, Destination, Expr,
|
||||
self as hir, def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, ByRef, Closure, Destination, Expr,
|
||||
ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, Item,
|
||||
ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment, PrimTy,
|
||||
QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp,
|
||||
@ -107,7 +107,6 @@ use rustc_lint::{LateContext, Level, Lint, LintContext};
|
||||
use rustc_middle::hir::place::PlaceBase;
|
||||
use rustc_middle::mir::Const;
|
||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
|
||||
use rustc_middle::ty::binding::BindingMode;
|
||||
use rustc_middle::ty::fast_reject::SimplifiedType;
|
||||
use rustc_middle::ty::layout::IntegerExt;
|
||||
use rustc_middle::ty::{
|
||||
@ -1006,11 +1005,12 @@ pub fn capture_local_usage(cx: &LateContext<'_>, e: &Expr<'_>) -> CaptureKind {
|
||||
.typeck_results()
|
||||
.extract_binding_mode(cx.sess(), id, span)
|
||||
.unwrap()
|
||||
.0
|
||||
{
|
||||
BindingMode::BindByValue(_) if !is_copy(cx, cx.typeck_results().node_type(id)) => {
|
||||
ByRef::No if !is_copy(cx, cx.typeck_results().node_type(id)) => {
|
||||
capture = CaptureKind::Value;
|
||||
},
|
||||
BindingMode::BindByReference(Mutability::Mut) if capture != CaptureKind::Value => {
|
||||
ByRef::Yes(Mutability::Mut) if capture != CaptureKind::Value => {
|
||||
capture = CaptureKind::Ref(Mutability::Mut);
|
||||
},
|
||||
_ => (),
|
||||
@ -2035,7 +2035,7 @@ fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
|
||||
.typeck_results()
|
||||
.pat_binding_modes()
|
||||
.get(pat.hir_id)
|
||||
.is_some_and(|mode| matches!(mode, BindingMode::BindByReference(_)))
|
||||
.is_some_and(|mode| matches!(mode.0, ByRef::Yes(_)))
|
||||
{
|
||||
// If a tuple `(x, y)` is of type `&(i32, i32)`, then due to match ergonomics,
|
||||
// the inner patterns become references. Don't consider this the identity function
|
||||
|
@ -107,18 +107,19 @@ impl Rewrite for Pat {
|
||||
}
|
||||
PatKind::Box(ref pat) => rewrite_unary_prefix(context, "box ", &**pat, shape),
|
||||
PatKind::Ident(BindingAnnotation(by_ref, mutability), ident, ref sub_pat) => {
|
||||
let prefix = match by_ref {
|
||||
ByRef::Yes => "ref",
|
||||
ByRef::No => "",
|
||||
let mut_prefix = format_mutability(mutability).trim();
|
||||
|
||||
let (ref_kw, mut_infix) = match by_ref {
|
||||
ByRef::Yes(rmutbl) => ("ref", format_mutability(rmutbl).trim()),
|
||||
ByRef::No => ("", ""),
|
||||
};
|
||||
let mut_infix = format_mutability(mutability).trim();
|
||||
let id_str = rewrite_ident(context, ident);
|
||||
let sub_pat = match *sub_pat {
|
||||
Some(ref p) => {
|
||||
// 2 - `@ `.
|
||||
let width = shape
|
||||
.width
|
||||
.checked_sub(prefix.len() + mut_infix.len() + id_str.len() + 2)?;
|
||||
let width = shape.width.checked_sub(
|
||||
mut_prefix.len() + ref_kw.len() + mut_infix.len() + id_str.len() + 2,
|
||||
)?;
|
||||
let lo = context.snippet_provider.span_after(self.span, "@");
|
||||
combine_strs_with_missing_comments(
|
||||
context,
|
||||
@ -132,33 +133,55 @@ impl Rewrite for Pat {
|
||||
None => "".to_owned(),
|
||||
};
|
||||
|
||||
// combine prefix and mut
|
||||
let (first_lo, first) = if !prefix.is_empty() && !mut_infix.is_empty() {
|
||||
let hi = context.snippet_provider.span_before(self.span, "mut");
|
||||
let lo = context.snippet_provider.span_after(self.span, "ref");
|
||||
(
|
||||
// combine prefix and ref
|
||||
let (first_lo, first) = match (mut_prefix.is_empty(), ref_kw.is_empty()) {
|
||||
(false, false) => {
|
||||
let lo = context.snippet_provider.span_after(self.span, "mut");
|
||||
let hi = context.snippet_provider.span_before(self.span, "ref");
|
||||
(
|
||||
context.snippet_provider.span_after(self.span, "ref"),
|
||||
combine_strs_with_missing_comments(
|
||||
context,
|
||||
mut_prefix,
|
||||
ref_kw,
|
||||
mk_sp(lo, hi),
|
||||
shape,
|
||||
true,
|
||||
)?,
|
||||
)
|
||||
}
|
||||
(false, true) => (
|
||||
context.snippet_provider.span_after(self.span, "mut"),
|
||||
combine_strs_with_missing_comments(
|
||||
context,
|
||||
prefix,
|
||||
mut_infix,
|
||||
mk_sp(lo, hi),
|
||||
shape,
|
||||
true,
|
||||
)?,
|
||||
)
|
||||
} else if !prefix.is_empty() {
|
||||
(
|
||||
mut_prefix.to_owned(),
|
||||
),
|
||||
(true, false) => (
|
||||
context.snippet_provider.span_after(self.span, "ref"),
|
||||
prefix.to_owned(),
|
||||
)
|
||||
} else if !mut_infix.is_empty() {
|
||||
(
|
||||
context.snippet_provider.span_after(self.span, "mut"),
|
||||
mut_infix.to_owned(),
|
||||
)
|
||||
} else {
|
||||
(self.span.lo(), "".to_owned())
|
||||
ref_kw.to_owned(),
|
||||
),
|
||||
(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()) {
|
||||
(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");
|
||||
(
|
||||
context.snippet_provider.span_after(end_span, "mut"),
|
||||
combine_strs_with_missing_comments(
|
||||
context,
|
||||
&first,
|
||||
mut_infix,
|
||||
mk_sp(lo, hi),
|
||||
shape,
|
||||
true,
|
||||
)?,
|
||||
)
|
||||
}
|
||||
(false, true) => (first_lo, first),
|
||||
(true, false) => unreachable!("mut_infix necessarily follows a ref"),
|
||||
(true, true) => (self.span.lo(), "".to_owned()),
|
||||
};
|
||||
|
||||
let next = if !sub_pat.is_empty() {
|
||||
@ -177,9 +200,9 @@ impl Rewrite for Pat {
|
||||
|
||||
combine_strs_with_missing_comments(
|
||||
context,
|
||||
&first,
|
||||
&second,
|
||||
&next,
|
||||
mk_sp(first_lo, ident.span.lo()),
|
||||
mk_sp(second_lo, ident.span.lo()),
|
||||
shape,
|
||||
true,
|
||||
)
|
||||
|
53
tests/ui/match/mut-ref-mut-2021.rs
Normal file
53
tests/ui/match/mut-ref-mut-2021.rs
Normal file
@ -0,0 +1,53 @@
|
||||
//@ edition: 2021
|
||||
|
||||
struct Foo(u8);
|
||||
|
||||
fn main() {
|
||||
let Foo(a) = Foo(0);
|
||||
a = 42; //~ ERROR [E0384]
|
||||
|
||||
let Foo(mut a) = Foo(0);
|
||||
a = 42;
|
||||
|
||||
let Foo(ref a) = Foo(0);
|
||||
a = &42; //~ ERROR [E0384]
|
||||
|
||||
let Foo(mut ref a) = Foo(0);
|
||||
a = &42;
|
||||
|
||||
let Foo(ref mut a) = Foo(0);
|
||||
a = &mut 42; //~ ERROR [E0384]
|
||||
|
||||
let Foo(mut ref mut a) = Foo(0);
|
||||
a = &mut 42;
|
||||
|
||||
let Foo(a) = &Foo(0);
|
||||
a = &42; //~ ERROR [E0384]
|
||||
|
||||
let Foo(mut a) = &Foo(0);
|
||||
a = 42;
|
||||
|
||||
let Foo(ref a) = &Foo(0);
|
||||
a = &42; //~ ERROR [E0384]
|
||||
|
||||
let Foo(mut ref a) = &Foo(0);
|
||||
a = &42;
|
||||
|
||||
let Foo(a) = &mut Foo(0);
|
||||
a = &mut 42; //~ ERROR [E0384]
|
||||
|
||||
let Foo(mut a) = &mut Foo(0);
|
||||
a = 42;
|
||||
|
||||
let Foo(ref a) = &mut Foo(0);
|
||||
a = &42; //~ ERROR [E0384]
|
||||
|
||||
let Foo(mut ref a) = &mut Foo(0);
|
||||
a = &42;
|
||||
|
||||
let Foo(ref mut a) = &mut Foo(0);
|
||||
a = &mut 42; //~ ERROR [E0384]
|
||||
|
||||
let Foo(mut ref mut a) = &mut Foo(0);
|
||||
a = &mut 42;
|
||||
}
|
70
tests/ui/match/mut-ref-mut-2021.stderr
Normal file
70
tests/ui/match/mut-ref-mut-2021.stderr
Normal file
@ -0,0 +1,70 @@
|
||||
error[E0384]: cannot assign twice to immutable variable `a`
|
||||
--> $DIR/mut-ref-mut-2021.rs:7:5
|
||||
|
|
||||
LL | let Foo(a) = Foo(0);
|
||||
| -
|
||||
| |
|
||||
| first assignment to `a`
|
||||
| help: consider making this binding mutable: `mut a`
|
||||
LL | a = 42;
|
||||
| ^^^^^^ cannot assign twice to immutable variable
|
||||
|
||||
error[E0384]: cannot assign twice to immutable variable `a`
|
||||
--> $DIR/mut-ref-mut-2021.rs:13:5
|
||||
|
|
||||
LL | let Foo(ref a) = Foo(0);
|
||||
| ----- first assignment to `a`
|
||||
LL | a = &42;
|
||||
| ^^^^^^^ cannot assign twice to immutable variable
|
||||
|
||||
error[E0384]: cannot assign twice to immutable variable `a`
|
||||
--> $DIR/mut-ref-mut-2021.rs:19:5
|
||||
|
|
||||
LL | let Foo(ref mut a) = Foo(0);
|
||||
| --------- first assignment to `a`
|
||||
LL | a = &mut 42;
|
||||
| ^^^^^^^^^^^ cannot assign twice to immutable variable
|
||||
|
||||
error[E0384]: cannot assign twice to immutable variable `a`
|
||||
--> $DIR/mut-ref-mut-2021.rs:25:5
|
||||
|
|
||||
LL | let Foo(a) = &Foo(0);
|
||||
| - first assignment to `a`
|
||||
LL | a = &42;
|
||||
| ^^^^^^^ cannot assign twice to immutable variable
|
||||
|
||||
error[E0384]: cannot assign twice to immutable variable `a`
|
||||
--> $DIR/mut-ref-mut-2021.rs:31:5
|
||||
|
|
||||
LL | let Foo(ref a) = &Foo(0);
|
||||
| ----- first assignment to `a`
|
||||
LL | a = &42;
|
||||
| ^^^^^^^ cannot assign twice to immutable variable
|
||||
|
||||
error[E0384]: cannot assign twice to immutable variable `a`
|
||||
--> $DIR/mut-ref-mut-2021.rs:37:5
|
||||
|
|
||||
LL | let Foo(a) = &mut Foo(0);
|
||||
| - first assignment to `a`
|
||||
LL | a = &mut 42;
|
||||
| ^^^^^^^^^^^ cannot assign twice to immutable variable
|
||||
|
||||
error[E0384]: cannot assign twice to immutable variable `a`
|
||||
--> $DIR/mut-ref-mut-2021.rs:43:5
|
||||
|
|
||||
LL | let Foo(ref a) = &mut Foo(0);
|
||||
| ----- first assignment to `a`
|
||||
LL | a = &42;
|
||||
| ^^^^^^^ cannot assign twice to immutable variable
|
||||
|
||||
error[E0384]: cannot assign twice to immutable variable `a`
|
||||
--> $DIR/mut-ref-mut-2021.rs:49:5
|
||||
|
|
||||
LL | let Foo(ref mut a) = &mut Foo(0);
|
||||
| --------- first assignment to `a`
|
||||
LL | a = &mut 42;
|
||||
| ^^^^^^^^^^^ cannot assign twice to immutable variable
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0384`.
|
@ -1,4 +1,10 @@
|
||||
//@ check-pass
|
||||
|
||||
fn main() {
|
||||
let mut ref x = 10; //~ ERROR the order of `mut` and `ref` is incorrect
|
||||
let ref mut y = 11;
|
||||
let mut ref x = 10;
|
||||
x = &11;
|
||||
let ref mut y = 12;
|
||||
*y = 13;
|
||||
let mut ref mut z = 14;
|
||||
z = &mut 15;
|
||||
}
|
||||
|
@ -1,8 +0,0 @@
|
||||
error: the order of `mut` and `ref` is incorrect
|
||||
--> $DIR/mut-ref.rs:2:9
|
||||
|
|
||||
LL | let mut ref x = 10;
|
||||
| ^^^^^^^ help: try switching the order: `ref mut`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
@ -11,9 +11,8 @@ params: [
|
||||
span: $DIR/thir-tree-match.rs:15:14: 15:17 (#0)
|
||||
kind: PatKind {
|
||||
Binding {
|
||||
mutability: Not
|
||||
name: "foo"
|
||||
mode: ByValue
|
||||
mode: BindingAnnotation(No, Not)
|
||||
var: LocalVarId(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).2))
|
||||
ty: Foo
|
||||
is_primary: true
|
||||
|
Loading…
Reference in New Issue
Block a user