diff options
| author | Patrick Walton <pcwalton@mimiga.net> | 2012-11-05 17:50:01 -0800 |
|---|---|---|
| committer | Patrick Walton <pcwalton@mimiga.net> | 2012-11-07 12:34:32 -0800 |
| commit | 29040955709a145842f93fe11d4cd803415020be (patch) | |
| tree | cd27b595087e924d76c4ae1fcb7a91806cb95a44 /src/rustc | |
| parent | 70886d314d0e49fe652f022139b03c2ddaca7b14 (diff) | |
| download | rust-29040955709a145842f93fe11d4cd803415020be.tar.gz rust-29040955709a145842f93fe11d4cd803415020be.zip | |
rustc: Implement the Drop trait. r=brson
Diffstat (limited to 'src/rustc')
| -rw-r--r-- | src/rustc/middle/lang_items.rs | 6 | ||||
| -rw-r--r-- | src/rustc/middle/ty.rs | 20 | ||||
| -rw-r--r-- | src/rustc/middle/typeck/check/method.rs | 20 | ||||
| -rw-r--r-- | src/rustc/middle/typeck/coherence.rs | 57 |
4 files changed, 101 insertions, 2 deletions
diff --git a/src/rustc/middle/lang_items.rs b/src/rustc/middle/lang_items.rs index 383fe2db323..b1d68bee259 100644 --- a/src/rustc/middle/lang_items.rs +++ b/src/rustc/middle/lang_items.rs @@ -28,6 +28,8 @@ struct LanguageItems { mut send_trait: Option<def_id>, mut owned_trait: Option<def_id>, + mut drop_trait: Option<def_id>, + mut add_trait: Option<def_id>, mut sub_trait: Option<def_id>, mut mul_trait: Option<def_id>, @@ -59,6 +61,8 @@ mod language_items { send_trait: None, owned_trait: None, + drop_trait: None, + add_trait: None, sub_trait: None, mul_trait: None, @@ -94,6 +98,8 @@ fn LanguageItemCollector(crate: @crate, session: Session, item_refs.insert(~"send", &mut items.send_trait); item_refs.insert(~"owned", &mut items.owned_trait); + item_refs.insert(~"drop", &mut items.drop_trait); + item_refs.insert(~"add", &mut items.add_trait); item_refs.insert(~"sub", &mut items.sub_trait); item_refs.insert(~"mul", &mut items.mul_trait); diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index 14c5ed5e71e..5e1bccb6c9d 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -404,7 +404,16 @@ type ctxt = // A mapping from the def ID of an impl to the IDs of the derived // methods within it. automatically_derived_methods_for_impl: - HashMap<ast::def_id, @~[ast::def_id]> + HashMap<ast::def_id, @~[ast::def_id]>, + + // A mapping from the def ID of an enum or struct type to the def ID + // of the method that implements its destructor. If the type is not + // present in this map, it does not have a destructor. This map is + // populated during the coherence phase of typechecking. + destructor_for_type: HashMap<ast::def_id, ast::def_id>, + + // A method will be in this list if and only if it is a destructor. + destructors: HashMap<ast::def_id, ()> }; enum tbox_flag { @@ -921,7 +930,9 @@ fn mk_ctxt(s: session::Session, deriving_struct_methods: HashMap(), deriving_enum_methods: HashMap(), automatically_derived_methods: HashMap(), - automatically_derived_methods_for_impl: HashMap()} + automatically_derived_methods_for_impl: HashMap(), + destructor_for_type: HashMap(), + destructors: HashMap()} } @@ -3580,6 +3591,11 @@ fn item_path_str(cx: ctxt, id: ast::def_id) -> ~str { /* If class_id names a class with a dtor, return Some(the dtor's id). Otherwise return none. */ fn ty_dtor(cx: ctxt, class_id: def_id) -> Option<def_id> { + match cx.destructor_for_type.find(class_id) { + Some(method_def_id) => return Some(method_def_id), + None => {} // Continue. + } + if is_local(class_id) { match cx.items.find(class_id.node) { Some(ast_map::node_item(@{ diff --git a/src/rustc/middle/typeck/check/method.rs b/src/rustc/middle/typeck/check/method.rs index dd3f4069a9c..8afd28a5914 100644 --- a/src/rustc/middle/typeck/check/method.rs +++ b/src/rustc/middle/typeck/check/method.rs @@ -774,6 +774,7 @@ impl LookupContext { let fty = self.fn_ty_from_origin(&candidate.origin); self.enforce_trait_instance_limitations(fty, candidate); + self.enforce_drop_trait_limitations(candidate); // before we only checked whether self_ty could be a subtype // of rcvr_ty; now we actually make it so (this may cause @@ -858,6 +859,25 @@ impl LookupContext { } } + fn enforce_drop_trait_limitations(&self, candidate: &Candidate) { + // No code can call the finalize method explicitly. + let bad; + match candidate.origin { + method_static(method_id) | method_self(method_id, _) => { + bad = self.tcx().destructors.contains_key(method_id); + } + method_param({trait_id: trait_id, _}) | + method_trait(trait_id, _, _) => { + bad = self.tcx().destructor_for_type.contains_key(trait_id); + } + } + + if bad { + self.tcx().sess.span_err(self.expr.span, + ~"explicit call to destructor"); + } + } + fn is_relevant(&self, self_ty: ty::t, candidate: &Candidate) -> bool { debug!("is_relevant(self_ty=%s, candidate=%s)", self.ty_to_str(self_ty), self.cand_to_str(candidate)); diff --git a/src/rustc/middle/typeck/coherence.rs b/src/rustc/middle/typeck/coherence.rs index d0ec2b3cfc5..26c559fd135 100644 --- a/src/rustc/middle/typeck/coherence.rs +++ b/src/rustc/middle/typeck/coherence.rs @@ -228,6 +228,11 @@ impl CoherenceChecker { // coherence checks, because we ensure by construction that no errors // can happen at link time. self.add_external_crates(); + + // Populate the table of destructors. It might seem a bit strange to + // do this here, but it's actually the most convenient place, since + // the coherence tables contain the trait -> type mappings. + self.populate_destructor_table(); } fn check_implementation(item: @item, associated_traits: ~[@trait_ref]) { @@ -913,6 +918,58 @@ impl CoherenceChecker { } } } + + // + // Destructors + // + + fn populate_destructor_table() { + let coherence_info = &self.crate_context.coherence_info; + let tcx = self.crate_context.tcx; + let drop_trait = tcx.lang_items.drop_trait.get(); + let impls_opt = coherence_info.extension_methods.find(drop_trait); + + let impls; + match impls_opt { + None => return, // No types with (new-style) destructors present. + Some(found_impls) => impls = found_impls + } + + for impls.each |impl_info| { + if impl_info.methods.len() < 1 { + // We'll error out later. For now, just don't ICE. + loop; + } + let method_def_id = impl_info.methods[0].did; + + let self_type = self.get_self_type_for_implementation(*impl_info); + match ty::get(self_type.ty).sty { + ty::ty_class(type_def_id, _) => { + tcx.destructor_for_type.insert(type_def_id, method_def_id); + tcx.destructors.insert(method_def_id, ()); + } + _ => { + // Destructors only work on nominal types. + if impl_info.did.crate == ast::local_crate { + match tcx.items.find(impl_info.did.node) { + Some(ast_map::node_item(@item, _)) => { + tcx.sess.span_err(item.span, + ~"the Drop trait may only \ + be implemented on \ + structures"); + } + _ => { + tcx.sess.bug(~"didn't find impl in ast map"); + } + } + } else { + tcx.sess.bug(~"found external impl of Drop trait on \ + something other than a struct"); + } + } + } + } + } } fn check_coherence(crate_context: @crate_ctxt, crate: @crate) { |
