Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/infer/pat.rs')
| -rw-r--r-- | crates/hir-ty/src/infer/pat.rs | 387 |
1 files changed, 204 insertions, 183 deletions
diff --git a/crates/hir-ty/src/infer/pat.rs b/crates/hir-ty/src/infer/pat.rs index 6e11fa942b..a02e280ac6 100644 --- a/crates/hir-ty/src/infer/pat.rs +++ b/crates/hir-ty/src/infer/pat.rs @@ -1,6 +1,6 @@ //! Type inference for patterns. -use std::iter::repeat_with; +use std::{cmp, iter}; use hir_def::{ HasModule, @@ -8,37 +8,34 @@ use hir_def::{ hir::{Binding, BindingAnnotation, BindingId, Expr, ExprId, Literal, Pat, PatId}, }; use hir_expand::name::Name; +use rustc_ast_ir::Mutability; +use rustc_type_ir::inherent::{GenericArg as _, GenericArgs as _, IntoKind, SliceLike, Ty as _}; use stdx::TupleExt; -use crate::infer::AllowTwoPhase; -use crate::next_solver::mapping::{ChalkToNextSolver, NextSolverToChalk}; use crate::{ - DeclContext, DeclOrigin, InferenceDiagnostic, Interner, Mutability, Scalar, Substitution, Ty, - TyBuilder, TyExt, TyKind, + DeclContext, DeclOrigin, InferenceDiagnostic, consteval::{self, try_const_usize, usize_const}, infer::{ - BindingMode, Expectation, InferenceContext, TypeMismatch, coerce::CoerceNever, - expr::ExprIsRead, + AllowTwoPhase, BindingMode, Expectation, InferenceContext, TypeMismatch, expr::ExprIsRead, }, - lower::lower_to_chalk_mutability, - primitive::UintTy, - static_lifetime, + lower::lower_mutability, + next_solver::{GenericArgs, Ty, TyKind, Tys, infer::traits::ObligationCause}, }; -impl InferenceContext<'_> { +impl<'db> InferenceContext<'_, 'db> { /// Infers type for tuple struct pattern or its corresponding assignee expression. /// /// Ellipses found in the original pattern or expression must be filtered out. pub(super) fn infer_tuple_struct_pat_like( &mut self, path: Option<&Path>, - expected: &Ty, + expected: Ty<'db>, default_bm: BindingMode, id: PatId, ellipsis: Option<u32>, subs: &[PatId], decl: Option<DeclContext>, - ) -> Ty { + ) -> Ty<'db> { let (ty, def) = self.resolve_variant(id.into(), path, true); let var_data = def.map(|it| it.fields(self.db)); if let Some(variant) = def { @@ -56,7 +53,7 @@ impl InferenceContext<'_> { } } - self.unify(&ty, expected); + self.unify(ty, expected); match def { _ if subs.is_empty() => {} @@ -85,10 +82,10 @@ impl InferenceContext<'_> { { // FIXME(DIAGNOSE): private tuple field } - let f = field_types[local_id].clone(); + let f = field_types[local_id]; let expected_ty = match substs { - Some(substs) => f.substitute(Interner, substs), - None => f.substitute(Interner, &Substitution::empty(Interner)), + Some(substs) => f.instantiate(self.interner(), substs), + None => f.instantiate(self.interner(), &[]), }; self.process_remote_user_written_ty(expected_ty) } @@ -96,13 +93,13 @@ impl InferenceContext<'_> { } }; - self.infer_pat(subpat, &expected_ty, default_bm, decl); + self.infer_pat(subpat, expected_ty, default_bm, decl); } } None => { let err_ty = self.err_ty(); for &inner in subs { - self.infer_pat(inner, &err_ty, default_bm, decl); + self.infer_pat(inner, err_ty, default_bm, decl); } } } @@ -114,18 +111,18 @@ impl InferenceContext<'_> { pub(super) fn infer_record_pat_like( &mut self, path: Option<&Path>, - expected: &Ty, + expected: Ty<'db>, default_bm: BindingMode, id: PatId, subs: impl ExactSizeIterator<Item = (Name, PatId)>, decl: Option<DeclContext>, - ) -> Ty { + ) -> Ty<'db> { let (ty, def) = self.resolve_variant(id.into(), path, false); if let Some(variant) = def { self.write_variant_resolution(id.into(), variant); } - self.unify(&ty, expected); + self.unify(ty, expected); match def { _ if subs.len() == 0 => {} @@ -149,10 +146,10 @@ impl InferenceContext<'_> { variant: def, }); } - let f = field_types[local_id].clone(); + let f = field_types[local_id]; let expected_ty = match substs { - Some(substs) => f.substitute(Interner, substs), - None => f.substitute(Interner, &Substitution::empty(Interner)), + Some(substs) => f.instantiate(self.interner(), substs), + None => f.instantiate(self.interner(), &[]), }; self.process_remote_user_written_ty(expected_ty) } @@ -167,13 +164,13 @@ impl InferenceContext<'_> { } }; - self.infer_pat(inner, &expected_ty, default_bm, decl); + self.infer_pat(inner, expected_ty, default_bm, decl); } } None => { let err_ty = self.err_ty(); for (_, inner) in subs { - self.infer_pat(inner, &err_ty, default_bm, decl); + self.infer_pat(inner, err_ty, default_bm, decl); } } } @@ -186,60 +183,81 @@ impl InferenceContext<'_> { /// Ellipses found in the original pattern or expression must be filtered out. pub(super) fn infer_tuple_pat_like( &mut self, - expected: &Ty, + pat: PatId, + expected: Ty<'db>, default_bm: BindingMode, ellipsis: Option<u32>, - subs: &[PatId], + elements: &[PatId], decl: Option<DeclContext>, - ) -> Ty { - let expected = self.table.structurally_resolve_type(expected); - let expectations = match expected.as_tuple() { - Some(parameters) => parameters.as_slice(Interner), - _ => &[], - }; + ) -> Ty<'db> { + let mut expected_len = elements.len(); + if ellipsis.is_some() { + // Require known type only when `..` is present. + if let TyKind::Tuple(tys) = self.table.structurally_resolve_type(expected).kind() { + expected_len = tys.len(); + } + } + let max_len = cmp::max(expected_len, elements.len()); - let ((pre, post), n_uncovered_patterns) = match ellipsis { - Some(idx) => { - (subs.split_at(idx as usize), expectations.len().saturating_sub(subs.len())) + let element_tys_iter = (0..max_len).map(|_| self.table.next_ty_var()); + let element_tys = Tys::new_from_iter(self.interner(), element_tys_iter); + let pat_ty = Ty::new(self.interner(), TyKind::Tuple(element_tys)); + if self.demand_eqtype(pat.into(), expected, pat_ty).is_err() + && let TyKind::Tuple(expected) = expected.kind() + { + // Equate expected type with the infer vars, for better diagnostics. + for (expected, elem_ty) in iter::zip(expected, element_tys) { + _ = self + .table + .at(&ObligationCause::dummy()) + .eq(expected, elem_ty) + .map(|infer_ok| self.table.register_infer_ok(infer_ok)); + } + } + let (before_ellipsis, after_ellipsis) = match ellipsis { + Some(ellipsis) => { + let element_tys = element_tys.as_slice(); + // Don't check patterns twice. + let from_end_start = cmp::max( + element_tys.len().saturating_sub(elements.len() - ellipsis as usize), + ellipsis as usize, + ); + ( + element_tys.get(..ellipsis as usize).unwrap_or(element_tys), + element_tys.get(from_end_start..).unwrap_or_default(), + ) } - None => ((subs, &[][..]), 0), + None => (element_tys.as_slice(), &[][..]), }; - let mut expectations_iter = expectations - .iter() - .map(|a| a.assert_ty_ref(Interner).clone()) - .chain(repeat_with(|| self.table.new_type_var())); - - let mut inner_tys = Vec::with_capacity(n_uncovered_patterns + subs.len()); - - inner_tys.extend(expectations_iter.by_ref().take(n_uncovered_patterns + subs.len())); - - // Process pre - for (ty, pat) in inner_tys.iter_mut().zip(pre) { - *ty = self.infer_pat(*pat, ty, default_bm, decl); + for (&elem, &elem_ty) in iter::zip(elements, before_ellipsis.iter().chain(after_ellipsis)) { + self.infer_pat(elem, elem_ty, default_bm, decl); } - - // Process post - for (ty, pat) in inner_tys.iter_mut().skip(pre.len() + n_uncovered_patterns).zip(post) { - *ty = self.infer_pat(*pat, ty, default_bm, decl); + if let Some(uncovered) = elements.get(element_tys.len()..) { + for &elem in uncovered { + self.infer_pat(elem, self.types.error, default_bm, decl); + } } - - TyKind::Tuple(inner_tys.len(), Substitution::from_iter(Interner, inner_tys)) - .intern(Interner) + pat_ty } /// The resolver needs to be updated to the surrounding expression when inside assignment /// (because there, `Pat::Path` can refer to a variable). - pub(super) fn infer_top_pat(&mut self, pat: PatId, expected: &Ty, decl: Option<DeclContext>) { + pub(super) fn infer_top_pat( + &mut self, + pat: PatId, + expected: Ty<'db>, + decl: Option<DeclContext>, + ) { self.infer_pat(pat, expected, BindingMode::default(), decl); } fn infer_pat( &mut self, pat: PatId, - expected: &Ty, + expected: Ty<'db>, mut default_bm: BindingMode, decl: Option<DeclContext>, - ) -> Ty { + ) -> Ty<'db> { let mut expected = self.table.structurally_resolve_type(expected); if matches!(&self.body[pat], Pat::Ref { .. }) || self.inside_assignment { @@ -251,9 +269,9 @@ impl InferenceContext<'_> { default_bm = BindingMode::Move; } else if self.is_non_ref_pat(self.body, pat) { let mut pat_adjustments = Vec::new(); - while let Some((inner, _lifetime, mutability)) = expected.as_reference() { - pat_adjustments.push(expected.clone()); - expected = self.table.structurally_resolve_type(inner); + while let TyKind::Ref(_lifetime, inner, mutability) = expected.kind() { + pat_adjustments.push(expected); + expected = self.table.try_structurally_resolve_type(inner); default_bm = match default_bm { BindingMode::Move => BindingMode::Ref(mutability), BindingMode::Ref(Mutability::Not) => BindingMode::Ref(Mutability::Not), @@ -273,25 +291,21 @@ impl InferenceContext<'_> { let ty = match &self.body[pat] { Pat::Tuple { args, ellipsis } => { - self.infer_tuple_pat_like(&expected, default_bm, *ellipsis, args, decl) + self.infer_tuple_pat_like(pat, expected, default_bm, *ellipsis, args, decl) } Pat::Or(pats) => { for pat in pats.iter() { - self.infer_pat(*pat, &expected, default_bm, decl); + self.infer_pat(*pat, expected, default_bm, decl); } - expected.clone() + expected + } + &Pat::Ref { pat, mutability } => { + self.infer_ref_pat(pat, lower_mutability(mutability), expected, default_bm, decl) } - &Pat::Ref { pat, mutability } => self.infer_ref_pat( - pat, - lower_to_chalk_mutability(mutability), - &expected, - default_bm, - decl, - ), Pat::TupleStruct { path: p, args: subpats, ellipsis } => self .infer_tuple_struct_pat_like( p.as_deref(), - &expected, + expected, default_bm, pat, *ellipsis, @@ -300,29 +314,26 @@ impl InferenceContext<'_> { ), Pat::Record { path: p, args: fields, ellipsis: _ } => { let subs = fields.iter().map(|f| (f.name.clone(), f.pat)); - self.infer_record_pat_like(p.as_deref(), &expected, default_bm, pat, subs, decl) + self.infer_record_pat_like(p.as_deref(), expected, default_bm, pat, subs, decl) } Pat::Path(path) => { let ty = self.infer_path(path, pat.into()).unwrap_or_else(|| self.err_ty()); - let ty_inserted_vars = self.insert_type_vars_shallow(ty.clone()); + let ty_inserted_vars = self.insert_type_vars_shallow(ty); match self.coerce( pat.into(), - expected.to_nextsolver(self.table.interner), - ty_inserted_vars.to_nextsolver(self.table.interner), + expected, + ty_inserted_vars, AllowTwoPhase::No, - CoerceNever::Yes, + ExprIsRead::No, ) { Ok(coerced_ty) => { - self.write_pat_ty(pat, coerced_ty.to_chalk(self.table.interner)); + self.write_pat_ty(pat, coerced_ty); return self.pat_ty_after_adjustment(pat); } Err(_) => { - self.result.type_mismatches.insert( + self.result.type_mismatches.get_or_insert_default().insert( pat.into(), - TypeMismatch { - expected: expected.clone(), - actual: ty_inserted_vars.clone(), - }, + TypeMismatch { expected, actual: ty_inserted_vars }, ); self.write_pat_ty(pat, ty); // We return `expected` to prevent cascading errors. I guess an alternative is to @@ -332,81 +343,86 @@ impl InferenceContext<'_> { } } Pat::Bind { id, subpat } => { - return self.infer_bind_pat(pat, *id, default_bm, *subpat, &expected, decl); + return self.infer_bind_pat(pat, *id, default_bm, *subpat, expected, decl); } Pat::Slice { prefix, slice, suffix } => { - self.infer_slice_pat(&expected, prefix, slice, suffix, default_bm, decl) + self.infer_slice_pat(expected, prefix, *slice, suffix, default_bm, decl) } - Pat::Wild => expected.clone(), - Pat::Range { .. } => { - // FIXME: do some checks here. - expected.clone() + Pat::Wild => expected, + Pat::Range { start, end, range_type: _ } => { + if let Some(start) = *start { + let start_ty = self.infer_expr(start, &Expectation::None, ExprIsRead::Yes); + _ = self.demand_eqtype(start.into(), expected, start_ty); + } + if let Some(end) = *end { + let end_ty = self.infer_expr(end, &Expectation::None, ExprIsRead::Yes); + _ = self.demand_eqtype(end.into(), expected, end_ty); + } + expected } &Pat::Lit(expr) => { // Don't emit type mismatches again, the expression lowering already did that. - let ty = self.infer_lit_pat(expr, &expected); + let ty = self.infer_lit_pat(expr, expected); self.write_pat_ty(pat, ty); return self.pat_ty_after_adjustment(pat); } Pat::Box { inner } => match self.resolve_boxed_box() { Some(box_adt) => { let (inner_ty, alloc_ty) = match expected.as_adt() { - Some((adt, subst)) if adt == box_adt => ( - subst.at(Interner, 0).assert_ty_ref(Interner).clone(), - subst.as_slice(Interner).get(1).and_then(|a| a.ty(Interner).cloned()), - ), - _ => (self.result.standard_types.unknown.clone(), None), + Some((adt, subst)) if adt == box_adt => { + (subst.type_at(0), subst.as_slice().get(1).and_then(|a| a.as_type())) + } + _ => (self.types.error, None), }; - let inner_ty = self.infer_pat(*inner, &inner_ty, default_bm, decl); - let mut b = TyBuilder::adt(self.db, box_adt).push(inner_ty); - - if let Some(alloc_ty) = alloc_ty { - b = b.push(alloc_ty); - } - b.fill_with_defaults(self.db, || self.table.new_type_var()).build() + let inner_ty = self.infer_pat(*inner, inner_ty, default_bm, decl); + Ty::new_adt( + self.interner(), + box_adt, + GenericArgs::fill_with_defaults( + self.interner(), + box_adt.into(), + iter::once(inner_ty.into()).chain(alloc_ty.map(Into::into)), + |_, id, _| self.table.next_var_for_param(id), + ), + ) } None => self.err_ty(), }, Pat::ConstBlock(expr) => { let old_inside_assign = std::mem::replace(&mut self.inside_assignment, false); - let result = self.infer_expr( - *expr, - &Expectation::has_type(expected.clone()), - ExprIsRead::Yes, - ); + let result = + self.infer_expr(*expr, &Expectation::has_type(expected), ExprIsRead::Yes); self.inside_assignment = old_inside_assign; result } Pat::Expr(expr) => { let old_inside_assign = std::mem::replace(&mut self.inside_assignment, false); // LHS of assignment doesn't constitute reads. - let result = self.infer_expr_coerce( - *expr, - &Expectation::has_type(expected.clone()), - ExprIsRead::No, - ); + let expr_is_read = ExprIsRead::No; + let result = + self.infer_expr_coerce(*expr, &Expectation::has_type(expected), expr_is_read); // We are returning early to avoid the unifiability check below. let lhs_ty = self.insert_type_vars_shallow(result); let ty = match self.coerce( - pat.into(), - expected.to_nextsolver(self.table.interner), - lhs_ty.to_nextsolver(self.table.interner), + (*expr).into(), + expected, + lhs_ty, AllowTwoPhase::No, - CoerceNever::Yes, + expr_is_read, ) { - Ok(ty) => ty.to_chalk(self.table.interner), + Ok(ty) => ty, Err(_) => { - self.result.type_mismatches.insert( - pat.into(), - TypeMismatch { expected: expected.clone(), actual: lhs_ty.clone() }, - ); + self.result + .type_mismatches + .get_or_insert_default() + .insert(pat.into(), TypeMismatch { expected, actual: lhs_ty }); // `rhs_ty` is returned so no further type mismatches are // reported because of this mismatch. expected } }; - self.write_pat_ty(pat, ty.clone()); + self.write_pat_ty(pat, ty); self.inside_assignment = old_inside_assign; return ty; } @@ -415,46 +431,46 @@ impl InferenceContext<'_> { // use a new type variable if we got error type here let ty = self.insert_type_vars_shallow(ty); // FIXME: This never check is odd, but required with out we do inference right now - if !expected.is_never() && !self.unify(&ty, &expected) { + if !expected.is_never() && !self.unify(ty, expected) { self.result .type_mismatches - .insert(pat.into(), TypeMismatch { expected, actual: ty.clone() }); + .get_or_insert_default() + .insert(pat.into(), TypeMismatch { expected, actual: ty }); } self.write_pat_ty(pat, ty); self.pat_ty_after_adjustment(pat) } - fn pat_ty_after_adjustment(&self, pat: PatId) -> Ty { - self.result + fn pat_ty_after_adjustment(&self, pat: PatId) -> Ty<'db> { + *self + .result .pat_adjustments .get(&pat) - .and_then(|it| it.first()) + .and_then(|it| it.last()) .unwrap_or(&self.result.type_of_pat[pat]) - .clone() } fn infer_ref_pat( &mut self, inner_pat: PatId, mutability: Mutability, - expected: &Ty, + expected: Ty<'db>, default_bm: BindingMode, decl: Option<DeclContext>, - ) -> Ty { - let (expectation_type, expectation_lt) = match expected.as_reference() { - Some((inner_ty, lifetime, _exp_mut)) => (inner_ty.clone(), lifetime), - None => { - let inner_ty = self.table.new_type_var(); - let inner_lt = self.table.new_lifetime_var(); - let ref_ty = - TyKind::Ref(mutability, inner_lt.clone(), inner_ty.clone()).intern(Interner); + ) -> Ty<'db> { + let (expectation_type, expectation_lt) = match expected.kind() { + TyKind::Ref(lifetime, inner_ty, _exp_mut) => (inner_ty, lifetime), + _ => { + let inner_ty = self.table.next_ty_var(); + let inner_lt = self.table.next_region_var(); + let ref_ty = Ty::new_ref(self.interner(), inner_lt, inner_ty, mutability); // Unification failure will be reported by the caller. - self.unify(&ref_ty, expected); + self.unify(ref_ty, expected); (inner_ty, inner_lt) } }; - let subty = self.infer_pat(inner_pat, &expectation_type, default_bm, decl); - TyKind::Ref(mutability, expectation_lt, subty).intern(Interner) + let subty = self.infer_pat(inner_pat, expectation_type, default_bm, decl); + Ty::new_ref(self.interner(), expectation_lt, subty, mutability) } fn infer_bind_pat( @@ -463,9 +479,9 @@ impl InferenceContext<'_> { binding: BindingId, default_bm: BindingMode, subpat: Option<PatId>, - expected: &Ty, + expected: Ty<'db>, decl: Option<DeclContext>, - ) -> Ty { + ) -> Ty<'db> { let Binding { mode, .. } = self.body[binding]; let mode = if mode == BindingAnnotation::Unannotated { default_bm @@ -476,31 +492,31 @@ impl InferenceContext<'_> { let inner_ty = match subpat { Some(subpat) => self.infer_pat(subpat, expected, default_bm, decl), - None => expected.clone(), + None => expected, }; let inner_ty = self.insert_type_vars_shallow(inner_ty); let bound_ty = match mode { BindingMode::Ref(mutability) => { - let inner_lt = self.table.new_lifetime_var(); - TyKind::Ref(mutability, inner_lt, inner_ty.clone()).intern(Interner) + let inner_lt = self.table.next_region_var(); + Ty::new_ref(self.interner(), inner_lt, expected, mutability) } - BindingMode::Move => inner_ty.clone(), + BindingMode::Move => expected, }; - self.write_pat_ty(pat, inner_ty.clone()); + self.write_pat_ty(pat, inner_ty); self.write_binding_ty(binding, bound_ty); inner_ty } fn infer_slice_pat( &mut self, - expected: &Ty, + expected: Ty<'db>, prefix: &[PatId], - slice: &Option<PatId>, + slice: Option<PatId>, suffix: &[PatId], default_bm: BindingMode, decl: Option<DeclContext>, - ) -> Ty { + ) -> Ty<'db> { let expected = self.table.structurally_resolve_type(expected); // If `expected` is an infer ty, we try to equate it to an array if the given pattern @@ -510,56 +526,61 @@ impl InferenceContext<'_> { && let Some(resolved_array_ty) = self.try_resolve_slice_ty_to_array_ty(prefix, suffix, slice) { - self.unify(&expected, &resolved_array_ty); + self.unify(expected, resolved_array_ty); } - let expected = self.table.structurally_resolve_type(&expected); - let elem_ty = match expected.kind(Interner) { - TyKind::Array(st, _) | TyKind::Slice(st) => st.clone(), + let expected = self.table.try_structurally_resolve_type(expected); + let elem_ty = match expected.kind() { + TyKind::Array(st, _) | TyKind::Slice(st) => st, _ => self.err_ty(), }; for &pat_id in prefix.iter().chain(suffix.iter()) { - self.infer_pat(pat_id, &elem_ty, default_bm, decl); + self.infer_pat(pat_id, elem_ty, default_bm, decl); } - if let &Some(slice_pat_id) = slice { - let rest_pat_ty = match expected.kind(Interner) { + if let Some(slice_pat_id) = slice { + let rest_pat_ty = match expected.kind() { TyKind::Array(_, length) => { let len = try_const_usize(self.db, length); let len = len.and_then(|len| len.checked_sub((prefix.len() + suffix.len()) as u128)); - TyKind::Array(elem_ty.clone(), usize_const(self.db, len, self.resolver.krate())) + Ty::new_array_with_const_len( + self.interner(), + elem_ty, + usize_const(self.db, len, self.resolver.krate()), + ) } - _ => TyKind::Slice(elem_ty.clone()), - } - .intern(Interner); - self.infer_pat(slice_pat_id, &rest_pat_ty, default_bm, decl); + _ => Ty::new_slice(self.interner(), elem_ty), + }; + self.infer_pat(slice_pat_id, rest_pat_ty, default_bm, decl); } - match expected.kind(Interner) { - TyKind::Array(_, const_) => TyKind::Array(elem_ty, const_.clone()), - _ => TyKind::Slice(elem_ty), + match expected.kind() { + TyKind::Array(_, const_) => { + Ty::new_array_with_const_len(self.interner(), elem_ty, const_) + } + _ => Ty::new_slice(self.interner(), elem_ty), } - .intern(Interner) } - fn infer_lit_pat(&mut self, expr: ExprId, expected: &Ty) -> Ty { + fn infer_lit_pat(&mut self, expr: ExprId, expected: Ty<'db>) -> Ty<'db> { // Like slice patterns, byte string patterns can denote both `&[u8; N]` and `&[u8]`. if let Expr::Literal(Literal::ByteString(_)) = self.body[expr] - && let Some((inner, ..)) = expected.as_reference() + && let TyKind::Ref(_, inner, _) = expected.kind() { - let inner = self.table.structurally_resolve_type(inner); - if matches!(inner.kind(Interner), TyKind::Slice(_)) { - let elem_ty = TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(Interner); - let slice_ty = TyKind::Slice(elem_ty).intern(Interner); - let ty = TyKind::Ref(Mutability::Not, static_lifetime(), slice_ty).intern(Interner); - self.write_expr_ty(expr, ty.clone()); + let inner = self.table.try_structurally_resolve_type(inner); + if matches!(inner.kind(), TyKind::Slice(_)) { + let elem_ty = self.types.u8; + let slice_ty = Ty::new_slice(self.interner(), elem_ty); + let ty = + Ty::new_ref(self.interner(), self.types.re_static, slice_ty, Mutability::Not); + self.write_expr_ty(expr, ty); return ty; } } - self.infer_expr(expr, &Expectation::has_type(expected.clone()), ExprIsRead::Yes) + self.infer_expr(expr, &Expectation::has_type(expected), ExprIsRead::Yes) } fn is_non_ref_pat(&mut self, body: &hir_def::expr_store::Body, pat: PatId) -> bool { @@ -593,17 +614,17 @@ impl InferenceContext<'_> { &mut self, before: &[PatId], suffix: &[PatId], - slice: &Option<PatId>, - ) -> Option<Ty> { - if !slice.is_none() { + slice: Option<PatId>, + ) -> Option<Ty<'db>> { + if slice.is_some() { return None; } let len = before.len() + suffix.len(); let size = consteval::usize_const(self.db, Some(len as u128), self.owner.krate(self.db)); - let elem_ty = self.table.new_type_var(); - let array_ty = TyKind::Array(elem_ty, size).intern(Interner); + let elem_ty = self.table.next_ty_var(); + let array_ty = Ty::new_array_with_const_len(self.interner(), elem_ty, size); Some(array_ty) } |