Check type_const type is ConstParamTy_ and that RHS matches it

This commit is contained in:
Noah Lev 2025-11-08 16:53:38 -05:00
parent c0939d4ec0
commit 9ba89327df
20 changed files with 234 additions and 55 deletions

View file

@ -3065,7 +3065,7 @@ macro_rules! expect_methods_self_kind {
$(
#[track_caller]
pub fn $name(&self) -> $ret_ty {
let $pat = &self.kind else { expect_failed(stringify!($ident), self) };
let $pat = &self.kind else { expect_failed(stringify!($name), self) };
$ret_val
}
)*
@ -3077,7 +3077,7 @@ macro_rules! expect_methods_self {
$(
#[track_caller]
pub fn $name(&self) -> $ret_ty {
let $pat = self else { expect_failed(stringify!($ident), self) };
let $pat = self else { expect_failed(stringify!($name), self) };
$ret_val
}
)*
@ -4790,6 +4790,11 @@ impl<'hir> Node<'hir> {
ForeignItemKind::Static(ty, ..) => Some(ty),
_ => None,
},
Node::GenericParam(param) => match param.kind {
GenericParamKind::Lifetime { .. } => None,
GenericParamKind::Type { default, .. } => default,
GenericParamKind::Const { ty, .. } => Some(ty),
},
_ => None,
}
}

View file

@ -918,7 +918,10 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(),
);
check_where_clauses(wfcx, def_id);
wfcheck::check_const_item_rhs(wfcx, def_id)
if find_attr!(tcx.get_all_attrs(def_id), AttributeKind::TypeConst(_)) {
wfcheck::check_type_const(wfcx, def_id, ty, true)?;
}
Ok(())
}));
// Only `Node::Item` and `Node::ForeignItem` still have HIR based

View file

@ -951,7 +951,12 @@ pub(crate) fn check_associated_item(
let ty = wfcx.deeply_normalize(span, Some(WellFormedLoc::Ty(def_id)), ty);
wfcx.register_wf_obligation(span, loc, ty.into());
if item.defaultness(tcx).has_value() {
let has_value = item.defaultness(tcx).has_value();
if find_attr!(tcx.get_all_attrs(def_id), AttributeKind::TypeConst(_)) {
check_type_const(wfcx, def_id, ty, has_value)?;
}
if has_value {
let code = ObligationCauseCode::SizedConstOrStatic;
wfcx.register_bound(
ObligationCause::new(span, def_id, code),
@ -959,8 +964,6 @@ pub(crate) fn check_associated_item(
ty,
tcx.require_lang_item(LangItem::Sized, span),
);
check_const_item_rhs(wfcx, def_id)?;
}
Ok(())
@ -1230,16 +1233,33 @@ pub(crate) fn check_static_item<'tcx>(
}
#[instrument(level = "debug", skip(wfcx))]
pub(super) fn check_const_item_rhs<'tcx>(
pub(super) fn check_type_const<'tcx>(
wfcx: &WfCheckingCtxt<'_, 'tcx>,
def_id: LocalDefId,
item_ty: Ty<'tcx>,
has_value: bool,
) -> Result<(), ErrorGuaranteed> {
let tcx = wfcx.tcx();
if find_attr!(tcx.get_all_attrs(def_id), AttributeKind::TypeConst(_)) {
let span = tcx.def_span(def_id);
wfcx.register_bound(
ObligationCause::new(span, def_id, ObligationCauseCode::ConstParam(item_ty)),
wfcx.param_env,
item_ty,
tcx.require_lang_item(LangItem::ConstParamTy, span),
);
if has_value {
let raw_ct = tcx.const_of_item(def_id).instantiate_identity();
let span = tcx.def_span(def_id);
let norm_ct = wfcx.deeply_normalize(span, Some(WellFormedLoc::Ty(def_id)), raw_ct);
wfcx.register_wf_obligation(span, Some(WellFormedLoc::Ty(def_id)), norm_ct.into());
wfcx.register_obligation(Obligation::new(
tcx,
ObligationCause::new(span, def_id, ObligationCauseCode::WellFormed(None)),
wfcx.param_env,
ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(norm_ct, item_ty)),
));
}
Ok(())
}

View file

@ -1286,12 +1286,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
ty: Ty<'tcx>,
obligation: &PredicateObligation<'tcx>,
) -> Diag<'a> {
let param = obligation.cause.body_id;
let hir::GenericParamKind::Const { ty: &hir::Ty { span, .. }, .. } =
self.tcx.hir_node_by_def_id(param).expect_generic_param().kind
else {
bug!()
};
let def_id = obligation.cause.body_id;
let span = self.tcx.ty_span(def_id);
let mut file = None;
let ty_str = self.tcx.short_string(ty, &mut file);

View file

@ -1,7 +1,7 @@
// We used to say "ambiguous associated type" on ambiguous associated consts.
// Ensure that we now use the correct label.
#![feature(associated_const_equality, min_generic_const_args)]
#![feature(associated_const_equality, min_generic_const_args, unsized_const_params)]
#![allow(incomplete_features)]
trait Trait0: Parent0<i32> + Parent0<u32> {}

View file

@ -1,9 +1,16 @@
// Check that we eventually catch types of assoc const bounds
// (containing late-bound vars) that are ill-formed.
#![feature(associated_const_equality, min_generic_const_args)]
#![feature(
associated_const_equality,
min_generic_const_args,
adt_const_params,
unsized_const_params,
)]
#![allow(incomplete_features)]
trait Trait<T> {
use std::marker::ConstParamTy_;
trait Trait<T: ConstParamTy_> {
#[type_const]
const K: T;
}

View file

@ -1,11 +1,11 @@
error: higher-ranked subtype error
--> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:14:13
--> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:21:13
|
LL | K = { () }
| ^^^^^^
error: higher-ranked subtype error
--> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:14:13
--> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:21:13
|
LL | K = { () }
| ^^^^^^
@ -13,7 +13,7 @@ LL | K = { () }
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: implementation of `Project` is not general enough
--> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:12:13
--> $DIR/assoc-const-eq-bound-var-in-ty-not-wf.rs:19:13
|
LL | _: impl Trait<
| _____________^

View file

@ -3,10 +3,17 @@
//
//@ check-pass
#![feature(associated_const_equality, min_generic_const_args)]
#![feature(
associated_const_equality,
min_generic_const_args,
adt_const_params,
unsized_const_params,
)]
#![allow(incomplete_features)]
trait Trait<T> {
use std::marker::ConstParamTy_;
trait Trait<T: ConstParamTy_> {
#[type_const]
const K: T;
}

View file

@ -1,6 +1,6 @@
// Detect and reject escaping late-bound generic params in
// the type of assoc consts used in an equality bound.
#![feature(associated_const_equality, min_generic_const_args)]
#![feature(associated_const_equality, min_generic_const_args, unsized_const_params)]
#![allow(incomplete_features)]
trait Trait<'a> {

View file

@ -1,14 +1,21 @@
// Regression test for issue #108271.
// Detect and reject generic params in the type of assoc consts used in an equality bound.
#![feature(associated_const_equality, min_generic_const_args)]
#![feature(
associated_const_equality,
min_generic_const_args,
adt_const_params,
unsized_const_params,
)]
#![allow(incomplete_features)]
trait Trait<'a, T: 'a, const N: usize> {
use std::marker::ConstParamTy_;
trait Trait<'a, T: 'a + ConstParamTy_, const N: usize> {
#[type_const]
const K: &'a [T; N];
}
fn take0<'r, A: 'r, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} }>) {}
fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} }>) {}
//~^ ERROR the type of the associated constant `K` must not depend on generic parameters
//~| NOTE its type must not depend on the lifetime parameter `'r`
//~| NOTE the lifetime parameter `'r` is defined here
@ -22,7 +29,7 @@ fn take0<'r, A: 'r, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} }>) {}
//~| NOTE the const parameter `Q` is defined here
//~| NOTE `K` has type `&'r [A; Q]`
trait Project {
trait Project: ConstParamTy_ {
#[type_const]
const SELF: Self;
}
@ -38,7 +45,7 @@ fn take2<P: Project<SELF = {}>>(_: P) {}
//~| NOTE the type parameter `P` is defined here
//~| NOTE `SELF` has type `P`
trait Iface<'r> {
trait Iface<'r>: ConstParamTy_ {
//~^ NOTE the lifetime parameter `'r` is defined here
//~| NOTE the lifetime parameter `'r` is defined here
type Assoc<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>

View file

@ -1,31 +1,31 @@
error: the type of the associated constant `K` must not depend on generic parameters
--> $DIR/assoc-const-eq-param-in-ty.rs:11:61
--> $DIR/assoc-const-eq-param-in-ty.rs:18:77
|
LL | fn take0<'r, A: 'r, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} }>) {}
| -- the lifetime parameter `'r` is defined here ^ its type must not depend on the lifetime parameter `'r`
LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} }>) {}
| -- the lifetime parameter `'r` is defined here ^ its type must not depend on the lifetime parameter `'r`
|
= note: `K` has type `&'r [A; Q]`
error: the type of the associated constant `K` must not depend on generic parameters
--> $DIR/assoc-const-eq-param-in-ty.rs:11:61
--> $DIR/assoc-const-eq-param-in-ty.rs:18:77
|
LL | fn take0<'r, A: 'r, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} }>) {}
| - the type parameter `A` is defined here ^ its type must not depend on the type parameter `A`
LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} }>) {}
| - the type parameter `A` is defined here ^ its type must not depend on the type parameter `A`
|
= note: `K` has type `&'r [A; Q]`
error: the type of the associated constant `K` must not depend on generic parameters
--> $DIR/assoc-const-eq-param-in-ty.rs:11:61
--> $DIR/assoc-const-eq-param-in-ty.rs:18:77
|
LL | fn take0<'r, A: 'r, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} }>) {}
| - ^ its type must not depend on the const parameter `Q`
| |
| the const parameter `Q` is defined here
LL | fn take0<'r, A: 'r + ConstParamTy_, const Q: usize>(_: impl Trait<'r, A, Q, K = { loop {} }>) {}
| - ^ its type must not depend on the const parameter `Q`
| |
| the const parameter `Q` is defined here
|
= note: `K` has type `&'r [A; Q]`
error: the type of the associated constant `SELF` must not depend on `impl Trait`
--> $DIR/assoc-const-eq-param-in-ty.rs:30:26
--> $DIR/assoc-const-eq-param-in-ty.rs:37:26
|
LL | fn take1(_: impl Project<SELF = {}>) {}
| -------------^^^^------
@ -34,7 +34,7 @@ LL | fn take1(_: impl Project<SELF = {}>) {}
| the `impl Trait` is specified here
error: the type of the associated constant `SELF` must not depend on generic parameters
--> $DIR/assoc-const-eq-param-in-ty.rs:35:21
--> $DIR/assoc-const-eq-param-in-ty.rs:42:21
|
LL | fn take2<P: Project<SELF = {}>>(_: P) {}
| - ^^^^ its type must not depend on the type parameter `P`
@ -44,9 +44,9 @@ LL | fn take2<P: Project<SELF = {}>>(_: P) {}
= note: `SELF` has type `P`
error: the type of the associated constant `K` must not depend on generic parameters
--> $DIR/assoc-const-eq-param-in-ty.rs:44:52
--> $DIR/assoc-const-eq-param-in-ty.rs:51:52
|
LL | trait Iface<'r> {
LL | trait Iface<'r>: ConstParamTy_ {
| -- the lifetime parameter `'r` is defined here
...
LL | type Assoc<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
@ -55,7 +55,7 @@ LL | type Assoc<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
= note: `K` has type `&'r [Self; Q]`
error: the type of the associated constant `K` must not depend on `Self`
--> $DIR/assoc-const-eq-param-in-ty.rs:44:52
--> $DIR/assoc-const-eq-param-in-ty.rs:51:52
|
LL | type Assoc<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
| ^ its type must not depend on `Self`
@ -63,7 +63,7 @@ LL | type Assoc<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
= note: `K` has type `&'r [Self; Q]`
error: the type of the associated constant `K` must not depend on generic parameters
--> $DIR/assoc-const-eq-param-in-ty.rs:44:52
--> $DIR/assoc-const-eq-param-in-ty.rs:51:52
|
LL | type Assoc<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
| - ^ its type must not depend on the const parameter `Q`
@ -73,9 +73,9 @@ LL | type Assoc<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
= note: `K` has type `&'r [Self; Q]`
error: the type of the associated constant `K` must not depend on generic parameters
--> $DIR/assoc-const-eq-param-in-ty.rs:44:52
--> $DIR/assoc-const-eq-param-in-ty.rs:51:52
|
LL | trait Iface<'r> {
LL | trait Iface<'r>: ConstParamTy_ {
| -- the lifetime parameter `'r` is defined here
...
LL | type Assoc<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
@ -85,7 +85,7 @@ LL | type Assoc<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: the type of the associated constant `K` must not depend on `Self`
--> $DIR/assoc-const-eq-param-in-ty.rs:44:52
--> $DIR/assoc-const-eq-param-in-ty.rs:51:52
|
LL | type Assoc<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
| ^ its type must not depend on `Self`
@ -94,7 +94,7 @@ LL | type Assoc<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: the type of the associated constant `K` must not depend on generic parameters
--> $DIR/assoc-const-eq-param-in-ty.rs:44:52
--> $DIR/assoc-const-eq-param-in-ty.rs:51:52
|
LL | type Assoc<const Q: usize>: Trait<'r, Self, Q, K = { loop {} }>
| - ^ its type must not depend on the const parameter `Q`

View file

@ -3,12 +3,19 @@
//@ check-pass
#![feature(associated_const_equality, min_generic_const_args)]
#![feature(
associated_const_equality,
min_generic_const_args,
adt_const_params,
unsized_const_params,
)]
#![allow(incomplete_features)]
use std::marker::ConstParamTy_;
trait Trait: SuperTrait {}
trait SuperTrait: SuperSuperTrait<i32> {}
trait SuperSuperTrait<T> {
trait SuperSuperTrait<T: ConstParamTy_> {
#[type_const]
const K: T;
}

View file

@ -5,7 +5,7 @@
//@ check-pass
#![feature(associated_const_equality, min_generic_const_args)]
#![feature(associated_const_equality, min_generic_const_args, unsized_const_params)]
#![allow(incomplete_features)]
trait Trait: SuperTrait {

View file

@ -0,0 +1,23 @@
#![expect(incomplete_features)]
#![feature(min_generic_const_args)]
#[type_const]
const FREE: u32 = 5_usize;
//~^ ERROR mismatched types
#[type_const]
const FREE2: isize = FREE;
//~^ ERROR the constant `5` is not of type `isize`
trait Tr {
#[type_const]
const N: usize;
}
impl Tr for () {
#[type_const]
const N: usize = false;
//~^ ERROR mismatched types
}
fn main() {}

View file

@ -0,0 +1,27 @@
error: the constant `5` is not of type `isize`
--> $DIR/type_const-mismatched-types.rs:9:1
|
LL | const FREE2: isize = FREE;
| ^^^^^^^^^^^^^^^^^^ expected `isize`, found `u32`
error[E0308]: mismatched types
--> $DIR/type_const-mismatched-types.rs:5:19
|
LL | const FREE: u32 = 5_usize;
| ^^^^^^^ expected `u32`, found `usize`
|
help: change the type of the numeric literal from `usize` to `u32`
|
LL - const FREE: u32 = 5_usize;
LL + const FREE: u32 = 5_u32;
|
error[E0308]: mismatched types
--> $DIR/type_const-mismatched-types.rs:19:22
|
LL | const N: usize = false;
| ^^^^^ expected `usize`, found `bool`
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0308`.

View file

@ -0,0 +1,26 @@
#![expect(incomplete_features)]
#![feature(min_generic_const_args)]
struct S;
// FIXME(mgca): need support for ctors without anon const
// (we use double-braces to trigger an anon const here)
#[type_const]
const FREE: S = { { S } };
//~^ ERROR `S` must implement `ConstParamTy` to be used as the type of a const generic parameter
trait Tr {
#[type_const]
const N: S;
//~^ ERROR `S` must implement `ConstParamTy` to be used as the type of a const generic parameter
}
impl Tr for S {
// FIXME(mgca): need support for ctors without anon const
// (we use double-braces to trigger an anon const here)
#[type_const]
const N: S = { { S } };
//~^ ERROR `S` must implement `ConstParamTy` to be used as the type of a const generic parameter
}
fn main() {}

View file

@ -0,0 +1,39 @@
error[E0741]: `S` must implement `ConstParamTy` to be used as the type of a const generic parameter
--> $DIR/type_const-not-constparamty.rs:9:13
|
LL | const FREE: S = { { S } };
| ^
|
help: add `#[derive(ConstParamTy, PartialEq, Eq)]` to the struct
|
LL + #[derive(ConstParamTy, PartialEq, Eq)]
LL | struct S;
|
error[E0741]: `S` must implement `ConstParamTy` to be used as the type of a const generic parameter
--> $DIR/type_const-not-constparamty.rs:22:14
|
LL | const N: S = { { S } };
| ^
|
help: add `#[derive(ConstParamTy, PartialEq, Eq)]` to the struct
|
LL + #[derive(ConstParamTy, PartialEq, Eq)]
LL | struct S;
|
error[E0741]: `S` must implement `ConstParamTy` to be used as the type of a const generic parameter
--> $DIR/type_const-not-constparamty.rs:14:14
|
LL | const N: S;
| ^
|
help: add `#[derive(ConstParamTy, PartialEq, Eq)]` to the struct
|
LL + #[derive(ConstParamTy, PartialEq, Eq)]
LL | struct S;
|
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0741`.

View file

@ -1,9 +1,12 @@
//@ known-bug: #119783
// Regression test for #119783
#![expect(incomplete_features)]
#![feature(associated_const_equality, min_generic_const_args)]
trait Trait {
#[type_const]
const F: fn();
//~^ ERROR using function pointers as const generic parameters is forbidden
}
fn take(_: impl Trait<F = { || {} }>) {}

View file

@ -0,0 +1,9 @@
error[E0741]: using function pointers as const generic parameters is forbidden
--> $DIR/using-fnptr-as-type_const.rs:8:14
|
LL | const F: fn();
| ^^^^
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0741`.

View file

@ -1,6 +1,6 @@
// ICE: assertion failed: !value.has_infer()
// issue: rust-lang/rust#115806
#![feature(associated_const_equality, min_generic_const_args)]
#![feature(associated_const_equality, min_generic_const_args, unsized_const_params)]
#![allow(incomplete_features)]
pub struct NoPin;