Skip to content

Commit 0308d4a

Browse files
Compute bound vars correctly
1 parent 773e8a5 commit 0308d4a

File tree

2 files changed

+108
-17
lines changed

2 files changed

+108
-17
lines changed

compiler/rustc_hir_analysis/src/astconv/mod.rs

+55-16
Original file line numberDiff line numberDiff line change
@@ -1088,7 +1088,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
10881088

10891089
// TODO: rtn comment goes here
10901090
let associated_return_type_bound =
1091-
binding.gen_args.parenthesized && self.tcx().features().associated_return_type_bounds;
1091+
binding.gen_args.parenthesized && tcx.features().associated_return_type_bounds;
10921092

10931093
let candidate = if return_type_notation {
10941094
if self.trait_defines_associated_item_named(
@@ -1156,7 +1156,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
11561156
dup_bindings
11571157
.entry(assoc_item.def_id)
11581158
.and_modify(|prev_span| {
1159-
self.tcx().sess.emit_err(ValueOfAssociatedStructAlreadySpecified {
1159+
tcx.sess.emit_err(ValueOfAssociatedStructAlreadySpecified {
11601160
span: binding.span,
11611161
prev_span: *prev_span,
11621162
item_name: binding.item_name,
@@ -1166,14 +1166,53 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
11661166
.or_insert(binding.span);
11671167
}
11681168

1169-
let projection_ty = if associated_return_type_bound {
1170-
let generics = self.tcx().generics_of(assoc_item.def_id);
1171-
if !generics.params.is_empty() {
1172-
todo!();
1173-
}
1174-
let output = self.tcx().fn_sig(assoc_item.def_id).skip_binder().output();
1175-
let fn_bound_vars = output.bound_vars();
1169+
let projection_ty = if return_type_notation {
1170+
// If we have an method return type bound, then we need to substitute
1171+
// the method's early bound params with suitable late-bound params.
1172+
let mut num_bound_vars = candidate.bound_vars().len();
1173+
let substs =
1174+
candidate.skip_binder().substs.extend_to(tcx, assoc_item.def_id, |param, _| {
1175+
let subst = match param.kind {
1176+
GenericParamDefKind::Lifetime => tcx
1177+
.mk_re_late_bound(
1178+
ty::INNERMOST,
1179+
ty::BoundRegion {
1180+
var: ty::BoundVar::from_usize(num_bound_vars),
1181+
kind: ty::BoundRegionKind::BrNamed(param.def_id, param.name),
1182+
},
1183+
)
1184+
.into(),
1185+
GenericParamDefKind::Type { .. } => tcx
1186+
.mk_bound(
1187+
ty::INNERMOST,
1188+
ty::BoundTy {
1189+
var: ty::BoundVar::from_usize(num_bound_vars),
1190+
kind: ty::BoundTyKind::Param(param.def_id, param.name),
1191+
},
1192+
)
1193+
.into(),
1194+
GenericParamDefKind::Const { .. } => {
1195+
let ty = tcx
1196+
.type_of(param.def_id)
1197+
.no_bound_vars()
1198+
.expect("ct params cannot have early bound vars");
1199+
tcx.mk_const(
1200+
ty::ConstKind::Bound(
1201+
ty::INNERMOST,
1202+
ty::BoundVar::from_usize(num_bound_vars),
1203+
),
1204+
ty,
1205+
)
1206+
.into()
1207+
}
1208+
};
1209+
num_bound_vars += 1;
1210+
subst
1211+
});
11761212

1213+
// Next, we need to check that the return-type notation is being used on
1214+
// an RPITIT (return-position impl trait in trait) or AFIT (async fn in trait).
1215+
let output = tcx.fn_sig(assoc_item.def_id).skip_binder().output();
11771216
let output = if let ty::Alias(ty::Projection, alias_ty) = *output.skip_binder().kind()
11781217
&& tcx.def_kind(alias_ty.def_id) == DefKind::ImplTraitPlaceholder
11791218
{
@@ -1182,13 +1221,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
11821221
todo!("found return type of {output:?}");
11831222
};
11841223

1185-
let trait_bound_vars = candidate.bound_vars();
1186-
let shifted_output = tcx.shift_bound_var_indices(trait_bound_vars.len(), output);
1187-
let subst_output =
1188-
ty::EarlyBinder(shifted_output).subst(tcx, candidate.skip_binder().substs);
1189-
let bound_vars =
1190-
tcx.mk_bound_variable_kinds_from_iter(trait_bound_vars.iter().chain(fn_bound_vars));
1224+
// Finally, move the fn return type's bound vars over to account for the early bound
1225+
// params (and trait ref's late bound params). This logic is very similar to
1226+
// `Predicate::subst_supertrait`, and it's no coincidence why.
1227+
let shifted_output = tcx.shift_bound_var_indices(num_bound_vars, output);
1228+
let subst_output = ty::EarlyBinder(shifted_output).subst(tcx, substs);
11911229

1230+
let bound_vars = tcx.late_bound_vars(binding.hir_id);
11921231
ty::Binder::bind_with_vars(subst_output, bound_vars)
11931232
} else {
11941233
// Include substitutions for generic parameters of associated types
@@ -1211,7 +1250,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
12111250

12121251
debug!(?substs_trait_ref_and_assoc_item);
12131252

1214-
self.tcx().mk_alias_ty(assoc_item.def_id, substs_trait_ref_and_assoc_item)
1253+
tcx.mk_alias_ty(assoc_item.def_id, substs_trait_ref_and_assoc_item)
12151254
})
12161255
};
12171256

compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs

+53-1
Original file line numberDiff line numberDiff line change
@@ -1640,7 +1640,59 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
16401640
},
16411641
s: self.scope,
16421642
};
1643-
if let Some(type_def_id) = type_def_id {
1643+
// If the binding is parenthesized, then this must be `feature(return_type_notation)`.
1644+
// In that case, introduce a binder over all of the function's early and late bound vars.
1645+
//
1646+
// For example, given
1647+
// ```
1648+
// trait Foo {
1649+
// async fn x<'r, T>();
1650+
// }
1651+
// ```
1652+
// and a bound that looks like:
1653+
// `for<'a> T::Trait<'a, x(): for<'b> Other<'b>>`
1654+
// this is going to expand to something like:
1655+
// `for<'a> for<'r, T> <T as Trait<'a>>::x::<'r, T>::{opaque#0}: for<'b> Other<'b>`.
1656+
if binding.gen_args.parenthesized {
1657+
let bound_vars = if let Some(type_def_id) = type_def_id
1658+
&& self.tcx.def_kind(type_def_id) == DefKind::Trait
1659+
// FIXME(return_type_notation): We could bound supertrait methods.
1660+
&& let Some(assoc_fn) = self
1661+
.tcx
1662+
.associated_items(type_def_id)
1663+
.find_by_name_and_kind(self.tcx, binding.ident, ty::AssocKind::Fn, type_def_id)
1664+
{
1665+
self.tcx
1666+
.generics_of(assoc_fn.def_id)
1667+
.params
1668+
.iter()
1669+
.map(|param| match param.kind {
1670+
ty::GenericParamDefKind::Lifetime => ty::BoundVariableKind::Region(
1671+
ty::BoundRegionKind::BrNamed(param.def_id, param.name),
1672+
),
1673+
ty::GenericParamDefKind::Type { .. } => ty::BoundVariableKind::Ty(
1674+
ty::BoundTyKind::Param(param.def_id, param.name),
1675+
),
1676+
ty::GenericParamDefKind::Const { .. } => ty::BoundVariableKind::Const,
1677+
})
1678+
.chain(self.tcx.fn_sig(assoc_fn.def_id).subst_identity().bound_vars())
1679+
.collect()
1680+
} else {
1681+
self.tcx.sess.delay_span_bug(
1682+
binding.ident.span,
1683+
"bad return type notation here",
1684+
);
1685+
vec![]
1686+
};
1687+
self.with(scope, |this| {
1688+
let scope = Scope::Supertrait { bound_vars, s: this.scope };
1689+
this.with(scope, |this| {
1690+
let (bound_vars, _) = this.poly_trait_ref_binder_info();
1691+
this.record_late_bound_vars(binding.hir_id, bound_vars);
1692+
this.visit_assoc_type_binding(binding)
1693+
});
1694+
});
1695+
} else if let Some(type_def_id) = type_def_id {
16441696
let bound_vars =
16451697
BoundVarContext::supertrait_hrtb_vars(self.tcx, type_def_id, binding.ident);
16461698
self.with(scope, |this| {

0 commit comments

Comments
 (0)