Skip to content

Commit e52e711

Browse files
committed
Auto merge of rust-lang#96515 - lcnr:user-types-in-pat, r=nikomatsakis
correctly deal with user type ascriptions in pat supersedes rust-lang#93856 `thir::PatKind::AscribeUserType` previously resulted in `CanonicalUserTypeAnnotations` where the inferred type already had a subtyping relation according to `variance` to the `user_ty`. The bug can pretty much be summarized as follows: - during mir building - `user_ty -> inferred_ty`: considers variance - `StatementKind::AscribeUserType`: `inferred_ty` is the type of the place, so no variance needed - during mir borrowck - `user_ty -> inferred_ty`: does not consider variance - `StatementKind::AscribeUserType`: applies variance This mostly worked fine. The lifetimes in `inferred_ty` were only bound by its relation to `user_ty` and to the `place` of `StatementKind::AscribeUserType`, so it doesn't matter where exactly the subtyping happens. It does however matter when having higher ranked subtying. At this point the place where the subtyping happens is forced, causing this mismatch between building and borrowck to result in unintended errors. cc rust-lang#96514 which is pretty much the same issue r? `@nikomatsakis`
2 parents 9257f5a + 7637008 commit e52e711

21 files changed

+304
-189
lines changed

Diff for: compiler/rustc_middle/src/mir/pretty.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1007,10 +1007,11 @@ fn write_user_type_annotations(
10071007
for (index, annotation) in body.user_type_annotations.iter_enumerated() {
10081008
writeln!(
10091009
w,
1010-
"| {:?}: {:?} at {}",
1010+
"| {:?}: user_ty: {:?}, span: {}, inferred_ty: {:?}",
10111011
index.index(),
10121012
annotation.user_ty,
1013-
tcx.sess.source_map().span_to_embeddable_string(annotation.span)
1013+
tcx.sess.source_map().span_to_embeddable_string(annotation.span),
1014+
annotation.inferred_ty,
10141015
)?;
10151016
}
10161017
if !body.user_type_annotations.is_empty() {

Diff for: compiler/rustc_middle/src/thir.rs

+9-41
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,11 @@ use rustc_index::vec::IndexVec;
1818
use rustc_middle::infer::canonical::Canonical;
1919
use rustc_middle::middle::region;
2020
use rustc_middle::mir::interpret::AllocId;
21-
use rustc_middle::mir::{
22-
self, BinOp, BorrowKind, FakeReadCause, Field, Mutability, UnOp, UserTypeProjection,
23-
};
21+
use rustc_middle::mir::{self, BinOp, BorrowKind, FakeReadCause, Field, Mutability, UnOp};
2422
use rustc_middle::ty::adjustment::PointerCast;
2523
use rustc_middle::ty::subst::SubstsRef;
24+
use rustc_middle::ty::CanonicalUserTypeAnnotation;
2625
use rustc_middle::ty::{self, AdtDef, Ty, UpvarSubsts, UserType};
27-
use rustc_middle::ty::{
28-
CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
29-
};
3026
use rustc_span::{Span, Symbol, DUMMY_SP};
3127
use rustc_target::abi::VariantIdx;
3228
use rustc_target::asm::InlineAsmRegOrRegClass;
@@ -540,13 +536,13 @@ pub enum BindingMode {
540536
ByRef(BorrowKind),
541537
}
542538

543-
#[derive(Clone, Debug, PartialEq, HashStable)]
539+
#[derive(Clone, Debug, HashStable)]
544540
pub struct FieldPat<'tcx> {
545541
pub field: Field,
546542
pub pattern: Pat<'tcx>,
547543
}
548544

549-
#[derive(Clone, Debug, PartialEq, HashStable)]
545+
#[derive(Clone, Debug, HashStable)]
550546
pub struct Pat<'tcx> {
551547
pub ty: Ty<'tcx>,
552548
pub span: Span,
@@ -559,37 +555,10 @@ impl<'tcx> Pat<'tcx> {
559555
}
560556
}
561557

562-
#[derive(Copy, Clone, Debug, PartialEq, HashStable)]
563-
pub struct PatTyProj<'tcx> {
564-
pub user_ty: CanonicalUserType<'tcx>,
565-
}
566-
567-
impl<'tcx> PatTyProj<'tcx> {
568-
pub fn from_user_type(user_annotation: CanonicalUserType<'tcx>) -> Self {
569-
Self { user_ty: user_annotation }
570-
}
571-
572-
pub fn user_ty(
573-
self,
574-
annotations: &mut CanonicalUserTypeAnnotations<'tcx>,
575-
inferred_ty: Ty<'tcx>,
576-
span: Span,
577-
) -> UserTypeProjection {
578-
UserTypeProjection {
579-
base: annotations.push(CanonicalUserTypeAnnotation {
580-
span,
581-
user_ty: self.user_ty,
582-
inferred_ty,
583-
}),
584-
projs: Vec::new(),
585-
}
586-
}
587-
}
588-
589-
#[derive(Copy, Clone, Debug, PartialEq, HashStable)]
558+
#[derive(Clone, Debug, HashStable)]
590559
pub struct Ascription<'tcx> {
591-
pub user_ty: PatTyProj<'tcx>,
592-
/// Variance to use when relating the type `user_ty` to the **type of the value being
560+
pub annotation: CanonicalUserTypeAnnotation<'tcx>,
561+
/// Variance to use when relating the `user_ty` to the **type of the value being
593562
/// matched**. Typically, this is `Variance::Covariant`, since the value being matched must
594563
/// have a type that is some subtype of the ascribed type.
595564
///
@@ -608,12 +577,11 @@ pub struct Ascription<'tcx> {
608577
/// probably be checking for a `PartialEq` impl instead, but this preserves the behavior
609578
/// of the old type-check for now. See #57280 for details.
610579
pub variance: ty::Variance,
611-
pub user_ty_span: Span,
612580
}
613581

614-
#[derive(Clone, Debug, PartialEq, HashStable)]
582+
#[derive(Clone, Debug, HashStable)]
615583
pub enum PatKind<'tcx> {
616-
/// A wildward pattern: `_`.
584+
/// A wildcard pattern: `_`.
617585
Wild,
618586

619587
AscribeUserType {

Diff for: compiler/rustc_mir_build/src/build/matches/mod.rs

+22-37
Original file line numberDiff line numberDiff line change
@@ -523,8 +523,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
523523
},
524524
..
525525
},
526-
ascription:
527-
thir::Ascription { user_ty: pat_ascription_ty, variance: _, user_ty_span },
526+
ascription: thir::Ascription { annotation, variance: _ },
528527
} => {
529528
let place =
530529
self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true);
@@ -535,18 +534,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
535534
let cause_let = FakeReadCause::ForLet(None);
536535
self.cfg.push_fake_read(block, pattern_source_info, cause_let, place);
537536

538-
let ty_source_info = self.source_info(user_ty_span);
539-
let user_ty = pat_ascription_ty.user_ty(
540-
&mut self.canonical_user_type_annotations,
541-
place.ty(&self.local_decls, self.tcx).ty,
542-
ty_source_info.span,
543-
);
537+
let ty_source_info = self.source_info(annotation.span);
538+
539+
let base = self.canonical_user_type_annotations.push(annotation);
544540
self.cfg.push(
545541
block,
546542
Statement {
547543
source_info: ty_source_info,
548544
kind: StatementKind::AscribeUserType(
549-
Box::new((place, user_ty)),
545+
Box::new((place, UserTypeProjection { base, projs: Vec::new() })),
550546
// We always use invariant as the variance here. This is because the
551547
// variance field from the ascription refers to the variance to use
552548
// when applying the type to the value being matched, but this
@@ -789,7 +785,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
789785

790786
PatKind::AscribeUserType {
791787
ref subpattern,
792-
ascription: thir::Ascription { ref user_ty, user_ty_span, variance: _ },
788+
ascription: thir::Ascription { ref annotation, variance: _ },
793789
} => {
794790
// This corresponds to something like
795791
//
@@ -799,16 +795,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
799795
//
800796
// Note that the variance doesn't apply here, as we are tracking the effect
801797
// of `user_ty` on any bindings contained with subpattern.
802-
let annotation = CanonicalUserTypeAnnotation {
803-
span: user_ty_span,
804-
user_ty: user_ty.user_ty,
805-
inferred_ty: subpattern.ty,
806-
};
798+
807799
let projection = UserTypeProjection {
808-
base: self.canonical_user_type_annotations.push(annotation),
800+
base: self.canonical_user_type_annotations.push(annotation.clone()),
809801
projs: Vec::new(),
810802
};
811-
let subpattern_user_ty = pattern_user_ty.push_projection(&projection, user_ty_span);
803+
let subpattern_user_ty =
804+
pattern_user_ty.push_projection(&projection, annotation.span);
812805
self.visit_primary_bindings(subpattern, subpattern_user_ty, f)
813806
}
814807

@@ -932,9 +925,8 @@ struct Binding<'tcx> {
932925
/// influence region inference.
933926
#[derive(Clone, Debug)]
934927
struct Ascription<'tcx> {
935-
span: Span,
936928
source: Place<'tcx>,
937-
user_ty: PatTyProj<'tcx>,
929+
annotation: CanonicalUserTypeAnnotation<'tcx>,
938930
variance: ty::Variance,
939931
}
940932

@@ -1863,7 +1855,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
18631855
parent_bindings
18641856
.iter()
18651857
.flat_map(|(_, ascriptions)| ascriptions)
1866-
.chain(&candidate.ascriptions),
1858+
.cloned()
1859+
.chain(candidate.ascriptions),
18671860
);
18681861

18691862
// rust-lang/rust#27282: The `autoref` business deserves some
@@ -2067,32 +2060,24 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
20672060

20682061
/// Append `AscribeUserType` statements onto the end of `block`
20692062
/// for each ascription
2070-
fn ascribe_types<'b>(
2063+
fn ascribe_types(
20712064
&mut self,
20722065
block: BasicBlock,
2073-
ascriptions: impl IntoIterator<Item = &'b Ascription<'tcx>>,
2074-
) where
2075-
'tcx: 'b,
2076-
{
2066+
ascriptions: impl IntoIterator<Item = Ascription<'tcx>>,
2067+
) {
20772068
for ascription in ascriptions {
2078-
let source_info = self.source_info(ascription.span);
2069+
let source_info = self.source_info(ascription.annotation.span);
20792070

2080-
debug!(
2081-
"adding user ascription at span {:?} of place {:?} and {:?}",
2082-
source_info.span, ascription.source, ascription.user_ty,
2083-
);
2084-
2085-
let user_ty = ascription.user_ty.user_ty(
2086-
&mut self.canonical_user_type_annotations,
2087-
ascription.source.ty(&self.local_decls, self.tcx).ty,
2088-
source_info.span,
2089-
);
2071+
let base = self.canonical_user_type_annotations.push(ascription.annotation);
20902072
self.cfg.push(
20912073
block,
20922074
Statement {
20932075
source_info,
20942076
kind: StatementKind::AscribeUserType(
2095-
Box::new((ascription.source, user_ty)),
2077+
Box::new((
2078+
ascription.source,
2079+
UserTypeProjection { base, projs: Vec::new() },
2080+
)),
20962081
ascription.variance,
20972082
),
20982083
},

Diff for: compiler/rustc_mir_build/src/build/matches/simplify.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -152,15 +152,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
152152
match *match_pair.pattern.kind {
153153
PatKind::AscribeUserType {
154154
ref subpattern,
155-
ascription: thir::Ascription { variance, user_ty, user_ty_span },
155+
ascription: thir::Ascription { ref annotation, variance },
156156
} => {
157157
// Apply the type ascription to the value at `match_pair.place`, which is the
158158
if let Ok(place_resolved) =
159159
match_pair.place.clone().try_upvars_resolved(self.tcx, self.typeck_results)
160160
{
161161
candidate.ascriptions.push(Ascription {
162-
span: user_ty_span,
163-
user_ty,
162+
annotation: annotation.clone(),
164163
source: place_resolved.into_place(self.tcx, self.typeck_results),
165164
variance,
166165
});

Diff for: compiler/rustc_mir_build/src/thir/cx/block.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use rustc_middle::thir::*;
66
use rustc_middle::ty;
77

88
use rustc_index::vec::Idx;
9+
use rustc_middle::ty::CanonicalUserTypeAnnotation;
910

1011
impl<'tcx> Cx<'tcx> {
1112
pub(crate) fn mirror_block(&mut self, block: &'tcx hir::Block<'tcx>) -> Block {
@@ -80,13 +81,17 @@ impl<'tcx> Cx<'tcx> {
8081
self.typeck_results.user_provided_types().get(ty.hir_id)
8182
{
8283
debug!("mirror_stmts: user_ty={:?}", user_ty);
84+
let annotation = CanonicalUserTypeAnnotation {
85+
user_ty,
86+
span: ty.span,
87+
inferred_ty: self.typeck_results.node_type(ty.hir_id),
88+
};
8389
pattern = Pat {
8490
ty: pattern.ty,
8591
span: pattern.span,
8692
kind: Box::new(PatKind::AscribeUserType {
8793
ascription: Ascription {
88-
user_ty: PatTyProj::from_user_type(user_ty),
89-
user_ty_span: ty.span,
94+
annotation,
9095
variance: ty::Variance::Covariant,
9196
},
9297
subpattern: pattern,

Diff for: compiler/rustc_mir_build/src/thir/pattern/mod.rs

+22-20
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,9 @@ use rustc_middle::mir::interpret::{get_slice_bytes, ConstValue};
1919
use rustc_middle::mir::interpret::{ErrorHandled, LitToConstError, LitToConstInput};
2020
use rustc_middle::mir::{self, UserTypeProjection};
2121
use rustc_middle::mir::{BorrowKind, Field, Mutability};
22-
use rustc_middle::thir::{Ascription, BindingMode, FieldPat, Pat, PatKind, PatRange, PatTyProj};
22+
use rustc_middle::thir::{Ascription, BindingMode, FieldPat, Pat, PatKind, PatRange};
2323
use rustc_middle::ty::subst::{GenericArg, SubstsRef};
24+
use rustc_middle::ty::CanonicalUserTypeAnnotation;
2425
use rustc_middle::ty::{self, AdtDef, ConstKind, DefIdTree, Region, Ty, TyCtxt, UserType};
2526
use rustc_span::{Span, Symbol};
2627

@@ -227,7 +228,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
227228
for end in &[lo, hi] {
228229
if let Some((_, Some(ascription))) = end {
229230
let subpattern = Pat { span: pat.span, ty, kind: Box::new(kind) };
230-
kind = PatKind::AscribeUserType { ascription: *ascription, subpattern };
231+
kind =
232+
PatKind::AscribeUserType { ascription: ascription.clone(), subpattern };
231233
}
232234
}
233235

@@ -432,13 +434,14 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
432434

433435
if let Some(user_ty) = self.user_substs_applied_to_ty_of_hir_id(hir_id) {
434436
debug!("lower_variant_or_leaf: kind={:?} user_ty={:?} span={:?}", kind, user_ty, span);
437+
let annotation = CanonicalUserTypeAnnotation {
438+
user_ty,
439+
span,
440+
inferred_ty: self.typeck_results.node_type(hir_id),
441+
};
435442
kind = PatKind::AscribeUserType {
436443
subpattern: Pat { span, ty, kind: Box::new(kind) },
437-
ascription: Ascription {
438-
user_ty: PatTyProj::from_user_type(user_ty),
439-
user_ty_span: span,
440-
variance: ty::Variance::Covariant,
441-
},
444+
ascription: Ascription { annotation, variance: ty::Variance::Covariant },
442445
};
443446
}
444447

@@ -499,18 +502,21 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
499502
}
500503

501504
let user_provided_types = self.typeck_results().user_provided_types();
502-
if let Some(u_ty) = user_provided_types.get(id) {
503-
let user_ty = PatTyProj::from_user_type(*u_ty);
505+
if let Some(&user_ty) = user_provided_types.get(id) {
506+
let annotation = CanonicalUserTypeAnnotation {
507+
user_ty,
508+
span,
509+
inferred_ty: self.typeck_results().node_type(id),
510+
};
504511
Pat {
505512
span,
506513
kind: Box::new(PatKind::AscribeUserType {
507514
subpattern: pattern,
508515
ascription: Ascription {
516+
annotation,
509517
/// Note that use `Contravariant` here. See the
510518
/// `variance` field documentation for details.
511519
variance: ty::Variance::Contravariant,
512-
user_ty,
513-
user_ty_span: span,
514520
},
515521
}),
516522
ty: const_.ty(),
@@ -645,7 +651,7 @@ impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Option<T> {
645651
}
646652
}
647653

648-
macro_rules! CloneImpls {
654+
macro_rules! ClonePatternFoldableImpls {
649655
(<$lt_tcx:tt> $($ty:ty),+) => {
650656
$(
651657
impl<$lt_tcx> PatternFoldable<$lt_tcx> for $ty {
@@ -657,11 +663,11 @@ macro_rules! CloneImpls {
657663
}
658664
}
659665

660-
CloneImpls! { <'tcx>
666+
ClonePatternFoldableImpls! { <'tcx>
661667
Span, Field, Mutability, Symbol, hir::HirId, usize, ty::Const<'tcx>,
662668
Region<'tcx>, Ty<'tcx>, BindingMode, AdtDef<'tcx>,
663669
SubstsRef<'tcx>, &'tcx GenericArg<'tcx>, UserType<'tcx>,
664-
UserTypeProjection, PatTyProj<'tcx>
670+
UserTypeProjection, CanonicalUserTypeAnnotation<'tcx>
665671
}
666672

667673
impl<'tcx> PatternFoldable<'tcx> for FieldPat<'tcx> {
@@ -694,14 +700,10 @@ impl<'tcx> PatternFoldable<'tcx> for PatKind<'tcx> {
694700
PatKind::Wild => PatKind::Wild,
695701
PatKind::AscribeUserType {
696702
ref subpattern,
697-
ascription: Ascription { variance, ref user_ty, user_ty_span },
703+
ascription: Ascription { ref annotation, variance },
698704
} => PatKind::AscribeUserType {
699705
subpattern: subpattern.fold_with(folder),
700-
ascription: Ascription {
701-
user_ty: user_ty.fold_with(folder),
702-
variance,
703-
user_ty_span,
704-
},
706+
ascription: Ascription { annotation: annotation.fold_with(folder), variance },
705707
},
706708
PatKind::Binding { mutability, name, mode, var, ty, ref subpattern, is_primary } => {
707709
PatKind::Binding {

0 commit comments

Comments
 (0)