Skip to content

Commit

Permalink
Auto merge of #17505 - ShoyuVanilla:issue-17199, r=Veykril
Browse files Browse the repository at this point in the history
Use proper `ImplTraits` in `insert_inference_vars_for_impl_trait`

Fixes #17199 and fixes #17403

In the previous implementation, I passed `rpits` as a function parameter and used `idx` of `ImplTraitId` for indexing `ImplTrait`.

https://github.com/rust-lang/rust-analyzer/blob/4e836c622a7bdab41be8e82733dd9fe40af128b2/crates/hir-ty/src/infer.rs#L881-L887

But that `idx` is rather a "local" one, so in the cases like mentioned issues, the async function that can be expanded roughly as

```rust
type TypeAlias = impl Something;
fn expanded_async() -> impl Future<Output = TypeAlias> { ... }
```

there are two bundles of `ImplTraits`; one for the `impl Future` and the other one for `TypeAlias`.
So using `idx` with `rpits` returns `ImplTrait` for `impl Future` even if we are asking for `TypeAlias` and this caused a stack overflow.

This PR is a fix for that implementation miss 😅
  • Loading branch information
bors committed Jun 28, 2024
2 parents 4e836c6 + 7e9da2d commit 9463d9e
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 31 deletions.
50 changes: 19 additions & 31 deletions crates/hir-ty/src/infer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -835,11 +835,7 @@ impl<'a> InferenceContext<'a> {
let return_ty = if let Some(rpits) = self.db.return_type_impl_traits(func) {
// RPIT opaque types use substitution of their parent function.
let fn_placeholders = TyBuilder::placeholder_subst(self.db, func);
let result = self.insert_inference_vars_for_impl_trait(
return_ty,
rpits.clone(),
fn_placeholders,
);
let result = self.insert_inference_vars_for_impl_trait(return_ty, fn_placeholders);
let rpits = rpits.skip_binders();
for (id, _) in rpits.impl_traits.iter() {
if let Entry::Vacant(e) = self.result.type_of_rpit.entry(id) {
Expand All @@ -862,12 +858,7 @@ impl<'a> InferenceContext<'a> {
self.insert_atpit_coercion_table(params_and_ret_tys.iter());
}

fn insert_inference_vars_for_impl_trait<T>(
&mut self,
t: T,
rpits: Arc<chalk_ir::Binders<crate::ImplTraits>>,
placeholders: Substitution,
) -> T
fn insert_inference_vars_for_impl_trait<T>(&mut self, t: T, placeholders: Substitution) -> T
where
T: crate::HasInterner<Interner = Interner> + crate::TypeFoldable<Interner>,
{
Expand All @@ -878,25 +869,30 @@ impl<'a> InferenceContext<'a> {
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,
ImplTraitId::AssociatedTypeImplTrait(_, idx) => idx,
_ => unreachable!(),
let (impl_traits, idx) =
match self.db.lookup_intern_impl_trait_id(opaque_ty_id.into()) {
ImplTraitId::ReturnTypeImplTrait(def, idx) => {
(self.db.return_type_impl_traits(def), idx)
}
ImplTraitId::AssociatedTypeImplTrait(def, idx) => {
(self.db.type_alias_impl_traits(def), idx)
}
_ => unreachable!(),
};
let Some(impl_traits) = impl_traits else {
return ty;
};
let bounds =
(*rpits).map_ref(|rpits| rpits.impl_traits[idx].bounds.map_ref(|it| it.iter()));
let bounds = (*impl_traits)
.map_ref(|rpits| rpits.impl_traits[idx].bounds.map_ref(|it| it.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, &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_impl_trait(
var_predicate,
rpits.clone(),
placeholders.clone(),
);
let var_predicate = self
.insert_inference_vars_for_impl_trait(var_predicate, placeholders.clone());
self.push_obligation(var_predicate.cast(Interner));
}
self.result.type_of_rpit.insert(idx, var.clone());
Expand Down Expand Up @@ -983,16 +979,8 @@ impl<'a> InferenceContext<'a> {
self.db.lookup_intern_impl_trait_id(opaque_ty_id.into())
{
if assoc_tys.contains(&alias_id) {
let atpits = self
.db
.type_alias_impl_traits(alias_id)
.expect("Marked as ATPIT but no impl traits!");
let alias_placeholders = TyBuilder::placeholder_subst(self.db, alias_id);
let ty = self.insert_inference_vars_for_impl_trait(
ty,
atpits,
alias_placeholders,
);
let ty = self.insert_inference_vars_for_impl_trait(ty, alias_placeholders);
return Some((opaque_ty_id, ty));
}
}
Expand Down
19 changes: 19 additions & 0 deletions crates/hir-ty/src/tests/regression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1999,3 +1999,22 @@ where
"#,
);
}

#[test]
fn tait_async_stack_overflow_17199() {
check_types(
r#"
//- minicore: fmt, future
type Foo = impl core::fmt::Debug;
async fn foo() -> Foo {
()
}
async fn test() {
let t = foo().await;
// ^ impl Debug
}
"#,
);
}

0 comments on commit 9463d9e

Please sign in to comment.