diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 5831636a81b2c..7b11be8d754dc 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -464,6 +464,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { check_incompatible_features(sess, features); check_dependent_features(sess, features); check_new_solver_banned_features(sess, features); + check_features_requiring_new_solver(sess, features); let mut visitor = PostExpansionVisitor { sess, features }; @@ -738,3 +739,25 @@ fn check_new_solver_banned_features(sess: &Session, features: &Features) { }); } } + +fn check_features_requiring_new_solver(sess: &Session, features: &Features) { + if sess.opts.unstable_opts.next_solver.globally { + return; + } + + // Require the new solver with GCA, because the old solver can't implement GCA correctly as it + // does not support normalization obligations for free and inherent consts. + if let Some(gca_span) = features + .enabled_lang_features() + .iter() + .find(|feat| feat.gate_name == sym::generic_const_args) + .map(|feat| feat.attr_sp) + { + #[allow(rustc::symbol_intern_string_literal)] + sess.dcx().emit_err(errors::MissingDependentFeatures { + parent_span: gca_span, + parent: sym::generic_const_exprs, + missing: String::from("-Znext-solver=globally"), + }); + } +} diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index a43e373415ab7..324de1f9f707e 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -3041,7 +3041,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span: Span, ) -> Result<(), ErrorGuaranteed> { let tcx = self.tcx(); - if tcx.is_type_const(def_id) { + // FIXME(gca): Intentionally disallowing paths to inherent associated non-type constants + // until a refactoring for how generic args for IACs are represented has been landed. + let is_inherent_assoc_const = tcx.def_kind(def_id) + == DefKind::AssocConst { is_type_const: false } + && tcx.def_kind(tcx.parent(def_id)) == DefKind::Impl { of_trait: false }; + if tcx.is_type_const(def_id) + || tcx.features().generic_const_args() && !is_inherent_assoc_const + { Ok(()) } else { let mut err = self.dcx().struct_span_err( diff --git a/compiler/rustc_middle/src/ty/context/impl_interner.rs b/compiler/rustc_middle/src/ty/context/impl_interner.rs index ccda7aeb910ca..a16c06a369661 100644 --- a/compiler/rustc_middle/src/ty/context/impl_interner.rs +++ b/compiler/rustc_middle/src/ty/context/impl_interner.rs @@ -177,6 +177,9 @@ impl<'tcx> Interner for TyCtxt<'tcx> { fn type_of_opaque_hir_typeck(self, def_id: LocalDefId) -> ty::EarlyBinder<'tcx, Ty<'tcx>> { self.type_of_opaque_hir_typeck(def_id) } + fn is_type_const(self, def_id: DefId) -> bool { + self.is_type_const(def_id) + } fn const_of_item(self, def_id: DefId) -> ty::EarlyBinder<'tcx, Const<'tcx>> { self.const_of_item(def_id) } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index e224febd3c927..d9a7c1c8c4272 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -1168,6 +1168,40 @@ where self.delegate.evaluate_const(param_env, uv) } + pub(super) fn evaluate_const_and_instantiate_normalizes_to_term( + &mut self, + goal: Goal>, + uv: ty::UnevaluatedConst, + ) -> QueryResult { + match self.evaluate_const(goal.param_env, uv) { + Some(evaluated) => { + self.instantiate_normalizes_to_term(goal, evaluated.into()); + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } + None => { + // HACK(khyperia): calling `resolve_vars_if_possible` here shouldn't be necessary, + // `try_evaluate_const` calls `resolve_vars_if_possible` already. However, we want + // to check `has_non_region_infer` against the type with vars resolved (i.e. check + // if there are vars we failed to resolve), so we need to call it again here. + // Perhaps we could split EvaluateConstErr::HasGenericsOrInfers into HasGenerics and + // HasInfers or something, make evaluate_const return that, and make this branch be + // based on that, rather than checking `has_non_region_infer`. + if self.resolve_vars_if_possible(uv).has_non_region_infer() { + self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) + } else { + // We do not instantiate to the `uv` passed in, but rather + // `goal.predicate.alias`. The `uv` passed in might correspond to the `impl` + // form of a constant (with generic arguments corresponding to the impl block), + // however, we want to structurally instantiate to the original, non-rebased, + // trait `Self` form of the constant (with generic arguments being the trait + // `Self` type). + self.structurally_instantiate_normalizes_to_term(goal, goal.predicate.alias); + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } + } + } + } + pub(super) fn is_transmutable( &mut self, src: I::Ty, diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs index b3703639d99ef..2941f93e42bb0 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs @@ -14,17 +14,23 @@ where &mut self, goal: Goal>, ) -> QueryResult { - if let Some(normalized_const) = self.evaluate_const( - goal.param_env, - ty::UnevaluatedConst::new( - goal.predicate.alias.def_id().try_into().unwrap(), - goal.predicate.alias.args, - ), - ) { - self.instantiate_normalizes_to_term(goal, normalized_const.into()); - self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + let cx = self.cx(); + let uv = goal.predicate.alias.expect_ct(self.cx()); + // keep legacy behavior for array repeat expressions: + // when a constant is too generic to be evaluated, the legacy behavior is to return + // Ambiguous, whereas evaluate_const_and_instantiate_normalizes_to_term structurally + // instantiates to itself and returns Yes (if there are no inference variables) + let is_repeat_expr = + cx.anon_const_kind(uv.def.into()) == ty::AnonConstKind::RepeatExprCount; + if is_repeat_expr { + if let Some(normalized_const) = self.evaluate_const(goal.param_env, uv) { + self.instantiate_normalizes_to_term(goal, normalized_const.into()); + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } else { + self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) + } } else { - self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) + self.evaluate_const_and_instantiate_normalizes_to_term(goal, uv) } } } diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs index f3004e4c8105b..44fe2913b73de 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs @@ -30,13 +30,20 @@ where .map(|pred| goal.with(cx, pred)), ); - let actual = if free_alias.kind(cx).is_type() { - cx.type_of(free_alias.def_id()).instantiate(cx, free_alias.args).skip_norm_wip().into() - } else { - cx.const_of_item(free_alias.def_id()) - .instantiate(cx, free_alias.args) - .skip_norm_wip() - .into() + let actual = match free_alias.kind(cx) { + ty::AliasTermKind::FreeTy { def_id } => { + cx.type_of(def_id).instantiate(cx, free_alias.args).skip_norm_wip().into() + } + ty::AliasTermKind::FreeConst { def_id } if cx.is_type_const(def_id) => { + cx.const_of_item(def_id).instantiate(cx, free_alias.args).skip_norm_wip().into() + } + ty::AliasTermKind::FreeConst { .. } => { + return self.evaluate_const_and_instantiate_normalizes_to_term( + goal, + free_alias.expect_ct(cx), + ); + } + kind => panic!("expected free alias, found {kind:?}"), }; self.instantiate_normalizes_to_term(goal, actual); diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs index 4d62407fe2995..00b5fd7fdcbce 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs @@ -52,13 +52,23 @@ where .map(|pred| goal.with(cx, pred)), ); - let normalized = if inherent.kind(cx).is_type() { - cx.type_of(inherent.def_id()).instantiate(cx, inherent_args).skip_norm_wip().into() - } else { - cx.const_of_item(inherent.def_id()) - .instantiate(cx, inherent_args) - .skip_norm_wip() - .into() + let normalized = match inherent.kind(cx) { + ty::AliasTermKind::InherentTy { def_id } => { + cx.type_of(def_id).instantiate(cx, inherent_args).skip_norm_wip().into() + } + ty::AliasTermKind::InherentConst { def_id } if cx.is_type_const(def_id) => { + cx.const_of_item(def_id).instantiate(cx, inherent_args).skip_norm_wip().into() + } + ty::AliasTermKind::InherentConst { .. } => { + // FIXME(gca): This is dead code at the moment. It should eventually call + // self.evaluate_const like projected consts do in consider_impl_candidate in + // normalizes_to/mod.rs. However, how generic args are represented for IACs is up in + // the air right now. + // Will self.evaluate_const eventually take the inherent_args or the impl_args form + // of args? It might be either. + panic!("References to inherent associated consts should have been blocked"); + } + kind => panic!("expected inherent alias, found {kind:?}"), }; self.instantiate_normalizes_to_term(goal, normalized); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index 1d74f1efe9136..4a77662bf11ea 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -384,19 +384,30 @@ where // Finally we construct the actual value of the associated type. let term = match goal.predicate.alias.kind(cx) { - ty::AliasTermKind::ProjectionTy { .. } => { - cx.type_of(target_item_def_id).map_bound(|ty| ty.into()) + ty::AliasTermKind::ProjectionTy { .. } => cx + .type_of(target_item_def_id) + .instantiate(cx, target_args) + .skip_norm_wip() + .into(), + ty::AliasTermKind::ProjectionConst { .. } + if cx.is_type_const(target_item_def_id) => + { + cx.const_of_item(target_item_def_id) + .instantiate(cx, target_args) + .skip_norm_wip() + .into() } ty::AliasTermKind::ProjectionConst { .. } => { - cx.const_of_item(target_item_def_id).map_bound(|ct| ct.into()) + let uv = ty::UnevaluatedConst::new( + target_item_def_id.try_into().unwrap(), + target_args, + ); + return ecx.evaluate_const_and_instantiate_normalizes_to_term(goal, uv); } kind => panic!("expected projection, found {kind:?}"), }; - ecx.instantiate_normalizes_to_term( - goal, - term.instantiate(cx, target_args).skip_norm_wip(), - ); + ecx.instantiate_normalizes_to_term(goal, term); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 0196b8bee7cca..a4be589172f6f 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -696,7 +696,10 @@ pub fn try_evaluate_const<'tcx>( // logic does not go through type system normalization. If it did this would // be a backwards compatibility problem as we do not enforce "syntactic" non- // usage of generic parameters like we do here. - if uv.args.has_non_region_param() || uv.args.has_non_region_infer() { + if uv.args.has_non_region_param() + || uv.args.has_non_region_infer() + || uv.args.has_non_region_placeholders() + { return Err(EvaluateConstErr::HasGenericsOrInfers); } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 66a2fcaa562d1..258eed52e167b 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -1060,7 +1060,7 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { ty::ConstKind::Unevaluated(uv) => { if !c.has_escaping_bound_vars() { // Skip type consts as mGCA doesn't support evaluatable clauses - if !tcx.is_type_const(uv.def) { + if !tcx.is_type_const(uv.def) && !tcx.features().generic_const_args() { let predicate = ty::Binder::dummy(ty::PredicateKind::Clause( ty::ClauseKind::ConstEvaluatable(c), )); diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index f350e5da9654c..1ef1a40479197 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -205,6 +205,7 @@ pub trait Interner: fn type_of(self, def_id: Self::DefId) -> ty::EarlyBinder; fn type_of_opaque_hir_typeck(self, def_id: Self::LocalDefId) -> ty::EarlyBinder; + fn is_type_const(self, def_id: Self::DefId) -> bool; fn const_of_item(self, def_id: Self::DefId) -> ty::EarlyBinder; fn anon_const_kind(self, def_id: Self::DefId) -> ty::AnonConstKind; diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index 0545fbfda6e41..7a48cfb23d6a2 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -732,16 +732,32 @@ impl AliasTerm { AliasTermKind::InherentTy { def_id } => AliasTyKind::Inherent { def_id }, AliasTermKind::OpaqueTy { def_id } => AliasTyKind::Opaque { def_id }, AliasTermKind::FreeTy { def_id } => AliasTyKind::Free { def_id }, - AliasTermKind::InherentConst { .. } + kind @ (AliasTermKind::InherentConst { .. } | AliasTermKind::FreeConst { .. } | AliasTermKind::UnevaluatedConst { .. } - | AliasTermKind::ProjectionConst { .. } => { - panic!("Cannot turn `UnevaluatedConst` into `AliasTy`") + | AliasTermKind::ProjectionConst { .. }) => { + panic!("Cannot turn `{}` into `AliasTy`", kind.descr()) } }; ty::AliasTy { kind, args: self.args, _use_alias_ty_new_instead: () } } + pub fn expect_ct(self, interner: I) -> ty::UnevaluatedConst { + let def_id = match self.kind(interner) { + AliasTermKind::InherentConst { def_id } + | AliasTermKind::FreeConst { def_id } + | AliasTermKind::UnevaluatedConst { def_id } + | AliasTermKind::ProjectionConst { def_id } => def_id, + kind @ (AliasTermKind::ProjectionTy { .. } + | AliasTermKind::InherentTy { .. } + | AliasTermKind::OpaqueTy { .. } + | AliasTermKind::FreeTy { .. }) => { + panic!("Cannot turn `{}` into `UnevaluatedConst`", kind.descr()) + } + }; + ty::UnevaluatedConst { def: def_id.try_into().unwrap(), args: self.args } + } + // FIXME: remove this function (access the field instead) pub fn kind(self, _interner: I) -> AliasTermKind { self.kind diff --git a/src/doc/rustc-dev-guide/src/feature-gate-check.md b/src/doc/rustc-dev-guide/src/feature-gate-check.md index 038a14ac070e1..0b4fc0cd680c0 100644 --- a/src/doc/rustc-dev-guide/src/feature-gate-check.md +++ b/src/doc/rustc-dev-guide/src/feature-gate-check.md @@ -69,6 +69,8 @@ in `check_crate` and its AST visitor. (declared in `rustc_feature::INCOMPATIBLE_FEATURES`) are not used together. - `check_new_solver_banned_features`: Bans features incompatible with compiler mode for the next trait solver. +- `check_features_requiring_new_solver`: Requires the new trait solver for + features incompatible with the old solver. - **Parser-gated spans**: Processes the `GatedSpans` recorded during parsing (see [Checking `GatedSpans`](#checking-gatedspans)). diff --git a/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.next.stderr b/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.next.stderr new file mode 100644 index 0000000000000..ea9f0bb2d1302 --- /dev/null +++ b/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.next.stderr @@ -0,0 +1,48 @@ +error[E0284]: type annotations needed for `([(); _], [(); 10])` + --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:29:9 + | +LL | let (mut arr, mut arr_with_weird_len) = free(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------ type must be known at this point + | +note: required by a const generic parameter in `free` + --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:24:9 + | +LL | fn free() -> ([(); N], [(); FREE::]) { + | ^^^^^^^^^^^^^^ required by this const generic parameter in `free` +help: consider giving this pattern a type, where the value of const parameter `N` is specified + | +LL | let (mut arr, mut arr_with_weird_len): ([_; N], _) = free(); + | +++++++++++++ + +error[E0271]: type mismatch resolving `2 == 10` + --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:35:45 + | +LL | let (mut arr, mut arr_with_weird_len) = free(); + | ^^^^^^ types differ + +error[E0284]: type annotations needed for `([(); _], [(); 10])` + --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:46:9 + | +LL | let (mut arr, mut arr_with_weird_len) = proj(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------ type must be known at this point + | +note: required by a const generic parameter in `proj` + --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:41:9 + | +LL | fn proj() -> ([(); N], [(); ::PROJ::]) { + | ^^^^^^^^^^^^^^ required by this const generic parameter in `proj` +help: consider giving this pattern a type, where the value of const parameter `N` is specified + | +LL | let (mut arr, mut arr_with_weird_len): ([_; N], _) = proj(); + | +++++++++++++ + +error[E0271]: type mismatch resolving `2 == 10` + --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:52:45 + | +LL | let (mut arr, mut arr_with_weird_len) = proj(); + | ^^^^^^ types differ + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0271, E0284. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.old.stderr b/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.old.stderr new file mode 100644 index 0000000000000..cf0d305696b40 --- /dev/null +++ b/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.old.stderr @@ -0,0 +1,10 @@ +error: `generic_const_exprs` requires -Znext-solver=globally to be enabled + --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:9:12 + | +LL | #![feature(generic_const_args)] + | ^^^^^^^^^^^^^^^^^^ + | + = help: enable all of these features + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.rs b/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.rs new file mode 100644 index 0000000000000..dce9feb675a06 --- /dev/null +++ b/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.rs @@ -0,0 +1,61 @@ +//@ revisions: old next +//@[next] compile-flags: -Znext-solver +// (`test_free_mismatch` is quite difficult to implement in the old solver, so make sure this test +// runs on the old solver, just in case someone attempts to implement GCA for the old solver and +// removes the restriction that -Znext-solver must be enabled) + +#![feature(generic_const_items)] +#![feature(min_generic_const_args)] +#![feature(generic_const_args)] +//[old]~^ ERROR next-solver +#![expect(incomplete_features)] + +const FREE: usize = 10; + +trait Trait { + const PROJ: usize; +} +struct S; + +impl Trait for S { + const PROJ: usize = 10; +} + +fn free() -> ([(); N], [(); FREE::]) { + loop {} +} + +fn test_free() { + let (mut arr, mut arr_with_weird_len) = free(); + //[next]~^ ERROR type annotations needed + arr_with_weird_len = [(); 10]; +} + +fn test_free_mismatch() { + let (mut arr, mut arr_with_weird_len) = free(); + //[next]~^ ERROR type mismatch resolving `2 == 10` + arr_with_weird_len = [(); 2]; + arr = [(); 10]; +} + +fn proj() -> ([(); N], [(); ::PROJ::]) { + loop {} +} + +fn test_proj() { + let (mut arr, mut arr_with_weird_len) = proj(); + //[next]~^ ERROR type annotations needed + arr_with_weird_len = [(); 10]; +} + +fn test_proj_mismatch() { + let (mut arr, mut arr_with_weird_len) = proj(); + //[next]~^ ERROR type mismatch resolving `2 == 10` + arr_with_weird_len = [(); 2]; + arr = [(); 10]; +} + +fn main() { + test_free(); + test_proj(); +} diff --git a/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars.rs b/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars.rs new file mode 100644 index 0000000000000..4be1b036d6946 --- /dev/null +++ b/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars.rs @@ -0,0 +1,43 @@ +//@ check-pass +//@ compile-flags: -Znext-solver + +#![feature(generic_const_items)] +#![feature(min_generic_const_args)] +#![feature(generic_const_args)] +#![expect(incomplete_features)] + +const FREE: usize = 10; + +trait Trait { + const PROJ: usize; +} +struct S; + +impl Trait for S { + const PROJ: usize = 10; +} + +fn free() -> ([(); N], [(); FREE::]) { + loop {} +} + +fn test_free() { + let (mut arr, mut arr_with_weird_len) = free(); + arr_with_weird_len = [(); 10]; + arr = [(); 10]; +} + +fn proj() -> ([(); N], [(); ::PROJ::]) { + loop {} +} + +fn test_proj() { + let (mut arr, mut arr_with_weird_len) = proj(); + arr_with_weird_len = [(); 10]; + arr = [(); 10]; +} + +fn main() { + test_free(); + test_proj(); +} diff --git a/tests/ui/const-generics/gca/basic-different-definitions.rs b/tests/ui/const-generics/gca/basic-different-definitions.rs index d96c718617d24..ec26f26630a57 100644 --- a/tests/ui/const-generics/gca/basic-different-definitions.rs +++ b/tests/ui/const-generics/gca/basic-different-definitions.rs @@ -1,4 +1,5 @@ //@ check-pass +//@ compile-flags: -Znext-solver #![feature(generic_const_items)] #![feature(min_generic_const_args)] diff --git a/tests/ui/const-generics/gca/basic.rs b/tests/ui/const-generics/gca/basic.rs index e80540d621de5..40c28c3d38c0e 100644 --- a/tests/ui/const-generics/gca/basic.rs +++ b/tests/ui/const-generics/gca/basic.rs @@ -1,4 +1,5 @@ //@ check-pass +//@ compile-flags: -Znext-solver #![feature(generic_const_items)] #![feature(min_generic_const_args)] diff --git a/tests/ui/const-generics/gca/coherence-fail.rs b/tests/ui/const-generics/gca/coherence-fail.rs index 1b181d792d362..079c8cf63e144 100644 --- a/tests/ui/const-generics/gca/coherence-fail.rs +++ b/tests/ui/const-generics/gca/coherence-fail.rs @@ -1,3 +1,4 @@ +//@ compile-flags: -Znext-solver #![feature(generic_const_items, min_generic_const_args, generic_const_args)] #![expect(incomplete_features)] diff --git a/tests/ui/const-generics/gca/coherence-fail.stderr b/tests/ui/const-generics/gca/coherence-fail.stderr index e8122c1b832f1..d180654cc84a6 100644 --- a/tests/ui/const-generics/gca/coherence-fail.stderr +++ b/tests/ui/const-generics/gca/coherence-fail.stderr @@ -1,5 +1,5 @@ error[E0119]: conflicting implementations of trait `Trait1` for type `[(); 2]` - --> $DIR/coherence-fail.rs:9:1 + --> $DIR/coherence-fail.rs:10:1 | LL | impl Trait1 for [(); FOO::<1>] {} | ------------------------------ first implementation here @@ -7,7 +7,7 @@ LL | impl Trait1 for [(); BAR::<1>] {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `[(); 2]` error[E0119]: conflicting implementations of trait `Trait2` for type `[(); 1]` - --> $DIR/coherence-fail.rs:16:1 + --> $DIR/coherence-fail.rs:17:1 | LL | impl Trait2 for [(); DIV2::<2>] {} | ------------------------------- first implementation here @@ -15,7 +15,7 @@ LL | impl Trait2 for [(); DIV2::<3>] {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `[(); 1]` error[E0119]: conflicting implementations of trait `Trait3` for type `[(); 2]` - --> $DIR/coherence-fail.rs:25:1 + --> $DIR/coherence-fail.rs:26:1 | LL | impl Trait3 for [(); ADD1::<1>] {} | ------------------------------- first implementation here diff --git a/tests/ui/const-generics/gca/coherence-ok.rs b/tests/ui/const-generics/gca/coherence-ok.rs index 447f25bfdc36b..38899badf5f03 100644 --- a/tests/ui/const-generics/gca/coherence-ok.rs +++ b/tests/ui/const-generics/gca/coherence-ok.rs @@ -1,4 +1,5 @@ //@ check-pass +//@ compile-flags: -Znext-solver #![feature(generic_const_items, min_generic_const_args, generic_const_args)] #![expect(incomplete_features)] diff --git a/tests/ui/const-generics/gca/generic-free-const.rs b/tests/ui/const-generics/gca/generic-free-const.rs new file mode 100644 index 0000000000000..e7816728d461e --- /dev/null +++ b/tests/ui/const-generics/gca/generic-free-const.rs @@ -0,0 +1,19 @@ +//@ check-pass +//@ compile-flags: -Znext-solver + +#![feature(min_generic_const_args)] +#![feature(generic_const_args)] +#![feature(generic_const_items)] +#![expect(incomplete_features)] + +const ADD1: usize = N + 1; + +fn a() -> [usize; ADD1::] { + [ADD1::; ADD1::] +} + +fn main() { + let _: [(); ADD1::<1>] = [(); ADD1::<1>]; + let _: [(); ADD1::<{ ADD1::<1> }>] = [(); ADD1::<2>]; + a::<2>(); +} diff --git a/tests/ui/const-generics/gca/generic-param-rhs.rs b/tests/ui/const-generics/gca/generic-param-rhs.rs index ed4467d6f0039..ea6e2d7398b57 100644 --- a/tests/ui/const-generics/gca/generic-param-rhs.rs +++ b/tests/ui/const-generics/gca/generic-param-rhs.rs @@ -1,3 +1,4 @@ +//@ compile-flags: -Znext-solver #![feature(min_generic_const_args, generic_const_args)] #![expect(incomplete_features)] diff --git a/tests/ui/const-generics/gca/generic-param-rhs.stderr b/tests/ui/const-generics/gca/generic-param-rhs.stderr index acf3a5b21a855..ca0ce899b8b0d 100644 --- a/tests/ui/const-generics/gca/generic-param-rhs.stderr +++ b/tests/ui/const-generics/gca/generic-param-rhs.stderr @@ -1,5 +1,5 @@ error: generic parameters in const blocks are only allowed as the direct value of a `type const` - --> $DIR/generic-param-rhs.rs:6:19 + --> $DIR/generic-param-rhs.rs:7:19 | LL | foo::(); | ^ diff --git a/tests/ui/const-generics/gca/non-type-equality-fail.rs b/tests/ui/const-generics/gca/non-type-equality-fail.rs new file mode 100644 index 0000000000000..235ab37f8b570 --- /dev/null +++ b/tests/ui/const-generics/gca/non-type-equality-fail.rs @@ -0,0 +1,44 @@ +//@ compile-flags: -Znext-solver + +#![feature(min_generic_const_args)] +#![feature(generic_const_args)] +#![expect(incomplete_features)] + +trait Trait { + const PROJECTED_A: usize; + const PROJECTED_B: usize; +} + +struct StructImpl; +struct GenericStructImpl; + +impl Trait for StructImpl { + const PROJECTED_A: usize = 1; + const PROJECTED_B: usize = 1; +} + +impl Trait for GenericStructImpl { + const PROJECTED_A: usize = N; + const PROJECTED_B: usize = N; +} + +const FREE_A: usize = 1; +const FREE_B: usize = 1; + +struct Struct; + +fn f() { + let _: Struct<{ as Trait>::PROJECTED_A }> = + Struct::<{ as Trait>::PROJECTED_B }>; + //~^ ERROR mismatched types +} + +fn g() { + let _: Struct<{ T::PROJECTED_A }> = Struct::<{ T::PROJECTED_B }>; + //~^ ERROR mismatched types +} + +fn main() { + f::<2>(); + g::(); +} diff --git a/tests/ui/const-generics/gca/non-type-equality-fail.stderr b/tests/ui/const-generics/gca/non-type-equality-fail.stderr new file mode 100644 index 0000000000000..796efdcea93cc --- /dev/null +++ b/tests/ui/const-generics/gca/non-type-equality-fail.stderr @@ -0,0 +1,25 @@ +error[E0308]: mismatched types + --> $DIR/non-type-equality-fail.rs:32:9 + | +LL | let _: Struct<{ as Trait>::PROJECTED_A }> = + | -------------------------------------------------------- expected due to this +LL | Struct::<{ as Trait>::PROJECTED_B }>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ + | + = note: expected struct `Struct< as Trait>::PROJECTED_A>` + found struct `Struct< as Trait>::PROJECTED_B>` + +error[E0308]: mismatched types + --> $DIR/non-type-equality-fail.rs:37:41 + | +LL | let _: Struct<{ T::PROJECTED_A }> = Struct::<{ T::PROJECTED_B }>; + | -------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ + | | + | expected due to this + | + = note: expected struct `Struct<::PROJECTED_A>` + found struct `Struct<::PROJECTED_B>` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/gca/non-type-equality-ok.rs b/tests/ui/const-generics/gca/non-type-equality-ok.rs new file mode 100644 index 0000000000000..443fbc46bd8a0 --- /dev/null +++ b/tests/ui/const-generics/gca/non-type-equality-ok.rs @@ -0,0 +1,47 @@ +//@ check-pass +//@ compile-flags: -Znext-solver + +#![feature(min_generic_const_args)] +#![feature(generic_const_args)] +#![feature(generic_const_items)] +#![expect(incomplete_features)] + +trait Trait { + const PROJECTED_A: usize; + const PROJECTED_B: usize; +} + +struct StructImpl; +struct GenericStructImpl; + +impl Trait for StructImpl { + const PROJECTED_A: usize = 1; + const PROJECTED_B: usize = 1; +} + +impl Trait for GenericStructImpl { + const PROJECTED_A: usize = N; + const PROJECTED_B: usize = N; +} + +const FREE_A: usize = 1; +const FREE_B: usize = 1; + +struct Struct; + +fn f() { + let _: Struct<{ as Trait>::PROJECTED_A }> = + Struct::<{ as Trait>::PROJECTED_A }>; +} + +fn g() { + let _: Struct<{ T::PROJECTED_A }> = Struct::<{ T::PROJECTED_A }>; +} + +fn main() { + let _: Struct = Struct::; + let _: Struct<{ ::PROJECTED_A }> = + Struct::<{ ::PROJECTED_B }>; + let _: Struct<{ as Trait>::PROJECTED_A }> = + Struct::<{ as Trait>::PROJECTED_B }>; +} diff --git a/tests/ui/const-generics/gca/path-to-non-type-const.rs b/tests/ui/const-generics/gca/path-to-non-type-const.rs new file mode 100644 index 0000000000000..c36dbbcc578fa --- /dev/null +++ b/tests/ui/const-generics/gca/path-to-non-type-const.rs @@ -0,0 +1,35 @@ +//@ check-pass +//@ compile-flags: -Znext-solver + +#![feature(min_generic_const_args)] +#![feature(generic_const_args)] +#![expect(incomplete_features)] + +trait Trait { + const PROJECTED: usize; +} + +struct StructImpl; +struct GenericStructImpl; + +const FREE: usize = 1; + +impl Trait for StructImpl { + const PROJECTED: usize = 1; +} + +impl Trait for GenericStructImpl { + const PROJECTED: usize = A; +} + +struct Struct; + +fn f() { + let _ = Struct::<{ T::PROJECTED }>; +} + +fn main() { + let _ = Struct::; + let _ = Struct::<{ ::PROJECTED }>; + let _ = Struct::<{ as Trait>::PROJECTED }>; +} diff --git a/tests/ui/const-generics/gca/path-to-non-type-inherent-associated-const.rs b/tests/ui/const-generics/gca/path-to-non-type-inherent-associated-const.rs new file mode 100644 index 0000000000000..1b9164d4a2300 --- /dev/null +++ b/tests/ui/const-generics/gca/path-to-non-type-inherent-associated-const.rs @@ -0,0 +1,28 @@ +//! This test should be part of path-to-non-type-const.rs, and should pass. However, we are holding +//! off on implementing paths to IACs until a refactoring of how IAC generics are represented. +//@ compile-flags: -Znext-solver + +#![feature(min_generic_const_args)] +#![feature(generic_const_args)] +#![feature(inherent_associated_types)] +#![expect(incomplete_features)] + +struct StructImpl; +struct GenericStructImpl; + +impl StructImpl { + const INHERENT: usize = 1; +} + +impl GenericStructImpl { + const INHERENT: usize = A; +} + +struct Struct; + +fn main() { + let _ = Struct::<{ StructImpl::INHERENT }>; + //~^ ERROR use of `const` in the type system not defined as `type const` + let _ = Struct::<{ GenericStructImpl::<2>::INHERENT }>; + //~^ ERROR use of `const` in the type system not defined as `type const` +} diff --git a/tests/ui/const-generics/gca/path-to-non-type-inherent-associated-const.stderr b/tests/ui/const-generics/gca/path-to-non-type-inherent-associated-const.stderr new file mode 100644 index 0000000000000..b5da53f0f1c8e --- /dev/null +++ b/tests/ui/const-generics/gca/path-to-non-type-inherent-associated-const.stderr @@ -0,0 +1,24 @@ +error: use of `const` in the type system not defined as `type const` + --> $DIR/path-to-non-type-inherent-associated-const.rs:24:24 + | +LL | let _ = Struct::<{ StructImpl::INHERENT }>; + | ^^^^^^^^^^^^^^^^^^^^ + | +help: add `type` before `const` for `StructImpl::INHERENT` + | +LL | type const INHERENT: usize = 1; + | ++++ + +error: use of `const` in the type system not defined as `type const` + --> $DIR/path-to-non-type-inherent-associated-const.rs:26:24 + | +LL | let _ = Struct::<{ GenericStructImpl::<2>::INHERENT }>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add `type` before `const` for `GenericStructImpl::::INHERENT` + | +LL | type const INHERENT: usize = A; + | ++++ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/const-generics/gca/require-next-solver.rs b/tests/ui/const-generics/gca/require-next-solver.rs new file mode 100644 index 0000000000000..ffe3141b0f28a --- /dev/null +++ b/tests/ui/const-generics/gca/require-next-solver.rs @@ -0,0 +1,4 @@ +#![feature(min_generic_const_args)] +#![feature(generic_const_args)] +//~^ ERROR next-solver +fn main() {} diff --git a/tests/ui/const-generics/gca/require-next-solver.stderr b/tests/ui/const-generics/gca/require-next-solver.stderr new file mode 100644 index 0000000000000..bb52543554199 --- /dev/null +++ b/tests/ui/const-generics/gca/require-next-solver.stderr @@ -0,0 +1,10 @@ +error: `generic_const_exprs` requires -Znext-solver=globally to be enabled + --> $DIR/require-next-solver.rs:2:12 + | +LL | #![feature(generic_const_args)] + | ^^^^^^^^^^^^^^^^^^ + | + = help: enable all of these features + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/gca/rhs-but-not-root.rs b/tests/ui/const-generics/gca/rhs-but-not-root.rs index 6c0337dbbd470..61762a2851356 100644 --- a/tests/ui/const-generics/gca/rhs-but-not-root.rs +++ b/tests/ui/const-generics/gca/rhs-but-not-root.rs @@ -1,3 +1,4 @@ +//@ compile-flags: -Znext-solver #![feature(generic_const_items)] #![feature(min_generic_const_args)] #![feature(generic_const_args)] diff --git a/tests/ui/const-generics/gca/rhs-but-not-root.stderr b/tests/ui/const-generics/gca/rhs-but-not-root.stderr index 6481407eedc42..06f5ae248ac14 100644 --- a/tests/ui/const-generics/gca/rhs-but-not-root.stderr +++ b/tests/ui/const-generics/gca/rhs-but-not-root.stderr @@ -1,5 +1,5 @@ error: generic parameters in const blocks are only allowed as the direct value of a `type const` - --> $DIR/rhs-but-not-root.rs:7:54 + --> $DIR/rhs-but-not-root.rs:8:54 | LL | type const FOO: usize = ID::; | ^