Skip to content

Commit 616e379

Browse files
committed
Auto merge of #116756 - fee1-dead-contrib:dupe-those-bounds, r=oli-obk
Duplicate `~const` bounds with a non-const one in effects desugaring This should unblock #116058. r? `@oli-obk`
2 parents 2e57d64 + f0f89d6 commit 616e379

File tree

10 files changed

+661
-40
lines changed

10 files changed

+661
-40
lines changed

compiler/rustc_hir_analysis/src/astconv/mod.rs

+33-1
Original file line numberDiff line numberDiff line change
@@ -1091,7 +1091,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
10911091
self.trait_defines_associated_item_named(r.def_id(), ty::AssocKind::Const, assoc_name)
10921092
});
10931093

1094-
let (bound, next_cand) = match (matching_candidates.next(), const_candidates.next()) {
1094+
let (mut bound, mut next_cand) = match (matching_candidates.next(), const_candidates.next())
1095+
{
10951096
(Some(bound), _) => (bound, matching_candidates.next()),
10961097
(None, Some(bound)) => (bound, const_candidates.next()),
10971098
(None, None) => {
@@ -1107,6 +1108,37 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
11071108
};
11081109
debug!(?bound);
11091110

1111+
// look for a candidate that is not the same as our first bound, disregarding
1112+
// whether the bound is const.
1113+
while let Some(mut bound2) = next_cand {
1114+
debug!(?bound2);
1115+
let tcx = self.tcx();
1116+
if bound2.bound_vars() != bound.bound_vars() {
1117+
break;
1118+
}
1119+
1120+
let generics = tcx.generics_of(bound.def_id());
1121+
let Some(host_index) = generics.host_effect_index else { break };
1122+
1123+
// always return the bound that contains the host param.
1124+
if let ty::ConstKind::Param(_) = bound2.skip_binder().args.const_at(host_index).kind() {
1125+
(bound, bound2) = (bound2, bound);
1126+
}
1127+
1128+
let unconsted_args = bound
1129+
.skip_binder()
1130+
.args
1131+
.iter()
1132+
.enumerate()
1133+
.map(|(n, arg)| if host_index == n { tcx.consts.true_.into() } else { arg });
1134+
1135+
if unconsted_args.eq(bound2.skip_binder().args.iter()) {
1136+
next_cand = matching_candidates.next().or_else(|| const_candidates.next());
1137+
} else {
1138+
break;
1139+
}
1140+
}
1141+
11101142
if let Some(bound2) = next_cand {
11111143
debug!(?bound2);
11121144

compiler/rustc_hir_analysis/src/bounds.rs

+27
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,33 @@ impl<'tcx> Bounds<'tcx> {
4343
trait_ref: ty::PolyTraitRef<'tcx>,
4444
span: Span,
4545
polarity: ty::ImplPolarity,
46+
) {
47+
self.push_trait_bound_inner(tcx, trait_ref, span, polarity);
48+
49+
// if we have a host param, we push an unconst trait bound in addition
50+
// to the const one.
51+
// FIXME(effects) we should find a better way than name matching
52+
if tcx.features().effects && trait_ref.skip_binder().args.host_effect_param().is_some() {
53+
let generics = tcx.generics_of(trait_ref.def_id());
54+
let Some(host_index) = generics.host_effect_index else { return };
55+
let trait_ref = trait_ref.map_bound(|mut trait_ref| {
56+
trait_ref.args =
57+
tcx.mk_args_from_iter(trait_ref.args.iter().enumerate().map(|(n, arg)| {
58+
if host_index == n { tcx.consts.true_.into() } else { arg }
59+
}));
60+
trait_ref
61+
});
62+
63+
self.push_trait_bound_inner(tcx, trait_ref, span, polarity);
64+
}
65+
}
66+
67+
fn push_trait_bound_inner(
68+
&mut self,
69+
tcx: TyCtxt<'tcx>,
70+
trait_ref: ty::PolyTraitRef<'tcx>,
71+
span: Span,
72+
polarity: ty::ImplPolarity,
4673
) {
4774
self.clauses.push((
4875
trait_ref

compiler/rustc_hir_analysis/src/collect/predicates_of.rs

+32-5
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use rustc_hir::intravisit::{self, Visitor};
1111
use rustc_middle::ty::{self, Ty, TyCtxt};
1212
use rustc_middle::ty::{GenericPredicates, ImplTraitInTraitData, ToPredicate};
1313
use rustc_span::symbol::Ident;
14-
use rustc_span::{Span, DUMMY_SP};
14+
use rustc_span::{sym, Span, DUMMY_SP};
1515

1616
/// Returns a list of all type predicates (explicit and implicit) for the definition with
1717
/// ID `def_id`. This includes all predicates returned by `predicates_defined_on`, plus
@@ -38,11 +38,38 @@ pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredic
3838
// an obligation and instead be skipped. Otherwise we'd use
3939
// `tcx.def_span(def_id);`
4040
let span = rustc_span::DUMMY_SP;
41-
result.predicates =
42-
tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(std::iter::once((
43-
ty::TraitRef::identity(tcx, def_id).to_predicate(tcx),
41+
let non_const_bound = if tcx.features().effects && tcx.has_attr(def_id, sym::const_trait) {
42+
// when `Self` is a const trait, also add `Self: Trait<.., true>` as implied bound,
43+
// because only implementing `Self: Trait<.., false>` is currently not possible.
44+
Some((
45+
ty::TraitRef::new(
46+
tcx,
47+
def_id,
48+
ty::GenericArgs::for_item(tcx, def_id, |param, _| {
49+
if param.is_host_effect() {
50+
tcx.consts.true_.into()
51+
} else {
52+
tcx.mk_param_from_def(param)
53+
}
54+
}),
55+
)
56+
.to_predicate(tcx),
4457
span,
45-
))));
58+
))
59+
} else {
60+
None
61+
};
62+
result.predicates = tcx.arena.alloc_from_iter(
63+
result
64+
.predicates
65+
.iter()
66+
.copied()
67+
.chain(std::iter::once((
68+
ty::TraitRef::identity(tcx, def_id).to_predicate(tcx),
69+
span,
70+
)))
71+
.chain(non_const_bound),
72+
);
4673
}
4774
debug!("predicates_of(def_id={:?}) = {:?}", def_id, result);
4875
result

compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -221,14 +221,14 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
221221
let item_def_id = tcx.hir().ty_param_owner(def_id);
222222
let generics = tcx.generics_of(item_def_id);
223223
let index = generics.param_def_id_to_index[&def_id.to_def_id()];
224+
// HACK(eddyb) should get the original `Span`.
225+
let span = tcx.def_span(def_id);
224226
ty::GenericPredicates {
225227
parent: None,
226228
predicates: tcx.arena.alloc_from_iter(
227229
self.param_env.caller_bounds().iter().filter_map(|predicate| {
228230
match predicate.kind().skip_binder() {
229231
ty::ClauseKind::Trait(data) if data.self_ty().is_param(index) => {
230-
// HACK(eddyb) should get the original `Span`.
231-
let span = tcx.def_span(def_id);
232232
Some((predicate, span))
233233
}
234234
_ => None,

compiler/rustc_middle/src/ty/generics.rs

+4
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ impl GenericParamDef {
7979
}
8080
}
8181

82+
pub fn is_host_effect(&self) -> bool {
83+
matches!(self.kind, GenericParamDefKind::Const { is_host_effect: true, .. })
84+
}
85+
8286
pub fn default_value<'tcx>(
8387
&self,
8488
tcx: TyCtxt<'tcx>,
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
1-
error[E0277]: the trait bound `T: Foo` is not satisfied
2-
--> $DIR/assoc-type-const-bound-usage.rs:12:6
1+
error[E0308]: mismatched types
2+
--> $DIR/assoc-type-const-bound-usage.rs:12:5
33
|
44
LL | <T as Foo>::Assoc::foo();
5-
| ^ the trait `Foo` is not implemented for `T`
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^ expected `host`, found `true`
66
|
7-
help: consider further restricting this bound
8-
|
9-
LL | const fn foo<T: ~const Foo + Foo>() {
10-
| +++++
7+
= note: expected constant `host`
8+
found constant `true`
119

1210
error: aborting due to previous error
1311

14-
For more information about this error, try `rustc --explain E0277`.
12+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)