-
Notifications
You must be signed in to change notification settings - Fork 698
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
Use fix point analysis to implement can_derive_debug #824
Conversation
Thanks for the pull request, and welcome! The Servo team is excited to review your changes, and you should hear from @fitzgen (or someone else) soon. |
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 looks right to me, will have to take a look at the errors to get a better idea of what is going wrong.
src/ir/can_derive_debug.rs
Outdated
let ty_kind = ty.map(|ty| ty.kind()); | ||
|
||
match ty_kind { | ||
Some(&TypeKind::Void) | |
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.
Since we only care about types here, we should exit the function early with non-types, which will get rid of these annoying Some(...)
s and the unwrap
s:
let ty = match item.as_type() {
None => return false,
Some(ty) => ty
};
match ty.kind() {
...
}
src/ir/can_derive_debug.rs
Outdated
@@ -0,0 +1,269 @@ | |||
use super::analysis::MonotoneFramework; |
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.
nitpick: need a module doc comment, or the tests will fail with --features testing_only_docs
:
//! Determining which types for which we can emit `#[derive(Debug)]`.
src/ir/can_derive_debug.rs
Outdated
use ir::comp::CompKind; | ||
|
||
#[derive(Debug, Clone)] | ||
pub struct CanDeriveDebugAnalysis<'ctx, 'gen> |
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.
nitpick: and a doc comment here.
See the doc comment above the UsedTemplateParameters
type; the doc comment should help readers understand how this analysis works, why its domain is a finite height lattice and we will therefore definitely reach a fixed point, an overview of the constraining operations for different items/types are, etc...
src/ir/context.rs
Outdated
@@ -1652,6 +1659,21 @@ impl<'ctx> BindgenContext<'ctx> { | |||
pub fn need_bindegen_complex_type(&self) -> bool { | |||
self.generated_bindegen_complex.get() | |||
} | |||
|
|||
/// compute whether we can derive debug |
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.
nitpick: please capitalize and punctuate sentences:
/// Compute whether we can derive `Debug` for each type.
src/ir/context.rs
Outdated
self.can_derive_debug = Some(analyze::<CanDeriveDebugAnalysis>(self)); | ||
} | ||
|
||
pub fn lookup_item_id_can_derive_debug(&self, id: ItemId) -> bool { |
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.
nitpick: this will also need a doc comment.
src/ir/item.rs
Outdated
.map_or(true, |l| l.opaque().can_derive_debug(ctx, ())) | ||
} else { | ||
ty.can_derive_debug(ctx, ()) | ||
ctx.options().derive_debug && |
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.
When ctx.options().derive_debug
, the whole rest of the method should just be call to lookup_item_id_can_derive_debug
now.
src/ir/can_derive_debug.rs
Outdated
Some(&TypeKind::Pointer(inner)) => { | ||
let inner_type = self.ctx.resolve_type(inner); | ||
if let TypeKind::Function(ref sig) = | ||
*inner_type.canonical_type (self.ctx).kind() { |
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.
nitpick: no space between the method name and parentheses:
inner_type.canonical_type(self.ctx)
Here is --- expected: "/home/travis/build/servo/rust-bindgen/tests/expectations/tests/inner_template_self.rs"
+++ generated from: "/home/travis/build/servo/rust-bindgen/tests/headers/inner_template_self.hpp"
/* automatically generated by rust-bindgen */
#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
#[repr(C)]
-#[derive(Debug, Copy, Clone)]
+#[derive(Copy, Clone)]
pub struct LinkedList {
pub next: *mut LinkedList,
pub prev: *mut LinkedList,
}
impl Default for LinkedList {
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
#[repr(C)]
-#[derive(Debug, Copy)]
+#[derive(Copy)]
pub struct InstantiateIt {
pub m_list: LinkedList,
} Pointers are always |
src/ir/can_derive_debug.rs
Outdated
if self.can_derive_debug.contains(&inner) { | ||
self.can_derive_debug.insert(id); | ||
return 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.
There should be no check whether the pointed-to inner
type is in the set or not: pointers can always derive Debug
(its just their address) so the non-function pointer case should simply be this:
self.can_derive_debug.insert(id);
return true;
I think that should fix most of the test failures. If not, then let's look at which tests are still failing after fixing that. |
After the above fix and move the consider edge a bit, it fails 15 tests now. I'm not so sure about whether the edge I'm adding is correct or not. The next failure is
|
src/ir/can_derive_debug.rs
Outdated
true | ||
}, | ||
&TypeKind::Opaque => { | ||
if ty.layout(self.ctx) |
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.
In the original implementation, the Opaque type is always true. Should I do that or uses the current implementation?
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.
Let's try and translate exactly what master is doing into the constraint function.
src/ir/can_derive_debug.rs
Outdated
match ty.kind() { | ||
&TypeKind::Void | | ||
&TypeKind::NullPtr | | ||
&TypeKind::Int(..) | |
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.
To avoid all the repeated &
s, we can match *ty.kind() { ... }
I'd suggest working on getting the smaller (and therefore usually simpler) test cases passing before working on larger ones. Often, the root cause of the issue will be the same in a larger test case, but easier to understand in a smaller setting that has less extra context, and then when you fix it for the small test case, the larger test case is also fixed. It looks like --- expected: "/home/travis/build/servo/rust-bindgen/tests/expectations/tests/template-param-usage-15.rs"
+++ generated from: "/home/travis/build/servo/rust-bindgen/tests/headers/template-param-usage-15.hpp"
/* automatically generated by rust-bindgen */
#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct BaseUsesT<T> {
pub usage: *mut T,
pub _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell<T>>,
}
impl <T> Default for BaseUsesT<T> {
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
}
#[repr(C)]
-#[derive(Debug, Copy, Clone)]
+#[derive(Copy, Clone)]
pub struct CrtpIgnoresU {
pub _base: BaseUsesT<CrtpIgnoresU>,
pub y: ::std::os::raw::c_int,
}
impl Default for CrtpIgnoresU {
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
} It looks like maybe the |
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 looks really great!
There are just a few things to change before landing, mostly nitpicks, see below.
Thanks a ton @photoszzt ! :)
src/ir/can_derive_debug.rs
Outdated
|
||
/// An analysis that finds for each IR item whether debug can be derived. | ||
/// | ||
/// TODO More comments before merge |
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.
TODO ;)
src/ir/can_derive_debug.rs
Outdated
|
||
// The incremental result of this analysis's computation. Everything in this | ||
// set can derive debug. | ||
cant_derive_debug: HashSet<ItemId>, |
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.
The comment needs to be updated.
src/ir/can_derive_debug.rs
Outdated
EdgeKind::TemplateDeclaration | | ||
EdgeKind::TemplateParameterDefinition | | ||
EdgeKind::InnerType | | ||
EdgeKind::InnerVar => 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.
I'm a bit surprised to see InnerType
and InnerVar
here. How can they affect whether a type can derive debug or not?
src/ir/can_derive_debug.rs
Outdated
} | ||
|
||
impl<'ctx, 'gen> CantDeriveDebugAnalysis<'ctx, 'gen> { | ||
// Don't know where to call this method |
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.
It's called now, so I think this comment can be removed ;)
src/ir/can_derive_debug.rs
Outdated
} | ||
let consider_base = info.base_members() | ||
.iter() | ||
.all(|base| !self.cant_derive_debug.contains(&base.ty)); |
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.
Each of the places where we do something like
let things_can_derive = things.all(|thing| !self.cant_derive_debug.contains(thing));
should become
let things_cant_derive = things.any(|thing| self.cant_derive_debug.contains(thing));
Its equivalent (de Morgan's) but the latter reads much more naturally.
Additionally, we should early return whenever we find something that would cause us to update the cant_derive_debug
set, rather than continuing to consider (for example) fields even after we know we can't derive debug because of the bases.
That is, we should do something like this:
let bases_cant_derive = ...;
if bases_cant_derive {
self.cant_derive_debug.insert(id);
return true;
}
let fields_cant_derive = ...;
if fields_cant_derive {
self.cant_derive_debug.insert(id);
return true;
}
false
To avoid repeating the insert-into-the-set-and-then-return-true dance over and over, we can define a helper:
impl CantDeriveDebugAnalysis {
...
fn insert(&mut self, id: ItemId) -> bool {
let was_already_in = self.cant_derive_debug.insert(&id);
assert!(
!was_already_in,
"We shouldn't try and insert twice because if it was already in the set, \
`constrain` would have exited early."
);
true
}
}
src/ir/ty.rs
Outdated
inst.can_derive_debug(ctx, self.layout(ctx)) | ||
} | ||
_ => 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.
Are there any other CanDeriveDebug
impls that are now unused and we can remove? I'd try commenting all of them out other than Item
and ItemId
and see if any call sites start failing to compile, and then look at each of those call sites and determine whether it would be easier to just use an Item
/ItemId
impl or to uncomment the impl that was being used. I expect most of them are handled by Item
and ItemId
.
We should at minimum be able to delete the detect_can_derive_debug_cycle
member from CompInfo
and its CanDeriveDebug
impl as well.
src/ir/context.rs
Outdated
@@ -1652,6 +1660,23 @@ impl<'ctx> BindgenContext<'ctx> { | |||
pub fn need_bindegen_complex_type(&self) -> bool { | |||
self.generated_bindegen_complex.get() | |||
} | |||
|
|||
/// Compute whether we can derive debug |
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.
Nitpick: missing a period.
src/ir/context.rs
Outdated
@@ -169,6 +170,11 @@ pub struct BindgenContext<'ctx> { | |||
|
|||
/// Whether we need the mangling hack which removes the prefixing underscore. | |||
needs_mangling_hack: bool, | |||
|
|||
/// Set of ItemId that can't derive debug |
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.
Nitpick: missing a period.
src/ir/can_derive_debug.rs
Outdated
TypeKind::Comp(ref info) => { | ||
if info.has_non_type_template_params() { | ||
if ty.layout(self.ctx).map_or(false, | ||
|l| l.opaque().can_derive_debug(self.ctx, ())) { |
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.
Nitpick: funky indentation
@photoszzt, looks like there are compilation errors with the latest commit:
|
☔ The latest upstream changes (presumably #823) made this pull request unmergeable. Please resolve the merge conflicts. |
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 for sticking this one out!
@bors-servo r+ |
📌 Commit 01c609c has been approved by |
☀️ Test successful - status-travis |
…derive debug analysis. We have a special-case for them in codegen to generate a blob, that can derive debug. This is a regression from rust-lang#824, and hit stylo.
…derive debug analysis. We have a special-case for them in codegen to generate a blob, that can derive debug. This is a regression from rust-lang#824, and hit stylo.
analysis: Account for template instantiations of opaque types in the derive debug analysis. We have a special-case for them in codegen to generate a blob, that can derive debug. This is a regression from #824, and hit stylo.
…derive debug analysis. We have a special-case for them in codegen to generate a blob, that can derive debug. This is a regression from rust-lang#824, and hit stylo.
It's failing about 30 tests now and most of them is related to template. I'm also not so sure about the place to call compute_can_derive_debug in gen.
Fix: #767
r? @fitzgen