Skip to content

Commit 0dbb867

Browse files
authored
Rollup merge of #58371 - davidtwco:issue-58299, r=arielb1
Check user type annotations for range patterns. Fixes #58299. This PR builds on the fix from #58161 (which fixed miscompilation caused by the introduction of `AscribeUserType` patterns for associated constants) to start checking these patterns are well-formed for ranges (previous fix just ignored them so that miscompilation wouldn't occur). r? @arielb1
2 parents 0431857 + ee82d09 commit 0dbb867

File tree

7 files changed

+176
-85
lines changed

7 files changed

+176
-85
lines changed

src/librustc_mir/build/matches/mod.rs

+11-7
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::build::scope::{CachedBlock, DropKind};
77
use crate::build::ForGuard::{self, OutsideGuard, RefWithinGuard, ValWithinGuard};
88
use crate::build::{BlockAnd, BlockAndExtension, Builder};
99
use crate::build::{GuardFrame, GuardFrameLocal, LocalsForNode};
10-
use crate::hair::*;
10+
use crate::hair::{self, *};
1111
use rustc::mir::*;
1212
use rustc::ty::{self, CanonicalUserTypeAnnotation, Ty};
1313
use rustc::ty::layout::VariantIdx;
@@ -283,9 +283,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
283283
},
284284
..
285285
},
286-
user_ty: pat_ascription_ty,
287-
variance: _,
288-
user_ty_span,
286+
ascription: hair::pattern::Ascription {
287+
user_ty: pat_ascription_ty,
288+
variance: _,
289+
user_ty_span,
290+
},
289291
} => {
290292
let place =
291293
self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard);
@@ -560,9 +562,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
560562
}
561563
PatternKind::AscribeUserType {
562564
ref subpattern,
563-
ref user_ty,
564-
user_ty_span,
565-
variance: _,
565+
ascription: hair::pattern::Ascription {
566+
ref user_ty,
567+
user_ty_span,
568+
variance: _,
569+
},
566570
} => {
567571
// This corresponds to something like
568572
//

src/librustc_mir/build/matches/simplify.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
1515
use crate::build::Builder;
1616
use crate::build::matches::{Ascription, Binding, MatchPair, Candidate};
17-
use crate::hair::*;
17+
use crate::hair::{self, *};
1818
use rustc::ty;
1919
use rustc::ty::layout::{Integer, IntegerExt, Size};
2020
use syntax::attr::{SignedInt, UnsignedInt};
@@ -58,9 +58,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
5858
match *match_pair.pattern.kind {
5959
PatternKind::AscribeUserType {
6060
ref subpattern,
61-
variance,
62-
ref user_ty,
63-
user_ty_span
61+
ascription: hair::pattern::Ascription {
62+
variance,
63+
ref user_ty,
64+
user_ty_span,
65+
},
6466
} => {
6567
// Apply the type ascription to the value at `match_pair.place`, which is the
6668
// value being matched, taking the variance field into account.

src/librustc_mir/hair/cx/block.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::hair::*;
1+
use crate::hair::{self, *};
22
use crate::hair::cx::Cx;
33
use crate::hair::cx::to_ref::ToRef;
44
use rustc::middle::region;
@@ -83,10 +83,12 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
8383
ty: pattern.ty,
8484
span: pattern.span,
8585
kind: Box::new(PatternKind::AscribeUserType {
86-
user_ty: PatternTypeProjection::from_user_type(user_ty),
87-
user_ty_span: ty.span,
86+
ascription: hair::pattern::Ascription {
87+
user_ty: PatternTypeProjection::from_user_type(user_ty),
88+
user_ty_span: ty.span,
89+
variance: ty::Variance::Covariant,
90+
},
8891
subpattern: pattern,
89-
variance: ty::Variance::Covariant,
9092
})
9193
};
9294
}

src/librustc_mir/hair/pattern/_match.rs

+17-11
Original file line numberDiff line numberDiff line change
@@ -871,18 +871,24 @@ impl<'tcx> IntRange<'tcx> {
871871
}
872872

873873
fn from_pat(tcx: TyCtxt<'_, 'tcx, 'tcx>,
874-
pat: &Pattern<'tcx>)
874+
mut pat: &Pattern<'tcx>)
875875
-> Option<IntRange<'tcx>> {
876-
Self::from_ctor(tcx, &match pat.kind {
877-
box PatternKind::Constant { value } => ConstantValue(value),
878-
box PatternKind::Range(PatternRange { lo, hi, ty, end }) => ConstantRange(
879-
lo.to_bits(tcx, ty::ParamEnv::empty().and(ty)).unwrap(),
880-
hi.to_bits(tcx, ty::ParamEnv::empty().and(ty)).unwrap(),
881-
ty,
882-
end,
883-
),
884-
_ => return None,
885-
})
876+
let range = loop {
877+
match pat.kind {
878+
box PatternKind::Constant { value } => break ConstantValue(value),
879+
box PatternKind::Range(PatternRange { lo, hi, ty, end }) => break ConstantRange(
880+
lo.to_bits(tcx, ty::ParamEnv::empty().and(ty)).unwrap(),
881+
hi.to_bits(tcx, ty::ParamEnv::empty().and(ty)).unwrap(),
882+
ty,
883+
end,
884+
),
885+
box PatternKind::AscribeUserType { ref subpattern, .. } => {
886+
pat = subpattern;
887+
},
888+
_ => return None,
889+
}
890+
};
891+
Self::from_ctor(tcx, &range)
886892
}
887893

888894
// The return value of `signed_bias` should be XORed with an endpoint to encode/decode it.

src/librustc_mir/hair/pattern/mod.rs

+86-59
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ pub struct Pattern<'tcx> {
5858
}
5959

6060

61-
#[derive(Clone, Debug)]
61+
#[derive(Copy, Clone, Debug, PartialEq)]
6262
pub struct PatternTypeProjection<'tcx> {
6363
pub user_ty: CanonicalUserType<'tcx>,
6464
}
@@ -87,33 +87,38 @@ impl<'tcx> PatternTypeProjection<'tcx> {
8787
}
8888
}
8989

90+
#[derive(Copy, Clone, Debug, PartialEq)]
91+
pub struct Ascription<'tcx> {
92+
pub user_ty: PatternTypeProjection<'tcx>,
93+
/// Variance to use when relating the type `user_ty` to the **type of the value being
94+
/// matched**. Typically, this is `Variance::Covariant`, since the value being matched must
95+
/// have a type that is some subtype of the ascribed type.
96+
///
97+
/// Note that this variance does not apply for any bindings within subpatterns. The type
98+
/// assigned to those bindings must be exactly equal to the `user_ty` given here.
99+
///
100+
/// The only place where this field is not `Covariant` is when matching constants, where
101+
/// we currently use `Contravariant` -- this is because the constant type just needs to
102+
/// be "comparable" to the type of the input value. So, for example:
103+
///
104+
/// ```text
105+
/// match x { "foo" => .. }
106+
/// ```
107+
///
108+
/// requires that `&'static str <: T_x`, where `T_x` is the type of `x`. Really, we should
109+
/// probably be checking for a `PartialEq` impl instead, but this preserves the behavior
110+
/// of the old type-check for now. See #57280 for details.
111+
pub variance: ty::Variance,
112+
pub user_ty_span: Span,
113+
}
114+
90115
#[derive(Clone, Debug)]
91116
pub enum PatternKind<'tcx> {
92117
Wild,
93118

94119
AscribeUserType {
95-
user_ty: PatternTypeProjection<'tcx>,
120+
ascription: Ascription<'tcx>,
96121
subpattern: Pattern<'tcx>,
97-
/// Variance to use when relating the type `user_ty` to the **type of the value being
98-
/// matched**. Typically, this is `Variance::Covariant`, since the value being matched must
99-
/// have a type that is some subtype of the ascribed type.
100-
///
101-
/// Note that this variance does not apply for any bindings within subpatterns. The type
102-
/// assigned to those bindings must be exactly equal to the `user_ty` given here.
103-
///
104-
/// The only place where this field is not `Covariant` is when matching constants, where
105-
/// we currently use `Contravariant` -- this is because the constant type just needs to
106-
/// be "comparable" to the type of the input value. So, for example:
107-
///
108-
/// ```text
109-
/// match x { "foo" => .. }
110-
/// ```
111-
///
112-
/// requires that `&'static str <: T_x`, where `T_x` is the type of `x`. Really, we should
113-
/// probably be checking for a `PartialEq` impl instead, but this preserves the behavior
114-
/// of the old type-check for now. See #57280 for details.
115-
variance: ty::Variance,
116-
user_ty_span: Span,
117122
},
118123

119124
/// `x`, `ref x`, `x @ P`, etc.
@@ -169,18 +174,7 @@ pub enum PatternKind<'tcx> {
169174
},
170175
}
171176

172-
impl<'tcx> PatternKind<'tcx> {
173-
/// If this is a `PatternKind::AscribeUserType` then return the subpattern kind, otherwise
174-
/// return this pattern kind.
175-
fn with_user_type_ascription_subpattern(self) -> Self {
176-
match self {
177-
PatternKind::AscribeUserType { subpattern: Pattern { box kind, .. }, .. } => kind,
178-
kind => kind,
179-
}
180-
}
181-
}
182-
183-
#[derive(Clone, Copy, Debug, PartialEq)]
177+
#[derive(Copy, Clone, Debug, PartialEq)]
184178
pub struct PatternRange<'tcx> {
185179
pub lo: ty::Const<'tcx>,
186180
pub hi: ty::Const<'tcx>,
@@ -407,6 +401,19 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
407401
)
408402
}
409403

404+
fn lower_range_expr(
405+
&mut self,
406+
expr: &'tcx hir::Expr,
407+
) -> (PatternKind<'tcx>, Option<Ascription<'tcx>>) {
408+
match self.lower_lit(expr) {
409+
PatternKind::AscribeUserType {
410+
ascription: lo_ascription,
411+
subpattern: Pattern { kind: box kind, .. },
412+
} => (kind, Some(lo_ascription)),
413+
kind => (kind, None),
414+
}
415+
}
416+
410417
fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat) -> Pattern<'tcx> {
411418
let mut ty = self.tables.node_type(pat.hir_id);
412419

@@ -416,14 +423,10 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
416423
PatKind::Lit(ref value) => self.lower_lit(value),
417424

418425
PatKind::Range(ref lo_expr, ref hi_expr, end) => {
419-
match (
420-
// Look for `PatternKind::Constant` patterns inside of any
421-
// `PatternKind::AscribeUserType` patterns. Type ascriptions can be safely
422-
// ignored for the purposes of lowering a range correctly - these are checked
423-
// elsewhere for well-formedness.
424-
self.lower_lit(lo_expr).with_user_type_ascription_subpattern(),
425-
self.lower_lit(hi_expr).with_user_type_ascription_subpattern(),
426-
) {
426+
let (lo, lo_ascription) = self.lower_range_expr(lo_expr);
427+
let (hi, hi_ascription) = self.lower_range_expr(hi_expr);
428+
429+
let mut kind = match (lo, hi) {
427430
(PatternKind::Constant { value: lo }, PatternKind::Constant { value: hi }) => {
428431
use std::cmp::Ordering;
429432
let cmp = compare_const_vals(
@@ -472,17 +475,33 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
472475
PatternKind::Wild
473476
}
474477
}
475-
}
478+
},
476479
ref pats => {
477480
self.tcx.sess.delay_span_bug(
478481
pat.span,
479-
&format!("found bad range pattern `{:?}` outside of error recovery",
480-
pats),
482+
&format!(
483+
"found bad range pattern `{:?}` outside of error recovery",
484+
pats,
485+
),
481486
);
482487

483488
PatternKind::Wild
489+
},
490+
};
491+
492+
// If we are handling a range with associated constants (e.g.
493+
// `Foo::<'a>::A..=Foo::B`), we need to put the ascriptions for the associated
494+
// constants somewhere. Have them on the range pattern.
495+
for ascription in &[lo_ascription, hi_ascription] {
496+
if let Some(ascription) = ascription {
497+
kind = PatternKind::AscribeUserType {
498+
ascription: *ascription,
499+
subpattern: Pattern { span: pat.span, ty, kind: Box::new(kind), },
500+
};
484501
}
485502
}
503+
504+
kind
486505
}
487506

488507
PatKind::Path(ref qpath) => {
@@ -758,9 +777,11 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
758777
ty,
759778
kind: Box::new(kind),
760779
},
761-
user_ty: PatternTypeProjection::from_user_type(user_ty),
762-
user_ty_span: span,
763-
variance: ty::Variance::Covariant,
780+
ascription: Ascription {
781+
user_ty: PatternTypeProjection::from_user_type(user_ty),
782+
user_ty_span: span,
783+
variance: ty::Variance::Covariant,
784+
},
764785
};
765786
}
766787

@@ -810,11 +831,13 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
810831
kind: Box::new(
811832
PatternKind::AscribeUserType {
812833
subpattern: pattern,
813-
/// Note that use `Contravariant` here. See the
814-
/// `variance` field documentation for details.
815-
variance: ty::Variance::Contravariant,
816-
user_ty,
817-
user_ty_span: span,
834+
ascription: Ascription {
835+
/// Note that use `Contravariant` here. See the
836+
/// `variance` field documentation for details.
837+
variance: ty::Variance::Contravariant,
838+
user_ty,
839+
user_ty_span: span,
840+
},
818841
}
819842
),
820843
ty: value.ty,
@@ -1107,14 +1130,18 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> {
11071130
PatternKind::Wild => PatternKind::Wild,
11081131
PatternKind::AscribeUserType {
11091132
ref subpattern,
1110-
variance,
1111-
ref user_ty,
1112-
user_ty_span,
1133+
ascription: Ascription {
1134+
variance,
1135+
ref user_ty,
1136+
user_ty_span,
1137+
},
11131138
} => PatternKind::AscribeUserType {
11141139
subpattern: subpattern.fold_with(folder),
1115-
user_ty: user_ty.fold_with(folder),
1116-
variance,
1117-
user_ty_span,
1140+
ascription: Ascription {
1141+
user_ty: user_ty.fold_with(folder),
1142+
variance,
1143+
user_ty_span,
1144+
},
11181145
},
11191146
PatternKind::Binding {
11201147
mutability,

src/test/ui/nll/issue-58299.rs

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#![allow(dead_code)]
2+
#![feature(nll)]
3+
4+
struct A<'a>(&'a ());
5+
6+
trait Y {
7+
const X: i32;
8+
}
9+
10+
impl Y for A<'static> {
11+
const X: i32 = 10;
12+
}
13+
14+
fn foo<'a>(x: i32) {
15+
match x {
16+
// This uses <A<'a> as Y>::X, but `A<'a>` does not implement `Y`.
17+
A::<'a>::X..=A::<'static>::X => (), //~ ERROR lifetime may not live long enough
18+
_ => (),
19+
}
20+
}
21+
22+
fn bar<'a>(x: i32) {
23+
match x {
24+
// This uses <A<'a> as Y>::X, but `A<'a>` does not implement `Y`.
25+
A::<'static>::X..=A::<'a>::X => (), //~ ERROR lifetime may not live long enough
26+
_ => (),
27+
}
28+
}
29+
30+
fn main() {}

src/test/ui/nll/issue-58299.stderr

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error: lifetime may not live long enough
2+
--> $DIR/issue-58299.rs:17:9
3+
|
4+
LL | fn foo<'a>(x: i32) {
5+
| -- lifetime `'a` defined here
6+
...
7+
LL | A::<'a>::X..=A::<'static>::X => (), //~ ERROR lifetime may not live long enough
8+
| ^^^^^^^^^^ requires that `'a` must outlive `'static`
9+
10+
error: lifetime may not live long enough
11+
--> $DIR/issue-58299.rs:25:27
12+
|
13+
LL | fn bar<'a>(x: i32) {
14+
| -- lifetime `'a` defined here
15+
...
16+
LL | A::<'static>::X..=A::<'a>::X => (), //~ ERROR lifetime may not live long enough
17+
| ^^^^^^^^^^ requires that `'a` must outlive `'static`
18+
19+
error: aborting due to 2 previous errors
20+

0 commit comments

Comments
 (0)