Skip to content

Commit b4151a4

Browse files
committed
Auto merge of #93429 - fee1-dead-contrib:allow-super-trait-tilde-const, r=oli-obk
Allow `trait A: ~const B` What's included: a minimal working change set for `~const` supertraits to work. r? `@oli-obk`
2 parents 35a0617 + 6660227 commit b4151a4

File tree

9 files changed

+153
-12
lines changed

9 files changed

+153
-12
lines changed

compiler/rustc_ast_passes/src/ast_validation.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1272,7 +1272,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
12721272
self.visit_vis(&item.vis);
12731273
self.visit_ident(item.ident);
12741274
self.visit_generics(generics);
1275-
self.with_banned_tilde_const(|this| {
1275+
self.with_tilde_const_allowed(|this| {
12761276
walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits)
12771277
});
12781278
walk_list!(self, visit_assoc_item, items, AssocCtxt::Trait);

compiler/rustc_infer/src/traits/util.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,12 @@ impl<'tcx> Elaborator<'tcx> {
145145
// Get predicates declared on the trait.
146146
let predicates = tcx.super_predicates_of(data.def_id());
147147

148-
let obligations = predicates.predicates.iter().map(|&(pred, _)| {
148+
let obligations = predicates.predicates.iter().map(|&(mut pred, _)| {
149+
// when parent predicate is non-const, elaborate it to non-const predicates.
150+
if data.constness == ty::BoundConstness::NotConst {
151+
pred = pred.without_const(tcx);
152+
}
153+
149154
predicate_obligation(
150155
pred.subst_supertrait(tcx, &bound_predicate.rebind(data.trait_ref)),
151156
obligation.param_env,

compiler/rustc_trait_selection/src/traits/wf.rs

+35-8
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ pub fn trait_obligations<'a, 'tcx>(
8585
infcx: &InferCtxt<'a, 'tcx>,
8686
param_env: ty::ParamEnv<'tcx>,
8787
body_id: hir::HirId,
88-
trait_ref: &ty::TraitRef<'tcx>,
88+
trait_pred: &ty::TraitPredicate<'tcx>,
8989
span: Span,
9090
item: &'tcx hir::Item<'tcx>,
9191
) -> Vec<traits::PredicateObligation<'tcx>> {
@@ -98,7 +98,7 @@ pub fn trait_obligations<'a, 'tcx>(
9898
recursion_depth: 0,
9999
item: Some(item),
100100
};
101-
wf.compute_trait_ref(trait_ref, Elaborate::All);
101+
wf.compute_trait_pred(trait_pred, Elaborate::All);
102102
debug!(obligations = ?wf.out);
103103
wf.normalize(infcx)
104104
}
@@ -123,7 +123,7 @@ pub fn predicate_obligations<'a, 'tcx>(
123123
// It's ok to skip the binder here because wf code is prepared for it
124124
match predicate.kind().skip_binder() {
125125
ty::PredicateKind::Trait(t) => {
126-
wf.compute_trait_ref(&t.trait_ref, Elaborate::None);
126+
wf.compute_trait_pred(&t, Elaborate::None);
127127
}
128128
ty::PredicateKind::RegionOutlives(..) => {}
129129
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => {
@@ -301,11 +301,18 @@ impl<'tcx> WfPredicates<'tcx> {
301301
}
302302

303303
/// Pushes the obligations required for `trait_ref` to be WF into `self.out`.
304-
fn compute_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>, elaborate: Elaborate) {
304+
fn compute_trait_pred(&mut self, trait_pred: &ty::TraitPredicate<'tcx>, elaborate: Elaborate) {
305305
let tcx = self.tcx;
306-
let obligations = self.nominal_obligations(trait_ref.def_id, trait_ref.substs);
306+
let trait_ref = &trait_pred.trait_ref;
307307

308-
debug!("compute_trait_ref obligations {:?}", obligations);
308+
// if the trait predicate is not const, the wf obligations should not be const as well.
309+
let obligations = if trait_pred.constness == ty::BoundConstness::NotConst {
310+
self.nominal_obligations_without_const(trait_ref.def_id, trait_ref.substs)
311+
} else {
312+
self.nominal_obligations(trait_ref.def_id, trait_ref.substs)
313+
};
314+
315+
debug!("compute_trait_pred obligations {:?}", obligations);
309316
let param_env = self.param_env;
310317
let depth = self.recursion_depth;
311318

@@ -685,10 +692,11 @@ impl<'tcx> WfPredicates<'tcx> {
685692
}
686693

687694
#[instrument(level = "debug", skip(self))]
688-
fn nominal_obligations(
695+
fn nominal_obligations_inner(
689696
&mut self,
690697
def_id: DefId,
691698
substs: SubstsRef<'tcx>,
699+
remap_constness: bool,
692700
) -> Vec<traits::PredicateObligation<'tcx>> {
693701
let predicates = self.tcx.predicates_of(def_id);
694702
let mut origins = vec![def_id; predicates.predicates.len()];
@@ -703,19 +711,38 @@ impl<'tcx> WfPredicates<'tcx> {
703711
debug_assert_eq!(predicates.predicates.len(), origins.len());
704712

705713
iter::zip(iter::zip(predicates.predicates, predicates.spans), origins.into_iter().rev())
706-
.map(|((pred, span), origin_def_id)| {
714+
.map(|((mut pred, span), origin_def_id)| {
707715
let code = if span.is_dummy() {
708716
traits::MiscObligation
709717
} else {
710718
traits::BindingObligation(origin_def_id, span)
711719
};
712720
let cause = self.cause(code);
721+
if remap_constness {
722+
pred = pred.without_const(self.tcx);
723+
}
713724
traits::Obligation::with_depth(cause, self.recursion_depth, self.param_env, pred)
714725
})
715726
.filter(|pred| !pred.has_escaping_bound_vars())
716727
.collect()
717728
}
718729

730+
fn nominal_obligations(
731+
&mut self,
732+
def_id: DefId,
733+
substs: SubstsRef<'tcx>,
734+
) -> Vec<traits::PredicateObligation<'tcx>> {
735+
self.nominal_obligations_inner(def_id, substs, false)
736+
}
737+
738+
fn nominal_obligations_without_const(
739+
&mut self,
740+
def_id: DefId,
741+
substs: SubstsRef<'tcx>,
742+
) -> Vec<traits::PredicateObligation<'tcx>> {
743+
self.nominal_obligations_inner(def_id, substs, true)
744+
}
745+
719746
fn from_object_ty(
720747
&mut self,
721748
ty: Ty<'tcx>,

compiler/rustc_typeck/src/check/wfcheck.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
183183
// We match on both `ty::ImplPolarity` and `ast::ImplPolarity` just to get the `!` span.
184184
match (tcx.impl_polarity(def_id), impl_.polarity) {
185185
(ty::ImplPolarity::Positive, _) => {
186-
check_impl(tcx, item, impl_.self_ty, &impl_.of_trait);
186+
check_impl(tcx, item, impl_.self_ty, &impl_.of_trait, impl_.constness);
187187
}
188188
(ty::ImplPolarity::Negative, ast::ImplPolarity::Negative(span)) => {
189189
// FIXME(#27579): what amount of WF checking do we need for neg impls?
@@ -1242,6 +1242,7 @@ fn check_impl<'tcx>(
12421242
item: &'tcx hir::Item<'tcx>,
12431243
ast_self_ty: &hir::Ty<'_>,
12441244
ast_trait_ref: &Option<hir::TraitRef<'_>>,
1245+
constness: hir::Constness,
12451246
) {
12461247
enter_wf_checking_ctxt(tcx, item.span, item.def_id, |wfcx| {
12471248
match *ast_trait_ref {
@@ -1251,11 +1252,19 @@ fn check_impl<'tcx>(
12511252
// won't hold).
12521253
let trait_ref = tcx.impl_trait_ref(item.def_id).unwrap();
12531254
let trait_ref = wfcx.normalize(ast_trait_ref.path.span, None, trait_ref);
1255+
let trait_pred = ty::TraitPredicate {
1256+
trait_ref,
1257+
constness: match constness {
1258+
hir::Constness::Const => ty::BoundConstness::ConstIfConst,
1259+
hir::Constness::NotConst => ty::BoundConstness::NotConst,
1260+
},
1261+
polarity: ty::ImplPolarity::Positive,
1262+
};
12541263
let obligations = traits::wf::trait_obligations(
12551264
wfcx.infcx,
12561265
wfcx.param_env,
12571266
wfcx.body_id,
1258-
&trait_ref,
1267+
&trait_pred,
12591268
ast_trait_ref.path.span,
12601269
item,
12611270
);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#![feature(const_trait_impl)]
2+
3+
trait Foo {
4+
fn a(&self);
5+
}
6+
trait Bar: ~const Foo {}
7+
8+
const fn foo<T: Bar>(x: &T) {
9+
x.a();
10+
//~^ ERROR the trait bound
11+
//~| ERROR cannot call
12+
}
13+
14+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
error[E0277]: the trait bound `T: ~const Foo` is not satisfied
2+
--> $DIR/super-traits-fail-2.rs:9:7
3+
|
4+
LL | x.a();
5+
| ^^^ the trait `~const Foo` is not implemented for `T`
6+
|
7+
note: the trait `Foo` is implemented for `T`, but that implementation is not `const`
8+
--> $DIR/super-traits-fail-2.rs:9:7
9+
|
10+
LL | x.a();
11+
| ^^^
12+
13+
error[E0015]: cannot call non-const fn `<T as Foo>::a` in constant functions
14+
--> $DIR/super-traits-fail-2.rs:9:7
15+
|
16+
LL | x.a();
17+
| ^^^
18+
|
19+
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
20+
21+
error: aborting due to 2 previous errors
22+
23+
Some errors have detailed explanations: E0015, E0277.
24+
For more information about an error, try `rustc --explain E0015`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#![feature(const_trait_impl)]
2+
3+
trait Foo {
4+
fn a(&self);
5+
}
6+
trait Bar: ~const Foo {}
7+
8+
struct S;
9+
impl Foo for S {
10+
fn a(&self) {}
11+
}
12+
13+
impl const Bar for S {}
14+
//~^ ERROR the trait bound
15+
16+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
error[E0277]: the trait bound `S: ~const Foo` is not satisfied
2+
--> $DIR/super-traits-fail.rs:13:12
3+
|
4+
LL | impl const Bar for S {}
5+
| ^^^ the trait `~const Foo` is not implemented for `S`
6+
|
7+
note: the trait `Foo` is implemented for `S`, but that implementation is not `const`
8+
--> $DIR/super-traits-fail.rs:13:12
9+
|
10+
LL | impl const Bar for S {}
11+
| ^^^
12+
note: required by a bound in `Bar`
13+
--> $DIR/super-traits-fail.rs:6:12
14+
|
15+
LL | trait Bar: ~const Foo {}
16+
| ^^^^^^^^^^ required by this bound in `Bar`
17+
help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
18+
|
19+
LL | impl const Bar for S where S: ~const Foo {}
20+
| +++++++++++++++++++
21+
22+
error: aborting due to previous error
23+
24+
For more information about this error, try `rustc --explain E0277`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// check-pass
2+
#![feature(const_trait_impl)]
3+
4+
trait Foo {
5+
fn a(&self);
6+
}
7+
trait Bar: ~const Foo {}
8+
9+
struct S;
10+
impl const Foo for S {
11+
fn a(&self) {}
12+
}
13+
14+
impl const Bar for S {}
15+
16+
const fn foo<T: ~const Bar>(t: &T) {
17+
t.a();
18+
}
19+
20+
const _: () = foo(&S);
21+
22+
fn main() {}

0 commit comments

Comments
 (0)