diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index bbc3d291e2007..fb4d675f68020 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -430,6 +430,8 @@ declare_features! ( (active, half_open_range_patterns_in_slices, "1.66.0", Some(67264), None), /// Allows `if let` guard in match arms. (active, if_let_guard, "1.47.0", Some(51114), None), + /// Allow multiple const-generic impls to unify for traits which are abstract. + (active, impl_exhaustive_const_traits, "1.65.0", Some(104806), None), /// Allows `impl Trait` to be used inside associated types (RFC 2515). (active, impl_trait_in_assoc_type, "1.70.0", Some(63063), None), /// Allows `impl Trait` as output type in `Fn` traits in return position of functions. diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 85116555fc0ec..2ea0394531488 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -653,6 +653,8 @@ pub enum ImplSource<'tcx, N> { /// Successful resolution for a builtin impl. Builtin(BuiltinImplSource, Vec), + /// Impl Source for an Abstract Const unification. + Exhaustive(Vec), } impl<'tcx, N> ImplSource<'tcx, N> { @@ -660,6 +662,7 @@ impl<'tcx, N> ImplSource<'tcx, N> { match self { ImplSource::UserDefined(i) => i.nested, ImplSource::Param(_, n) | ImplSource::Builtin(_, n) => n, + ImplSource::Exhaustive(n) => n, } } @@ -667,6 +670,7 @@ impl<'tcx, N> ImplSource<'tcx, N> { match self { ImplSource::UserDefined(i) => &i.nested, ImplSource::Param(_, n) | ImplSource::Builtin(_, n) => &n, + ImplSource::Exhaustive(n) => &n, } } @@ -674,6 +678,7 @@ impl<'tcx, N> ImplSource<'tcx, N> { match self { ImplSource::UserDefined(i) => &mut i.nested, ImplSource::Param(_, n) | ImplSource::Builtin(_, n) => n, + ImplSource::Exhaustive(ref mut n) => n, } } @@ -691,6 +696,7 @@ impl<'tcx, N> ImplSource<'tcx, N> { ImplSource::Builtin(source, n) => { ImplSource::Builtin(source, n.into_iter().map(f).collect()) } + ImplSource::Exhaustive(n) => ImplSource::Exhaustive(n.into_iter().map(f).collect()), } } } diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index a90d58f5fc17a..c26dc594c3858 100644 --- a/compiler/rustc_middle/src/traits/select.rs +++ b/compiler/rustc_middle/src/traits/select.rs @@ -167,6 +167,11 @@ pub enum SelectionCandidate<'tcx> { /// Implementation of `const Destruct`, optionally from a custom `impl const Drop`. ConstDestructCandidate(Option), + + /// Candidate which is generated for a abstract const, unifying other impls if they + /// exhaustively cover all values for a type. + /// Will never actually be used, by construction. + ExhaustiveCandidate(ty::PolyTraitPredicate<'tcx>), } /// The result of trait evaluation. The order is important diff --git a/compiler/rustc_middle/src/traits/structural_impls.rs b/compiler/rustc_middle/src/traits/structural_impls.rs index d7dc429f53b06..daafa4e80cd5f 100644 --- a/compiler/rustc_middle/src/traits/structural_impls.rs +++ b/compiler/rustc_middle/src/traits/structural_impls.rs @@ -16,6 +16,7 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSource<'tcx, N> { super::ImplSource::Param(ct, n) => { write!(f, "ImplSourceParamData({n:?}, {ct:?})") } + super::ImplSource::Exhaustive(ref n) => write!(f, "Exhaustive({:?})", n), } } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index d3739733c1d10..122e111ea3e75 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -815,6 +815,7 @@ symbols! { if_let_guard, if_while_or_patterns, ignore, + impl_exhaustive_const_traits, impl_header_lifetime_elision, impl_lint_pass, impl_trait_in_assoc_type, diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 98f458267273d..8a454452467c4 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1926,6 +1926,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // why we special case object types. false } + ImplSource::Exhaustive(..) => false, ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { .. }, _) | ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => { // These traits have no associated types. @@ -2007,6 +2008,7 @@ fn confirm_select_candidate<'cx, 'tcx>( } ImplSource::Builtin(BuiltinImplSource::Object { .. }, _) | ImplSource::Param(..) + | ImplSource::Exhaustive(..) | ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { .. }, _) | ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => { // we don't create Select candidates with this kind of resolution diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index b9f31be25b175..8e224251135e7 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -12,7 +12,7 @@ use rustc_hir as hir; use rustc_infer::traits::ObligationCause; use rustc_infer::traits::{Obligation, PolyTraitObligation, SelectionError}; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; -use rustc_middle::ty::{self, Ty, TypeVisitableExt}; +use rustc_middle::ty::{self, ConstKind, Ty, TypeVisitableExt}; use crate::traits; use crate::traits::query::evaluate_obligation::InferCtxtExt; @@ -118,6 +118,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.assemble_closure_candidates(obligation, &mut candidates); self.assemble_fn_pointer_candidates(obligation, &mut candidates); + self.assemble_candidates_from_exhaustive_impls(obligation, &mut candidates); self.assemble_candidates_from_impls(obligation, &mut candidates); self.assemble_candidates_from_object_ty(obligation, &mut candidates); } @@ -348,6 +349,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::ForLookup }; let obligation_args = obligation.predicate.skip_binder().trait_ref.args; + // disallow any adts to have recursive types in the LHS + if let ty::Adt(_, args) = obligation.predicate.skip_binder().self_ty().kind() { + if args.consts().any(|c| matches!(c.kind(), ConstKind::Expr(_))) { + return; + } + } self.tcx().for_each_relevant_impl( obligation.predicate.def_id(), obligation.predicate.skip_binder().trait_ref.self_ty(), @@ -465,6 +472,54 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } false } + /// When constructing an impl over a generic const enum (i.e. bool = { true, false }) + /// If all possible variants of an enum are implemented AND the obligation is over that + /// variant, + fn assemble_candidates_from_exhaustive_impls( + &mut self, + obligation: &PolyTraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) { + if !self.tcx().features().impl_exhaustive_const_traits { + return; + } + + // see note in `assemble_candidates_from_impls`. + if obligation.predicate.references_error() { + return; + } + + // note: ow = otherwise + // - check if trait has abstract const argument(s) which is (are) enum or bool, ow return + // - check if trait enum is non-exhaustive, ow return + // - construct required set of possible combinations, with false unless present + // for each relevant trait + // - check if is same trait + // - set combo as present + // If all required sets are present, add candidate impl generic over all combinations. + + let query = obligation.predicate.skip_binder().self_ty(); + let ty::Adt(_adt_def, adt_substs) = query.kind() else { + return; + }; + + let Some(ct) = adt_substs + .consts() + .filter(|ct| { + matches!(ct.kind(), ty::ConstKind::Unevaluated(..) | ty::ConstKind::Param(_)) + }) + .next() + else { + return; + }; + + // explicitly gate certain types which are exhaustive + if !super::exhaustive_types(self.tcx(), ct.ty(), |_| {}) { + return; + } + + candidates.vec.push(ExhaustiveCandidate(obligation.predicate)); + } fn assemble_candidates_from_auto_impls( &mut self, diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 7140fedb74a3e..1957f14a66963 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -14,7 +14,7 @@ use rustc_infer::infer::{DefineOpaqueTypes, InferOk}; use rustc_middle::traits::{BuiltinImplSource, SelectionOutputTypeParameterMismatch}; use rustc_middle::ty::{ self, GenericArgs, GenericArgsRef, GenericParamDefKind, ToPolyTraitRef, ToPredicate, - TraitPredicate, Ty, TyCtxt, TypeVisitableExt, + TraitPredicate, TraitRef, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeVisitableExt, }; use rustc_span::def_id::DefId; @@ -120,6 +120,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let data = self.confirm_const_destruct_candidate(obligation, def_id)?; ImplSource::Builtin(BuiltinImplSource::Misc, data) } + ExhaustiveCandidate(candidate) => { + let obligations = self.confirm_exhaustive_candidate(obligation, candidate); + ImplSource::Exhaustive(obligations) + } }; // The obligations returned by confirmation are recursively evaluated @@ -1360,4 +1364,75 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(nested) } + + /// Generates obligations for a lazy candidate + /// Where the obligations generated are all possible values for the type of a + /// `ConstKind::Unevaluated(..)`. + /// In the future, it would be nice to extend this to inductive proofs. + #[allow(unused_variables, unused_mut, dead_code)] + fn confirm_exhaustive_candidate( + &mut self, + obligation: &PolyTraitObligation<'tcx>, + candidate: ty::PolyTraitPredicate<'tcx>, + ) -> Vec> { + let mut obligations = vec![]; + let tcx = self.tcx(); + + let query = obligation.predicate.skip_binder().trait_ref.self_ty(); + let ty::Adt(_adt_def, adt_substs) = query.kind() else { + return obligations; + }; + // Find one adt subst at a time, then will be handled recursively. + let const_to_replace = adt_substs + .consts() + .find(|ct| { + matches!(ct.kind(), ty::ConstKind::Unevaluated(..) | ty::ConstKind::Param(_)) + }) + .unwrap(); + let is_exhaustive = super::exhaustive_types(tcx, const_to_replace.ty(), |val| { + let predicate = candidate.map_bound(|pt_ref| { + let query = pt_ref.self_ty(); + let mut folder = Folder { tcx, replace: const_to_replace, with: val }; + let mut new_poly_trait_ref = pt_ref.clone(); + new_poly_trait_ref.trait_ref = TraitRef::new( + tcx, + pt_ref.trait_ref.def_id, + [query.fold_with(&mut folder).into()] + .into_iter() + .chain(pt_ref.trait_ref.args.iter().skip(1)), + ); + new_poly_trait_ref + }); + + let ob = Obligation::new( + self.tcx(), + obligation.cause.clone(), + obligation.param_env, + predicate, + ); + obligations.push(ob); + }); + + // should only allow exhaustive types in + // candidate_assembly::assemble_candidates_from_exhaustive_impls + assert!(is_exhaustive); + + obligations + } +} + +/// Folder for replacing specific const values in `substs`. +struct Folder<'tcx> { + tcx: TyCtxt<'tcx>, + replace: ty::Const<'tcx>, + with: ty::Const<'tcx>, +} + +impl<'tcx> TypeFolder> for Folder<'tcx> { + fn interner(&self) -> TyCtxt<'tcx> { + self.tcx + } + fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> { + if c == self.replace { self.with } else { c } + } } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index c29696bc817f7..f4ed0aa267bbd 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1806,6 +1806,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> { // This is a fix for #53123 and prevents winnowing from accidentally extending the // lifetime of a variable. match (&other.candidate, &victim.candidate) { + (_, ExhaustiveCandidate(..)) => DropVictim::Yes, + (ExhaustiveCandidate(..), _) => DropVictim::No, // FIXME(@jswrenn): this should probably be more sophisticated (TransmutabilityCandidate, _) | (_, TransmutabilityCandidate) => DropVictim::No, @@ -2604,6 +2606,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { assert_eq!(predicates.parent, None); let predicates = predicates.instantiate_own(tcx, args); let mut obligations = Vec::with_capacity(predicates.len()); + for (index, (predicate, span)) in predicates.into_iter().enumerate() { let cause = if Some(parent_trait_pred.def_id()) == tcx.lang_items().coerce_unsized_trait() { @@ -2999,3 +3002,52 @@ fn bind_generator_hidden_types_above<'tcx>( )); ty::Binder::bind_with_vars(hidden_types, bound_vars) } + +// For a given type, will run a function over all constants for that type if permitted. +// returns false if not permitted. Callers should not rely on the order. +fn exhaustive_types<'tcx>( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + mut f: impl FnMut(ty::Const<'tcx>), +) -> bool { + use std::mem::transmute; + match ty.kind() { + ty::Bool => { + for v in [true, false].into_iter() { + f(ty::Const::from_bool(tcx, v)); + } + } + // Should always compile, as this is never instantiable + ty::Never => {} + ty::Adt(adt_def, _substs) => { + if adt_def.is_payloadfree() { + return true; + } + if adt_def.is_variant_list_non_exhaustive() { + return false; + } + + // FIXME(julianknodt): here need to create constants for each variant + return false; + } + + ty::Int(ty::IntTy::I8) => { + for v in -128i8..127i8 { + let c = ty::Const::from_bits( + tcx, + unsafe { transmute(v as i128) }, + ty::ParamEnv::empty().and(ty), + ); + f(c); + } + } + ty::Uint(ty::UintTy::U8) => { + for v in 0u8..=255u8 { + let c = ty::Const::from_bits(tcx, v as u128, ty::ParamEnv::empty().and(ty)); + f(c); + } + } + _ => return false, + } + true +} diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index a21b5ef05e60b..4d8e0083ca399 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -295,6 +295,7 @@ fn resolve_associated_item<'tcx>( } traits::ImplSource::Param(..) | traits::ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { .. }, _) + | traits::ImplSource::Exhaustive(..) | traits::ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => None, }) } diff --git a/tests/ui/const-generics/bool_cond.normal.stderr b/tests/ui/const-generics/bool_cond.normal.stderr new file mode 100644 index 0000000000000..87915c1b790cc --- /dev/null +++ b/tests/ui/const-generics/bool_cond.normal.stderr @@ -0,0 +1,31 @@ +error[E0277]: the trait bound `ConstOption: Default` is not satisfied + --> $DIR/bool_cond.rs:42:5 + | +LL | #[derive(Default)] + | ------- in this derive macro expansion +... +LL | _a: ConstOption, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Default` is not implemented for `ConstOption` + | + = help: the following other types implement trait `Default`: + ConstOption + ConstOption + = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `ConstOption: Default` is not satisfied + --> $DIR/bool_cond.rs:44:5 + | +LL | #[derive(Default)] + | ------- in this derive macro expansion +... +LL | _b: ConstOption, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Default` is not implemented for `ConstOption` + | + = help: the following other types implement trait `Default`: + ConstOption + ConstOption + = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/const-generics/bool_cond.rs b/tests/ui/const-generics/bool_cond.rs new file mode 100644 index 0000000000000..4abe6e99a5db8 --- /dev/null +++ b/tests/ui/const-generics/bool_cond.rs @@ -0,0 +1,50 @@ +// gate-test-impl_exhaustive_const_traits +// [unified] run-pass +// revisions: unified normal +#![feature(generic_const_exprs)] +#![cfg_attr(unified, feature(impl_exhaustive_const_traits))] +#![allow(incomplete_features)] + +pub const fn bool_to_usize(b: bool) -> usize { + b as usize +} + +pub struct ConstOption where [T; bool_to_usize(S)]:, { + _v: [T; bool_to_usize(S)] +} + +impl Default for ConstOption { + fn default() -> Self { + Self { + _v: [T::default()] + } + } +} + +impl Default for ConstOption { + fn default() -> Self { + Self { + _v: [], + } + } +} + +fn _test_func() where ConstOption= 5}>: Default, + [usize; bool_to_usize(N >= 5)]: { + +} + +#[derive(Default)] +pub struct Arg where + [(); bool_to_usize(N <= 0)]:, [(); bool_to_usize(N <= 1)]:, + [(); bool_to_usize(N <= 5)]:, [(); bool_to_usize(N > 3)]:, + { + _a: ConstOption, + //[normal]~^ ERROR: the trait + _b: ConstOption, + //[normal]~^ ERROR: the trait +} + +fn main() { + let _def = Arg::<2>::default(); +} diff --git a/tests/ui/const-generics/bool_must_be_exhaustive.rs b/tests/ui/const-generics/bool_must_be_exhaustive.rs new file mode 100644 index 0000000000000..bc79dcae62fd7 --- /dev/null +++ b/tests/ui/const-generics/bool_must_be_exhaustive.rs @@ -0,0 +1,36 @@ +#![feature(generic_const_exprs)] +#![feature(impl_exhaustive_const_traits)] +#![allow(incomplete_features)] + +pub const fn bool_to_usize(b: bool) -> usize { + b as usize +} + +pub struct ConstOption where [T; bool_to_usize(S)]:, { + _v: [T; bool_to_usize(S)] +} + +impl Default for ConstOption { + fn default() -> Self { + Self { + _v: [T::default()] + } + } +} + +fn _test_func() where ConstOption= 5}>: Default, + [usize; bool_to_usize(N >= 5)]: { + +} + +#[derive(Default)] +pub struct Arg where [(); bool_to_usize(N <= 0)]:, [(); bool_to_usize(N <= 1)]:, { + _a: ConstOption, + //~^ ERROR trait bound + _b: ConstOption, + //~^ ERROR trait bound +} + +fn main() { + let _def = Arg::<2>::default(); +} diff --git a/tests/ui/const-generics/bool_must_be_exhaustive.stderr b/tests/ui/const-generics/bool_must_be_exhaustive.stderr new file mode 100644 index 0000000000000..c6aea4351ec08 --- /dev/null +++ b/tests/ui/const-generics/bool_must_be_exhaustive.stderr @@ -0,0 +1,27 @@ +error[E0277]: the trait bound `ConstOption: Default` is not satisfied + --> $DIR/bool_must_be_exhaustive.rs:28:5 + | +LL | #[derive(Default)] + | ------- in this derive macro expansion +LL | pub struct Arg where [(); bool_to_usize(N <= 0)]:, [(); bool_to_usize(N <= 1)]:, { +LL | _a: ConstOption, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Default` is not implemented for `ConstOption` + | + = help: the trait `Default` is implemented for `ConstOption` + = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `ConstOption: Default` is not satisfied + --> $DIR/bool_must_be_exhaustive.rs:30:5 + | +LL | #[derive(Default)] + | ------- in this derive macro expansion +... +LL | _b: ConstOption, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Default` is not implemented for `ConstOption` + | + = help: the trait `Default` is implemented for `ConstOption` + = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/const-generics/double_bool_cond.normal.stderr b/tests/ui/const-generics/double_bool_cond.normal.stderr new file mode 100644 index 0000000000000..f0cb3f76ecc3f --- /dev/null +++ b/tests/ui/const-generics/double_bool_cond.normal.stderr @@ -0,0 +1,24 @@ +error[E0277]: the trait bound `ConstTwo<{ N <= 5 }, {N > 3}>: Default` is not satisfied + --> $DIR/double_bool_cond.rs:30:5 + | +LL | #[derive(Default)] + | ------- in this derive macro expansion +... +LL | _c: ConstTwo<{ N <= 5 }, {N > 3}>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Default` is not implemented for `ConstTwo<{ N <= 5 }, {N > 3}>` + | + = help: the following other types implement trait `Default`: + ConstTwo + ConstTwo + ConstTwo + ConstTwo + = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider annotating `ConstTwo<{ N <= 5 }, {N > 3}>` with `#[derive(Default)]` + | +LL + #[derive(Default)] +LL | pub struct ConstTwo; + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/const-generics/double_bool_cond.rs b/tests/ui/const-generics/double_bool_cond.rs new file mode 100644 index 0000000000000..c4c51318ce924 --- /dev/null +++ b/tests/ui/const-generics/double_bool_cond.rs @@ -0,0 +1,36 @@ +// [unified] run-pass +// revisions: unified normal +#![feature(generic_const_exprs)] +#![cfg_attr(unified, feature(impl_exhaustive_const_traits))] +#![allow(incomplete_features)] + +pub const fn bool_to_usize(b: bool) -> usize { + b as usize +} + +pub struct ConstTwo; + +impl Default for ConstTwo { + fn default() -> Self { Self } +} +impl Default for ConstTwo { + fn default() -> Self { Self } +} +impl Default for ConstTwo { + fn default() -> Self { Self } +} +impl Default for ConstTwo { + fn default() -> Self { Self } +} + +#[derive(Default)] +pub struct Arg where + [(); bool_to_usize(N <= 5)]:, [(); bool_to_usize(N > 3)]:, + { + _c: ConstTwo<{ N <= 5 }, {N > 3}>, + //[normal]~^ ERROR: the trait +} + +fn main() { + let _def = Arg::<2>::default(); +} diff --git a/tests/ui/const-generics/inductive.rs b/tests/ui/const-generics/inductive.rs new file mode 100644 index 0000000000000..477b5758b44e1 --- /dev/null +++ b/tests/ui/const-generics/inductive.rs @@ -0,0 +1,14 @@ +// check-fail +#![allow(incomplete_features)] +#![feature(impl_exhaustive_const_traits)] +#![feature(generic_const_exprs)] + +trait Dot {} + +struct Mat; + +impl Dot for Mat<0> {} +impl Dot for Mat where Mat<{N-1}>: Dot {} +//~^ ERROR: evaluation of + +fn main() {} diff --git a/tests/ui/const-generics/inductive.stderr b/tests/ui/const-generics/inductive.stderr new file mode 100644 index 0000000000000..372d3ab87d55c --- /dev/null +++ b/tests/ui/const-generics/inductive.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of ` as Dot>::{constant#0}` failed + --> $DIR/inductive.rs:11:48 + | +LL | impl Dot for Mat where Mat<{N-1}>: Dot {} + | ^^^ attempt to compute `0_usize - 1_usize`, which would overflow + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/const-generics/int_must_be_exhaustive.rs b/tests/ui/const-generics/int_must_be_exhaustive.rs new file mode 100644 index 0000000000000..3d83a7f7052b1 --- /dev/null +++ b/tests/ui/const-generics/int_must_be_exhaustive.rs @@ -0,0 +1,46 @@ +// check-pass +#![feature(generic_const_exprs)] +#![feature(impl_exhaustive_const_traits)] +#![allow(incomplete_features)] + +struct Val {} + +macro_rules! u8_impl { + ($( $v: expr ),*) => { + $( + impl Default for Val<$v> { + fn default() -> Self { Self {} } + } + )* + } +} + +u8_impl!( + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, + 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, + 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, + 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, + 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, + 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 +); + +pub const fn wrapping_u8_add(v: u8) -> u8 { + v.wrapping_add(1) +} + +#[derive(Default)] +struct Example { + v: Val, +} + +fn main() {} diff --git a/tests/ui/const-generics/unified_with_assoc.rs b/tests/ui/const-generics/unified_with_assoc.rs new file mode 100644 index 0000000000000..7810768617434 --- /dev/null +++ b/tests/ui/const-generics/unified_with_assoc.rs @@ -0,0 +1,27 @@ +#![feature(generic_const_exprs)] +#![feature(impl_exhaustive_const_traits)] +#![allow(incomplete_features)] + +pub trait WithAssoc { + const VAL: usize; + type Item; +} + +pub struct Demo; + +impl WithAssoc for Demo { + const VAL: usize = 3; + type Item = usize; +} +impl WithAssoc for Demo { + const VAL: usize = 5; + type Item = String; +} +fn demo_func() where Demo<{ N > 5 }>: WithAssoc, + [();Demo::<{N>5}>::VAL]:, + //~^ ERROR cycle detected + { + let _ = [0; Demo::<{N>5}>::VAL]; +} + +fn main() {} diff --git a/tests/ui/const-generics/unified_with_assoc.stderr b/tests/ui/const-generics/unified_with_assoc.stderr new file mode 100644 index 0000000000000..9aa8608e1d205 --- /dev/null +++ b/tests/ui/const-generics/unified_with_assoc.stderr @@ -0,0 +1,28 @@ +error[E0391]: cycle detected when building an abstract representation for `demo_func::{constant#1}` + --> $DIR/unified_with_assoc.rs:21:7 + | +LL | [();Demo::<{N>5}>::VAL]:, + | ^^^^^^^^^^^^^^^^^^ + | +note: ...which requires building THIR for `demo_func::{constant#1}`... + --> $DIR/unified_with_assoc.rs:21:7 + | +LL | [();Demo::<{N>5}>::VAL]:, + | ^^^^^^^^^^^^^^^^^^ +note: ...which requires type-checking `demo_func::{constant#1}`... + --> $DIR/unified_with_assoc.rs:21:7 + | +LL | [();Demo::<{N>5}>::VAL]:, + | ^^^^^^^^^^^^^^^^^^ + = note: ...which again requires building an abstract representation for `demo_func::{constant#1}`, completing the cycle +note: cycle used when checking that `demo_func` is well-formed + --> $DIR/unified_with_assoc.rs:20:1 + | +LL | / fn demo_func() where Demo<{ N > 5 }>: WithAssoc, +LL | | [();Demo::<{N>5}>::VAL]:, + | |___________________________^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0391`.