Skip to content

Commit 4243dbf

Browse files
committed
fix: Panic when a TAIT exists in a RPIT
1 parent c9955bf commit 4243dbf

File tree

2 files changed

+72
-11
lines changed

2 files changed

+72
-11
lines changed

crates/hir-ty/src/infer.rs

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,11 @@ fn find_continuable(
604604
}
605605
}
606606

607+
enum ImplTraitReplacingMode {
608+
ReturnPosition(FxHashSet<Ty>),
609+
TypeAlias,
610+
}
611+
607612
impl<'a> InferenceContext<'a> {
608613
fn new(
609614
db: &'a dyn HirDatabase,
@@ -825,13 +830,13 @@ impl<'a> InferenceContext<'a> {
825830
self.write_binding_ty(self_param, ty);
826831
}
827832
}
828-
let mut params_and_ret_tys = Vec::new();
833+
let mut tait_candidates = FxHashSet::default();
829834
for (ty, pat) in param_tys.zip(&*self.body.params) {
830835
let ty = self.insert_type_vars(ty);
831836
let ty = self.normalize_associated_types_in(ty);
832837

833838
self.infer_top_pat(*pat, &ty);
834-
params_and_ret_tys.push(ty);
839+
tait_candidates.insert(ty);
835840
}
836841
let return_ty = &*data.ret_type;
837842

@@ -844,7 +849,12 @@ impl<'a> InferenceContext<'a> {
844849
let return_ty = if let Some(rpits) = self.db.return_type_impl_traits(func) {
845850
// RPIT opaque types use substitution of their parent function.
846851
let fn_placeholders = TyBuilder::placeholder_subst(self.db, func);
847-
let result = self.insert_inference_vars_for_impl_trait(return_ty, fn_placeholders);
852+
let mut mode = ImplTraitReplacingMode::ReturnPosition(FxHashSet::default());
853+
let result =
854+
self.insert_inference_vars_for_impl_trait(return_ty, fn_placeholders, &mut mode);
855+
if let ImplTraitReplacingMode::ReturnPosition(taits) = mode {
856+
tait_candidates.extend(taits);
857+
}
848858
let rpits = rpits.skip_binders();
849859
for (id, _) in rpits.impl_traits.iter() {
850860
if let Entry::Vacant(e) = self.result.type_of_rpit.entry(id) {
@@ -863,11 +873,16 @@ impl<'a> InferenceContext<'a> {
863873
// Functions might be defining usage sites of TAITs.
864874
// To define an TAITs, that TAIT must appear in the function's signatures.
865875
// So, it suffices to check for params and return types.
866-
params_and_ret_tys.push(self.return_ty.clone());
867-
self.make_tait_coercion_table(params_and_ret_tys.iter());
876+
tait_candidates.insert(self.return_ty.clone());
877+
self.make_tait_coercion_table(tait_candidates.iter());
868878
}
869879

870-
fn insert_inference_vars_for_impl_trait<T>(&mut self, t: T, placeholders: Substitution) -> T
880+
fn insert_inference_vars_for_impl_trait<T>(
881+
&mut self,
882+
t: T,
883+
placeholders: Substitution,
884+
mode: &mut ImplTraitReplacingMode,
885+
) -> T
871886
where
872887
T: crate::HasInterner<Interner = Interner> + crate::TypeFoldable<Interner>,
873888
{
@@ -880,10 +895,31 @@ impl<'a> InferenceContext<'a> {
880895
};
881896
let (impl_traits, idx) =
882897
match self.db.lookup_intern_impl_trait_id(opaque_ty_id.into()) {
898+
// We don't replace opaque types from other kind with inference vars
899+
// because `insert_inference_vars_for_impl_traits` for each kinds
900+
// and unreplaced opaque types of other kind are resolved while
901+
// inferencing because of `tait_coercion_table`.
902+
// Moreover, calling `insert_inference_vars_for_impl_traits` with same
903+
// `placeholders` for other kind may cause trouble because
904+
// the substs for the bounds of each impl traits do not match
883905
ImplTraitId::ReturnTypeImplTrait(def, idx) => {
906+
if matches!(mode, ImplTraitReplacingMode::TypeAlias) {
907+
// RPITs don't have `tait_coercion_table`, so use inserted inference
908+
// vars for them.
909+
if let Some(ty) = self.result.type_of_rpit.get(idx) {
910+
return ty.clone();
911+
}
912+
return ty;
913+
}
884914
(self.db.return_type_impl_traits(def), idx)
885915
}
886916
ImplTraitId::TypeAliasImplTrait(def, idx) => {
917+
if let ImplTraitReplacingMode::ReturnPosition(taits) = mode {
918+
// Gather TAITs while replacing RPITs because TAITs inside RPITs
919+
// may not visited while replacing TAITs
920+
taits.insert(ty.clone());
921+
return ty;
922+
}
887923
(self.db.type_alias_impl_traits(def), idx)
888924
}
889925
_ => unreachable!(),
@@ -892,16 +928,20 @@ impl<'a> InferenceContext<'a> {
892928
return ty;
893929
};
894930
let bounds = (*impl_traits)
895-
.map_ref(|rpits| rpits.impl_traits[idx].bounds.map_ref(|it| it.iter()));
931+
.map_ref(|its| its.impl_traits[idx].bounds.map_ref(|it| it.iter()));
896932
let var = self.table.new_type_var();
897933
let var_subst = Substitution::from1(Interner, var.clone());
898934
for bound in bounds {
899-
let predicate = bound.map(|it| it.cloned()).substitute(Interner, &placeholders);
935+
let predicate = bound.map(|it| it.cloned());
936+
let predicate = predicate.substitute(Interner, &placeholders);
900937
let (var_predicate, binders) =
901938
predicate.substitute(Interner, &var_subst).into_value_and_skipped_binders();
902939
always!(binders.is_empty(Interner)); // quantified where clauses not yet handled
903-
let var_predicate = self
904-
.insert_inference_vars_for_impl_trait(var_predicate, placeholders.clone());
940+
let var_predicate = self.insert_inference_vars_for_impl_trait(
941+
var_predicate,
942+
placeholders.clone(),
943+
mode,
944+
);
905945
self.push_obligation(var_predicate.cast(Interner));
906946
}
907947
self.result.type_of_rpit.insert(idx, var.clone());
@@ -1038,7 +1078,11 @@ impl<'a> InferenceContext<'a> {
10381078
self.db.lookup_intern_impl_trait_id(id.into())
10391079
{
10401080
let subst = TyBuilder::placeholder_subst(self.db, alias_id);
1041-
let ty = self.insert_inference_vars_for_impl_trait(ty, subst);
1081+
let ty = self.insert_inference_vars_for_impl_trait(
1082+
ty,
1083+
subst,
1084+
&mut ImplTraitReplacingMode::TypeAlias,
1085+
);
10421086
Some((id, ty))
10431087
} else {
10441088
None

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2211,3 +2211,20 @@ fn f() -> Foo {}
22112211
"#]],
22122212
);
22132213
}
2214+
2215+
#[test]
2216+
fn issue_17921() {
2217+
check_infer(
2218+
r#"
2219+
//- minicore: future
2220+
trait Foo {}
2221+
type Bar = impl Foo;
2222+
2223+
async fn f<A, B, C>() -> Bar {}
2224+
"#,
2225+
expect![[r#"
2226+
64..66 '{}': ()
2227+
64..66 '{}': impl Future<Output = ()>
2228+
"#]],
2229+
);
2230+
}

0 commit comments

Comments
 (0)