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:
bors 2022-05-21 23:34:30 +00:00
commit e52e7115c7
21 changed files with 304 additions and 189 deletions

View file

@ -1007,10 +1007,11 @@ fn write_user_type_annotations(
for (index, annotation) in body.user_type_annotations.iter_enumerated() {
writeln!(
w,
"| {:?}: {:?} at {}",
"| {:?}: user_ty: {:?}, span: {}, inferred_ty: {:?}",
index.index(),
annotation.user_ty,
tcx.sess.source_map().span_to_embeddable_string(annotation.span)
tcx.sess.source_map().span_to_embeddable_string(annotation.span),
annotation.inferred_ty,
)?;
}
if !body.user_type_annotations.is_empty() {

View file

@ -18,15 +18,11 @@ use rustc_index::vec::IndexVec;
use rustc_middle::infer::canonical::Canonical;
use rustc_middle::middle::region;
use rustc_middle::mir::interpret::AllocId;
use rustc_middle::mir::{
self, BinOp, BorrowKind, FakeReadCause, Field, Mutability, UnOp, UserTypeProjection,
};
use rustc_middle::mir::{self, BinOp, BorrowKind, FakeReadCause, Field, Mutability, UnOp};
use rustc_middle::ty::adjustment::PointerCast;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::CanonicalUserTypeAnnotation;
use rustc_middle::ty::{self, AdtDef, Ty, UpvarSubsts, UserType};
use rustc_middle::ty::{
CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
};
use rustc_span::{Span, Symbol, DUMMY_SP};
use rustc_target::abi::VariantIdx;
use rustc_target::asm::InlineAsmRegOrRegClass;
@ -540,13 +536,13 @@ pub enum BindingMode {
ByRef(BorrowKind),
}
#[derive(Clone, Debug, PartialEq, HashStable)]
#[derive(Clone, Debug, HashStable)]
pub struct FieldPat<'tcx> {
pub field: Field,
pub pattern: Pat<'tcx>,
}
#[derive(Clone, Debug, PartialEq, HashStable)]
#[derive(Clone, Debug, HashStable)]
pub struct Pat<'tcx> {
pub ty: Ty<'tcx>,
pub span: Span,
@ -559,37 +555,10 @@ impl<'tcx> Pat<'tcx> {
}
}
#[derive(Copy, Clone, Debug, PartialEq, HashStable)]
pub struct PatTyProj<'tcx> {
pub user_ty: CanonicalUserType<'tcx>,
}
impl<'tcx> PatTyProj<'tcx> {
pub fn from_user_type(user_annotation: CanonicalUserType<'tcx>) -> Self {
Self { user_ty: user_annotation }
}
pub fn user_ty(
self,
annotations: &mut CanonicalUserTypeAnnotations<'tcx>,
inferred_ty: Ty<'tcx>,
span: Span,
) -> UserTypeProjection {
UserTypeProjection {
base: annotations.push(CanonicalUserTypeAnnotation {
span,
user_ty: self.user_ty,
inferred_ty,
}),
projs: Vec::new(),
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, HashStable)]
#[derive(Clone, Debug, HashStable)]
pub struct Ascription<'tcx> {
pub user_ty: PatTyProj<'tcx>,
/// Variance to use when relating the type `user_ty` to the **type of the value being
pub annotation: CanonicalUserTypeAnnotation<'tcx>,
/// Variance to use when relating the `user_ty` to the **type of the value being
/// matched**. Typically, this is `Variance::Covariant`, since the value being matched must
/// have a type that is some subtype of the ascribed type.
///
@ -608,12 +577,11 @@ pub struct Ascription<'tcx> {
/// probably be checking for a `PartialEq` impl instead, but this preserves the behavior
/// of the old type-check for now. See #57280 for details.
pub variance: ty::Variance,
pub user_ty_span: Span,
}
#[derive(Clone, Debug, PartialEq, HashStable)]
#[derive(Clone, Debug, HashStable)]
pub enum PatKind<'tcx> {
/// A wildward pattern: `_`.
/// A wildcard pattern: `_`.
Wild,
AscribeUserType {