Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 39 additions & 26 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1422,14 +1422,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
LowerTypeRelativePathMode::Const,
)? {
TypeRelativePath::AssocItem(def_id, args) => {
if !self.tcx().is_type_const(def_id) {
let mut err = self.dcx().struct_span_err(
span,
"use of trait associated const without `#[type_const]`",
);
err.note("the declaration in the trait must be marked with `#[type_const]`");
return Err(err.emit());
}
self.require_type_const_attribute(def_id, span)?;
let ct = Const::new_unevaluated(tcx, ty::UnevaluatedConst::new(def_id, args));
let ct = self.check_param_uses_if_mcg(ct, span, false);
Ok(ct)
Expand Down Expand Up @@ -1885,30 +1878,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
item_def_id: DefId,
trait_segment: Option<&hir::PathSegment<'tcx>>,
item_segment: &hir::PathSegment<'tcx>,
) -> Const<'tcx> {
match self.lower_resolved_assoc_item_path(
) -> Result<Const<'tcx>, ErrorGuaranteed> {
let (item_def_id, item_args) = self.lower_resolved_assoc_item_path(
span,
opt_self_ty,
item_def_id,
trait_segment,
item_segment,
ty::AssocTag::Const,
) {
Ok((item_def_id, item_args)) => {
if !self.tcx().is_type_const(item_def_id) {
let mut err = self.dcx().struct_span_err(
span,
"use of `const` in the type system without `#[type_const]`",
);
err.note("the declaration must be marked with `#[type_const]`");
return Const::new_error(self.tcx(), err.emit());
}

let uv = ty::UnevaluatedConst::new(item_def_id, item_args);
Const::new_unevaluated(self.tcx(), uv)
}
Err(guar) => Const::new_error(self.tcx(), guar),
}
)?;
self.require_type_const_attribute(item_def_id, span)?;
let uv = ty::UnevaluatedConst::new(item_def_id, item_args);
Ok(Const::new_unevaluated(self.tcx(), uv))
}

/// Lower a [resolved][hir::QPath::Resolved] (type-level) associated item path.
Expand Down Expand Up @@ -2668,6 +2649,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
self.lower_const_param(def_id, hir_id)
}
Res::Def(DefKind::Const, did) => {
if let Err(guar) = self.require_type_const_attribute(did, span) {
return Const::new_error(self.tcx(), guar);
}

assert_eq!(opt_self_ty, None);
let [leading_segments @ .., segment] = path.segments else { bug!() };
let _ = self
Expand Down Expand Up @@ -2718,6 +2703,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
trait_segment,
path.segments.last().unwrap(),
)
.unwrap_or_else(|guar| Const::new_error(tcx, guar))
}
Res::Def(DefKind::Static { .. }, _) => {
span_bug!(span, "use of bare `static` ConstArgKind::Path's not yet supported")
Expand Down Expand Up @@ -2843,6 +2829,33 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.map(|l| tcx.at(expr.span).lit_to_const(l))
}

fn require_type_const_attribute(
&self,
def_id: DefId,
span: Span,
) -> Result<(), ErrorGuaranteed> {
let tcx = self.tcx();
if tcx.is_type_const(def_id) {
Ok(())
} else {
let mut err = self
.dcx()
.struct_span_err(span, "use of `const` in the type system without `#[type_const]`");
if def_id.is_local() {
let name = tcx.def_path_str(def_id);
err.span_suggestion(
tcx.def_span(def_id).shrink_to_lo(),
format!("add `#[type_const]` attribute to `{name}`"),
format!("#[type_const]\n"),
Applicability::MaybeIncorrect,
);
} else {
err.note("only consts marked with `#[type_const]` may be used in types");
}
Err(err.emit())
}
}

fn lower_delegation_ty(&self, idx: hir::InferDelegationKind) -> Ty<'tcx> {
let delegation_sig = self.tcx().inherit_sig_for_delegation_item(self.item_def_id());
match idx {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#![feature(min_generic_const_args)]
#![allow(incomplete_features)]

#[type_const]
pub const NON_LOCAL_CONST: char = 'a';
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
// regression test for #133808.
//@ aux-build:non_local_type_const.rs

#![feature(generic_const_exprs)]
#![feature(min_generic_const_args)]
#![allow(incomplete_features)]
#![crate_type = "lib"]
extern crate non_local_type_const;

pub trait Foo {}
impl Foo for [u8; std::path::MAIN_SEPARATOR] {}
//~^ ERROR the constant `MAIN_SEPARATOR` is not of type `usize`
impl Foo for [u8; non_local_type_const::NON_LOCAL_CONST] {}
//~^ ERROR the constant `'a'` is not of type `usize`
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
error: the constant `MAIN_SEPARATOR` is not of type `usize`
--> $DIR/non-local-const.rs:9:14
error: the constant `'a'` is not of type `usize`
--> $DIR/non-local-const.rs:11:14
|
LL | impl Foo for [u8; std::path::MAIN_SEPARATOR] {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `char`
LL | impl Foo for [u8; non_local_type_const::NON_LOCAL_CONST] {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `char`
|
= note: the length of array `[u8; MAIN_SEPARATOR]` must be type `usize`
= note: the length of array `[u8; 'a']` must be type `usize`

error: aborting due to 1 previous error

16 changes: 12 additions & 4 deletions tests/ui/const-generics/mgca/assoc-const-without-type_const.stderr
Original file line number Diff line number Diff line change
@@ -1,18 +1,26 @@
error: use of trait associated const without `#[type_const]`
error: use of `const` in the type system without `#[type_const]`
--> $DIR/assoc-const-without-type_const.rs:8:35
|
LL | fn mk_array<T: Tr>(_x: T) -> [(); T::SIZE] {
| ^^^^^^^
|
= note: the declaration in the trait must be marked with `#[type_const]`
help: add `#[type_const]` attribute to `Tr::SIZE`
|
LL + #[type_const]
LL | const SIZE: usize;
|

error: use of trait associated const without `#[type_const]`
error: use of `const` in the type system without `#[type_const]`
--> $DIR/assoc-const-without-type_const.rs:10:10
|
LL | [(); T::SIZE]
| ^^^^^^^
|
= note: the declaration in the trait must be marked with `#[type_const]`
help: add `#[type_const]` attribute to `Tr::SIZE`
|
LL + #[type_const]
LL | const SIZE: usize;
|

error: aborting due to 2 previous errors

1 change: 1 addition & 0 deletions tests/ui/const-generics/mgca/auxiliary/non_local_const.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub const N: usize = 2;
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#![expect(incomplete_features)]
#![feature(min_generic_const_args)]

#[type_const]
const C: usize = 0;
pub struct A<const M: usize> {}
impl A<C> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
error[E0107]: missing generics for struct `A`
--> $DIR/const-arg-coherence-conflicting-methods.rs:12:6
--> $DIR/const-arg-coherence-conflicting-methods.rs:13:6
|
LL | impl A {
| ^ expected 1 generic argument
|
note: struct defined here, with 1 generic parameter: `M`
--> $DIR/const-arg-coherence-conflicting-methods.rs:7:12
--> $DIR/const-arg-coherence-conflicting-methods.rs:8:12
|
LL | pub struct A<const M: usize> {}
| ^ --------------
Expand All @@ -15,7 +15,7 @@ LL | impl A<M> {
| +++

error[E0592]: duplicate definitions with name `fun1`
--> $DIR/const-arg-coherence-conflicting-methods.rs:9:5
--> $DIR/const-arg-coherence-conflicting-methods.rs:10:5
|
LL | fn fun1() {}
| ^^^^^^^^^ duplicate definitions for `fun1`
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Just a test of the error message (it's different for non-local consts)
//@ aux-build:non_local_const.rs
#![feature(min_generic_const_args)]
#![allow(incomplete_features)]
extern crate non_local_const;
fn main() {
let x = [(); non_local_const::N];
//~^ ERROR use of `const` in the type system without `#[type_const]`
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
error: use of `const` in the type system without `#[type_const]`
--> $DIR/non-local-const-without-type_const.rs:7:18
|
LL | let x = [(); non_local_const::N];
| ^^^^^^^^^^^^^^^^^^
|
= note: only consts marked with `#[type_const]` may be used in types

error: aborting due to 1 previous error

1 change: 1 addition & 0 deletions tests/ui/const-generics/mgca/tuple_ctor_erroneous.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ enum MyEnum<T> {
Unit,
}

#[type_const]
const CONST_ITEM: u32 = 42;

fn accepts_point<const P: Point>() {}
Expand Down
20 changes: 10 additions & 10 deletions tests/ui/const-generics/mgca/tuple_ctor_erroneous.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0425]: cannot find function, tuple struct or tuple variant `UnresolvedIdent` in this scope
--> $DIR/tuple_ctor_erroneous.rs:29:23
--> $DIR/tuple_ctor_erroneous.rs:30:23
|
LL | accepts_point::<{ UnresolvedIdent(N, N) }>();
| ^^^^^^^^^^^^^^^ not found in this scope
Expand All @@ -10,55 +10,55 @@ LL | fn test_errors<const N: usize, const UnresolvedIdent: /* Type */>() {
| +++++++++++++++++++++++++++++++++++

error: tuple constructor has 2 arguments but 1 were provided
--> $DIR/tuple_ctor_erroneous.rs:23:23
--> $DIR/tuple_ctor_erroneous.rs:24:23
|
LL | accepts_point::<{ Point(N) }>();
| ^^^^^^^^

error: tuple constructor has 2 arguments but 3 were provided
--> $DIR/tuple_ctor_erroneous.rs:26:23
--> $DIR/tuple_ctor_erroneous.rs:27:23
|
LL | accepts_point::<{ Point(N, N, N) }>();
| ^^^^^^^^^^^^^^

error: tuple constructor with invalid base path
--> $DIR/tuple_ctor_erroneous.rs:29:23
--> $DIR/tuple_ctor_erroneous.rs:30:23
|
LL | accepts_point::<{ UnresolvedIdent(N, N) }>();
| ^^^^^^^^^^^^^^^^^^^^^

error: tuple constructor with invalid base path
--> $DIR/tuple_ctor_erroneous.rs:33:23
--> $DIR/tuple_ctor_erroneous.rs:34:23
|
LL | accepts_point::<{ non_ctor(N, N) }>();
| ^^^^^^^^^^^^^^

error: tuple constructor with invalid base path
--> $DIR/tuple_ctor_erroneous.rs:36:23
--> $DIR/tuple_ctor_erroneous.rs:37:23
|
LL | accepts_point::<{ CONST_ITEM(N, N) }>();
| ^^^^^^^^^^^^^^^^

error: the constant `Point` is not of type `Point`
--> $DIR/tuple_ctor_erroneous.rs:39:23
--> $DIR/tuple_ctor_erroneous.rs:40:23
|
LL | accepts_point::<{ Point }>();
| ^^^^^ expected `Point`, found struct constructor
|
note: required by a const generic parameter in `accepts_point`
--> $DIR/tuple_ctor_erroneous.rs:17:18
--> $DIR/tuple_ctor_erroneous.rs:18:18
|
LL | fn accepts_point<const P: Point>() {}
| ^^^^^^^^^^^^^^ required by this const generic parameter in `accepts_point`

error: the constant `MyEnum::<u32>::Variant` is not of type `MyEnum<u32>`
--> $DIR/tuple_ctor_erroneous.rs:42:22
--> $DIR/tuple_ctor_erroneous.rs:43:22
|
LL | accepts_enum::<{ MyEnum::Variant::<u32> }>();
| ^^^^^^^^^^^^^^^^^^^^^^ expected `MyEnum<u32>`, found enum constructor
|
note: required by a const generic parameter in `accepts_enum`
--> $DIR/tuple_ctor_erroneous.rs:18:17
--> $DIR/tuple_ctor_erroneous.rs:19:17
|
LL | fn accepts_enum<const E: MyEnum<u32>>() {}
| ^^^^^^^^^^^^^^^^^^^^ required by this const generic parameter in `accepts_enum`
Expand Down
11 changes: 11 additions & 0 deletions tests/ui/const-generics/mgca/unmarked-free-const.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// regression test, used to ICE

#![feature(min_generic_const_args)]
#![allow(incomplete_features)]

const N: usize = 4;

fn main() {
let x = [(); N];
//~^ ERROR use of `const` in the type system without `#[type_const]`
}
14 changes: 14 additions & 0 deletions tests/ui/const-generics/mgca/unmarked-free-const.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
error: use of `const` in the type system without `#[type_const]`
--> $DIR/unmarked-free-const.rs:9:18
|
LL | let x = [(); N];
| ^
|
help: add `#[type_const]` attribute to `N`
|
LL + #[type_const]
LL | const N: usize = 4;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pointing to the definition site of the non-type const is rly nice :3 thanks

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

something I was thinking of: what happens with non-local spans?

err.span_note(
    self.tcx().def_span(def_id),
    "the declaration must be marked with `#[type_const]`",
);

I wasn't able to make it not print the source location - referring to a compiletest auxiliary crate printed the true source location, as did referring to std::path::MAIN_SEPARATOR

  • does def_span return DUMMY_SP on unknown spans? does span_note handle DUMMY_SP cleanly?
  • or is source just, always available, I guess? (I'm used to C# where it's not, haha)

Relatedly, printing "hey you need #[type_const] on this item" when the item is in std isn't super helpful, and also when it's in a crate you don't control - but if it's in a crate you do control, maybe you do want that message, so idk. In any case, I think if we decide to stabilize #[type_const] (maybe we don't), this error needs additional work (make it a proper autofix suggestion, etc.) so maybe it's fine to leave it for now.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At the end of compiling a crate we'll serialize a bunch of information to disk to allow for accessing information in cross-crate circumstances. Spans of DefIds are one such case.

The source of other crates isnt available only some of the information we computed from it.

I agree that we probably want to customise the diagnostic here for cases when the DefId is non-local 🤔

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can use DefId::is_local/DefId::as_local (https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.DefId.html#method.as_local) to figure out if a DefId is from the current crate or not

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok im fancy and did a suggestion :3

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i like it!

|

error: aborting due to 1 previous error

Loading