Skip to content

Commit 3b2bf26

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 3b2bf26

File tree

4 files changed

+132
-15
lines changed

4 files changed

+132
-15
lines changed

compiler/rustc_borrowck/src/type_check/mod.rs

Lines changed: 49 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(def.expect_local(), args, span);
1110+
} else {
1111+
self.ascribe_user_type(inferred_ty, annotation, span);
1112+
}
11061113
}
11071114
}
11081115

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

1205+
fn check_inline_const(&mut self, def_id: LocalDefId, args: UserArgs, span: Span) {
1206+
assert!(args.user_self_ty.is_none());
1207+
let const_ty = tcx.type_of(def_id).instantiate(tcx, args.args);
1208+
if let Err(terr) =
1209+
self.eq_types(const_ty, inferred_ty, Locations::All(span), ConstraintCategory::Boring)
1210+
{
1211+
span_bug!(
1212+
span,
1213+
"bad inline const pattern: ({:?} = {:?}) {:?}",
1214+
const_ty,
1215+
inferred_ty,
1216+
terr
1217+
);
1218+
}
1219+
let args = self.infcx.resolve_vars_if_possible(args.args);
1220+
let predicates = self.prove_closure_bounds(tcx, def_id, args, Locations::All(span));
1221+
self.normalize_and_prove_instantiated_predicates(
1222+
def_id.to_def_id(),
1223+
predicates,
1224+
Locations::All(span),
1225+
);
1226+
}
1227+
11981228
fn tcx(&self) -> TyCtxt<'tcx> {
11991229
self.infcx.tcx
12001230
}
@@ -1851,7 +1881,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
18511881
let def_id = uv.def;
18521882
if tcx.def_kind(def_id) == DefKind::InlineConst {
18531883
let def_id = def_id.expect_local();
1854-
let predicates = self.prove_closure_bounds(tcx, def_id, uv.args, location);
1884+
let predicates = self.prove_closure_bounds(
1885+
tcx,
1886+
def_id,
1887+
uv.args,
1888+
location.to_locations(),
1889+
);
18551890
self.normalize_and_prove_instantiated_predicates(
18561891
def_id.to_def_id(),
18571892
predicates,
@@ -2654,9 +2689,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
26542689
// desugaring. A closure gets desugared to a struct, and
26552690
// these extra requirements are basically like where
26562691
// 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-
}
2692+
AggregateKind::Closure(def_id, args) | AggregateKind::Coroutine(def_id, args) => (
2693+
def_id,
2694+
self.prove_closure_bounds(
2695+
tcx,
2696+
def_id.expect_local(),
2697+
args,
2698+
location.to_locations(),
2699+
),
2700+
),
26602701

26612702
AggregateKind::Array(_) | AggregateKind::Tuple => {
26622703
(CRATE_DEF_ID.to_def_id(), ty::InstantiatedPredicates::empty())
@@ -2675,7 +2716,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
26752716
tcx: TyCtxt<'tcx>,
26762717
def_id: LocalDefId,
26772718
args: GenericArgsRef<'tcx>,
2678-
location: Location,
2719+
locations: Locations,
26792720
) -> ty::InstantiatedPredicates<'tcx> {
26802721
if let Some(closure_requirements) = &tcx.mir_borrowck(def_id).closure_requirements {
26812722
constraint_conversion::ConstraintConversion::new(
@@ -2684,7 +2725,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
26842725
self.region_bound_pairs,
26852726
self.implicit_region_bound,
26862727
self.param_env,
2687-
location.to_locations(),
2728+
locations,
26882729
DUMMY_SP, // irrelevant; will be overridden.
26892730
ConstraintCategory::Boring, // same as above.
26902731
self.borrowck_context.constraints,
@@ -2710,7 +2751,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
27102751
if let Err(_) = self.eq_args(
27112752
typeck_root_args,
27122753
parent_args,
2713-
location.to_locations(),
2754+
locations,
27142755
ConstraintCategory::BoringNoLocation,
27152756
) {
27162757
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)