Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 83fa46f

Browse files
committed
Borrow check inline const patterns
Add type annotations to MIR so that borrowck can pass constraints from inline constants in patterns to the containing function.
1 parent e35a56d commit 83fa46f

File tree

4 files changed

+139
-15
lines changed

4 files changed

+139
-15
lines changed

compiler/rustc_borrowck/src/type_check/mod.rs

Lines changed: 56 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1099,10 +1099,17 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
10991099
#[instrument(skip(self), level = "debug")]
11001100
fn check_user_type_annotations(&mut self) {
11011101
debug!(?self.user_type_annotations);
1102+
let tcx = self.tcx();
11021103
for user_annotation in self.user_type_annotations {
11031104
let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation;
11041105
let annotation = self.instantiate_canonical_with_fresh_inference_vars(span, user_ty);
1105-
self.ascribe_user_type(inferred_ty, annotation, span);
1106+
if let ty::UserType::TypeOf(def, args) = annotation
1107+
&& let DefKind::InlineConst = tcx.def_kind(def)
1108+
{
1109+
self.check_inline_const(inferred_ty, def.expect_local(), args, span);
1110+
} else {
1111+
self.ascribe_user_type(inferred_ty, annotation, span);
1112+
}
11061113
}
11071114
}
11081115

@@ -1195,6 +1202,36 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
11951202
Ok(())
11961203
}
11971204

1205+
fn check_inline_const(
1206+
&mut self,
1207+
inferred_ty: Ty<'tcx>,
1208+
def_id: LocalDefId,
1209+
args: UserArgs<'tcx>,
1210+
span: Span,
1211+
) {
1212+
assert!(args.user_self_ty.is_none());
1213+
let tcx = self.tcx();
1214+
let const_ty = tcx.type_of(def_id).instantiate(tcx, args.args);
1215+
if let Err(terr) =
1216+
self.eq_types(const_ty, inferred_ty, Locations::All(span), ConstraintCategory::Boring)
1217+
{
1218+
span_bug!(
1219+
span,
1220+
"bad inline const pattern: ({:?} = {:?}) {:?}",
1221+
const_ty,
1222+
inferred_ty,
1223+
terr
1224+
);
1225+
}
1226+
let args = self.infcx.resolve_vars_if_possible(args.args);
1227+
let predicates = self.prove_closure_bounds(tcx, def_id, args, Locations::All(span));
1228+
self.normalize_and_prove_instantiated_predicates(
1229+
def_id.to_def_id(),
1230+
predicates,
1231+
Locations::All(span),
1232+
);
1233+
}
1234+
11981235
fn tcx(&self) -> TyCtxt<'tcx> {
11991236
self.infcx.tcx
12001237
}
@@ -1851,7 +1888,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
18511888
let def_id = uv.def;
18521889
if tcx.def_kind(def_id) == DefKind::InlineConst {
18531890
let def_id = def_id.expect_local();
1854-
let predicates = self.prove_closure_bounds(tcx, def_id, uv.args, location);
1891+
let predicates = self.prove_closure_bounds(
1892+
tcx,
1893+
def_id,
1894+
uv.args,
1895+
location.to_locations(),
1896+
);
18551897
self.normalize_and_prove_instantiated_predicates(
18561898
def_id.to_def_id(),
18571899
predicates,
@@ -2654,9 +2696,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
26542696
// desugaring. A closure gets desugared to a struct, and
26552697
// these extra requirements are basically like where
26562698
// clauses on the struct.
2657-
AggregateKind::Closure(def_id, args) | AggregateKind::Coroutine(def_id, args) => {
2658-
(def_id, self.prove_closure_bounds(tcx, def_id.expect_local(), args, location))
2659-
}
2699+
AggregateKind::Closure(def_id, args) | AggregateKind::Coroutine(def_id, args) => (
2700+
def_id,
2701+
self.prove_closure_bounds(
2702+
tcx,
2703+
def_id.expect_local(),
2704+
args,
2705+
location.to_locations(),
2706+
),
2707+
),
26602708

26612709
AggregateKind::Array(_) | AggregateKind::Tuple => {
26622710
(CRATE_DEF_ID.to_def_id(), ty::InstantiatedPredicates::empty())
@@ -2675,7 +2723,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
26752723
tcx: TyCtxt<'tcx>,
26762724
def_id: LocalDefId,
26772725
args: GenericArgsRef<'tcx>,
2678-
location: Location,
2726+
locations: Locations,
26792727
) -> ty::InstantiatedPredicates<'tcx> {
26802728
if let Some(closure_requirements) = &tcx.mir_borrowck(def_id).closure_requirements {
26812729
constraint_conversion::ConstraintConversion::new(
@@ -2684,7 +2732,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
26842732
self.region_bound_pairs,
26852733
self.implicit_region_bound,
26862734
self.param_env,
2687-
location.to_locations(),
2735+
locations,
26882736
DUMMY_SP, // irrelevant; will be overridden.
26892737
ConstraintCategory::Boring, // same as above.
26902738
self.borrowck_context.constraints,
@@ -2710,7 +2758,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
27102758
if let Err(_) = self.eq_args(
27112759
typeck_root_args,
27122760
parent_args,
2713-
location.to_locations(),
2761+
locations,
27142762
ConstraintCategory::BoringNoLocation,
27152763
) {
27162764
span_mirbug!(

compiler/rustc_mir_build/src/build/matches/simplify.rs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
use crate::build::expr::as_place::PlaceBuilder;
1616
use crate::build::matches::{Ascription, Binding, Candidate, MatchPair};
1717
use crate::build::Builder;
18+
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
1819
use rustc_middle::thir::{self, *};
20+
use rustc_middle::ty;
1921

2022
use std::mem;
2123

@@ -149,7 +151,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
149151
ref subpattern,
150152
ascription: thir::Ascription { ref annotation, variance },
151153
} => {
152-
// Apply the type ascription to the value at `match_pair.place`, which is the
154+
// Apply the type ascription to the value at `match_pair.place`
153155
if let Some(source) = match_pair.place.try_to_place(self) {
154156
candidate.ascriptions.push(Ascription {
155157
annotation: annotation.clone(),
@@ -205,7 +207,38 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
205207
Err(match_pair)
206208
}
207209

208-
PatKind::InlineConstant { subpattern: ref pattern, def: _ } => {
210+
PatKind::InlineConstant { subpattern: ref pattern, def } => {
211+
// Apply a type ascription for the inline constant to the value at `match_pair.place`
212+
if let Some(source) = match_pair.place.try_to_place(self) {
213+
let span = match_pair.pattern.span;
214+
let parent_id = self.tcx.typeck_root_def_id(self.def_id.to_def_id());
215+
let args = ty::InlineConstArgs::new(
216+
self.tcx,
217+
ty::InlineConstArgsParts {
218+
parent_args: ty::GenericArgs::identity_for_item(self.tcx, parent_id),
219+
ty: self.infcx.next_ty_var(TypeVariableOrigin {
220+
kind: TypeVariableOriginKind::MiscVariable,
221+
span,
222+
}),
223+
},
224+
)
225+
.args;
226+
let user_ty =
227+
self.infcx.canonicalize_user_type_annotation(ty::UserType::TypeOf(
228+
def.to_def_id(),
229+
ty::UserArgs { args, user_self_ty: None },
230+
));
231+
let annotation = ty::CanonicalUserTypeAnnotation {
232+
inferred_ty: pattern.ty,
233+
span,
234+
user_ty: Box::new(user_ty),
235+
};
236+
candidate.ascriptions.push(Ascription {
237+
annotation,
238+
source,
239+
variance: ty::Contravariant,
240+
});
241+
}
209242
candidate.match_pairs.push(MatchPair::new(match_pair.place, pattern, self));
210243

211244
Ok(())
Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
// ignore-test (This is currently broken)
2-
31
#![allow(incomplete_features)]
42
#![feature(const_mut_refs)]
53
#![feature(inline_const_pat)]
@@ -9,6 +7,9 @@ use std::marker::PhantomData;
97
#[derive(PartialEq, Eq)]
108
pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
119

10+
#[derive(PartialEq, Eq)]
11+
pub struct CovariantRef<'a, T: ?Sized>(&'a T);
12+
1213
impl<'a, T: ?Sized> InvariantRef<'a, T> {
1314
pub const fn new(r: &'a T) -> Self {
1415
InvariantRef(r, PhantomData)
@@ -19,16 +20,30 @@ impl<'a> InvariantRef<'a, ()> {
1920
pub const NEW: Self = InvariantRef::new(&());
2021
}
2122

23+
impl<'a> CovariantRef<'a, ()> {
24+
pub const NEW: Self = CovariantRef(&());
25+
}
26+
2227
fn match_invariant_ref<'a>() {
2328
let y = ();
2429
match InvariantRef::new(&y) {
25-
//~^ ERROR `y` does not live long enough [E0597]
26-
// FIXME(nbdd0121): This should give the same error as `InvariantRef::<'a>::NEW` (without
27-
// const block)
30+
//~^ ERROR `y` does not live long enough [E0597]
2831
const { InvariantRef::<'a>::NEW } => (),
2932
}
3033
}
3134

35+
fn match_covariant_ref<'a>() {
36+
// Unclear if we should error here (should we be able to subtype the type of
37+
// `y.0`), but using the associated const directly in the pattern also
38+
// errors.
39+
let y: (CovariantRef<'static, _>,) = (CovariantRef(&()),);
40+
//~^ ERROR lifetime may not live long enough
41+
match y.0 {
42+
const { CovariantRef::<'a>::NEW } => (),
43+
}
44+
}
45+
3246
fn main() {
3347
match_invariant_ref();
48+
match_covariant_ref();
3449
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
error[E0597]: `y` does not live long enough
2+
--> $DIR/const-match-pat-lifetime-err.rs:29:29
3+
|
4+
LL | fn match_invariant_ref<'a>() {
5+
| -- lifetime `'a` defined here
6+
LL | let y = ();
7+
| - binding `y` declared here
8+
LL | match InvariantRef::new(&y) {
9+
| ^^ borrowed value does not live long enough
10+
LL |
11+
LL | const { InvariantRef::<'a>::NEW } => (),
12+
| --------------------------------- type annotation requires that `y` is borrowed for `'a`
13+
LL | }
14+
LL | }
15+
| - `y` dropped here while still borrowed
16+
17+
error: lifetime may not live long enough
18+
--> $DIR/const-match-pat-lifetime-err.rs:39:12
19+
|
20+
LL | fn match_covariant_ref<'a>() {
21+
| -- lifetime `'a` defined here
22+
...
23+
LL | let y: (CovariantRef<'static, _>,) = (CovariantRef(&()),);
24+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
25+
26+
error: aborting due to 2 previous errors
27+
28+
For more information about this error, try `rustc --explain E0597`.

0 commit comments

Comments
 (0)