|
13 | 13 | //! to certain types. To record this, we use the union-find implementation from
|
14 | 14 | //! the `ena` crate, which is extracted from rustc.
|
15 | 15 |
|
16 |
| -use std::ops::Index; |
17 | 16 | use std::sync::Arc;
|
| 17 | +use std::{convert::identity, ops::Index}; |
18 | 18 |
|
19 | 19 | use chalk_ir::{cast::Cast, ConstValue, DebruijnIndex, Mutability, Safety, Scalar, TypeFlags};
|
20 | 20 | use either::Either;
|
@@ -791,6 +791,65 @@ impl<'a> InferenceContext<'a> {
|
791 | 791 | self.table.unify(ty1, ty2)
|
792 | 792 | }
|
793 | 793 |
|
| 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 | + |
794 | 853 | /// Recurses through the given type, normalizing associated types mentioned
|
795 | 854 | /// in it by replacing them by type variables and registering obligations to
|
796 | 855 | /// resolve later. This should be done once for every type we get from some
|
@@ -1138,9 +1197,8 @@ impl Expectation {
|
1138 | 1197 | /// which still is useful, because it informs integer literals and the like.
|
1139 | 1198 | /// See the test case `test/ui/coerce-expect-unsized.rs` and #20169
|
1140 | 1199 | /// 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) { |
1144 | 1202 | TyKind::Slice(_) | TyKind::Str | TyKind::Dyn(_) => Expectation::RValueLikeUnsized(ty),
|
1145 | 1203 | _ => Expectation::has_type(ty),
|
1146 | 1204 | }
|
|
0 commit comments