Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit a486f34

Browse files
committed
Auto merge of rust-lang#14434 - Veykril:ty-tail-norm, r=Veykril
fix: Use struct_tail_without_normalization in Expectation::rvalue_hint
2 parents 7a98e24 + bea1c71 commit a486f34

File tree

4 files changed

+71
-14
lines changed

4 files changed

+71
-14
lines changed

crates/hir-ty/src/infer.rs

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
//! to certain types. To record this, we use the union-find implementation from
1414
//! the `ena` crate, which is extracted from rustc.
1515
16-
use std::ops::Index;
1716
use std::sync::Arc;
17+
use std::{convert::identity, ops::Index};
1818

1919
use chalk_ir::{cast::Cast, ConstValue, DebruijnIndex, Mutability, Safety, Scalar, TypeFlags};
2020
use either::Either;
@@ -791,6 +791,65 @@ impl<'a> InferenceContext<'a> {
791791
self.table.unify(ty1, ty2)
792792
}
793793

794+
/// Attempts to returns the deeply last field of nested structures, but
795+
/// does not apply any normalization in its search. Returns the same type
796+
/// if input `ty` is not a structure at all.
797+
fn struct_tail_without_normalization(&mut self, ty: Ty) -> Ty {
798+
self.struct_tail_with_normalize(ty, identity)
799+
}
800+
801+
/// Returns the deeply last field of nested structures, or the same type if
802+
/// not a structure at all. Corresponds to the only possible unsized field,
803+
/// and its type can be used to determine unsizing strategy.
804+
///
805+
/// This is parameterized over the normalization strategy (i.e. how to
806+
/// handle `<T as Trait>::Assoc` and `impl Trait`); pass the identity
807+
/// function to indicate no normalization should take place.
808+
fn struct_tail_with_normalize(
809+
&mut self,
810+
mut ty: Ty,
811+
mut normalize: impl FnMut(Ty) -> Ty,
812+
) -> Ty {
813+
// FIXME: fetch the limit properly
814+
let recursion_limit = 10;
815+
for iteration in 0.. {
816+
if iteration > recursion_limit {
817+
return self.err_ty();
818+
}
819+
match ty.kind(Interner) {
820+
TyKind::Adt(chalk_ir::AdtId(hir_def::AdtId::StructId(struct_id)), substs) => {
821+
match self.db.field_types((*struct_id).into()).values().next_back().cloned() {
822+
Some(field) => {
823+
ty = field.substitute(Interner, substs);
824+
}
825+
None => break,
826+
}
827+
}
828+
TyKind::Adt(..) => break,
829+
TyKind::Tuple(_, substs) => {
830+
match substs
831+
.as_slice(Interner)
832+
.split_last()
833+
.and_then(|(last_ty, _)| last_ty.ty(Interner))
834+
{
835+
Some(last_ty) => ty = last_ty.clone(),
836+
None => break,
837+
}
838+
}
839+
TyKind::Alias(..) => {
840+
let normalized = normalize(ty.clone());
841+
if ty == normalized {
842+
return ty;
843+
} else {
844+
ty = normalized;
845+
}
846+
}
847+
_ => break,
848+
}
849+
}
850+
ty
851+
}
852+
794853
/// Recurses through the given type, normalizing associated types mentioned
795854
/// in it by replacing them by type variables and registering obligations to
796855
/// resolve later. This should be done once for every type we get from some
@@ -1138,9 +1197,8 @@ impl Expectation {
11381197
/// which still is useful, because it informs integer literals and the like.
11391198
/// See the test case `test/ui/coerce-expect-unsized.rs` and #20169
11401199
/// for examples of where this comes up,.
1141-
fn rvalue_hint(table: &mut unify::InferenceTable<'_>, ty: Ty) -> Self {
1142-
// FIXME: do struct_tail_without_normalization
1143-
match table.resolve_ty_shallow(&ty).kind(Interner) {
1200+
fn rvalue_hint(ctx: &mut InferenceContext<'_>, ty: Ty) -> Self {
1201+
match ctx.struct_tail_without_normalization(ty.clone()).kind(Interner) {
11441202
TyKind::Slice(_) | TyKind::Str | TyKind::Dyn(_) => Expectation::RValueLikeUnsized(ty),
11451203
_ => Expectation::has_type(ty),
11461204
}

crates/hir-ty/src/infer/expr.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -643,7 +643,7 @@ impl<'a> InferenceContext<'a> {
643643
// FIXME: record type error - expected reference but found ptr,
644644
// which cannot be coerced
645645
}
646-
Expectation::rvalue_hint(&mut self.table, Ty::clone(exp_inner))
646+
Expectation::rvalue_hint(self, Ty::clone(exp_inner))
647647
} else {
648648
Expectation::none()
649649
};
@@ -998,7 +998,7 @@ impl<'a> InferenceContext<'a> {
998998
.filter(|(e_adt, _)| e_adt == &box_id)
999999
.map(|(_, subts)| {
10001000
let g = subts.at(Interner, 0);
1001-
Expectation::rvalue_hint(table, Ty::clone(g.assert_ty_ref(Interner)))
1001+
Expectation::rvalue_hint(self, Ty::clone(g.assert_ty_ref(Interner)))
10021002
})
10031003
.unwrap_or_else(Expectation::none);
10041004

@@ -1593,7 +1593,7 @@ impl<'a> InferenceContext<'a> {
15931593
// the parameter to coerce to the expected type (for example in
15941594
// `coerce_unsize_expected_type_4`).
15951595
let param_ty = self.normalize_associated_types_in(param_ty);
1596-
let expected = Expectation::rvalue_hint(&mut self.table, expected_ty);
1596+
let expected = Expectation::rvalue_hint(self, expected_ty);
15971597
// infer with the expected type we have...
15981598
let ty = self.infer_expr_inner(arg, &expected);
15991599

crates/hir-ty/src/tests/coercion.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -536,7 +536,6 @@ fn test() {
536536

537537
#[test]
538538
fn coerce_unsize_generic() {
539-
// FIXME: fix the type mismatches here
540539
check(
541540
r#"
542541
//- minicore: coerce_unsized
@@ -545,9 +544,9 @@ struct Bar<T>(Foo<T>);
545544
546545
fn test() {
547546
let _: &Foo<[usize]> = &Foo { t: [1, 2, 3] };
548-
//^^^^^^^^^ expected [usize], got [usize; 3]
547+
//^^^^^^^^^^^^^^^^^^^^^ expected &Foo<[usize]>, got &Foo<[i32; 3]>
549548
let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] });
550-
//^^^^^^^^^ expected [usize], got [usize; 3]
549+
//^^^^^^^^^^^^^^^^^^^^^^^^^^ expected &Bar<[usize]>, got &Bar<[i32; 3]>
551550
}
552551
"#,
553552
);

lib/la-arena/src/map.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,17 +72,17 @@ impl<T, V> ArenaMap<Idx<T>, V> {
7272
}
7373

7474
/// Returns an iterator over the values in the map.
75-
pub fn values(&self) -> impl Iterator<Item = &V> {
75+
pub fn values(&self) -> impl Iterator<Item = &V> + DoubleEndedIterator {
7676
self.v.iter().filter_map(|o| o.as_ref())
7777
}
7878

7979
/// Returns an iterator over mutable references to the values in the map.
80-
pub fn values_mut(&mut self) -> impl Iterator<Item = &mut V> {
80+
pub fn values_mut(&mut self) -> impl Iterator<Item = &mut V> + DoubleEndedIterator {
8181
self.v.iter_mut().filter_map(|o| o.as_mut())
8282
}
8383

8484
/// Returns an iterator over the arena indexes and values in the map.
85-
pub fn iter(&self) -> impl Iterator<Item = (Idx<T>, &V)> {
85+
pub fn iter(&self) -> impl Iterator<Item = (Idx<T>, &V)> + DoubleEndedIterator {
8686
self.v.iter().enumerate().filter_map(|(idx, o)| Some((Self::from_idx(idx), o.as_ref()?)))
8787
}
8888

@@ -96,7 +96,7 @@ impl<T, V> ArenaMap<Idx<T>, V> {
9696

9797
/// Returns an iterator over the arena indexes and values in the map.
9898
// FIXME: Implement `IntoIterator` trait.
99-
pub fn into_iter(self) -> impl Iterator<Item = (Idx<T>, V)> {
99+
pub fn into_iter(self) -> impl Iterator<Item = (Idx<T>, V)> + DoubleEndedIterator {
100100
self.v.into_iter().enumerate().filter_map(|(idx, o)| Some((Self::from_idx(idx), o?)))
101101
}
102102

0 commit comments

Comments
 (0)