TMI: Loose ends
Jun. 13th, 2012 01:05 am![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
It's late and I've been too hot on the trail of various bugs (or at least feeling like I was) to write a post, but I don't want to get too much out of the habit of writing.
On Friday I was working on two bugs. The first had to do with changing comm to use classes. The bug wasn't what I thought it was at all. Instead, it was just that the destructors for port_ptrs weren't running at all when the call to port was in a different crate than core. That explained the behavior where the destructor would run if it was called from within the core crate, but not when run from the driver. This was because the serialization code just wasn't handling the case where a destructor had type parameters and thus needed to be inlined, and written into the crate metadata. Once I implemented that, the memory leak went away (obviously, since the destructor was now running). But then some of the unit tests for core::comm started failing because of memory leaks -- different ones, involving strings instead of ports. So I'm still working on that. In any case, my triumph was narrowing down the test case so my test case wasn't the entire compiler -- I was able to separate the relevant parts of comm and get them to compile separately. That really made debugging a lot easier.
The other bug from Friday turned out to be because I just didn't understand the syntax for warn attributes, and an attribute that I thought applied to the whole module applied to just one item (the wrong one). Once I realized that, I was able to make a test case that tested what I wanted.
Yesterday (I think) I started on changing the trans::common::block type to be a class instead of a record. This was just a minor cleanup thing that was called out in a FIXME comment. But it turned out to expose two different bugs: first, that it's possible to make either the typechecker or trans (I'm still not sure which) go into an infinite loop with a mutually-recursive class and type synonym (so class T has a U field, where U is a type synonym for a type that mentions T directly). Second, that once you break the cycle by changing the type synonym to what's analogous to a Haskell newtype (written like enum T = U in Rust), there was a bug (or, perhaps, unexpected behavior) in the "borrow checking" pass in the compiler that would reject a bunch of code involving a mutable block field in some other data structure. Intuitively I'd expect T to be treated just like U if I've written one of those newtype-like declarations, but the borrow checking code wasn't working that way. Once I pointed this out to Niko and he fixed it, he also pointed out that I would still have to change the argument mode on a bunch of functions to allow borrow checking to work with this type -- but since the plan is to get rid of argument modes soon, this should be a temporary fix. So I was able to finish that today.
So I guess this wasn't such a short post, but it could have been a lot longer!
On Friday I was working on two bugs. The first had to do with changing comm to use classes. The bug wasn't what I thought it was at all. Instead, it was just that the destructors for port_ptrs weren't running at all when the call to port was in a different crate than core. That explained the behavior where the destructor would run if it was called from within the core crate, but not when run from the driver. This was because the serialization code just wasn't handling the case where a destructor had type parameters and thus needed to be inlined, and written into the crate metadata. Once I implemented that, the memory leak went away (obviously, since the destructor was now running). But then some of the unit tests for core::comm started failing because of memory leaks -- different ones, involving strings instead of ports. So I'm still working on that. In any case, my triumph was narrowing down the test case so my test case wasn't the entire compiler -- I was able to separate the relevant parts of comm and get them to compile separately. That really made debugging a lot easier.
The other bug from Friday turned out to be because I just didn't understand the syntax for warn attributes, and an attribute that I thought applied to the whole module applied to just one item (the wrong one). Once I realized that, I was able to make a test case that tested what I wanted.
Yesterday (I think) I started on changing the trans::common::block type to be a class instead of a record. This was just a minor cleanup thing that was called out in a FIXME comment. But it turned out to expose two different bugs: first, that it's possible to make either the typechecker or trans (I'm still not sure which) go into an infinite loop with a mutually-recursive class and type synonym (so class T has a U field, where U is a type synonym for a type that mentions T directly). Second, that once you break the cycle by changing the type synonym to what's analogous to a Haskell newtype (written like enum T = U in Rust), there was a bug (or, perhaps, unexpected behavior) in the "borrow checking" pass in the compiler that would reject a bunch of code involving a mutable block field in some other data structure. Intuitively I'd expect T to be treated just like U if I've written one of those newtype-like declarations, but the borrow checking code wasn't working that way. Once I pointed this out to Niko and he fixed it, he also pointed out that I would still have to change the argument mode on a bunch of functions to allow borrow checking to work with this type -- but since the plan is to get rid of argument modes soon, this should be a temporary fix. So I was able to finish that today.
So I guess this wasn't such a short post, but it could have been a lot longer!