mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-31 21:47:15 +03:00
Merge pull request #21060 from ChayimFriedman2/adjust-last
fix: Fix some inference of patterns
This commit is contained in:
@@ -759,7 +759,6 @@ struct InternedStandardTypes<'db> {
|
||||
re_erased: Region<'db>,
|
||||
|
||||
empty_args: GenericArgs<'db>,
|
||||
empty_tys: Tys<'db>,
|
||||
}
|
||||
|
||||
impl<'db> InternedStandardTypes<'db> {
|
||||
@@ -795,7 +794,6 @@ fn new(interner: DbInterner<'db>) -> Self {
|
||||
re_erased: Region::new_erased(interner),
|
||||
|
||||
empty_args: GenericArgs::new_from_iter(interner, []),
|
||||
empty_tys: Tys::new_from_iter(interner, []),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1475,15 +1473,30 @@ fn resolve_associated_type(
|
||||
self.resolve_associated_type_with_params(inner_ty, assoc_ty, &[])
|
||||
}
|
||||
|
||||
fn demand_eqtype(&mut self, expected: Ty<'db>, actual: Ty<'db>) {
|
||||
fn demand_eqtype(
|
||||
&mut self,
|
||||
id: ExprOrPatId,
|
||||
expected: Ty<'db>,
|
||||
actual: Ty<'db>,
|
||||
) -> Result<(), ()> {
|
||||
let result = self.demand_eqtype_fixme_no_diag(expected, actual);
|
||||
if result.is_err() {
|
||||
self.result.type_mismatches.insert(id, TypeMismatch { expected, actual });
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fn demand_eqtype_fixme_no_diag(
|
||||
&mut self,
|
||||
expected: Ty<'db>,
|
||||
actual: Ty<'db>,
|
||||
) -> Result<(), ()> {
|
||||
let result = self
|
||||
.table
|
||||
.at(&ObligationCause::new())
|
||||
.eq(expected, actual)
|
||||
.map(|infer_ok| self.table.register_infer_ok(infer_ok));
|
||||
if let Err(_err) = result {
|
||||
// FIXME: Emit diagnostic.
|
||||
}
|
||||
result.map_err(drop)
|
||||
}
|
||||
|
||||
fn demand_suptype(&mut self, expected: Ty<'db>, actual: Ty<'db>) {
|
||||
|
||||
@@ -160,7 +160,7 @@ fn fallback_if_possible(
|
||||
};
|
||||
debug!("fallback_if_possible(ty={:?}): defaulting to `{:?}`", ty, fallback);
|
||||
|
||||
self.demand_eqtype(ty, fallback);
|
||||
_ = self.demand_eqtype_fixme_no_diag(ty, fallback);
|
||||
true
|
||||
}
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ pub(crate) fn infer_binop_expr(
|
||||
{
|
||||
let builtin_return_ty =
|
||||
self.enforce_builtin_binop_types(lhs_ty, rhs_ty, category);
|
||||
self.demand_eqtype(builtin_return_ty, return_ty);
|
||||
_ = self.demand_eqtype(expr.into(), builtin_return_ty, return_ty);
|
||||
builtin_return_ty
|
||||
} else {
|
||||
return_ty
|
||||
|
||||
@@ -109,7 +109,7 @@ fn compute_definition_site_hidden_types(
|
||||
|
||||
let expected =
|
||||
EarlyBinder::bind(ty.ty).instantiate(interner, opaque_type_key.args);
|
||||
self.demand_eqtype(expected, hidden_type.ty);
|
||||
_ = self.demand_eqtype_fixme_no_diag(expected, hidden_type.ty);
|
||||
}
|
||||
|
||||
self.result.type_of_opaque.insert(def_id, ty.ty);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! Type inference for patterns.
|
||||
|
||||
use std::iter::repeat_with;
|
||||
use std::{cmp, iter};
|
||||
|
||||
use hir_def::{
|
||||
HasModule,
|
||||
@@ -19,7 +19,7 @@
|
||||
AllowTwoPhase, BindingMode, Expectation, InferenceContext, TypeMismatch, expr::ExprIsRead,
|
||||
},
|
||||
lower::lower_mutability,
|
||||
next_solver::{GenericArgs, Ty, TyKind},
|
||||
next_solver::{GenericArgs, Ty, TyKind, Tys, infer::traits::ObligationCause},
|
||||
};
|
||||
|
||||
impl<'db> InferenceContext<'_, 'db> {
|
||||
@@ -183,42 +183,61 @@ pub(super) fn infer_record_pat_like(
|
||||
/// Ellipses found in the original pattern or expression must be filtered out.
|
||||
pub(super) fn infer_tuple_pat_like(
|
||||
&mut self,
|
||||
pat: PatId,
|
||||
expected: Ty<'db>,
|
||||
default_bm: BindingMode,
|
||||
ellipsis: Option<u32>,
|
||||
subs: &[PatId],
|
||||
elements: &[PatId],
|
||||
decl: Option<DeclContext>,
|
||||
) -> Ty<'db> {
|
||||
let expected = self.table.structurally_resolve_type(expected);
|
||||
let expectations = match expected.kind() {
|
||||
TyKind::Tuple(parameters) => parameters,
|
||||
_ => self.types.empty_tys,
|
||||
};
|
||||
|
||||
let ((pre, post), n_uncovered_patterns) = match ellipsis {
|
||||
Some(idx) => {
|
||||
(subs.split_at(idx as usize), expectations.len().saturating_sub(subs.len()))
|
||||
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();
|
||||
}
|
||||
None => ((subs, &[][..]), 0),
|
||||
}
|
||||
let max_len = cmp::max(expected_len, elements.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 => (element_tys.as_slice(), &[][..]),
|
||||
};
|
||||
let mut expectations_iter =
|
||||
expectations.iter().chain(repeat_with(|| self.table.next_ty_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);
|
||||
}
|
||||
}
|
||||
|
||||
Ty::new_tup_from_iter(self.interner(), inner_tys.into_iter())
|
||||
pat_ty
|
||||
}
|
||||
|
||||
/// The resolver needs to be updated to the surrounding expression when inside assignment
|
||||
@@ -272,7 +291,7 @@ fn infer_pat(
|
||||
|
||||
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() {
|
||||
@@ -356,7 +375,7 @@ fn infer_pat(
|
||||
GenericArgs::fill_with_defaults(
|
||||
self.interner(),
|
||||
box_adt.into(),
|
||||
std::iter::once(inner_ty.into()).chain(alloc_ty.map(Into::into)),
|
||||
iter::once(inner_ty.into()).chain(alloc_ty.map(Into::into)),
|
||||
|_, id, _| self.table.next_var_for_param(id),
|
||||
),
|
||||
)
|
||||
@@ -416,7 +435,7 @@ fn pat_ty_after_adjustment(&self, pat: PatId) -> Ty<'db> {
|
||||
.result
|
||||
.pat_adjustments
|
||||
.get(&pat)
|
||||
.and_then(|it| it.first())
|
||||
.and_then(|it| it.last())
|
||||
.unwrap_or(&self.result.type_of_pat[pat])
|
||||
}
|
||||
|
||||
@@ -469,9 +488,9 @@ fn infer_bind_pat(
|
||||
let bound_ty = match mode {
|
||||
BindingMode::Ref(mutability) => {
|
||||
let inner_lt = self.table.next_region_var();
|
||||
Ty::new_ref(self.interner(), inner_lt, inner_ty, mutability)
|
||||
Ty::new_ref(self.interner(), inner_lt, expected, mutability)
|
||||
}
|
||||
BindingMode::Move => inner_ty,
|
||||
BindingMode::Move => expected,
|
||||
};
|
||||
self.write_pat_ty(pat, inner_ty);
|
||||
self.write_binding_ty(binding, bound_ty);
|
||||
|
||||
@@ -833,11 +833,11 @@ struct V<T> { t: T }
|
||||
fn main() {
|
||||
let a: V<&dyn Tr>;
|
||||
(a,) = V { t: &S };
|
||||
//^^^^expected V<&'? S>, got (V<&'? (dyn Tr + 'static)>,)
|
||||
//^^^^expected V<&'? S>, got (V<&'? (dyn Tr + '?)>,)
|
||||
|
||||
let mut a: V<&dyn Tr> = V { t: &S };
|
||||
(a,) = V { t: &S };
|
||||
//^^^^expected V<&'? S>, got (V<&'? (dyn Tr + 'static)>,)
|
||||
//^^^^expected V<&'? S>, got (V<&'? (dyn Tr + '?)>,)
|
||||
}
|
||||
"#,
|
||||
);
|
||||
|
||||
@@ -1259,3 +1259,22 @@ fn main() {
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn destructuring_assign_ref() {
|
||||
check_no_mismatches(
|
||||
r#"
|
||||
struct Foo;
|
||||
|
||||
fn foo() -> (&'static Foo, u32) {
|
||||
(&Foo, 0)
|
||||
}
|
||||
|
||||
fn bar() {
|
||||
let ext: &Foo;
|
||||
let v;
|
||||
(ext, v) = foo();
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user