-
Notifications
You must be signed in to change notification settings - Fork 78
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Generate our own impl block names for consistency between ghost/erased runs of rustc #709
base: main
Are you sure you want to change the base?
Conversation
Example:
old SMT:
new SMT:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, this numbering is not necessarily consistent between the keep-ghost-code run of rustc and the erased-ghost-code run of rustc.
Why is this important?
source/rust_verify/src/names.rs
Outdated
TyKind::Bound(..) => TypTree::String(ty.to_string()), | ||
|
||
TyKind::FnDef(..) => TypTree::String("fndef".to_string()), | ||
TyKind::FnPtr(..) => TypTree::String("fnptr".to_string()), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do FnDef and FnPtr not include type arguments?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These should probably be unsupported_err!
, as in mid_ty_to_vir_ghost
. I just have to set up the spans and Result
return types so that these errors would get reported properly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I updated the pull request to use unsupported_err!
If this issue happens while compiling vstd, the compiled rust library will have different names from the serialized VIR (in the persisted .vir file). This causes Verus to fail to find the expected names in the .vir file in code that uses vstd. We never saw this before because it happened that the names always matched up, but in recent experiments on the https://github.com/verus-lang/verus/tree/rustc_build branch this has actually happened (before using the fix in this PR). |
source/vir/src/def.rs
Outdated
@@ -66,6 +66,7 @@ const SUBST_RENAME_SEPARATOR: &str = "$$"; | |||
const KRATE_SEPARATOR: &str = "!"; | |||
const PATH_SEPARATOR: &str = "."; | |||
const PATHS_SEPARATOR: &str = "/"; | |||
const IMPL_SEPARATOR: &str = "/"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it OK for the IMPL_SEPARATOR to be the same as the PATHS_SEPARATOR? the impl name can be part of a path, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. I changed IMPL_SEPARATOR to "&/".
I don't understand the function of |
I renamed this to
|
So it's just a stringified version of the DefPath? Is it not possible to use the DefPath or DefId as the key? |
I took a closer look at this. Also, the code for |
Hm, ok, there's still something I'm missing here. Why does |
This was also confusing for me while I was writing the code, so it's probably good to document the approach better. I added more comments describing a typical scenario:
|
OK, I think I get it now. Just to check, we use the fingerprinting in order to make sure these two things map to the same Ident:
But the fingerprints don't get serialized, the thing we serialize is the erase_ghost mapping, which matches the rlib file? |
} | ||
|
||
fn def_path_to_path<'tcx>(tcx: TyCtxt<'tcx>, def_path: DefPath) -> TypPath { | ||
def_path_to_rustc_id(tcx, def_path, usize::MAX).0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add an assert here that the disambiguator list we're ignoring is empty?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add an assert here that the disambiguator list we're ignoring is empty?
I just tried this:
fn def_path_to_path<'tcx>(tcx: TyCtxt<'tcx>, def_path: DefPath) -> TypPath {
let (path, disambiguators) = def_path_to_rustc_id(tcx, def_path, usize::MAX);
assert!(disambiguators.len() == 0);
path
}
However, this assertion fails for nested impls (which, admittedly, we don't support yet, but we could in the future, and names.rs
is intended to account for this):
struct S;
impl S {
fn f() {
struct Q;
impl Q {
fn g() {}
}
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I... had no idea nested impls were a thing.
Can you give a rough argument why the fingerprinting is sound even when disambiguators are thrown away?
yes |
yes |
Good point. The fingerprints had been unnecessarily marked Serialize, Deserialize. I just removed that. |
Previously, our VIR paths contained rustc-generated segments like "impl%0" and "impl%1", using rustc's numbering for the "impl%n" names. Unfortunately, this numbering is not necessarily consistent between the keep-ghost-code run of rustc and the erased-ghost-code run of rustc. Therefore, this pull request generates our own unique names for impl blocks independent of rustc's numbering.
The generated unique names include abbreviations of the datatype and (optionally) trait name for each impl block, so this pull request also has the side effect of making the VIR names more readable.