From c9b21b0ea22d6caa1d0caa9e68ee22f72729229d Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 28 Jul 2022 17:30:39 +0200 Subject: [PATCH 1/2] orphan check: remove const generics fixme --- .../src/traits/coherence.rs | 11 +++++++- .../auxiliary/trait-with-const-param.rs | 1 + .../const-generics-orphan-check-ok.rs | 28 +++++++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/coherence/auxiliary/trait-with-const-param.rs create mode 100644 src/test/ui/coherence/const-generics-orphan-check-ok.rs diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index fa94aa19abda5..da17a9c3da6b5 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -746,8 +746,17 @@ impl<'tcx> TypeVisitor<'tcx> for OrphanChecker<'tcx> { result } - // FIXME: Constants should participate in orphan checking. fn visit_const(&mut self, _c: ty::Const<'tcx>) -> ControlFlow { + // All possible values for a constant parameter already exist + // in the crate defining the trait, so they are always non-local. + // + // Because there's no way to have an impl where the first local + // generic argument is a constant, we also don't have to fail + // the orphan check when encountering a parameter or a generic constant. + // + // This means that we can completely ignore constants during the orphan check. + // + // See `src/test/ui/coherence/const-generics-orphan-check-ok.rs` for examples. ControlFlow::CONTINUE } } diff --git a/src/test/ui/coherence/auxiliary/trait-with-const-param.rs b/src/test/ui/coherence/auxiliary/trait-with-const-param.rs new file mode 100644 index 0000000000000..a44eb14f8e4cf --- /dev/null +++ b/src/test/ui/coherence/auxiliary/trait-with-const-param.rs @@ -0,0 +1 @@ +pub trait Trait {} diff --git a/src/test/ui/coherence/const-generics-orphan-check-ok.rs b/src/test/ui/coherence/const-generics-orphan-check-ok.rs new file mode 100644 index 0000000000000..217e8aed234b1 --- /dev/null +++ b/src/test/ui/coherence/const-generics-orphan-check-ok.rs @@ -0,0 +1,28 @@ +// check-pass +// aux-build:trait-with-const-param.rs +extern crate trait_with_const_param; +use trait_with_const_param::*; + +// Trivial case, const param after local type. +struct Local1; +impl Trait for Local1 {} + +// Concrete consts behave the same as foreign types, +// so this also trivially works. +impl Trait<3, Local1> for i32 {} + +// This case isn't as trivial as we would forbid type +// parameters here, we do allow const parameters though. +// +// The reason that type parameters are forbidden for +// `impl Trait for i32 {}` is that another +// downstream crate can add `impl Trait for i32`. +// As these two impls would overlap we forbid any impls which +// have a type parameter in front of a local type. +// +// With const parameters this issue does not exist as there are no +// constants local to another downstream crate. +struct Local2; +impl Trait for i32 {} + +fn main() {} From 2634309eb39b5af7b1d26a3656079efc0b9340d1 Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 29 Jul 2022 09:43:22 +0200 Subject: [PATCH 2/2] update comment --- .../src/traits/coherence.rs | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index da17a9c3da6b5..337fbb2c15e3a 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -746,17 +746,22 @@ impl<'tcx> TypeVisitor<'tcx> for OrphanChecker<'tcx> { result } + /// All possible values for a constant parameter already exist + /// in the crate defining the trait, so they are always non-local[^1]. + /// + /// Because there's no way to have an impl where the first local + /// generic argument is a constant, we also don't have to fail + /// the orphan check when encountering a parameter or a generic constant. + /// + /// This means that we can completely ignore constants during the orphan check. + /// + /// See `src/test/ui/coherence/const-generics-orphan-check-ok.rs` for examples. + /// + /// [^1]: This might not hold for function pointers or trait objects in the future. + /// As these should be quite rare as const arguments and especially rare as impl + /// parameters, allowing uncovered const parameters in impls seems more useful + /// than allowing `impl Trait for i32` to compile. fn visit_const(&mut self, _c: ty::Const<'tcx>) -> ControlFlow { - // All possible values for a constant parameter already exist - // in the crate defining the trait, so they are always non-local. - // - // Because there's no way to have an impl where the first local - // generic argument is a constant, we also don't have to fail - // the orphan check when encountering a parameter or a generic constant. - // - // This means that we can completely ignore constants during the orphan check. - // - // See `src/test/ui/coherence/const-generics-orphan-check-ok.rs` for examples. ControlFlow::CONTINUE } }