Skip to content

Commit 15f5622

Browse files
committed
Auto merge of rust-lang#97896 - compiler-errors:rollup-mrl7ng0, r=compiler-errors
Rollup of 9 pull requests Successful merges: - rust-lang#97557 (Fix indices and remove some unwraps in arg mismatch algorithm) - rust-lang#97830 (Add std::alloc::set_alloc_error_hook example) - rust-lang#97856 (Don't suggest adding `let` in certain `if` conditions) - rust-lang#97857 (Suggest escaping `box` as identifier) - rust-lang#97871 (Suggest using `iter()` or `into_iter()` for `Vec`) - rust-lang#97882 (Add regresion test for rust-lang#67498) - rust-lang#97883 (Remove `ignore-compare-mode-nll` annotations from tests) - rust-lang#97891 (Update books) - rust-lang#97894 (Fix polonius compare mode.) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
2 parents 7466d54 + cfc0677 commit 15f5622

32 files changed

+433
-74
lines changed

compiler/rustc_ast/src/ast.rs

+16
Original file line numberDiff line numberDiff line change
@@ -1278,6 +1278,22 @@ impl Expr {
12781278
},
12791279
)
12801280
}
1281+
1282+
// To a first-order approximation, is this a pattern
1283+
pub fn is_approximately_pattern(&self) -> bool {
1284+
match &self.peel_parens().kind {
1285+
ExprKind::Box(_)
1286+
| ExprKind::Array(_)
1287+
| ExprKind::Call(_, _)
1288+
| ExprKind::Tup(_)
1289+
| ExprKind::Lit(_)
1290+
| ExprKind::Range(_, _, _)
1291+
| ExprKind::Underscore
1292+
| ExprKind::Path(_, _)
1293+
| ExprKind::Struct(_) => true,
1294+
_ => false,
1295+
}
1296+
}
12811297
}
12821298

12831299
/// Limit types of a range (inclusive or exclusive)

compiler/rustc_hir/src/hir.rs

+14
Original file line numberDiff line numberDiff line change
@@ -1813,6 +1813,20 @@ impl Expr<'_> {
18131813
| ExprKind::Err => true,
18141814
}
18151815
}
1816+
1817+
// To a first-order approximation, is this a pattern
1818+
pub fn is_approximately_pattern(&self) -> bool {
1819+
match &self.kind {
1820+
ExprKind::Box(_)
1821+
| ExprKind::Array(_)
1822+
| ExprKind::Call(..)
1823+
| ExprKind::Tup(_)
1824+
| ExprKind::Lit(_)
1825+
| ExprKind::Path(_)
1826+
| ExprKind::Struct(..) => true,
1827+
_ => false,
1828+
}
1829+
}
18161830
}
18171831

18181832
/// Checks if the specified expression is a built-in range literal.

compiler/rustc_parse/src/parser/pat.rs

+57-4
Original file line numberDiff line numberDiff line change
@@ -360,10 +360,7 @@ impl<'a> Parser<'a> {
360360
let mutbl = self.parse_mutability();
361361
self.parse_pat_ident(BindingMode::ByRef(mutbl))?
362362
} else if self.eat_keyword(kw::Box) {
363-
// Parse `box pat`
364-
let pat = self.parse_pat_with_range_pat(false, None)?;
365-
self.sess.gated_spans.gate(sym::box_patterns, lo.to(self.prev_token.span));
366-
PatKind::Box(pat)
363+
self.parse_pat_box()?
367364
} else if self.check_inline_const(0) {
368365
// Parse `const pat`
369366
let const_expr = self.parse_const_block(lo.to(self.token.span), true)?;
@@ -915,6 +912,62 @@ impl<'a> Parser<'a> {
915912
Ok(PatKind::TupleStruct(qself, path, fields))
916913
}
917914

915+
/// Are we sure this could not possibly be the start of a pattern?
916+
///
917+
/// Currently, this only accounts for tokens that can follow identifiers
918+
/// in patterns, but this can be extended as necessary.
919+
fn isnt_pattern_start(&self) -> bool {
920+
[
921+
token::Eq,
922+
token::Colon,
923+
token::Comma,
924+
token::Semi,
925+
token::At,
926+
token::OpenDelim(Delimiter::Brace),
927+
token::CloseDelim(Delimiter::Brace),
928+
token::CloseDelim(Delimiter::Parenthesis),
929+
]
930+
.contains(&self.token.kind)
931+
}
932+
933+
/// Parses `box pat`
934+
fn parse_pat_box(&mut self) -> PResult<'a, PatKind> {
935+
let box_span = self.prev_token.span;
936+
937+
if self.isnt_pattern_start() {
938+
self.struct_span_err(
939+
self.token.span,
940+
format!("expected pattern, found {}", super::token_descr(&self.token)),
941+
)
942+
.span_note(box_span, "`box` is a reserved keyword")
943+
.span_suggestion_verbose(
944+
box_span.shrink_to_lo(),
945+
"escape `box` to use it as an identifier",
946+
"r#",
947+
Applicability::MaybeIncorrect,
948+
)
949+
.emit();
950+
951+
// We cannot use `parse_pat_ident()` since it will complain `box`
952+
// is not an identifier.
953+
let sub = if self.eat(&token::At) {
954+
Some(self.parse_pat_no_top_alt(Some("binding pattern"))?)
955+
} else {
956+
None
957+
};
958+
959+
Ok(PatKind::Ident(
960+
BindingMode::ByValue(Mutability::Not),
961+
Ident::new(kw::Box, box_span),
962+
sub,
963+
))
964+
} else {
965+
let pat = self.parse_pat_with_range_pat(false, None)?;
966+
self.sess.gated_spans.gate(sym::box_patterns, box_span.to(self.prev_token.span));
967+
Ok(PatKind::Box(pat))
968+
}
969+
}
970+
918971
/// Parses the fields of a struct-like pattern.
919972
fn parse_pat_fields(&mut self) -> PResult<'a, (Vec<PatField>, bool)> {
920973
let mut fields = Vec::new();

compiler/rustc_resolve/src/late/diagnostics.rs

+15-7
Original file line numberDiff line numberDiff line change
@@ -265,13 +265,21 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
265265
);
266266
}
267267
match (source, self.diagnostic_metadata.in_if_condition) {
268-
(PathSource::Expr(_), Some(Expr { span, kind: ExprKind::Assign(..), .. })) => {
269-
err.span_suggestion_verbose(
270-
span.shrink_to_lo(),
271-
"you might have meant to use pattern matching",
272-
"let ".to_string(),
273-
Applicability::MaybeIncorrect,
274-
);
268+
(
269+
PathSource::Expr(_),
270+
Some(Expr { span: expr_span, kind: ExprKind::Assign(lhs, _, _), .. }),
271+
) => {
272+
// Icky heuristic so we don't suggest:
273+
// `if (i + 2) = 2` => `if let (i + 2) = 2` (approximately pattern)
274+
// `if 2 = i` => `if let 2 = i` (lhs needs to contain error span)
275+
if lhs.is_approximately_pattern() && lhs.span.contains(span) {
276+
err.span_suggestion_verbose(
277+
expr_span.shrink_to_lo(),
278+
"you might have meant to use pattern matching",
279+
"let ".to_string(),
280+
Applicability::MaybeIncorrect,
281+
);
282+
}
275283
}
276284
_ => {}
277285
}

compiler/rustc_typeck/src/check/expr.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1035,7 +1035,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10351035
} else {
10361036
(Applicability::MaybeIncorrect, false)
10371037
};
1038-
if !lhs.is_syntactic_place_expr() && !matches!(lhs.kind, hir::ExprKind::Lit(_)) {
1038+
if !lhs.is_syntactic_place_expr()
1039+
&& lhs.is_approximately_pattern()
1040+
&& !matches!(lhs.kind, hir::ExprKind::Lit(_))
1041+
{
10391042
// Do not suggest `if let x = y` as `==` is way more likely to be the intention.
10401043
let hir = self.tcx.hir();
10411044
if let hir::Node::Expr(hir::Expr { kind: ExprKind::If { .. }, .. }) =

compiler/rustc_typeck/src/check/fn_ctxt/checks.rs

+25-18
Original file line numberDiff line numberDiff line change
@@ -445,16 +445,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
445445
let found_errors = !errors.is_empty();
446446

447447
errors.drain_filter(|error| {
448-
let Error::Invalid(input_idx, arg_idx, Compatibility::Incompatible(error)) = error else { return false };
448+
let Error::Invalid(input_idx, arg_idx, Compatibility::Incompatible(Some(e))) = error else { return false };
449449
let expected_ty = expected_input_tys[*arg_idx];
450-
let provided_ty = final_arg_types[*input_idx].map(|ty| ty.0).unwrap();
450+
let provided_ty = final_arg_types[*input_idx].map(|ty| ty.0).unwrap_or_else(|| tcx.ty_error());
451451
let cause = &self.misc(provided_args[*input_idx].span);
452452
let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
453-
if let Some(e) = error {
454-
if !matches!(trace.cause.as_failure_code(e), FailureCode::Error0308(_)) {
455-
self.report_and_explain_type_error(trace, e).emit();
456-
return true;
457-
}
453+
if !matches!(trace.cause.as_failure_code(e), FailureCode::Error0308(_)) {
454+
self.report_and_explain_type_error(trace, e).emit();
455+
return true;
458456
}
459457
false
460458
});
@@ -585,7 +583,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
585583
)) = errors.iter().next()
586584
{
587585
let expected_ty = expected_input_tys[*arg_idx];
588-
let provided_ty = final_arg_types[*arg_idx].map(|ty| ty.0).unwrap();
586+
let provided_ty = final_arg_types[*input_idx]
587+
.map(|ty| ty.0)
588+
.unwrap_or_else(|| tcx.ty_error());
589589
let expected_ty = self.resolve_vars_if_possible(expected_ty);
590590
let provided_ty = self.resolve_vars_if_possible(provided_ty);
591591
let cause = &self.misc(provided_args[*input_idx].span);
@@ -595,7 +595,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
595595
&mut err,
596596
&provided_args[*input_idx],
597597
provided_ty,
598-
final_arg_types[*input_idx].map(|ty| ty.1).unwrap(),
598+
final_arg_types[*input_idx]
599+
.map(|ty| ty.1)
600+
.unwrap_or_else(|| tcx.ty_error()),
599601
None,
600602
None,
601603
);
@@ -652,7 +654,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
652654
match error {
653655
Error::Invalid(input_idx, arg_idx, compatibility) => {
654656
let expected_ty = expected_input_tys[arg_idx];
655-
let provided_ty = final_arg_types[input_idx].map(|ty| ty.0).unwrap();
657+
let provided_ty = final_arg_types[input_idx]
658+
.map(|ty| ty.0)
659+
.unwrap_or_else(|| tcx.ty_error());
656660
let expected_ty = self.resolve_vars_if_possible(expected_ty);
657661
let provided_ty = self.resolve_vars_if_possible(provided_ty);
658662
if let Compatibility::Incompatible(error) = &compatibility {
@@ -674,8 +678,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
674678
self.emit_coerce_suggestions(
675679
&mut err,
676680
&provided_args[input_idx],
677-
final_arg_types[input_idx].map(|ty| ty.0).unwrap(),
678-
final_arg_types[input_idx].map(|ty| ty.1).unwrap(),
681+
provided_ty,
682+
// FIXME(compiler-errors): expected_ty?
683+
final_arg_types[input_idx]
684+
.map(|ty| ty.1)
685+
.unwrap_or_else(|| tcx.ty_error()),
679686
None,
680687
None,
681688
);
@@ -860,7 +867,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
860867
let first_expected_ty =
861868
self.resolve_vars_if_possible(expected_input_tys[arg_idx]);
862869
let first_provided_ty = if let Some((ty, _)) = final_arg_types[input_idx] {
863-
format!(",found `{}`", ty)
870+
format!(", found `{}`", ty)
864871
} else {
865872
String::new()
866873
};
@@ -872,7 +879,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
872879
self.resolve_vars_if_possible(expected_input_tys[other_arg_idx]);
873880
let other_provided_ty =
874881
if let Some((ty, _)) = final_arg_types[other_input_idx] {
875-
format!(",found `{}`", ty)
882+
format!(", found `{}`", ty)
876883
} else {
877884
String::new()
878885
};
@@ -888,14 +895,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
888895
Error::Permutation(args) => {
889896
for (dst_arg, dest_input) in args {
890897
let expected_ty =
891-
self.resolve_vars_if_possible(expected_input_tys[dest_input]);
892-
let provided_ty = if let Some((ty, _)) = final_arg_types[dst_arg] {
893-
format!(",found `{}`", ty)
898+
self.resolve_vars_if_possible(expected_input_tys[dst_arg]);
899+
let provided_ty = if let Some((ty, _)) = final_arg_types[dest_input] {
900+
format!(", found `{}`", ty)
894901
} else {
895902
String::new()
896903
};
897904
labels.push((
898-
provided_args[dst_arg].span,
905+
provided_args[dest_input].span,
899906
format!("expected `{}`{}", expected_ty, provided_ty),
900907
));
901908
}

library/core/src/iter/traits/iterator.rs

+4
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
4040
label = "`{Self}` is not an iterator; try calling `.into_iter()` or `.iter()`"
4141
),
4242
on(_Self = "&[]", label = "`{Self}` is not an iterator; try calling `.iter()`"),
43+
on(
44+
_Self = "std::vec::Vec<T, A>",
45+
label = "`{Self}` is not an iterator; try calling `.into_iter()` or `.iter()`"
46+
),
4347
on(
4448
_Self = "&str",
4549
label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`"

library/std/src/alloc.rs

+14
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,20 @@ static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut());
296296
/// about the allocation that failed.
297297
///
298298
/// The allocation error hook is a global resource.
299+
///
300+
/// # Examples
301+
///
302+
/// ```
303+
/// #![feature(alloc_error_hook)]
304+
///
305+
/// use std::alloc::{Layout, set_alloc_error_hook};
306+
///
307+
/// fn custom_alloc_error_hook(layout: Layout) {
308+
/// panic!("memory allocation of {} bytes failed", layout.size());
309+
/// }
310+
///
311+
/// set_alloc_error_hook(custom_alloc_error_hook);
312+
/// ```
299313
#[unstable(feature = "alloc_error_hook", issue = "51245")]
300314
pub fn set_alloc_error_hook(hook: fn(Layout)) {
301315
HOOK.store(hook as *mut (), Ordering::SeqCst);

src/doc/book

Submodule book updated 240 files

src/doc/embedded-book

src/doc/reference

src/test/ui/argument-suggestions/basic.stderr

+5-5
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,9 @@ error[E0308]: arguments to this function are incorrect
4848
--> $DIR/basic.rs:23:5
4949
|
5050
LL | swapped("", 1);
51-
| ^^^^^^^ -- - expected `&str`,found `{integer}`
51+
| ^^^^^^^ -- - expected `&str`, found `{integer}`
5252
| |
53-
| expected `u32`,found `&'static str`
53+
| expected `u32`, found `&'static str`
5454
|
5555
note: function defined here
5656
--> $DIR/basic.rs:16:4
@@ -66,10 +66,10 @@ error[E0308]: arguments to this function are incorrect
6666
--> $DIR/basic.rs:24:5
6767
|
6868
LL | permuted(Y {}, Z {}, X {});
69-
| ^^^^^^^^ ---- ---- ---- expected `Z`,found `X`
69+
| ^^^^^^^^ ---- ---- ---- expected `Z`, found `X`
7070
| | |
71-
| | expected `Y`,found `Z`
72-
| expected `X`,found `Y`
71+
| | expected `Y`, found `Z`
72+
| expected `X`, found `Y`
7373
|
7474
note: function defined here
7575
--> $DIR/basic.rs:17:4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
struct A;
2+
struct B;
3+
struct C;
4+
struct D;
5+
struct E;
6+
struct F;
7+
struct G;
8+
9+
fn foo(a: &A, d: D, e: &E, g: G) {}
10+
11+
fn main() {
12+
foo(&&A, B, C, D, E, F, G);
13+
//~^ ERROR this function takes 4 arguments but 7 arguments were supplied
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
error[E0061]: this function takes 4 arguments but 7 arguments were supplied
2+
--> $DIR/issue-97484.rs:12:5
3+
|
4+
LL | foo(&&A, B, C, D, E, F, G);
5+
| ^^^ - - - argument unexpected
6+
| | |
7+
| | argument of type `&E` unexpected
8+
| argument of type `D` unexpected
9+
|
10+
note: function defined here
11+
--> $DIR/issue-97484.rs:9:4
12+
|
13+
LL | fn foo(a: &A, d: D, e: &E, g: G) {}
14+
| ^^^ ----- ---- ----- ----
15+
help: consider removing the ``
16+
|
17+
LL - foo(&&A, B, C, D, E, F, G);
18+
LL + foo(&&A, B, C, D, E, F, G);
19+
|
20+
help: remove the extra arguments
21+
|
22+
LL | foo(&&A, D, {&E}, G);
23+
| ~~~~~~~~~~~~~~~~~~~~
24+
25+
error: aborting due to previous error
26+
27+
For more information about this error, try `rustc --explain E0061`.

0 commit comments

Comments
 (0)