From 9b75f2d498d67f61c3b40ec57f5ce23ef8e3d874 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Sat, 29 Jan 2022 01:47:20 +1100 Subject: [PATCH 1/4] Allow `~const` on super traits --- compiler/rustc_ast_passes/src/ast_validation.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 334326e927fad..60560b1c00e25 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1272,7 +1272,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.visit_vis(&item.vis); self.visit_ident(item.ident); self.visit_generics(generics); - self.with_banned_tilde_const(|this| { + self.with_tilde_const_allowed(|this| { walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits) }); walk_list!(self, visit_assoc_item, items, AssocCtxt::Trait); From 08cb87843010ef1dcee0e8bc91c3d95eed70c1eb Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Sat, 29 Jan 2022 01:47:58 +1100 Subject: [PATCH 2/4] Remap elaborated obligation constness --- compiler/rustc_infer/src/traits/util.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 674c75fdee561..38ff9343537dc 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -145,7 +145,12 @@ impl<'tcx> Elaborator<'tcx> { // Get predicates declared on the trait. let predicates = tcx.super_predicates_of(data.def_id()); - let obligations = predicates.predicates.iter().map(|&(pred, _)| { + let obligations = predicates.predicates.iter().map(|&(mut pred, _)| { + // when parent predicate is non-const, elaborate it to non-const predicates. + if data.constness == ty::BoundConstness::NotConst { + pred = pred.without_const(tcx); + } + predicate_obligation( pred.subst_supertrait(tcx, &bound_predicate.rebind(data.trait_ref)), obligation.param_env, From 05bb26fdb6635508aaa75c26e593672a86d03084 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Sat, 29 Jan 2022 01:49:15 +1100 Subject: [PATCH 3/4] Add tests --- .../super-traits-fail-2.rs | 14 +++++++++++ .../super-traits-fail-2.stderr | 24 +++++++++++++++++++ .../super-traits-fail.rs | 16 +++++++++++++ .../super-traits-fail.stderr | 24 +++++++++++++++++++ .../rfc-2632-const-trait-impl/super-traits.rs | 22 +++++++++++++++++ 5 files changed, 100 insertions(+) create mode 100644 src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.rs create mode 100644 src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.stderr create mode 100644 src/test/ui/rfc-2632-const-trait-impl/super-traits-fail.rs create mode 100644 src/test/ui/rfc-2632-const-trait-impl/super-traits-fail.stderr create mode 100644 src/test/ui/rfc-2632-const-trait-impl/super-traits.rs diff --git a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.rs b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.rs new file mode 100644 index 0000000000000..7b38c15afc20b --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.rs @@ -0,0 +1,14 @@ +#![feature(const_trait_impl)] + +trait Foo { + fn a(&self); +} +trait Bar: ~const Foo {} + +const fn foo(x: &T) { + x.a(); + //~^ ERROR the trait bound + //~| ERROR cannot call +} + +fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.stderr b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.stderr new file mode 100644 index 0000000000000..1766cdbee8af2 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail-2.stderr @@ -0,0 +1,24 @@ +error[E0277]: the trait bound `T: ~const Foo` is not satisfied + --> $DIR/super-traits-fail-2.rs:9:7 + | +LL | x.a(); + | ^^^ the trait `~const Foo` is not implemented for `T` + | +note: the trait `Foo` is implemented for `T`, but that implementation is not `const` + --> $DIR/super-traits-fail-2.rs:9:7 + | +LL | x.a(); + | ^^^ + +error[E0015]: cannot call non-const fn `::a` in constant functions + --> $DIR/super-traits-fail-2.rs:9:7 + | +LL | x.a(); + | ^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0015, E0277. +For more information about an error, try `rustc --explain E0015`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail.rs b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail.rs new file mode 100644 index 0000000000000..af465cad3d240 --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail.rs @@ -0,0 +1,16 @@ +#![feature(const_trait_impl)] + +trait Foo { + fn a(&self); +} +trait Bar: ~const Foo {} + +struct S; +impl Foo for S { + fn a(&self) {} +} + +impl const Bar for S {} +//~^ ERROR the trait bound + +fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail.stderr b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail.stderr new file mode 100644 index 0000000000000..9e8b8f8c6ba1f --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/super-traits-fail.stderr @@ -0,0 +1,24 @@ +error[E0277]: the trait bound `S: ~const Foo` is not satisfied + --> $DIR/super-traits-fail.rs:13:12 + | +LL | impl const Bar for S {} + | ^^^ the trait `~const Foo` is not implemented for `S` + | +note: the trait `Foo` is implemented for `S`, but that implementation is not `const` + --> $DIR/super-traits-fail.rs:13:12 + | +LL | impl const Bar for S {} + | ^^^ +note: required by a bound in `Bar` + --> $DIR/super-traits-fail.rs:6:12 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^^^^^ required by this bound in `Bar` +help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement + | +LL | impl const Bar for S where S: ~const Foo {} + | +++++++++++++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/super-traits.rs b/src/test/ui/rfc-2632-const-trait-impl/super-traits.rs new file mode 100644 index 0000000000000..aded4ca9a998c --- /dev/null +++ b/src/test/ui/rfc-2632-const-trait-impl/super-traits.rs @@ -0,0 +1,22 @@ +// check-pass +#![feature(const_trait_impl)] + +trait Foo { + fn a(&self); +} +trait Bar: ~const Foo {} + +struct S; +impl const Foo for S { + fn a(&self) {} +} + +impl const Bar for S {} + +const fn foo(t: &T) { + t.a(); +} + +const _: () = foo(&S); + +fn main() {} From 666022730ffc40e2f4dc7802954b9c0a5697cf22 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Sat, 23 Jul 2022 14:25:32 +0000 Subject: [PATCH 4/4] Instantiate constness in wfcheck --- .../rustc_trait_selection/src/traits/wf.rs | 43 +++++++++++++++---- compiler/rustc_typeck/src/check/wfcheck.rs | 13 +++++- 2 files changed, 46 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 6b758ba63cd0f..414857f0acc80 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -85,7 +85,7 @@ pub fn trait_obligations<'a, 'tcx>( infcx: &InferCtxt<'a, 'tcx>, param_env: ty::ParamEnv<'tcx>, body_id: hir::HirId, - trait_ref: &ty::TraitRef<'tcx>, + trait_pred: &ty::TraitPredicate<'tcx>, span: Span, item: &'tcx hir::Item<'tcx>, ) -> Vec> { @@ -98,7 +98,7 @@ pub fn trait_obligations<'a, 'tcx>( recursion_depth: 0, item: Some(item), }; - wf.compute_trait_ref(trait_ref, Elaborate::All); + wf.compute_trait_pred(trait_pred, Elaborate::All); debug!(obligations = ?wf.out); wf.normalize(infcx) } @@ -123,7 +123,7 @@ pub fn predicate_obligations<'a, 'tcx>( // It's ok to skip the binder here because wf code is prepared for it match predicate.kind().skip_binder() { ty::PredicateKind::Trait(t) => { - wf.compute_trait_ref(&t.trait_ref, Elaborate::None); + wf.compute_trait_pred(&t, Elaborate::None); } ty::PredicateKind::RegionOutlives(..) => {} ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => { @@ -301,11 +301,18 @@ impl<'tcx> WfPredicates<'tcx> { } /// Pushes the obligations required for `trait_ref` to be WF into `self.out`. - fn compute_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>, elaborate: Elaborate) { + fn compute_trait_pred(&mut self, trait_pred: &ty::TraitPredicate<'tcx>, elaborate: Elaborate) { let tcx = self.tcx; - let obligations = self.nominal_obligations(trait_ref.def_id, trait_ref.substs); + let trait_ref = &trait_pred.trait_ref; - debug!("compute_trait_ref obligations {:?}", obligations); + // if the trait predicate is not const, the wf obligations should not be const as well. + let obligations = if trait_pred.constness == ty::BoundConstness::NotConst { + self.nominal_obligations_without_const(trait_ref.def_id, trait_ref.substs) + } else { + self.nominal_obligations(trait_ref.def_id, trait_ref.substs) + }; + + debug!("compute_trait_pred obligations {:?}", obligations); let param_env = self.param_env; let depth = self.recursion_depth; @@ -685,10 +692,11 @@ impl<'tcx> WfPredicates<'tcx> { } #[instrument(level = "debug", skip(self))] - fn nominal_obligations( + fn nominal_obligations_inner( &mut self, def_id: DefId, substs: SubstsRef<'tcx>, + remap_constness: bool, ) -> Vec> { let predicates = self.tcx.predicates_of(def_id); let mut origins = vec![def_id; predicates.predicates.len()]; @@ -703,19 +711,38 @@ impl<'tcx> WfPredicates<'tcx> { debug_assert_eq!(predicates.predicates.len(), origins.len()); iter::zip(iter::zip(predicates.predicates, predicates.spans), origins.into_iter().rev()) - .map(|((pred, span), origin_def_id)| { + .map(|((mut pred, span), origin_def_id)| { let code = if span.is_dummy() { traits::MiscObligation } else { traits::BindingObligation(origin_def_id, span) }; let cause = self.cause(code); + if remap_constness { + pred = pred.without_const(self.tcx); + } traits::Obligation::with_depth(cause, self.recursion_depth, self.param_env, pred) }) .filter(|pred| !pred.has_escaping_bound_vars()) .collect() } + fn nominal_obligations( + &mut self, + def_id: DefId, + substs: SubstsRef<'tcx>, + ) -> Vec> { + self.nominal_obligations_inner(def_id, substs, false) + } + + fn nominal_obligations_without_const( + &mut self, + def_id: DefId, + substs: SubstsRef<'tcx>, + ) -> Vec> { + self.nominal_obligations_inner(def_id, substs, true) + } + fn from_object_ty( &mut self, ty: Ty<'tcx>, diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 1b80e4edca910..b8e998229ba8e 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -183,7 +183,7 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) { // We match on both `ty::ImplPolarity` and `ast::ImplPolarity` just to get the `!` span. match (tcx.impl_polarity(def_id), impl_.polarity) { (ty::ImplPolarity::Positive, _) => { - check_impl(tcx, item, impl_.self_ty, &impl_.of_trait); + check_impl(tcx, item, impl_.self_ty, &impl_.of_trait, impl_.constness); } (ty::ImplPolarity::Negative, ast::ImplPolarity::Negative(span)) => { // FIXME(#27579): what amount of WF checking do we need for neg impls? @@ -1242,6 +1242,7 @@ fn check_impl<'tcx>( item: &'tcx hir::Item<'tcx>, ast_self_ty: &hir::Ty<'_>, ast_trait_ref: &Option>, + constness: hir::Constness, ) { enter_wf_checking_ctxt(tcx, item.span, item.def_id, |wfcx| { match *ast_trait_ref { @@ -1251,11 +1252,19 @@ fn check_impl<'tcx>( // won't hold). let trait_ref = tcx.impl_trait_ref(item.def_id).unwrap(); let trait_ref = wfcx.normalize(ast_trait_ref.path.span, None, trait_ref); + let trait_pred = ty::TraitPredicate { + trait_ref, + constness: match constness { + hir::Constness::Const => ty::BoundConstness::ConstIfConst, + hir::Constness::NotConst => ty::BoundConstness::NotConst, + }, + polarity: ty::ImplPolarity::Positive, + }; let obligations = traits::wf::trait_obligations( wfcx.infcx, wfcx.param_env, wfcx.body_id, - &trait_ref, + &trait_pred, ast_trait_ref.path.span, item, );