diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index cf28e62177f..488dfc64cf6 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1099,10 +1099,17 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { #[instrument(skip(self), level = "debug")] fn check_user_type_annotations(&mut self) { debug!(?self.user_type_annotations); + let tcx = self.tcx(); for user_annotation in self.user_type_annotations { let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation; let annotation = self.instantiate_canonical_with_fresh_inference_vars(span, user_ty); - self.ascribe_user_type(inferred_ty, annotation, span); + if let ty::UserType::TypeOf(def, args) = annotation + && let DefKind::InlineConst = tcx.def_kind(def) + { + self.check_inline_const(inferred_ty, def.expect_local(), args, span); + } else { + self.ascribe_user_type(inferred_ty, annotation, span); + } } } @@ -1195,6 +1202,36 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { Ok(()) } + fn check_inline_const( + &mut self, + inferred_ty: Ty<'tcx>, + def_id: LocalDefId, + args: UserArgs<'tcx>, + span: Span, + ) { + assert!(args.user_self_ty.is_none()); + let tcx = self.tcx(); + let const_ty = tcx.type_of(def_id).instantiate(tcx, args.args); + if let Err(terr) = + self.eq_types(const_ty, inferred_ty, Locations::All(span), ConstraintCategory::Boring) + { + span_bug!( + span, + "bad inline const pattern: ({:?} = {:?}) {:?}", + const_ty, + inferred_ty, + terr + ); + } + let args = self.infcx.resolve_vars_if_possible(args.args); + let predicates = self.prove_closure_bounds(tcx, def_id, args, Locations::All(span)); + self.normalize_and_prove_instantiated_predicates( + def_id.to_def_id(), + predicates, + Locations::All(span), + ); + } + fn tcx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } @@ -1851,7 +1888,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let def_id = uv.def; if tcx.def_kind(def_id) == DefKind::InlineConst { let def_id = def_id.expect_local(); - let predicates = self.prove_closure_bounds(tcx, def_id, uv.args, location); + let predicates = self.prove_closure_bounds( + tcx, + def_id, + uv.args, + location.to_locations(), + ); self.normalize_and_prove_instantiated_predicates( def_id.to_def_id(), predicates, @@ -2654,9 +2696,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // desugaring. A closure gets desugared to a struct, and // these extra requirements are basically like where // clauses on the struct. - AggregateKind::Closure(def_id, args) | AggregateKind::Coroutine(def_id, args) => { - (def_id, self.prove_closure_bounds(tcx, def_id.expect_local(), args, location)) - } + AggregateKind::Closure(def_id, args) | AggregateKind::Coroutine(def_id, args) => ( + def_id, + self.prove_closure_bounds( + tcx, + def_id.expect_local(), + args, + location.to_locations(), + ), + ), AggregateKind::Array(_) | AggregateKind::Tuple => { (CRATE_DEF_ID.to_def_id(), ty::InstantiatedPredicates::empty()) @@ -2675,7 +2723,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { tcx: TyCtxt<'tcx>, def_id: LocalDefId, args: GenericArgsRef<'tcx>, - location: Location, + locations: Locations, ) -> ty::InstantiatedPredicates<'tcx> { if let Some(closure_requirements) = &tcx.mir_borrowck(def_id).closure_requirements { constraint_conversion::ConstraintConversion::new( @@ -2684,7 +2732,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.region_bound_pairs, self.implicit_region_bound, self.param_env, - location.to_locations(), + locations, DUMMY_SP, // irrelevant; will be overridden. ConstraintCategory::Boring, // same as above. self.borrowck_context.constraints, @@ -2710,7 +2758,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { if let Err(_) = self.eq_args( typeck_root_args, parent_args, - location.to_locations(), + locations, ConstraintCategory::BoringNoLocation, ) { span_mirbug!( diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index a7f6f4873e3..065c93e86a8 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -15,7 +15,9 @@ use crate::build::expr::as_place::PlaceBuilder; use crate::build::matches::{Ascription, Binding, Candidate, MatchPair}; use crate::build::Builder; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_middle::thir::{self, *}; +use rustc_middle::ty; use std::mem; @@ -149,7 +151,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ref subpattern, ascription: thir::Ascription { ref annotation, variance }, } => { - // Apply the type ascription to the value at `match_pair.place`, which is the + // Apply the type ascription to the value at `match_pair.place` if let Some(source) = match_pair.place.try_to_place(self) { candidate.ascriptions.push(Ascription { annotation: annotation.clone(), @@ -205,7 +207,38 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Err(match_pair) } - PatKind::InlineConstant { subpattern: ref pattern, def: _ } => { + PatKind::InlineConstant { subpattern: ref pattern, def } => { + // Apply a type ascription for the inline constant to the value at `match_pair.place` + if let Some(source) = match_pair.place.try_to_place(self) { + let span = match_pair.pattern.span; + let parent_id = self.tcx.typeck_root_def_id(self.def_id.to_def_id()); + let args = ty::InlineConstArgs::new( + self.tcx, + ty::InlineConstArgsParts { + parent_args: ty::GenericArgs::identity_for_item(self.tcx, parent_id), + ty: self.infcx.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::MiscVariable, + span, + }), + }, + ) + .args; + let user_ty = + self.infcx.canonicalize_user_type_annotation(ty::UserType::TypeOf( + def.to_def_id(), + ty::UserArgs { args, user_self_ty: None }, + )); + let annotation = ty::CanonicalUserTypeAnnotation { + inferred_ty: pattern.ty, + span, + user_ty: Box::new(user_ty), + }; + candidate.ascriptions.push(Ascription { + annotation, + source, + variance: ty::Contravariant, + }); + } candidate.match_pairs.push(MatchPair::new(match_pair.place, pattern, self)); Ok(()) diff --git a/tests/ui/inline-const/const-match-pat-lifetime-err.rs b/tests/ui/inline-const/const-match-pat-lifetime-err.rs index 366ad26bb27..ce91e5233bc 100644 --- a/tests/ui/inline-const/const-match-pat-lifetime-err.rs +++ b/tests/ui/inline-const/const-match-pat-lifetime-err.rs @@ -1,5 +1,3 @@ -// ignore-test (This is currently broken) - #![allow(incomplete_features)] #![feature(const_mut_refs)] #![feature(inline_const_pat)] @@ -9,6 +7,9 @@ use std::marker::PhantomData; #[derive(PartialEq, Eq)] pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>); +#[derive(PartialEq, Eq)] +pub struct CovariantRef<'a, T: ?Sized>(&'a T); + impl<'a, T: ?Sized> InvariantRef<'a, T> { pub const fn new(r: &'a T) -> Self { InvariantRef(r, PhantomData) @@ -19,16 +20,30 @@ impl<'a> InvariantRef<'a, ()> { pub const NEW: Self = InvariantRef::new(&()); } +impl<'a> CovariantRef<'a, ()> { + pub const NEW: Self = CovariantRef(&()); +} + fn match_invariant_ref<'a>() { let y = (); match InvariantRef::new(&y) { - //~^ ERROR `y` does not live long enough [E0597] - // FIXME(nbdd0121): This should give the same error as `InvariantRef::<'a>::NEW` (without - // const block) + //~^ ERROR `y` does not live long enough [E0597] const { InvariantRef::<'a>::NEW } => (), } } +fn match_covariant_ref<'a>() { + // Unclear if we should error here (should we be able to subtype the type of + // `y.0`), but using the associated const directly in the pattern also + // errors. + let y: (CovariantRef<'static, _>,) = (CovariantRef(&()),); + //~^ ERROR lifetime may not live long enough + match y.0 { + const { CovariantRef::<'a>::NEW } => (), + } +} + fn main() { match_invariant_ref(); + match_covariant_ref(); } diff --git a/tests/ui/inline-const/const-match-pat-lifetime-err.stderr b/tests/ui/inline-const/const-match-pat-lifetime-err.stderr new file mode 100644 index 00000000000..c5760f1027e --- /dev/null +++ b/tests/ui/inline-const/const-match-pat-lifetime-err.stderr @@ -0,0 +1,28 @@ +error[E0597]: `y` does not live long enough + --> $DIR/const-match-pat-lifetime-err.rs:29:29 + | +LL | fn match_invariant_ref<'a>() { + | -- lifetime `'a` defined here +LL | let y = (); + | - binding `y` declared here +LL | match InvariantRef::new(&y) { + | ^^ borrowed value does not live long enough +LL | +LL | const { InvariantRef::<'a>::NEW } => (), + | --------------------------------- type annotation requires that `y` is borrowed for `'a` +LL | } +LL | } + | - `y` dropped here while still borrowed + +error: lifetime may not live long enough + --> $DIR/const-match-pat-lifetime-err.rs:39:12 + | +LL | fn match_covariant_ref<'a>() { + | -- lifetime `'a` defined here +... +LL | let y: (CovariantRef<'static, _>,) = (CovariantRef(&()),); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0597`.