Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upCompile-time checked version of `unimplemented!()` #1911
Comments
jonhoo
referenced this issue
Feb 19, 2017
Closed
proposal: add compile-time version of unimplemented!() #39930
This comment has been minimized.
This comment has been minimized.
|
Posted to internals at https://internals.rust-lang.org/t/compile-time-checked-version-of-unimplemented/4837 |
This comment has been minimized.
This comment has been minimized.
|
I feel like there might be a misunderstanding of having type Your existing macro_rules! incomplete {
() => {{
#[deny(non_snake_case)]
let _mustBeImplemented = ();
unsafe { ::std::mem::uninitialized() }
}}
}Another idea instead of the |
This comment has been minimized.
This comment has been minimized.
|
@cuviper Ah, no, I'm aware of the semantic meaning of unsafe { ::std::mem::uninitialized() }trick, and used |
This comment has been minimized.
This comment has been minimized.
|
I realized that has a type-inference problem if used in statement context, macro_rules! incomplete {
($ty:ty) => {{
#[forbid(non_snake_case)]
let _mustBeImplemented = ();
unsafe { ::std::mem::uninitialized::<$ty>() }
}};
() => { incomplete!(_) }
}
fn main(){
let _x: () = incomplete!(); // inferred type
incomplete!(()); // explicit type `()`
}Also, I think |
This comment has been minimized.
This comment has been minimized.
|
Oh, yeah, good catch. |
This comment has been minimized.
This comment has been minimized.
|
I've also been thinking about whether there's a better way to have the displayed error be more relevant (obviously, having this be a "true" compiler error would be better). I was hoping to use macro_rules! incomplete {
($ty:ty) => {{
if false {
loop{};
#[deny(unreachable_code)]
() // must be implemented
}
unsafe { ::std::mem::uninitialized::<$ty>() }
}};
() => { incomplete!(_) }
}
fn main() {
let _x: () = incomplete!(); // inferred type
incomplete!(()); // explicit type `()`
}namely
though for some reason the warning doesn't seem to be turned into an error (neither does using |
This comment has been minimized.
This comment has been minimized.
|
Hmm, the lint controls don't seem to work on statements -- only on items? Here's a way: #[forbid(unused_must_use)]
fn _incomplete() { Err::<(), ()>(()); }But it gets an extra note about where the lint level was set:
Maybe there's a lint to trigger that's default deny/forbid. |
This comment has been minimized.
This comment has been minimized.
|
Good enough? fn _incomplete() { '_: loop {} }
Still hacky to abuse lints, of course -- not as good as it could be as a real compiler macro. |
This comment has been minimized.
This comment has been minimized.
|
That last one is pretty good. I liked the unreachable code one primarily because the message is very clear, highlighting the |
This comment has been minimized.
This comment has been minimized.
|
FWIW, I made a crate: https://github.com/jonhoo/incomplete. |
This comment has been minimized.
This comment has been minimized.
|
Actually, come to think of it, maybe all I really want is a lint like #![warn(unimplemented)]or #![deny(unimplemented)] |
This comment has been minimized.
This comment has been minimized.
|
I noticed that the |
This comment has been minimized.
This comment has been minimized.
sanmai-NL
commented
Apr 18, 2017
fn my_fn() -> usize {
unimplemented()!;
0
}produces:
Does this suffice to point out left-over |
This comment has been minimized.
This comment has been minimized.
|
@sanmai-NL You mean
|
Centril
added
T-libs
T-lang
labels
Feb 23, 2018
This comment has been minimized.
This comment has been minimized.
|
I believe this is either |
Centril
closed this
Oct 8, 2018
This comment has been minimized.
This comment has been minimized.
|
@Centril I don't think that's quite accurate. |
This comment has been minimized.
This comment has been minimized.
|
@jonhoo so... the only difference between |
Centril
reopened this
Oct 8, 2018
This comment has been minimized.
This comment has been minimized.
burdges
commented
Oct 8, 2018
|
Isn't the goal here |
This comment has been minimized.
This comment has been minimized.
|
@burdges No, there are reasonable cases where I want to run my code when it still has @Centril yes, it's perhaps a little niche, but it would be super handy when doing bigger refactoring. If I'm not mistaken, |
This comment has been minimized.
This comment has been minimized.
cc @oli-obk re. this question |
This comment has been minimized.
This comment has been minimized.
|
No, after checking. all const eval happens after borrow checking and Mir computation for that item. other items may be in different states though. On topic of this feature request. this is doable in clippy and feels niche enough to me to not be in the compiler |
This comment has been minimized.
This comment has been minimized.
|
@oli-obk If this were in clippy it wouldn't actually be useful, because I don't think most developers regularly run clippy. You do however regularly run the compiler. It's an interesting point that |
This comment has been minimized.
This comment has been minimized.
|
(note: the |
This comment has been minimized.
This comment has been minimized.
|
It only runs in the end for the containing item. you might error out immediately on that and never see your other errors. I don't see how being in clippy would make this less useful. Rls will show it, and if your workflow uses this kind of check, then your workflow will just contain clippy from now on That said. This kind of scheme does not fit into queries very well. Any improvements for queries will likely end up reporting these errors earlier again. I do think the grep method is the most reliable one, or doing it in clippy, which doesn't need to uphold the query system As a hack you could create this macro on nightly yourself by using broken inline assembly. |
This comment has been minimized.
This comment has been minimized.
|
Rls will only show it if clippy is enabled :) I'm working on a 50k LOC codebase that wasn't originally written with clippy enabled, so it's not actually feasible to have clippy running all the time (at least not yet) because it generates too much noise. You might be right that for most projects a clippy lint is the way to go, but what would the macro then ever consist of? It would have to also be possible to compile outside of clippy? |
This comment has been minimized.
This comment has been minimized.
burdges
commented
Oct 9, 2018
|
I quite like the idea of
which permits seeing reminders for only a fragment of the tree too. |
This comment has been minimized.
This comment has been minimized.
You can run it all the time and just enable the lints you feel confident about. E.g. leave all lints disabled and just enable the one about You might be right that for most projects a clippy lint is the way to go, but what would the macro then ever consist of? It would just forward to
yes indeed. Without clippy it would just be the same as writing Even easier would be to simply find all |
jonhoo commentedFeb 19, 2017
We all know and love the
unimplemented!()macro for keeping track of things we haven't yet gotten around to. However, it is only checked at runtime if a certain code path is encountered. This is fine in many cases, but when writing new code from scratch (especially when porting), refactoring large amounts of code, or building comprehensive new features, you often have segments of code that you haven't implemented yet, but you know you'll have to.At least for me, it is common to write a chunk of code, but leaving out some annoying edge cases, or maybe logic (like generating a unique identifier) that I want to deal with alter. I know that I will have to complete that block of code before the program does something useful, but I want to do it later. This can be either because I want to complete the main logical flow of the code first, because I haven't figured out how to do that part yet, or simply because I want to see if the rest of my code compiles correctly.
It would be extremely useful to have a variant of
unimplemented!()that would generate a compile-time error if present in my code. Something likeincomplete!(). However, it should have some properties that I believe mean it can't be implemented without some help from the compiler:!forunimplemented!())incomplete!().unimplemented!()does).The closest I've been able to come up with on my own is the following
This will only error out after all compiler passes (2), and since it returns
!, it is sort of usable in place of any expression (1). However, it does not fit (3), because the infinite loop makes the compiler believe that all code following it is dead. Furthermore, the error it produces is obviously not appropriate for what the macro's intent is.NOTE: originally posted as rust-lang/rust#39930, but moved here following @sanmai-NL's suggestion.