Skip to content

Commit 549eeb0

Browse files
authored
Rollup merge of #120390 - matthewjasper:inline-constant-pat-mir, r=davidtwco
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. Also enables some inline constant pattern tests that were fixed by the THIR unsafeck stabilization. cc #76001
2 parents d04bede + 44824e0 commit 549eeb0

File tree

8 files changed

+178
-18
lines changed

8 files changed

+178
-18
lines changed

compiler/rustc_borrowck/src/type_check/mod.rs

+56-8
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

+35-2
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(())
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
}
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`.

tests/ui/inline-const/pat-unsafe-err.rs

-2
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(inline_const_pat)]
53

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error[E0133]: call to unsafe function `require_unsafe` is unsafe and requires unsafe function or block
2+
--> $DIR/pat-unsafe-err.rs:11:13
3+
|
4+
LL | require_unsafe();
5+
| ^^^^^^^^^^^^^^^^ call to unsafe function
6+
|
7+
= note: consult the function's documentation for information on how to avoid undefined behavior
8+
9+
error[E0133]: call to unsafe function `require_unsafe` is unsafe and requires unsafe function or block
10+
--> $DIR/pat-unsafe-err.rs:18:13
11+
|
12+
LL | require_unsafe()
13+
| ^^^^^^^^^^^^^^^^ call to unsafe function
14+
|
15+
= note: consult the function's documentation for information on how to avoid undefined behavior
16+
17+
error: aborting due to 2 previous errors
18+
19+
For more information about this error, try `rustc --explain E0133`.

tests/ui/inline-const/pat-unsafe.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
// check-pass
2-
// ignore-test This is currently broken
32

43
#![allow(incomplete_features)]
54
#![warn(unused_unsafe)]
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
warning: unnecessary `unsafe` block
2+
--> $DIR/pat-unsafe.rs:16:17
3+
|
4+
LL | unsafe {}
5+
| ^^^^^^ unnecessary `unsafe` block
6+
|
7+
note: the lint level is defined here
8+
--> $DIR/pat-unsafe.rs:4:9
9+
|
10+
LL | #![warn(unused_unsafe)]
11+
| ^^^^^^^^^^^^^
12+
13+
warning: unnecessary `unsafe` block
14+
--> $DIR/pat-unsafe.rs:23:17
15+
|
16+
LL | unsafe {}
17+
| ^^^^^^ unnecessary `unsafe` block
18+
19+
warning: 2 warnings emitted
20+

0 commit comments

Comments
 (0)