Closed rodrimati1992 closed 4 years ago
#![feature(const_type_id)]
#![feature(core_intrinsics)]
pub struct GetTypeId<T>(T);
impl<T: 'static> GetTypeId<T> {
pub const VALUE: u64 = std::intrinsics::type_id::<T>();
}
const fn check_type_id<T: 'static>() -> bool {
matches!(GetTypeId::<T>::VALUE, GetTypeId::<T>::VALUE)
}
fn main() {
assert!(check_type_id::<usize>());
}
Seems something wrong with the intrinsics evaluation.
I think the issue is that TyKind::Param is in place when we try to hash Ty
. I am not very familiar with the code here but I think this might be evaluated before monomorphization which causes this issue.
Another example showing this is pre-monomorphization:
#![feature(const_type_id)]
#![feature(core_intrinsics)]
struct X([u8; std::intrinsics::type_id::<Self>() as usize]);
fn main() {
let _ = std::mem::MaybeUninit::<X>::uninit();
}
rustc happily compiles this, but I would expect something like cycle detected when const-evaluating + checking X::0::{{constant}}#0
.
I was trying to do something somewhat similar with const type_id when I filed #72602. There seem to be some inconsistencies in what combinations of generics and patterns are allowed, which might be contributing to the problem.
I have no idea what is going on, but it certainly looks odd... Cc @rust-lang/wg-const-eval @eddyb @nikomatsakis
https://github.com/rust-lang/rust/blob/cd1a46d644791c79433db934ad4e6131c577efcc/src/librustc_mir/interpret/intrinsics.rs#L71 needs to monomorphize the type before evaluating it I'd guess (an assert checking for needs_subst
would make sense there, too I'd think).
@oli-obk I wonder if instead of needs_subst
we should more explicitly check for "type or const params", but I think it's mostly about aesthetics thanks to miri working with lifetime-erased types.
You said "assert" but I think the type is already monomorphized and what we need to do is return TooGeneric
if it's not monomorphic. Same for type_name
, actually - any reflection that doesn't rely on layout_of
will have this problem.
oh right, this may be an evaluation happening too early, so TooGeneric
is totally reasonable to emit here. I'm always wary of emitting TooGeneric
.
oh right, this may be an evaluation happening too early, so
TooGeneric
is totally reasonable to emit here. I'm always wary of emittingTooGeneric
.
Doesn't that mean that the code samples above will be forbidden?
No, just evaluating the consts early will fail. Once everything is monomorphized it will work.
No, just evaluating the consts early will fail. Once everything is monomorphized it will work.
I have an attempt here: https://github.com/nbdd0121/rust/tree/issue-73976. It prevents OP's snippet from compiling:
error: could not evaluate constant pattern
--> test.rs:12:37
|
12 | matches!(GetTypeId::<T>::VALUE, GetTypeId::<T>::VALUE)
| ^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
hmm... maybe const prop is interfering here. Can you try running the same build with -Ztreat-err-as-bug
and RUST_BACKTRACE=1
?
error: could not evaluate constant pattern
--> test.rs:13:37
|
13 | matches!(GetTypeId::<T>::VALUE, GetTypeId::<T>::VALUE)
| ^^^^^^^^^^^^^^^^^^^^^
thread 'rustc' panicked at 'aborting due to `-Z treat-err-as-bug=1`', src/librustc_errors/lib.rs:942:13
stack backtrace:
0: <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt
1: core::fmt::write
2: std::io::Write::write_fmt
3: std::panicking::default_hook::{{closure}}
4: std::panicking::default_hook
5: rustc_driver::report_ice
6: std::panicking::rust_panic_with_hook
7: std::panicking::begin_panic
8: rustc_errors::HandlerInner::emit_diagnostic
9: rustc_errors::Handler::emit_diag_at_span
10: rustc_mir_build::hair::pattern::PatCtxt::lower_path
11: rustc_mir_build::hair::pattern::PatCtxt::lower_pattern
12: rustc_mir_build::hair::pattern::check_match::MatchVisitor::lower_pattern
13: <core::iter::adapters::Map<I,F> as core::iter::traits::iterator::Iterator>::fold
14: <rustc_mir_build::hair::pattern::check_match::MatchVisitor as rustc_hir::intravisit::Visitor>::visit_expr
15: <rustc_mir_build::hair::pattern::check_match::MatchVisitor as rustc_hir::intravisit::Visitor>::visit_expr
16: rustc_mir_build::hair::pattern::check_match::check_match
17: rustc_middle::ty::query::<impl rustc_query_system::query::config::QueryAccessors<rustc_middle::ty::context::TyCtxt> for rustc_middle::ty::query::queries::check_match>::compute
18: rustc_query_system::dep_graph::graph::DepGraph<K>::with_task_impl
19: rustc_data_structures::stack::ensure_sufficient_stack
20: rustc_query_system::query::plumbing::get_query_impl
21: rustc_query_system::query::plumbing::ensure_query_impl
22: rustc_session::utils::<impl rustc_session::session::Session>::time
23: rustc_session::utils::<impl rustc_session::session::Session>::time
24: rustc_interface::passes::analysis
25: rustc_middle::ty::query::<impl rustc_query_system::query::config::QueryAccessors<rustc_middle::ty::context::TyCtxt> for rustc_middle::ty::query::queries::analysis>::compute
26: rustc_query_system::dep_graph::graph::DepGraph<K>::with_task_impl
27: rustc_data_structures::stack::ensure_sufficient_stack
28: rustc_query_system::query::plumbing::get_query_impl
29: rustc_middle::ty::context::tls::enter_global
30: rustc_interface::interface::run_compiler_in_existing_thread_pool
31: scoped_tls::ScopedKey<T>::set
32: rustc_ast::attr::with_globals
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
error: internal compiler error: unexpected panic
note: the compiler unexpectedly panicked. this is a bug.
note: we would appreciate a bug report: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports
note: rustc 1.46.0-dev running on x86_64-unknown-linux-gnu
note: compiler flags: -Z treat-err-as-bug
Ah, so this is a different issue. It's the same issue (even if a different symptom) of running
struct Foo<T>(T);
impl<T> Foo<T> {
const BAR: usize = std::mem::size_of::<T>();
}
fn muh<T>() {
match 42 {
Foo::<T>::BAR => {}
_ => {}
}
}
Patterns need to be monomorphic, you can never have a pattern that depends on generic parameters. We may lift this restriction in the future, but it's a separate issue and needs a language RFC afaik
struct Foo<T>(T); impl<T> Foo<T> { const BAR: usize = std::mem::size_of::<T>(); } fn muh<T>() { match 42 { Foo::<T>::BAR => {} _ => {} } }
This gives:
error[E0158]: associated consts cannot be referenced in patterns
in stable and gives
error: could not evaluate constant pattern
in nightly.
We will need a better diagnostics for the TooGeneric error.
struct Foo<T>(T);
impl<T> Foo<T> {
const BAR: usize = 42;
}
fn muh<T>() {
match 42 {
Foo::<T>::BAR => {}
_ => {}
}
}
works on stable, so the old diagnostic was wrong. It's specifically associated constants that depend on generic parameters.
@oli-obk so is the approach of returning TooGeneric
all we need to do here? If so @nbdd0121 would you be happy to open your branch as a PR so we could look at adding some ui tests and whatnot?
@KodrAus The thing I worried is that the error error: could not evaluate constant pattern
isn't very helpful. Maybe fixing that diagnostics should be a separate PR?
Yea, cleaning up the diagnostics can be done after fixing the bug
I tried this code: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=57bb53139f14a69326e005ea9d9f7cd7
I expected the code to run without errors
Instead, the assertion failed.
Meta
Compiler version: 1.46.0-nightly (2020-07-01 f781babf87dea29c44f9)