diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs index a8753628afad..86e5afdb5092 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs @@ -334,7 +334,11 @@ impl InferenceContext<'_> { ExprIsRead::No }; let input_ty = self.infer_expr(expr, &Expectation::none(), child_is_read); - self.infer_top_pat(pat, &input_ty, None); + self.infer_top_pat( + pat, + &input_ty, + Some(DeclContext { origin: DeclOrigin::LetExpr }), + ); self.result.standard_types.bool_.clone() } Expr::Block { statements, tail, label, id } => { @@ -1633,8 +1637,7 @@ impl InferenceContext<'_> { }; let decl = DeclContext { - has_else: else_branch.is_some(), - origin: DeclOrigin::LocalDecl, + origin: DeclOrigin::LocalDecl { has_else: else_branch.is_some() }, }; this.infer_top_pat(*pat, &ty, Some(decl)); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs index 98693de4bb61..5ff22bea34de 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs @@ -498,7 +498,7 @@ impl InferenceContext<'_> { // If `expected` is an infer ty, we try to equate it to an array if the given pattern // allows it. See issue #16609 - if self.decl_allows_array_type_infer(decl) && expected.is_ty_var() { + if self.pat_is_irrefutable(decl) && expected.is_ty_var() { if let Some(resolved_array_ty) = self.try_resolve_slice_ty_to_array_ty(prefix, suffix, slice) { @@ -601,42 +601,38 @@ impl InferenceContext<'_> { Some(array_ty) } - /// Determines whether we can infer the expected type in the slice pattern to be of type array. + /// Used to determine 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]; + /// 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] { + /// 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 - /// } - /// } + /// impl Into<&'static [usize]> for Zeroes { + /// fn into(self) -> &'static [usize] { + /// &ARR2 + /// } + /// } /// - /// fn main() { - /// let &[a, b]: &[usize] = Zeroes.into() else { - /// .. - /// }; - /// } + /// 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 decl_allows_array_type_infer(&self, decl_ctxt: Option) -> bool { - if let Some(decl_ctxt) = decl_ctxt { - !decl_ctxt.has_else && matches!(decl_ctxt.origin, DeclOrigin::LocalDecl) - } else { - false - } + /// the slice impl candidate would be rejected anyway (if no ambiguity existed). + fn pat_is_irrefutable(&self, decl_ctxt: Option) -> bool { + matches!(decl_ctxt, Some(DeclContext { origin: DeclOrigin::LocalDecl { has_else: false } })) } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index acac7ddcad3c..55d81875a2be 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -1052,18 +1052,17 @@ pub fn known_const_to_ast( #[derive(Debug, Copy, Clone)] pub(crate) enum DeclOrigin { - // from an `if let` expression LetExpr, - // from `let x = ..` - LocalDecl, + /// from `let x = ..` + LocalDecl { + has_else: bool, + }, } /// 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. +/// the size of the array. See issue rust-lang/rust#76342. #[derive(Debug, Copy, Clone)] pub(crate) struct DeclContext { - // whether we're in a let-else context - pub(crate) has_else: bool, pub(crate) origin: DeclOrigin, } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs index 50bc47cf673a..4949d4016bf1 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs @@ -67,9 +67,9 @@ fn infer_pattern() { 143..144 'e': {unknown} 157..204 'if let... }': () 160..175 'let [val] = opt': bool - 164..169 '[val]': [{unknown}; 1] + 164..169 '[val]': [{unknown}] 165..168 'val': {unknown} - 172..175 'opt': [{unknown}; 1] + 172..175 'opt': [{unknown}] 176..204 '{ ... }': () 190..191 'h': {unknown} 194..197 'val': {unknown}