diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 26e070af764..b99e7573000 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -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 { diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 05b1342cf8c..6225193ea1a 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -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 @@ -784,7 +780,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 // @@ -794,16 +790,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) } @@ -927,9 +920,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, } @@ -1858,7 +1850,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 @@ -2062,32 +2055,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>, - ) where - 'tcx: 'b, - { + ascriptions: impl IntoIterator>, + ) { 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, ), }, diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index 895df5808db..b4a0c965d6b 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -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, }); diff --git a/compiler/rustc_mir_build/src/thir/cx/block.rs b/compiler/rustc_mir_build/src/thir/cx/block.rs index 2d9b5c1d98a..ad1d7daec95 100644 --- a/compiler/rustc_mir_build/src/thir/cx/block.rs +++ b/compiler/rustc_mir_build/src/thir/cx/block.rs @@ -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> { 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, diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 55d84782c48..5d7a4215c57 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -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 { } } -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 { diff --git a/src/test/ui/hr-subtype/placeholder-pattern-fail.rs b/src/test/ui/hr-subtype/placeholder-pattern-fail.rs new file mode 100644 index 00000000000..3b5b075cb58 --- /dev/null +++ b/src/test/ui/hr-subtype/placeholder-pattern-fail.rs @@ -0,0 +1,27 @@ +// Check that incorrect higher ranked subtyping +// causes an error. +struct Inv<'a>(fn(&'a ()) -> &'a ()); +fn hr_subtype<'c>(f: for<'a, 'b> fn(Inv<'a>, Inv<'a>)) { + // ok + let _: for<'a> fn(Inv<'a>, Inv<'a>) = f; + let sub: for<'a> fn(Inv<'a>, Inv<'a>) = f; + // no + let _: for<'a, 'b> fn(Inv<'a>, Inv<'b>) = sub; + //~^ ERROR mismatched types +} + +fn simple1<'c>(x: (&'c i32,)) { + let _x: (&'static i32,) = x; + //~^ ERROR mismatched types +} + +fn simple2<'c>(x: (&'c i32,)) { + let _: (&'static i32,) = x; + //~^ ERROR mismatched types +} + +fn main() { + hr_subtype(|_, _| {}); + simple1((&3,)); + simple2((&3,)); +} diff --git a/src/test/ui/hr-subtype/placeholder-pattern-fail.stderr b/src/test/ui/hr-subtype/placeholder-pattern-fail.stderr new file mode 100644 index 00000000000..7bd5308052b --- /dev/null +++ b/src/test/ui/hr-subtype/placeholder-pattern-fail.stderr @@ -0,0 +1,42 @@ +error[E0308]: mismatched types + --> $DIR/placeholder-pattern-fail.rs:9:47 + | +LL | let _: for<'a, 'b> fn(Inv<'a>, Inv<'b>) = sub; + | ^^^ one type is more general than the other + | + = note: expected fn pointer `for<'a, 'b> fn(Inv<'a>, Inv<'b>)` + found fn pointer `for<'a> fn(Inv<'a>, Inv<'a>)` + +error[E0308]: mismatched types + --> $DIR/placeholder-pattern-fail.rs:14:31 + | +LL | let _x: (&'static i32,) = x; + | ^ lifetime mismatch + | + = note: expected tuple `(&'static i32,)` + found tuple `(&'c i32,)` +note: the lifetime `'c` as defined here... + --> $DIR/placeholder-pattern-fail.rs:13:12 + | +LL | fn simple1<'c>(x: (&'c i32,)) { + | ^^ + = note: ...does not necessarily outlive the static lifetime + +error[E0308]: mismatched types + --> $DIR/placeholder-pattern-fail.rs:19:30 + | +LL | let _: (&'static i32,) = x; + | ^ lifetime mismatch + | + = note: expected tuple `(&'static i32,)` + found tuple `(&'c i32,)` +note: the lifetime `'c` as defined here... + --> $DIR/placeholder-pattern-fail.rs:18:12 + | +LL | fn simple2<'c>(x: (&'c i32,)) { + | ^^ + = note: ...does not necessarily outlive the static lifetime + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/hr-subtype/placeholder-pattern.rs b/src/test/ui/hr-subtype/placeholder-pattern.rs new file mode 100644 index 00000000000..061e66e54d2 --- /dev/null +++ b/src/test/ui/hr-subtype/placeholder-pattern.rs @@ -0,0 +1,18 @@ +// check-pass +// Check that higher ranked subtyping correctly works when using +// placeholder patterns. +fn hr_subtype<'c>(f: for<'a, 'b> fn(&'a (), &'b ())) { + let _: for<'a> fn(&'a (), &'a ()) = f; + let _: for<'a, 'b> fn(&'a (), &'b ()) = f; + let _: for<'a> fn(&'a (), &'c ()) = f; + let _: fn(&'c (), &'c ()) = f; +} + +fn simple<'c>(x: (&'static i32,)) { + let _: (&'c i32,) = x; +} + +fn main() { + hr_subtype(|_, _| {}); + simple((&3,)); +} diff --git a/src/test/ui/lifetimes/re-empty-in-error.rs b/src/test/ui/lifetimes/re-empty-in-error.rs new file mode 100644 index 00000000000..41c3718592d --- /dev/null +++ b/src/test/ui/lifetimes/re-empty-in-error.rs @@ -0,0 +1,10 @@ +// We didn't have a single test mentioning +// `ReEmpty` and this test changes that. +fn foo<'a>(_a: &'a u32) where for<'b> &'b (): 'a { + //~^ NOTE type must outlive the empty lifetime as required by this binding +} + +fn main() { + foo(&10); + //~^ ERROR the type `&'b ()` does not fulfill the required lifetime +} diff --git a/src/test/ui/lifetimes/re-empty-in-error.stderr b/src/test/ui/lifetimes/re-empty-in-error.stderr new file mode 100644 index 00000000000..227e3ca6139 --- /dev/null +++ b/src/test/ui/lifetimes/re-empty-in-error.stderr @@ -0,0 +1,15 @@ +error[E0477]: the type `&'b ()` does not fulfill the required lifetime + --> $DIR/re-empty-in-error.rs:8:5 + | +LL | foo(&10); + | ^^^ + | +note: type must outlive the empty lifetime as required by this binding + --> $DIR/re-empty-in-error.rs:3:47 + | +LL | fn foo<'a>(_a: &'a u32) where for<'b> &'b (): 'a { + | ^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0477`. diff --git a/src/test/ui/nll/issue-57280-1-flipped.rs b/src/test/ui/nll/issue-57280-1-flipped.rs new file mode 100644 index 00000000000..ad4b8dcfde4 --- /dev/null +++ b/src/test/ui/nll/issue-57280-1-flipped.rs @@ -0,0 +1,23 @@ +// This test should compile, as the lifetimes +// in matches don't really matter. +// +// We currently use contravariance when checking the +// type of match arms. + +trait Foo<'a> { + const C: &'a u32; +} + +impl<'a, T> Foo<'a> for T { + const C: &'a u32 = &22; +} + +fn foo<'a>(x: &'static u32) { + match x { + <() as Foo<'a>>::C => { } + //~^ ERROR lifetime may not live long enough + &_ => { } + } +} + +fn main() {} diff --git a/src/test/ui/nll/issue-57280-1-flipped.stderr b/src/test/ui/nll/issue-57280-1-flipped.stderr new file mode 100644 index 00000000000..7a2135a2ade --- /dev/null +++ b/src/test/ui/nll/issue-57280-1-flipped.stderr @@ -0,0 +1,11 @@ +error: lifetime may not live long enough + --> $DIR/issue-57280-1-flipped.rs:17:9 + | +LL | fn foo<'a>(x: &'static u32) { + | -- lifetime `'a` defined here +LL | match x { +LL | <() as Foo<'a>>::C => { } + | ^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` + +error: aborting due to previous error +