mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 23:04:33 +00:00
Auto merge of #113199 - b-naber:slice-pattern-type-inference, r=lcnr
Infer type in irrefutable slice patterns with fixed length as array Fixes https://github.com/rust-lang/rust/issues/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`
This commit is contained in:
commit
fcf3006e01
@ -41,7 +41,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
// #55810: Type check patterns first so we get types for all bindings.
|
// #55810: Type check patterns first so we get types for all bindings.
|
||||||
let scrut_span = scrut.span.find_ancestor_inside(expr.span).unwrap_or(scrut.span);
|
let scrut_span = scrut.span.find_ancestor_inside(expr.span).unwrap_or(scrut.span);
|
||||||
for arm in arms {
|
for arm in arms {
|
||||||
self.check_pat_top(&arm.pat, scrutinee_ty, Some(scrut_span), Some(scrut));
|
self.check_pat_top(&arm.pat, scrutinee_ty, Some(scrut_span), Some(scrut), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now typecheck the blocks.
|
// Now typecheck the blocks.
|
||||||
|
@ -89,7 +89,7 @@ pub(super) fn check_fn<'a, 'tcx>(
|
|||||||
for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() {
|
for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() {
|
||||||
// Check the pattern.
|
// Check the pattern.
|
||||||
let ty_span = try { inputs_hir?.get(idx)?.span };
|
let ty_span = try { inputs_hir?.get(idx)?.span };
|
||||||
fcx.check_pat_top(¶m.pat, param_ty, ty_span, None);
|
fcx.check_pat_top(¶m.pat, param_ty, ty_span, None, None);
|
||||||
|
|
||||||
// Check that argument is Sized.
|
// Check that argument is Sized.
|
||||||
if !params_can_be_unsized {
|
if !params_can_be_unsized {
|
||||||
|
@ -1463,11 +1463,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Type check the pattern. Override if necessary to avoid knock-on errors.
|
// Type check the pattern. Override if necessary to avoid knock-on errors.
|
||||||
self.check_pat_top(&decl.pat, decl_ty, ty_span, origin_expr);
|
self.check_pat_top(&decl.pat, decl_ty, ty_span, origin_expr, Some(decl.origin));
|
||||||
let pat_ty = self.node_ty(decl.pat.hir_id);
|
let pat_ty = self.node_ty(decl.pat.hir_id);
|
||||||
self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, pat_ty);
|
self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, pat_ty);
|
||||||
|
|
||||||
if let Some(blk) = decl.els {
|
if let Some(blk) = decl.origin.try_get_else() {
|
||||||
let previous_diverges = self.diverges.get();
|
let previous_diverges = self.diverges.get();
|
||||||
let else_ty = self.check_block_with_expected(blk, NoExpectation);
|
let else_ty = self.check_block_with_expected(blk, NoExpectation);
|
||||||
let cause = self.cause(blk.span, ObligationCauseCode::LetElse);
|
let cause = self.cause(blk.span, ObligationCauseCode::LetElse);
|
||||||
|
@ -9,6 +9,26 @@ use rustc_span::def_id::LocalDefId;
|
|||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_trait_selection::traits;
|
use rustc_trait_selection::traits;
|
||||||
|
|
||||||
|
/// Provides context for checking patterns in declarations. More specifically this
|
||||||
|
/// allows us to infer array types if the pattern is irrefutable and allows us to infer
|
||||||
|
/// the size of the array. See issue #76342.
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub(super) enum DeclOrigin<'a> {
|
||||||
|
// from an `if let` expression
|
||||||
|
LetExpr,
|
||||||
|
// from `let x = ..`
|
||||||
|
LocalDecl { els: Option<&'a hir::Block<'a>> },
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> DeclOrigin<'a> {
|
||||||
|
pub(super) fn try_get_else(&self) -> Option<&'a hir::Block<'a>> {
|
||||||
|
match self {
|
||||||
|
Self::LocalDecl { els } => *els,
|
||||||
|
Self::LetExpr => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A declaration is an abstraction of [hir::Local] and [hir::Let].
|
/// A declaration is an abstraction of [hir::Local] and [hir::Let].
|
||||||
///
|
///
|
||||||
/// It must have a hir_id, as this is how we connect gather_locals to the check functions.
|
/// 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> {
|
|||||||
pub ty: Option<&'a hir::Ty<'a>>,
|
pub ty: Option<&'a hir::Ty<'a>>,
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub init: Option<&'a hir::Expr<'a>>,
|
pub init: Option<&'a hir::Expr<'a>>,
|
||||||
pub els: Option<&'a hir::Block<'a>>,
|
pub origin: DeclOrigin<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a hir::Local<'a>> for Declaration<'a> {
|
impl<'a> From<&'a hir::Local<'a>> for Declaration<'a> {
|
||||||
fn from(local: &'a hir::Local<'a>) -> Self {
|
fn from(local: &'a hir::Local<'a>) -> Self {
|
||||||
let hir::Local { hir_id, pat, ty, span, init, els, source: _ } = *local;
|
let hir::Local { hir_id, pat, ty, span, init, els, source: _ } = *local;
|
||||||
Declaration { hir_id, pat, ty, span, init, els }
|
Declaration { hir_id, pat, ty, span, init, origin: DeclOrigin::LocalDecl { els } }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a hir::Let<'a>> for Declaration<'a> {
|
impl<'a> From<&'a hir::Let<'a>> for Declaration<'a> {
|
||||||
fn from(let_expr: &'a hir::Let<'a>) -> Self {
|
fn from(let_expr: &'a hir::Let<'a>) -> Self {
|
||||||
let hir::Let { hir_id, pat, ty, span, init } = *let_expr;
|
let hir::Let { hir_id, pat, ty, span, init } = *let_expr;
|
||||||
Declaration { hir_id, pat, ty, span, init: Some(init), els: None }
|
Declaration { hir_id, pat, ty, span, init: Some(init), origin: DeclOrigin::LetExpr }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use crate::gather_locals::DeclOrigin;
|
||||||
use crate::{errors, FnCtxt, RawTy};
|
use crate::{errors, FnCtxt, RawTy};
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
@ -77,6 +78,13 @@ struct TopInfo<'tcx> {
|
|||||||
span: Option<Span>,
|
span: Option<Span>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
struct PatInfo<'tcx, 'a> {
|
||||||
|
binding_mode: BindingMode,
|
||||||
|
top_info: TopInfo<'tcx>,
|
||||||
|
decl_origin: Option<DeclOrigin<'a>>,
|
||||||
|
}
|
||||||
|
|
||||||
impl<'tcx> FnCtxt<'_, 'tcx> {
|
impl<'tcx> FnCtxt<'_, 'tcx> {
|
||||||
fn pattern_cause(&self, ti: TopInfo<'tcx>, cause_span: Span) -> ObligationCause<'tcx> {
|
fn pattern_cause(&self, ti: TopInfo<'tcx>, cause_span: Span) -> ObligationCause<'tcx> {
|
||||||
let code =
|
let code =
|
||||||
@ -135,15 +143,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
///
|
///
|
||||||
/// Otherwise, `Some(span)` represents the span of a type expression
|
/// Otherwise, `Some(span)` represents the span of a type expression
|
||||||
/// which originated the `expected` type.
|
/// which originated the `expected` type.
|
||||||
pub fn check_pat_top(
|
pub(crate) fn check_pat_top(
|
||||||
&self,
|
&self,
|
||||||
pat: &'tcx Pat<'tcx>,
|
pat: &'tcx Pat<'tcx>,
|
||||||
expected: Ty<'tcx>,
|
expected: Ty<'tcx>,
|
||||||
span: Option<Span>,
|
span: Option<Span>,
|
||||||
origin_expr: Option<&'tcx hir::Expr<'tcx>>,
|
origin_expr: Option<&'tcx hir::Expr<'tcx>>,
|
||||||
|
decl_origin: Option<DeclOrigin<'tcx>>,
|
||||||
) {
|
) {
|
||||||
let info = TopInfo { expected, origin_expr, span };
|
let info = TopInfo { expected, origin_expr, span };
|
||||||
self.check_pat(pat, expected, INITIAL_BM, info);
|
let pat_info = PatInfo { binding_mode: INITIAL_BM, top_info: info, decl_origin };
|
||||||
|
self.check_pat(pat, expected, pat_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Type check the given `pat` against the `expected` type
|
/// Type check the given `pat` against the `expected` type
|
||||||
@ -151,14 +161,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
///
|
///
|
||||||
/// Outside of this module, `check_pat_top` should always be used.
|
/// Outside of this module, `check_pat_top` should always be used.
|
||||||
/// Conversely, inside this module, `check_pat_top` should never be used.
|
/// Conversely, inside this module, `check_pat_top` should never be used.
|
||||||
#[instrument(level = "debug", skip(self, ti))]
|
#[instrument(level = "debug", skip(self, pat_info))]
|
||||||
fn check_pat(
|
fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'tcx, '_>) {
|
||||||
&self,
|
let PatInfo { binding_mode: def_bm, top_info: ti, .. } = pat_info;
|
||||||
pat: &'tcx Pat<'tcx>,
|
|
||||||
expected: Ty<'tcx>,
|
|
||||||
def_bm: BindingMode,
|
|
||||||
ti: TopInfo<'tcx>,
|
|
||||||
) {
|
|
||||||
let path_res = match &pat.kind {
|
let path_res = match &pat.kind {
|
||||||
PatKind::Path(qpath) => {
|
PatKind::Path(qpath) => {
|
||||||
Some(self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span))
|
Some(self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span))
|
||||||
@ -167,38 +172,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
};
|
};
|
||||||
let adjust_mode = self.calc_adjust_mode(pat, path_res.map(|(res, ..)| res));
|
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 (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 {
|
let ty = match pat.kind {
|
||||||
PatKind::Wild => expected,
|
PatKind::Wild => expected,
|
||||||
PatKind::Lit(lt) => self.check_pat_lit(pat.span, lt, expected, ti),
|
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::Range(lhs, rhs, _) => self.check_pat_range(pat.span, lhs, rhs, expected, ti),
|
||||||
PatKind::Binding(ba, var_id, _, sub) => {
|
PatKind::Binding(ba, var_id, _, sub) => {
|
||||||
self.check_pat_ident(pat, ba, var_id, sub, expected, def_bm, ti)
|
self.check_pat_ident(pat, ba, var_id, sub, expected, pat_info)
|
||||||
}
|
}
|
||||||
PatKind::TupleStruct(ref qpath, subpats, ddpos) => {
|
PatKind::TupleStruct(ref qpath, subpats, ddpos) => {
|
||||||
self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, def_bm, ti)
|
self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, pat_info)
|
||||||
}
|
}
|
||||||
PatKind::Path(ref qpath) => {
|
PatKind::Path(ref qpath) => {
|
||||||
self.check_pat_path(pat, qpath, path_res.unwrap(), expected, ti)
|
self.check_pat_path(pat, qpath, path_res.unwrap(), expected, ti)
|
||||||
}
|
}
|
||||||
PatKind::Struct(ref qpath, fields, has_rest_pat) => {
|
PatKind::Struct(ref qpath, fields, has_rest_pat) => {
|
||||||
self.check_pat_struct(pat, qpath, fields, has_rest_pat, expected, def_bm, ti)
|
self.check_pat_struct(pat, qpath, fields, has_rest_pat, expected, pat_info)
|
||||||
}
|
}
|
||||||
PatKind::Or(pats) => {
|
PatKind::Or(pats) => {
|
||||||
for pat in pats {
|
for pat in pats {
|
||||||
self.check_pat(pat, expected, def_bm, ti);
|
self.check_pat(pat, expected, pat_info);
|
||||||
}
|
}
|
||||||
expected
|
expected
|
||||||
}
|
}
|
||||||
PatKind::Tuple(elements, ddpos) => {
|
PatKind::Tuple(elements, ddpos) => {
|
||||||
self.check_pat_tuple(pat.span, elements, ddpos, expected, def_bm, ti)
|
self.check_pat_tuple(pat.span, elements, ddpos, expected, pat_info)
|
||||||
}
|
|
||||||
PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, def_bm, ti),
|
|
||||||
PatKind::Ref(inner, mutbl) => {
|
|
||||||
self.check_pat_ref(pat, inner, mutbl, expected, def_bm, ti)
|
|
||||||
}
|
}
|
||||||
|
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) => {
|
PatKind::Slice(before, slice, after) => {
|
||||||
self.check_pat_slice(pat.span, before, slice, after, expected, def_bm, ti)
|
self.check_pat_slice(pat.span, before, slice, after, expected, pat_info)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -580,9 +585,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
var_id: HirId,
|
var_id: HirId,
|
||||||
sub: Option<&'tcx Pat<'tcx>>,
|
sub: Option<&'tcx Pat<'tcx>>,
|
||||||
expected: Ty<'tcx>,
|
expected: Ty<'tcx>,
|
||||||
def_bm: BindingMode,
|
pat_info: PatInfo<'tcx, '_>,
|
||||||
ti: TopInfo<'tcx>,
|
|
||||||
) -> Ty<'tcx> {
|
) -> Ty<'tcx> {
|
||||||
|
let PatInfo { binding_mode: def_bm, top_info: ti, .. } = pat_info;
|
||||||
|
|
||||||
// Determine the binding mode...
|
// Determine the binding mode...
|
||||||
let bm = match ba {
|
let bm = match ba {
|
||||||
hir::BindingAnnotation::NONE => def_bm,
|
hir::BindingAnnotation::NONE => def_bm,
|
||||||
@ -620,7 +626,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(p) = sub {
|
if let Some(p) = sub {
|
||||||
self.check_pat(p, expected, def_bm, ti);
|
self.check_pat(p, expected, pat_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
local_ty
|
local_ty
|
||||||
@ -843,8 +849,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
fields: &'tcx [hir::PatField<'tcx>],
|
fields: &'tcx [hir::PatField<'tcx>],
|
||||||
has_rest_pat: bool,
|
has_rest_pat: bool,
|
||||||
expected: Ty<'tcx>,
|
expected: Ty<'tcx>,
|
||||||
def_bm: BindingMode,
|
pat_info: PatInfo<'tcx, '_>,
|
||||||
ti: TopInfo<'tcx>,
|
|
||||||
) -> Ty<'tcx> {
|
) -> Ty<'tcx> {
|
||||||
// Resolve the path and check the definition for errors.
|
// Resolve the path and check the definition for errors.
|
||||||
let (variant, pat_ty) = match self.check_struct_path(qpath, pat.hir_id) {
|
let (variant, pat_ty) = match self.check_struct_path(qpath, pat.hir_id) {
|
||||||
@ -852,18 +857,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
Err(guar) => {
|
Err(guar) => {
|
||||||
let err = Ty::new_error(self.tcx, guar);
|
let err = Ty::new_error(self.tcx, guar);
|
||||||
for field in fields {
|
for field in fields {
|
||||||
let ti = ti;
|
self.check_pat(field.pat, err, pat_info);
|
||||||
self.check_pat(field.pat, err, def_bm, ti);
|
|
||||||
}
|
}
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Type-check the path.
|
// 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.
|
// Type-check subpatterns.
|
||||||
if self.check_struct_pat_fields(pat_ty, &pat, variant, fields, has_rest_pat, def_bm, ti) {
|
if self.check_struct_pat_fields(pat_ty, &pat, variant, fields, has_rest_pat, pat_info) {
|
||||||
pat_ty
|
pat_ty
|
||||||
} else {
|
} else {
|
||||||
Ty::new_misc_error(self.tcx)
|
Ty::new_misc_error(self.tcx)
|
||||||
@ -1029,13 +1033,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
subpats: &'tcx [Pat<'tcx>],
|
subpats: &'tcx [Pat<'tcx>],
|
||||||
ddpos: hir::DotDotPos,
|
ddpos: hir::DotDotPos,
|
||||||
expected: Ty<'tcx>,
|
expected: Ty<'tcx>,
|
||||||
def_bm: BindingMode,
|
pat_info: PatInfo<'tcx, '_>,
|
||||||
ti: TopInfo<'tcx>,
|
|
||||||
) -> Ty<'tcx> {
|
) -> Ty<'tcx> {
|
||||||
|
let PatInfo { binding_mode: def_bm, top_info: ti, decl_origin } = pat_info;
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
let on_error = |e| {
|
let on_error = |e| {
|
||||||
for pat in subpats {
|
for pat in subpats {
|
||||||
self.check_pat(pat, Ty::new_error(tcx, e), def_bm, ti);
|
self.check_pat(
|
||||||
|
pat,
|
||||||
|
Ty::new_error(tcx, e),
|
||||||
|
PatInfo { binding_mode: def_bm, top_info: ti, decl_origin },
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let report_unexpected_res = |res: Res| {
|
let report_unexpected_res = |res: Res| {
|
||||||
@ -1101,7 +1109,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) {
|
for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) {
|
||||||
let field = &variant.fields[FieldIdx::from_usize(i)];
|
let field = &variant.fields[FieldIdx::from_usize(i)];
|
||||||
let field_ty = self.field_ty(subpat.span, field, args);
|
let field_ty = self.field_ty(subpat.span, field, args);
|
||||||
self.check_pat(subpat, field_ty, def_bm, ti);
|
self.check_pat(
|
||||||
|
subpat,
|
||||||
|
field_ty,
|
||||||
|
PatInfo { binding_mode: def_bm, top_info: ti, decl_origin },
|
||||||
|
);
|
||||||
|
|
||||||
self.tcx.check_stability(
|
self.tcx.check_stability(
|
||||||
variant.fields[FieldIdx::from_usize(i)].did,
|
variant.fields[FieldIdx::from_usize(i)].did,
|
||||||
@ -1285,8 +1297,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
elements: &'tcx [Pat<'tcx>],
|
elements: &'tcx [Pat<'tcx>],
|
||||||
ddpos: hir::DotDotPos,
|
ddpos: hir::DotDotPos,
|
||||||
expected: Ty<'tcx>,
|
expected: Ty<'tcx>,
|
||||||
def_bm: BindingMode,
|
pat_info: PatInfo<'tcx, '_>,
|
||||||
ti: TopInfo<'tcx>,
|
|
||||||
) -> Ty<'tcx> {
|
) -> Ty<'tcx> {
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
let mut expected_len = elements.len();
|
let mut expected_len = elements.len();
|
||||||
@ -1307,18 +1318,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
});
|
});
|
||||||
let element_tys = tcx.mk_type_list_from_iter(element_tys_iter);
|
let element_tys = tcx.mk_type_list_from_iter(element_tys_iter);
|
||||||
let pat_ty = Ty::new_tup(tcx, element_tys);
|
let pat_ty = Ty::new_tup(tcx, element_tys);
|
||||||
if let Some(mut err) = self.demand_eqtype_pat_diag(span, expected, pat_ty, ti) {
|
if let Some(mut err) =
|
||||||
|
self.demand_eqtype_pat_diag(span, expected, pat_ty, pat_info.top_info)
|
||||||
|
{
|
||||||
let reported = err.emit();
|
let reported = err.emit();
|
||||||
// Walk subpatterns with an expected type of `err` in this case to silence
|
// Walk subpatterns with an expected type of `err` in this case to silence
|
||||||
// further errors being emitted when using the bindings. #50333
|
// further errors being emitted when using the bindings. #50333
|
||||||
let element_tys_iter = (0..max_len).map(|_| Ty::new_error(tcx, reported));
|
let element_tys_iter = (0..max_len).map(|_| Ty::new_error(tcx, reported));
|
||||||
for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
|
for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
|
||||||
self.check_pat(elem, Ty::new_error(tcx, reported), def_bm, ti);
|
self.check_pat(elem, Ty::new_error(tcx, reported), pat_info);
|
||||||
}
|
}
|
||||||
Ty::new_tup_from_iter(tcx, element_tys_iter)
|
Ty::new_tup_from_iter(tcx, element_tys_iter)
|
||||||
} else {
|
} else {
|
||||||
for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
|
for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
|
||||||
self.check_pat(elem, element_tys[i], def_bm, ti);
|
self.check_pat(elem, element_tys[i], pat_info);
|
||||||
}
|
}
|
||||||
pat_ty
|
pat_ty
|
||||||
}
|
}
|
||||||
@ -1331,8 +1344,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
variant: &'tcx ty::VariantDef,
|
variant: &'tcx ty::VariantDef,
|
||||||
fields: &'tcx [hir::PatField<'tcx>],
|
fields: &'tcx [hir::PatField<'tcx>],
|
||||||
has_rest_pat: bool,
|
has_rest_pat: bool,
|
||||||
def_bm: BindingMode,
|
pat_info: PatInfo<'tcx, '_>,
|
||||||
ti: TopInfo<'tcx>,
|
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
|
|
||||||
@ -1379,7 +1391,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.check_pat(field.pat, field_ty, def_bm, ti);
|
self.check_pat(field.pat, field_ty, pat_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut unmentioned_fields = variant
|
let mut unmentioned_fields = variant
|
||||||
@ -1937,8 +1949,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
span: Span,
|
span: Span,
|
||||||
inner: &'tcx Pat<'tcx>,
|
inner: &'tcx Pat<'tcx>,
|
||||||
expected: Ty<'tcx>,
|
expected: Ty<'tcx>,
|
||||||
def_bm: BindingMode,
|
pat_info: PatInfo<'tcx, '_>,
|
||||||
ti: TopInfo<'tcx>,
|
|
||||||
) -> Ty<'tcx> {
|
) -> Ty<'tcx> {
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
let (box_ty, inner_ty) = match self.check_dereferenceable(span, expected, inner) {
|
let (box_ty, inner_ty) = match self.check_dereferenceable(span, expected, inner) {
|
||||||
@ -1950,7 +1961,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
span: inner.span,
|
span: inner.span,
|
||||||
});
|
});
|
||||||
let box_ty = Ty::new_box(tcx, inner_ty);
|
let box_ty = Ty::new_box(tcx, inner_ty);
|
||||||
self.demand_eqtype_pat(span, expected, box_ty, ti);
|
self.demand_eqtype_pat(span, expected, box_ty, pat_info.top_info);
|
||||||
(box_ty, inner_ty)
|
(box_ty, inner_ty)
|
||||||
}
|
}
|
||||||
Err(guar) => {
|
Err(guar) => {
|
||||||
@ -1958,7 +1969,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
(err, err)
|
(err, err)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
self.check_pat(inner, inner_ty, def_bm, ti);
|
self.check_pat(inner, inner_ty, pat_info);
|
||||||
box_ty
|
box_ty
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1969,8 +1980,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
inner: &'tcx Pat<'tcx>,
|
inner: &'tcx Pat<'tcx>,
|
||||||
mutbl: hir::Mutability,
|
mutbl: hir::Mutability,
|
||||||
expected: Ty<'tcx>,
|
expected: Ty<'tcx>,
|
||||||
def_bm: BindingMode,
|
pat_info: PatInfo<'tcx, '_>,
|
||||||
ti: TopInfo<'tcx>,
|
|
||||||
) -> Ty<'tcx> {
|
) -> Ty<'tcx> {
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
let expected = self.shallow_resolve(expected);
|
let expected = self.shallow_resolve(expected);
|
||||||
@ -1992,7 +2002,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
});
|
});
|
||||||
let ref_ty = self.new_ref_ty(pat.span, mutbl, inner_ty);
|
let ref_ty = self.new_ref_ty(pat.span, mutbl, inner_ty);
|
||||||
debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty);
|
debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty);
|
||||||
let err = self.demand_eqtype_pat_diag(pat.span, expected, ref_ty, ti);
|
let err = self.demand_eqtype_pat_diag(
|
||||||
|
pat.span,
|
||||||
|
expected,
|
||||||
|
ref_ty,
|
||||||
|
pat_info.top_info,
|
||||||
|
);
|
||||||
|
|
||||||
// Look for a case like `fn foo(&foo: u32)` and suggest
|
// Look for a case like `fn foo(&foo: u32)` and suggest
|
||||||
// `fn foo(foo: &u32)`
|
// `fn foo(foo: &u32)`
|
||||||
@ -2009,7 +2024,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
(err, err)
|
(err, err)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
self.check_pat(inner, inner_ty, def_bm, ti);
|
self.check_pat(inner, inner_ty, pat_info);
|
||||||
ref_ty
|
ref_ty
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2020,6 +2035,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
Ty::new_ref(self.tcx, region, mt)
|
Ty::new_ref(self.tcx, region, mt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn try_resolve_slice_ty_to_array_ty(
|
||||||
|
&self,
|
||||||
|
before: &'tcx [Pat<'tcx>],
|
||||||
|
slice: Option<&'tcx Pat<'tcx>>,
|
||||||
|
span: Span,
|
||||||
|
) -> Option<Ty<'tcx>> {
|
||||||
|
if !slice.is_none() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let tcx = self.tcx;
|
||||||
|
let len = before.len();
|
||||||
|
let ty_var_origin =
|
||||||
|
TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span };
|
||||||
|
let inner_ty = self.next_ty_var(ty_var_origin);
|
||||||
|
|
||||||
|
Some(Ty::new_array(tcx, inner_ty, len.try_into().unwrap()))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Used to determines whether we can infer the expected type in the slice pattern to be of type array.
|
||||||
|
/// This is only possible if we're in an irrefutable pattern. If we were to allow this in refutable
|
||||||
|
/// patterns we wouldn't e.g. report ambiguity in the following situation:
|
||||||
|
///
|
||||||
|
/// ```ignore(rust)
|
||||||
|
/// 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]: &[usize] = Zeroes.into() else {
|
||||||
|
/// ..
|
||||||
|
/// };
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// 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 {
|
||||||
|
match decl_origin {
|
||||||
|
Some(DeclOrigin::LocalDecl { els: None }) => true,
|
||||||
|
Some(DeclOrigin::LocalDecl { els: Some(_) } | DeclOrigin::LetExpr) | None => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Type check a slice pattern.
|
/// Type check a slice pattern.
|
||||||
///
|
///
|
||||||
/// Syntactically, these look like `[pat_0, ..., pat_n]`.
|
/// Syntactically, these look like `[pat_0, ..., pat_n]`.
|
||||||
@ -2037,10 +2108,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
slice: Option<&'tcx Pat<'tcx>>,
|
slice: Option<&'tcx Pat<'tcx>>,
|
||||||
after: &'tcx [Pat<'tcx>],
|
after: &'tcx [Pat<'tcx>],
|
||||||
expected: Ty<'tcx>,
|
expected: Ty<'tcx>,
|
||||||
def_bm: BindingMode,
|
pat_info: PatInfo<'tcx, '_>,
|
||||||
ti: TopInfo<'tcx>,
|
|
||||||
) -> Ty<'tcx> {
|
) -> Ty<'tcx> {
|
||||||
|
let expected = self.try_structurally_resolve_type(span, expected);
|
||||||
|
|
||||||
|
// If the pattern is irrefutable and `expected` is an infer ty, we try to equate it
|
||||||
|
// to an array if the given pattern allows it. See issue #76342
|
||||||
|
if self.pat_is_irrefutable(pat_info.decl_origin) && expected.is_ty_var() {
|
||||||
|
if let Some(resolved_arr_ty) =
|
||||||
|
self.try_resolve_slice_ty_to_array_ty(before, slice, span)
|
||||||
|
{
|
||||||
|
debug!(?resolved_arr_ty);
|
||||||
|
self.demand_eqtype(span, expected, resolved_arr_ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let expected = self.structurally_resolve_type(span, expected);
|
let expected = self.structurally_resolve_type(span, expected);
|
||||||
|
debug!(?expected);
|
||||||
|
|
||||||
let (element_ty, opt_slice_ty, inferred) = match *expected.kind() {
|
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];`.
|
// An array, so we might have something like `let [a, b, c] = [0, 1, 2];`.
|
||||||
ty::Array(element_ty, len) => {
|
ty::Array(element_ty, len) => {
|
||||||
@ -2055,10 +2140,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
ty::Slice(element_ty) => (element_ty, Some(expected), expected),
|
ty::Slice(element_ty) => (element_ty, Some(expected), expected),
|
||||||
// The expected type must be an array or slice, but was neither, so error.
|
// The expected type must be an array or slice, but was neither, so error.
|
||||||
_ => {
|
_ => {
|
||||||
let guar = expected
|
let guar = expected.error_reported().err().unwrap_or_else(|| {
|
||||||
.error_reported()
|
self.error_expected_array_or_slice(span, expected, pat_info.top_info)
|
||||||
.err()
|
});
|
||||||
.unwrap_or_else(|| self.error_expected_array_or_slice(span, expected, ti));
|
|
||||||
let err = Ty::new_error(self.tcx, guar);
|
let err = Ty::new_error(self.tcx, guar);
|
||||||
(err, Some(err), err)
|
(err, Some(err), err)
|
||||||
}
|
}
|
||||||
@ -2066,15 +2150,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
|
|
||||||
// Type check all the patterns before `slice`.
|
// Type check all the patterns before `slice`.
|
||||||
for elt in before {
|
for elt in before {
|
||||||
self.check_pat(elt, element_ty, def_bm, ti);
|
self.check_pat(elt, element_ty, pat_info);
|
||||||
}
|
}
|
||||||
// Type check the `slice`, if present, against its expected type.
|
// Type check the `slice`, if present, against its expected type.
|
||||||
if let Some(slice) = slice {
|
if let Some(slice) = slice {
|
||||||
self.check_pat(slice, opt_slice_ty.unwrap(), def_bm, ti);
|
self.check_pat(slice, opt_slice_ty.unwrap(), pat_info);
|
||||||
}
|
}
|
||||||
// Type check the elements after `slice`, if present.
|
// Type check the elements after `slice`, if present.
|
||||||
for elt in after {
|
for elt in after {
|
||||||
self.check_pat(elt, element_ty, def_bm, ti);
|
self.check_pat(elt, element_ty, pat_info);
|
||||||
}
|
}
|
||||||
inferred
|
inferred
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// see issue #70529
|
// check-pass
|
||||||
struct A;
|
struct A;
|
||||||
|
|
||||||
impl From<A> for [u8; 2] {
|
impl From<A> for [u8; 2] {
|
||||||
@ -13,9 +13,7 @@ impl From<A> for [u8; 3] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let a = A;
|
let a = A;
|
||||||
let [_, _] = a.into();
|
let [_, _] = a.into();
|
||||||
//~^ ERROR type annotations needed
|
|
||||||
}
|
}
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
error[E0282]: type annotations needed
|
|
||||||
--> $DIR/infer_array_len.rs:19:9
|
|
||||||
|
|
|
||||||
LL | let [_, _] = a.into();
|
|
||||||
| ^^^^^^
|
|
||||||
|
|
|
||||||
help: consider giving this pattern a type
|
|
||||||
|
|
|
||||||
LL | let [_, _]: /* Type */ = a.into();
|
|
||||||
| ++++++++++++
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0282`.
|
|
@ -2,7 +2,7 @@ fn main() {
|
|||||||
match "foo".to_string() {
|
match "foo".to_string() {
|
||||||
['f', 'o', ..] => {}
|
['f', 'o', ..] => {}
|
||||||
//~^ ERROR expected an array or slice, found `String`
|
//~^ ERROR expected an array or slice, found `String`
|
||||||
_ => { }
|
_ => {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Note that this one works with default binding modes.
|
// Note that this one works with default binding modes.
|
||||||
@ -15,7 +15,7 @@ fn main() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
match [0, 1, 2] {
|
match [0, 1, 2] {
|
||||||
[0] => {}, //~ ERROR pattern requires
|
[0] => {} //~ ERROR pattern requires
|
||||||
|
|
||||||
[0, 1, x @ ..] => {
|
[0, 1, x @ ..] => {
|
||||||
let a: [_; 1] = x;
|
let a: [_; 1] = x;
|
||||||
@ -23,14 +23,15 @@ fn main() {
|
|||||||
[0, 1, 2, 3, x @ ..] => {} //~ ERROR pattern requires
|
[0, 1, 2, 3, x @ ..] => {} //~ ERROR pattern requires
|
||||||
};
|
};
|
||||||
|
|
||||||
match does_not_exist { //~ ERROR cannot find value `does_not_exist` in this scope
|
match does_not_exist {
|
||||||
[] => {}
|
//~^ ERROR cannot find value `does_not_exist` in this scope
|
||||||
|
[] => {} // ERROR cannot find value `does_not_exist` in this scope
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn another_fn_to_avoid_suppression() {
|
fn another_fn_to_avoid_suppression() {
|
||||||
match Default::default()
|
match Default::default() {
|
||||||
{
|
[] => {}
|
||||||
[] => {} //~ ERROR type annotations needed
|
//~^ ERROR type annotations needed
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ LL | ['f', 'o', ..] => {}
|
|||||||
error[E0527]: pattern requires 1 element but array has 3
|
error[E0527]: pattern requires 1 element but array has 3
|
||||||
--> $DIR/slice-pat-type-mismatches.rs:18:9
|
--> $DIR/slice-pat-type-mismatches.rs:18:9
|
||||||
|
|
|
|
||||||
LL | [0] => {},
|
LL | [0] => {}
|
||||||
| ^^^ expected 3 elements
|
| ^^^ expected 3 elements
|
||||||
|
|
||||||
error[E0528]: pattern requires at least 4 elements but array has 3
|
error[E0528]: pattern requires at least 4 elements but array has 3
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
fn main() {
|
fn main() {
|
||||||
let (mut a, mut b);
|
let (mut a, mut b);
|
||||||
[a, .., b, ..] = [0, 1]; //~ ERROR `..` can only be used once per slice pattern
|
[a, .., b, ..] = [0, 1]; //~ ERROR `..` can only be used once per slice pattern
|
||||||
[a, a, b] = [1, 2]; //~ ERROR pattern requires 3 elements but array has 2
|
[a, a, b] = [1, 2];
|
||||||
[_] = [1, 2]; //~ ERROR pattern requires 1 element but array has 2
|
//~^ ERROR pattern requires 3 elements but array has 2
|
||||||
|
[_] = [1, 2];
|
||||||
|
//~^ ERROR pattern requires 1 element but array has 2
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
error: `..` can only be used once per slice pattern
|
error: `..` can only be used once per slice pattern
|
||||||
--> $DIR/slice_destructure_fail.rs:3:14
|
--> $DIR/slice_destructure_fail.rs:3:16
|
||||||
|
|
|
|
||||||
LL | [a, .., b, ..] = [0, 1];
|
LL | [a, .., b, ..] = [0, 1];
|
||||||
| -- ^^ can only be used once per slice pattern
|
| -- ^^ can only be used once per slice pattern
|
||||||
| |
|
| |
|
||||||
| previously used here
|
| previously used here
|
||||||
|
|
||||||
error[E0527]: pattern requires 3 elements but array has 2
|
error[E0527]: pattern requires 3 elements but array has 2
|
||||||
--> $DIR/slice_destructure_fail.rs:4:3
|
--> $DIR/slice_destructure_fail.rs:4:5
|
||||||
|
|
|
|
||||||
LL | [a, a, b] = [1, 2];
|
LL | [a, a, b] = [1, 2];
|
||||||
| ^^^^^^^^^ expected 2 elements
|
| ^^^^^^^^^ expected 2 elements
|
||||||
|
|
||||||
error[E0527]: pattern requires 1 element but array has 2
|
error[E0527]: pattern requires 1 element but array has 2
|
||||||
--> $DIR/slice_destructure_fail.rs:5:3
|
--> $DIR/slice_destructure_fail.rs:6:5
|
||||||
|
|
|
|
||||||
LL | [_] = [1, 2];
|
LL | [_] = [1, 2];
|
||||||
| ^^^ expected 2 elements
|
| ^^^ expected 2 elements
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
27
tests/ui/pattern/slice-array-infer.rs
Normal file
27
tests/ui/pattern/slice-array-infer.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// check-pass
|
||||||
|
|
||||||
|
#![allow(unused_variables)]
|
||||||
|
#![feature(generic_arg_infer)]
|
||||||
|
|
||||||
|
struct Zeroes;
|
||||||
|
impl Into<&'static [usize; 3]> for Zeroes {
|
||||||
|
fn into(self) -> &'static [usize; 3] {
|
||||||
|
&[0; 3]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Into<[usize; 3]> for Zeroes {
|
||||||
|
fn into(self) -> [usize; 3] {
|
||||||
|
[0; 3]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn main() {
|
||||||
|
let [a, b, c] = Zeroes.into();
|
||||||
|
let [d, e, f] = <Zeroes as Into<&'static [usize; 3]>>::into(Zeroes);
|
||||||
|
let &[g, h, i] = Zeroes.into();
|
||||||
|
let [j, k, l]: [usize; _] = Zeroes.into();
|
||||||
|
let [m, n, o]: &[usize; _] = Zeroes.into();
|
||||||
|
|
||||||
|
// check the binding mode of these patterns:
|
||||||
|
let _: &[usize] = &[a, b, c, g, h, i, j, k, l];
|
||||||
|
let _: &[&usize] = &[d, e, f, m, n, o];
|
||||||
|
}
|
36
tests/ui/pattern/slice-pattern-refutable.rs
Normal file
36
tests/ui/pattern/slice-pattern-refutable.rs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// 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;
|
||||||
|
|
||||||
|
impl Into<[usize; 3]> for Zeroes {
|
||||||
|
fn into(self) -> [usize; 3] {
|
||||||
|
[0; 3]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn let_else() {
|
||||||
|
let [a, b, c] = Zeroes.into() else {
|
||||||
|
//~^ ERROR type annotations needed
|
||||||
|
unreachable!();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn if_let() {
|
||||||
|
if let [a, b, c] = Zeroes.into() {
|
||||||
|
//~^ ERROR type annotations needed
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn if_let_else() {
|
||||||
|
if let [a, b, c] = Zeroes.into() {
|
||||||
|
//~^ ERROR type annotations needed
|
||||||
|
unreachable!();
|
||||||
|
} else {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
40
tests/ui/pattern/slice-pattern-refutable.stderr
Normal file
40
tests/ui/pattern/slice-pattern-refutable.stderr
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
error[E0282]: type annotations needed
|
||||||
|
--> $DIR/slice-pattern-refutable.rs:14:9
|
||||||
|
|
|
||||||
|
LL | let [a, b, c] = Zeroes.into() else {
|
||||||
|
| ^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: consider giving this pattern a type
|
||||||
|
|
|
||||||
|
LL | let [a, b, c]: /* Type */ = Zeroes.into() else {
|
||||||
|
| ++++++++++++
|
||||||
|
|
||||||
|
error[E0282]: type annotations needed
|
||||||
|
--> $DIR/slice-pattern-refutable.rs:21:31
|
||||||
|
|
|
||||||
|
LL | if let [a, b, c] = Zeroes.into() {
|
||||||
|
| --------- ^^^^
|
||||||
|
| |
|
||||||
|
| type must be known at this point
|
||||||
|
|
|
||||||
|
help: try using a fully qualified path to specify the expected types
|
||||||
|
|
|
||||||
|
LL | if let [a, b, c] = <Zeroes as Into<T>>::into(Zeroes) {
|
||||||
|
| ++++++++++++++++++++++++++ ~
|
||||||
|
|
||||||
|
error[E0282]: type annotations needed
|
||||||
|
--> $DIR/slice-pattern-refutable.rs:28:31
|
||||||
|
|
|
||||||
|
LL | if let [a, b, c] = Zeroes.into() {
|
||||||
|
| --------- ^^^^
|
||||||
|
| |
|
||||||
|
| type must be known at this point
|
||||||
|
|
|
||||||
|
help: try using a fully qualified path to specify the expected types
|
||||||
|
|
|
||||||
|
LL | if let [a, b, c] = <Zeroes as Into<T>>::into(Zeroes) {
|
||||||
|
| ++++++++++++++++++++++++++ ~
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0282`.
|
47
tests/ui/pattern/slice-patterns-ambiguity.rs
Normal file
47
tests/ui/pattern/slice-patterns-ambiguity.rs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#![allow(unused_variables)]
|
||||||
|
|
||||||
|
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 let_decl() {
|
||||||
|
let &[a, b] = Zeroes.into();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn let_else() {
|
||||||
|
let &[a, b] = Zeroes.into() else {
|
||||||
|
//~^ ERROR type annotations needed
|
||||||
|
unreachable!();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn if_let() {
|
||||||
|
if let &[a, b] = Zeroes.into() {
|
||||||
|
//~^ ERROR type annotations needed
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn if_let_else() {
|
||||||
|
if let &[a, b] = Zeroes.into() {
|
||||||
|
//~^ ERROR type annotations needed
|
||||||
|
unreachable!();
|
||||||
|
} else {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
40
tests/ui/pattern/slice-patterns-ambiguity.stderr
Normal file
40
tests/ui/pattern/slice-patterns-ambiguity.stderr
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
error[E0282]: type annotations needed for `&_`
|
||||||
|
--> $DIR/slice-patterns-ambiguity.rs:25:9
|
||||||
|
|
|
||||||
|
LL | let &[a, b] = Zeroes.into() else {
|
||||||
|
| ^^^^^^^
|
||||||
|
|
|
||||||
|
help: consider giving this pattern a type, where the placeholders `_` are specified
|
||||||
|
|
|
||||||
|
LL | let &[a, b]: &_ = Zeroes.into() else {
|
||||||
|
| ++++
|
||||||
|
|
||||||
|
error[E0282]: type annotations needed
|
||||||
|
--> $DIR/slice-patterns-ambiguity.rs:32:29
|
||||||
|
|
|
||||||
|
LL | if let &[a, b] = Zeroes.into() {
|
||||||
|
| ------ ^^^^
|
||||||
|
| |
|
||||||
|
| type must be known at this point
|
||||||
|
|
|
||||||
|
help: try using a fully qualified path to specify the expected types
|
||||||
|
|
|
||||||
|
LL | if let &[a, b] = <Zeroes as Into<&_>>::into(Zeroes) {
|
||||||
|
| +++++++++++++++++++++++++++ ~
|
||||||
|
|
||||||
|
error[E0282]: type annotations needed
|
||||||
|
--> $DIR/slice-patterns-ambiguity.rs:39:29
|
||||||
|
|
|
||||||
|
LL | if let &[a, b] = Zeroes.into() {
|
||||||
|
| ------ ^^^^
|
||||||
|
| |
|
||||||
|
| type must be known at this point
|
||||||
|
|
|
||||||
|
help: try using a fully qualified path to specify the expected types
|
||||||
|
|
|
||||||
|
LL | if let &[a, b] = <Zeroes as Into<&_>>::into(Zeroes) {
|
||||||
|
| +++++++++++++++++++++++++++ ~
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0282`.
|
74
tests/ui/pattern/slice-patterns-irrefutable.rs
Normal file
74
tests/ui/pattern/slice-patterns-irrefutable.rs
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
// Test that we infer the expected type of a pattern to an array of the given length.
|
||||||
|
|
||||||
|
#![allow(unused_variables)]
|
||||||
|
|
||||||
|
use std::array::TryFromSliceError;
|
||||||
|
use std::convert::TryInto;
|
||||||
|
|
||||||
|
struct Zeroes;
|
||||||
|
impl Into<[usize; 2]> for Zeroes {
|
||||||
|
fn into(self) -> [usize; 2] {
|
||||||
|
[0; 2]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Into<[usize; 3]> for Zeroes {
|
||||||
|
fn into(self) -> [usize; 3] {
|
||||||
|
[0; 3]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Into<[usize; 4]> for Zeroes {
|
||||||
|
fn into(self) -> [usize; 4] {
|
||||||
|
[0; 4]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn zeroes_into() {
|
||||||
|
let [a, b, c] = Zeroes.into();
|
||||||
|
let [d, e, f]: [_; 3] = Zeroes.into();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn array_try_from(x: &[usize]) -> Result<usize, TryFromSliceError> {
|
||||||
|
let [a, b] = x.try_into()?;
|
||||||
|
Ok(a + b)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn destructuring_assignment() {
|
||||||
|
let a: i32;
|
||||||
|
let b;
|
||||||
|
[a, b] = Default::default();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_nested_array() {
|
||||||
|
let a: [_; 3];
|
||||||
|
let b;
|
||||||
|
//~^ ERROR type annotations needed
|
||||||
|
[a, b] = Default::default();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_nested_array_type_hint() {
|
||||||
|
let a: [_; 3];
|
||||||
|
let b;
|
||||||
|
[a, b] = Default::default();
|
||||||
|
let _: i32 = b[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_working_nested_array() {
|
||||||
|
let a: i32;
|
||||||
|
[[a, _, _], _, _] = Default::default();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Foo<T>([T; 2]);
|
||||||
|
|
||||||
|
impl<T: Default + Copy> Default for Foo<T> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Foo([Default::default(); 2])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn field_array() {
|
||||||
|
let a: i32;
|
||||||
|
let b;
|
||||||
|
Foo([a, b]) = Default::default();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
14
tests/ui/pattern/slice-patterns-irrefutable.stderr
Normal file
14
tests/ui/pattern/slice-patterns-irrefutable.stderr
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
error[E0282]: type annotations needed for `[_; 3]`
|
||||||
|
--> $DIR/slice-patterns-irrefutable.rs:43:9
|
||||||
|
|
|
||||||
|
LL | let b;
|
||||||
|
| ^
|
||||||
|
|
|
||||||
|
help: consider giving `b` an explicit type, where the placeholders `_` are specified
|
||||||
|
|
|
||||||
|
LL | let b: [_; 3];
|
||||||
|
| ++++++++
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0282`.
|
15
tests/ui/pattern/slice-patterns-nested.rs
Normal file
15
tests/ui/pattern/slice-patterns-nested.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// check-pass
|
||||||
|
#![allow(unused_variables)]
|
||||||
|
|
||||||
|
struct Zeroes;
|
||||||
|
struct Foo<T>(T);
|
||||||
|
|
||||||
|
impl Into<[usize; 3]> for Zeroes {
|
||||||
|
fn into(self) -> [usize; 3] {
|
||||||
|
[0; 3]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let Foo([a, b, c]) = Foo(Zeroes.into());
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user