mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-29 06:23:25 +00:00
Auto merge of #14434 - Veykril:ty-tail-norm, r=Veykril
fix: Use struct_tail_without_normalization in Expectation::rvalue_hint
This commit is contained in:
commit
a486f34048
4 changed files with 71 additions and 14 deletions
|
@ -13,8 +13,8 @@
|
|||
//! to certain types. To record this, we use the union-find implementation from
|
||||
//! the `ena` crate, which is extracted from rustc.
|
||||
|
||||
use std::ops::Index;
|
||||
use std::sync::Arc;
|
||||
use std::{convert::identity, ops::Index};
|
||||
|
||||
use chalk_ir::{cast::Cast, ConstValue, DebruijnIndex, Mutability, Safety, Scalar, TypeFlags};
|
||||
use either::Either;
|
||||
|
@ -791,6 +791,65 @@ impl<'a> InferenceContext<'a> {
|
|||
self.table.unify(ty1, ty2)
|
||||
}
|
||||
|
||||
/// Attempts to returns the deeply last field of nested structures, but
|
||||
/// does not apply any normalization in its search. Returns the same type
|
||||
/// if input `ty` is not a structure at all.
|
||||
fn struct_tail_without_normalization(&mut self, ty: Ty) -> Ty {
|
||||
self.struct_tail_with_normalize(ty, identity)
|
||||
}
|
||||
|
||||
/// Returns the deeply last field of nested structures, or the same type if
|
||||
/// not a structure at all. Corresponds to the only possible unsized field,
|
||||
/// and its type can be used to determine unsizing strategy.
|
||||
///
|
||||
/// This is parameterized over the normalization strategy (i.e. how to
|
||||
/// handle `<T as Trait>::Assoc` and `impl Trait`); pass the identity
|
||||
/// function to indicate no normalization should take place.
|
||||
fn struct_tail_with_normalize(
|
||||
&mut self,
|
||||
mut ty: Ty,
|
||||
mut normalize: impl FnMut(Ty) -> Ty,
|
||||
) -> Ty {
|
||||
// FIXME: fetch the limit properly
|
||||
let recursion_limit = 10;
|
||||
for iteration in 0.. {
|
||||
if iteration > recursion_limit {
|
||||
return self.err_ty();
|
||||
}
|
||||
match ty.kind(Interner) {
|
||||
TyKind::Adt(chalk_ir::AdtId(hir_def::AdtId::StructId(struct_id)), substs) => {
|
||||
match self.db.field_types((*struct_id).into()).values().next_back().cloned() {
|
||||
Some(field) => {
|
||||
ty = field.substitute(Interner, substs);
|
||||
}
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
TyKind::Adt(..) => break,
|
||||
TyKind::Tuple(_, substs) => {
|
||||
match substs
|
||||
.as_slice(Interner)
|
||||
.split_last()
|
||||
.and_then(|(last_ty, _)| last_ty.ty(Interner))
|
||||
{
|
||||
Some(last_ty) => ty = last_ty.clone(),
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
TyKind::Alias(..) => {
|
||||
let normalized = normalize(ty.clone());
|
||||
if ty == normalized {
|
||||
return ty;
|
||||
} else {
|
||||
ty = normalized;
|
||||
}
|
||||
}
|
||||
_ => break,
|
||||
}
|
||||
}
|
||||
ty
|
||||
}
|
||||
|
||||
/// Recurses through the given type, normalizing associated types mentioned
|
||||
/// in it by replacing them by type variables and registering obligations to
|
||||
/// resolve later. This should be done once for every type we get from some
|
||||
|
@ -1138,9 +1197,8 @@ impl Expectation {
|
|||
/// which still is useful, because it informs integer literals and the like.
|
||||
/// See the test case `test/ui/coerce-expect-unsized.rs` and #20169
|
||||
/// for examples of where this comes up,.
|
||||
fn rvalue_hint(table: &mut unify::InferenceTable<'_>, ty: Ty) -> Self {
|
||||
// FIXME: do struct_tail_without_normalization
|
||||
match table.resolve_ty_shallow(&ty).kind(Interner) {
|
||||
fn rvalue_hint(ctx: &mut InferenceContext<'_>, ty: Ty) -> Self {
|
||||
match ctx.struct_tail_without_normalization(ty.clone()).kind(Interner) {
|
||||
TyKind::Slice(_) | TyKind::Str | TyKind::Dyn(_) => Expectation::RValueLikeUnsized(ty),
|
||||
_ => Expectation::has_type(ty),
|
||||
}
|
||||
|
|
|
@ -643,7 +643,7 @@ impl<'a> InferenceContext<'a> {
|
|||
// FIXME: record type error - expected reference but found ptr,
|
||||
// which cannot be coerced
|
||||
}
|
||||
Expectation::rvalue_hint(&mut self.table, Ty::clone(exp_inner))
|
||||
Expectation::rvalue_hint(self, Ty::clone(exp_inner))
|
||||
} else {
|
||||
Expectation::none()
|
||||
};
|
||||
|
@ -998,7 +998,7 @@ impl<'a> InferenceContext<'a> {
|
|||
.filter(|(e_adt, _)| e_adt == &box_id)
|
||||
.map(|(_, subts)| {
|
||||
let g = subts.at(Interner, 0);
|
||||
Expectation::rvalue_hint(table, Ty::clone(g.assert_ty_ref(Interner)))
|
||||
Expectation::rvalue_hint(self, Ty::clone(g.assert_ty_ref(Interner)))
|
||||
})
|
||||
.unwrap_or_else(Expectation::none);
|
||||
|
||||
|
@ -1593,7 +1593,7 @@ impl<'a> InferenceContext<'a> {
|
|||
// the parameter to coerce to the expected type (for example in
|
||||
// `coerce_unsize_expected_type_4`).
|
||||
let param_ty = self.normalize_associated_types_in(param_ty);
|
||||
let expected = Expectation::rvalue_hint(&mut self.table, expected_ty);
|
||||
let expected = Expectation::rvalue_hint(self, expected_ty);
|
||||
// infer with the expected type we have...
|
||||
let ty = self.infer_expr_inner(arg, &expected);
|
||||
|
||||
|
|
|
@ -536,7 +536,6 @@ fn test() {
|
|||
|
||||
#[test]
|
||||
fn coerce_unsize_generic() {
|
||||
// FIXME: fix the type mismatches here
|
||||
check(
|
||||
r#"
|
||||
//- minicore: coerce_unsized
|
||||
|
@ -545,9 +544,9 @@ struct Bar<T>(Foo<T>);
|
|||
|
||||
fn test() {
|
||||
let _: &Foo<[usize]> = &Foo { t: [1, 2, 3] };
|
||||
//^^^^^^^^^ expected [usize], got [usize; 3]
|
||||
//^^^^^^^^^^^^^^^^^^^^^ expected &Foo<[usize]>, got &Foo<[i32; 3]>
|
||||
let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] });
|
||||
//^^^^^^^^^ expected [usize], got [usize; 3]
|
||||
//^^^^^^^^^^^^^^^^^^^^^^^^^^ expected &Bar<[usize]>, got &Bar<[i32; 3]>
|
||||
}
|
||||
"#,
|
||||
);
|
||||
|
|
|
@ -72,17 +72,17 @@ impl<T, V> ArenaMap<Idx<T>, V> {
|
|||
}
|
||||
|
||||
/// Returns an iterator over the values in the map.
|
||||
pub fn values(&self) -> impl Iterator<Item = &V> {
|
||||
pub fn values(&self) -> impl Iterator<Item = &V> + DoubleEndedIterator {
|
||||
self.v.iter().filter_map(|o| o.as_ref())
|
||||
}
|
||||
|
||||
/// Returns an iterator over mutable references to the values in the map.
|
||||
pub fn values_mut(&mut self) -> impl Iterator<Item = &mut V> {
|
||||
pub fn values_mut(&mut self) -> impl Iterator<Item = &mut V> + DoubleEndedIterator {
|
||||
self.v.iter_mut().filter_map(|o| o.as_mut())
|
||||
}
|
||||
|
||||
/// Returns an iterator over the arena indexes and values in the map.
|
||||
pub fn iter(&self) -> impl Iterator<Item = (Idx<T>, &V)> {
|
||||
pub fn iter(&self) -> impl Iterator<Item = (Idx<T>, &V)> + DoubleEndedIterator {
|
||||
self.v.iter().enumerate().filter_map(|(idx, o)| Some((Self::from_idx(idx), o.as_ref()?)))
|
||||
}
|
||||
|
||||
|
@ -96,7 +96,7 @@ impl<T, V> ArenaMap<Idx<T>, V> {
|
|||
|
||||
/// Returns an iterator over the arena indexes and values in the map.
|
||||
// FIXME: Implement `IntoIterator` trait.
|
||||
pub fn into_iter(self) -> impl Iterator<Item = (Idx<T>, V)> {
|
||||
pub fn into_iter(self) -> impl Iterator<Item = (Idx<T>, V)> + DoubleEndedIterator {
|
||||
self.v.into_iter().enumerate().filter_map(|(idx, o)| Some((Self::from_idx(idx), o?)))
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue