Skip to content

Commit 92344e3

Browse files
authored
Rollup merge of rust-lang#99861 - lcnr:orphan-check-cg, r=jackh726
orphan check: rationalize our handling of constants cc `@rust-lang/types` `@rust-lang/project-const-generics` on whether you agree with this reasoning. r? types
2 parents a9f3e03 + 2634309 commit 92344e3

File tree

3 files changed

+44
-1
lines changed

3 files changed

+44
-1
lines changed

Diff for: compiler/rustc_trait_selection/src/traits/coherence.rs

+15-1
Original file line numberDiff line numberDiff line change
@@ -734,7 +734,21 @@ impl<'tcx> TypeVisitor<'tcx> for OrphanChecker<'tcx> {
734734
result
735735
}
736736

737-
// FIXME: Constants should participate in orphan checking.
737+
/// All possible values for a constant parameter already exist
738+
/// in the crate defining the trait, so they are always non-local[^1].
739+
///
740+
/// Because there's no way to have an impl where the first local
741+
/// generic argument is a constant, we also don't have to fail
742+
/// the orphan check when encountering a parameter or a generic constant.
743+
///
744+
/// This means that we can completely ignore constants during the orphan check.
745+
///
746+
/// See `src/test/ui/coherence/const-generics-orphan-check-ok.rs` for examples.
747+
///
748+
/// [^1]: This might not hold for function pointers or trait objects in the future.
749+
/// As these should be quite rare as const arguments and especially rare as impl
750+
/// parameters, allowing uncovered const parameters in impls seems more useful
751+
/// than allowing `impl<T> Trait<local_fn_ptr, T> for i32` to compile.
738752
fn visit_const(&mut self, _c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
739753
ControlFlow::CONTINUE
740754
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub trait Trait<const N: usize, T> {}
+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// check-pass
2+
// aux-build:trait-with-const-param.rs
3+
extern crate trait_with_const_param;
4+
use trait_with_const_param::*;
5+
6+
// Trivial case, const param after local type.
7+
struct Local1;
8+
impl<const N: usize, T> Trait<N, T> for Local1 {}
9+
10+
// Concrete consts behave the same as foreign types,
11+
// so this also trivially works.
12+
impl Trait<3, Local1> for i32 {}
13+
14+
// This case isn't as trivial as we would forbid type
15+
// parameters here, we do allow const parameters though.
16+
//
17+
// The reason that type parameters are forbidden for
18+
// `impl<T> Trait<T, LocalInA> for i32 {}` is that another
19+
// downstream crate can add `impl<T> Trait<LocalInB, T> for i32`.
20+
// As these two impls would overlap we forbid any impls which
21+
// have a type parameter in front of a local type.
22+
//
23+
// With const parameters this issue does not exist as there are no
24+
// constants local to another downstream crate.
25+
struct Local2;
26+
impl<const N: usize> Trait<N, Local2> for i32 {}
27+
28+
fn main() {}

0 commit comments

Comments
 (0)