mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-07 09:13:07 +03:00
generic_const_args: allow paths to non type consts
This commit is contained in:
@@ -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 };
|
||||
|
||||
@@ -739,3 +740,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_args,
|
||||
missing: String::from("-Znext-solver=globally"),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3064,7 +3064,14 @@ fn require_type_const_attribute(
|
||||
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(
|
||||
|
||||
@@ -106,6 +106,10 @@ fn generic_const_exprs(self) -> bool {
|
||||
self.generic_const_exprs()
|
||||
}
|
||||
|
||||
fn generic_const_args(self) -> bool {
|
||||
self.generic_const_args()
|
||||
}
|
||||
|
||||
fn coroutine_clone(self) -> bool {
|
||||
self.coroutine_clone()
|
||||
}
|
||||
|
||||
@@ -172,6 +172,9 @@ fn type_of(self, def_id: DefId) -> ty::EarlyBinder<'tcx, Ty<'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)
|
||||
}
|
||||
|
||||
@@ -1196,6 +1196,44 @@ pub(super) fn evaluate_const(
|
||||
self.delegate.evaluate_const(param_env, uv)
|
||||
}
|
||||
|
||||
pub(super) fn evaluate_const_and_instantiate_normalizes_to_term(
|
||||
&mut self,
|
||||
goal: Goal<I, ty::NormalizesTo<I>>,
|
||||
uv: ty::UnevaluatedConst<I>,
|
||||
) -> QueryResult<I> {
|
||||
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 if self.cx().features().generic_const_args() => {
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
None => {
|
||||
// Legacy behavior: always treat as ambiguous
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn is_transmutable(
|
||||
&mut self,
|
||||
src: I::Ty,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::delegate::SolverDelegate;
|
||||
use crate::solve::{Certainty, EvalCtxt, Goal, QueryResult};
|
||||
use crate::solve::{EvalCtxt, Goal, QueryResult};
|
||||
|
||||
impl<D, I> EvalCtxt<'_, D>
|
||||
where
|
||||
@@ -14,17 +14,7 @@ pub(super) fn normalize_anon_const(
|
||||
&mut self,
|
||||
goal: Goal<I, ty::NormalizesTo<I>>,
|
||||
) -> QueryResult<I> {
|
||||
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)
|
||||
} else {
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
|
||||
}
|
||||
let uv = goal.predicate.alias.expect_ct(self.cx());
|
||||
self.evaluate_const_and_instantiate_normalizes_to_term(goal, uv)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,13 +30,20 @@ pub(super) fn normalize_free_alias(
|
||||
.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);
|
||||
|
||||
@@ -52,13 +52,23 @@ pub(super) fn normalize_inherent_associated_term(
|
||||
.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)
|
||||
|
||||
@@ -383,19 +383,30 @@ fn consider_impl_candidate(
|
||||
|
||||
// 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)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -701,7 +701,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);
|
||||
}
|
||||
|
||||
|
||||
@@ -1065,7 +1065,7 @@ fn visit_const(&mut self, c: ty::Const<'tcx>) -> Self::Result {
|
||||
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),
|
||||
));
|
||||
|
||||
@@ -629,6 +629,8 @@ pub trait ParamEnv<I: Interner>: Copy + Debug + Hash + Eq + TypeFoldable<I> {
|
||||
pub trait Features<I: Interner>: Copy {
|
||||
fn generic_const_exprs(self) -> bool;
|
||||
|
||||
fn generic_const_args(self) -> bool;
|
||||
|
||||
fn coroutine_clone(self) -> bool;
|
||||
|
||||
fn feature_bound_holds_in_crate(self, symbol: I::Symbol) -> bool;
|
||||
|
||||
@@ -203,6 +203,7 @@ fn opt_alias_variances(
|
||||
fn type_of(self, def_id: Self::DefId) -> ty::EarlyBinder<Self, Self::Ty>;
|
||||
fn type_of_opaque_hir_typeck(self, def_id: Self::LocalDefId)
|
||||
-> ty::EarlyBinder<Self, Self::Ty>;
|
||||
fn is_type_const(self, def_id: Self::DefId) -> bool;
|
||||
fn const_of_item(self, def_id: Self::DefId) -> ty::EarlyBinder<Self, Self::Const>;
|
||||
fn anon_const_kind(self, def_id: Self::DefId) -> ty::AnonConstKind;
|
||||
|
||||
|
||||
@@ -726,16 +726,32 @@ pub fn expect_ty(self, interner: I) -> ty::AliasTy<I> {
|
||||
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<I> {
|
||||
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<I> {
|
||||
self.kind
|
||||
|
||||
@@ -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)).
|
||||
|
||||
|
||||
@@ -23,7 +23,8 @@ See also: [generic_const_items]
|
||||
|
||||
## Examples
|
||||
|
||||
```rust
|
||||
<!-- NOTE(ignore) generic_const_args requires -Znext-solver to compile -->
|
||||
```rust,ignore (requires-Z-next-solver)
|
||||
#![feature(generic_const_items)]
|
||||
#![feature(min_generic_const_args)]
|
||||
#![feature(generic_const_args)]
|
||||
|
||||
@@ -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<const N: usize>() -> ([(); N], [(); FREE::<N>]) {
|
||||
| ^^^^^^^^^^^^^^ 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 `10 == 2`
|
||||
--> $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<const N: usize>() -> ([(); N], [(); <S as Trait>::PROJ::<N>]) {
|
||||
| ^^^^^^^^^^^^^^ 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 `10 == 2`
|
||||
--> $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`.
|
||||
@@ -0,0 +1,10 @@
|
||||
error: `generic_const_args` 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
|
||||
|
||||
@@ -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<const A: usize>: usize = 10;
|
||||
|
||||
trait Trait {
|
||||
const PROJ<const A: usize>: usize;
|
||||
}
|
||||
struct S;
|
||||
|
||||
impl Trait for S {
|
||||
const PROJ<const A: usize>: usize = 10;
|
||||
}
|
||||
|
||||
fn free<const N: usize>() -> ([(); N], [(); FREE::<N>]) {
|
||||
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 `10 == 2`
|
||||
arr_with_weird_len = [(); 2];
|
||||
arr = [(); 10];
|
||||
}
|
||||
|
||||
fn proj<const N: usize>() -> ([(); N], [(); <S as Trait>::PROJ::<N>]) {
|
||||
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 `10 == 2`
|
||||
arr_with_weird_len = [(); 2];
|
||||
arr = [(); 10];
|
||||
}
|
||||
|
||||
fn main() {
|
||||
test_free();
|
||||
test_proj();
|
||||
}
|
||||
@@ -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<const A: usize>: usize = 10;
|
||||
|
||||
trait Trait {
|
||||
const PROJ<const A: usize>: usize;
|
||||
}
|
||||
struct S;
|
||||
|
||||
impl Trait for S {
|
||||
const PROJ<const A: usize>: usize = 10;
|
||||
}
|
||||
|
||||
fn free<const N: usize>() -> ([(); N], [(); FREE::<N>]) {
|
||||
loop {}
|
||||
}
|
||||
|
||||
fn test_free() {
|
||||
let (mut arr, mut arr_with_weird_len) = free();
|
||||
arr_with_weird_len = [(); 10];
|
||||
arr = [(); 10];
|
||||
}
|
||||
|
||||
fn proj<const N: usize>() -> ([(); N], [(); <S as Trait>::PROJ::<N>]) {
|
||||
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();
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
//@ check-pass
|
||||
//@ compile-flags: -Znext-solver
|
||||
|
||||
#![feature(generic_const_items)]
|
||||
#![feature(min_generic_const_args)]
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
//@ check-pass
|
||||
//@ compile-flags: -Znext-solver
|
||||
|
||||
#![feature(generic_const_items)]
|
||||
#![feature(min_generic_const_args)]
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//@ compile-flags: -Znext-solver
|
||||
#![feature(generic_const_items, min_generic_const_args, generic_const_args)]
|
||||
#![expect(incomplete_features)]
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
//@ check-pass
|
||||
//@ compile-flags: -Znext-solver
|
||||
#![feature(generic_const_items, min_generic_const_args, generic_const_args)]
|
||||
#![expect(incomplete_features)]
|
||||
|
||||
|
||||
@@ -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<const N: usize>: usize = N + 1;
|
||||
|
||||
fn a<const N: usize>() -> [usize; ADD1::<N>] {
|
||||
[ADD1::<N>; ADD1::<N>]
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _: [(); ADD1::<1>] = [(); ADD1::<1>];
|
||||
let _: [(); ADD1::<{ ADD1::<1> }>] = [(); ADD1::<2>];
|
||||
a::<2>();
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
//@ compile-flags: -Znext-solver
|
||||
#![feature(min_generic_const_args, generic_const_args)]
|
||||
#![expect(incomplete_features)]
|
||||
|
||||
|
||||
@@ -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::<const { N + 1 }>();
|
||||
| ^
|
||||
|
||||
@@ -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<const N: usize>;
|
||||
|
||||
impl Trait for StructImpl {
|
||||
const PROJECTED_A: usize = 1;
|
||||
const PROJECTED_B: usize = 1;
|
||||
}
|
||||
|
||||
impl<const N: usize> Trait for GenericStructImpl<N> {
|
||||
const PROJECTED_A: usize = N;
|
||||
const PROJECTED_B: usize = N;
|
||||
}
|
||||
|
||||
const FREE_A: usize = 1;
|
||||
const FREE_B: usize = 1;
|
||||
|
||||
struct Struct<const N: usize>;
|
||||
|
||||
fn f<const N: usize>() {
|
||||
let _: Struct<{ <GenericStructImpl<N> as Trait>::PROJECTED_A }> =
|
||||
Struct::<{ <GenericStructImpl<N> as Trait>::PROJECTED_B }>;
|
||||
//~^ ERROR mismatched types
|
||||
}
|
||||
|
||||
fn g<T: Trait>() {
|
||||
let _: Struct<{ T::PROJECTED_A }> = Struct::<{ T::PROJECTED_B }>;
|
||||
//~^ ERROR mismatched types
|
||||
}
|
||||
|
||||
fn main() {
|
||||
f::<2>();
|
||||
g::<StructImpl>();
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/non-type-equality-fail.rs:32:9
|
||||
|
|
||||
LL | let _: Struct<{ <GenericStructImpl<N> as Trait>::PROJECTED_A }> =
|
||||
| -------------------------------------------------------- expected due to this
|
||||
LL | Struct::<{ <GenericStructImpl<N> as Trait>::PROJECTED_B }>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ
|
||||
|
|
||||
= note: expected struct `Struct<<GenericStructImpl<N> as Trait>::PROJECTED_A>`
|
||||
found struct `Struct<<GenericStructImpl<N> 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<<T as Trait>::PROJECTED_A>`
|
||||
found struct `Struct<<T as Trait>::PROJECTED_B>`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
@@ -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<const N: usize>;
|
||||
|
||||
impl Trait for StructImpl {
|
||||
const PROJECTED_A: usize = 1;
|
||||
const PROJECTED_B: usize = 1;
|
||||
}
|
||||
|
||||
impl<const N: usize> Trait for GenericStructImpl<N> {
|
||||
const PROJECTED_A: usize = N;
|
||||
const PROJECTED_B: usize = N;
|
||||
}
|
||||
|
||||
const FREE_A: usize = 1;
|
||||
const FREE_B: usize = 1;
|
||||
|
||||
struct Struct<const N: usize>;
|
||||
|
||||
fn f<const N: usize>() {
|
||||
let _: Struct<{ <GenericStructImpl<N> as Trait>::PROJECTED_A }> =
|
||||
Struct::<{ <GenericStructImpl<N> as Trait>::PROJECTED_A }>;
|
||||
}
|
||||
|
||||
fn g<T: Trait>() {
|
||||
let _: Struct<{ T::PROJECTED_A }> = Struct::<{ T::PROJECTED_A }>;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _: Struct<FREE_A> = Struct::<FREE_B>;
|
||||
let _: Struct<{ <StructImpl as Trait>::PROJECTED_A }> =
|
||||
Struct::<{ <StructImpl as Trait>::PROJECTED_B }>;
|
||||
let _: Struct<{ <GenericStructImpl<2> as Trait>::PROJECTED_A }> =
|
||||
Struct::<{ <GenericStructImpl<2> as Trait>::PROJECTED_B }>;
|
||||
}
|
||||
@@ -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 A: usize>;
|
||||
|
||||
const FREE: usize = 1;
|
||||
|
||||
impl Trait for StructImpl {
|
||||
const PROJECTED: usize = 1;
|
||||
}
|
||||
|
||||
impl<const A: usize> Trait for GenericStructImpl<A> {
|
||||
const PROJECTED: usize = A;
|
||||
}
|
||||
|
||||
struct Struct<const N: usize>;
|
||||
|
||||
fn f<T: Trait>() {
|
||||
let _ = Struct::<{ T::PROJECTED }>;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _ = Struct::<FREE>;
|
||||
let _ = Struct::<{ <StructImpl as Trait>::PROJECTED }>;
|
||||
let _ = Struct::<{ <GenericStructImpl<2> as Trait>::PROJECTED }>;
|
||||
}
|
||||
@@ -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<const A: usize>;
|
||||
|
||||
impl StructImpl {
|
||||
const INHERENT: usize = 1;
|
||||
}
|
||||
|
||||
impl<const A: usize> GenericStructImpl<A> {
|
||||
const INHERENT: usize = A;
|
||||
}
|
||||
|
||||
struct Struct<const N: usize>;
|
||||
|
||||
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`
|
||||
}
|
||||
@@ -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::<A>::INHERENT`
|
||||
|
|
||||
LL | type const INHERENT: usize = A;
|
||||
| ++++
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
#![feature(min_generic_const_args)]
|
||||
#![feature(generic_const_args)]
|
||||
//~^ ERROR next-solver
|
||||
fn main() {}
|
||||
@@ -0,0 +1,10 @@
|
||||
error: `generic_const_args` 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
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//@ compile-flags: -Znext-solver
|
||||
#![feature(generic_const_items)]
|
||||
#![feature(min_generic_const_args)]
|
||||
#![feature(generic_const_args)]
|
||||
|
||||
@@ -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<const N: usize>: usize = ID::<const { N + 1 }>;
|
||||
| ^
|
||||
|
||||
Reference in New Issue
Block a user