mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-16 13:05:18 +03:00
Rollup merge of #155341 - khyperia:non-type-const, r=BoxyUwU
generic_const_args: allow paths to non type consts tracking issue: https://github.com/rust-lang/rust/issues/151972 Non type consts should be usable in the type system in `feature(generic_const_args)`. These are directly plugged into the constant evaluator, unlike type consts, which are attempted to be reasoned about by the type system. Inherent associated constants are not supported at this time, due to complications around how generic arguments are represented for them (it's currently a mess). The mess is being cleaned up (e.g. https://github.com/rust-lang/rust/pull/154758), so instead of trying to hack support in before the refactoring is done, let's just wait to be able to implement it more cleanly. r? @BoxyUwU
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)
|
||||
}
|
||||
|
||||
@@ -1200,6 +1200,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