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