Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit b92c6ee

Browse files
committedFeb 14, 2020
Auto merge of #69172 - JohnTitor:rollup-6cbmwcw, r=JohnTitor
Rollup of 7 pull requests Successful merges: - #68129 (Correct inference of primitive operand type behind binary operation) - #68475 (Use a `ParamEnvAnd<Predicate>` for caching in `ObligationForest`) - #68856 (typeck: clarify def_bm adjustments & add tests for or-patterns) - #69051 (simplify_try: address some of eddyb's comments) - #69128 (Fix extra subslice lowering) - #69150 (Follow-up to #68848) - #69164 (Update pulldown-cmark dependency) Failed merges: r? @ghost
2 parents 433aae9 + a6ff1db commit b92c6ee

File tree

20 files changed

+715
-207
lines changed

20 files changed

+715
-207
lines changed
 

‎Cargo.lock

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1564,7 +1564,7 @@ dependencies = [
15641564
"rand_xoshiro",
15651565
"sized-chunks",
15661566
"typenum",
1567-
"version_check 0.9.1",
1567+
"version_check",
15681568
]
15691569

15701570
[[package]]
@@ -2014,9 +2014,9 @@ dependencies = [
20142014

20152015
[[package]]
20162016
name = "memchr"
2017-
version = "2.2.0"
2017+
version = "2.3.2"
20182018
source = "registry+https://github.com/rust-lang/crates.io-index"
2019-
checksum = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39"
2019+
checksum = "53445de381a1f436797497c61d851644d0e8e88e6140f22872ad33a704933978"
20202020

20212021
[[package]]
20222022
name = "memmap"
@@ -2604,23 +2604,23 @@ dependencies = [
26042604

26052605
[[package]]
26062606
name = "pulldown-cmark"
2607-
version = "0.5.3"
2607+
version = "0.6.1"
26082608
source = "registry+https://github.com/rust-lang/crates.io-index"
2609-
checksum = "77043da1282374688ee212dc44b3f37ff929431de9c9adc3053bd3cee5630357"
2609+
checksum = "1c205cc82214f3594e2d50686730314f817c67ffa80fe800cf0db78c3c2b9d9e"
26102610
dependencies = [
26112611
"bitflags",
2612+
"getopts",
26122613
"memchr",
26132614
"unicase",
26142615
]
26152616

26162617
[[package]]
26172618
name = "pulldown-cmark"
2618-
version = "0.6.1"
2619+
version = "0.7.0"
26192620
source = "registry+https://github.com/rust-lang/crates.io-index"
2620-
checksum = "1c205cc82214f3594e2d50686730314f817c67ffa80fe800cf0db78c3c2b9d9e"
2621+
checksum = "2c2d7fd131800e0d63df52aff46201acaab70b431a4a1ec6f0343fe8e64f35a4"
26212622
dependencies = [
26222623
"bitflags",
2623-
"getopts",
26242624
"memchr",
26252625
"unicase",
26262626
]
@@ -4160,7 +4160,7 @@ version = "0.0.0"
41604160
dependencies = [
41614161
"itertools 0.8.0",
41624162
"minifier",
4163-
"pulldown-cmark 0.5.3",
4163+
"pulldown-cmark 0.7.0",
41644164
"rustc-rayon",
41654165
"serde",
41664166
"serde_json",
@@ -5160,11 +5160,11 @@ checksum = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86"
51605160

51615161
[[package]]
51625162
name = "unicase"
5163-
version = "2.5.1"
5163+
version = "2.6.0"
51645164
source = "registry+https://github.com/rust-lang/crates.io-index"
5165-
checksum = "2e2e6bd1e59e56598518beb94fd6db628ded570326f0a98c679a304bd9f00150"
5165+
checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
51665166
dependencies = [
5167-
"version_check 0.1.5",
5167+
"version_check",
51685168
]
51695169

51705170
[[package]]
@@ -5334,12 +5334,6 @@ dependencies = [
53345334
"failure",
53355335
]
53365336

5337-
[[package]]
5338-
name = "version_check"
5339-
version = "0.1.5"
5340-
source = "registry+https://github.com/rust-lang/crates.io-index"
5341-
checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
5342-
53435337
[[package]]
53445338
name = "version_check"
53455339
version = "0.9.1"

‎src/librustc/traits/fulfill.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,13 @@ use super::{FulfillmentError, FulfillmentErrorCode};
1818
use super::{ObligationCause, PredicateObligation};
1919

2020
impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> {
21-
type Predicate = ty::Predicate<'tcx>;
21+
/// Note that we include both the `ParamEnv` and the `Predicate`,
22+
/// as the `ParamEnv` can influence whether fulfillment succeeds
23+
/// or fails.
24+
type CacheKey = ty::ParamEnvAnd<'tcx, ty::Predicate<'tcx>>;
2225

23-
fn as_predicate(&self) -> &Self::Predicate {
24-
&self.obligation.predicate
26+
fn as_cache_key(&self) -> Self::CacheKey {
27+
self.obligation.param_env.and(self.obligation.predicate)
2528
}
2629
}
2730

‎src/librustc_ast_lowering/pat.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
128128
let mut slice = None;
129129
let mut prev_rest_span = None;
130130

131+
// Lowers `$bm $ident @ ..` to `$bm $ident @ _`.
132+
let lower_rest_sub = |this: &mut Self, pat, bm, ident, sub| {
133+
let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub));
134+
let node = this.lower_pat_ident(pat, bm, ident, lower_sub);
135+
this.pat_with_node_id_of(pat, node)
136+
};
137+
131138
let mut iter = pats.iter();
132139
// Lower all the patterns until the first occurrence of a sub-slice pattern.
133140
for pat in iter.by_ref() {
@@ -142,9 +149,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
142149
// Record, lower it to `$binding_mode $ident @ _`, and stop here.
143150
PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => {
144151
prev_rest_span = Some(sub.span);
145-
let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub));
146-
let node = self.lower_pat_ident(pat, bm, ident, lower_sub);
147-
slice = Some(self.pat_with_node_id_of(pat, node));
152+
slice = Some(lower_rest_sub(self, pat, bm, ident, sub));
148153
break;
149154
}
150155
// It was not a subslice pattern so lower it normally.
@@ -157,9 +162,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
157162
// There was a previous subslice pattern; make sure we don't allow more.
158163
let rest_span = match pat.kind {
159164
PatKind::Rest => Some(pat.span),
160-
PatKind::Ident(.., Some(ref sub)) if sub.is_rest() => {
161-
// The `HirValidator` is merciless; add a `_` pattern to avoid ICEs.
162-
after.push(self.pat_wild_with_node_id_of(pat));
165+
PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => {
166+
// #69103: Lower into `binding @ _` as above to avoid ICEs.
167+
after.push(lower_rest_sub(self, pat, bm, ident, sub));
163168
Some(sub.span)
164169
}
165170
_ => None,

‎src/librustc_data_structures/obligation_forest/graphviz.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ impl<'a, O: ForestObligation + 'a> dot::Labeller<'a> for &'a ObligationForest<O>
5252

5353
fn node_label(&self, index: &Self::Node) -> dot::LabelText<'_> {
5454
let node = &self.nodes[*index];
55-
let label = format!("{:?} ({:?})", node.obligation.as_predicate(), node.state.get());
55+
let label = format!("{:?} ({:?})", node.obligation.as_cache_key(), node.state.get());
5656

5757
dot::LabelText::LabelStr(label.into())
5858
}

‎src/librustc_data_structures/obligation_forest/mod.rs

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,13 @@ mod graphviz;
8686
mod tests;
8787

8888
pub trait ForestObligation: Clone + Debug {
89-
type Predicate: Clone + hash::Hash + Eq + Debug;
89+
type CacheKey: Clone + hash::Hash + Eq + Debug;
9090

91-
fn as_predicate(&self) -> &Self::Predicate;
91+
/// Converts this `ForestObligation` suitable for use as a cache key.
92+
/// If two distinct `ForestObligations`s return the same cache key,
93+
/// then it must be sound to use the result of processing one obligation
94+
/// (e.g. success for error) for the other obligation
95+
fn as_cache_key(&self) -> Self::CacheKey;
9296
}
9397

9498
pub trait ObligationProcessor {
@@ -138,12 +142,12 @@ pub struct ObligationForest<O: ForestObligation> {
138142
nodes: Vec<Node<O>>,
139143

140144
/// A cache of predicates that have been successfully completed.
141-
done_cache: FxHashSet<O::Predicate>,
145+
done_cache: FxHashSet<O::CacheKey>,
142146

143147
/// A cache of the nodes in `nodes`, indexed by predicate. Unfortunately,
144148
/// its contents are not guaranteed to match those of `nodes`. See the
145149
/// comments in `process_obligation` for details.
146-
active_cache: FxHashMap<O::Predicate, usize>,
150+
active_cache: FxHashMap<O::CacheKey, usize>,
147151

148152
/// A vector reused in compress(), to avoid allocating new vectors.
149153
node_rewrites: Vec<usize>,
@@ -157,7 +161,7 @@ pub struct ObligationForest<O: ForestObligation> {
157161
/// See [this][details] for details.
158162
///
159163
/// [details]: https://github.com/rust-lang/rust/pull/53255#issuecomment-421184780
160-
error_cache: FxHashMap<ObligationTreeId, FxHashSet<O::Predicate>>,
164+
error_cache: FxHashMap<ObligationTreeId, FxHashSet<O::CacheKey>>,
161165
}
162166

163167
#[derive(Debug)]
@@ -305,11 +309,12 @@ impl<O: ForestObligation> ObligationForest<O> {
305309

306310
// Returns Err(()) if we already know this obligation failed.
307311
fn register_obligation_at(&mut self, obligation: O, parent: Option<usize>) -> Result<(), ()> {
308-
if self.done_cache.contains(obligation.as_predicate()) {
312+
if self.done_cache.contains(&obligation.as_cache_key()) {
313+
debug!("register_obligation_at: ignoring already done obligation: {:?}", obligation);
309314
return Ok(());
310315
}
311316

312-
match self.active_cache.entry(obligation.as_predicate().clone()) {
317+
match self.active_cache.entry(obligation.as_cache_key().clone()) {
313318
Entry::Occupied(o) => {
314319
let node = &mut self.nodes[*o.get()];
315320
if let Some(parent_index) = parent {
@@ -333,7 +338,7 @@ impl<O: ForestObligation> ObligationForest<O> {
333338
&& self
334339
.error_cache
335340
.get(&obligation_tree_id)
336-
.map(|errors| errors.contains(obligation.as_predicate()))
341+
.map(|errors| errors.contains(&obligation.as_cache_key()))
337342
.unwrap_or(false);
338343

339344
if already_failed {
@@ -380,7 +385,7 @@ impl<O: ForestObligation> ObligationForest<O> {
380385
self.error_cache
381386
.entry(node.obligation_tree_id)
382387
.or_default()
383-
.insert(node.obligation.as_predicate().clone());
388+
.insert(node.obligation.as_cache_key().clone());
384389
}
385390

386391
/// Performs a pass through the obligation list. This must
@@ -618,11 +623,11 @@ impl<O: ForestObligation> ObligationForest<O> {
618623
// `self.nodes`. See the comment in `process_obligation`
619624
// for more details.
620625
if let Some((predicate, _)) =
621-
self.active_cache.remove_entry(node.obligation.as_predicate())
626+
self.active_cache.remove_entry(&node.obligation.as_cache_key())
622627
{
623628
self.done_cache.insert(predicate);
624629
} else {
625-
self.done_cache.insert(node.obligation.as_predicate().clone());
630+
self.done_cache.insert(node.obligation.as_cache_key().clone());
626631
}
627632
if do_completed == DoCompleted::Yes {
628633
// Extract the success stories.
@@ -635,7 +640,7 @@ impl<O: ForestObligation> ObligationForest<O> {
635640
// We *intentionally* remove the node from the cache at this point. Otherwise
636641
// tests must come up with a different type on every type error they
637642
// check against.
638-
self.active_cache.remove(node.obligation.as_predicate());
643+
self.active_cache.remove(&node.obligation.as_cache_key());
639644
self.insert_into_error_cache(index);
640645
node_rewrites[index] = orig_nodes_len;
641646
dead_nodes += 1;

‎src/librustc_data_structures/obligation_forest/tests.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ use std::fmt;
44
use std::marker::PhantomData;
55

66
impl<'a> super::ForestObligation for &'a str {
7-
type Predicate = &'a str;
7+
type CacheKey = &'a str;
88

9-
fn as_predicate(&self) -> &Self::Predicate {
9+
fn as_cache_key(&self) -> Self::CacheKey {
1010
self
1111
}
1212
}

‎src/librustc_expand/mbe/macro_rules.rs

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -191,9 +191,9 @@ fn generic_extension<'cx>(
191191
let mut best_failure: Option<(Token, &str)> = None;
192192

193193
// We create a base parser that can be used for the "black box" parts.
194-
// Every iteration needs a fresh copy of that base parser. However, the
195-
// parser is not mutated on many of the iterations, particularly when
196-
// dealing with macros like this:
194+
// Every iteration needs a fresh copy of that parser. However, the parser
195+
// is not mutated on many of the iterations, particularly when dealing with
196+
// macros like this:
197197
//
198198
// macro_rules! foo {
199199
// ("a") => (A);
@@ -209,11 +209,9 @@ fn generic_extension<'cx>(
209209
// hacky, but speeds up the `html5ever` benchmark significantly. (Issue
210210
// 68836 suggests a more comprehensive but more complex change to deal with
211211
// this situation.)
212-
let base_parser = base_parser_from_cx(&cx.current_expansion, &cx.parse_sess, arg.clone());
212+
let parser = parser_from_cx(&cx.current_expansion, &cx.parse_sess, arg.clone());
213213

214214
for (i, lhs) in lhses.iter().enumerate() {
215-
let mut parser = Cow::Borrowed(&base_parser);
216-
217215
// try each arm's matchers
218216
let lhs_tt = match *lhs {
219217
mbe::TokenTree::Delimited(_, ref delim) => &delim.tts[..],
@@ -224,13 +222,14 @@ fn generic_extension<'cx>(
224222
// This is used so that if a matcher is not `Success(..)`ful,
225223
// then the spans which became gated when parsing the unsuccessful matcher
226224
// are not recorded. On the first `Success(..)`ful matcher, the spans are merged.
227-
let mut gated_spans_snaphot = mem::take(&mut *cx.parse_sess.gated_spans.spans.borrow_mut());
225+
let mut gated_spans_snapshot =
226+
mem::take(&mut *cx.parse_sess.gated_spans.spans.borrow_mut());
228227

229-
match parse_tt(&mut parser, lhs_tt) {
228+
match parse_tt(&mut Cow::Borrowed(&parser), lhs_tt) {
230229
Success(named_matches) => {
231230
// The matcher was `Success(..)`ful.
232231
// Merge the gated spans from parsing the matcher with the pre-existing ones.
233-
cx.parse_sess.gated_spans.merge(gated_spans_snaphot);
232+
cx.parse_sess.gated_spans.merge(gated_spans_snapshot);
234233

235234
let rhs = match rhses[i] {
236235
// ignore delimiters
@@ -291,9 +290,9 @@ fn generic_extension<'cx>(
291290

292291
// The matcher was not `Success(..)`ful.
293292
// Restore to the state before snapshotting and maybe try again.
294-
mem::swap(&mut gated_spans_snaphot, &mut cx.parse_sess.gated_spans.spans.borrow_mut());
293+
mem::swap(&mut gated_spans_snapshot, &mut cx.parse_sess.gated_spans.spans.borrow_mut());
295294
}
296-
drop(base_parser);
295+
drop(parser);
297296

298297
let (token, label) = best_failure.expect("ran no matchers");
299298
let span = token.span.substitute_dummy(sp);
@@ -311,9 +310,8 @@ fn generic_extension<'cx>(
311310
mbe::TokenTree::Delimited(_, ref delim) => &delim.tts[..],
312311
_ => continue,
313312
};
314-
let base_parser =
315-
base_parser_from_cx(&cx.current_expansion, &cx.parse_sess, arg.clone());
316-
match parse_tt(&mut Cow::Borrowed(&base_parser), lhs_tt) {
313+
let parser = parser_from_cx(&cx.current_expansion, &cx.parse_sess, arg.clone());
314+
match parse_tt(&mut Cow::Borrowed(&parser), lhs_tt) {
317315
Success(_) => {
318316
if comma_span.is_dummy() {
319317
err.note("you might be missing a comma");
@@ -395,8 +393,8 @@ pub fn compile_declarative_macro(
395393
),
396394
];
397395

398-
let base_parser = Parser::new(sess, body, None, true, true, rustc_parse::MACRO_ARGUMENTS);
399-
let argument_map = match parse_tt(&mut Cow::Borrowed(&base_parser), &argument_gram) {
396+
let parser = Parser::new(sess, body, None, true, true, rustc_parse::MACRO_ARGUMENTS);
397+
let argument_map = match parse_tt(&mut Cow::Borrowed(&parser), &argument_gram) {
400398
Success(m) => m,
401399
Failure(token, msg) => {
402400
let s = parse_failure_msg(&token);
@@ -1212,7 +1210,7 @@ fn quoted_tt_to_string(tt: &mbe::TokenTree) -> String {
12121210
}
12131211
}
12141212

1215-
fn base_parser_from_cx<'cx>(
1213+
fn parser_from_cx<'cx>(
12161214
current_expansion: &'cx ExpansionData,
12171215
sess: &'cx ParseSess,
12181216
tts: TokenStream,

‎src/librustc_mir/transform/simplify_try.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ impl<'tcx> MirPass<'tcx> for SimplifyArmIdentity {
5252
Some(x) => x,
5353
};
5454
if local_tmp_s0 != local_tmp_s1
55+
// Avoid moving into ourselves.
56+
|| local_0 == local_1
5557
// The field-and-variant information match up.
5658
|| vf_s0 != vf_s1
5759
// Source and target locals have the same type.
@@ -64,6 +66,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyArmIdentity {
6466
}
6567

6668
// Right shape; transform!
69+
s0.source_info = s2.source_info;
6770
match &mut s0.kind {
6871
StatementKind::Assign(box (place, rvalue)) => {
6972
*place = local_0.into();

‎src/librustc_typeck/check/op.rs

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2525

2626
let ty =
2727
if !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() && is_builtin_binop(lhs_ty, rhs_ty, op) {
28-
self.enforce_builtin_binop_types(lhs, lhs_ty, rhs, rhs_ty, op);
28+
self.enforce_builtin_binop_types(&lhs.span, lhs_ty, &rhs.span, rhs_ty, op);
2929
self.tcx.mk_unit()
3030
} else {
3131
return_ty
@@ -86,8 +86,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
8686
&& !rhs_ty.is_ty_var()
8787
&& is_builtin_binop(lhs_ty, rhs_ty, op)
8888
{
89-
let builtin_return_ty =
90-
self.enforce_builtin_binop_types(lhs_expr, lhs_ty, rhs_expr, rhs_ty, op);
89+
let builtin_return_ty = self.enforce_builtin_binop_types(
90+
&lhs_expr.span,
91+
lhs_ty,
92+
&rhs_expr.span,
93+
rhs_ty,
94+
op,
95+
);
9196
self.demand_suptype(expr.span, builtin_return_ty, return_ty);
9297
}
9398

@@ -98,19 +103,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
98103

99104
fn enforce_builtin_binop_types(
100105
&self,
101-
lhs_expr: &'tcx hir::Expr<'tcx>,
106+
lhs_span: &Span,
102107
lhs_ty: Ty<'tcx>,
103-
rhs_expr: &'tcx hir::Expr<'tcx>,
108+
rhs_span: &Span,
104109
rhs_ty: Ty<'tcx>,
105110
op: hir::BinOp,
106111
) -> Ty<'tcx> {
107112
debug_assert!(is_builtin_binop(lhs_ty, rhs_ty, op));
108113

114+
// Special-case a single layer of referencing, so that things like `5.0 + &6.0f32` work.
115+
// (See https://github.com/rust-lang/rust/issues/57447.)
116+
let (lhs_ty, rhs_ty) = (deref_ty_if_possible(lhs_ty), deref_ty_if_possible(rhs_ty));
117+
109118
let tcx = self.tcx;
110119
match BinOpCategory::from(op) {
111120
BinOpCategory::Shortcircuit => {
112-
self.demand_suptype(lhs_expr.span, tcx.mk_bool(), lhs_ty);
113-
self.demand_suptype(rhs_expr.span, tcx.mk_bool(), rhs_ty);
121+
self.demand_suptype(*lhs_span, tcx.mk_bool(), lhs_ty);
122+
self.demand_suptype(*rhs_span, tcx.mk_bool(), rhs_ty);
114123
tcx.mk_bool()
115124
}
116125

@@ -121,13 +130,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
121130

122131
BinOpCategory::Math | BinOpCategory::Bitwise => {
123132
// both LHS and RHS and result will have the same type
124-
self.demand_suptype(rhs_expr.span, lhs_ty, rhs_ty);
133+
self.demand_suptype(*rhs_span, lhs_ty, rhs_ty);
125134
lhs_ty
126135
}
127136

128137
BinOpCategory::Comparison => {
129138
// both LHS and RHS and result will have the same type
130-
self.demand_suptype(rhs_expr.span, lhs_ty, rhs_ty);
139+
self.demand_suptype(*rhs_span, lhs_ty, rhs_ty);
131140
tcx.mk_bool()
132141
}
133142
}
@@ -862,6 +871,14 @@ enum Op {
862871
Unary(hir::UnOp, Span),
863872
}
864873

874+
/// Dereferences a single level of immutable referencing.
875+
fn deref_ty_if_possible<'tcx>(ty: Ty<'tcx>) -> Ty<'tcx> {
876+
match ty.kind {
877+
ty::Ref(_, ty, hir::Mutability::Not) => ty,
878+
_ => ty,
879+
}
880+
}
881+
865882
/// Returns `true` if this is a built-in arithmetic operation (e.g., u32
866883
/// + u32, i16x4 == i16x4) and false if these types would have to be
867884
/// overloaded to be legal. There are two reasons that we distinguish
@@ -878,7 +895,11 @@ enum Op {
878895
/// Reason #2 is the killer. I tried for a while to always use
879896
/// overloaded logic and just check the types in constants/codegen after
880897
/// the fact, and it worked fine, except for SIMD types. -nmatsakis
881-
fn is_builtin_binop(lhs: Ty<'_>, rhs: Ty<'_>, op: hir::BinOp) -> bool {
898+
fn is_builtin_binop<'tcx>(lhs: Ty<'tcx>, rhs: Ty<'tcx>, op: hir::BinOp) -> bool {
899+
// Special-case a single layer of referencing, so that things like `5.0 + &6.0f32` work.
900+
// (See https://github.com/rust-lang/rust/issues/57447.)
901+
let (lhs, rhs) = (deref_ty_if_possible(lhs), deref_ty_if_possible(rhs));
902+
882903
match BinOpCategory::from(op) {
883904
BinOpCategory::Shortcircuit => true,
884905

‎src/librustc_typeck/check/pat.rs

Lines changed: 64 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,18 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
8989
}
9090
}
9191

92+
const INITIAL_BM: BindingMode = BindingMode::BindByValue(hir::Mutability::Not);
93+
94+
/// Mode for adjusting the expected type and binding mode.
95+
enum AdjustMode {
96+
/// Peel off all immediate reference types.
97+
Peel,
98+
/// Reset binding mode to the inital mode.
99+
Reset,
100+
/// Pass on the input binding mode and expected type.
101+
Pass,
102+
}
103+
92104
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
93105
/// Type check the given top level pattern against the `expected` type.
94106
///
@@ -105,8 +117,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
105117
span: Option<Span>,
106118
origin_expr: bool,
107119
) {
108-
let def_bm = BindingMode::BindByValue(hir::Mutability::Not);
109-
self.check_pat(pat, expected, def_bm, TopInfo { expected, origin_expr, span });
120+
self.check_pat(pat, expected, INITIAL_BM, TopInfo { expected, origin_expr, span });
110121
}
111122

112123
/// Type check the given `pat` against the `expected` type
@@ -123,12 +134,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
123134
) {
124135
debug!("check_pat(pat={:?},expected={:?},def_bm={:?})", pat, expected, def_bm);
125136

126-
let path_resolution = match &pat.kind {
137+
let path_res = match &pat.kind {
127138
PatKind::Path(qpath) => Some(self.resolve_ty_and_res_ufcs(qpath, pat.hir_id, pat.span)),
128139
_ => None,
129140
};
130-
let is_nrp = self.is_non_ref_pat(pat, path_resolution.map(|(res, ..)| res));
131-
let (expected, def_bm) = self.calc_default_binding_mode(pat, expected, def_bm, is_nrp);
141+
let adjust_mode = self.calc_adjust_mode(pat, path_res.map(|(res, ..)| res));
142+
let (expected, def_bm) = self.calc_default_binding_mode(pat, expected, def_bm, adjust_mode);
132143

133144
let ty = match pat.kind {
134145
PatKind::Wild => expected,
@@ -141,7 +152,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
141152
self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, def_bm, ti)
142153
}
143154
PatKind::Path(ref qpath) => {
144-
self.check_pat_path(pat, path_resolution.unwrap(), qpath, expected)
155+
self.check_pat_path(pat, path_res.unwrap(), qpath, expected)
145156
}
146157
PatKind::Struct(ref qpath, fields, etc) => {
147158
self.check_pat_struct(pat, qpath, fields, etc, expected, def_bm, ti)
@@ -223,64 +234,68 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
223234
pat: &'tcx Pat<'tcx>,
224235
expected: Ty<'tcx>,
225236
def_bm: BindingMode,
226-
is_non_ref_pat: bool,
237+
adjust_mode: AdjustMode,
227238
) -> (Ty<'tcx>, BindingMode) {
228-
if is_non_ref_pat {
229-
debug!("pattern is non reference pattern");
230-
self.peel_off_references(pat, expected, def_bm)
231-
} else {
232-
// When you encounter a `&pat` pattern, reset to "by
233-
// value". This is so that `x` and `y` here are by value,
234-
// as they appear to be:
235-
//
236-
// ```
237-
// match &(&22, &44) {
238-
// (&x, &y) => ...
239-
// }
240-
// ```
241-
//
242-
// See issue #46688.
243-
let def_bm = match pat.kind {
244-
PatKind::Ref(..) => ty::BindByValue(hir::Mutability::Not),
245-
_ => def_bm,
246-
};
247-
(expected, def_bm)
239+
match adjust_mode {
240+
AdjustMode::Pass => (expected, def_bm),
241+
AdjustMode::Reset => (expected, INITIAL_BM),
242+
AdjustMode::Peel => self.peel_off_references(pat, expected, def_bm),
248243
}
249244
}
250245

251-
/// Is the pattern a "non reference pattern"?
246+
/// How should the binding mode and expected type be adjusted?
247+
///
252248
/// When the pattern is a path pattern, `opt_path_res` must be `Some(res)`.
253-
fn is_non_ref_pat(&self, pat: &'tcx Pat<'tcx>, opt_path_res: Option<Res>) -> bool {
254-
match pat.kind {
249+
fn calc_adjust_mode(&self, pat: &'tcx Pat<'tcx>, opt_path_res: Option<Res>) -> AdjustMode {
250+
match &pat.kind {
251+
// Type checking these product-like types successfully always require
252+
// that the expected type be of those types and not reference types.
255253
PatKind::Struct(..)
256254
| PatKind::TupleStruct(..)
257255
| PatKind::Tuple(..)
258256
| PatKind::Box(_)
259257
| PatKind::Range(..)
260-
| PatKind::Slice(..) => true,
261-
PatKind::Lit(ref lt) => {
262-
let ty = self.check_expr(lt);
263-
match ty.kind {
264-
ty::Ref(..) => false,
265-
_ => true,
266-
}
267-
}
258+
| PatKind::Slice(..) => AdjustMode::Peel,
259+
// String and byte-string literals result in types `&str` and `&[u8]` respectively.
260+
// All other literals result in non-reference types.
261+
// As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo {}`.
262+
PatKind::Lit(lt) => match self.check_expr(lt).kind {
263+
ty::Ref(..) => AdjustMode::Pass,
264+
_ => AdjustMode::Peel,
265+
},
268266
PatKind::Path(_) => match opt_path_res.unwrap() {
269-
Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => false,
270-
_ => true,
267+
// These constants can be of a reference type, e.g. `const X: &u8 = &0;`.
268+
// Peeling the reference types too early will cause type checking failures.
269+
// Although it would be possible to *also* peel the types of the constants too.
270+
Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => AdjustMode::Pass,
271+
// In the `ValueNS`, we have `SelfCtor(..) | Ctor(_, Const), _)` remaining which
272+
// could successfully compile. The former being `Self` requires a unit struct.
273+
// In either case, and unlike constants, the pattern itself cannot be
274+
// a reference type wherefore peeling doesn't give up any expressivity.
275+
_ => AdjustMode::Peel,
271276
},
272-
// FIXME(or_patterns; Centril | dlrobertson): To keep things compiling
273-
// for or-patterns at the top level, we need to make `p_0 | ... | p_n`
274-
// a "non reference pattern". For example the following currently compiles:
277+
// When encountering a `& mut? pat` pattern, reset to "by value".
278+
// This is so that `x` and `y` here are by value, as they appear to be:
279+
//
275280
// ```
276-
// match &1 {
277-
// e @ &(1...2) | e @ &(3...4) => {}
278-
// _ => {}
281+
// match &(&22, &44) {
282+
// (&x, &y) => ...
279283
// }
280284
// ```
281285
//
282-
// We should consider whether we should do something special in nested or-patterns.
283-
PatKind::Or(_) | PatKind::Wild | PatKind::Binding(..) | PatKind::Ref(..) => false,
286+
// See issue #46688.
287+
PatKind::Ref(..) => AdjustMode::Reset,
288+
// A `_` pattern works with any expected type, so there's no need to do anything.
289+
PatKind::Wild
290+
// Bindings also work with whatever the expected type is,
291+
// and moreover if we peel references off, that will give us the wrong binding type.
292+
// Also, we can have a subpattern `binding @ pat`.
293+
// Each side of the `@` should be treated independently (like with OR-patterns).
294+
| PatKind::Binding(..)
295+
// An OR-pattern just propagates to each individual alternative.
296+
// This is maximally flexible, allowing e.g., `Some(mut x) | &Some(mut x)`.
297+
// In that example, `Some(mut x)` results in `Peel` whereas `&Some(mut x)` in `Reset`.
298+
| PatKind::Or(_) => AdjustMode::Pass,
284299
}
285300
}
286301

@@ -508,7 +523,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
508523
let local_ty = self.local_ty(pat.span, pat.hir_id).decl_ty;
509524
let eq_ty = match bm {
510525
ty::BindByReference(mutbl) => {
511-
// If the binding is like `ref x | ref const x | ref mut x`
526+
// If the binding is like `ref x | ref mut x`,
512527
// then `x` is assigned a value of type `&M T` where M is the
513528
// mutability and T is the expected type.
514529
//

‎src/librustdoc/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ name = "rustdoc"
99
path = "lib.rs"
1010

1111
[dependencies]
12-
pulldown-cmark = { version = "0.5.3", default-features = false }
12+
pulldown-cmark = { version = "0.7", default-features = false }
1313
minifier = "0.0.33"
1414
rayon = { version = "0.3.0", package = "rustc-rayon" }
1515
serde = { version = "1.0", features = ["derive"] }

‎src/librustdoc/html/markdown.rs

Lines changed: 95 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use crate::html::highlight;
3333
use crate::html::toc::TocBuilder;
3434
use crate::test;
3535

36-
use pulldown_cmark::{html, CowStr, Event, Options, Parser, Tag};
36+
use pulldown_cmark::{html, CodeBlockKind, CowStr, Event, Options, Parser, Tag};
3737

3838
#[cfg(test)]
3939
mod tests;
@@ -189,10 +189,15 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
189189
let compile_fail;
190190
let ignore;
191191
let edition;
192-
if let Some(Event::Start(Tag::CodeBlock(lang))) = event {
193-
let parse_result = LangString::parse(&lang, self.check_error_codes, false);
192+
if let Some(Event::Start(Tag::CodeBlock(kind))) = event {
193+
let parse_result = match kind {
194+
CodeBlockKind::Fenced(ref lang) => {
195+
LangString::parse(&lang, self.check_error_codes, false)
196+
}
197+
CodeBlockKind::Indented => LangString::all_false(),
198+
};
194199
if !parse_result.rust {
195-
return Some(Event::Start(Tag::CodeBlock(lang)));
200+
return Some(Event::Start(Tag::CodeBlock(kind)));
196201
}
197202
compile_fail = parse_result.compile_fail;
198203
ignore = parse_result.ignore;
@@ -370,11 +375,11 @@ impl<'a, 'b, 'ids, I: Iterator<Item = Event<'a>>> Iterator for HeadingLinks<'a,
370375
}
371376

372377
let event = self.inner.next();
373-
if let Some(Event::Start(Tag::Header(level))) = event {
378+
if let Some(Event::Start(Tag::Heading(level))) = event {
374379
let mut id = String::new();
375380
for event in &mut self.inner {
376381
match &event {
377-
Event::End(Tag::Header(..)) => break,
382+
Event::End(Tag::Heading(..)) => break,
378383
Event::Text(text) | Event::Code(text) => {
379384
id.extend(text.chars().filter_map(slugify));
380385
}
@@ -391,18 +396,18 @@ impl<'a, 'b, 'ids, I: Iterator<Item = Event<'a>>> Iterator for HeadingLinks<'a,
391396
let mut html_header = String::new();
392397
html::push_html(&mut html_header, self.buf.iter().cloned());
393398
let sec = builder.push(level as u32, html_header, id.clone());
394-
self.buf.push_front(Event::InlineHtml(format!("{} ", sec).into()));
399+
self.buf.push_front(Event::Html(format!("{} ", sec).into()));
395400
}
396401

397-
self.buf.push_back(Event::InlineHtml(format!("</a></h{}>", level).into()));
402+
self.buf.push_back(Event::Html(format!("</a></h{}>", level).into()));
398403

399404
let start_tags = format!(
400405
"<h{level} id=\"{id}\" class=\"section-header\">\
401406
<a href=\"#{id}\">",
402407
id = id,
403408
level = level
404409
);
405-
return Some(Event::InlineHtml(start_tags.into()));
410+
return Some(Event::Html(start_tags.into()));
406411
}
407412
event
408413
}
@@ -556,40 +561,44 @@ pub fn find_testable_code<T: test::Tester>(
556561
error_codes: ErrorCodes,
557562
enable_per_target_ignores: bool,
558563
) {
559-
let mut parser = Parser::new(doc);
564+
let mut parser = Parser::new(doc).into_offset_iter();
560565
let mut prev_offset = 0;
561566
let mut nb_lines = 0;
562567
let mut register_header = None;
563-
while let Some(event) = parser.next() {
568+
while let Some((event, offset)) = parser.next() {
564569
match event {
565-
Event::Start(Tag::CodeBlock(s)) => {
566-
let offset = parser.get_offset();
567-
568-
let block_info = if s.is_empty() {
569-
LangString::all_false()
570-
} else {
571-
LangString::parse(&*s, error_codes, enable_per_target_ignores)
570+
Event::Start(Tag::CodeBlock(kind)) => {
571+
let block_info = match kind {
572+
CodeBlockKind::Fenced(ref lang) => {
573+
if lang.is_empty() {
574+
LangString::all_false()
575+
} else {
576+
LangString::parse(lang, error_codes, enable_per_target_ignores)
577+
}
578+
}
579+
CodeBlockKind::Indented => LangString::all_false(),
572580
};
573581
if !block_info.rust {
574582
continue;
575583
}
584+
576585
let mut test_s = String::new();
577586

578-
while let Some(Event::Text(s)) = parser.next() {
587+
while let Some((Event::Text(s), _)) = parser.next() {
579588
test_s.push_str(&s);
580589
}
581-
582590
let text = test_s
583591
.lines()
584592
.map(|l| map_line(l).for_code())
585593
.collect::<Vec<Cow<'_, str>>>()
586594
.join("\n");
587-
nb_lines += doc[prev_offset..offset].lines().count();
588-
let line = tests.get_line() + nb_lines;
595+
596+
nb_lines += doc[prev_offset..offset.start].lines().count();
597+
let line = tests.get_line() + nb_lines + 1;
589598
tests.add_test(text, block_info, line);
590-
prev_offset = offset;
599+
prev_offset = offset.start;
591600
}
592-
Event::Start(Tag::Header(level)) => {
601+
Event::Start(Tag::Heading(level)) => {
593602
register_header = Some(level as u32);
594603
}
595604
Event::Text(ref s) if register_header.is_some() => {
@@ -783,7 +792,7 @@ impl MarkdownHtml<'_> {
783792

784793
// Treat inline HTML as plain text.
785794
let p = p.map(|event| match event {
786-
Event::Html(text) | Event::InlineHtml(text) => Event::Text(text),
795+
Event::Html(text) => Event::Text(text),
787796
_ => event,
788797
});
789798

@@ -842,10 +851,10 @@ pub fn plain_summary_line(md: &str) -> String {
842851
let next_event = next_event.unwrap();
843852
let (ret, is_in) = match next_event {
844853
Event::Start(Tag::Paragraph) => (None, 1),
845-
Event::Start(Tag::Header(_)) => (None, 1),
854+
Event::Start(Tag::Heading(_)) => (None, 1),
846855
Event::Code(code) => (Some(format!("`{}`", code)), 0),
847856
Event::Text(ref s) if self.is_in > 0 => (Some(s.as_ref().to_owned()), 0),
848-
Event::End(Tag::Paragraph) | Event::End(Tag::Header(_)) => (None, -1),
857+
Event::End(Tag::Paragraph) | Event::End(Tag::Heading(_)) => (None, -1),
849858
_ => (None, 0),
850859
};
851860
if is_in > 0 || (is_in < 0 && self.is_in > 0) {
@@ -940,68 +949,79 @@ crate fn rust_code_blocks(md: &str) -> Vec<RustCodeBlock> {
940949
return code_blocks;
941950
}
942951

943-
let mut p = Parser::new_ext(md, opts());
944-
945-
let mut code_block_start = 0;
946-
let mut code_start = 0;
947-
let mut is_fenced = false;
948-
let mut previous_offset = 0;
949-
let mut in_rust_code_block = false;
950-
while let Some(event) = p.next() {
951-
let offset = p.get_offset();
952+
let mut p = Parser::new_ext(md, opts()).into_offset_iter();
952953

954+
while let Some((event, offset)) = p.next() {
953955
match event {
954956
Event::Start(Tag::CodeBlock(syntax)) => {
955-
let lang_string = if syntax.is_empty() {
956-
LangString::all_false()
957-
} else {
958-
LangString::parse(&*syntax, ErrorCodes::Yes, false)
959-
};
960-
961-
if lang_string.rust {
962-
in_rust_code_block = true;
963-
964-
code_start = offset;
965-
code_block_start = match md[previous_offset..offset].find("```") {
966-
Some(fence_idx) => {
967-
is_fenced = true;
968-
previous_offset + fence_idx
957+
let (syntax, code_start, code_end, range, is_fenced) = match syntax {
958+
CodeBlockKind::Fenced(syntax) => {
959+
let syntax = syntax.as_ref();
960+
let lang_string = if syntax.is_empty() {
961+
LangString::all_false()
962+
} else {
963+
LangString::parse(&*syntax, ErrorCodes::Yes, false)
964+
};
965+
if !lang_string.rust {
966+
continue;
969967
}
970-
None => {
971-
is_fenced = false;
972-
offset
968+
let syntax = if syntax.is_empty() { None } else { Some(syntax.to_owned()) };
969+
let (code_start, mut code_end) = match p.next() {
970+
Some((Event::Text(_), offset)) => (offset.start, offset.end),
971+
Some((_, sub_offset)) => {
972+
let code = Range { start: sub_offset.start, end: sub_offset.start };
973+
code_blocks.push(RustCodeBlock {
974+
is_fenced: true,
975+
range: offset,
976+
code,
977+
syntax,
978+
});
979+
continue;
980+
}
981+
None => {
982+
let code = Range { start: offset.end, end: offset.end };
983+
code_blocks.push(RustCodeBlock {
984+
is_fenced: true,
985+
range: offset,
986+
code,
987+
syntax,
988+
});
989+
continue;
990+
}
991+
};
992+
while let Some((Event::Text(_), offset)) = p.next() {
993+
code_end = offset.end;
973994
}
974-
};
975-
}
976-
}
977-
Event::End(Tag::CodeBlock(syntax)) if in_rust_code_block => {
978-
in_rust_code_block = false;
979-
980-
let code_block_end = if is_fenced {
981-
let fence_str = &md[previous_offset..offset].chars().rev().collect::<String>();
982-
fence_str
983-
.find("```")
984-
.map(|fence_idx| offset - fence_idx)
985-
.unwrap_or_else(|| offset)
986-
} else if md.as_bytes().get(offset).map(|b| *b == b'\n').unwrap_or_default() {
987-
offset - 1
988-
} else {
989-
offset
995+
(syntax, code_start, code_end, offset, true)
996+
}
997+
CodeBlockKind::Indented => {
998+
// The ending of the offset goes too far sometime so we reduce it by one in
999+
// these cases.
1000+
if offset.end > offset.start
1001+
&& md.get(offset.end..=offset.end) == Some(&"\n")
1002+
{
1003+
(
1004+
None,
1005+
offset.start,
1006+
offset.end,
1007+
Range { start: offset.start, end: offset.end - 1 },
1008+
false,
1009+
)
1010+
} else {
1011+
(None, offset.start, offset.end, offset, false)
1012+
}
1013+
}
9901014
};
9911015

992-
let code_end = if is_fenced { previous_offset } else { code_block_end };
993-
9941016
code_blocks.push(RustCodeBlock {
9951017
is_fenced,
996-
range: Range { start: code_block_start, end: code_block_end },
1018+
range,
9971019
code: Range { start: code_start, end: code_end },
998-
syntax: if !syntax.is_empty() { Some(syntax.into_string()) } else { None },
1020+
syntax,
9991021
});
10001022
}
10011023
_ => (),
10021024
}
1003-
1004-
previous_offset = offset;
10051025
}
10061026

10071027
code_blocks
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// We used to not lower the extra `b @ ..` into `b @ _` which meant that no type
2+
// was registered for the binding `b` although it passed through resolve.
3+
// This resulted in an ICE (#69103).
4+
5+
fn main() {
6+
let [a @ .., b @ ..] = &mut [1, 2];
7+
//~^ ERROR `..` can only be used once per slice pattern
8+
b;
9+
10+
let [.., c @ ..] = [1, 2];
11+
//~^ ERROR `..` can only be used once per slice pattern
12+
c;
13+
14+
// This never ICEd, but let's make sure it won't regress either.
15+
let (.., d @ ..) = (1, 2);
16+
//~^ ERROR `..` patterns are not allowed here
17+
d;
18+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
error: `..` can only be used once per slice pattern
2+
--> $DIR/issue-69103-extra-binding-subslice.rs:6:22
3+
|
4+
LL | let [a @ .., b @ ..] = &mut [1, 2];
5+
| -- ^^ can only be used once per slice pattern
6+
| |
7+
| previously used here
8+
9+
error: `..` can only be used once per slice pattern
10+
--> $DIR/issue-69103-extra-binding-subslice.rs:10:18
11+
|
12+
LL | let [.., c @ ..] = [1, 2];
13+
| -- ^^ can only be used once per slice pattern
14+
| |
15+
| previously used here
16+
17+
error: `..` patterns are not allowed here
18+
--> $DIR/issue-69103-extra-binding-subslice.rs:15:18
19+
|
20+
LL | let (.., d @ ..) = (1, 2);
21+
| ^^
22+
|
23+
= note: only allowed in tuple, tuple struct, and slice patterns
24+
25+
error: aborting due to 3 previous errors
26+
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// check-pass
2+
3+
fn main() {
4+
// Test that we can infer the type of binary operands when
5+
// references are involved, on various types and operators.
6+
let _: u8 = 0 + 0;
7+
let _: u8 = 0 + &0;
8+
let _: u8 = &0 + 0;
9+
let _: u8 = &0 + &0;
10+
11+
let _: f32 = 0.0 + 0.0;
12+
let _: f32 = 0.0 + &0.0;
13+
let _: f32 = &0.0 + 0.0;
14+
let _: f32 = &0.0 + &0.0;
15+
16+
let _: u8 = 0 << 0;
17+
let _: u8 = 0 << &0;
18+
let _: u8 = &0 << 0;
19+
let _: u8 = &0 << &0;
20+
21+
// Test type inference when variable types are indirectly inferred.
22+
let a = 22;
23+
let _: usize = a + &44;
24+
25+
// When we have no expected type, the types of the operands is the default type.
26+
let _ = 0 + 0;
27+
let _ = 0 + &0;
28+
let _ = &0 + 0;
29+
let _ = &0 + &0;
30+
}

‎src/test/ui/or-patterns/or-pattern-mismatch.rs

Lines changed: 0 additions & 4 deletions
This file was deleted.

‎src/test/ui/or-patterns/or-pattern-mismatch.stderr

Lines changed: 0 additions & 9 deletions
This file was deleted.
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// Here we test type checking of bindings when combined with or-patterns.
2+
// Specifically, we ensure that introducing bindings of different types result in type errors.
3+
4+
#![feature(or_patterns)]
5+
6+
fn main() {
7+
enum Blah {
8+
A(isize, isize, usize),
9+
B(isize, isize),
10+
}
11+
12+
match Blah::A(1, 1, 2) {
13+
Blah::A(_, x, y) | Blah::B(x, y) => {} //~ ERROR mismatched types
14+
}
15+
16+
match Some(Blah::A(1, 1, 2)) {
17+
Some(Blah::A(_, x, y) | Blah::B(x, y)) => {} //~ ERROR mismatched types
18+
}
19+
20+
match (0u8, 1u16) {
21+
(x, y) | (y, x) => {} //~ ERROR mismatched types
22+
//~^ ERROR mismatched types
23+
}
24+
25+
match Some((0u8, Some((1u16, 2u32)))) {
26+
Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {}
27+
//~^ ERROR mismatched types
28+
//~| ERROR mismatched types
29+
//~| ERROR mismatched types
30+
//~| ERROR mismatched types
31+
_ => {}
32+
}
33+
34+
if let Blah::A(_, x, y) | Blah::B(x, y) = Blah::A(1, 1, 2) {
35+
//~^ ERROR mismatched types
36+
}
37+
38+
if let Some(Blah::A(_, x, y) | Blah::B(x, y)) = Some(Blah::A(1, 1, 2)) {
39+
//~^ ERROR mismatched types
40+
}
41+
42+
if let (x, y) | (y, x) = (0u8, 1u16) {
43+
//~^ ERROR mismatched types
44+
//~| ERROR mismatched types
45+
}
46+
47+
if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x))))
48+
//~^ ERROR mismatched types
49+
//~| ERROR mismatched types
50+
//~| ERROR mismatched types
51+
//~| ERROR mismatched types
52+
= Some((0u8, Some((1u16, 2u32))))
53+
{}
54+
55+
let Blah::A(_, x, y) | Blah::B(x, y) = Blah::A(1, 1, 2);
56+
//~^ ERROR mismatched types
57+
58+
let (x, y) | (y, x) = (0u8, 1u16);
59+
//~^ ERROR mismatched types
60+
//~| ERROR mismatched types
61+
62+
fn f1((Blah::A(_, x, y) | Blah::B(x, y)): Blah) {}
63+
//~^ ERROR mismatched types
64+
65+
fn f2(((x, y) | (y, x)): (u8, u16)) {}
66+
//~^ ERROR mismatched types
67+
//~| ERROR mismatched types
68+
}
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/or-patterns-binding-type-mismatch.rs:13:39
3+
|
4+
LL | match Blah::A(1, 1, 2) {
5+
| ---------------- this expression has type `main::Blah`
6+
LL | Blah::A(_, x, y) | Blah::B(x, y) => {}
7+
| ^ expected `usize`, found `isize`
8+
9+
error[E0308]: mismatched types
10+
--> $DIR/or-patterns-binding-type-mismatch.rs:17:44
11+
|
12+
LL | match Some(Blah::A(1, 1, 2)) {
13+
| ---------------------- this expression has type `std::option::Option<main::Blah>`
14+
LL | Some(Blah::A(_, x, y) | Blah::B(x, y)) => {}
15+
| ^ expected `usize`, found `isize`
16+
17+
error[E0308]: mismatched types
18+
--> $DIR/or-patterns-binding-type-mismatch.rs:21:19
19+
|
20+
LL | match (0u8, 1u16) {
21+
| ----------- this expression has type `(u8, u16)`
22+
LL | (x, y) | (y, x) => {}
23+
| ^ expected `u16`, found `u8`
24+
25+
error[E0308]: mismatched types
26+
--> $DIR/or-patterns-binding-type-mismatch.rs:21:22
27+
|
28+
LL | match (0u8, 1u16) {
29+
| ----------- this expression has type `(u8, u16)`
30+
LL | (x, y) | (y, x) => {}
31+
| ^ expected `u8`, found `u16`
32+
33+
error[E0308]: mismatched types
34+
--> $DIR/or-patterns-binding-type-mismatch.rs:26:41
35+
|
36+
LL | match Some((0u8, Some((1u16, 2u32)))) {
37+
| ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>`
38+
LL | Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {}
39+
| ^ expected `u16`, found `u8`
40+
41+
error[E0308]: mismatched types
42+
--> $DIR/or-patterns-binding-type-mismatch.rs:26:50
43+
|
44+
LL | match Some((0u8, Some((1u16, 2u32)))) {
45+
| ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>`
46+
LL | Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {}
47+
| ^ expected `u8`, found `u16`
48+
49+
error[E0308]: mismatched types
50+
--> $DIR/or-patterns-binding-type-mismatch.rs:26:59
51+
|
52+
LL | match Some((0u8, Some((1u16, 2u32)))) {
53+
| ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>`
54+
LL | Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {}
55+
| ^ expected `u32`, found `u16`
56+
57+
error[E0308]: mismatched types
58+
--> $DIR/or-patterns-binding-type-mismatch.rs:26:62
59+
|
60+
LL | match Some((0u8, Some((1u16, 2u32)))) {
61+
| ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>`
62+
LL | Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {}
63+
| ^ expected `u8`, found `u32`
64+
65+
error[E0308]: mismatched types
66+
--> $DIR/or-patterns-binding-type-mismatch.rs:34:42
67+
|
68+
LL | if let Blah::A(_, x, y) | Blah::B(x, y) = Blah::A(1, 1, 2) {
69+
| ^ ---------------- this expression has type `main::Blah`
70+
| |
71+
| expected `usize`, found `isize`
72+
73+
error[E0308]: mismatched types
74+
--> $DIR/or-patterns-binding-type-mismatch.rs:38:47
75+
|
76+
LL | if let Some(Blah::A(_, x, y) | Blah::B(x, y)) = Some(Blah::A(1, 1, 2)) {
77+
| ^ ---------------------- this expression has type `std::option::Option<main::Blah>`
78+
| |
79+
| expected `usize`, found `isize`
80+
81+
error[E0308]: mismatched types
82+
--> $DIR/or-patterns-binding-type-mismatch.rs:42:22
83+
|
84+
LL | if let (x, y) | (y, x) = (0u8, 1u16) {
85+
| ^ ----------- this expression has type `(u8, u16)`
86+
| |
87+
| expected `u16`, found `u8`
88+
89+
error[E0308]: mismatched types
90+
--> $DIR/or-patterns-binding-type-mismatch.rs:42:25
91+
|
92+
LL | if let (x, y) | (y, x) = (0u8, 1u16) {
93+
| ^ ----------- this expression has type `(u8, u16)`
94+
| |
95+
| expected `u8`, found `u16`
96+
97+
error[E0308]: mismatched types
98+
--> $DIR/or-patterns-binding-type-mismatch.rs:47:44
99+
|
100+
LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x))))
101+
| ^ expected `u16`, found `u8`
102+
...
103+
LL | = Some((0u8, Some((1u16, 2u32))))
104+
| ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>`
105+
106+
error[E0308]: mismatched types
107+
--> $DIR/or-patterns-binding-type-mismatch.rs:47:53
108+
|
109+
LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x))))
110+
| ^ expected `u8`, found `u16`
111+
...
112+
LL | = Some((0u8, Some((1u16, 2u32))))
113+
| ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>`
114+
115+
error[E0308]: mismatched types
116+
--> $DIR/or-patterns-binding-type-mismatch.rs:47:62
117+
|
118+
LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x))))
119+
| ^ expected `u32`, found `u16`
120+
...
121+
LL | = Some((0u8, Some((1u16, 2u32))))
122+
| ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>`
123+
124+
error[E0308]: mismatched types
125+
--> $DIR/or-patterns-binding-type-mismatch.rs:47:65
126+
|
127+
LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x))))
128+
| ^ expected `u8`, found `u32`
129+
...
130+
LL | = Some((0u8, Some((1u16, 2u32))))
131+
| ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>`
132+
133+
error[E0308]: mismatched types
134+
--> $DIR/or-patterns-binding-type-mismatch.rs:55:39
135+
|
136+
LL | let Blah::A(_, x, y) | Blah::B(x, y) = Blah::A(1, 1, 2);
137+
| ^ ---------------- this expression has type `main::Blah`
138+
| |
139+
| expected `usize`, found `isize`
140+
141+
error[E0308]: mismatched types
142+
--> $DIR/or-patterns-binding-type-mismatch.rs:58:19
143+
|
144+
LL | let (x, y) | (y, x) = (0u8, 1u16);
145+
| ^ ----------- this expression has type `(u8, u16)`
146+
| |
147+
| expected `u16`, found `u8`
148+
149+
error[E0308]: mismatched types
150+
--> $DIR/or-patterns-binding-type-mismatch.rs:58:22
151+
|
152+
LL | let (x, y) | (y, x) = (0u8, 1u16);
153+
| ^ ----------- this expression has type `(u8, u16)`
154+
| |
155+
| expected `u8`, found `u16`
156+
157+
error[E0308]: mismatched types
158+
--> $DIR/or-patterns-binding-type-mismatch.rs:62:42
159+
|
160+
LL | fn f1((Blah::A(_, x, y) | Blah::B(x, y)): Blah) {}
161+
| ^ ---- expected due to this
162+
| |
163+
| expected `usize`, found `isize`
164+
165+
error[E0308]: mismatched types
166+
--> $DIR/or-patterns-binding-type-mismatch.rs:65:22
167+
|
168+
LL | fn f2(((x, y) | (y, x)): (u8, u16)) {}
169+
| ^ --------- expected due to this
170+
| |
171+
| expected `u16`, found `u8`
172+
173+
error[E0308]: mismatched types
174+
--> $DIR/or-patterns-binding-type-mismatch.rs:65:25
175+
|
176+
LL | fn f2(((x, y) | (y, x)): (u8, u16)) {}
177+
| ^ --------- expected due to this
178+
| |
179+
| expected `u8`, found `u16`
180+
181+
error: aborting due to 22 previous errors
182+
183+
For more information about this error, try `rustc --explain E0308`.
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
// Test that or-patterns are pass-through with respect to default binding modes.
2+
3+
// check-pass
4+
5+
#![feature(or_patterns)]
6+
#![allow(irrefutable_let_patterns)]
7+
8+
fn main() {
9+
// A regression test for a mistake we made at one point:
10+
match &1 {
11+
e @ &(1..=2) | e @ &(3..=4) => {}
12+
_ => {}
13+
}
14+
15+
match &0 {
16+
0 | &1 => {}
17+
_ => {}
18+
}
19+
20+
type R<'a> = &'a Result<u8, u8>;
21+
22+
let res: R<'_> = &Ok(0);
23+
24+
match res {
25+
// Alternatives propagate expected type / binding mode independently.
26+
Ok(mut x) | &Err(mut x) => drop::<u8>(x),
27+
}
28+
match res {
29+
&(Ok(x) | Err(x)) => drop::<u8>(x),
30+
}
31+
match res {
32+
Ok(x) | Err(x) => drop::<&u8>(x),
33+
}
34+
if let Ok(mut x) | &Err(mut x) = res {
35+
drop::<u8>(x);
36+
}
37+
if let &(Ok(x) | Err(x)) = res {
38+
drop::<u8>(x);
39+
}
40+
let Ok(mut x) | &Err(mut x) = res;
41+
drop::<u8>(x);
42+
let &(Ok(x) | Err(x)) = res;
43+
drop::<u8>(x);
44+
let Ok(x) | Err(x) = res;
45+
drop::<&u8>(x);
46+
for Ok(mut x) | &Err(mut x) in std::iter::once(res) {
47+
drop::<u8>(x);
48+
}
49+
for &(Ok(x) | Err(x)) in std::iter::once(res) {
50+
drop::<u8>(x);
51+
}
52+
for Ok(x) | Err(x) in std::iter::once(res) {
53+
drop::<&u8>(x);
54+
}
55+
fn f1((Ok(mut x) | &Err(mut x)): R<'_>) {
56+
drop::<u8>(x);
57+
}
58+
fn f2(&(Ok(x) | Err(x)): R<'_>) {
59+
drop::<u8>(x);
60+
}
61+
fn f3((Ok(x) | Err(x)): R<'_>) {
62+
drop::<&u8>(x);
63+
}
64+
65+
// Wrap inside another type (a product for a simplity with irrefutable contexts).
66+
#[derive(Copy, Clone)]
67+
struct Wrap<T>(T);
68+
let wres = Wrap(res);
69+
70+
match wres {
71+
Wrap(Ok(mut x) | &Err(mut x)) => drop::<u8>(x),
72+
}
73+
match wres {
74+
Wrap(&(Ok(x) | Err(x))) => drop::<u8>(x),
75+
}
76+
match wres {
77+
Wrap(Ok(x) | Err(x)) => drop::<&u8>(x),
78+
}
79+
if let Wrap(Ok(mut x) | &Err(mut x)) = wres {
80+
drop::<u8>(x);
81+
}
82+
if let Wrap(&(Ok(x) | Err(x))) = wres {
83+
drop::<u8>(x);
84+
}
85+
if let Wrap(Ok(x) | Err(x)) = wres {
86+
drop::<&u8>(x);
87+
}
88+
let Wrap(Ok(mut x) | &Err(mut x)) = wres;
89+
drop::<u8>(x);
90+
let Wrap(&(Ok(x) | Err(x))) = wres;
91+
drop::<u8>(x);
92+
let Wrap(Ok(x) | Err(x)) = wres;
93+
drop::<&u8>(x);
94+
for Wrap(Ok(mut x) | &Err(mut x)) in std::iter::once(wres) {
95+
drop::<u8>(x);
96+
}
97+
for Wrap(&(Ok(x) | Err(x))) in std::iter::once(wres) {
98+
drop::<u8>(x);
99+
}
100+
for Wrap(Ok(x) | Err(x)) in std::iter::once(wres) {
101+
drop::<&u8>(x);
102+
}
103+
fn fw1(Wrap(Ok(mut x) | &Err(mut x)): Wrap<R<'_>>) {
104+
drop::<u8>(x);
105+
}
106+
fn fw2(Wrap(&(Ok(x) | Err(x))): Wrap<R<'_>>) {
107+
drop::<u8>(x);
108+
}
109+
fn fw3(Wrap(Ok(x) | Err(x)): Wrap<R<'_>>) {
110+
drop::<&u8>(x);
111+
}
112+
113+
// Nest some more:
114+
115+
enum Tri<P> {
116+
A(P),
117+
B(P),
118+
C(P),
119+
}
120+
121+
let tri = &Tri::A(&Ok(0));
122+
let Tri::A(Ok(mut x) | Err(mut x))
123+
| Tri::B(&Ok(mut x) | Err(mut x))
124+
| &Tri::C(Ok(mut x) | Err(mut x)) = tri;
125+
drop::<u8>(x);
126+
127+
match tri {
128+
Tri::A(Ok(mut x) | Err(mut x))
129+
| Tri::B(&Ok(mut x) | Err(mut x))
130+
| &Tri::C(Ok(mut x) | Err(mut x)) => drop::<u8>(x),
131+
}
132+
}

0 commit comments

Comments
 (0)
Please sign in to comment.