]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc/metadata/decoder.rs
rollup merge of #17355 : gamazeps/issue17210
[rust.git] / src / librustc / metadata / decoder.rs
index c9807a18383e8ef5bc932222cfb55f306e44b121..ac7f83cb385c2d6f8c12ee230d477e815c844136 100644 (file)
 use metadata::csearch::StaticMethodInfo;
 use metadata::csearch;
 use metadata::cstore;
-use metadata::tydecode::{parse_ty_data, parse_def_id,
-                         parse_type_param_def_data,
+use metadata::tydecode::{parse_ty_data, parse_region_data, parse_def_id,
+                         parse_type_param_def_data, parse_bounds_data,
                          parse_bare_fn_ty_data, parse_trait_ref_data};
-use middle::lang_items;
 use middle::def;
+use middle::lang_items;
+use middle::resolve::{TraitItemKind, TypeTraitItemKind};
 use middle::subst;
 use middle::ty::{ImplContainer, TraitContainer};
 use middle::ty;
 use middle::typeck;
 use middle::astencode::vtable_decoder_helpers;
 
-use std::gc::Gc;
 use std::hash::Hash;
 use std::hash;
 use std::io::extensions::u64_from_be_bytes;
@@ -47,6 +47,7 @@
 use syntax::print::pprust;
 use syntax::ast;
 use syntax::codemap;
+use syntax::ptr::P;
 
 pub type Cmd<'a> = &'a crate_metadata;
 
@@ -165,9 +166,11 @@ fn item_visibility(item: rbml::Doc) -> ast::Visibility {
     }
 }
 
-fn item_method_sort(item: rbml::Doc) -> char {
+fn item_sort(item: rbml::Doc) -> char {
+    // NB(pcwalton): The default of 'r' here is relied upon in
+    // `is_associated_type` below.
     let mut ret = 'r';
-    reader::tagged_docs(item, tag_item_trait_method_sort, |doc| {
+    reader::tagged_docs(item, tag_item_trait_item_sort, |doc| {
         ret = doc.as_str_slice().as_bytes()[0] as char;
         false
     });
@@ -241,48 +244,14 @@ fn item_trait_ref(doc: rbml::Doc, tcx: &ty::ctxt, cdata: Cmd) -> ty::TraitRef {
     doc_trait_ref(tp, tcx, cdata)
 }
 
-fn item_ty_param_defs(item: rbml::Doc,
-                      tcx: &ty::ctxt,
-                      cdata: Cmd,
-                      tag: uint)
-                      -> subst::VecPerParamSpace<ty::TypeParameterDef> {
-    let mut bounds = subst::VecPerParamSpace::empty();
-    reader::tagged_docs(item, tag, |p| {
-        let bd = parse_type_param_def_data(
-            p.data, p.start, cdata.cnum, tcx,
-            |_, did| translate_def_id(cdata, did));
-        bounds.push(bd.space, bd);
-        true
-    });
-    bounds
+fn doc_bounds(doc: rbml::Doc, tcx: &ty::ctxt, cdata: Cmd) -> ty::ParamBounds {
+    parse_bounds_data(doc.data, cdata.cnum, doc.start, tcx,
+                      |_, did| translate_def_id(cdata, did))
 }
 
-fn item_region_param_defs(item_doc: rbml::Doc, cdata: Cmd)
-                          -> subst::VecPerParamSpace<ty::RegionParameterDef>
-{
-    let mut v = subst::VecPerParamSpace::empty();
-    reader::tagged_docs(item_doc, tag_region_param_def, |rp_doc| {
-        let ident_str_doc = reader::get_doc(rp_doc,
-                                            tag_region_param_def_ident);
-        let ident = item_name(&*token::get_ident_interner(), ident_str_doc);
-        let def_id_doc = reader::get_doc(rp_doc,
-                                         tag_region_param_def_def_id);
-        let def_id = reader::with_doc_data(def_id_doc, parse_def_id);
-        let def_id = translate_def_id(cdata, def_id);
-
-        let doc = reader::get_doc(rp_doc, tag_region_param_def_space);
-        let space = subst::ParamSpace::from_uint(reader::doc_as_u64(doc) as uint);
-
-        let doc = reader::get_doc(rp_doc, tag_region_param_def_index);
-        let index = reader::doc_as_u64(doc) as uint;
-
-        v.push(space, ty::RegionParameterDef { name: ident.name,
-                                               def_id: def_id,
-                                               space: space,
-                                               index: index });
-        true
-    });
-    v
+fn trait_def_bounds(doc: rbml::Doc, tcx: &ty::ctxt, cdata: Cmd) -> ty::ParamBounds {
+    let d = reader::get_doc(doc, tag_trait_def_bounds);
+    doc_bounds(d, tcx, cdata)
 }
 
 fn enum_variant_ids(item: rbml::Doc, cdata: Cmd) -> Vec<ast::DefId> {
@@ -338,15 +307,18 @@ fn item_to_def_like(item: rbml::Doc, did: ast::DefId, cnum: ast::CrateNum)
         UnsafeFn  => DlDef(def::DefFn(did, ast::UnsafeFn)),
         Fn        => DlDef(def::DefFn(did, ast::NormalFn)),
         StaticMethod | UnsafeStaticMethod => {
-            let fn_style = if fam == UnsafeStaticMethod { ast::UnsafeFn } else
-                { ast::NormalFn };
+            let fn_style = if fam == UnsafeStaticMethod {
+                ast::UnsafeFn
+            } else {
+                ast::NormalFn
+            };
             // def_static_method carries an optional field of its enclosing
             // trait or enclosing impl (if this is an inherent static method).
             // So we need to detect whether this is in a trait or not, which
             // we do through the mildly hacky way of checking whether there is
-            // a trait_method_sort.
+            // a trait_parent_sort.
             let provenance = if reader::maybe_get_doc(
-                  item, tag_item_trait_method_sort).is_some() {
+                  item, tag_item_trait_parent_sort).is_some() {
                 def::FromTrait(item_reqd_and_translated_parent_item(cnum,
                                                                     item))
             } else {
@@ -355,7 +327,7 @@ fn item_to_def_like(item: rbml::Doc, did: ast::DefId, cnum: ast::CrateNum)
             };
             DlDef(def::DefStaticMethod(did, provenance, fn_style))
         }
-        Type | ForeignType => DlDef(def::DefTy(did)),
+        Type | ForeignType => DlDef(def::DefTy(did, false)),
         Mod => DlDef(def::DefMod(did)),
         ForeignMod => DlDef(def::DefForeignMod(did)),
         StructVariant => {
@@ -367,7 +339,7 @@ fn item_to_def_like(item: rbml::Doc, did: ast::DefId, cnum: ast::CrateNum)
             DlDef(def::DefVariant(enum_did, did, false))
         }
         Trait => DlDef(def::DefTrait(did)),
-        Enum => DlDef(def::DefTy(did)),
+        Enum => DlDef(def::DefTy(did, true)),
         Impl => DlImpl(did),
         PublicField | InheritedField => DlField,
     }
@@ -378,24 +350,11 @@ pub fn get_trait_def(cdata: Cmd,
                      tcx: &ty::ctxt) -> ty::TraitDef
 {
     let item_doc = lookup_item(item_id, cdata.data());
-    let tp_defs = item_ty_param_defs(item_doc, tcx, cdata,
-                                     tag_items_data_item_ty_param_bounds);
-    let rp_defs = item_region_param_defs(item_doc, cdata);
-    let mut bounds = ty::empty_builtin_bounds();
-    // Collect the builtin bounds from the encoded supertraits.
-    // FIXME(#8559): They should be encoded directly.
-    reader::tagged_docs(item_doc, tag_item_super_trait_ref, |trait_doc| {
-        // NB. Bypasses real supertraits. See get_supertraits() if you wanted them.
-        let trait_ref = doc_trait_ref(trait_doc, tcx, cdata);
-        tcx.lang_items.to_builtin_kind(trait_ref.def_id).map(|bound| {
-            bounds.add(bound);
-        });
-        true
-    });
+    let generics = doc_generics(item_doc, tcx, cdata, tag_item_generics);
+    let bounds = trait_def_bounds(item_doc, tcx, cdata);
 
     ty::TraitDef {
-        generics: ty::Generics {types: tp_defs,
-                                regions: rp_defs},
+        generics: generics,
         bounds: bounds,
         trait_ref: Rc::new(item_trait_ref(item_doc, tcx, cdata))
     }
@@ -409,12 +368,10 @@ pub fn get_type(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt)
     let t = item_type(ast::DefId { krate: cdata.cnum, node: id }, item, tcx,
                       cdata);
 
-    let tp_defs = item_ty_param_defs(item, tcx, cdata, tag_items_data_item_ty_param_bounds);
-    let rp_defs = item_region_param_defs(item, cdata);
+    let generics = doc_generics(item, tcx, cdata, tag_item_generics);
 
     ty::Polytype {
-        generics: ty::Generics {types: tp_defs,
-                                regions: rp_defs},
+        generics: generics,
         ty: t
     }
 }
@@ -536,14 +493,11 @@ fn each_child_of_item_or_crate(intr: Rc<IdentInterner>,
             None => {}
             Some(inherent_impl_doc) => {
                 let _ = reader::tagged_docs(inherent_impl_doc,
-                                            tag_item_impl_method,
-                                            |impl_method_def_id_doc| {
-                    let impl_method_def_id =
-                        reader::with_doc_data(impl_method_def_id_doc,
-                                              parse_def_id);
-                    let impl_method_def_id =
-                        translate_def_id(cdata, impl_method_def_id);
-                    match maybe_find_item(impl_method_def_id.node, items) {
+                                            tag_item_impl_item,
+                                            |impl_item_def_id_doc| {
+                    let impl_item_def_id = item_def_id(impl_item_def_id_doc,
+                                                       cdata);
+                    match maybe_find_item(impl_item_def_id.node, items) {
                         None => {}
                         Some(impl_method_doc) => {
                             match item_family(impl_method_doc) {
@@ -554,7 +508,7 @@ fn each_child_of_item_or_crate(intr: Rc<IdentInterner>,
                                         item_name(&*intr, impl_method_doc);
                                     let static_method_def_like =
                                         item_to_def_like(impl_method_doc,
-                                                         impl_method_def_id,
+                                                         impl_item_def_id,
                                                          cdata.cnum);
                                     callback(static_method_def_like,
                                              static_method_name,
@@ -660,27 +614,28 @@ pub fn get_item_path(cdata: Cmd, id: ast::NodeId) -> Vec<ast_map::PathElem> {
     item_path(lookup_item(id, cdata.data()))
 }
 
-pub type DecodeInlinedItem<'a> = |cdata: Cmd,
-                                  tcx: &ty::ctxt,
-                                  path: Vec<ast_map::PathElem>,
-                                  par_doc: rbml::Doc|: 'a
-                                  -> Result<ast::InlinedItem, Vec<ast_map::PathElem> >;
+pub type DecodeInlinedItem<'a> = <'tcx> |cdata: Cmd,
+                                         tcx: &ty::ctxt<'tcx>,
+                                         path: Vec<ast_map::PathElem>,
+                                         par_doc: rbml::Doc|: 'a
+                                         -> Result<&'tcx ast::InlinedItem,
+                                                   Vec<ast_map::PathElem>>;
 
-pub fn maybe_get_item_ast(cdata: Cmd, tcx: &ty::ctxt, id: ast::NodeId,
-                          decode_inlined_item: DecodeInlinedItem)
-                          -> csearch::found_ast {
+pub fn maybe_get_item_ast<'tcx>(cdata: Cmd, tcx: &ty::ctxt<'tcx>, id: ast::NodeId,
+                                decode_inlined_item: DecodeInlinedItem)
+                                -> csearch::found_ast<'tcx> {
     debug!("Looking up item: {}", id);
     let item_doc = lookup_item(id, cdata.data());
     let path = Vec::from_slice(item_path(item_doc).init());
     match decode_inlined_item(cdata, tcx, path, item_doc) {
-        Ok(ref ii) => csearch::found(*ii),
+        Ok(ii) => csearch::found(ii),
         Err(path) => {
             match item_parent_item(item_doc) {
                 Some(did) => {
                     let did = translate_def_id(cdata, did);
                     let parent_item = lookup_item(did.node, cdata.data());
                     match decode_inlined_item(cdata, tcx, path, parent_item) {
-                        Ok(ref ii) => csearch::found_parent(did, *ii),
+                        Ok(ii) => csearch::found_parent(did, ii),
                         Err(_) => csearch::not_found
                     }
                 }
@@ -752,34 +707,50 @@ fn get_mutability(ch: u8) -> ast::Mutability {
     }
 }
 
-/// Returns information about the given implementation.
-pub fn get_impl_methods(cdata: Cmd, impl_id: ast::NodeId) -> Vec<ast::DefId> {
-    let mut methods = Vec::new();
+/// Returns the def IDs of all the items in the given implementation.
+pub fn get_impl_items(cdata: Cmd, impl_id: ast::NodeId)
+                      -> Vec<ty::ImplOrTraitItemId> {
+    let mut impl_items = Vec::new();
     reader::tagged_docs(lookup_item(impl_id, cdata.data()),
-                        tag_item_impl_method, |doc| {
-        let m_did = reader::with_doc_data(doc, parse_def_id);
-        methods.push(translate_def_id(cdata, m_did));
+                        tag_item_impl_item, |doc| {
+        let def_id = item_def_id(doc, cdata);
+        match item_sort(doc) {
+            'r' | 'p' => impl_items.push(ty::MethodTraitItemId(def_id)),
+            't' => impl_items.push(ty::TypeTraitItemId(def_id)),
+            _ => fail!("unknown impl item sort"),
+        }
         true
     });
 
-    methods
+    impl_items
 }
 
-pub fn get_method_name_and_explicit_self(intr: Rc<IdentInterner>,
-                                         cdata: Cmd,
-                                         id: ast::NodeId)
-                                         -> (ast::Ident,
-                                             ty::ExplicitSelfCategory) {
-    let method_doc = lookup_item(id, cdata.data());
-    let name = item_name(&*intr, method_doc);
-    let explicit_self = get_explicit_self(method_doc);
-    (name, explicit_self)
+pub fn get_trait_item_name_and_kind(intr: Rc<IdentInterner>,
+                                    cdata: Cmd,
+                                    id: ast::NodeId)
+                                    -> (ast::Ident, TraitItemKind) {
+    let doc = lookup_item(id, cdata.data());
+    let name = item_name(&*intr, doc);
+    match item_sort(doc) {
+        'r' | 'p' => {
+            let explicit_self = get_explicit_self(doc);
+            (name, TraitItemKind::from_explicit_self_category(explicit_self))
+        }
+        't' => (name, TypeTraitItemKind),
+        c => {
+            fail!("get_trait_item_name_and_kind(): unknown trait item kind \
+                   in metadata: `{}`", c)
+        }
+    }
 }
 
-pub fn get_method(intr: Rc<IdentInterner>, cdata: Cmd, id: ast::NodeId,
-                  tcx: &ty::ctxt) -> ty::Method
-{
+pub fn get_impl_or_trait_item(intr: Rc<IdentInterner>,
+                              cdata: Cmd,
+                              id: ast::NodeId,
+                              tcx: &ty::ctxt)
+                              -> ty::ImplOrTraitItem {
     let method_doc = lookup_item(id, cdata.data());
+
     let def_id = item_def_id(method_doc, cdata);
 
     let container_id = item_reqd_and_translated_parent_item(cdata.cnum,
@@ -791,36 +762,49 @@ pub fn get_method(intr: Rc<IdentInterner>, cdata: Cmd, id: ast::NodeId,
     };
 
     let name = item_name(&*intr, method_doc);
-    let type_param_defs = item_ty_param_defs(method_doc, tcx, cdata,
-                                             tag_item_method_tps);
-    let rp_defs = item_region_param_defs(method_doc, cdata);
-    let fty = doc_method_fty(method_doc, tcx, cdata);
     let vis = item_visibility(method_doc);
-    let explicit_self = get_explicit_self(method_doc);
-    let provided_source = get_provided_source(method_doc, cdata);
-
-    ty::Method::new(
-        name,
-        ty::Generics {
-            types: type_param_defs,
-            regions: rp_defs,
-        },
-        fty,
-        explicit_self,
-        vis,
-        def_id,
-        container,
-        provided_source
-    )
-}
-
-pub fn get_trait_method_def_ids(cdata: Cmd,
-                                id: ast::NodeId) -> Vec<ast::DefId> {
+
+    match item_sort(method_doc) {
+        'r' | 'p' => {
+            let generics = doc_generics(method_doc, tcx, cdata,
+                                        tag_method_ty_generics);
+            let fty = doc_method_fty(method_doc, tcx, cdata);
+            let explicit_self = get_explicit_self(method_doc);
+            let provided_source = get_provided_source(method_doc, cdata);
+
+            ty::MethodTraitItem(Rc::new(ty::Method::new(name,
+                                                        generics,
+                                                        fty,
+                                                        explicit_self,
+                                                        vis,
+                                                        def_id,
+                                                        container,
+                                                        provided_source)))
+        }
+        't' => {
+            ty::TypeTraitItem(Rc::new(ty::AssociatedType {
+                ident: name,
+                vis: vis,
+                def_id: def_id,
+                container: container,
+            }))
+        }
+        _ => fail!("unknown impl/trait item sort"),
+    }
+}
+
+pub fn get_trait_item_def_ids(cdata: Cmd, id: ast::NodeId)
+                              -> Vec<ty::ImplOrTraitItemId> {
     let data = cdata.data();
     let item = lookup_item(id, data);
     let mut result = Vec::new();
-    reader::tagged_docs(item, tag_item_trait_method, |mth| {
-        result.push(item_def_id(mth, cdata));
+    reader::tagged_docs(item, tag_item_trait_item, |mth| {
+        let def_id = item_def_id(mth, cdata);
+        match item_sort(mth) {
+            'r' | 'p' => result.push(ty::MethodTraitItemId(def_id)),
+            't' => result.push(ty::TypeTraitItemId(def_id)),
+            _ => fail!("unknown trait item sort"),
+        }
         true
     });
     result
@@ -834,19 +818,30 @@ pub fn get_item_variances(cdata: Cmd, id: ast::NodeId) -> ty::ItemVariances {
     Decodable::decode(&mut decoder).unwrap()
 }
 
-pub fn get_provided_trait_methods(intr: Rc<IdentInterner>, cdata: Cmd,
-                                  id: ast::NodeId, tcx: &ty::ctxt)
+pub fn get_provided_trait_methods(intr: Rc<IdentInterner>,
+                                  cdata: Cmd,
+                                  id: ast::NodeId,
+                                  tcx: &ty::ctxt)
                                   -> Vec<Rc<ty::Method>> {
     let data = cdata.data();
     let item = lookup_item(id, data);
     let mut result = Vec::new();
 
-    reader::tagged_docs(item, tag_item_trait_method, |mth_id| {
+    reader::tagged_docs(item, tag_item_trait_item, |mth_id| {
         let did = item_def_id(mth_id, cdata);
         let mth = lookup_item(did.node, data);
 
-        if item_method_sort(mth) == 'p' {
-            result.push(Rc::new(get_method(intr.clone(), cdata, did.node, tcx)));
+        if item_sort(mth) == 'p' {
+            let trait_item = get_impl_or_trait_item(intr.clone(),
+                                                    cdata,
+                                                    did.node,
+                                                    tcx);
+            match trait_item {
+                ty::MethodTraitItem(ref method) => {
+                    result.push((*method).clone())
+                }
+                ty::TypeTraitItem(_) => {}
+            }
         }
         true
     });
@@ -905,8 +900,8 @@ pub fn get_static_methods_if_impl(intr: Rc<IdentInterner>,
     if !ret { return None }
 
     let mut impl_method_ids = Vec::new();
-    reader::tagged_docs(item, tag_item_impl_method, |impl_method_doc| {
-        impl_method_ids.push(reader::with_doc_data(impl_method_doc, parse_def_id));
+    reader::tagged_docs(item, tag_item_impl_item, |impl_method_doc| {
+        impl_method_ids.push(item_def_id(impl_method_doc, cdata));
         true
     });
 
@@ -1023,8 +1018,8 @@ pub fn get_struct_fields(intr: Rc<IdentInterner>, cdata: Cmd, id: ast::NodeId)
     result
 }
 
-fn get_meta_items(md: rbml::Doc) -> Vec<Gc<ast::MetaItem>> {
-    let mut items: Vec<Gc<ast::MetaItem>> = Vec::new();
+fn get_meta_items(md: rbml::Doc) -> Vec<P<ast::MetaItem>> {
+    let mut items: Vec<P<ast::MetaItem>> = Vec::new();
     reader::tagged_docs(md, tag_meta_item_word, |meta_item_doc| {
         let nd = reader::get_doc(meta_item_doc, tag_meta_item_name);
         let n = token::intern_and_get_ident(nd.as_str_slice());
@@ -1045,7 +1040,7 @@ fn get_meta_items(md: rbml::Doc) -> Vec<Gc<ast::MetaItem>> {
         let nd = reader::get_doc(meta_item_doc, tag_meta_item_name);
         let n = token::intern_and_get_ident(nd.as_str_slice());
         let subitems = get_meta_items(meta_item_doc);
-        items.push(attr::mk_list_item(n, subitems.move_iter().collect()));
+        items.push(attr::mk_list_item(n, subitems.into_iter().collect()));
         true
     });
     return items;
@@ -1063,7 +1058,7 @@ fn get_attributes(md: rbml::Doc) -> Vec<ast::Attribute> {
             // Currently it's only possible to have a single meta item on
             // an attribute
             assert_eq!(meta_items.len(), 1u);
-            let meta_item = *meta_items.get(0);
+            let meta_item = meta_items.into_iter().nth(0).unwrap();
             attrs.push(
                 codemap::Spanned {
                     node: ast::Attribute_ {
@@ -1230,8 +1225,8 @@ pub fn each_implementation_for_trait(cdata: Cmd,
     });
 }
 
-pub fn get_trait_of_method(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt)
-                           -> Option<ast::DefId> {
+pub fn get_trait_of_item(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt)
+                         -> Option<ast::DefId> {
     let item_doc = lookup_item(id, cdata.data());
     let parent_item_id = match item_parent_item(item_doc) {
         None => return None,
@@ -1359,3 +1354,66 @@ pub fn is_typedef(cdata: Cmd, id: ast::NodeId) -> bool {
         _ => false,
     }
 }
+
+fn doc_generics(base_doc: rbml::Doc,
+                tcx: &ty::ctxt,
+                cdata: Cmd,
+                tag: uint)
+                -> ty::Generics
+{
+    let doc = reader::get_doc(base_doc, tag);
+
+    let mut types = subst::VecPerParamSpace::empty();
+    reader::tagged_docs(doc, tag_type_param_def, |p| {
+        let bd = parse_type_param_def_data(
+            p.data, p.start, cdata.cnum, tcx,
+            |_, did| translate_def_id(cdata, did));
+        types.push(bd.space, bd);
+        true
+    });
+
+    let mut regions = subst::VecPerParamSpace::empty();
+    reader::tagged_docs(doc, tag_region_param_def, |rp_doc| {
+        let ident_str_doc = reader::get_doc(rp_doc,
+                                            tag_region_param_def_ident);
+        let ident = item_name(&*token::get_ident_interner(), ident_str_doc);
+        let def_id_doc = reader::get_doc(rp_doc,
+                                         tag_region_param_def_def_id);
+        let def_id = reader::with_doc_data(def_id_doc, parse_def_id);
+        let def_id = translate_def_id(cdata, def_id);
+
+        let doc = reader::get_doc(rp_doc, tag_region_param_def_space);
+        let space = subst::ParamSpace::from_uint(reader::doc_as_u64(doc) as uint);
+
+        let doc = reader::get_doc(rp_doc, tag_region_param_def_index);
+        let index = reader::doc_as_u64(doc) as uint;
+
+        let mut bounds = Vec::new();
+        reader::tagged_docs(rp_doc, tag_items_data_region, |p| {
+            bounds.push(
+                parse_region_data(
+                    p.data, cdata.cnum, p.start, tcx,
+                    |_, did| translate_def_id(cdata, did)));
+            true
+        });
+
+        regions.push(space, ty::RegionParameterDef { name: ident.name,
+                                                     def_id: def_id,
+                                                     space: space,
+                                                     index: index,
+                                                     bounds: bounds });
+
+        true
+    });
+
+    ty::Generics { types: types, regions: regions }
+}
+
+pub fn is_associated_type(cdata: Cmd, id: ast::NodeId) -> bool {
+    let items = reader::get_doc(rbml::Doc::new(cdata.data()), tag_items);
+    match maybe_find_item(id, items) {
+        None => false,
+        Some(item) => item_sort(item) == 't',
+    }
+}
+