Skip to content

Commit 6ffda7e

Browse files
committed
---
yaml --- r: 38892 b: refs/heads/incoming c: 2904095 h: refs/heads/master v: v3
1 parent b567ecf commit 6ffda7e

File tree

12 files changed

+201
-24
lines changed

12 files changed

+201
-24
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ refs/heads/try: 3d5418789064fdb463e872a4e651af1c628a3650
66
refs/tags/release-0.1: 1f5c5126e96c79d22cb7862f75304136e204f105
77
refs/heads/ndm: f3868061cd7988080c30d6d5bf352a5a5fe2460b
88
refs/heads/try2: a810c03263670238bccd64cabb12a23a46e3a278
9-
refs/heads/incoming: 70886d314d0e49fe652f022139b03c2ddaca7b14
9+
refs/heads/incoming: 29040955709a145842f93fe11d4cd803415020be
1010
refs/heads/dist-snap: 22efa39382d41b084fde1719df7ae8ce5697d8c9
1111
refs/tags/release-0.2: c870d2dffb391e14efb05aa27898f1f6333a9596
1212
refs/tags/release-0.3: b5f0d0f648d9a6153664837026ba1be43d3e2503

branches/incoming/doc/tutorial.md

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -751,25 +751,6 @@ match mypoint {
751751
}
752752
~~~
753753

754-
Structs are the only type in Rust that may have user-defined
755-
destructors, defined with `drop` blocks. Inside a `drop`, the name
756-
`self` refers to the struct's value.
757-
758-
~~~
759-
struct TimeBomb {
760-
explosivity: uint,
761-
762-
drop {
763-
for iter::repeat(self.explosivity) {
764-
io::println(fmt!("blam!"));
765-
}
766-
}
767-
}
768-
~~~
769-
770-
> ***Note***: This destructor syntax is temporary. Eventually destructors
771-
> will be defined for any type using [traits](#traits).
772-
773754
## Enums
774755

775756
Enums are datatypes that have several alternate representations. For
@@ -1909,8 +1890,8 @@ traits are automatically derived and implemented for all applicable
19091890
types by the compiler, and may not be overridden:
19101891

19111892
* `Copy` - Types that can be copied: either implicitly, or explicitly with the
1912-
`copy` operator. All types are copyable unless they are classes
1913-
with destructors or otherwise contain classes with destructors.
1893+
`copy` operator. All types are copyable unless they have destructors or
1894+
contain types with destructors.
19141895

19151896
* `Send` - Sendable (owned) types. All types are sendable unless they
19161897
contain managed boxes, managed closures, or otherwise managed
@@ -1922,6 +1903,28 @@ types by the compiler, and may not be overridden:
19221903
> ***Note:*** These three traits were referred to as 'kinds' in earlier
19231904
> iterations of the language, and often still are.
19241905
1906+
There is also a special trait known as `Drop`. This trait defines one method
1907+
called `finalize`, which is automatically called when value of the a type that
1908+
implements this trait is destroyed, either because the value went out of scope
1909+
or because the garbage collector reclaimed it.
1910+
1911+
~~~
1912+
struct TimeBomb {
1913+
explosivity: uint,
1914+
}
1915+
1916+
impl TimeBomb : Drop {
1917+
fn finalize() {
1918+
for iter::repeat(self.explosivity) {
1919+
io::println("blam!");
1920+
}
1921+
}
1922+
}
1923+
~~~
1924+
1925+
It is illegal to call `finalize` directly. Only code inserted by the compiler
1926+
may call it.
1927+
19251928
## Declaring and implementing traits
19261929

19271930
A trait consists of a set of methods, without bodies, or may be empty,

branches/incoming/src/libcore/core.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ pub use to_str::ToStr;
2828
#[cfg(notest)]
2929
pub use ops::{Const, Copy, Send, Owned};
3030
#[cfg(notest)]
31+
pub use ops::{Drop};
32+
#[cfg(notest)]
3133
pub use ops::{Add, Sub, Mul, Div, Modulo, Neg, BitAnd, BitOr, BitXor};
3234
#[cfg(notest)]
3335
pub use ops::{Shl, Shr, Index};
@@ -38,6 +40,8 @@ extern mod coreops(name = "core", vers = "0.5");
3840
#[cfg(test)]
3941
pub use coreops::ops::{Const, Copy, Send, Owned};
4042
#[cfg(test)]
43+
pub use coreops::ops::{Drop};
44+
#[cfg(test)]
4145
pub use coreops::ops::{Add, Sub, Mul, Div, Modulo, Neg, BitAnd, BitOr};
4246
#[cfg(test)]
4347
pub use coreops::ops::{BitXor};

branches/incoming/src/libcore/ops.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ pub trait Owned {
2323
// Empty.
2424
}
2525

26+
#[lang="drop"]
27+
pub trait Drop {
28+
fn finalize(); // XXX: Rename to "drop"? --pcwalton
29+
}
30+
2631
#[lang="add"]
2732
pub trait Add<RHS,Result> {
2833
pure fn add(rhs: &RHS) -> Result;

branches/incoming/src/rustc/middle/lang_items.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ struct LanguageItems {
2828
mut send_trait: Option<def_id>,
2929
mut owned_trait: Option<def_id>,
3030

31+
mut drop_trait: Option<def_id>,
32+
3133
mut add_trait: Option<def_id>,
3234
mut sub_trait: Option<def_id>,
3335
mut mul_trait: Option<def_id>,
@@ -59,6 +61,8 @@ mod language_items {
5961
send_trait: None,
6062
owned_trait: None,
6163

64+
drop_trait: None,
65+
6266
add_trait: None,
6367
sub_trait: None,
6468
mul_trait: None,
@@ -94,6 +98,8 @@ fn LanguageItemCollector(crate: @crate, session: Session,
9498
item_refs.insert(~"send", &mut items.send_trait);
9599
item_refs.insert(~"owned", &mut items.owned_trait);
96100

101+
item_refs.insert(~"drop", &mut items.drop_trait);
102+
97103
item_refs.insert(~"add", &mut items.add_trait);
98104
item_refs.insert(~"sub", &mut items.sub_trait);
99105
item_refs.insert(~"mul", &mut items.mul_trait);

branches/incoming/src/rustc/middle/ty.rs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,16 @@ type ctxt =
404404
// A mapping from the def ID of an impl to the IDs of the derived
405405
// methods within it.
406406
automatically_derived_methods_for_impl:
407-
HashMap<ast::def_id, @~[ast::def_id]>
407+
HashMap<ast::def_id, @~[ast::def_id]>,
408+
409+
// A mapping from the def ID of an enum or struct type to the def ID
410+
// of the method that implements its destructor. If the type is not
411+
// present in this map, it does not have a destructor. This map is
412+
// populated during the coherence phase of typechecking.
413+
destructor_for_type: HashMap<ast::def_id, ast::def_id>,
414+
415+
// A method will be in this list if and only if it is a destructor.
416+
destructors: HashMap<ast::def_id, ()>
408417
};
409418

410419
enum tbox_flag {
@@ -921,7 +930,9 @@ fn mk_ctxt(s: session::Session,
921930
deriving_struct_methods: HashMap(),
922931
deriving_enum_methods: HashMap(),
923932
automatically_derived_methods: HashMap(),
924-
automatically_derived_methods_for_impl: HashMap()}
933+
automatically_derived_methods_for_impl: HashMap(),
934+
destructor_for_type: HashMap(),
935+
destructors: HashMap()}
925936
}
926937

927938

@@ -3580,6 +3591,11 @@ fn item_path_str(cx: ctxt, id: ast::def_id) -> ~str {
35803591
/* If class_id names a class with a dtor, return Some(the dtor's id).
35813592
Otherwise return none. */
35823593
fn ty_dtor(cx: ctxt, class_id: def_id) -> Option<def_id> {
3594+
match cx.destructor_for_type.find(class_id) {
3595+
Some(method_def_id) => return Some(method_def_id),
3596+
None => {} // Continue.
3597+
}
3598+
35833599
if is_local(class_id) {
35843600
match cx.items.find(class_id.node) {
35853601
Some(ast_map::node_item(@{

branches/incoming/src/rustc/middle/typeck/check/method.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -774,6 +774,7 @@ impl LookupContext {
774774
let fty = self.fn_ty_from_origin(&candidate.origin);
775775

776776
self.enforce_trait_instance_limitations(fty, candidate);
777+
self.enforce_drop_trait_limitations(candidate);
777778

778779
// before we only checked whether self_ty could be a subtype
779780
// of rcvr_ty; now we actually make it so (this may cause
@@ -858,6 +859,25 @@ impl LookupContext {
858859
}
859860
}
860861

862+
fn enforce_drop_trait_limitations(&self, candidate: &Candidate) {
863+
// No code can call the finalize method explicitly.
864+
let bad;
865+
match candidate.origin {
866+
method_static(method_id) | method_self(method_id, _) => {
867+
bad = self.tcx().destructors.contains_key(method_id);
868+
}
869+
method_param({trait_id: trait_id, _}) |
870+
method_trait(trait_id, _, _) => {
871+
bad = self.tcx().destructor_for_type.contains_key(trait_id);
872+
}
873+
}
874+
875+
if bad {
876+
self.tcx().sess.span_err(self.expr.span,
877+
~"explicit call to destructor");
878+
}
879+
}
880+
861881
fn is_relevant(&self, self_ty: ty::t, candidate: &Candidate) -> bool {
862882
debug!("is_relevant(self_ty=%s, candidate=%s)",
863883
self.ty_to_str(self_ty), self.cand_to_str(candidate));

branches/incoming/src/rustc/middle/typeck/coherence.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,11 @@ impl CoherenceChecker {
228228
// coherence checks, because we ensure by construction that no errors
229229
// can happen at link time.
230230
self.add_external_crates();
231+
232+
// Populate the table of destructors. It might seem a bit strange to
233+
// do this here, but it's actually the most convenient place, since
234+
// the coherence tables contain the trait -> type mappings.
235+
self.populate_destructor_table();
231236
}
232237

233238
fn check_implementation(item: @item, associated_traits: ~[@trait_ref]) {
@@ -913,6 +918,58 @@ impl CoherenceChecker {
913918
}
914919
}
915920
}
921+
922+
//
923+
// Destructors
924+
//
925+
926+
fn populate_destructor_table() {
927+
let coherence_info = &self.crate_context.coherence_info;
928+
let tcx = self.crate_context.tcx;
929+
let drop_trait = tcx.lang_items.drop_trait.get();
930+
let impls_opt = coherence_info.extension_methods.find(drop_trait);
931+
932+
let impls;
933+
match impls_opt {
934+
None => return, // No types with (new-style) destructors present.
935+
Some(found_impls) => impls = found_impls
936+
}
937+
938+
for impls.each |impl_info| {
939+
if impl_info.methods.len() < 1 {
940+
// We'll error out later. For now, just don't ICE.
941+
loop;
942+
}
943+
let method_def_id = impl_info.methods[0].did;
944+
945+
let self_type = self.get_self_type_for_implementation(*impl_info);
946+
match ty::get(self_type.ty).sty {
947+
ty::ty_class(type_def_id, _) => {
948+
tcx.destructor_for_type.insert(type_def_id, method_def_id);
949+
tcx.destructors.insert(method_def_id, ());
950+
}
951+
_ => {
952+
// Destructors only work on nominal types.
953+
if impl_info.did.crate == ast::local_crate {
954+
match tcx.items.find(impl_info.did.node) {
955+
Some(ast_map::node_item(@item, _)) => {
956+
tcx.sess.span_err(item.span,
957+
~"the Drop trait may only \
958+
be implemented on \
959+
structures");
960+
}
961+
_ => {
962+
tcx.sess.bug(~"didn't find impl in ast map");
963+
}
964+
}
965+
} else {
966+
tcx.sess.bug(~"found external impl of Drop trait on \
967+
something other than a struct");
968+
}
969+
}
970+
}
971+
}
972+
}
916973
}
917974

918975
fn check_coherence(crate_context: @crate_ctxt, crate: @crate) {
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
type Foo = @[u8];
2+
3+
impl Foo : Drop { //~ ERROR the Drop trait may only be implemented
4+
fn finalize() {
5+
io::println("kaboom");
6+
}
7+
}
8+
9+
fn main() {
10+
}
11+
12+
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
struct Foo {
2+
x: int
3+
}
4+
5+
impl Foo : Drop {
6+
fn finalize() {
7+
io::println("kaboom");
8+
}
9+
}
10+
11+
fn main() {
12+
let x = Foo { x: 3 };
13+
x.finalize(); //~ ERROR explicit call to destructor
14+
}
15+
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
struct Foo {
2+
x: int
3+
}
4+
5+
trait Bar : Drop {
6+
fn blah();
7+
}
8+
9+
impl Foo : Drop {
10+
fn finalize() {
11+
io::println("kaboom");
12+
}
13+
}
14+
15+
impl Foo : Bar {
16+
fn blah() {
17+
self.finalize(); //~ ERROR explicit call to destructor
18+
}
19+
}
20+
21+
fn main() {
22+
let x = Foo { x: 3 };
23+
}
24+
25+
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
struct Foo {
2+
x: int
3+
}
4+
5+
impl Foo : Drop {
6+
fn finalize() {
7+
io::println("bye");
8+
}
9+
}
10+
11+
fn main() {
12+
let x: Foo = Foo { x: 3 };
13+
}
14+

0 commit comments

Comments
 (0)