Implement pattern matching for &pin mut|const T
This commit is contained in:
parent
292be5c7c0
commit
26f35ae269
53 changed files with 2552 additions and 86 deletions
|
|
@ -789,14 +789,14 @@ pub struct PatField {
|
|||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
#[derive(Encodable, Decodable, HashStable_Generic, Walkable)]
|
||||
pub enum ByRef {
|
||||
Yes(Mutability),
|
||||
Yes(Pinnedness, Mutability),
|
||||
No,
|
||||
}
|
||||
|
||||
impl ByRef {
|
||||
#[must_use]
|
||||
pub fn cap_ref_mutability(mut self, mutbl: Mutability) -> Self {
|
||||
if let ByRef::Yes(old_mutbl) = &mut self {
|
||||
if let ByRef::Yes(_, old_mutbl) = &mut self {
|
||||
*old_mutbl = cmp::min(*old_mutbl, mutbl);
|
||||
}
|
||||
self
|
||||
|
|
@ -814,20 +814,33 @@ pub struct BindingMode(pub ByRef, pub Mutability);
|
|||
|
||||
impl BindingMode {
|
||||
pub const NONE: Self = Self(ByRef::No, Mutability::Not);
|
||||
pub const REF: Self = Self(ByRef::Yes(Mutability::Not), Mutability::Not);
|
||||
pub const REF: Self = Self(ByRef::Yes(Pinnedness::Not, Mutability::Not), Mutability::Not);
|
||||
pub const REF_PIN: Self =
|
||||
Self(ByRef::Yes(Pinnedness::Pinned, Mutability::Not), Mutability::Not);
|
||||
pub const MUT: Self = Self(ByRef::No, 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 const REF_MUT: Self = Self(ByRef::Yes(Pinnedness::Not, Mutability::Mut), Mutability::Not);
|
||||
pub const REF_PIN_MUT: Self =
|
||||
Self(ByRef::Yes(Pinnedness::Pinned, Mutability::Mut), Mutability::Not);
|
||||
pub const MUT_REF: Self = Self(ByRef::Yes(Pinnedness::Not, Mutability::Not), Mutability::Mut);
|
||||
pub const MUT_REF_PIN: Self =
|
||||
Self(ByRef::Yes(Pinnedness::Pinned, Mutability::Not), Mutability::Mut);
|
||||
pub const MUT_REF_MUT: Self =
|
||||
Self(ByRef::Yes(Pinnedness::Not, Mutability::Mut), Mutability::Mut);
|
||||
pub const MUT_REF_PIN_MUT: Self =
|
||||
Self(ByRef::Yes(Pinnedness::Pinned, Mutability::Mut), Mutability::Mut);
|
||||
|
||||
pub fn prefix_str(self) -> &'static str {
|
||||
match self {
|
||||
Self::NONE => "",
|
||||
Self::REF => "ref ",
|
||||
Self::REF_PIN => "ref pin const ",
|
||||
Self::MUT => "mut ",
|
||||
Self::REF_MUT => "ref mut ",
|
||||
Self::REF_PIN_MUT => "ref pin mut ",
|
||||
Self::MUT_REF => "mut ref ",
|
||||
Self::MUT_REF_PIN => "mut ref pin ",
|
||||
Self::MUT_REF_MUT => "mut ref mut ",
|
||||
Self::MUT_REF_PIN_MUT => "mut ref pin mut ",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -368,6 +368,7 @@ macro_rules! common_visitor_and_walkers {
|
|||
crate::tokenstream::TokenStream,
|
||||
Movability,
|
||||
Mutability,
|
||||
Pinnedness,
|
||||
Result<(), rustc_span::ErrorGuaranteed>,
|
||||
rustc_data_structures::fx::FxHashMap<Symbol, usize>,
|
||||
rustc_span::ErrorGuaranteed,
|
||||
|
|
|
|||
|
|
@ -311,3 +311,10 @@ pub enum Pinnedness {
|
|||
Not,
|
||||
Pinned,
|
||||
}
|
||||
|
||||
impl Pinnedness {
|
||||
/// Return `true` if self is pinned
|
||||
pub fn is_pinned(self) -> bool {
|
||||
matches!(self, Self::Pinned)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1712,10 +1712,15 @@ impl<'a> State<'a> {
|
|||
if mutbl.is_mut() {
|
||||
self.word_nbsp("mut");
|
||||
}
|
||||
if let ByRef::Yes(rmutbl) = by_ref {
|
||||
if let ByRef::Yes(pinnedness, rmutbl) = by_ref {
|
||||
self.word_nbsp("ref");
|
||||
if pinnedness.is_pinned() {
|
||||
self.word_nbsp("pin");
|
||||
}
|
||||
if rmutbl.is_mut() {
|
||||
self.word_nbsp("mut");
|
||||
} else if pinnedness.is_pinned() {
|
||||
self.word_nbsp("const");
|
||||
}
|
||||
}
|
||||
self.print_ident(*ident);
|
||||
|
|
|
|||
|
|
@ -1188,7 +1188,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
}
|
||||
|
||||
LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
|
||||
binding_mode: BindingMode(ByRef::Yes(_), _),
|
||||
binding_mode: BindingMode(ByRef::Yes(..), _),
|
||||
..
|
||||
})) => {
|
||||
let pattern_span: Span = local_decl.source_info.span;
|
||||
|
|
|
|||
|
|
@ -2584,6 +2584,16 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
_ => bug!("Deref of unexpected type: {:?}", base_ty),
|
||||
}
|
||||
}
|
||||
// Check as the inner reference type if it is a field projection
|
||||
// from the `&pin` pattern
|
||||
ProjectionElem::Field(FieldIdx::ZERO, _)
|
||||
if let Some(adt) =
|
||||
place_base.ty(self.body(), self.infcx.tcx).ty.ty_adt_def()
|
||||
&& adt.is_pin()
|
||||
&& self.infcx.tcx.features().pin_ergonomics() =>
|
||||
{
|
||||
self.is_mutable(place_base, is_local_mutation_allowed)
|
||||
}
|
||||
// All other projections are owned by their base path, so mutable if
|
||||
// base path is mutable
|
||||
ProjectionElem::Field(..)
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use rustc_ast::{
|
|||
pub use rustc_ast::{
|
||||
AssignOp, AssignOpKind, AttrId, AttrStyle, BinOp, BinOpKind, BindingMode, BorrowKind,
|
||||
BoundConstness, BoundPolarity, ByRef, CaptureBy, DelimArgs, ImplPolarity, IsAuto,
|
||||
MetaItemInner, MetaItemLit, Movability, Mutability, UnOp,
|
||||
MetaItemInner, MetaItemLit, Movability, Mutability, Pinnedness, UnOp,
|
||||
};
|
||||
use rustc_data_structures::fingerprint::Fingerprint;
|
||||
use rustc_data_structures::sorted_map::SortedMap;
|
||||
|
|
|
|||
|
|
@ -575,7 +575,7 @@ fn resolve_local<'tcx>(
|
|||
// & expression, and its lifetime would be extended to the end of the block (due
|
||||
// to a different rule, not the below code).
|
||||
match pat.kind {
|
||||
PatKind::Binding(hir::BindingMode(hir::ByRef::Yes(_), _), ..) => true,
|
||||
PatKind::Binding(hir::BindingMode(hir::ByRef::Yes(..), _), ..) => true,
|
||||
|
||||
PatKind::Struct(_, field_pats, _) => field_pats.iter().any(|fp| is_binding_pat(fp.pat)),
|
||||
|
||||
|
|
|
|||
|
|
@ -1928,10 +1928,15 @@ impl<'a> State<'a> {
|
|||
if mutbl.is_mut() {
|
||||
self.word_nbsp("mut");
|
||||
}
|
||||
if let ByRef::Yes(rmutbl) = by_ref {
|
||||
if let ByRef::Yes(pinnedness, rmutbl) = by_ref {
|
||||
self.word_nbsp("ref");
|
||||
if pinnedness.is_pinned() {
|
||||
self.word_nbsp("pin");
|
||||
}
|
||||
if rmutbl.is_mut() {
|
||||
self.word_nbsp("mut");
|
||||
} else if pinnedness.is_pinned() {
|
||||
self.word_nbsp("const");
|
||||
}
|
||||
}
|
||||
self.print_ident(ident);
|
||||
|
|
|
|||
|
|
@ -986,7 +986,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
// of the pattern, as this just looks confusing, instead use the span
|
||||
// of the discriminant.
|
||||
match bm.0 {
|
||||
hir::ByRef::Yes(m) => {
|
||||
hir::ByRef::Yes(_, m) => {
|
||||
let bk = ty::BorrowKind::from_mutbl(m);
|
||||
self.delegate.borrow_mut().borrow(place, discr_place.hir_id, bk);
|
||||
}
|
||||
|
|
@ -1004,7 +1004,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
// Deref patterns on boxes don't borrow, so we ignore them here.
|
||||
// HACK: this could be a fake pattern corresponding to a deref inserted by match
|
||||
// ergonomics, in which case `pat.hir_id` will be the id of the subpattern.
|
||||
if let hir::ByRef::Yes(mutability) =
|
||||
if let hir::ByRef::Yes(_, mutability) =
|
||||
self.cx.typeck_results().deref_pat_borrow_mode(place.place.ty(), subpattern)
|
||||
{
|
||||
let bk = ty::BorrowKind::from_mutbl(mutability);
|
||||
|
|
@ -1256,7 +1256,15 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
.get(pat.hir_id)
|
||||
.expect("missing binding mode");
|
||||
|
||||
if matches!(bm.0, hir::ByRef::Yes(_)) {
|
||||
if let hir::ByRef::Yes(pinnedness, _) = bm.0 {
|
||||
let base_ty = if pinnedness.is_pinned() {
|
||||
base_ty.pinned_ty().ok_or_else(|| {
|
||||
debug!("By-pin-ref binding of non-`Pin` type: {base_ty:?}");
|
||||
self.cx.report_bug(pat.span, "by-pin-ref binding of non-`Pin` type")
|
||||
})?
|
||||
} else {
|
||||
base_ty
|
||||
};
|
||||
// a bind-by-ref means that the base_ty will be the type of the ident itself,
|
||||
// but what we want here is the type of the underlying value being borrowed.
|
||||
// So peel off one-level, turning the &T into T.
|
||||
|
|
@ -1264,7 +1272,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
{
|
||||
Some(ty) => Ok(ty),
|
||||
None => {
|
||||
debug!("By-ref binding of non-derefable type");
|
||||
debug!("By-ref binding of non-derefable type: {base_ty:?}");
|
||||
Err(self
|
||||
.cx
|
||||
.report_bug(pat.span, "by-ref binding of non-derefable type"))
|
||||
|
|
@ -1706,6 +1714,18 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
};
|
||||
self.pat_deref_place(pat.hir_id, place_with_id, pat, target_ty)?
|
||||
}
|
||||
adjustment::PatAdjust::PinDeref => {
|
||||
debug!("`PinDeref` of non-pinned-reference type: {:?}", adjust.source);
|
||||
let target_ty = adjust.source.pinned_ty().ok_or_else(|| {
|
||||
self.cx.report_bug(
|
||||
self.cx.tcx().hir_span(pat.hir_id),
|
||||
"`PinDeref` of non-pinned-reference type",
|
||||
)
|
||||
})?;
|
||||
let kind = ProjectionKind::Field(FieldIdx::ZERO, FIRST_VARIANT);
|
||||
place_with_id = self.cat_projection(pat.hir_id, place_with_id, target_ty, kind);
|
||||
self.cat_deref(pat.hir_id, place_with_id)?
|
||||
}
|
||||
};
|
||||
}
|
||||
drop(typeck_results); // explicitly release borrow of typeck results, just in case.
|
||||
|
|
@ -1877,7 +1897,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
// Deref patterns on boxes are lowered using a built-in deref.
|
||||
hir::ByRef::No => self.cat_deref(hir_id, base_place),
|
||||
// For other types, we create a temporary to match on.
|
||||
hir::ByRef::Yes(mutability) => {
|
||||
hir::ByRef::Yes(_, mutability) => {
|
||||
let re_erased = self.cx.tcx().lifetimes.re_erased;
|
||||
let ty = Ty::new_ref(self.cx.tcx(), re_erased, target_ty, mutability);
|
||||
// A deref pattern stores the result of `Deref::deref` or `DerefMut::deref_mut` ...
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ use rustc_hir::{
|
|||
use rustc_hir_analysis::autoderef::report_autoderef_recursion_limit_error;
|
||||
use rustc_infer::infer::RegionVariableOrigin;
|
||||
use rustc_middle::traits::PatternOriginExpr;
|
||||
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
|
||||
use rustc_middle::ty::{self, Pinnedness, Ty, TypeVisitableExt};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
|
||||
use rustc_session::parse::feature_err;
|
||||
|
|
@ -413,7 +413,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
pat,
|
||||
derefed_tys.iter().filter_map(|adjust| match adjust.kind {
|
||||
PatAdjust::OverloadedDeref => Some(adjust.source),
|
||||
PatAdjust::BuiltinDeref => None,
|
||||
PatAdjust::BuiltinDeref | PatAdjust::PinDeref => None,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
|
@ -471,7 +471,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
pat_info: PatInfo<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
#[cfg(debug_assertions)]
|
||||
if pat_info.binding_mode == ByRef::Yes(Mutability::Mut)
|
||||
if matches!(pat_info.binding_mode, ByRef::Yes(_, Mutability::Mut))
|
||||
&& pat_info.max_ref_mutbl != MutblCap::Mut
|
||||
&& self.downgrade_mut_inside_shared()
|
||||
{
|
||||
|
|
@ -489,12 +489,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let old_pat_info = pat_info;
|
||||
let pat_info = PatInfo { current_depth: old_pat_info.current_depth + 1, ..old_pat_info };
|
||||
|
||||
let adjust_binding_mode = |inner_pinnedness, inner_mutability| {
|
||||
match pat_info.binding_mode {
|
||||
// If default binding mode is by value, make it `ref`, `ref mut`, `ref pin const`
|
||||
// or `ref pin mut` (depending on whether we observe `&`, `&mut`, `&pin const` or
|
||||
// `&pin mut`).
|
||||
ByRef::No => ByRef::Yes(inner_pinnedness, inner_mutability),
|
||||
// When `ref mut`, stay a `ref mut` (on `&mut`) or downgrade to `ref` (on `&`).
|
||||
// Pinnedness is preserved.
|
||||
ByRef::Yes(pinnedness, Mutability::Mut) => ByRef::Yes(pinnedness, inner_mutability),
|
||||
// Once a `ref`, always a `ref`.
|
||||
// This is because a `& &mut` cannot mutate the underlying value.
|
||||
// Pinnedness is preserved.
|
||||
ByRef::Yes(pinnedness, Mutability::Not) => ByRef::Yes(pinnedness, Mutability::Not),
|
||||
}
|
||||
};
|
||||
|
||||
match pat.kind {
|
||||
// Peel off a `&` or `&mut` from the scrutinee type. See the examples in
|
||||
// Peel off a `&` or `&mut`from the scrutinee type. See the examples in
|
||||
// `tests/ui/rfcs/rfc-2005-default-binding-mode`.
|
||||
_ if let AdjustMode::Peel { kind: peel_kind } = adjust_mode
|
||||
&& pat.default_binding_modes
|
||||
&& let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind()
|
||||
&& let &ty::Ref(_, inner_ty, inner_mutability) = expected.kind()
|
||||
&& self.should_peel_ref(peel_kind, expected) =>
|
||||
{
|
||||
debug!("inspecting {:?}", expected);
|
||||
|
|
@ -508,22 +524,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
.or_default()
|
||||
.push(PatAdjustment { kind: PatAdjust::BuiltinDeref, source: expected });
|
||||
|
||||
let mut binding_mode = ByRef::Yes(match pat_info.binding_mode {
|
||||
// If default binding mode is by value, make it `ref` or `ref mut`
|
||||
// (depending on whether we observe `&` or `&mut`).
|
||||
ByRef::No |
|
||||
// When `ref mut`, stay a `ref mut` (on `&mut`) or downgrade to `ref` (on `&`).
|
||||
ByRef::Yes(Mutability::Mut) => inner_mutability,
|
||||
// Once a `ref`, always a `ref`.
|
||||
// This is because a `& &mut` cannot mutate the underlying value.
|
||||
ByRef::Yes(Mutability::Not) => Mutability::Not,
|
||||
});
|
||||
let mut binding_mode = adjust_binding_mode(Pinnedness::Not, inner_mutability);
|
||||
|
||||
let mut max_ref_mutbl = pat_info.max_ref_mutbl;
|
||||
if self.downgrade_mut_inside_shared() {
|
||||
binding_mode = binding_mode.cap_ref_mutability(max_ref_mutbl.as_mutbl());
|
||||
}
|
||||
if binding_mode == ByRef::Yes(Mutability::Not) {
|
||||
if matches!(binding_mode, ByRef::Yes(_, Mutability::Not)) {
|
||||
max_ref_mutbl = MutblCap::Not;
|
||||
}
|
||||
debug!("default binding mode is now {:?}", binding_mode);
|
||||
|
|
@ -533,6 +540,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// Recurse with the new expected type.
|
||||
self.check_pat_inner(pat, opt_path_res, adjust_mode, inner_ty, new_pat_info)
|
||||
}
|
||||
// If `pin_ergonomics` is enabled, peel the `&pin` from the pinned reference type. See the
|
||||
// examples in `tests/ui/async-await/pin-ergonomics/`.
|
||||
_ if self.tcx.features().pin_ergonomics()
|
||||
&& let AdjustMode::Peel { kind: peel_kind } = adjust_mode
|
||||
&& pat.default_binding_modes
|
||||
&& self.should_peel_smart_pointer(peel_kind, expected)
|
||||
&& let Some(pinned_ty) = expected.pinned_ty()
|
||||
// Currently, only pinned reference is specially handled, leaving other
|
||||
// pinned types (e.g. `Pin<Box<T>>` to deref patterns) handled as a
|
||||
// deref pattern.
|
||||
&& let &ty::Ref(_, inner_ty, inner_mutability) = pinned_ty.kind() =>
|
||||
{
|
||||
debug!("scrutinee ty {expected:?} is a pinned reference, inserting pin deref");
|
||||
// Preserve the pinned type. We'll need it later during THIR lowering.
|
||||
self.typeck_results
|
||||
.borrow_mut()
|
||||
.pat_adjustments_mut()
|
||||
.entry(pat.hir_id)
|
||||
.or_default()
|
||||
.push(PatAdjustment { kind: PatAdjust::PinDeref, source: expected });
|
||||
|
||||
let binding_mode = adjust_binding_mode(Pinnedness::Pinned, inner_mutability);
|
||||
// If the pinnedness is `Not`, it means the pattern is unpinned
|
||||
// and thus requires an `Unpin` bound.
|
||||
if binding_mode == ByRef::Yes(Pinnedness::Not, Mutability::Mut) {
|
||||
self.register_bound(
|
||||
inner_ty,
|
||||
self.tcx.require_lang_item(hir::LangItem::Unpin, pat.span),
|
||||
self.misc(pat.span),
|
||||
);
|
||||
}
|
||||
// Use the old pat info to keep `current_depth` to its old value.
|
||||
let new_pat_info = PatInfo { binding_mode, ..old_pat_info };
|
||||
// Recurse with the new expected type.
|
||||
// using `break` instead of `return` in case where any shared codes are added
|
||||
// after the `match pat.kind {}`.
|
||||
self.check_pat_inner(pat, opt_path_res, adjust_mode, inner_ty, new_pat_info)
|
||||
}
|
||||
// If `deref_patterns` is enabled, peel a smart pointer from the scrutinee type. See the
|
||||
// examples in `tests/ui/pattern/deref_patterns/`.
|
||||
_ if self.tcx.features().deref_patterns()
|
||||
|
|
@ -1061,7 +1106,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
// Determine the binding mode...
|
||||
let bm = match user_bind_annot {
|
||||
BindingMode(ByRef::No, Mutability::Mut) if let ByRef::Yes(def_br_mutbl) = def_br => {
|
||||
BindingMode(ByRef::No, Mutability::Mut) if let ByRef::Yes(_, def_br_mutbl) = def_br => {
|
||||
// Only mention the experimental `mut_ref` feature if if we're in edition 2024 and
|
||||
// using other experimental matching features compatible with it.
|
||||
if pat.span.at_least_rust_2024()
|
||||
|
|
@ -1091,8 +1136,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
BindingMode(ByRef::No, mutbl) => BindingMode(def_br, mutbl),
|
||||
BindingMode(ByRef::Yes(user_br_mutbl), _) => {
|
||||
if let ByRef::Yes(def_br_mutbl) = def_br {
|
||||
BindingMode(ByRef::Yes(_, user_br_mutbl), _) => {
|
||||
if let ByRef::Yes(_, def_br_mutbl) = def_br {
|
||||
// `ref`/`ref mut` overrides the binding mode on edition <= 2021
|
||||
self.add_rust_2024_migration_desugared_pat(
|
||||
pat_info.top_info.hir_id,
|
||||
|
|
@ -1108,7 +1153,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
};
|
||||
|
||||
if bm.0 == ByRef::Yes(Mutability::Mut)
|
||||
if matches!(bm.0, ByRef::Yes(_, Mutability::Mut))
|
||||
&& let MutblCap::WeaklyNot(and_pat_span) = pat_info.max_ref_mutbl
|
||||
{
|
||||
let mut err = struct_span_code_err!(
|
||||
|
|
@ -1136,7 +1181,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
let local_ty = self.local_ty(pat.span, pat.hir_id);
|
||||
let eq_ty = match bm.0 {
|
||||
ByRef::Yes(mutbl) => {
|
||||
ByRef::Yes(Pinnedness::Not, mutbl) => {
|
||||
// If the binding is like `ref x | ref mut x`,
|
||||
// then `x` is assigned a value of type `&M T` where M is the
|
||||
// mutability and T is the expected type.
|
||||
|
|
@ -1146,6 +1191,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// See (note_1) for an explanation.
|
||||
self.new_ref_ty(pat.span, mutbl, expected)
|
||||
}
|
||||
// Wrapping the type into `Pin` if the binding is like `ref pin const|mut x`
|
||||
ByRef::Yes(Pinnedness::Pinned, mutbl) => Ty::new_adt(
|
||||
self.tcx,
|
||||
self.tcx.adt_def(self.tcx.require_lang_item(hir::LangItem::Pin, pat.span)),
|
||||
self.tcx.mk_args(&[self.new_ref_ty(pat.span, mutbl, expected).into()]),
|
||||
),
|
||||
// Otherwise, the type of x is the expected type `T`.
|
||||
ByRef::No => expected, // As above, `T <: typeof(x)` is required, but we use equality, see (note_1).
|
||||
};
|
||||
|
|
@ -2605,7 +2656,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
expected = self.try_structurally_resolve_type(pat.span, expected);
|
||||
// Determine whether we're consuming an inherited reference and resetting the default
|
||||
// binding mode, based on edition and enabled experimental features.
|
||||
if let ByRef::Yes(inh_mut) = pat_info.binding_mode {
|
||||
if let ByRef::Yes(_, inh_mut) = pat_info.binding_mode {
|
||||
match self.ref_pat_matches_inherited_ref(pat.span.edition()) {
|
||||
InheritedRefMatchRule::EatOuter => {
|
||||
// ref pattern attempts to consume inherited reference
|
||||
|
|
@ -3126,8 +3177,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// If the user-provided binding modifier doesn't match the default binding mode, we'll
|
||||
// need to suggest reference patterns, which can affect other bindings.
|
||||
// For simplicity, we opt to suggest making the pattern fully explicit.
|
||||
info.suggest_eliding_modes &=
|
||||
user_bind_annot == BindingMode(ByRef::Yes(def_br_mutbl), Mutability::Not);
|
||||
info.suggest_eliding_modes &= matches!(
|
||||
user_bind_annot,
|
||||
BindingMode(ByRef::Yes(_, mutbl), Mutability::Not) if mutbl == def_br_mutbl
|
||||
);
|
||||
if user_bind_annot == BindingMode(ByRef::No, Mutability::Mut) {
|
||||
info.bad_mut_modifiers = true;
|
||||
"`mut` binding modifier"
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for StaticMutRefs {
|
|||
fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &Stmt<'_>) {
|
||||
if let hir::StmtKind::Let(loc) = stmt.kind
|
||||
&& let hir::PatKind::Binding(ba, _, _, _) = loc.pat.kind
|
||||
&& let hir::ByRef::Yes(m) = ba.0
|
||||
&& let hir::ByRef::Yes(_, m) = ba.0
|
||||
&& let Some(init) = loc.init
|
||||
&& let Some(err_span) = path_is_static_mut(init, init.span)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -232,4 +232,7 @@ pub enum PatAdjust {
|
|||
/// An implicit call to `Deref(Mut)::deref(_mut)` before matching, such as when matching the
|
||||
/// pattern `[..]` against a scrutinee of type `Vec<T>`.
|
||||
OverloadedDeref,
|
||||
/// An implicit dereference before matching a `&pin` reference (under feature `pin_ergonomics`),
|
||||
/// which will be lowered as a builtin deref of the private field `__pointer` in `Pin`
|
||||
PinDeref,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,6 +55,8 @@ bitflags::bitflags! {
|
|||
const IS_UNSAFE_CELL = 1 << 9;
|
||||
/// Indicates whether the type is `UnsafePinned`.
|
||||
const IS_UNSAFE_PINNED = 1 << 10;
|
||||
/// Indicates whether the type is `Pin`.
|
||||
const IS_PIN = 1 << 11;
|
||||
}
|
||||
}
|
||||
rustc_data_structures::external_bitflags_debug! { AdtFlags }
|
||||
|
|
@ -313,6 +315,9 @@ impl AdtDefData {
|
|||
if tcx.is_lang_item(did, LangItem::UnsafePinned) {
|
||||
flags |= AdtFlags::IS_UNSAFE_PINNED;
|
||||
}
|
||||
if tcx.is_lang_item(did, LangItem::Pin) {
|
||||
flags |= AdtFlags::IS_PIN;
|
||||
}
|
||||
|
||||
AdtDefData { did, variants, flags, repr }
|
||||
}
|
||||
|
|
@ -428,6 +433,12 @@ impl<'tcx> AdtDef<'tcx> {
|
|||
self.flags().contains(AdtFlags::IS_MANUALLY_DROP)
|
||||
}
|
||||
|
||||
/// Returns `true` if this is `Pin<T>`.
|
||||
#[inline]
|
||||
pub fn is_pin(self) -> bool {
|
||||
self.flags().contains(AdtFlags::IS_PIN)
|
||||
}
|
||||
|
||||
/// Returns `true` if this type has a destructor.
|
||||
pub fn has_dtor(self, tcx: TyCtxt<'tcx>) -> bool {
|
||||
self.destructor(tcx).is_some()
|
||||
|
|
|
|||
|
|
@ -1349,6 +1349,13 @@ impl<'tcx> Ty<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn pinned_ty(self) -> Option<Ty<'tcx>> {
|
||||
match self.kind() {
|
||||
Adt(def, args) if def.is_pin() => Some(args.type_at(0)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Panics if called on any type other than `Box<T>`.
|
||||
pub fn expect_boxed_ty(self) -> Ty<'tcx> {
|
||||
self.boxed_ty()
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdMap};
|
|||
use rustc_hir::hir_id::OwnerId;
|
||||
use rustc_hir::{
|
||||
self as hir, BindingMode, ByRef, HirId, ItemLocalId, ItemLocalMap, ItemLocalSet, Mutability,
|
||||
Pinnedness,
|
||||
};
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
|
||||
|
|
@ -479,7 +480,7 @@ impl<'tcx> TypeckResults<'tcx> {
|
|||
let mut has_ref_mut = false;
|
||||
pat.walk(|pat| {
|
||||
if let hir::PatKind::Binding(_, id, _, _) = pat.kind
|
||||
&& let Some(BindingMode(ByRef::Yes(Mutability::Mut), _)) =
|
||||
&& let Some(BindingMode(ByRef::Yes(_, Mutability::Mut), _)) =
|
||||
self.pat_binding_modes().get(id)
|
||||
{
|
||||
has_ref_mut = true;
|
||||
|
|
@ -503,7 +504,7 @@ impl<'tcx> TypeckResults<'tcx> {
|
|||
ByRef::No
|
||||
} else {
|
||||
let mutable = self.pat_has_ref_mut_binding(inner);
|
||||
ByRef::Yes(if mutable { Mutability::Mut } else { Mutability::Not })
|
||||
ByRef::Yes(Pinnedness::Not, if mutable { Mutability::Mut } else { Mutability::Not })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use rustc_abi::FieldIdx;
|
||||
use rustc_hir::ByRef;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::thir::*;
|
||||
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
|
||||
use rustc_middle::ty::{self, Pinnedness, Ty, TypeVisitableExt};
|
||||
|
||||
use crate::builder::Builder;
|
||||
use crate::builder::expr::as_place::{PlaceBase, PlaceBuilder};
|
||||
|
|
@ -299,7 +300,24 @@ impl<'tcx> MatchPairTree<'tcx> {
|
|||
None
|
||||
}
|
||||
|
||||
PatKind::DerefPattern { ref subpattern, borrow: ByRef::Yes(mutability) } => {
|
||||
PatKind::DerefPattern { ref subpattern, borrow: ByRef::Yes(Pinnedness::Pinned, _) } => {
|
||||
let Some(ref_ty) = pattern.ty.pinned_ty() else {
|
||||
rustc_middle::bug!("RefPin pattern on non-`Pin` type {:?}", pattern.ty);
|
||||
};
|
||||
MatchPairTree::for_pattern(
|
||||
place_builder.field(FieldIdx::ZERO, ref_ty).deref(),
|
||||
subpattern,
|
||||
cx,
|
||||
&mut subpairs,
|
||||
extra_data,
|
||||
);
|
||||
None
|
||||
}
|
||||
|
||||
PatKind::DerefPattern {
|
||||
ref subpattern,
|
||||
borrow: ByRef::Yes(Pinnedness::Not, mutability),
|
||||
} => {
|
||||
// Create a new temporary for each deref pattern.
|
||||
// FIXME(deref_patterns): dedup temporaries to avoid multiple `deref()` calls?
|
||||
let temp = cx.temp(
|
||||
|
|
|
|||
|
|
@ -5,20 +5,21 @@
|
|||
//! This also includes code for pattern bindings in `let` statements and
|
||||
//! function parameters.
|
||||
|
||||
use std::assert_matches::debug_assert_matches;
|
||||
use std::borrow::Borrow;
|
||||
use std::mem;
|
||||
use std::sync::Arc;
|
||||
|
||||
use itertools::{Itertools, Position};
|
||||
use rustc_abi::VariantIdx;
|
||||
use rustc_abi::{FIRST_VARIANT, FieldIdx, VariantIdx};
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_hir::{BindingMode, ByRef, LetStmt, LocalSource, Node};
|
||||
use rustc_middle::bug;
|
||||
use rustc_hir::{BindingMode, ByRef, LangItem, LetStmt, LocalSource, Node, Pinnedness};
|
||||
use rustc_middle::middle::region;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::thir::{self, *};
|
||||
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, ValTree, ValTreeKind};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_pattern_analysis::constructor::RangeEnd;
|
||||
use rustc_pattern_analysis::rustc::{DeconstructedPat, RustcPatCtxt};
|
||||
use rustc_span::{BytePos, Pos, Span, Symbol, sym};
|
||||
|
|
@ -917,6 +918,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
visit_subpat(self, subpattern, &user_tys.deref(), f);
|
||||
}
|
||||
|
||||
PatKind::DerefPattern { ref subpattern, borrow: ByRef::Yes(Pinnedness::Pinned, _) } => {
|
||||
visit_subpat(self, subpattern, &user_tys.leaf(FieldIdx::ZERO).deref(), f);
|
||||
}
|
||||
|
||||
PatKind::DerefPattern { ref subpattern, .. } => {
|
||||
visit_subpat(self, subpattern, &ProjectedUserTypesNode::None, f);
|
||||
}
|
||||
|
|
@ -2747,9 +2752,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
let rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, binding.source);
|
||||
self.cfg.push_assign(block, source_info, ref_for_guard, rvalue);
|
||||
}
|
||||
ByRef::Yes(mutbl) => {
|
||||
// The arm binding will be by reference, so eagerly create it now. Drops must
|
||||
// be scheduled to emit `StorageDead` on the guard's failure/break branches.
|
||||
ByRef::Yes(pinnedness, mutbl) => {
|
||||
// The arm binding will be by reference, so eagerly create it now // be scheduled to emit `StorageDead` on the guard's failure/break branches.
|
||||
let value_for_arm = self.storage_live_binding(
|
||||
block,
|
||||
binding.var_id,
|
||||
|
|
@ -2761,6 +2765,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
|
||||
let rvalue =
|
||||
Rvalue::Ref(re_erased, util::ref_pat_borrow_kind(mutbl), binding.source);
|
||||
let rvalue = match pinnedness {
|
||||
ty::Pinnedness::Not => rvalue,
|
||||
ty::Pinnedness::Pinned => {
|
||||
self.pin_borrowed_local(block, value_for_arm.local, rvalue, source_info)
|
||||
}
|
||||
};
|
||||
self.cfg.push_assign(block, source_info, value_for_arm, rvalue);
|
||||
// For the guard binding, take a shared reference to that reference.
|
||||
let rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, value_for_arm);
|
||||
|
|
@ -2797,14 +2807,59 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
}
|
||||
let rvalue = match binding.binding_mode.0 {
|
||||
ByRef::No => Rvalue::Use(self.consume_by_copy_or_move(binding.source)),
|
||||
ByRef::Yes(mutbl) => {
|
||||
Rvalue::Ref(re_erased, util::ref_pat_borrow_kind(mutbl), binding.source)
|
||||
ByRef::Yes(pinnedness, mutbl) => {
|
||||
let rvalue =
|
||||
Rvalue::Ref(re_erased, util::ref_pat_borrow_kind(mutbl), binding.source);
|
||||
match pinnedness {
|
||||
ty::Pinnedness::Not => rvalue,
|
||||
ty::Pinnedness::Pinned => {
|
||||
self.pin_borrowed_local(block, local.local, rvalue, source_info)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
self.cfg.push_assign(block, source_info, local, rvalue);
|
||||
}
|
||||
}
|
||||
|
||||
/// Given an rvalue `&[mut]borrow` and a local `local`, generate the pinned borrow for it:
|
||||
/// ```ignore (illustrative)
|
||||
/// pinned_temp = &borrow;
|
||||
/// local = Pin { __pointer: move pinned_temp };
|
||||
/// ```
|
||||
fn pin_borrowed_local(
|
||||
&mut self,
|
||||
block: BasicBlock,
|
||||
local: Local,
|
||||
borrow: Rvalue<'tcx>,
|
||||
source_info: SourceInfo,
|
||||
) -> Rvalue<'tcx> {
|
||||
debug_assert_matches!(borrow, Rvalue::Ref(..));
|
||||
|
||||
let local_ty = self.local_decls[local].ty;
|
||||
|
||||
let pinned_ty = local_ty.pinned_ty().unwrap_or_else(|| {
|
||||
span_bug!(
|
||||
source_info.span,
|
||||
"expect type `Pin` for a pinned binding, found type {:?}",
|
||||
local_ty
|
||||
)
|
||||
});
|
||||
let pinned_temp =
|
||||
Place::from(self.local_decls.push(LocalDecl::new(pinned_ty, source_info.span)));
|
||||
self.cfg.push_assign(block, source_info, pinned_temp, borrow);
|
||||
Rvalue::Aggregate(
|
||||
Box::new(AggregateKind::Adt(
|
||||
self.tcx.require_lang_item(LangItem::Pin, source_info.span),
|
||||
FIRST_VARIANT,
|
||||
self.tcx.mk_args(&[pinned_ty.into()]),
|
||||
None,
|
||||
None,
|
||||
)),
|
||||
std::iter::once(Operand::Move(pinned_temp)).collect(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Each binding (`ref mut var`/`ref var`/`mut var`/`var`, where the bound
|
||||
/// `var` has type `T` in the arm body) in a pattern maps to 2 locals. The
|
||||
/// first local is a binding for occurrences of `var` in the guard, which
|
||||
|
|
|
|||
|
|
@ -383,7 +383,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
|||
}
|
||||
visit::walk_pat(self, pat);
|
||||
}
|
||||
PatKind::Binding { mode: BindingMode(ByRef::Yes(rm), _), ty, .. } => {
|
||||
PatKind::Binding { mode: BindingMode(ByRef::Yes(_, rm), _), ty, .. } => {
|
||||
if self.inside_adt {
|
||||
let ty::Ref(_, ty, _) = ty.kind() else {
|
||||
span_bug!(
|
||||
|
|
|
|||
|
|
@ -797,7 +797,7 @@ fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, 'tcx>, pat:
|
|||
// We have `x @ pat` where `x` is by-move. Reject all borrows in `pat`.
|
||||
let mut conflicts_ref = Vec::new();
|
||||
sub.each_binding(|_, mode, _, span| {
|
||||
if matches!(mode, ByRef::Yes(_)) {
|
||||
if matches!(mode, ByRef::Yes(..)) {
|
||||
conflicts_ref.push(span)
|
||||
}
|
||||
});
|
||||
|
|
@ -813,7 +813,7 @@ fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, 'tcx>, pat:
|
|||
return;
|
||||
}
|
||||
ByRef::No => return,
|
||||
ByRef::Yes(m) => m,
|
||||
ByRef::Yes(_, m) => m,
|
||||
};
|
||||
|
||||
// We now have `ref $mut_outer binding @ sub` (semantically).
|
||||
|
|
@ -823,7 +823,7 @@ fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, 'tcx>, pat:
|
|||
let mut conflicts_mut_ref = Vec::new();
|
||||
sub.each_binding(|name, mode, ty, span| {
|
||||
match mode {
|
||||
ByRef::Yes(mut_inner) => match (mut_outer, mut_inner) {
|
||||
ByRef::Yes(_, mut_inner) => match (mut_outer, mut_inner) {
|
||||
// Both sides are `ref`.
|
||||
(Mutability::Not, Mutability::Not) => {}
|
||||
// 2x `ref mut`.
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@ impl<'a> PatMigration<'a> {
|
|||
}
|
||||
if !self.info.suggest_eliding_modes
|
||||
&& explicit_ba.0 == ByRef::No
|
||||
&& let ByRef::Yes(mutbl) = mode.0
|
||||
&& let ByRef::Yes(_, mutbl) = mode.0
|
||||
{
|
||||
// If we can't fix the pattern by eliding modifiers, we'll need to make the pattern
|
||||
// fully explicit. i.e. we'll need to suggest reference patterns for this.
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use rustc_abi::{FieldIdx, Integer};
|
|||
use rustc_errors::codes::*;
|
||||
use rustc_hir::def::{CtorOf, DefKind, Res};
|
||||
use rustc_hir::pat_util::EnumerateAndAdjustIterator;
|
||||
use rustc_hir::{self as hir, LangItem, RangeEnd};
|
||||
use rustc_hir::{self as hir, ByRef, LangItem, Mutability, Pinnedness, RangeEnd};
|
||||
use rustc_index::Idx;
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_middle::mir::interpret::LitToConstInput;
|
||||
|
|
@ -114,6 +114,16 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
let borrow = self.typeck_results.deref_pat_borrow_mode(adjust.source, pat);
|
||||
PatKind::DerefPattern { subpattern: thir_pat, borrow }
|
||||
}
|
||||
PatAdjust::PinDeref => {
|
||||
let mutable = self.typeck_results.pat_has_ref_mut_binding(pat);
|
||||
PatKind::DerefPattern {
|
||||
subpattern: thir_pat,
|
||||
borrow: ByRef::Yes(
|
||||
Pinnedness::Pinned,
|
||||
if mutable { Mutability::Mut } else { Mutability::Not },
|
||||
),
|
||||
}
|
||||
}
|
||||
};
|
||||
Box::new(Pat { span, ty: adjust.source, kind })
|
||||
});
|
||||
|
|
@ -354,11 +364,22 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
// A ref x pattern is the same node used for x, and as such it has
|
||||
// x's type, which is &T, where we want T (the type being matched).
|
||||
let var_ty = ty;
|
||||
if let hir::ByRef::Yes(_) = mode.0 {
|
||||
if let ty::Ref(_, rty, _) = ty.kind() {
|
||||
ty = *rty;
|
||||
} else {
|
||||
bug!("`ref {}` has wrong type {}", ident, ty);
|
||||
if let hir::ByRef::Yes(pinnedness, _) = mode.0 {
|
||||
match pinnedness {
|
||||
hir::Pinnedness::Pinned
|
||||
if let Some(pty) = ty.pinned_ty()
|
||||
&& let &ty::Ref(_, rty, _) = pty.kind() =>
|
||||
{
|
||||
debug_assert!(
|
||||
self.tcx.features().pin_ergonomics(),
|
||||
"`pin_ergonomics` must be enabled to have a by-pin-ref binding"
|
||||
);
|
||||
ty = rty;
|
||||
}
|
||||
hir::Pinnedness::Not if let &ty::Ref(_, rty, _) = ty.kind() => {
|
||||
ty = rty;
|
||||
}
|
||||
_ => bug!("`ref {}` has wrong type {}", ident, ty),
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -36,8 +36,8 @@ use rustc_ast::tokenstream::{
|
|||
use rustc_ast::util::case::Case;
|
||||
use rustc_ast::{
|
||||
self as ast, AnonConst, AttrArgs, AttrId, ByRef, Const, CoroutineKind, DUMMY_NODE_ID,
|
||||
DelimArgs, Expr, ExprKind, Extern, HasAttrs, HasTokens, Mutability, Recovered, Safety, StrLit,
|
||||
Visibility, VisibilityKind,
|
||||
DelimArgs, Expr, ExprKind, Extern, HasAttrs, HasTokens, Mutability, Pinnedness, Recovered,
|
||||
Safety, StrLit, Visibility, VisibilityKind,
|
||||
};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
|
|
@ -1317,7 +1317,12 @@ impl<'a> Parser<'a> {
|
|||
|
||||
/// Parses reference binding mode (`ref`, `ref mut`, or nothing).
|
||||
fn parse_byref(&mut self) -> ByRef {
|
||||
if self.eat_keyword(exp!(Ref)) { ByRef::Yes(self.parse_mutability()) } else { ByRef::No }
|
||||
if self.eat_keyword(exp!(Ref)) {
|
||||
// FIXME(pin_ergonomics): support `ref pin const|mut` bindings
|
||||
ByRef::Yes(Pinnedness::Not, self.parse_mutability())
|
||||
} else {
|
||||
ByRef::No
|
||||
}
|
||||
}
|
||||
|
||||
/// Possibly parses mutability (`const` or `mut`).
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@ use rustc_ast::util::parser::ExprPrecedence;
|
|||
use rustc_ast::visit::{self, Visitor};
|
||||
use rustc_ast::{
|
||||
self as ast, Arm, AttrVec, BindingMode, ByRef, Expr, ExprKind, LocalKind, MacCall, Mutability,
|
||||
Pat, PatField, PatFieldsRest, PatKind, Path, QSelf, RangeEnd, RangeSyntax, Stmt, StmtKind,
|
||||
Pat, PatField, PatFieldsRest, PatKind, Path, Pinnedness, QSelf, RangeEnd, RangeSyntax, Stmt,
|
||||
StmtKind,
|
||||
};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_errors::{Applicability, Diag, DiagArgValue, PResult, StashKey};
|
||||
|
|
@ -778,7 +779,11 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
// Parse ref ident @ pat / ref mut ident @ pat
|
||||
let mutbl = self.parse_mutability();
|
||||
self.parse_pat_ident(BindingMode(ByRef::Yes(mutbl), Mutability::Not), syntax_loc)?
|
||||
self.parse_pat_ident(
|
||||
// FIXME(pin_ergonomics): support `ref pin const|mut` bindings
|
||||
BindingMode(ByRef::Yes(Pinnedness::Not, mutbl), Mutability::Not),
|
||||
syntax_loc,
|
||||
)?
|
||||
} else if self.eat_keyword(exp!(Box)) {
|
||||
self.parse_pat_box()?
|
||||
} else if self.check_inline_const(0) {
|
||||
|
|
@ -1093,7 +1098,7 @@ impl<'a> Parser<'a> {
|
|||
self.ban_mut_general_pat(mut_span, &pat, changed_any_binding);
|
||||
}
|
||||
|
||||
if matches!(pat.kind, PatKind::Ident(BindingMode(ByRef::Yes(_), Mutability::Mut), ..)) {
|
||||
if matches!(pat.kind, PatKind::Ident(BindingMode(ByRef::Yes(..), Mutability::Mut), ..)) {
|
||||
self.psess.gated_spans.gate(sym::mut_ref, pat.span);
|
||||
}
|
||||
Ok(pat.kind)
|
||||
|
|
|
|||
|
|
@ -981,7 +981,7 @@ pub enum ConstructorSet<Cx: PatCx> {
|
|||
/// This type has the following list of constructors. If `variants` is empty and
|
||||
/// `non_exhaustive` is false, don't use this; use `NoConstructors` instead.
|
||||
Variants { variants: IndexVec<Cx::VariantIdx, VariantVisibility>, non_exhaustive: bool },
|
||||
/// The type is `&T`.
|
||||
/// The type is `&T`
|
||||
Ref,
|
||||
/// The type is a union.
|
||||
Union,
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ fn find_slice_values(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> FxIndexMap<Hir
|
|||
// We'll just ignore mut and ref mut for simplicity sake right now
|
||||
if let hir::PatKind::Binding(hir::BindingMode(by_ref, hir::Mutability::Not), value_hir_id, ident, sub_pat) =
|
||||
pat.kind
|
||||
&& by_ref != hir::ByRef::Yes(hir::Mutability::Mut)
|
||||
&& !matches!(by_ref, hir::ByRef::Yes(_, hir::Mutability::Mut))
|
||||
{
|
||||
// This block catches bindings with sub patterns. It would be hard to build a correct suggestion
|
||||
// for them and it's likely that the user knows what they are doing in such a case.
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option<Mutability> {
|
|||
.qpath_res(qpath, arm.pat.hir_id)
|
||||
.ctor_parent(cx)
|
||||
.is_lang_item(cx, LangItem::OptionSome)
|
||||
&& let PatKind::Binding(BindingMode(ByRef::Yes(mutabl), _), .., ident, _) = first_pat.kind
|
||||
&& let PatKind::Binding(BindingMode(ByRef::Yes(_, mutabl), _), .., ident, _) = first_pat.kind
|
||||
&& let ExprKind::Call(e, [arg]) = peel_blocks(arm.body).kind
|
||||
&& e.res(cx).ctor_parent(cx).is_lang_item(cx, LangItem::OptionSome)
|
||||
&& let ExprKind::Path(QPath::Resolved(_, path2)) = arg.kind
|
||||
|
|
|
|||
|
|
@ -172,7 +172,7 @@ fn pat_same_as_expr(pat: &Pat<'_>, expr: &Expr<'_>) -> bool {
|
|||
},
|
||||
)),
|
||||
) => {
|
||||
return !matches!(annot, BindingMode(ByRef::Yes(_), _)) && pat_ident.name == first_seg.ident.name;
|
||||
return !matches!(annot, BindingMode(ByRef::Yes(..), _)) && pat_ident.name == first_seg.ident.name;
|
||||
},
|
||||
// Example: `Custom::TypeA => Custom::TypeB`, or `None => None`
|
||||
(
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ fn get_pat_binding<'tcx>(
|
|||
if let PatKind::Binding(bind_annot, hir_id, ident, _) = pat.kind
|
||||
&& hir_id == local
|
||||
{
|
||||
if matches!(bind_annot.0, rustc_ast::ByRef::Yes(_)) {
|
||||
if matches!(bind_annot.0, rustc_ast::ByRef::Yes(..)) {
|
||||
let _ = byref_ident.insert(ident);
|
||||
}
|
||||
// the second call of `replace()` returns a `Some(span)`, meaning a multi-binding pattern
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>)
|
|||
_ => false,
|
||||
},
|
||||
// local binding capturing a reference
|
||||
Node::LetStmt(l) if matches!(l.pat.kind, PatKind::Binding(BindingMode(ByRef::Yes(_), _), ..)) => {
|
||||
Node::LetStmt(l) if matches!(l.pat.kind, PatKind::Binding(BindingMode(ByRef::Yes(..), _), ..)) => {
|
||||
return;
|
||||
},
|
||||
_ => false,
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ fn check_let_some_else_return_none(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
|
|||
let init_expr_str = Sugg::hir_with_applicability(cx, init_expr, "..", &mut applicability).maybe_paren();
|
||||
// Take care when binding is `ref`
|
||||
let sugg = if let PatKind::Binding(
|
||||
BindingMode(ByRef::Yes(ref_mutability), binding_mutability),
|
||||
BindingMode(ByRef::Yes(_,ref_mutability), binding_mutability),
|
||||
_hir_id,
|
||||
ident,
|
||||
subpattern,
|
||||
|
|
@ -169,7 +169,7 @@ fn check_let_some_else_return_none(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
|
|||
// Handle subpattern (@ subpattern)
|
||||
let maybe_subpattern = match subpattern {
|
||||
Some(Pat {
|
||||
kind: PatKind::Binding(BindingMode(ByRef::Yes(_), _), _, subident, None),
|
||||
kind: PatKind::Binding(BindingMode(ByRef::Yes(..), _), _, subident, None),
|
||||
..
|
||||
}) => {
|
||||
// avoid `&ref`
|
||||
|
|
@ -504,8 +504,8 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr:
|
|||
let receiver_str = snippet_with_applicability(cx, let_expr.span, "..", &mut applicability);
|
||||
let requires_semi = matches!(cx.tcx.parent_hir_node(expr.hir_id), Node::Stmt(_));
|
||||
let method_call_str = match by_ref {
|
||||
ByRef::Yes(Mutability::Mut) => ".as_mut()",
|
||||
ByRef::Yes(Mutability::Not) => ".as_ref()",
|
||||
ByRef::Yes(_, Mutability::Mut) => ".as_mut()",
|
||||
ByRef::Yes(_, Mutability::Not) => ".as_ref()",
|
||||
ByRef::No => "",
|
||||
};
|
||||
let sugg = format!(
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ impl<'tcx> LateLintPass<'tcx> for ToplevelRefArg {
|
|||
) {
|
||||
if !matches!(k, FnKind::Closure) {
|
||||
for arg in iter_input_pats(decl, body) {
|
||||
if let PatKind::Binding(BindingMode(ByRef::Yes(_), _), ..) = arg.pat.kind
|
||||
if let PatKind::Binding(BindingMode(ByRef::Yes(..), _), ..) = arg.pat.kind
|
||||
&& is_lint_allowed(cx, REF_PATTERNS, arg.pat.hir_id)
|
||||
&& !arg.span.in_external_macro(cx.tcx.sess.source_map())
|
||||
{
|
||||
|
|
@ -80,7 +80,7 @@ impl<'tcx> LateLintPass<'tcx> for ToplevelRefArg {
|
|||
|
||||
fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
|
||||
if let StmtKind::Let(local) = stmt.kind
|
||||
&& let PatKind::Binding(BindingMode(ByRef::Yes(mutabl), _), .., name, None) = local.pat.kind
|
||||
&& let PatKind::Binding(BindingMode(ByRef::Yes(_, mutabl), _), .., name, None) = local.pat.kind
|
||||
&& let Some(init) = local.init
|
||||
// Do not emit if clippy::ref_patterns is not allowed to avoid having two lints for the same issue.
|
||||
&& is_lint_allowed(cx, REF_PATTERNS, local.pat.hir_id)
|
||||
|
|
|
|||
|
|
@ -745,10 +745,14 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
|
|||
let ann = match ann {
|
||||
BindingMode::NONE => "NONE",
|
||||
BindingMode::REF => "REF",
|
||||
BindingMode::REF_PIN => "REF_PIN",
|
||||
BindingMode::MUT => "MUT",
|
||||
BindingMode::REF_MUT => "REF_MUT",
|
||||
BindingMode::REF_PIN_MUT => "REF_PIN_MUT",
|
||||
BindingMode::MUT_REF => "MUT_REF",
|
||||
BindingMode::MUT_REF_PIN => "MUT_REF_PIN",
|
||||
BindingMode::MUT_REF_MUT => "MUT_REF_MUT",
|
||||
BindingMode::MUT_REF_PIN_MUT => "MUT_REF_PIN_MUT",
|
||||
};
|
||||
kind!("Binding(BindingMode::{ann}, _, {name}, {sub})");
|
||||
self.ident(name);
|
||||
|
|
|
|||
|
|
@ -212,7 +212,12 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
|
|||
|
||||
// Custom `Deref` impl might have side effects
|
||||
ExprKind::Unary(UnOp::Deref, e)
|
||||
if self.cx.typeck_results().expr_ty(e).builtin_deref(true).is_none() =>
|
||||
if self
|
||||
.cx
|
||||
.typeck_results()
|
||||
.expr_ty(e)
|
||||
.builtin_deref(true)
|
||||
.is_none() =>
|
||||
{
|
||||
self.eagerness |= NoChange;
|
||||
},
|
||||
|
|
|
|||
|
|
@ -783,7 +783,7 @@ pub fn capture_local_usage(cx: &LateContext<'_>, e: &Expr<'_>) -> CaptureKind {
|
|||
ByRef::No if !is_copy(cx, cx.typeck_results().node_type(id)) => {
|
||||
capture = CaptureKind::Value;
|
||||
},
|
||||
ByRef::Yes(Mutability::Mut) if capture != CaptureKind::Value => {
|
||||
ByRef::Yes(_, Mutability::Mut) if capture != CaptureKind::Value => {
|
||||
capture = CaptureKind::Ref(Mutability::Mut);
|
||||
},
|
||||
_ => (),
|
||||
|
|
@ -1831,7 +1831,7 @@ pub fn is_expr_identity_of_pat(cx: &LateContext<'_>, pat: &Pat<'_>, expr: &Expr<
|
|||
.typeck_results()
|
||||
.pat_binding_modes()
|
||||
.get(pat.hir_id)
|
||||
.is_some_and(|mode| matches!(mode.0, ByRef::Yes(_)))
|
||||
.is_some_and(|mode| matches!(mode.0, ByRef::Yes(..)))
|
||||
{
|
||||
// If the parameter is `(x, y)` of type `&(T, T)`, or `[x, y]` of type `&[T; 2]`, then
|
||||
// due to match ergonomics, the inner patterns become references. Don't consider this
|
||||
|
|
|
|||
|
|
@ -134,7 +134,8 @@ impl Rewrite for Pat {
|
|||
let mut_prefix = format_mutability(mutability).trim();
|
||||
|
||||
let (ref_kw, mut_infix) = match by_ref {
|
||||
ByRef::Yes(rmutbl) => ("ref", format_mutability(rmutbl).trim()),
|
||||
// FIXME(pin_ergonomics): format the pinnedness
|
||||
ByRef::Yes(_, rmutbl) => ("ref", format_mutability(rmutbl).trim()),
|
||||
ByRef::No => ("", ""),
|
||||
};
|
||||
let id_str = rewrite_ident(context, ident);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
// MIR for `bar_const` after built
|
||||
|
||||
fn bar_const(_1: Pin<&Bar<T, U>>) -> () {
|
||||
debug bar => _1;
|
||||
let mut _0: ();
|
||||
let _2: std::pin::Pin<&T>;
|
||||
let _3: std::pin::Pin<&U>;
|
||||
let mut _4: &T;
|
||||
let mut _5: &U;
|
||||
scope 1 {
|
||||
debug x => _2;
|
||||
debug y => _3;
|
||||
}
|
||||
|
||||
bb0: {
|
||||
PlaceMention(_1);
|
||||
StorageLive(_2);
|
||||
_4 = &((*(_1.0: &Bar<T, U>)).0: T);
|
||||
_2 = Pin::<&T> { pointer: move _4 };
|
||||
StorageLive(_3);
|
||||
_5 = &((*(_1.0: &Bar<T, U>)).1: U);
|
||||
_3 = Pin::<&U> { pointer: move _5 };
|
||||
_0 = const ();
|
||||
StorageDead(_3);
|
||||
StorageDead(_2);
|
||||
return;
|
||||
}
|
||||
|
||||
bb1: {
|
||||
FakeRead(ForMatchedPlace(None), _1);
|
||||
unreachable;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
// MIR for `bar_mut` after built
|
||||
|
||||
fn bar_mut(_1: Pin<&mut Bar<T, U>>) -> () {
|
||||
debug bar => _1;
|
||||
let mut _0: ();
|
||||
let _2: std::pin::Pin<&mut T>;
|
||||
let _3: std::pin::Pin<&mut U>;
|
||||
let mut _4: &mut T;
|
||||
let mut _5: &mut U;
|
||||
scope 1 {
|
||||
debug x => _2;
|
||||
debug y => _3;
|
||||
}
|
||||
|
||||
bb0: {
|
||||
PlaceMention(_1);
|
||||
StorageLive(_2);
|
||||
_4 = &mut ((*(_1.0: &mut Bar<T, U>)).0: T);
|
||||
_2 = Pin::<&mut T> { pointer: move _4 };
|
||||
StorageLive(_3);
|
||||
_5 = &mut ((*(_1.0: &mut Bar<T, U>)).1: U);
|
||||
_3 = Pin::<&mut U> { pointer: move _5 };
|
||||
_0 = const ();
|
||||
StorageDead(_3);
|
||||
StorageDead(_2);
|
||||
return;
|
||||
}
|
||||
|
||||
bb1: {
|
||||
FakeRead(ForMatchedPlace(None), _1);
|
||||
unreachable;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,422 @@
|
|||
// MIR for `baz_baz_const` after built
|
||||
|
||||
fn baz_baz_const(_1: Pin<&Baz<Baz<T, U>, Baz<T, U>>>) -> () {
|
||||
debug baz => _1;
|
||||
let mut _0: ();
|
||||
let mut _2: isize;
|
||||
let mut _3: isize;
|
||||
let mut _4: isize;
|
||||
let mut _5: isize;
|
||||
let mut _6: isize;
|
||||
let mut _7: isize;
|
||||
let mut _8: isize;
|
||||
let _9: std::pin::Pin<&T>;
|
||||
let _10: std::pin::Pin<&U>;
|
||||
let _11: std::pin::Pin<&T>;
|
||||
let _12: std::pin::Pin<&U>;
|
||||
let mut _13: &T;
|
||||
let mut _14: &U;
|
||||
let mut _15: &T;
|
||||
let mut _16: &U;
|
||||
let _17: std::pin::Pin<&T>;
|
||||
let _18: std::pin::Pin<&U>;
|
||||
let _19: std::pin::Pin<&T>;
|
||||
let _20: std::pin::Pin<&U>;
|
||||
let mut _21: &T;
|
||||
let mut _22: &U;
|
||||
let mut _23: &T;
|
||||
let mut _24: &U;
|
||||
let _25: std::pin::Pin<&T>;
|
||||
let _26: std::pin::Pin<&U>;
|
||||
let _27: std::pin::Pin<&T>;
|
||||
let _28: std::pin::Pin<&U>;
|
||||
let mut _29: &T;
|
||||
let mut _30: &U;
|
||||
let mut _31: &T;
|
||||
let mut _32: &U;
|
||||
let _33: std::pin::Pin<&T>;
|
||||
let _34: std::pin::Pin<&U>;
|
||||
let _35: std::pin::Pin<&T>;
|
||||
let _36: std::pin::Pin<&U>;
|
||||
let mut _37: &T;
|
||||
let mut _38: &U;
|
||||
let mut _39: &T;
|
||||
let mut _40: &U;
|
||||
let _41: std::pin::Pin<&T>;
|
||||
let _42: std::pin::Pin<&U>;
|
||||
let _43: std::pin::Pin<&T>;
|
||||
let _44: std::pin::Pin<&U>;
|
||||
let mut _45: &T;
|
||||
let mut _46: &U;
|
||||
let mut _47: &T;
|
||||
let mut _48: &U;
|
||||
let _49: std::pin::Pin<&T>;
|
||||
let _50: std::pin::Pin<&U>;
|
||||
let _51: std::pin::Pin<&T>;
|
||||
let _52: std::pin::Pin<&U>;
|
||||
let mut _53: &T;
|
||||
let mut _54: &U;
|
||||
let mut _55: &T;
|
||||
let mut _56: &U;
|
||||
let _57: std::pin::Pin<&T>;
|
||||
let _58: std::pin::Pin<&U>;
|
||||
let _59: std::pin::Pin<&T>;
|
||||
let _60: std::pin::Pin<&U>;
|
||||
let mut _61: &T;
|
||||
let mut _62: &U;
|
||||
let mut _63: &T;
|
||||
let mut _64: &U;
|
||||
let _65: std::pin::Pin<&T>;
|
||||
let _66: std::pin::Pin<&U>;
|
||||
let _67: std::pin::Pin<&T>;
|
||||
let _68: std::pin::Pin<&U>;
|
||||
let mut _69: &T;
|
||||
let mut _70: &U;
|
||||
let mut _71: &T;
|
||||
let mut _72: &U;
|
||||
scope 1 {
|
||||
debug x => _9;
|
||||
debug y => _10;
|
||||
debug z => _11;
|
||||
debug w => _12;
|
||||
}
|
||||
scope 2 {
|
||||
debug x => _17;
|
||||
debug y => _18;
|
||||
debug z => _19;
|
||||
debug w => _20;
|
||||
}
|
||||
scope 3 {
|
||||
debug x => _25;
|
||||
debug y => _26;
|
||||
debug z => _27;
|
||||
debug w => _28;
|
||||
}
|
||||
scope 4 {
|
||||
debug x => _33;
|
||||
debug y => _34;
|
||||
debug z => _35;
|
||||
debug w => _36;
|
||||
}
|
||||
scope 5 {
|
||||
debug x => _41;
|
||||
debug y => _42;
|
||||
debug z => _43;
|
||||
debug w => _44;
|
||||
}
|
||||
scope 6 {
|
||||
debug x => _49;
|
||||
debug y => _50;
|
||||
debug z => _51;
|
||||
debug w => _52;
|
||||
}
|
||||
scope 7 {
|
||||
debug x => _57;
|
||||
debug y => _58;
|
||||
debug z => _59;
|
||||
debug w => _60;
|
||||
}
|
||||
scope 8 {
|
||||
debug x => _65;
|
||||
debug y => _66;
|
||||
debug z => _67;
|
||||
debug w => _68;
|
||||
}
|
||||
|
||||
bb0: {
|
||||
PlaceMention(_1);
|
||||
_8 = discriminant((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)));
|
||||
switchInt(move _8) -> [0: bb2, 1: bb16, otherwise: bb1];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
FakeRead(ForMatchedPlace(None), _1);
|
||||
unreachable;
|
||||
}
|
||||
|
||||
bb2: {
|
||||
_4 = discriminant((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Foo).0: Baz<T, U>));
|
||||
switchInt(move _4) -> [0: bb4, 1: bb10, otherwise: bb3];
|
||||
}
|
||||
|
||||
bb3: {
|
||||
goto -> bb1;
|
||||
}
|
||||
|
||||
bb4: {
|
||||
_2 = discriminant((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Foo).1: Baz<T, U>));
|
||||
switchInt(move _2) -> [0: bb6, 1: bb8, otherwise: bb5];
|
||||
}
|
||||
|
||||
bb5: {
|
||||
goto -> bb3;
|
||||
}
|
||||
|
||||
bb6: {
|
||||
falseEdge -> [real: bb36, imaginary: bb8];
|
||||
}
|
||||
|
||||
bb7: {
|
||||
goto -> bb5;
|
||||
}
|
||||
|
||||
bb8: {
|
||||
falseEdge -> [real: bb35, imaginary: bb10];
|
||||
}
|
||||
|
||||
bb9: {
|
||||
goto -> bb5;
|
||||
}
|
||||
|
||||
bb10: {
|
||||
_3 = discriminant((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Foo).1: Baz<T, U>));
|
||||
switchInt(move _3) -> [0: bb12, 1: bb14, otherwise: bb11];
|
||||
}
|
||||
|
||||
bb11: {
|
||||
goto -> bb3;
|
||||
}
|
||||
|
||||
bb12: {
|
||||
falseEdge -> [real: bb34, imaginary: bb14];
|
||||
}
|
||||
|
||||
bb13: {
|
||||
goto -> bb11;
|
||||
}
|
||||
|
||||
bb14: {
|
||||
falseEdge -> [real: bb33, imaginary: bb16];
|
||||
}
|
||||
|
||||
bb15: {
|
||||
goto -> bb11;
|
||||
}
|
||||
|
||||
bb16: {
|
||||
_7 = discriminant((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Bar).0: Baz<T, U>));
|
||||
switchInt(move _7) -> [0: bb18, 1: bb24, otherwise: bb17];
|
||||
}
|
||||
|
||||
bb17: {
|
||||
goto -> bb1;
|
||||
}
|
||||
|
||||
bb18: {
|
||||
_5 = discriminant((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Bar).1: Baz<T, U>));
|
||||
switchInt(move _5) -> [0: bb20, 1: bb22, otherwise: bb19];
|
||||
}
|
||||
|
||||
bb19: {
|
||||
goto -> bb17;
|
||||
}
|
||||
|
||||
bb20: {
|
||||
falseEdge -> [real: bb32, imaginary: bb22];
|
||||
}
|
||||
|
||||
bb21: {
|
||||
goto -> bb19;
|
||||
}
|
||||
|
||||
bb22: {
|
||||
falseEdge -> [real: bb31, imaginary: bb24];
|
||||
}
|
||||
|
||||
bb23: {
|
||||
goto -> bb19;
|
||||
}
|
||||
|
||||
bb24: {
|
||||
_6 = discriminant((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Bar).1: Baz<T, U>));
|
||||
switchInt(move _6) -> [0: bb26, 1: bb28, otherwise: bb25];
|
||||
}
|
||||
|
||||
bb25: {
|
||||
goto -> bb17;
|
||||
}
|
||||
|
||||
bb26: {
|
||||
falseEdge -> [real: bb30, imaginary: bb28];
|
||||
}
|
||||
|
||||
bb27: {
|
||||
goto -> bb25;
|
||||
}
|
||||
|
||||
bb28: {
|
||||
StorageLive(_65);
|
||||
_69 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Bar).0: Baz<T, U>) as Bar).0: T);
|
||||
_65 = Pin::<&T> { pointer: move _69 };
|
||||
StorageLive(_66);
|
||||
_70 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Bar).0: Baz<T, U>) as Bar).1: U);
|
||||
_66 = Pin::<&U> { pointer: move _70 };
|
||||
StorageLive(_67);
|
||||
_71 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Bar).1: Baz<T, U>) as Bar).0: T);
|
||||
_67 = Pin::<&T> { pointer: move _71 };
|
||||
StorageLive(_68);
|
||||
_72 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Bar).1: Baz<T, U>) as Bar).1: U);
|
||||
_68 = Pin::<&U> { pointer: move _72 };
|
||||
_0 = const ();
|
||||
StorageDead(_68);
|
||||
StorageDead(_67);
|
||||
StorageDead(_66);
|
||||
StorageDead(_65);
|
||||
goto -> bb37;
|
||||
}
|
||||
|
||||
bb29: {
|
||||
goto -> bb25;
|
||||
}
|
||||
|
||||
bb30: {
|
||||
StorageLive(_57);
|
||||
_61 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Bar).0: Baz<T, U>) as Bar).0: T);
|
||||
_57 = Pin::<&T> { pointer: move _61 };
|
||||
StorageLive(_58);
|
||||
_62 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Bar).0: Baz<T, U>) as Bar).1: U);
|
||||
_58 = Pin::<&U> { pointer: move _62 };
|
||||
StorageLive(_59);
|
||||
_63 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Bar).1: Baz<T, U>) as Foo).0: T);
|
||||
_59 = Pin::<&T> { pointer: move _63 };
|
||||
StorageLive(_60);
|
||||
_64 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Bar).1: Baz<T, U>) as Foo).1: U);
|
||||
_60 = Pin::<&U> { pointer: move _64 };
|
||||
_0 = const ();
|
||||
StorageDead(_60);
|
||||
StorageDead(_59);
|
||||
StorageDead(_58);
|
||||
StorageDead(_57);
|
||||
goto -> bb37;
|
||||
}
|
||||
|
||||
bb31: {
|
||||
StorageLive(_49);
|
||||
_53 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Bar).0: Baz<T, U>) as Foo).0: T);
|
||||
_49 = Pin::<&T> { pointer: move _53 };
|
||||
StorageLive(_50);
|
||||
_54 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Bar).0: Baz<T, U>) as Foo).1: U);
|
||||
_50 = Pin::<&U> { pointer: move _54 };
|
||||
StorageLive(_51);
|
||||
_55 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Bar).1: Baz<T, U>) as Bar).0: T);
|
||||
_51 = Pin::<&T> { pointer: move _55 };
|
||||
StorageLive(_52);
|
||||
_56 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Bar).1: Baz<T, U>) as Bar).1: U);
|
||||
_52 = Pin::<&U> { pointer: move _56 };
|
||||
_0 = const ();
|
||||
StorageDead(_52);
|
||||
StorageDead(_51);
|
||||
StorageDead(_50);
|
||||
StorageDead(_49);
|
||||
goto -> bb37;
|
||||
}
|
||||
|
||||
bb32: {
|
||||
StorageLive(_41);
|
||||
_45 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Bar).0: Baz<T, U>) as Foo).0: T);
|
||||
_41 = Pin::<&T> { pointer: move _45 };
|
||||
StorageLive(_42);
|
||||
_46 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Bar).0: Baz<T, U>) as Foo).1: U);
|
||||
_42 = Pin::<&U> { pointer: move _46 };
|
||||
StorageLive(_43);
|
||||
_47 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Bar).1: Baz<T, U>) as Foo).0: T);
|
||||
_43 = Pin::<&T> { pointer: move _47 };
|
||||
StorageLive(_44);
|
||||
_48 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Bar).1: Baz<T, U>) as Foo).1: U);
|
||||
_44 = Pin::<&U> { pointer: move _48 };
|
||||
_0 = const ();
|
||||
StorageDead(_44);
|
||||
StorageDead(_43);
|
||||
StorageDead(_42);
|
||||
StorageDead(_41);
|
||||
goto -> bb37;
|
||||
}
|
||||
|
||||
bb33: {
|
||||
StorageLive(_33);
|
||||
_37 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Foo).0: Baz<T, U>) as Bar).0: T);
|
||||
_33 = Pin::<&T> { pointer: move _37 };
|
||||
StorageLive(_34);
|
||||
_38 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Foo).0: Baz<T, U>) as Bar).1: U);
|
||||
_34 = Pin::<&U> { pointer: move _38 };
|
||||
StorageLive(_35);
|
||||
_39 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Foo).1: Baz<T, U>) as Bar).0: T);
|
||||
_35 = Pin::<&T> { pointer: move _39 };
|
||||
StorageLive(_36);
|
||||
_40 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Foo).1: Baz<T, U>) as Bar).1: U);
|
||||
_36 = Pin::<&U> { pointer: move _40 };
|
||||
_0 = const ();
|
||||
StorageDead(_36);
|
||||
StorageDead(_35);
|
||||
StorageDead(_34);
|
||||
StorageDead(_33);
|
||||
goto -> bb37;
|
||||
}
|
||||
|
||||
bb34: {
|
||||
StorageLive(_25);
|
||||
_29 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Foo).0: Baz<T, U>) as Bar).0: T);
|
||||
_25 = Pin::<&T> { pointer: move _29 };
|
||||
StorageLive(_26);
|
||||
_30 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Foo).0: Baz<T, U>) as Bar).1: U);
|
||||
_26 = Pin::<&U> { pointer: move _30 };
|
||||
StorageLive(_27);
|
||||
_31 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Foo).1: Baz<T, U>) as Foo).0: T);
|
||||
_27 = Pin::<&T> { pointer: move _31 };
|
||||
StorageLive(_28);
|
||||
_32 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Foo).1: Baz<T, U>) as Foo).1: U);
|
||||
_28 = Pin::<&U> { pointer: move _32 };
|
||||
_0 = const ();
|
||||
StorageDead(_28);
|
||||
StorageDead(_27);
|
||||
StorageDead(_26);
|
||||
StorageDead(_25);
|
||||
goto -> bb37;
|
||||
}
|
||||
|
||||
bb35: {
|
||||
StorageLive(_17);
|
||||
_21 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Foo).0: Baz<T, U>) as Foo).0: T);
|
||||
_17 = Pin::<&T> { pointer: move _21 };
|
||||
StorageLive(_18);
|
||||
_22 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Foo).0: Baz<T, U>) as Foo).1: U);
|
||||
_18 = Pin::<&U> { pointer: move _22 };
|
||||
StorageLive(_19);
|
||||
_23 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Foo).1: Baz<T, U>) as Bar).0: T);
|
||||
_19 = Pin::<&T> { pointer: move _23 };
|
||||
StorageLive(_20);
|
||||
_24 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Foo).1: Baz<T, U>) as Bar).1: U);
|
||||
_20 = Pin::<&U> { pointer: move _24 };
|
||||
_0 = const ();
|
||||
StorageDead(_20);
|
||||
StorageDead(_19);
|
||||
StorageDead(_18);
|
||||
StorageDead(_17);
|
||||
goto -> bb37;
|
||||
}
|
||||
|
||||
bb36: {
|
||||
StorageLive(_9);
|
||||
_13 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Foo).0: Baz<T, U>) as Foo).0: T);
|
||||
_9 = Pin::<&T> { pointer: move _13 };
|
||||
StorageLive(_10);
|
||||
_14 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Foo).0: Baz<T, U>) as Foo).1: U);
|
||||
_10 = Pin::<&U> { pointer: move _14 };
|
||||
StorageLive(_11);
|
||||
_15 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Foo).1: Baz<T, U>) as Foo).0: T);
|
||||
_11 = Pin::<&T> { pointer: move _15 };
|
||||
StorageLive(_12);
|
||||
_16 = &(((((*(_1.0: &Baz<Baz<T, U>, Baz<T, U>>)) as Foo).1: Baz<T, U>) as Foo).1: U);
|
||||
_12 = Pin::<&U> { pointer: move _16 };
|
||||
_0 = const ();
|
||||
StorageDead(_12);
|
||||
StorageDead(_11);
|
||||
StorageDead(_10);
|
||||
StorageDead(_9);
|
||||
goto -> bb37;
|
||||
}
|
||||
|
||||
bb37: {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,422 @@
|
|||
// MIR for `baz_baz_mut` after built
|
||||
|
||||
fn baz_baz_mut(_1: Pin<&mut Baz<Baz<T, U>, Baz<T, U>>>) -> () {
|
||||
debug baz => _1;
|
||||
let mut _0: ();
|
||||
let mut _2: isize;
|
||||
let mut _3: isize;
|
||||
let mut _4: isize;
|
||||
let mut _5: isize;
|
||||
let mut _6: isize;
|
||||
let mut _7: isize;
|
||||
let mut _8: isize;
|
||||
let _9: std::pin::Pin<&mut T>;
|
||||
let _10: std::pin::Pin<&mut U>;
|
||||
let _11: std::pin::Pin<&mut T>;
|
||||
let _12: std::pin::Pin<&mut U>;
|
||||
let mut _13: &mut T;
|
||||
let mut _14: &mut U;
|
||||
let mut _15: &mut T;
|
||||
let mut _16: &mut U;
|
||||
let _17: std::pin::Pin<&mut T>;
|
||||
let _18: std::pin::Pin<&mut U>;
|
||||
let _19: std::pin::Pin<&mut T>;
|
||||
let _20: std::pin::Pin<&mut U>;
|
||||
let mut _21: &mut T;
|
||||
let mut _22: &mut U;
|
||||
let mut _23: &mut T;
|
||||
let mut _24: &mut U;
|
||||
let _25: std::pin::Pin<&mut T>;
|
||||
let _26: std::pin::Pin<&mut U>;
|
||||
let _27: std::pin::Pin<&mut T>;
|
||||
let _28: std::pin::Pin<&mut U>;
|
||||
let mut _29: &mut T;
|
||||
let mut _30: &mut U;
|
||||
let mut _31: &mut T;
|
||||
let mut _32: &mut U;
|
||||
let _33: std::pin::Pin<&mut T>;
|
||||
let _34: std::pin::Pin<&mut U>;
|
||||
let _35: std::pin::Pin<&mut T>;
|
||||
let _36: std::pin::Pin<&mut U>;
|
||||
let mut _37: &mut T;
|
||||
let mut _38: &mut U;
|
||||
let mut _39: &mut T;
|
||||
let mut _40: &mut U;
|
||||
let _41: std::pin::Pin<&mut T>;
|
||||
let _42: std::pin::Pin<&mut U>;
|
||||
let _43: std::pin::Pin<&mut T>;
|
||||
let _44: std::pin::Pin<&mut U>;
|
||||
let mut _45: &mut T;
|
||||
let mut _46: &mut U;
|
||||
let mut _47: &mut T;
|
||||
let mut _48: &mut U;
|
||||
let _49: std::pin::Pin<&mut T>;
|
||||
let _50: std::pin::Pin<&mut U>;
|
||||
let _51: std::pin::Pin<&mut T>;
|
||||
let _52: std::pin::Pin<&mut U>;
|
||||
let mut _53: &mut T;
|
||||
let mut _54: &mut U;
|
||||
let mut _55: &mut T;
|
||||
let mut _56: &mut U;
|
||||
let _57: std::pin::Pin<&mut T>;
|
||||
let _58: std::pin::Pin<&mut U>;
|
||||
let _59: std::pin::Pin<&mut T>;
|
||||
let _60: std::pin::Pin<&mut U>;
|
||||
let mut _61: &mut T;
|
||||
let mut _62: &mut U;
|
||||
let mut _63: &mut T;
|
||||
let mut _64: &mut U;
|
||||
let _65: std::pin::Pin<&mut T>;
|
||||
let _66: std::pin::Pin<&mut U>;
|
||||
let _67: std::pin::Pin<&mut T>;
|
||||
let _68: std::pin::Pin<&mut U>;
|
||||
let mut _69: &mut T;
|
||||
let mut _70: &mut U;
|
||||
let mut _71: &mut T;
|
||||
let mut _72: &mut U;
|
||||
scope 1 {
|
||||
debug x => _9;
|
||||
debug y => _10;
|
||||
debug z => _11;
|
||||
debug w => _12;
|
||||
}
|
||||
scope 2 {
|
||||
debug x => _17;
|
||||
debug y => _18;
|
||||
debug z => _19;
|
||||
debug w => _20;
|
||||
}
|
||||
scope 3 {
|
||||
debug x => _25;
|
||||
debug y => _26;
|
||||
debug z => _27;
|
||||
debug w => _28;
|
||||
}
|
||||
scope 4 {
|
||||
debug x => _33;
|
||||
debug y => _34;
|
||||
debug z => _35;
|
||||
debug w => _36;
|
||||
}
|
||||
scope 5 {
|
||||
debug x => _41;
|
||||
debug y => _42;
|
||||
debug z => _43;
|
||||
debug w => _44;
|
||||
}
|
||||
scope 6 {
|
||||
debug x => _49;
|
||||
debug y => _50;
|
||||
debug z => _51;
|
||||
debug w => _52;
|
||||
}
|
||||
scope 7 {
|
||||
debug x => _57;
|
||||
debug y => _58;
|
||||
debug z => _59;
|
||||
debug w => _60;
|
||||
}
|
||||
scope 8 {
|
||||
debug x => _65;
|
||||
debug y => _66;
|
||||
debug z => _67;
|
||||
debug w => _68;
|
||||
}
|
||||
|
||||
bb0: {
|
||||
PlaceMention(_1);
|
||||
_8 = discriminant((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)));
|
||||
switchInt(move _8) -> [0: bb2, 1: bb16, otherwise: bb1];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
FakeRead(ForMatchedPlace(None), _1);
|
||||
unreachable;
|
||||
}
|
||||
|
||||
bb2: {
|
||||
_4 = discriminant((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Foo).0: Baz<T, U>));
|
||||
switchInt(move _4) -> [0: bb4, 1: bb10, otherwise: bb3];
|
||||
}
|
||||
|
||||
bb3: {
|
||||
goto -> bb1;
|
||||
}
|
||||
|
||||
bb4: {
|
||||
_2 = discriminant((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Foo).1: Baz<T, U>));
|
||||
switchInt(move _2) -> [0: bb6, 1: bb8, otherwise: bb5];
|
||||
}
|
||||
|
||||
bb5: {
|
||||
goto -> bb3;
|
||||
}
|
||||
|
||||
bb6: {
|
||||
falseEdge -> [real: bb36, imaginary: bb8];
|
||||
}
|
||||
|
||||
bb7: {
|
||||
goto -> bb5;
|
||||
}
|
||||
|
||||
bb8: {
|
||||
falseEdge -> [real: bb35, imaginary: bb10];
|
||||
}
|
||||
|
||||
bb9: {
|
||||
goto -> bb5;
|
||||
}
|
||||
|
||||
bb10: {
|
||||
_3 = discriminant((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Foo).1: Baz<T, U>));
|
||||
switchInt(move _3) -> [0: bb12, 1: bb14, otherwise: bb11];
|
||||
}
|
||||
|
||||
bb11: {
|
||||
goto -> bb3;
|
||||
}
|
||||
|
||||
bb12: {
|
||||
falseEdge -> [real: bb34, imaginary: bb14];
|
||||
}
|
||||
|
||||
bb13: {
|
||||
goto -> bb11;
|
||||
}
|
||||
|
||||
bb14: {
|
||||
falseEdge -> [real: bb33, imaginary: bb16];
|
||||
}
|
||||
|
||||
bb15: {
|
||||
goto -> bb11;
|
||||
}
|
||||
|
||||
bb16: {
|
||||
_7 = discriminant((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Bar).0: Baz<T, U>));
|
||||
switchInt(move _7) -> [0: bb18, 1: bb24, otherwise: bb17];
|
||||
}
|
||||
|
||||
bb17: {
|
||||
goto -> bb1;
|
||||
}
|
||||
|
||||
bb18: {
|
||||
_5 = discriminant((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Bar).1: Baz<T, U>));
|
||||
switchInt(move _5) -> [0: bb20, 1: bb22, otherwise: bb19];
|
||||
}
|
||||
|
||||
bb19: {
|
||||
goto -> bb17;
|
||||
}
|
||||
|
||||
bb20: {
|
||||
falseEdge -> [real: bb32, imaginary: bb22];
|
||||
}
|
||||
|
||||
bb21: {
|
||||
goto -> bb19;
|
||||
}
|
||||
|
||||
bb22: {
|
||||
falseEdge -> [real: bb31, imaginary: bb24];
|
||||
}
|
||||
|
||||
bb23: {
|
||||
goto -> bb19;
|
||||
}
|
||||
|
||||
bb24: {
|
||||
_6 = discriminant((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Bar).1: Baz<T, U>));
|
||||
switchInt(move _6) -> [0: bb26, 1: bb28, otherwise: bb25];
|
||||
}
|
||||
|
||||
bb25: {
|
||||
goto -> bb17;
|
||||
}
|
||||
|
||||
bb26: {
|
||||
falseEdge -> [real: bb30, imaginary: bb28];
|
||||
}
|
||||
|
||||
bb27: {
|
||||
goto -> bb25;
|
||||
}
|
||||
|
||||
bb28: {
|
||||
StorageLive(_65);
|
||||
_69 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Bar).0: Baz<T, U>) as Bar).0: T);
|
||||
_65 = Pin::<&mut T> { pointer: move _69 };
|
||||
StorageLive(_66);
|
||||
_70 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Bar).0: Baz<T, U>) as Bar).1: U);
|
||||
_66 = Pin::<&mut U> { pointer: move _70 };
|
||||
StorageLive(_67);
|
||||
_71 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Bar).1: Baz<T, U>) as Bar).0: T);
|
||||
_67 = Pin::<&mut T> { pointer: move _71 };
|
||||
StorageLive(_68);
|
||||
_72 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Bar).1: Baz<T, U>) as Bar).1: U);
|
||||
_68 = Pin::<&mut U> { pointer: move _72 };
|
||||
_0 = const ();
|
||||
StorageDead(_68);
|
||||
StorageDead(_67);
|
||||
StorageDead(_66);
|
||||
StorageDead(_65);
|
||||
goto -> bb37;
|
||||
}
|
||||
|
||||
bb29: {
|
||||
goto -> bb25;
|
||||
}
|
||||
|
||||
bb30: {
|
||||
StorageLive(_57);
|
||||
_61 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Bar).0: Baz<T, U>) as Bar).0: T);
|
||||
_57 = Pin::<&mut T> { pointer: move _61 };
|
||||
StorageLive(_58);
|
||||
_62 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Bar).0: Baz<T, U>) as Bar).1: U);
|
||||
_58 = Pin::<&mut U> { pointer: move _62 };
|
||||
StorageLive(_59);
|
||||
_63 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Bar).1: Baz<T, U>) as Foo).0: T);
|
||||
_59 = Pin::<&mut T> { pointer: move _63 };
|
||||
StorageLive(_60);
|
||||
_64 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Bar).1: Baz<T, U>) as Foo).1: U);
|
||||
_60 = Pin::<&mut U> { pointer: move _64 };
|
||||
_0 = const ();
|
||||
StorageDead(_60);
|
||||
StorageDead(_59);
|
||||
StorageDead(_58);
|
||||
StorageDead(_57);
|
||||
goto -> bb37;
|
||||
}
|
||||
|
||||
bb31: {
|
||||
StorageLive(_49);
|
||||
_53 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Bar).0: Baz<T, U>) as Foo).0: T);
|
||||
_49 = Pin::<&mut T> { pointer: move _53 };
|
||||
StorageLive(_50);
|
||||
_54 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Bar).0: Baz<T, U>) as Foo).1: U);
|
||||
_50 = Pin::<&mut U> { pointer: move _54 };
|
||||
StorageLive(_51);
|
||||
_55 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Bar).1: Baz<T, U>) as Bar).0: T);
|
||||
_51 = Pin::<&mut T> { pointer: move _55 };
|
||||
StorageLive(_52);
|
||||
_56 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Bar).1: Baz<T, U>) as Bar).1: U);
|
||||
_52 = Pin::<&mut U> { pointer: move _56 };
|
||||
_0 = const ();
|
||||
StorageDead(_52);
|
||||
StorageDead(_51);
|
||||
StorageDead(_50);
|
||||
StorageDead(_49);
|
||||
goto -> bb37;
|
||||
}
|
||||
|
||||
bb32: {
|
||||
StorageLive(_41);
|
||||
_45 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Bar).0: Baz<T, U>) as Foo).0: T);
|
||||
_41 = Pin::<&mut T> { pointer: move _45 };
|
||||
StorageLive(_42);
|
||||
_46 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Bar).0: Baz<T, U>) as Foo).1: U);
|
||||
_42 = Pin::<&mut U> { pointer: move _46 };
|
||||
StorageLive(_43);
|
||||
_47 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Bar).1: Baz<T, U>) as Foo).0: T);
|
||||
_43 = Pin::<&mut T> { pointer: move _47 };
|
||||
StorageLive(_44);
|
||||
_48 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Bar).1: Baz<T, U>) as Foo).1: U);
|
||||
_44 = Pin::<&mut U> { pointer: move _48 };
|
||||
_0 = const ();
|
||||
StorageDead(_44);
|
||||
StorageDead(_43);
|
||||
StorageDead(_42);
|
||||
StorageDead(_41);
|
||||
goto -> bb37;
|
||||
}
|
||||
|
||||
bb33: {
|
||||
StorageLive(_33);
|
||||
_37 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Foo).0: Baz<T, U>) as Bar).0: T);
|
||||
_33 = Pin::<&mut T> { pointer: move _37 };
|
||||
StorageLive(_34);
|
||||
_38 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Foo).0: Baz<T, U>) as Bar).1: U);
|
||||
_34 = Pin::<&mut U> { pointer: move _38 };
|
||||
StorageLive(_35);
|
||||
_39 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Foo).1: Baz<T, U>) as Bar).0: T);
|
||||
_35 = Pin::<&mut T> { pointer: move _39 };
|
||||
StorageLive(_36);
|
||||
_40 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Foo).1: Baz<T, U>) as Bar).1: U);
|
||||
_36 = Pin::<&mut U> { pointer: move _40 };
|
||||
_0 = const ();
|
||||
StorageDead(_36);
|
||||
StorageDead(_35);
|
||||
StorageDead(_34);
|
||||
StorageDead(_33);
|
||||
goto -> bb37;
|
||||
}
|
||||
|
||||
bb34: {
|
||||
StorageLive(_25);
|
||||
_29 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Foo).0: Baz<T, U>) as Bar).0: T);
|
||||
_25 = Pin::<&mut T> { pointer: move _29 };
|
||||
StorageLive(_26);
|
||||
_30 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Foo).0: Baz<T, U>) as Bar).1: U);
|
||||
_26 = Pin::<&mut U> { pointer: move _30 };
|
||||
StorageLive(_27);
|
||||
_31 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Foo).1: Baz<T, U>) as Foo).0: T);
|
||||
_27 = Pin::<&mut T> { pointer: move _31 };
|
||||
StorageLive(_28);
|
||||
_32 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Foo).1: Baz<T, U>) as Foo).1: U);
|
||||
_28 = Pin::<&mut U> { pointer: move _32 };
|
||||
_0 = const ();
|
||||
StorageDead(_28);
|
||||
StorageDead(_27);
|
||||
StorageDead(_26);
|
||||
StorageDead(_25);
|
||||
goto -> bb37;
|
||||
}
|
||||
|
||||
bb35: {
|
||||
StorageLive(_17);
|
||||
_21 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Foo).0: Baz<T, U>) as Foo).0: T);
|
||||
_17 = Pin::<&mut T> { pointer: move _21 };
|
||||
StorageLive(_18);
|
||||
_22 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Foo).0: Baz<T, U>) as Foo).1: U);
|
||||
_18 = Pin::<&mut U> { pointer: move _22 };
|
||||
StorageLive(_19);
|
||||
_23 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Foo).1: Baz<T, U>) as Bar).0: T);
|
||||
_19 = Pin::<&mut T> { pointer: move _23 };
|
||||
StorageLive(_20);
|
||||
_24 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Foo).1: Baz<T, U>) as Bar).1: U);
|
||||
_20 = Pin::<&mut U> { pointer: move _24 };
|
||||
_0 = const ();
|
||||
StorageDead(_20);
|
||||
StorageDead(_19);
|
||||
StorageDead(_18);
|
||||
StorageDead(_17);
|
||||
goto -> bb37;
|
||||
}
|
||||
|
||||
bb36: {
|
||||
StorageLive(_9);
|
||||
_13 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Foo).0: Baz<T, U>) as Foo).0: T);
|
||||
_9 = Pin::<&mut T> { pointer: move _13 };
|
||||
StorageLive(_10);
|
||||
_14 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Foo).0: Baz<T, U>) as Foo).1: U);
|
||||
_10 = Pin::<&mut U> { pointer: move _14 };
|
||||
StorageLive(_11);
|
||||
_15 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Foo).1: Baz<T, U>) as Foo).0: T);
|
||||
_11 = Pin::<&mut T> { pointer: move _15 };
|
||||
StorageLive(_12);
|
||||
_16 = &mut (((((*(_1.0: &mut Baz<Baz<T, U>, Baz<T, U>>)) as Foo).1: Baz<T, U>) as Foo).1: U);
|
||||
_12 = Pin::<&mut U> { pointer: move _16 };
|
||||
_0 = const ();
|
||||
StorageDead(_12);
|
||||
StorageDead(_11);
|
||||
StorageDead(_10);
|
||||
StorageDead(_9);
|
||||
goto -> bb37;
|
||||
}
|
||||
|
||||
bb37: {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
// MIR for `baz_const` after built
|
||||
|
||||
fn baz_const(_1: Pin<&Baz<T, U>>) -> () {
|
||||
debug baz => _1;
|
||||
let mut _0: ();
|
||||
let mut _2: isize;
|
||||
let _3: std::pin::Pin<&T>;
|
||||
let _4: std::pin::Pin<&U>;
|
||||
let mut _5: &T;
|
||||
let mut _6: &U;
|
||||
let _7: std::pin::Pin<&T>;
|
||||
let _8: std::pin::Pin<&U>;
|
||||
let mut _9: &T;
|
||||
let mut _10: &U;
|
||||
scope 1 {
|
||||
debug x => _3;
|
||||
debug y => _4;
|
||||
}
|
||||
scope 2 {
|
||||
debug x => _7;
|
||||
debug y => _8;
|
||||
}
|
||||
|
||||
bb0: {
|
||||
PlaceMention(_1);
|
||||
_2 = discriminant((*(_1.0: &Baz<T, U>)));
|
||||
switchInt(move _2) -> [0: bb2, 1: bb4, otherwise: bb1];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
FakeRead(ForMatchedPlace(None), _1);
|
||||
unreachable;
|
||||
}
|
||||
|
||||
bb2: {
|
||||
falseEdge -> [real: bb6, imaginary: bb4];
|
||||
}
|
||||
|
||||
bb3: {
|
||||
goto -> bb1;
|
||||
}
|
||||
|
||||
bb4: {
|
||||
StorageLive(_7);
|
||||
_9 = &(((*(_1.0: &Baz<T, U>)) as Bar).0: T);
|
||||
_7 = Pin::<&T> { pointer: move _9 };
|
||||
StorageLive(_8);
|
||||
_10 = &(((*(_1.0: &Baz<T, U>)) as Bar).1: U);
|
||||
_8 = Pin::<&U> { pointer: move _10 };
|
||||
_0 = const ();
|
||||
StorageDead(_8);
|
||||
StorageDead(_7);
|
||||
goto -> bb7;
|
||||
}
|
||||
|
||||
bb5: {
|
||||
goto -> bb1;
|
||||
}
|
||||
|
||||
bb6: {
|
||||
StorageLive(_3);
|
||||
_5 = &(((*(_1.0: &Baz<T, U>)) as Foo).0: T);
|
||||
_3 = Pin::<&T> { pointer: move _5 };
|
||||
StorageLive(_4);
|
||||
_6 = &(((*(_1.0: &Baz<T, U>)) as Foo).1: U);
|
||||
_4 = Pin::<&U> { pointer: move _6 };
|
||||
_0 = const ();
|
||||
StorageDead(_4);
|
||||
StorageDead(_3);
|
||||
goto -> bb7;
|
||||
}
|
||||
|
||||
bb7: {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
// MIR for `baz_mut` after built
|
||||
|
||||
fn baz_mut(_1: Pin<&mut Baz<T, U>>) -> () {
|
||||
debug baz => _1;
|
||||
let mut _0: ();
|
||||
let mut _2: isize;
|
||||
let _3: std::pin::Pin<&mut T>;
|
||||
let _4: std::pin::Pin<&mut U>;
|
||||
let mut _5: &mut T;
|
||||
let mut _6: &mut U;
|
||||
let _7: std::pin::Pin<&mut T>;
|
||||
let _8: std::pin::Pin<&mut U>;
|
||||
let mut _9: &mut T;
|
||||
let mut _10: &mut U;
|
||||
scope 1 {
|
||||
debug x => _3;
|
||||
debug y => _4;
|
||||
}
|
||||
scope 2 {
|
||||
debug x => _7;
|
||||
debug y => _8;
|
||||
}
|
||||
|
||||
bb0: {
|
||||
PlaceMention(_1);
|
||||
_2 = discriminant((*(_1.0: &mut Baz<T, U>)));
|
||||
switchInt(move _2) -> [0: bb2, 1: bb4, otherwise: bb1];
|
||||
}
|
||||
|
||||
bb1: {
|
||||
FakeRead(ForMatchedPlace(None), _1);
|
||||
unreachable;
|
||||
}
|
||||
|
||||
bb2: {
|
||||
falseEdge -> [real: bb6, imaginary: bb4];
|
||||
}
|
||||
|
||||
bb3: {
|
||||
goto -> bb1;
|
||||
}
|
||||
|
||||
bb4: {
|
||||
StorageLive(_7);
|
||||
_9 = &mut (((*(_1.0: &mut Baz<T, U>)) as Bar).0: T);
|
||||
_7 = Pin::<&mut T> { pointer: move _9 };
|
||||
StorageLive(_8);
|
||||
_10 = &mut (((*(_1.0: &mut Baz<T, U>)) as Bar).1: U);
|
||||
_8 = Pin::<&mut U> { pointer: move _10 };
|
||||
_0 = const ();
|
||||
StorageDead(_8);
|
||||
StorageDead(_7);
|
||||
goto -> bb7;
|
||||
}
|
||||
|
||||
bb5: {
|
||||
goto -> bb1;
|
||||
}
|
||||
|
||||
bb6: {
|
||||
StorageLive(_3);
|
||||
_5 = &mut (((*(_1.0: &mut Baz<T, U>)) as Foo).0: T);
|
||||
_3 = Pin::<&mut T> { pointer: move _5 };
|
||||
StorageLive(_4);
|
||||
_6 = &mut (((*(_1.0: &mut Baz<T, U>)) as Foo).1: U);
|
||||
_4 = Pin::<&mut U> { pointer: move _6 };
|
||||
_0 = const ();
|
||||
StorageDead(_4);
|
||||
StorageDead(_3);
|
||||
goto -> bb7;
|
||||
}
|
||||
|
||||
bb7: {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
// MIR for `foo_bar_const` after built
|
||||
|
||||
fn foo_bar_const(_1: Pin<&Foo<Bar<T, U>, Bar<T, U>>>) -> () {
|
||||
debug foo => _1;
|
||||
let mut _0: ();
|
||||
let _2: std::pin::Pin<&T>;
|
||||
let _3: std::pin::Pin<&U>;
|
||||
let _4: std::pin::Pin<&T>;
|
||||
let _5: std::pin::Pin<&U>;
|
||||
let mut _6: &T;
|
||||
let mut _7: &U;
|
||||
let mut _8: &T;
|
||||
let mut _9: &U;
|
||||
scope 1 {
|
||||
debug x => _2;
|
||||
debug y => _3;
|
||||
debug z => _4;
|
||||
debug w => _5;
|
||||
}
|
||||
|
||||
bb0: {
|
||||
PlaceMention(_1);
|
||||
StorageLive(_2);
|
||||
_6 = &(((*(_1.0: &Foo<Bar<T, U>, Bar<T, U>>)).0: Bar<T, U>).0: T);
|
||||
_2 = Pin::<&T> { pointer: move _6 };
|
||||
StorageLive(_3);
|
||||
_7 = &(((*(_1.0: &Foo<Bar<T, U>, Bar<T, U>>)).0: Bar<T, U>).1: U);
|
||||
_3 = Pin::<&U> { pointer: move _7 };
|
||||
StorageLive(_4);
|
||||
_8 = &(((*(_1.0: &Foo<Bar<T, U>, Bar<T, U>>)).1: Bar<T, U>).0: T);
|
||||
_4 = Pin::<&T> { pointer: move _8 };
|
||||
StorageLive(_5);
|
||||
_9 = &(((*(_1.0: &Foo<Bar<T, U>, Bar<T, U>>)).1: Bar<T, U>).1: U);
|
||||
_5 = Pin::<&U> { pointer: move _9 };
|
||||
_0 = const ();
|
||||
StorageDead(_5);
|
||||
StorageDead(_4);
|
||||
StorageDead(_3);
|
||||
StorageDead(_2);
|
||||
return;
|
||||
}
|
||||
|
||||
bb1: {
|
||||
FakeRead(ForMatchedPlace(None), _1);
|
||||
unreachable;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
// MIR for `foo_bar_mut` after built
|
||||
|
||||
fn foo_bar_mut(_1: Pin<&mut Foo<Bar<T, U>, Bar<T, U>>>) -> () {
|
||||
debug foo => _1;
|
||||
let mut _0: ();
|
||||
let _2: std::pin::Pin<&mut T>;
|
||||
let _3: std::pin::Pin<&mut U>;
|
||||
let _4: std::pin::Pin<&mut T>;
|
||||
let _5: std::pin::Pin<&mut U>;
|
||||
let mut _6: &mut T;
|
||||
let mut _7: &mut U;
|
||||
let mut _8: &mut T;
|
||||
let mut _9: &mut U;
|
||||
scope 1 {
|
||||
debug x => _2;
|
||||
debug y => _3;
|
||||
debug z => _4;
|
||||
debug w => _5;
|
||||
}
|
||||
|
||||
bb0: {
|
||||
PlaceMention(_1);
|
||||
StorageLive(_2);
|
||||
_6 = &mut (((*(_1.0: &mut Foo<Bar<T, U>, Bar<T, U>>)).0: Bar<T, U>).0: T);
|
||||
_2 = Pin::<&mut T> { pointer: move _6 };
|
||||
StorageLive(_3);
|
||||
_7 = &mut (((*(_1.0: &mut Foo<Bar<T, U>, Bar<T, U>>)).0: Bar<T, U>).1: U);
|
||||
_3 = Pin::<&mut U> { pointer: move _7 };
|
||||
StorageLive(_4);
|
||||
_8 = &mut (((*(_1.0: &mut Foo<Bar<T, U>, Bar<T, U>>)).1: Bar<T, U>).0: T);
|
||||
_4 = Pin::<&mut T> { pointer: move _8 };
|
||||
StorageLive(_5);
|
||||
_9 = &mut (((*(_1.0: &mut Foo<Bar<T, U>, Bar<T, U>>)).1: Bar<T, U>).1: U);
|
||||
_5 = Pin::<&mut U> { pointer: move _9 };
|
||||
_0 = const ();
|
||||
StorageDead(_5);
|
||||
StorageDead(_4);
|
||||
StorageDead(_3);
|
||||
StorageDead(_2);
|
||||
return;
|
||||
}
|
||||
|
||||
bb1: {
|
||||
FakeRead(ForMatchedPlace(None), _1);
|
||||
unreachable;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
// MIR for `foo_const` after built
|
||||
|
||||
fn foo_const(_1: Pin<&Foo<T, U>>) -> () {
|
||||
debug foo => _1;
|
||||
let mut _0: ();
|
||||
let _2: std::pin::Pin<&T>;
|
||||
let _3: std::pin::Pin<&U>;
|
||||
let mut _4: &T;
|
||||
let mut _5: &U;
|
||||
scope 1 {
|
||||
debug x => _2;
|
||||
debug y => _3;
|
||||
}
|
||||
|
||||
bb0: {
|
||||
PlaceMention(_1);
|
||||
StorageLive(_2);
|
||||
_4 = &((*(_1.0: &Foo<T, U>)).0: T);
|
||||
_2 = Pin::<&T> { pointer: move _4 };
|
||||
StorageLive(_3);
|
||||
_5 = &((*(_1.0: &Foo<T, U>)).1: U);
|
||||
_3 = Pin::<&U> { pointer: move _5 };
|
||||
_0 = const ();
|
||||
StorageDead(_3);
|
||||
StorageDead(_2);
|
||||
return;
|
||||
}
|
||||
|
||||
bb1: {
|
||||
FakeRead(ForMatchedPlace(None), _1);
|
||||
unreachable;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
// MIR for `foo_mut` after built
|
||||
|
||||
fn foo_mut(_1: Pin<&mut Foo<T, U>>) -> () {
|
||||
debug foo => _1;
|
||||
let mut _0: ();
|
||||
let _2: std::pin::Pin<&mut T>;
|
||||
let _3: std::pin::Pin<&mut U>;
|
||||
let mut _4: &mut T;
|
||||
let mut _5: &mut U;
|
||||
scope 1 {
|
||||
debug x => _2;
|
||||
debug y => _3;
|
||||
}
|
||||
|
||||
bb0: {
|
||||
PlaceMention(_1);
|
||||
StorageLive(_2);
|
||||
_4 = &mut ((*(_1.0: &mut Foo<T, U>)).0: T);
|
||||
_2 = Pin::<&mut T> { pointer: move _4 };
|
||||
StorageLive(_3);
|
||||
_5 = &mut ((*(_1.0: &mut Foo<T, U>)).1: U);
|
||||
_3 = Pin::<&mut U> { pointer: move _5 };
|
||||
_0 = const ();
|
||||
StorageDead(_3);
|
||||
StorageDead(_2);
|
||||
return;
|
||||
}
|
||||
|
||||
bb1: {
|
||||
FakeRead(ForMatchedPlace(None), _1);
|
||||
unreachable;
|
||||
}
|
||||
}
|
||||
95
tests/mir-opt/pin-ergonomics/project_pattern_match.rs
Normal file
95
tests/mir-opt/pin-ergonomics/project_pattern_match.rs
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
// skip-filecheck
|
||||
#![feature(pin_ergonomics)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
// This test verifies that a `&pin mut Foo` can be projected to a pinned
|
||||
// reference `&pin mut T` of a `?Unpin` field , and can be projected to
|
||||
// an unpinned reference `&mut U` of an `Unpin` field .
|
||||
|
||||
struct Foo<T, U> {
|
||||
x: T,
|
||||
y: U,
|
||||
}
|
||||
|
||||
struct Bar<T, U>(T, U);
|
||||
|
||||
enum Baz<T, U> {
|
||||
Foo(T, U),
|
||||
Bar { x: T, y: U },
|
||||
}
|
||||
|
||||
// EMIT_MIR project_pattern_match.foo_mut.built.after.mir
|
||||
fn foo_mut<T, U: Unpin>(foo: &pin mut Foo<T, U>) {
|
||||
let Foo { x, y } = foo;
|
||||
}
|
||||
|
||||
// EMIT_MIR project_pattern_match.foo_const.built.after.mir
|
||||
fn foo_const<T, U: Unpin>(foo: &pin const Foo<T, U>) {
|
||||
let Foo { x, y } = foo;
|
||||
}
|
||||
|
||||
// EMIT_MIR project_pattern_match.bar_mut.built.after.mir
|
||||
fn bar_mut<T, U: Unpin>(bar: &pin mut Bar<T, U>) {
|
||||
let Bar(x, y) = bar;
|
||||
}
|
||||
|
||||
// EMIT_MIR project_pattern_match.bar_const.built.after.mir
|
||||
fn bar_const<T, U: Unpin>(bar: &pin const Bar<T, U>) {
|
||||
let Bar(x, y) = bar;
|
||||
}
|
||||
|
||||
// EMIT_MIR project_pattern_match.foo_bar_mut.built.after.mir
|
||||
fn foo_bar_mut<T, U: Unpin>(foo: &pin mut Foo<Bar<T, U>, Bar<T, U>>) {
|
||||
let Foo { x: Bar(x, y), y: Bar(z, w) } = foo;
|
||||
}
|
||||
|
||||
// EMIT_MIR project_pattern_match.foo_bar_const.built.after.mir
|
||||
fn foo_bar_const<T, U: Unpin>(foo: &pin const Foo<Bar<T, U>, Bar<T, U>>) {
|
||||
let Foo { x: Bar(x, y), y: Bar(z, w) } = foo;
|
||||
}
|
||||
|
||||
// EMIT_MIR project_pattern_match.baz_mut.built.after.mir
|
||||
fn baz_mut<T, U: Unpin>(baz: &pin mut Baz<T, U>) {
|
||||
match baz {
|
||||
Baz::Foo(x, y) => {}
|
||||
Baz::Bar { x, y } => {}
|
||||
}
|
||||
}
|
||||
|
||||
// EMIT_MIR project_pattern_match.baz_const.built.after.mir
|
||||
fn baz_const<T, U: Unpin>(baz: &pin const Baz<T, U>) {
|
||||
match baz {
|
||||
Baz::Foo(x, y) => {}
|
||||
Baz::Bar { x, y } => {}
|
||||
}
|
||||
}
|
||||
|
||||
// EMIT_MIR project_pattern_match.baz_baz_mut.built.after.mir
|
||||
fn baz_baz_mut<T, U: Unpin>(baz: &pin mut Baz<Baz<T, U>, Baz<T, U>>) {
|
||||
match baz {
|
||||
Baz::Foo(Baz::Foo(x, y), Baz::Foo(z, w)) => {}
|
||||
Baz::Foo(Baz::Foo(x, y), Baz::Bar { x: z, y: w }) => {}
|
||||
Baz::Foo(Baz::Bar { x, y }, Baz::Foo(z, w)) => {}
|
||||
Baz::Foo(Baz::Bar { x, y }, Baz::Bar { x: z, y: w }) => {}
|
||||
Baz::Bar { x: Baz::Foo(x, y), y: Baz::Foo(z, w) } => {}
|
||||
Baz::Bar { x: Baz::Foo(x, y), y: Baz::Bar { x: z, y: w } } => {}
|
||||
Baz::Bar { x: Baz::Bar { x, y }, y: Baz::Foo(z, w) } => {}
|
||||
Baz::Bar { x: Baz::Bar { x, y }, y: Baz::Bar { x: z, y: w } } => {}
|
||||
}
|
||||
}
|
||||
|
||||
// EMIT_MIR project_pattern_match.baz_baz_const.built.after.mir
|
||||
fn baz_baz_const<T, U: Unpin>(baz: &pin const Baz<Baz<T, U>, Baz<T, U>>) {
|
||||
match baz {
|
||||
Baz::Foo(Baz::Foo(x, y), Baz::Foo(z, w)) => {}
|
||||
Baz::Foo(Baz::Foo(x, y), Baz::Bar { x: z, y: w }) => {}
|
||||
Baz::Foo(Baz::Bar { x, y }, Baz::Foo(z, w)) => {}
|
||||
Baz::Foo(Baz::Bar { x, y }, Baz::Bar { x: z, y: w }) => {}
|
||||
Baz::Bar { x: Baz::Foo(x, y), y: Baz::Foo(z, w) } => {}
|
||||
Baz::Bar { x: Baz::Foo(x, y), y: Baz::Bar { x: z, y: w } } => {}
|
||||
Baz::Bar { x: Baz::Bar { x, y }, y: Baz::Foo(z, w) } => {}
|
||||
Baz::Bar { x: Baz::Bar { x, y }, y: Baz::Bar { x: z, y: w } } => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
91
tests/ui/pin-ergonomics/pattern-matching-deref-pattern.rs
Normal file
91
tests/ui/pin-ergonomics/pattern-matching-deref-pattern.rs
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
//@ revisions: pin_ergonomics normal
|
||||
//@ edition:2024
|
||||
//@ check-pass
|
||||
// //@[normal] check-pass
|
||||
// //@[pin_ergonomics] rustc-env:RUSTC_LOG=rustc_hir_typeck::expr_use_visitor=DEBUG
|
||||
#![cfg_attr(pin_ergonomics, feature(pin_ergonomics))]
|
||||
#![feature(deref_patterns)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
// This test verifies that the `pin_ergonomics` feature works well
|
||||
// together with the `deref_patterns` feature.
|
||||
|
||||
use std::pin::Pin;
|
||||
|
||||
struct Foo<T, U> {
|
||||
x: T,
|
||||
y: U,
|
||||
}
|
||||
|
||||
struct Bar<T, U>(T, U);
|
||||
|
||||
enum Baz<T, U> {
|
||||
Foo(T, U),
|
||||
Bar { x: T, y: U },
|
||||
}
|
||||
|
||||
fn foo_mut<T: Unpin, U: Unpin>(foo: Pin<&mut Foo<T, U>>) {
|
||||
let Foo { .. } = foo;
|
||||
let Pin { .. } = foo;
|
||||
let _ = || {
|
||||
let Foo { .. } = foo;
|
||||
let Pin { .. } = foo;
|
||||
};
|
||||
|
||||
#[cfg(pin_ergonomics)]
|
||||
let Foo { x, y } = foo;
|
||||
#[cfg(pin_ergonomics)]
|
||||
let _ = || {
|
||||
let Foo { x, y } = foo;
|
||||
};
|
||||
}
|
||||
|
||||
fn foo_const<T: Unpin, U: Unpin>(foo: Pin<&Foo<T, U>>) {
|
||||
let Foo { .. } = foo;
|
||||
let Pin { .. } = foo;
|
||||
let _ = || {
|
||||
let Foo { .. } = foo;
|
||||
let Pin { .. } = foo;
|
||||
};
|
||||
|
||||
#[cfg(pin_ergonomics)]
|
||||
let Foo { x, y } = foo;
|
||||
#[cfg(pin_ergonomics)]
|
||||
let _ = || {
|
||||
let Foo { x, y } = foo;
|
||||
};
|
||||
}
|
||||
|
||||
fn bar_mut<T: Unpin, U: Unpin>(bar: Pin<&mut Bar<T, U>>) {
|
||||
let Bar(..) = bar;
|
||||
let Pin { .. } = bar;
|
||||
let _ = || {
|
||||
let Bar(..) = bar;
|
||||
let Pin { .. } = bar;
|
||||
};
|
||||
|
||||
#[cfg(pin_ergonomics)]
|
||||
let Bar(x, y) = bar;
|
||||
#[cfg(pin_ergonomics)]
|
||||
let _ = || {
|
||||
let Bar(x, y) = bar;
|
||||
};
|
||||
}
|
||||
|
||||
fn bar_const<T: Unpin, U: Unpin>(bar: Pin<&Bar<T, U>>) {
|
||||
let Bar(..) = bar;
|
||||
let Pin { .. } = bar;
|
||||
let _ = || {
|
||||
let Bar(..) = bar;
|
||||
let Pin { .. } = bar;
|
||||
};
|
||||
|
||||
#[cfg(pin_ergonomics)]
|
||||
let Bar(x, y) = bar;
|
||||
#[cfg(pin_ergonomics)]
|
||||
let _ = || {
|
||||
let Bar(x, y) = bar;
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
error: mix of deref patterns and normal constructors
|
||||
--> $DIR/pattern-matching-mix-deref-pattern.rs:27:9
|
||||
|
|
||||
LL | Foo { .. } => {}
|
||||
| ^^^^^^^^^^ matches on the result of dereferencing `Pin<&mut Foo<T, U>>`
|
||||
LL | Pin { .. } => {}
|
||||
| ^^^^^^^^^^ matches directly on `Pin<&mut Foo<T, U>>`
|
||||
|
||||
error: mix of deref patterns and normal constructors
|
||||
--> $DIR/pattern-matching-mix-deref-pattern.rs:31:9
|
||||
|
|
||||
LL | Foo { .. } => {}
|
||||
| ^^^^^^^^^^ matches on the result of dereferencing `Pin<&mut Foo<T, U>>`
|
||||
LL | Pin { .. } => {}
|
||||
| ^^^^^^^^^^ matches directly on `Pin<&mut Foo<T, U>>`
|
||||
|
||||
error: mix of deref patterns and normal constructors
|
||||
--> $DIR/pattern-matching-mix-deref-pattern.rs:49:9
|
||||
|
|
||||
LL | Foo { .. } => {}
|
||||
| ^^^^^^^^^^ matches on the result of dereferencing `Pin<&Foo<T, U>>`
|
||||
LL | Pin { .. } => {}
|
||||
| ^^^^^^^^^^ matches directly on `Pin<&Foo<T, U>>`
|
||||
|
||||
error: mix of deref patterns and normal constructors
|
||||
--> $DIR/pattern-matching-mix-deref-pattern.rs:53:9
|
||||
|
|
||||
LL | Foo { .. } => {}
|
||||
| ^^^^^^^^^^ matches on the result of dereferencing `Pin<&Foo<T, U>>`
|
||||
LL | Pin { .. } => {}
|
||||
| ^^^^^^^^^^ matches directly on `Pin<&Foo<T, U>>`
|
||||
|
||||
error: mix of deref patterns and normal constructors
|
||||
--> $DIR/pattern-matching-mix-deref-pattern.rs:71:9
|
||||
|
|
||||
LL | Bar(..) => {}
|
||||
| ^^^^^^^ matches on the result of dereferencing `Pin<&mut Bar<T, U>>`
|
||||
LL | Pin { .. } => {}
|
||||
| ^^^^^^^^^^ matches directly on `Pin<&mut Bar<T, U>>`
|
||||
|
||||
error: mix of deref patterns and normal constructors
|
||||
--> $DIR/pattern-matching-mix-deref-pattern.rs:75:9
|
||||
|
|
||||
LL | Bar(..) => {}
|
||||
| ^^^^^^^ matches on the result of dereferencing `Pin<&mut Bar<T, U>>`
|
||||
LL | Pin { .. } => {}
|
||||
| ^^^^^^^^^^ matches directly on `Pin<&mut Bar<T, U>>`
|
||||
|
||||
error: mix of deref patterns and normal constructors
|
||||
--> $DIR/pattern-matching-mix-deref-pattern.rs:93:9
|
||||
|
|
||||
LL | Bar(..) => {}
|
||||
| ^^^^^^^ matches on the result of dereferencing `Pin<&Bar<T, U>>`
|
||||
LL | Pin { .. } => {}
|
||||
| ^^^^^^^^^^ matches directly on `Pin<&Bar<T, U>>`
|
||||
|
||||
error: mix of deref patterns and normal constructors
|
||||
--> $DIR/pattern-matching-mix-deref-pattern.rs:97:9
|
||||
|
|
||||
LL | Bar(..) => {}
|
||||
| ^^^^^^^ matches on the result of dereferencing `Pin<&Bar<T, U>>`
|
||||
LL | Pin { .. } => {}
|
||||
| ^^^^^^^^^^ matches directly on `Pin<&Bar<T, U>>`
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
error: mix of deref patterns and normal constructors
|
||||
--> $DIR/pattern-matching-mix-deref-pattern.rs:27:9
|
||||
|
|
||||
LL | Foo { .. } => {}
|
||||
| ^^^^^^^^^^ matches on the result of dereferencing `Pin<&mut Foo<T, U>>`
|
||||
LL | Pin { .. } => {}
|
||||
| ^^^^^^^^^^ matches directly on `Pin<&mut Foo<T, U>>`
|
||||
|
||||
error: mix of deref patterns and normal constructors
|
||||
--> $DIR/pattern-matching-mix-deref-pattern.rs:37:9
|
||||
|
|
||||
LL | Foo { x, y } => {}
|
||||
| ^^^^^^^^^^^^ matches on the result of dereferencing `Pin<&mut Foo<T, U>>`
|
||||
LL | Pin { .. } => {}
|
||||
| ^^^^^^^^^^ matches directly on `Pin<&mut Foo<T, U>>`
|
||||
|
||||
error: mix of deref patterns and normal constructors
|
||||
--> $DIR/pattern-matching-mix-deref-pattern.rs:31:9
|
||||
|
|
||||
LL | Foo { .. } => {}
|
||||
| ^^^^^^^^^^ matches on the result of dereferencing `Pin<&mut Foo<T, U>>`
|
||||
LL | Pin { .. } => {}
|
||||
| ^^^^^^^^^^ matches directly on `Pin<&mut Foo<T, U>>`
|
||||
|
||||
error: mix of deref patterns and normal constructors
|
||||
--> $DIR/pattern-matching-mix-deref-pattern.rs:42:9
|
||||
|
|
||||
LL | Foo { .. } => {}
|
||||
| ^^^^^^^^^^ matches on the result of dereferencing `Pin<&mut Foo<T, U>>`
|
||||
LL | Pin { .. } => {}
|
||||
| ^^^^^^^^^^ matches directly on `Pin<&mut Foo<T, U>>`
|
||||
|
||||
error: mix of deref patterns and normal constructors
|
||||
--> $DIR/pattern-matching-mix-deref-pattern.rs:49:9
|
||||
|
|
||||
LL | Foo { .. } => {}
|
||||
| ^^^^^^^^^^ matches on the result of dereferencing `Pin<&Foo<T, U>>`
|
||||
LL | Pin { .. } => {}
|
||||
| ^^^^^^^^^^ matches directly on `Pin<&Foo<T, U>>`
|
||||
|
||||
error: mix of deref patterns and normal constructors
|
||||
--> $DIR/pattern-matching-mix-deref-pattern.rs:59:9
|
||||
|
|
||||
LL | Foo { x, y } => {}
|
||||
| ^^^^^^^^^^^^ matches on the result of dereferencing `Pin<&Foo<T, U>>`
|
||||
LL | Pin { .. } => {}
|
||||
| ^^^^^^^^^^ matches directly on `Pin<&Foo<T, U>>`
|
||||
|
||||
error: mix of deref patterns and normal constructors
|
||||
--> $DIR/pattern-matching-mix-deref-pattern.rs:53:9
|
||||
|
|
||||
LL | Foo { .. } => {}
|
||||
| ^^^^^^^^^^ matches on the result of dereferencing `Pin<&Foo<T, U>>`
|
||||
LL | Pin { .. } => {}
|
||||
| ^^^^^^^^^^ matches directly on `Pin<&Foo<T, U>>`
|
||||
|
||||
error: mix of deref patterns and normal constructors
|
||||
--> $DIR/pattern-matching-mix-deref-pattern.rs:64:9
|
||||
|
|
||||
LL | Foo { .. } => {}
|
||||
| ^^^^^^^^^^ matches on the result of dereferencing `Pin<&Foo<T, U>>`
|
||||
LL | Pin { .. } => {}
|
||||
| ^^^^^^^^^^ matches directly on `Pin<&Foo<T, U>>`
|
||||
|
||||
error: mix of deref patterns and normal constructors
|
||||
--> $DIR/pattern-matching-mix-deref-pattern.rs:71:9
|
||||
|
|
||||
LL | Bar(..) => {}
|
||||
| ^^^^^^^ matches on the result of dereferencing `Pin<&mut Bar<T, U>>`
|
||||
LL | Pin { .. } => {}
|
||||
| ^^^^^^^^^^ matches directly on `Pin<&mut Bar<T, U>>`
|
||||
|
||||
error: mix of deref patterns and normal constructors
|
||||
--> $DIR/pattern-matching-mix-deref-pattern.rs:81:9
|
||||
|
|
||||
LL | Bar(x, y) => {}
|
||||
| ^^^^^^^^^ matches on the result of dereferencing `Pin<&mut Bar<T, U>>`
|
||||
LL | Pin { .. } => {}
|
||||
| ^^^^^^^^^^ matches directly on `Pin<&mut Bar<T, U>>`
|
||||
|
||||
error: mix of deref patterns and normal constructors
|
||||
--> $DIR/pattern-matching-mix-deref-pattern.rs:75:9
|
||||
|
|
||||
LL | Bar(..) => {}
|
||||
| ^^^^^^^ matches on the result of dereferencing `Pin<&mut Bar<T, U>>`
|
||||
LL | Pin { .. } => {}
|
||||
| ^^^^^^^^^^ matches directly on `Pin<&mut Bar<T, U>>`
|
||||
|
||||
error: mix of deref patterns and normal constructors
|
||||
--> $DIR/pattern-matching-mix-deref-pattern.rs:86:9
|
||||
|
|
||||
LL | Bar(x, y) => {}
|
||||
| ^^^^^^^^^ matches on the result of dereferencing `Pin<&mut Bar<T, U>>`
|
||||
LL | Pin { .. } => {}
|
||||
| ^^^^^^^^^^ matches directly on `Pin<&mut Bar<T, U>>`
|
||||
|
||||
error: mix of deref patterns and normal constructors
|
||||
--> $DIR/pattern-matching-mix-deref-pattern.rs:93:9
|
||||
|
|
||||
LL | Bar(..) => {}
|
||||
| ^^^^^^^ matches on the result of dereferencing `Pin<&Bar<T, U>>`
|
||||
LL | Pin { .. } => {}
|
||||
| ^^^^^^^^^^ matches directly on `Pin<&Bar<T, U>>`
|
||||
|
||||
error: mix of deref patterns and normal constructors
|
||||
--> $DIR/pattern-matching-mix-deref-pattern.rs:103:9
|
||||
|
|
||||
LL | Bar(x, y) => {}
|
||||
| ^^^^^^^^^ matches on the result of dereferencing `Pin<&Bar<T, U>>`
|
||||
LL | Pin { .. } => {}
|
||||
| ^^^^^^^^^^ matches directly on `Pin<&Bar<T, U>>`
|
||||
|
||||
error: mix of deref patterns and normal constructors
|
||||
--> $DIR/pattern-matching-mix-deref-pattern.rs:97:9
|
||||
|
|
||||
LL | Bar(..) => {}
|
||||
| ^^^^^^^ matches on the result of dereferencing `Pin<&Bar<T, U>>`
|
||||
LL | Pin { .. } => {}
|
||||
| ^^^^^^^^^^ matches directly on `Pin<&Bar<T, U>>`
|
||||
|
||||
error: mix of deref patterns and normal constructors
|
||||
--> $DIR/pattern-matching-mix-deref-pattern.rs:108:9
|
||||
|
|
||||
LL | Bar(x, y) => {}
|
||||
| ^^^^^^^^^ matches on the result of dereferencing `Pin<&Bar<T, U>>`
|
||||
LL | Pin { .. } => {}
|
||||
| ^^^^^^^^^^ matches directly on `Pin<&Bar<T, U>>`
|
||||
|
||||
error: aborting due to 16 previous errors
|
||||
|
||||
113
tests/ui/pin-ergonomics/pattern-matching-mix-deref-pattern.rs
Normal file
113
tests/ui/pin-ergonomics/pattern-matching-mix-deref-pattern.rs
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
//@ revisions: pin_ergonomics normal
|
||||
//@ edition:2024
|
||||
#![cfg_attr(pin_ergonomics, feature(pin_ergonomics))]
|
||||
#![feature(deref_patterns)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
// This test verifies that the `pin_ergonomics` feature works well
|
||||
// together with the `deref_patterns` feature under the error:
|
||||
// "mix of deref patterns and normal constructors".
|
||||
|
||||
use std::pin::Pin;
|
||||
|
||||
struct Foo<T, U> {
|
||||
x: T,
|
||||
y: U,
|
||||
}
|
||||
|
||||
struct Bar<T, U>(T, U);
|
||||
|
||||
enum Baz<T, U> {
|
||||
Foo(T, U),
|
||||
Bar { x: T, y: U },
|
||||
}
|
||||
|
||||
fn foo_mut<T: Unpin, U: Unpin>(foo: Pin<&mut Foo<T, U>>) {
|
||||
match foo {
|
||||
Foo { .. } => {} //~ ERROR mix of deref patterns and normal constructors
|
||||
Pin { .. } => {}
|
||||
}
|
||||
let _ = || match foo {
|
||||
Foo { .. } => {} //~ ERROR mix of deref patterns and normal constructors
|
||||
Pin { .. } => {}
|
||||
};
|
||||
|
||||
#[cfg(pin_ergonomics)]
|
||||
match foo {
|
||||
Foo { x, y } => {} //[pin_ergonomics]~ ERROR mix of deref patterns and normal constructors
|
||||
Pin { .. } => {}
|
||||
}
|
||||
#[cfg(pin_ergonomics)]
|
||||
let _ = || match foo {
|
||||
Foo { .. } => {} //[pin_ergonomics]~ ERROR mix of deref patterns and normal constructors
|
||||
Pin { .. } => {}
|
||||
};
|
||||
}
|
||||
|
||||
fn foo_const<T: Unpin, U: Unpin>(foo: Pin<&Foo<T, U>>) {
|
||||
match foo {
|
||||
Foo { .. } => {} //~ ERROR mix of deref patterns and normal constructors
|
||||
Pin { .. } => {}
|
||||
}
|
||||
let _ = || match foo {
|
||||
Foo { .. } => {} //~ ERROR mix of deref patterns and normal constructors
|
||||
Pin { .. } => {}
|
||||
};
|
||||
|
||||
#[cfg(pin_ergonomics)]
|
||||
match foo {
|
||||
Foo { x, y } => {} //[pin_ergonomics]~ ERROR mix of deref patterns and normal constructors
|
||||
Pin { .. } => {}
|
||||
}
|
||||
#[cfg(pin_ergonomics)]
|
||||
let _ = || match foo {
|
||||
Foo { .. } => {} //[pin_ergonomics]~ ERROR mix of deref patterns and normal constructors
|
||||
Pin { .. } => {}
|
||||
};
|
||||
}
|
||||
|
||||
fn bar_mut<T: Unpin, U: Unpin>(bar: Pin<&mut Bar<T, U>>) {
|
||||
match bar {
|
||||
Bar(..) => {} //~ ERROR mix of deref patterns and normal constructors
|
||||
Pin { .. } => {}
|
||||
}
|
||||
let _ = || match bar {
|
||||
Bar(..) => {} //~ ERROR mix of deref patterns and normal constructors
|
||||
Pin { .. } => {}
|
||||
};
|
||||
|
||||
#[cfg(pin_ergonomics)]
|
||||
match bar {
|
||||
Bar(x, y) => {} //[pin_ergonomics]~ ERROR mix of deref patterns and normal constructors
|
||||
Pin { .. } => {}
|
||||
}
|
||||
#[cfg(pin_ergonomics)]
|
||||
let _ = || match bar {
|
||||
Bar(x, y) => {} //[pin_ergonomics]~ ERROR mix of deref patterns and normal constructors
|
||||
Pin { .. } => {}
|
||||
};
|
||||
}
|
||||
|
||||
fn bar_const<T: Unpin, U: Unpin>(bar: Pin<&Bar<T, U>>) {
|
||||
match bar {
|
||||
Bar(..) => {} //~ ERROR mix of deref patterns and normal constructors
|
||||
Pin { .. } => {}
|
||||
}
|
||||
let _ = || match bar {
|
||||
Bar(..) => {} //~ ERROR mix of deref patterns and normal constructors
|
||||
Pin { .. } => {}
|
||||
};
|
||||
|
||||
#[cfg(pin_ergonomics)]
|
||||
match bar {
|
||||
Bar(x, y) => {} //[pin_ergonomics]~ ERROR mix of deref patterns and normal constructors
|
||||
Pin { .. } => {}
|
||||
}
|
||||
#[cfg(pin_ergonomics)]
|
||||
let _ = || match bar {
|
||||
Bar(x, y) => {} //[pin_ergonomics]~ ERROR mix of deref patterns and normal constructors
|
||||
Pin { .. } => {}
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
313
tests/ui/pin-ergonomics/pattern-matching.normal.stderr
Normal file
313
tests/ui/pin-ergonomics/pattern-matching.normal.stderr
Normal file
|
|
@ -0,0 +1,313 @@
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/pattern-matching.rs:35:9
|
||||
|
|
||||
LL | let Foo { x, y } = foo;
|
||||
| ^^^^^^^^^^^^ --- this expression has type `Pin<&mut Foo<T, U>>`
|
||||
| |
|
||||
| expected `Pin<&mut Foo<T, U>>`, found `Foo<_, _>`
|
||||
|
|
||||
= note: expected struct `Pin<&mut Foo<T, U>>`
|
||||
found struct `Foo<_, _>`
|
||||
help: consider dereferencing to access the inner value using the Deref trait
|
||||
|
|
||||
LL | let Foo { x, y } = *foo;
|
||||
| +
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/pattern-matching.rs:42:9
|
||||
|
|
||||
LL | let Foo { x, y } = foo;
|
||||
| ^^^^^^^^^^^^ --- this expression has type `Pin<&Foo<T, U>>`
|
||||
| |
|
||||
| expected `Pin<&Foo<T, U>>`, found `Foo<_, _>`
|
||||
|
|
||||
= note: expected struct `Pin<&Foo<T, U>>`
|
||||
found struct `Foo<_, _>`
|
||||
help: consider dereferencing to access the inner value using the Deref trait
|
||||
|
|
||||
LL | let Foo { x, y } = *foo;
|
||||
| +
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/pattern-matching.rs:49:9
|
||||
|
|
||||
LL | let Bar(x, y) = bar;
|
||||
| ^^^^^^^^^ --- this expression has type `Pin<&mut Bar<T, U>>`
|
||||
| |
|
||||
| expected `Pin<&mut Bar<T, U>>`, found `Bar<_, _>`
|
||||
|
|
||||
= note: expected struct `Pin<&mut Bar<T, U>>`
|
||||
found struct `Bar<_, _>`
|
||||
help: consider dereferencing to access the inner value using the Deref trait
|
||||
|
|
||||
LL | let Bar(x, y) = *bar;
|
||||
| +
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/pattern-matching.rs:56:9
|
||||
|
|
||||
LL | let Bar(x, y) = bar;
|
||||
| ^^^^^^^^^ --- this expression has type `Pin<&Bar<T, U>>`
|
||||
| |
|
||||
| expected `Pin<&Bar<T, U>>`, found `Bar<_, _>`
|
||||
|
|
||||
= note: expected struct `Pin<&Bar<T, U>>`
|
||||
found struct `Bar<_, _>`
|
||||
help: consider dereferencing to access the inner value using the Deref trait
|
||||
|
|
||||
LL | let Bar(x, y) = *bar;
|
||||
| +
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/pattern-matching.rs:63:9
|
||||
|
|
||||
LL | let Foo { x: Bar(x, y), y: Bar(z, w) } = foo;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --- this expression has type `Pin<&mut Foo<Bar<T, U>, Bar<T, U>>>`
|
||||
| |
|
||||
| expected `Pin<&mut Foo<Bar<T, U>, Bar<T, U>>>`, found `Foo<_, _>`
|
||||
|
|
||||
= note: expected struct `Pin<&mut Foo<Bar<T, U>, Bar<T, U>>>`
|
||||
found struct `Foo<_, _>`
|
||||
help: consider dereferencing to access the inner value using the Deref trait
|
||||
|
|
||||
LL | let Foo { x: Bar(x, y), y: Bar(z, w) } = *foo;
|
||||
| +
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/pattern-matching.rs:72:9
|
||||
|
|
||||
LL | let Foo { x: Bar(x, y), y: Bar(z, w) } = foo;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --- this expression has type `Pin<&Foo<Bar<T, U>, Bar<T, U>>>`
|
||||
| |
|
||||
| expected `Pin<&Foo<Bar<T, U>, Bar<T, U>>>`, found `Foo<_, _>`
|
||||
|
|
||||
= note: expected struct `Pin<&Foo<Bar<T, U>, Bar<T, U>>>`
|
||||
found struct `Foo<_, _>`
|
||||
help: consider dereferencing to access the inner value using the Deref trait
|
||||
|
|
||||
LL | let Foo { x: Bar(x, y), y: Bar(z, w) } = *foo;
|
||||
| +
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/pattern-matching.rs:82:9
|
||||
|
|
||||
LL | match baz {
|
||||
| --- this expression has type `Pin<&mut Baz<T, U>>`
|
||||
LL | Baz::Foo(x, y) => {
|
||||
| ^^^^^^^^^^^^^^ expected `Pin<&mut Baz<T, U>>`, found `Baz<_, _>`
|
||||
|
|
||||
= note: expected struct `Pin<&mut Baz<T, U>>`
|
||||
found enum `Baz<_, _>`
|
||||
help: consider dereferencing to access the inner value using the Deref trait
|
||||
|
|
||||
LL | match *baz {
|
||||
| +
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/pattern-matching.rs:87:9
|
||||
|
|
||||
LL | match baz {
|
||||
| --- this expression has type `Pin<&mut Baz<T, U>>`
|
||||
...
|
||||
LL | Baz::Bar { x, y } => {
|
||||
| ^^^^^^^^^^^^^^^^^ expected `Pin<&mut Baz<T, U>>`, found `Baz<_, _>`
|
||||
|
|
||||
= note: expected struct `Pin<&mut Baz<T, U>>`
|
||||
found enum `Baz<_, _>`
|
||||
help: consider dereferencing to access the inner value using the Deref trait
|
||||
|
|
||||
LL | match *baz {
|
||||
| +
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/pattern-matching.rs:97:9
|
||||
|
|
||||
LL | match baz {
|
||||
| --- this expression has type `Pin<&Baz<T, U>>`
|
||||
LL | Baz::Foo(x, y) => {
|
||||
| ^^^^^^^^^^^^^^ expected `Pin<&Baz<T, U>>`, found `Baz<_, _>`
|
||||
|
|
||||
= note: expected struct `Pin<&Baz<T, U>>`
|
||||
found enum `Baz<_, _>`
|
||||
help: consider dereferencing to access the inner value using the Deref trait
|
||||
|
|
||||
LL | match *baz {
|
||||
| +
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/pattern-matching.rs:102:9
|
||||
|
|
||||
LL | match baz {
|
||||
| --- this expression has type `Pin<&Baz<T, U>>`
|
||||
...
|
||||
LL | Baz::Bar { x, y } => {
|
||||
| ^^^^^^^^^^^^^^^^^ expected `Pin<&Baz<T, U>>`, found `Baz<_, _>`
|
||||
|
|
||||
= note: expected struct `Pin<&Baz<T, U>>`
|
||||
found enum `Baz<_, _>`
|
||||
help: consider dereferencing to access the inner value using the Deref trait
|
||||
|
|
||||
LL | match *baz {
|
||||
| +
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/pattern-matching.rs:112:9
|
||||
|
|
||||
LL | match baz {
|
||||
| --- this expression has type `Pin<&mut Baz<Baz<T, U>, Baz<T, U>>>`
|
||||
LL | Baz::Foo(Baz::Foo(x, y), Baz::Foo(z, w) | Baz::Bar { x: z, y: w }) => {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&mut Baz<Baz<T, U>, Baz<T, U>>>`, found `Baz<_, _>`
|
||||
|
|
||||
= note: expected struct `Pin<&mut Baz<Baz<T, U>, Baz<T, U>>>`
|
||||
found enum `Baz<_, _>`
|
||||
help: consider dereferencing to access the inner value using the Deref trait
|
||||
|
|
||||
LL | match *baz {
|
||||
| +
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/pattern-matching.rs:119:9
|
||||
|
|
||||
LL | match baz {
|
||||
| --- this expression has type `Pin<&mut Baz<Baz<T, U>, Baz<T, U>>>`
|
||||
...
|
||||
LL | Baz::Foo(Baz::Bar { x, y }, Baz::Foo(z, w) | Baz::Bar { x: z, y: w }) => {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&mut Baz<Baz<T, U>, Baz<T, U>>>`, found `Baz<_, _>`
|
||||
|
|
||||
= note: expected struct `Pin<&mut Baz<Baz<T, U>, Baz<T, U>>>`
|
||||
found enum `Baz<_, _>`
|
||||
help: consider dereferencing to access the inner value using the Deref trait
|
||||
|
|
||||
LL | match *baz {
|
||||
| +
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/pattern-matching.rs:126:9
|
||||
|
|
||||
LL | match baz {
|
||||
| --- this expression has type `Pin<&mut Baz<Baz<T, U>, Baz<T, U>>>`
|
||||
...
|
||||
LL | Baz::Bar { x: Baz::Foo(x, y), y: Baz::Foo(z, w) | Baz::Bar { x: z, y: w } } => {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&mut Baz<Baz<T, U>, Baz<T, U>>>`, found `Baz<_, _>`
|
||||
|
|
||||
= note: expected struct `Pin<&mut Baz<Baz<T, U>, Baz<T, U>>>`
|
||||
found enum `Baz<_, _>`
|
||||
help: consider dereferencing to access the inner value using the Deref trait
|
||||
|
|
||||
LL | match *baz {
|
||||
| +
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/pattern-matching.rs:133:9
|
||||
|
|
||||
LL | match baz {
|
||||
| --- this expression has type `Pin<&mut Baz<Baz<T, U>, Baz<T, U>>>`
|
||||
...
|
||||
LL | Baz::Bar { x: Baz::Bar { x, y }, y: Baz::Foo(z, w) | Baz::Bar { x: z, y: w } } => {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&mut Baz<Baz<T, U>, Baz<T, U>>>`, found `Baz<_, _>`
|
||||
|
|
||||
= note: expected struct `Pin<&mut Baz<Baz<T, U>, Baz<T, U>>>`
|
||||
found enum `Baz<_, _>`
|
||||
help: consider dereferencing to access the inner value using the Deref trait
|
||||
|
|
||||
LL | match *baz {
|
||||
| +
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/pattern-matching.rs:145:9
|
||||
|
|
||||
LL | match baz {
|
||||
| --- this expression has type `Pin<&Baz<Baz<T, U>, Baz<T, U>>>`
|
||||
LL | Baz::Foo(foo, _) if let Baz::Foo(x, y) = foo => {
|
||||
| ^^^^^^^^^^^^^^^^ expected `Pin<&Baz<Baz<T, U>, Baz<T, U>>>`, found `Baz<_, _>`
|
||||
|
|
||||
= note: expected struct `Pin<&Baz<Baz<T, U>, Baz<T, U>>>`
|
||||
found enum `Baz<_, _>`
|
||||
help: consider dereferencing to access the inner value using the Deref trait
|
||||
|
|
||||
LL | match *baz {
|
||||
| +
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/pattern-matching.rs:150:9
|
||||
|
|
||||
LL | match baz {
|
||||
| --- this expression has type `Pin<&Baz<Baz<T, U>, Baz<T, U>>>`
|
||||
...
|
||||
LL | Baz::Bar { x: _, y: bar } if let Baz::Bar { x, y } = bar => {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&Baz<Baz<T, U>, Baz<T, U>>>`, found `Baz<_, _>`
|
||||
|
|
||||
= note: expected struct `Pin<&Baz<Baz<T, U>, Baz<T, U>>>`
|
||||
found enum `Baz<_, _>`
|
||||
help: consider dereferencing to access the inner value using the Deref trait
|
||||
|
|
||||
LL | match *baz {
|
||||
| +
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/pattern-matching.rs:155:9
|
||||
|
|
||||
LL | match baz {
|
||||
| --- this expression has type `Pin<&Baz<Baz<T, U>, Baz<T, U>>>`
|
||||
...
|
||||
LL | Baz::Foo(Baz::Foo(x, y), Baz::Foo(z, w) | Baz::Bar { x: z, y: w }) => {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&Baz<Baz<T, U>, Baz<T, U>>>`, found `Baz<_, _>`
|
||||
|
|
||||
= note: expected struct `Pin<&Baz<Baz<T, U>, Baz<T, U>>>`
|
||||
found enum `Baz<_, _>`
|
||||
help: consider dereferencing to access the inner value using the Deref trait
|
||||
|
|
||||
LL | match *baz {
|
||||
| +
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/pattern-matching.rs:162:9
|
||||
|
|
||||
LL | match baz {
|
||||
| --- this expression has type `Pin<&Baz<Baz<T, U>, Baz<T, U>>>`
|
||||
...
|
||||
LL | Baz::Foo(Baz::Bar { x, y }, Baz::Foo(z, w) | Baz::Bar { x: z, y: w }) => {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&Baz<Baz<T, U>, Baz<T, U>>>`, found `Baz<_, _>`
|
||||
|
|
||||
= note: expected struct `Pin<&Baz<Baz<T, U>, Baz<T, U>>>`
|
||||
found enum `Baz<_, _>`
|
||||
help: consider dereferencing to access the inner value using the Deref trait
|
||||
|
|
||||
LL | match *baz {
|
||||
| +
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/pattern-matching.rs:169:9
|
||||
|
|
||||
LL | match baz {
|
||||
| --- this expression has type `Pin<&Baz<Baz<T, U>, Baz<T, U>>>`
|
||||
...
|
||||
LL | Baz::Bar { x: Baz::Foo(x, y), y: Baz::Foo(z, w) | Baz::Bar { x: z, y: w } } => {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&Baz<Baz<T, U>, Baz<T, U>>>`, found `Baz<_, _>`
|
||||
|
|
||||
= note: expected struct `Pin<&Baz<Baz<T, U>, Baz<T, U>>>`
|
||||
found enum `Baz<_, _>`
|
||||
help: consider dereferencing to access the inner value using the Deref trait
|
||||
|
|
||||
LL | match *baz {
|
||||
| +
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/pattern-matching.rs:176:9
|
||||
|
|
||||
LL | match baz {
|
||||
| --- this expression has type `Pin<&Baz<Baz<T, U>, Baz<T, U>>>`
|
||||
...
|
||||
LL | Baz::Bar { x: Baz::Bar { x, y }, y: Baz::Foo(z, w) | Baz::Bar { x: z, y: w } } => {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<&Baz<Baz<T, U>, Baz<T, U>>>`, found `Baz<_, _>`
|
||||
|
|
||||
= note: expected struct `Pin<&Baz<Baz<T, U>, Baz<T, U>>>`
|
||||
found enum `Baz<_, _>`
|
||||
help: consider dereferencing to access the inner value using the Deref trait
|
||||
|
|
||||
LL | match *baz {
|
||||
| +
|
||||
|
||||
error: aborting due to 20 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
186
tests/ui/pin-ergonomics/pattern-matching.rs
Normal file
186
tests/ui/pin-ergonomics/pattern-matching.rs
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
//@ revisions: pin_ergonomics normal
|
||||
//@ edition:2024
|
||||
//@[pin_ergonomics] check-pass
|
||||
#![cfg_attr(pin_ergonomics, feature(pin_ergonomics))]
|
||||
#![feature(if_let_guard)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
use std::pin::Pin;
|
||||
|
||||
// This test verifies that a `&pin mut Foo` can be projected to a pinned
|
||||
// reference `&pin mut T` of a `?Unpin` field , and can be projected to
|
||||
// an unpinned reference `&mut U` of an `Unpin` field.
|
||||
|
||||
struct Foo<T, U> {
|
||||
x: T,
|
||||
y: U,
|
||||
}
|
||||
|
||||
struct Bar<T, U>(T, U);
|
||||
|
||||
enum Baz<T, U> {
|
||||
Foo(T, U),
|
||||
Bar { x: T, y: U },
|
||||
}
|
||||
|
||||
trait IsPinMut {}
|
||||
trait IsPinConst {}
|
||||
impl<T: ?Sized> IsPinMut for Pin<&mut T> {}
|
||||
impl<T: ?Sized> IsPinConst for Pin<&T> {}
|
||||
|
||||
fn assert_pin_mut<T: IsPinMut>(_: T) {}
|
||||
fn assert_pin_const<T: IsPinConst>(_: T) {}
|
||||
|
||||
fn foo_mut<T, U: Unpin>(foo: Pin<&mut Foo<T, U>>) {
|
||||
let Foo { x, y } = foo;
|
||||
//[normal]~^ ERROR mismatched types
|
||||
assert_pin_mut(x);
|
||||
assert_pin_mut(y);
|
||||
}
|
||||
|
||||
fn foo_const<T, U: Unpin>(foo: Pin<&Foo<T, U>>) {
|
||||
let Foo { x, y } = foo;
|
||||
//[normal]~^ ERROR mismatched types
|
||||
assert_pin_const(x);
|
||||
assert_pin_const(y);
|
||||
}
|
||||
|
||||
fn bar_mut<T, U: Unpin>(bar: Pin<&mut Bar<T, U>>) {
|
||||
let Bar(x, y) = bar;
|
||||
//[normal]~^ ERROR mismatched types
|
||||
assert_pin_mut(x);
|
||||
assert_pin_mut(y);
|
||||
}
|
||||
|
||||
fn bar_const<T, U: Unpin>(bar: Pin<&Bar<T, U>>) {
|
||||
let Bar(x, y) = bar;
|
||||
//[normal]~^ ERROR mismatched types
|
||||
assert_pin_const(x);
|
||||
assert_pin_const(y);
|
||||
}
|
||||
|
||||
fn foo_bar_mut<T, U: Unpin>(foo: Pin<&mut Foo<Bar<T, U>, Bar<T, U>>>) {
|
||||
let Foo { x: Bar(x, y), y: Bar(z, w) } = foo;
|
||||
//[normal]~^ ERROR mismatched types
|
||||
assert_pin_mut(x);
|
||||
assert_pin_mut(y);
|
||||
assert_pin_mut(z);
|
||||
assert_pin_mut(w);
|
||||
}
|
||||
|
||||
fn foo_bar_const<T, U: Unpin>(foo: Pin<&Foo<Bar<T, U>, Bar<T, U>>>) {
|
||||
let Foo { x: Bar(x, y), y: Bar(z, w) } = foo;
|
||||
//[normal]~^ ERROR mismatched types
|
||||
assert_pin_const(x);
|
||||
assert_pin_const(y);
|
||||
assert_pin_const(z);
|
||||
assert_pin_const(w);
|
||||
}
|
||||
|
||||
fn baz_mut<T, U: Unpin>(baz: Pin<&mut Baz<T, U>>) {
|
||||
match baz {
|
||||
Baz::Foo(x, y) => {
|
||||
//[normal]~^ ERROR mismatched types
|
||||
assert_pin_mut(x);
|
||||
assert_pin_mut(y);
|
||||
}
|
||||
Baz::Bar { x, y } => {
|
||||
//[normal]~^ ERROR mismatched types
|
||||
assert_pin_mut(x);
|
||||
assert_pin_mut(y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn baz_const<T, U: Unpin>(baz: Pin<&Baz<T, U>>) {
|
||||
match baz {
|
||||
Baz::Foo(x, y) => {
|
||||
//[normal]~^ ERROR mismatched types
|
||||
assert_pin_const(x);
|
||||
assert_pin_const(y);
|
||||
}
|
||||
Baz::Bar { x, y } => {
|
||||
//[normal]~^ ERROR mismatched types
|
||||
assert_pin_const(x);
|
||||
assert_pin_const(y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn baz_baz_mut<T, U: Unpin>(baz: Pin<&mut Baz<Baz<T, U>, Baz<T, U>>>) {
|
||||
match baz {
|
||||
Baz::Foo(Baz::Foo(x, y), Baz::Foo(z, w) | Baz::Bar { x: z, y: w }) => {
|
||||
//[normal]~^ ERROR mismatched types
|
||||
assert_pin_mut(x);
|
||||
assert_pin_mut(y);
|
||||
assert_pin_mut(z);
|
||||
assert_pin_mut(w);
|
||||
}
|
||||
Baz::Foo(Baz::Bar { x, y }, Baz::Foo(z, w) | Baz::Bar { x: z, y: w }) => {
|
||||
//[normal]~^ ERROR mismatched types
|
||||
assert_pin_mut(x);
|
||||
assert_pin_mut(y);
|
||||
assert_pin_mut(z);
|
||||
assert_pin_mut(w);
|
||||
}
|
||||
Baz::Bar { x: Baz::Foo(x, y), y: Baz::Foo(z, w) | Baz::Bar { x: z, y: w } } => {
|
||||
//[normal]~^ ERROR mismatched types
|
||||
assert_pin_mut(x);
|
||||
assert_pin_mut(y);
|
||||
assert_pin_mut(z);
|
||||
assert_pin_mut(w);
|
||||
}
|
||||
Baz::Bar { x: Baz::Bar { x, y }, y: Baz::Foo(z, w) | Baz::Bar { x: z, y: w } } => {
|
||||
//[normal]~^ ERROR mismatched types
|
||||
assert_pin_mut(x);
|
||||
assert_pin_mut(y);
|
||||
assert_pin_mut(z);
|
||||
assert_pin_mut(w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn baz_baz_const<T, U: Unpin>(baz: Pin<&Baz<Baz<T, U>, Baz<T, U>>>) {
|
||||
match baz {
|
||||
Baz::Foo(foo, _) if let Baz::Foo(x, y) = foo => {
|
||||
//[normal]~^ ERROR mismatched types
|
||||
assert_pin_const(x);
|
||||
assert_pin_const(y);
|
||||
}
|
||||
Baz::Bar { x: _, y: bar } if let Baz::Bar { x, y } = bar => {
|
||||
//[normal]~^ ERROR mismatched types
|
||||
assert_pin_const(x);
|
||||
assert_pin_const(y);
|
||||
}
|
||||
Baz::Foo(Baz::Foo(x, y), Baz::Foo(z, w) | Baz::Bar { x: z, y: w }) => {
|
||||
//[normal]~^ ERROR mismatched types
|
||||
assert_pin_const(x);
|
||||
assert_pin_const(y);
|
||||
assert_pin_const(z);
|
||||
assert_pin_const(w);
|
||||
}
|
||||
Baz::Foo(Baz::Bar { x, y }, Baz::Foo(z, w) | Baz::Bar { x: z, y: w }) => {
|
||||
//[normal]~^ ERROR mismatched types
|
||||
assert_pin_const(x);
|
||||
assert_pin_const(y);
|
||||
assert_pin_const(z);
|
||||
assert_pin_const(w);
|
||||
}
|
||||
Baz::Bar { x: Baz::Foo(x, y), y: Baz::Foo(z, w) | Baz::Bar { x: z, y: w } } => {
|
||||
//[normal]~^ ERROR mismatched types
|
||||
assert_pin_const(x);
|
||||
assert_pin_const(y);
|
||||
assert_pin_const(z);
|
||||
assert_pin_const(w);
|
||||
}
|
||||
Baz::Bar { x: Baz::Bar { x, y }, y: Baz::Foo(z, w) | Baz::Bar { x: z, y: w } } => {
|
||||
//[normal]~^ ERROR mismatched types
|
||||
assert_pin_const(x);
|
||||
assert_pin_const(y);
|
||||
assert_pin_const(z);
|
||||
assert_pin_const(w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
Loading…
Add table
Add a link
Reference in a new issue