Auto merge of #96515 - lcnr:user-types-in-pat, r=nikomatsakis
correctly deal with user type ascriptions in pat supersedes #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 #96514 which is pretty much the same issue r? `@nikomatsakis`
This commit is contained in:
commit
e52e7115c7
21 changed files with 304 additions and 189 deletions
|
@ -523,8 +523,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
},
|
||||
..
|
||||
},
|
||||
ascription:
|
||||
thir::Ascription { user_ty: pat_ascription_ty, variance: _, user_ty_span },
|
||||
ascription: thir::Ascription { annotation, variance: _ },
|
||||
} => {
|
||||
let place =
|
||||
self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true);
|
||||
|
@ -535,18 +534,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
let cause_let = FakeReadCause::ForLet(None);
|
||||
self.cfg.push_fake_read(block, pattern_source_info, cause_let, place);
|
||||
|
||||
let ty_source_info = self.source_info(user_ty_span);
|
||||
let user_ty = pat_ascription_ty.user_ty(
|
||||
&mut self.canonical_user_type_annotations,
|
||||
place.ty(&self.local_decls, self.tcx).ty,
|
||||
ty_source_info.span,
|
||||
);
|
||||
let ty_source_info = self.source_info(annotation.span);
|
||||
|
||||
let base = self.canonical_user_type_annotations.push(annotation);
|
||||
self.cfg.push(
|
||||
block,
|
||||
Statement {
|
||||
source_info: ty_source_info,
|
||||
kind: StatementKind::AscribeUserType(
|
||||
Box::new((place, user_ty)),
|
||||
Box::new((place, UserTypeProjection { base, projs: Vec::new() })),
|
||||
// We always use invariant as the variance here. This is because the
|
||||
// variance field from the ascription refers to the variance to use
|
||||
// when applying the type to the value being matched, but this
|
||||
|
@ -789,7 +785,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
|
||||
PatKind::AscribeUserType {
|
||||
ref subpattern,
|
||||
ascription: thir::Ascription { ref user_ty, user_ty_span, variance: _ },
|
||||
ascription: thir::Ascription { ref annotation, variance: _ },
|
||||
} => {
|
||||
// This corresponds to something like
|
||||
//
|
||||
|
@ -799,16 +795,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
//
|
||||
// Note that the variance doesn't apply here, as we are tracking the effect
|
||||
// of `user_ty` on any bindings contained with subpattern.
|
||||
let annotation = CanonicalUserTypeAnnotation {
|
||||
span: user_ty_span,
|
||||
user_ty: user_ty.user_ty,
|
||||
inferred_ty: subpattern.ty,
|
||||
};
|
||||
|
||||
let projection = UserTypeProjection {
|
||||
base: self.canonical_user_type_annotations.push(annotation),
|
||||
base: self.canonical_user_type_annotations.push(annotation.clone()),
|
||||
projs: Vec::new(),
|
||||
};
|
||||
let subpattern_user_ty = pattern_user_ty.push_projection(&projection, user_ty_span);
|
||||
let subpattern_user_ty =
|
||||
pattern_user_ty.push_projection(&projection, annotation.span);
|
||||
self.visit_primary_bindings(subpattern, subpattern_user_ty, f)
|
||||
}
|
||||
|
||||
|
@ -932,9 +925,8 @@ struct Binding<'tcx> {
|
|||
/// influence region inference.
|
||||
#[derive(Clone, Debug)]
|
||||
struct Ascription<'tcx> {
|
||||
span: Span,
|
||||
source: Place<'tcx>,
|
||||
user_ty: PatTyProj<'tcx>,
|
||||
annotation: CanonicalUserTypeAnnotation<'tcx>,
|
||||
variance: ty::Variance,
|
||||
}
|
||||
|
||||
|
@ -1863,7 +1855,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
parent_bindings
|
||||
.iter()
|
||||
.flat_map(|(_, ascriptions)| ascriptions)
|
||||
.chain(&candidate.ascriptions),
|
||||
.cloned()
|
||||
.chain(candidate.ascriptions),
|
||||
);
|
||||
|
||||
// rust-lang/rust#27282: The `autoref` business deserves some
|
||||
|
@ -2067,32 +2060,24 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
|
||||
/// Append `AscribeUserType` statements onto the end of `block`
|
||||
/// for each ascription
|
||||
fn ascribe_types<'b>(
|
||||
fn ascribe_types(
|
||||
&mut self,
|
||||
block: BasicBlock,
|
||||
ascriptions: impl IntoIterator<Item = &'b Ascription<'tcx>>,
|
||||
) where
|
||||
'tcx: 'b,
|
||||
{
|
||||
ascriptions: impl IntoIterator<Item = Ascription<'tcx>>,
|
||||
) {
|
||||
for ascription in ascriptions {
|
||||
let source_info = self.source_info(ascription.span);
|
||||
let source_info = self.source_info(ascription.annotation.span);
|
||||
|
||||
debug!(
|
||||
"adding user ascription at span {:?} of place {:?} and {:?}",
|
||||
source_info.span, ascription.source, ascription.user_ty,
|
||||
);
|
||||
|
||||
let user_ty = ascription.user_ty.user_ty(
|
||||
&mut self.canonical_user_type_annotations,
|
||||
ascription.source.ty(&self.local_decls, self.tcx).ty,
|
||||
source_info.span,
|
||||
);
|
||||
let base = self.canonical_user_type_annotations.push(ascription.annotation);
|
||||
self.cfg.push(
|
||||
block,
|
||||
Statement {
|
||||
source_info,
|
||||
kind: StatementKind::AscribeUserType(
|
||||
Box::new((ascription.source, user_ty)),
|
||||
Box::new((
|
||||
ascription.source,
|
||||
UserTypeProjection { base, projs: Vec::new() },
|
||||
)),
|
||||
ascription.variance,
|
||||
),
|
||||
},
|
||||
|
|
|
@ -152,15 +152,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
match *match_pair.pattern.kind {
|
||||
PatKind::AscribeUserType {
|
||||
ref subpattern,
|
||||
ascription: thir::Ascription { variance, user_ty, user_ty_span },
|
||||
ascription: thir::Ascription { ref annotation, variance },
|
||||
} => {
|
||||
// Apply the type ascription to the value at `match_pair.place`, which is the
|
||||
if let Ok(place_resolved) =
|
||||
match_pair.place.clone().try_upvars_resolved(self.tcx, self.typeck_results)
|
||||
{
|
||||
candidate.ascriptions.push(Ascription {
|
||||
span: user_ty_span,
|
||||
user_ty,
|
||||
annotation: annotation.clone(),
|
||||
source: place_resolved.into_place(self.tcx, self.typeck_results),
|
||||
variance,
|
||||
});
|
||||
|
|
|
@ -6,6 +6,7 @@ use rustc_middle::thir::*;
|
|||
use rustc_middle::ty;
|
||||
|
||||
use rustc_index::vec::Idx;
|
||||
use rustc_middle::ty::CanonicalUserTypeAnnotation;
|
||||
|
||||
impl<'tcx> Cx<'tcx> {
|
||||
pub(crate) fn mirror_block(&mut self, block: &'tcx hir::Block<'tcx>) -> Block {
|
||||
|
@ -80,13 +81,17 @@ impl<'tcx> Cx<'tcx> {
|
|||
self.typeck_results.user_provided_types().get(ty.hir_id)
|
||||
{
|
||||
debug!("mirror_stmts: user_ty={:?}", user_ty);
|
||||
let annotation = CanonicalUserTypeAnnotation {
|
||||
user_ty,
|
||||
span: ty.span,
|
||||
inferred_ty: self.typeck_results.node_type(ty.hir_id),
|
||||
};
|
||||
pattern = Pat {
|
||||
ty: pattern.ty,
|
||||
span: pattern.span,
|
||||
kind: Box::new(PatKind::AscribeUserType {
|
||||
ascription: Ascription {
|
||||
user_ty: PatTyProj::from_user_type(user_ty),
|
||||
user_ty_span: ty.span,
|
||||
annotation,
|
||||
variance: ty::Variance::Covariant,
|
||||
},
|
||||
subpattern: pattern,
|
||||
|
|
|
@ -19,8 +19,9 @@ use rustc_middle::mir::interpret::{get_slice_bytes, ConstValue};
|
|||
use rustc_middle::mir::interpret::{ErrorHandled, LitToConstError, LitToConstInput};
|
||||
use rustc_middle::mir::{self, UserTypeProjection};
|
||||
use rustc_middle::mir::{BorrowKind, Field, Mutability};
|
||||
use rustc_middle::thir::{Ascription, BindingMode, FieldPat, Pat, PatKind, PatRange, PatTyProj};
|
||||
use rustc_middle::thir::{Ascription, BindingMode, FieldPat, Pat, PatKind, PatRange};
|
||||
use rustc_middle::ty::subst::{GenericArg, SubstsRef};
|
||||
use rustc_middle::ty::CanonicalUserTypeAnnotation;
|
||||
use rustc_middle::ty::{self, AdtDef, ConstKind, DefIdTree, Region, Ty, TyCtxt, UserType};
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
||||
|
@ -227,7 +228,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
for end in &[lo, hi] {
|
||||
if let Some((_, Some(ascription))) = end {
|
||||
let subpattern = Pat { span: pat.span, ty, kind: Box::new(kind) };
|
||||
kind = PatKind::AscribeUserType { ascription: *ascription, subpattern };
|
||||
kind =
|
||||
PatKind::AscribeUserType { ascription: ascription.clone(), subpattern };
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -432,13 +434,14 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
|
||||
if let Some(user_ty) = self.user_substs_applied_to_ty_of_hir_id(hir_id) {
|
||||
debug!("lower_variant_or_leaf: kind={:?} user_ty={:?} span={:?}", kind, user_ty, span);
|
||||
let annotation = CanonicalUserTypeAnnotation {
|
||||
user_ty,
|
||||
span,
|
||||
inferred_ty: self.typeck_results.node_type(hir_id),
|
||||
};
|
||||
kind = PatKind::AscribeUserType {
|
||||
subpattern: Pat { span, ty, kind: Box::new(kind) },
|
||||
ascription: Ascription {
|
||||
user_ty: PatTyProj::from_user_type(user_ty),
|
||||
user_ty_span: span,
|
||||
variance: ty::Variance::Covariant,
|
||||
},
|
||||
ascription: Ascription { annotation, variance: ty::Variance::Covariant },
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -499,18 +502,21 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
let user_provided_types = self.typeck_results().user_provided_types();
|
||||
if let Some(u_ty) = user_provided_types.get(id) {
|
||||
let user_ty = PatTyProj::from_user_type(*u_ty);
|
||||
if let Some(&user_ty) = user_provided_types.get(id) {
|
||||
let annotation = CanonicalUserTypeAnnotation {
|
||||
user_ty,
|
||||
span,
|
||||
inferred_ty: self.typeck_results().node_type(id),
|
||||
};
|
||||
Pat {
|
||||
span,
|
||||
kind: Box::new(PatKind::AscribeUserType {
|
||||
subpattern: pattern,
|
||||
ascription: Ascription {
|
||||
annotation,
|
||||
/// Note that use `Contravariant` here. See the
|
||||
/// `variance` field documentation for details.
|
||||
variance: ty::Variance::Contravariant,
|
||||
user_ty,
|
||||
user_ty_span: span,
|
||||
},
|
||||
}),
|
||||
ty: const_.ty(),
|
||||
|
@ -645,7 +651,7 @@ impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Option<T> {
|
|||
}
|
||||
}
|
||||
|
||||
macro_rules! CloneImpls {
|
||||
macro_rules! ClonePatternFoldableImpls {
|
||||
(<$lt_tcx:tt> $($ty:ty),+) => {
|
||||
$(
|
||||
impl<$lt_tcx> PatternFoldable<$lt_tcx> for $ty {
|
||||
|
@ -657,11 +663,11 @@ macro_rules! CloneImpls {
|
|||
}
|
||||
}
|
||||
|
||||
CloneImpls! { <'tcx>
|
||||
ClonePatternFoldableImpls! { <'tcx>
|
||||
Span, Field, Mutability, Symbol, hir::HirId, usize, ty::Const<'tcx>,
|
||||
Region<'tcx>, Ty<'tcx>, BindingMode, AdtDef<'tcx>,
|
||||
SubstsRef<'tcx>, &'tcx GenericArg<'tcx>, UserType<'tcx>,
|
||||
UserTypeProjection, PatTyProj<'tcx>
|
||||
UserTypeProjection, CanonicalUserTypeAnnotation<'tcx>
|
||||
}
|
||||
|
||||
impl<'tcx> PatternFoldable<'tcx> for FieldPat<'tcx> {
|
||||
|
@ -694,14 +700,10 @@ impl<'tcx> PatternFoldable<'tcx> for PatKind<'tcx> {
|
|||
PatKind::Wild => PatKind::Wild,
|
||||
PatKind::AscribeUserType {
|
||||
ref subpattern,
|
||||
ascription: Ascription { variance, ref user_ty, user_ty_span },
|
||||
ascription: Ascription { ref annotation, variance },
|
||||
} => PatKind::AscribeUserType {
|
||||
subpattern: subpattern.fold_with(folder),
|
||||
ascription: Ascription {
|
||||
user_ty: user_ty.fold_with(folder),
|
||||
variance,
|
||||
user_ty_span,
|
||||
},
|
||||
ascription: Ascription { annotation: annotation.fold_with(folder), variance },
|
||||
},
|
||||
PatKind::Binding { mutability, name, mode, var, ty, ref subpattern, is_primary } => {
|
||||
PatKind::Binding {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue