Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Infer type in irrefutable slice patterns with fixed length as array #113199

Merged
merged 11 commits into from
Aug 3, 2023
Prev Previous commit
Next Next commit
address review
b-naber committed Jul 17, 2023
commit 65f92a52bfee3f2d989695b80c36906404fffeca
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
Original file line number Diff line number Diff line change
@@ -1478,7 +1478,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let pat_ty = self.node_ty(decl.pat.hir_id);
self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, pat_ty);

if let Some(blk) = decl.origin.try_get_els() {
if let Some(blk) = decl.origin.try_get_else() {
let previous_diverges = self.diverges.get();
let else_ty = self.check_block_with_expected(blk, NoExpectation);
let cause = self.cause(blk.span, ObligationCauseCode::LetElse);
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/gather_locals.rs
Original file line number Diff line number Diff line change
@@ -21,7 +21,7 @@ pub(super) enum DeclOrigin<'a> {
}

impl<'a> DeclOrigin<'a> {
pub(super) fn try_get_els(&self) -> Option<&'a hir::Block<'a>> {
pub(super) fn try_get_else(&self) -> Option<&'a hir::Block<'a>> {
match self {
Self::LocalDecl { els } => *els,
Self::LetExpr => None,
117 changes: 31 additions & 86 deletions compiler/rustc_hir_typeck/src/pat.rs
Original file line number Diff line number Diff line change
@@ -163,7 +163,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Conversely, inside this module, `check_pat_top` should never be used.
#[instrument(level = "debug", skip(self, pat_info))]
fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'tcx, '_>) {
let PatInfo { binding_mode: def_bm, top_info: ti, decl_origin } = pat_info;
let PatInfo { binding_mode: def_bm, top_info: ti, .. } = pat_info;
let path_res = match &pat.kind {
PatKind::Path(qpath) => {
Some(self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span))
@@ -172,76 +172,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
let adjust_mode = self.calc_adjust_mode(pat, path_res.map(|(res, ..)| res));
let (expected, def_bm) = self.calc_default_binding_mode(pat, expected, def_bm, adjust_mode);
let pat_info =
PatInfo { binding_mode: def_bm, top_info: ti, decl_origin: pat_info.decl_origin };

let ty = match pat.kind {
PatKind::Wild => expected,
PatKind::Lit(lt) => self.check_pat_lit(pat.span, lt, expected, ti),
PatKind::Range(lhs, rhs, _) => self.check_pat_range(pat.span, lhs, rhs, expected, ti),
PatKind::Binding(ba, var_id, _, sub) => self.check_pat_ident(
pat,
ba,
var_id,
sub,
expected,
PatInfo { binding_mode: def_bm, top_info: ti, decl_origin },
),
PatKind::TupleStruct(ref qpath, subpats, ddpos) => self.check_pat_tuple_struct(
pat,
qpath,
subpats,
ddpos,
expected,
PatInfo { binding_mode: def_bm, top_info: ti, decl_origin },
),
PatKind::Binding(ba, var_id, _, sub) => {
self.check_pat_ident(pat, ba, var_id, sub, expected, pat_info)
}
PatKind::TupleStruct(ref qpath, subpats, ddpos) => {
self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, pat_info)
}
PatKind::Path(ref qpath) => {
self.check_pat_path(pat, qpath, path_res.unwrap(), expected, ti)
}
PatKind::Struct(ref qpath, fields, has_rest_pat) => self.check_pat_struct(
pat,
qpath,
fields,
has_rest_pat,
expected,
PatInfo { binding_mode: def_bm, top_info: ti, decl_origin },
),
PatKind::Struct(ref qpath, fields, has_rest_pat) => {
self.check_pat_struct(pat, qpath, fields, has_rest_pat, expected, pat_info)
}
PatKind::Or(pats) => {
for pat in pats {
self.check_pat(
pat,
expected,
PatInfo { binding_mode: def_bm, top_info: ti, decl_origin },
);
self.check_pat(pat, expected, pat_info);
}
expected
}
PatKind::Tuple(elements, ddpos) => self.check_pat_tuple(
pat.span,
elements,
ddpos,
expected,
PatInfo { binding_mode: def_bm, top_info: ti, decl_origin },
),
PatKind::Box(inner) => self.check_pat_box(
pat.span,
inner,
expected,
PatInfo { binding_mode: def_bm, top_info: ti, decl_origin },
),
PatKind::Ref(inner, mutbl) => self.check_pat_ref(
pat,
inner,
mutbl,
expected,
PatInfo { binding_mode: def_bm, top_info: ti, decl_origin },
),
PatKind::Slice(before, slice, after) => self.check_pat_slice(
pat.span,
before,
slice,
after,
expected,
PatInfo { binding_mode: def_bm, top_info: ti, decl_origin },
),
PatKind::Tuple(elements, ddpos) => {
self.check_pat_tuple(pat.span, elements, ddpos, expected, pat_info)
}
PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, pat_info),
PatKind::Ref(inner, mutbl) => self.check_pat_ref(pat, inner, mutbl, expected, pat_info),
PatKind::Slice(before, slice, after) => {
self.check_pat_slice(pat.span, before, slice, after, expected, pat_info)
}
};

self.write_ty(pat.hir_id, ty);
@@ -624,7 +587,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected: Ty<'tcx>,
pat_info: PatInfo<'tcx, '_>,
) -> Ty<'tcx> {
let PatInfo { binding_mode: def_bm, top_info: ti, decl_origin } = pat_info;
let PatInfo { binding_mode: def_bm, top_info: ti, .. } = pat_info;

// Determine the binding mode...
let bm = match ba {
@@ -663,11 +626,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}

if let Some(p) = sub {
self.check_pat(
p,
expected,
PatInfo { binding_mode: def_bm, top_info: ti, decl_origin },
);
self.check_pat(p, expected, pat_info);
}

local_ty
@@ -892,37 +851,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected: Ty<'tcx>,
pat_info: PatInfo<'tcx, '_>,
) -> Ty<'tcx> {
let PatInfo { binding_mode: def_bm, top_info: ti, decl_origin } = pat_info;

// Resolve the path and check the definition for errors.
let (variant, pat_ty) = match self.check_struct_path(qpath, pat.hir_id) {
Ok(data) => data,
Err(guar) => {
let err = Ty::new_error(self.tcx, guar);
for field in fields {
let ti = ti;
self.check_pat(
field.pat,
err,
PatInfo { binding_mode: def_bm, top_info: ti, decl_origin },
);
self.check_pat(field.pat, err, pat_info);
}
return err;
}
};

// Type-check the path.
self.demand_eqtype_pat(pat.span, expected, pat_ty, ti);
self.demand_eqtype_pat(pat.span, expected, pat_ty, pat_info.top_info);

// Type-check subpatterns.
if self.check_struct_pat_fields(
pat_ty,
&pat,
variant,
fields,
has_rest_pat,
PatInfo { binding_mode: def_bm, top_info: ti, decl_origin },
) {
if self.check_struct_pat_fields(pat_ty, &pat, variant, fields, has_rest_pat, pat_info) {
pat_ty
} else {
Ty::new_misc_error(self.tcx)
@@ -2144,11 +2089,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// If we're in an irrefutable pattern we prefer the array impl candidate given that
/// the slice impl candidate would be be rejected anyway (if no ambiguity existed).
fn pat_is_irrefutable(&self, decl_origin: Option<DeclOrigin<'_>>) -> bool {
if let Some(decl_origin) = decl_origin {
decl_origin.try_get_els().is_none()
&& matches!(decl_origin, DeclOrigin::LocalDecl { .. })
} else {
false
match decl_origin {
Some(DeclOrigin::LocalDecl { els: None }) => true,
Some(DeclOrigin::LocalDecl { els: Some(_) } | DeclOrigin::LetExpr) | None => false,
}
}

@@ -2183,6 +2126,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}

let expected = self.structurally_resolve_type(span, expected);
debug!(?expected);

let (element_ty, opt_slice_ty, inferred) = match *expected.kind() {
// An array, so we might have something like `let [a, b, c] = [0, 1, 2];`.
ty::Array(element_ty, len) => {
5 changes: 2 additions & 3 deletions tests/ui/array-slice-vec/slice-pat-type-mismatches.rs
Original file line number Diff line number Diff line change
@@ -30,9 +30,8 @@ fn main() {
}

fn another_fn_to_avoid_suppression() {
match Default
//~^ ERROR expected value, found trait
{
match Default::default() {
[] => {}
//~^ ERROR type annotations needed
};
}
16 changes: 8 additions & 8 deletions tests/ui/array-slice-vec/slice-pat-type-mismatches.stderr
Original file line number Diff line number Diff line change
@@ -4,12 +4,6 @@ error[E0425]: cannot find value `does_not_exist` in this scope
LL | match does_not_exist {
| ^^^^^^^^^^^^^^ not found in this scope

error[E0423]: expected value, found trait `Default`
--> $DIR/slice-pat-type-mismatches.rs:33:11
|
LL | match Default
| ^^^^^^^ not a value

error[E0529]: expected an array or slice, found `String`
--> $DIR/slice-pat-type-mismatches.rs:3:9
|
@@ -28,7 +22,13 @@ error[E0528]: pattern requires at least 4 elements but array has 3
LL | [0, 1, 2, 3, x @ ..] => {}
| ^^^^^^^^^^^^^^^^^^^^ pattern cannot match array of 3 elements

error[E0282]: type annotations needed
--> $DIR/slice-pat-type-mismatches.rs:34:9
|
LL | [] => {}
| ^^ cannot infer type

error: aborting due to 5 previous errors

Some errors have detailed explanations: E0423, E0425, E0527, E0528, E0529.
For more information about an error, try `rustc --explain E0423`.
Some errors have detailed explanations: E0282, E0425, E0527, E0528, E0529.
For more information about an error, try `rustc --explain E0282`.
3 changes: 3 additions & 0 deletions tests/ui/pattern/issue-76342.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
// check-pass

// Test that we infer the expected type of a pattern to an array of the given length.

#![allow(unused_variables)]
struct Zeroes;
impl Into<[usize; 2]> for Zeroes {
2 changes: 2 additions & 0 deletions tests/ui/pattern/slice-pattern-refutable.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// Test that we do not infer the expected types of patterns to an array
// if we're in a refutable pattern.
#![allow(unused_variables)]

struct Zeroes;
6 changes: 3 additions & 3 deletions tests/ui/pattern/slice-pattern-refutable.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0282]: type annotations needed
--> $DIR/slice-pattern-refutable.rs:12:9
--> $DIR/slice-pattern-refutable.rs:14:9
|
LL | let [a, b, c] = Zeroes.into() else {
| ^^^^^^^^^
@@ -10,7 +10,7 @@ LL | let [a, b, c]: /* Type */ = Zeroes.into() else {
| ++++++++++++

error[E0282]: type annotations needed
--> $DIR/slice-pattern-refutable.rs:19:31
--> $DIR/slice-pattern-refutable.rs:21:31
|
LL | if let [a, b, c] = Zeroes.into() {
| --------- ^^^^
@@ -23,7 +23,7 @@ LL | if let [a, b, c] = <Zeroes as Into<T>>::into(Zeroes) {
| ++++++++++++++++++++++++++ ~

error[E0282]: type annotations needed
--> $DIR/slice-pattern-refutable.rs:26:31
--> $DIR/slice-pattern-refutable.rs:28:31
|
LL | if let [a, b, c] = Zeroes.into() {
| --------- ^^^^