-
Notifications
You must be signed in to change notification settings - Fork 97
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
Resolve paths in kani::stub
attributes (ignoring use
statements)
#1999
Resolve paths in kani::stub
attributes (ignoring use
statements)
#1999
Conversation
f976d55
to
b11edcd
Compare
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.
I still have to go through the tests in this PR, but overall I think this is a great improvement to the user experience.
The logic here is fairly complicated, so I would like to ask you to add some debug!()
and trace!()
statements to help future development. Especially when things go wrong. There are a lot of places inside resolve.rs
that you return None
, which basically means that we fail resolution. It would be great to know which path we took to get there.
Another thing to consider is to give a more informative error when resolution fails. Let's say we fail in the following resolution:
::my_crate::my_module::my_function
If we fail while processing my_crate
, the error could say something like fail to find crate "my_crate"
. But if we have found my_crate
, but not my_module
, we can say couldn't find "my_module" inside "my_crate"
.
I'm OK if we leave the more detailed error for later, but you might want to consider at least what mechanism we should use to pass this error. For example, right now we discard whatever we process. We are also returning Option<>
everywhere, should we consider using Result<>
instead or should we just trigger the error whenever we find it?
#[derive(Debug)] | ||
struct Path { | ||
base: Base, | ||
segments: Segments, |
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 you please document that if may_be_external_path
is true, then segments cannot be 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.
Done
// `self` may be followed be `super` (handled below). | ||
let mut may_be_external_path = true; | ||
let first = segments[0].as_str(); | ||
if first == ROOT { |
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 you please replace this by match block?
match first {
ROOT => {}
SELF => {}
...
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.
Done
/// structure, resolving qualifiers (like `crate`, etc.) along the way. | ||
fn to_path(tcx: TyCtxt, current_module: LocalDefId, name: &str) -> Option<Path> { | ||
const CRATE: &str = "crate"; | ||
const ROOT: &str = "{{root}}"; |
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 this how the compiler maps initial "::"?
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.
Exactly. I added a comment
|
||
// Resolve qualifiers `crate`, initial `::`, and `self`. The qualifier | ||
// `self` may be followed be `super` (handled below). | ||
let mut may_be_external_path = true; |
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.
For readability, I would recommend inspecting the first element and assigning the proper value here. Something like:
let may_be_external_path = !matches!(first, CRATE, SELF, SUPER);
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.
This is cleaner! Done
type Item = (u64, u64); | ||
let item_to_def_id = |item: Item| -> DefId { | ||
let hash = DefPathHash(Fingerprint::new(item.0, item.1)); | ||
tcx.def_path_hash_to_def_id(hash, &mut || panic!()) |
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.
Maybe a friendly error would be nice here. Something on the terms that this is likely due to a Kani issue, please file a bug report.
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.
I checked, and the panic is caught by our panic handler, so the user does receive a message to that effect
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.
Thanks!
@@ -0,0 +1,236 @@ | |||
// Copyright Kani Contributors | |||
// SPDX-License-Identifier: Apache-2.0 OR MIT | |||
//! This module contains code for resolving strings to `DefId`s. |
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 you please expand this description? What kind of strings are we talking about? Does this module cover any string that represents a path? Do we support fully qualified paths? Maybe adding a link to the path syntax might help too: https://doc.rust-lang.org/reference/paths.html.
Which brings me a question, do we support qualified paths?
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.
Looking through the open issues kind of answers my last question about qualified paths: #1997
But I think it would be great if we can explicitly state that we are only handling simple paths and add a link to its definition: https://doc.rust-lang.org/reference/paths.html#simple-paths
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.
I've updated some comments to make this clearer (and included the link for simple paths)
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.
Thank you! BTW, great tests!
BTW, I create #2013 to track improvements to the stubbing error formats. |
bb5a0e2
to
d58d896
Compare
d58d896
to
ba93bc6
Compare
Thanks for taking a look! I've added traces so that we now get debug output like this:
Thanks! I think we should be able to support better errors by (as you suggest) changing the |
Description of changes:
Currently, when we resolve paths in
kani::stub
attributes we do not take into account the module of the harness and we do not support the path qualifierscrate
,self
,super
, and initial::
. This PR improves our path resolution algorithm to take into account the module of the harness (so we resolve relative paths correctly) and adds support for those qualifiers.It does not handle
use
statements (as inuse XXX;
oruse XXX as YYY;
); they will be addressed in a separate PR (tracked in #1998).Resolved issues:
Related to #1866
Resolves #1894
Call-outs:
Previously, we represented a stub mapping (mapping original functions/methods to their replacements) as a
FxHashMap<String, String>
, and then did a linear lookup in the HIR during the MIR transformation to try to find a function/method with the same string representation. Since we are actually resolving paths now when processing the attributes (and constructing the stub mappings), this PR uses aFxHashMap<DefPathHash, DefPathHash>
instead, which is more robust and removes the need for that linear lookup. ADefPathHash
is stable across crate and compilation boundaries.Testing:
How is this change tested? Existing tests and new tests
Is this a refactor change? No
Checklist
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.