tim: Tim with short hair, smiling, wearing a black jacket over a white T-shirt (work)
Tim Chevalier ([personal profile] tim) wrote2012-06-02 01:34 am
Entry tags:

TMI: Eve of destructors

Well, I missed a couple days, due to moving from San Francisco to San José. Turns out that takes effort!

Today, I felt like going back to porting test cases from using resources to using classes with destructors, rather than fixing other bugs. I guess because most of the test cases had turned out to be pretty easy to change, and I wanted to see if I could blow through most of them. Naturally, I found a couple of bugs.

The first one was in ty::ty_needs_drop. As you may recall, most heap data in Rust are automatically reference-counted, and the code generation part of the compiler implements ref counting by generating so-called "take glue" at each site that increments the ref count of a datum, and "drop glue" at each site that decrements a ref count. The "drop glue" has to call the destructor if there is one. It turned out I forgot to add a case for classes to ty::ty_needs_drop at all, so destructors were only running for classes that had fields that "needed a drop" (that is, fields that are or contain pointers into the heap). If a destructor has side effects, then this bug is observable, and fortunately, there was already a test case for resources that made it observable.

Along the way, I decided to close issue 2296 -- "enforce rules about copyability and sendability for classes" -- because it actually started to look pretty easy to fix. Types in Rust have kinds that, among other things, determine whether objects of a given type can be copied (since Rust is a systems language, its type system tries to make it as obvious as possible where implicit copies occur, by making some types non-copyable and requiring annotations on functions whose non-trivial arguments must be copied), or sent (shared between tasks, which is to say, lightweight threads). The spec for classes says that classes should be copyable if all their fields are copyable and they don't have destructors (this makes sense, so that the destructor for a given object never runs more than once) and should be sendable if all their fields are sendable. This rule was almost implemented already, save the part about classes with destructors not being copyable. So I fixed that, and fortuitously, there were already several tests to enforce the fix once I converted them to use classes.

Finally, I had to fix the analysis that checks whether types are inhabited -- that is to say, unlike:

enum t { u(v) }

enum v { w(t) }
Both t and v are uninhabitable because in order to construct an instance of one, you need an instance of the other. We all know there are uses for uninhabited types, but examples like this are probably an error we want to catch. You can construct a mutually recursive set of classes easily enough, as well:
class t {
   let foo: u;
   ...
}

class u {
   let bar: t;
   ...
}
and we should reject that too, but we weren't, since I forgot to add the case to the analysis that checks top-level class items for instantiability. That was an easy fix.

I finished porting over most of the "run-pass" (tests that should compile and run and exit with a success code) and "compile-fail" tests (tests that should fail to compile with a specified error message) -- the ones that are left are notably the ones that require the cycle collector to run destructors. The "run-fail" (tests that should compile, but fail with a non-success exit code when run) tests are yet to do. And that's all that I got to today.


Post a comment in response:

This account has disabled anonymous posting.
(will be screened if not on Access List)
(will be screened if not on Access List)
If you don't have an account you can create one now.
HTML doesn't work in the subject.
More info about formatting