Skip to content

Commit fcf3006

Browse files
committed
Auto merge of #113199 - b-naber:slice-pattern-type-inference, r=lcnr
Infer type in irrefutable slice patterns with fixed length as array Fixes #76342 In irrefutable slice patterns with a fixed length, we can infer the type as an array type. We now choose to prefer some implementations over others, e.g. in: ``` struct Zeroes; const ARR: [usize; 2] = [0; 2]; const ARR2: [usize; 2] = [2; 2]; impl Into<&'static [usize; 2]> for Zeroes { fn into(self) -> &'static [usize; 2] { &ARR } } impl Into<&'static [usize]> for Zeroes { fn into(self) -> &'static [usize] { &ARR2 } } fn main() { let &[a, b] = Zeroes.into(); } ``` We now prefer the impl candidate `impl Into<&'static [usize; 2]> for Zeroes`, it's not entirely clear to me that this is correct, but given that the slice impl would require a type annotation anyway, this doesn't seem unreasonable. r? `@lcnr`
2 parents c115ec1 + 5a9af37 commit fcf3006

19 files changed

+489
-105
lines changed

compiler/rustc_hir_typeck/src/_match.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
4141
// #55810: Type check patterns first so we get types for all bindings.
4242
let scrut_span = scrut.span.find_ancestor_inside(expr.span).unwrap_or(scrut.span);
4343
for arm in arms {
44-
self.check_pat_top(&arm.pat, scrutinee_ty, Some(scrut_span), Some(scrut));
44+
self.check_pat_top(&arm.pat, scrutinee_ty, Some(scrut_span), Some(scrut), None);
4545
}
4646

4747
// Now typecheck the blocks.

compiler/rustc_hir_typeck/src/check.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ pub(super) fn check_fn<'a, 'tcx>(
8989
for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() {
9090
// Check the pattern.
9191
let ty_span = try { inputs_hir?.get(idx)?.span };
92-
fcx.check_pat_top(&param.pat, param_ty, ty_span, None);
92+
fcx.check_pat_top(&param.pat, param_ty, ty_span, None, None);
9393

9494
// Check that argument is Sized.
9595
if !params_can_be_unsized {

compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1463,11 +1463,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14631463
};
14641464

14651465
// Type check the pattern. Override if necessary to avoid knock-on errors.
1466-
self.check_pat_top(&decl.pat, decl_ty, ty_span, origin_expr);
1466+
self.check_pat_top(&decl.pat, decl_ty, ty_span, origin_expr, Some(decl.origin));
14671467
let pat_ty = self.node_ty(decl.pat.hir_id);
14681468
self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, pat_ty);
14691469

1470-
if let Some(blk) = decl.els {
1470+
if let Some(blk) = decl.origin.try_get_else() {
14711471
let previous_diverges = self.diverges.get();
14721472
let else_ty = self.check_block_with_expected(blk, NoExpectation);
14731473
let cause = self.cause(blk.span, ObligationCauseCode::LetElse);

compiler/rustc_hir_typeck/src/gather_locals.rs

+23-3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,26 @@ use rustc_span::def_id::LocalDefId;
99
use rustc_span::Span;
1010
use rustc_trait_selection::traits;
1111

12+
/// Provides context for checking patterns in declarations. More specifically this
13+
/// allows us to infer array types if the pattern is irrefutable and allows us to infer
14+
/// the size of the array. See issue #76342.
15+
#[derive(Debug, Copy, Clone)]
16+
pub(super) enum DeclOrigin<'a> {
17+
// from an `if let` expression
18+
LetExpr,
19+
// from `let x = ..`
20+
LocalDecl { els: Option<&'a hir::Block<'a>> },
21+
}
22+
23+
impl<'a> DeclOrigin<'a> {
24+
pub(super) fn try_get_else(&self) -> Option<&'a hir::Block<'a>> {
25+
match self {
26+
Self::LocalDecl { els } => *els,
27+
Self::LetExpr => None,
28+
}
29+
}
30+
}
31+
1232
/// A declaration is an abstraction of [hir::Local] and [hir::Let].
1333
///
1434
/// It must have a hir_id, as this is how we connect gather_locals to the check functions.
@@ -18,20 +38,20 @@ pub(super) struct Declaration<'a> {
1838
pub ty: Option<&'a hir::Ty<'a>>,
1939
pub span: Span,
2040
pub init: Option<&'a hir::Expr<'a>>,
21-
pub els: Option<&'a hir::Block<'a>>,
41+
pub origin: DeclOrigin<'a>,
2242
}
2343

2444
impl<'a> From<&'a hir::Local<'a>> for Declaration<'a> {
2545
fn from(local: &'a hir::Local<'a>) -> Self {
2646
let hir::Local { hir_id, pat, ty, span, init, els, source: _ } = *local;
27-
Declaration { hir_id, pat, ty, span, init, els }
47+
Declaration { hir_id, pat, ty, span, init, origin: DeclOrigin::LocalDecl { els } }
2848
}
2949
}
3050

3151
impl<'a> From<&'a hir::Let<'a>> for Declaration<'a> {
3252
fn from(let_expr: &'a hir::Let<'a>) -> Self {
3353
let hir::Let { hir_id, pat, ty, span, init } = *let_expr;
34-
Declaration { hir_id, pat, ty, span, init: Some(init), els: None }
54+
Declaration { hir_id, pat, ty, span, init: Some(init), origin: DeclOrigin::LetExpr }
3555
}
3656
}
3757

0 commit comments

Comments
 (0)