Infer types of nested RPITs
This commit is contained in:
parent
44cf8ef49a
commit
a584cb998f
@ -92,6 +92,7 @@ pub enum LayoutError {
|
|||||||
SizeOverflow,
|
SizeOverflow,
|
||||||
TargetLayoutNotAvailable,
|
TargetLayoutNotAvailable,
|
||||||
HasPlaceholder,
|
HasPlaceholder,
|
||||||
|
HasErrorType,
|
||||||
NotImplemented,
|
NotImplemented,
|
||||||
Unknown,
|
Unknown,
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ use hir_def::{
|
|||||||
TraitId, TypeAliasId, VariantId,
|
TraitId, TypeAliasId, VariantId,
|
||||||
};
|
};
|
||||||
use hir_expand::name::{name, Name};
|
use hir_expand::name::{name, Name};
|
||||||
use la_arena::ArenaMap;
|
use la_arena::{ArenaMap, Entry};
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
use stdx::{always, never};
|
use stdx::{always, never};
|
||||||
|
|
||||||
@ -676,36 +676,16 @@ impl<'a> InferenceContext<'a> {
|
|||||||
let return_ty = if let Some(rpits) = self.db.return_type_impl_traits(func) {
|
let return_ty = if let Some(rpits) = self.db.return_type_impl_traits(func) {
|
||||||
// RPIT opaque types use substitution of their parent function.
|
// RPIT opaque types use substitution of their parent function.
|
||||||
let fn_placeholders = TyBuilder::placeholder_subst(self.db, func);
|
let fn_placeholders = TyBuilder::placeholder_subst(self.db, func);
|
||||||
fold_tys(
|
let result =
|
||||||
return_ty,
|
self.insert_inference_vars_for_rpit(return_ty, rpits.clone(), fn_placeholders);
|
||||||
|ty, _| {
|
let rpits = rpits.skip_binders();
|
||||||
let opaque_ty_id = match ty.kind(Interner) {
|
for (id, _) in rpits.impl_traits.iter() {
|
||||||
TyKind::OpaqueType(opaque_ty_id, _) => *opaque_ty_id,
|
if let Entry::Vacant(e) = self.result.type_of_rpit.entry(id) {
|
||||||
_ => return ty,
|
never!("Missed RPIT in `insert_inference_vars_for_rpit`");
|
||||||
};
|
e.insert(TyKind::Error.intern(Interner));
|
||||||
let idx = match self.db.lookup_intern_impl_trait_id(opaque_ty_id.into()) {
|
}
|
||||||
ImplTraitId::ReturnTypeImplTrait(_, idx) => idx,
|
}
|
||||||
_ => unreachable!(),
|
result
|
||||||
};
|
|
||||||
let bounds = (*rpits).map_ref(|rpits| {
|
|
||||||
rpits.impl_traits[idx].bounds.map_ref(|it| it.into_iter())
|
|
||||||
});
|
|
||||||
let var = self.table.new_type_var();
|
|
||||||
let var_subst = Substitution::from1(Interner, var.clone());
|
|
||||||
for bound in bounds {
|
|
||||||
let predicate =
|
|
||||||
bound.map(|it| it.cloned()).substitute(Interner, &fn_placeholders);
|
|
||||||
let (var_predicate, binders) = predicate
|
|
||||||
.substitute(Interner, &var_subst)
|
|
||||||
.into_value_and_skipped_binders();
|
|
||||||
always!(binders.is_empty(Interner)); // quantified where clauses not yet handled
|
|
||||||
self.push_obligation(var_predicate.cast(Interner));
|
|
||||||
}
|
|
||||||
self.result.type_of_rpit.insert(idx, var.clone());
|
|
||||||
var
|
|
||||||
},
|
|
||||||
DebruijnIndex::INNERMOST,
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
return_ty
|
return_ty
|
||||||
};
|
};
|
||||||
@ -714,6 +694,50 @@ impl<'a> InferenceContext<'a> {
|
|||||||
self.return_coercion = Some(CoerceMany::new(self.return_ty.clone()));
|
self.return_coercion = Some(CoerceMany::new(self.return_ty.clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn insert_inference_vars_for_rpit<T>(
|
||||||
|
&mut self,
|
||||||
|
t: T,
|
||||||
|
rpits: Arc<chalk_ir::Binders<crate::ReturnTypeImplTraits>>,
|
||||||
|
fn_placeholders: Substitution,
|
||||||
|
) -> T
|
||||||
|
where
|
||||||
|
T: crate::HasInterner<Interner = Interner> + crate::TypeFoldable<Interner>,
|
||||||
|
{
|
||||||
|
fold_tys(
|
||||||
|
t,
|
||||||
|
|ty, _| {
|
||||||
|
let opaque_ty_id = match ty.kind(Interner) {
|
||||||
|
TyKind::OpaqueType(opaque_ty_id, _) => *opaque_ty_id,
|
||||||
|
_ => return ty,
|
||||||
|
};
|
||||||
|
let idx = match self.db.lookup_intern_impl_trait_id(opaque_ty_id.into()) {
|
||||||
|
ImplTraitId::ReturnTypeImplTrait(_, idx) => idx,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
let bounds = (*rpits)
|
||||||
|
.map_ref(|rpits| rpits.impl_traits[idx].bounds.map_ref(|it| it.into_iter()));
|
||||||
|
let var = self.table.new_type_var();
|
||||||
|
let var_subst = Substitution::from1(Interner, var.clone());
|
||||||
|
for bound in bounds {
|
||||||
|
let predicate =
|
||||||
|
bound.map(|it| it.cloned()).substitute(Interner, &fn_placeholders);
|
||||||
|
let (var_predicate, binders) =
|
||||||
|
predicate.substitute(Interner, &var_subst).into_value_and_skipped_binders();
|
||||||
|
always!(binders.is_empty(Interner)); // quantified where clauses not yet handled
|
||||||
|
let var_predicate = self.insert_inference_vars_for_rpit(
|
||||||
|
var_predicate,
|
||||||
|
rpits.clone(),
|
||||||
|
fn_placeholders.clone(),
|
||||||
|
);
|
||||||
|
self.push_obligation(var_predicate.cast(Interner));
|
||||||
|
}
|
||||||
|
self.result.type_of_rpit.insert(idx, var.clone());
|
||||||
|
var
|
||||||
|
},
|
||||||
|
DebruijnIndex::INNERMOST,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn infer_body(&mut self) {
|
fn infer_body(&mut self) {
|
||||||
match self.return_coercion {
|
match self.return_coercion {
|
||||||
Some(_) => self.infer_return(self.body.body_expr),
|
Some(_) => self.infer_return(self.body.body_expr),
|
||||||
|
@ -245,8 +245,8 @@ pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty, krate: CrateId) -> Result<Lay
|
|||||||
TyKind::Generator(_, _) | TyKind::GeneratorWitness(_, _) => {
|
TyKind::Generator(_, _) | TyKind::GeneratorWitness(_, _) => {
|
||||||
return Err(LayoutError::NotImplemented)
|
return Err(LayoutError::NotImplemented)
|
||||||
}
|
}
|
||||||
|
TyKind::Error => return Err(LayoutError::HasErrorType),
|
||||||
TyKind::AssociatedType(_, _)
|
TyKind::AssociatedType(_, _)
|
||||||
| TyKind::Error
|
|
||||||
| TyKind::Alias(_)
|
| TyKind::Alias(_)
|
||||||
| TyKind::Placeholder(_)
|
| TyKind::Placeholder(_)
|
||||||
| TyKind::BoundVar(_)
|
| TyKind::BoundVar(_)
|
||||||
|
@ -232,6 +232,45 @@ fn return_position_impl_trait() {
|
|||||||
fn foo() -> (impl T, impl T, impl T) { (2i64, 5i32, 7i32) }
|
fn foo() -> (impl T, impl T, impl T) { (2i64, 5i32, 7i32) }
|
||||||
foo()
|
foo()
|
||||||
}
|
}
|
||||||
|
size_and_align_expr! {
|
||||||
|
minicore: iterators;
|
||||||
|
stmts: []
|
||||||
|
trait Tr {}
|
||||||
|
impl Tr for i32 {}
|
||||||
|
fn foo() -> impl Iterator<Item = impl Tr> {
|
||||||
|
[1, 2, 3].into_iter()
|
||||||
|
}
|
||||||
|
let mut iter = foo();
|
||||||
|
let item = iter.next();
|
||||||
|
(iter, item)
|
||||||
|
}
|
||||||
|
size_and_align_expr! {
|
||||||
|
minicore: future;
|
||||||
|
stmts: []
|
||||||
|
use core::{future::Future, task::{Poll, Context}, pin::pin};
|
||||||
|
use std::{task::Wake, sync::Arc};
|
||||||
|
trait Tr {}
|
||||||
|
impl Tr for i32 {}
|
||||||
|
async fn f() -> impl Tr {
|
||||||
|
2
|
||||||
|
}
|
||||||
|
fn unwrap_fut<T>(inp: impl Future<Output = T>) -> Poll<T> {
|
||||||
|
// In a normal test we could use `loop {}` or `panic!()` here,
|
||||||
|
// but rustc actually runs this code.
|
||||||
|
let pinned = pin!(inp);
|
||||||
|
struct EmptyWaker;
|
||||||
|
impl Wake for EmptyWaker {
|
||||||
|
fn wake(self: Arc<Self>) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let waker = Arc::new(EmptyWaker).into();
|
||||||
|
let mut context = Context::from_waker(&waker);
|
||||||
|
let x = pinned.poll(&mut context);
|
||||||
|
x
|
||||||
|
}
|
||||||
|
let x = unwrap_fut(f());
|
||||||
|
x
|
||||||
|
}
|
||||||
size_and_align_expr! {
|
size_and_align_expr! {
|
||||||
struct Foo<T>(T, T, (T, T));
|
struct Foo<T>(T, T, (T, T));
|
||||||
trait T {}
|
trait T {}
|
||||||
|
@ -891,12 +891,19 @@ pub mod iter {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub struct IntoIter<T, const N: usize>([T; N]);
|
struct IndexRange {
|
||||||
|
start: usize,
|
||||||
|
end: usize,
|
||||||
|
}
|
||||||
|
pub struct IntoIter<T, const N: usize> {
|
||||||
|
data: [T; N],
|
||||||
|
range: IndexRange,
|
||||||
|
}
|
||||||
impl<T, const N: usize> IntoIterator for [T; N] {
|
impl<T, const N: usize> IntoIterator for [T; N] {
|
||||||
type Item = T;
|
type Item = T;
|
||||||
type IntoIter = IntoIter<T, N>;
|
type IntoIter = IntoIter<T, N>;
|
||||||
fn into_iter(self) -> I {
|
fn into_iter(self) -> I {
|
||||||
IntoIter(self)
|
IntoIter { data: self, range: IndexRange { start: 0, end: self.len() } }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<T, const N: usize> Iterator for IntoIter<T, N> {
|
impl<T, const N: usize> Iterator for IntoIter<T, N> {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user