about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume1.gomez@gmail.com>2019-03-07 02:44:28 +0100
committerGuillaume Gomez <guillaume1.gomez@gmail.com>2019-03-21 22:49:42 +0100
commit64382f4b78bdca6bea1dd06e4a1039646b04ae93 (patch)
treea68023418fbcdfefffa2629b7111f0e86695f2fd
parent89573b3c8b629507130b1ec8beeaf550fdc0e046 (diff)
downloadrust-64382f4b78bdca6bea1dd06e4a1039646b04ae93.tar.gz
rust-64382f4b78bdca6bea1dd06e4a1039646b04ae93.zip
Greatly improve generics handling in rustdoc search
-rw-r--r--src/librustc_typeck/collect.rs60
-rw-r--r--src/librustc_typeck/lib.rs2
-rw-r--r--src/librustdoc/clean/inline.rs10
-rw-r--r--src/librustdoc/clean/mod.rs210
-rw-r--r--src/librustdoc/html/render.rs13
5 files changed, 273 insertions, 22 deletions
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 10e9613bf21..e723ee1d10a 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -1130,13 +1130,29 @@ fn report_assoc_ty_on_inherent_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span:
 }
 
 fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> {
+    checked_type_of(tcx, def_id, true).unwrap()
+}
+
+pub fn checked_type_of<'a, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    def_id: DefId,
+    fail: bool,
+) -> Option<Ty<'tcx>> {
     use rustc::hir::*;
 
-    let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
+    let hir_id = match tcx.hir().as_local_hir_id(def_id) {
+        Some(hir_id) => hir_id,
+        None => {
+            if !fail {
+                return None;
+            }
+            bug!("invalid node");
+        }
+    };
 
     let icx = ItemCtxt::new(tcx, def_id);
 
-    match tcx.hir().get_by_hir_id(hir_id) {
+    Some(match tcx.hir().get_by_hir_id(hir_id) {
         Node::TraitItem(item) => match item.node {
             TraitItemKind::Method(..) => {
                 let substs = InternalSubsts::identity_for_item(tcx, def_id);
@@ -1144,6 +1160,9 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> {
             }
             TraitItemKind::Const(ref ty, _) | TraitItemKind::Type(_, Some(ref ty)) => icx.to_ty(ty),
             TraitItemKind::Type(_, None) => {
+                if !fail {
+                    return None;
+                }
                 span_bug!(item.span, "associated type missing default");
             }
         },
@@ -1225,6 +1244,9 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> {
                 | ItemKind::GlobalAsm(..)
                 | ItemKind::ExternCrate(..)
                 | ItemKind::Use(..) => {
+                    if !fail {
+                        return None;
+                    }
                     span_bug!(
                         item.span,
                         "compute_type_of_item: unexpected item type: {:?}",
@@ -1264,7 +1286,7 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> {
             ..
         }) => {
             if gen.is_some() {
-                return tcx.typeck_tables_of(def_id).node_type(hir_id);
+                return Some(tcx.typeck_tables_of(def_id).node_type(hir_id));
             }
 
             let substs = ty::ClosureSubsts {
@@ -1342,6 +1364,9 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> {
                             }
                             // Sanity check to make sure everything is as expected.
                             if !found_const {
+                                if !fail {
+                                    return None;
+                                }
                                 bug!("no arg matching AnonConst in path")
                             }
                             match path.def {
@@ -1367,14 +1392,27 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> {
                                     return tcx.types.err;
                                 }
                                 Def::Err => tcx.types.err,
-                                x => bug!("unexpected const parent path def {:?}", x),
+                                x => {
+                                    if !fail {
+                                        return None;
+                                    }
+                                    bug!("unexpected const parent path def {:?}", x);
+                                }
+                            }
+                        }
+                        x => {
+                            if !fail {
+                                return None;
                             }
+                            bug!("unexpected const parent path {:?}", x);
                         }
-                        x => bug!("unexpected const parent path {:?}", x),
                     }
                 }
 
                 x => {
+                    if !fail {
+                        return None;
+                    }
                     bug!("unexpected const parent in type_of_def_id(): {:?}", x);
                 }
             }
@@ -1385,13 +1423,21 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> {
             hir::GenericParamKind::Const { ref ty, .. } => {
                 icx.to_ty(ty)
             }
-            x => bug!("unexpected non-type Node::GenericParam: {:?}", x),
+            x => {
+                if !fail {
+                    return None;
+                }
+                bug!("unexpected non-type Node::GenericParam: {:?}", x)
+            },
         },
 
         x => {
+            if !fail {
+                return None;
+            }
             bug!("unexpected sort of node in type_of_def_id(): {:?}", x);
         }
-    }
+    })
 }
 
 fn find_existential_constraints<'a, 'tcx>(
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index cbed7d26a99..7bb381d92d8 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -115,6 +115,8 @@ use util::common::time;
 
 use std::iter;
 
+pub use collect::checked_type_of;
+
 pub struct TypeAndSubsts<'tcx> {
     substs: SubstsRef<'tcx>,
     ty: Ty<'tcx>,
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 880f67281b9..2b45831f224 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -212,15 +212,19 @@ fn build_external_function(cx: &DocContext<'_>, did: DefId) -> clean::Function {
     };
 
     let predicates = cx.tcx.predicates_of(did);
+    let generics = (cx.tcx.generics_of(did), &predicates).clean(cx);
+    let decl = (did, sig).clean(cx);
+    let all_types = clean::get_all_types(&generics, &decl, cx);
     clean::Function {
-        decl: (did, sig).clean(cx),
-        generics: (cx.tcx.generics_of(did), &predicates).clean(cx),
+        decl,
+        generics,
         header: hir::FnHeader {
             unsafety: sig.unsafety(),
             abi: sig.abi(),
             constness,
             asyncness: hir::IsAsync::NotAsync,
-        }
+        },
+        all_types,
     }
 }
 
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 4819256a545..5d691b1873b 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1084,9 +1084,10 @@ impl GenericBound {
 
     fn get_trait_type(&self) -> Option<Type> {
         if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, _) = *self {
-            return Some(trait_.clone());
+            Some(trait_.clone())
+        } else {
+            None
         }
-        None
     }
 }
 
@@ -1319,6 +1320,16 @@ pub enum WherePredicate {
     EqPredicate { lhs: Type, rhs: Type },
 }
 
+impl WherePredicate {
+    pub fn get_bounds(&self) -> Option<&[GenericBound]> {
+        match *self {
+            WherePredicate::BoundPredicate { ref bounds, .. } => Some(bounds),
+            WherePredicate::RegionPredicate { ref bounds, .. } => Some(bounds),
+            _ => None,
+        }
+    }
+}
+
 impl Clean<WherePredicate> for hir::WherePredicate {
     fn clean(&self, cx: &DocContext<'_>) -> WherePredicate {
         match *self {
@@ -1455,6 +1466,25 @@ pub enum GenericParamDefKind {
     },
 }
 
+impl GenericParamDefKind {
+    pub fn is_type(&self) -> bool {
+        match *self {
+            GenericParamDefKind::Type { .. } => true,
+            _ => false,
+        }
+    }
+
+    pub fn get_type(&self, cx: &DocContext<'_, '_, '_>) -> Option<Type> {
+        match *self {
+            GenericParamDefKind::Type { did, .. } => {
+                rustc_typeck::checked_type_of(cx.tcx, did, false).map(|t| t.clean(cx))
+            }
+            GenericParamDefKind::Const { ref ty, .. } => Some(ty.clone()),
+            GenericParamDefKind::Lifetime => None,
+        }
+    }
+}
+
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
 pub struct GenericParamDef {
     pub name: String,
@@ -1466,12 +1496,25 @@ impl GenericParamDef {
     pub fn is_synthetic_type_param(&self) -> bool {
         match self.kind {
             GenericParamDefKind::Lifetime |
-            GenericParamDefKind::Const { .. } => {
-                false
-            }
+            GenericParamDefKind::Const { .. } => false,
             GenericParamDefKind::Type { ref synthetic, .. } => synthetic.is_some(),
         }
     }
+
+    pub fn is_type(&self) -> bool {
+        self.kind.is_type()
+    }
+
+    pub fn get_type(&self, cx: &DocContext<'_, '_, '_>) -> Option<Type> {
+        self.kind.get_type(cx)
+    }
+
+    pub fn get_bounds(&self) -> Option<&[GenericBound]> {
+        match self.kind {
+            GenericParamDefKind::Type { ref bounds, .. } => Some(bounds),
+            _ => None,
+        }
+    }
 }
 
 impl<'tcx> Clean<GenericParamDef> for ty::GenericParamDef {
@@ -1707,12 +1750,145 @@ impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics,
     }
 }
 
+// The point is to replace bounds with types.
+pub fn get_real_types(
+    generics: &Generics,
+    arg: &Type,
+    cx: &DocContext<'_, '_, '_>,
+    debug: bool,
+) -> Option<Vec<Type>> {
+    let mut res = Vec::new();
+    if arg.to_string() == "W" || arg.to_string() == "Z" || debug {
+        println!("0. {:?}", arg);
+    }
+    if let Some(where_pred) = generics.where_predicates.iter().find(|g| {
+        match g {
+            &WherePredicate::BoundPredicate { ref ty, .. } => ty.def_id() == arg.def_id(),
+            _ => false,
+        }
+    }) {
+        if arg.to_string() == "W" || arg.to_string() == "Z" || debug {
+            println!("1. {:?} => {:?}", arg, where_pred);
+        }
+        let bounds = where_pred.get_bounds().unwrap_or_else(|| &[]);
+        for bound in bounds.iter() {
+            match *bound {
+                GenericBound::TraitBound(ref poly_trait, _) => {
+                    if arg.to_string() == "W" || arg.to_string() == "Z" || debug {
+                        println!("    {:?}", poly_trait.trait_);
+                    }
+                    for x in poly_trait.generic_params.iter() {
+                        if !x.is_type() {
+                            continue
+                        }
+                        if let Some(ty) = x.get_type(cx) {
+                            if let Some(mut adds) = get_real_types(generics, &ty, cx,
+                                arg.to_string() == "W" || arg.to_string() == "Z" || debug) {
+                                res.append(&mut adds);
+                            } else if !ty.is_full_generic() {
+                                res.push(ty);
+                            }
+                        }
+                    }
+                }
+                _ => {}
+            }
+        }
+    } else {
+        let arg_s = arg.to_string();
+        if let Some(bound) = generics.params.iter().find(|g| {
+            g.is_type() && g.name == arg_s
+        }) {
+            if arg.to_string() == "W" || arg.to_string() == "Z" || debug {
+                println!("2. {:?} => {:?}", arg, bound);
+            }
+            for bound in bound.get_bounds().unwrap_or_else(|| &[]) {
+                if let Some(ty) = bound.get_trait_type() {
+                    if let Some(mut adds) = get_real_types(generics, &ty, cx,
+                        arg.to_string() == "W" || arg.to_string() == "Z" || debug) {
+                        if arg.to_string() == "W" || arg.to_string() == "Z" || debug {
+                            println!("3. {:?}", adds);
+                        }
+                        res.append(&mut adds);
+                    } else {
+                        if arg.to_string() == "W" || arg.to_string() == "Z" || debug {
+                            println!("4. {:?}", ty);
+                        }
+                        if !ty.is_full_generic() {
+                            res.push(ty.clone());
+                        }
+                    }
+                }
+            }
+            /*if let Some(ty) = bound.get_type(cx) {
+                if let Some(mut adds) = get_real_types(generics, &ty, cx, level + 1) {
+                    res.append(&mut adds);
+                } else {
+                    res.push(ty);
+                }
+            } else {
+                res.push(arg.clone());
+            }*/
+        } else if let Some(gens) = arg.generics() {
+            res.push(arg.clone());
+            for gen in gens.iter() {
+                if gen.is_full_generic() {
+                    if let Some(mut adds) = get_real_types(generics, gen, cx,
+                        arg.to_string() == "W" || arg.to_string() == "Z" || debug) {
+                        if arg.to_string() == "W" || arg.to_string() == "Z" || debug {
+                            println!("5. {:?}", adds);
+                        }
+                        res.append(&mut adds);
+                    }
+                } else {
+                    if arg.to_string() == "W" || arg.to_string() == "Z" || debug {
+                        println!("6. {:?}", gen);
+                    }
+                    res.push(gen.clone());
+                }
+            }
+        }
+    }
+    if res.is_empty() && !arg.is_full_generic() {
+        res.push(arg.clone());
+    }
+    if arg.to_string() == "W" || arg.to_string() == "Z" || debug {
+        println!("7. /!\\ {:?}", res);
+    }
+    Some(res)
+}
+
+pub fn get_all_types(
+    generics: &Generics,
+    decl: &FnDecl,
+    cx: &DocContext<'_, '_, '_>,
+) -> Vec<Type> {
+    let mut all_types = Vec::new();
+    for arg in decl.inputs.values.iter() {
+        if arg.type_.is_self_type() {
+            continue;
+        }
+        if let Some(mut args) = get_real_types(generics, &arg.type_, cx, false) {
+            all_types.append(&mut args);
+        } else {
+            all_types.push(arg.type_.clone());
+        }
+    }
+    all_types.sort_unstable_by(|a, b| a.to_string().partial_cmp(&b.to_string()).expect("a") );
+    all_types.dedup();
+    if decl.inputs.values.iter().any(|s| s.type_.to_string() == "W" || s.type_.to_string() == "Z") {
+        println!("||||> {:?}", all_types);
+    }
+    all_types
+}
+
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub struct Method {
     pub generics: Generics,
     pub decl: FnDecl,
     pub header: hir::FnHeader,
     pub defaultness: Option<hir::Defaultness>,
+    pub all_types: Vec<Type>,
 }
 
 impl<'a> Clean<Method> for (&'a hir::MethodSig, &'a hir::Generics, hir::BodyId,
@@ -1721,11 +1897,13 @@ impl<'a> Clean<Method> for (&'a hir::MethodSig, &'a hir::Generics, hir::BodyId,
         let (generics, decl) = enter_impl_trait(cx, || {
             (self.1.clean(cx), (&*self.0.decl, self.2).clean(cx))
         });
+        let all_types = get_all_types(&generics, &decl, cx);
         Method {
             decl,
             generics,
             header: self.0.header,
             defaultness: self.3,
+            all_types,
         }
     }
 }
@@ -1735,6 +1913,7 @@ pub struct TyMethod {
     pub header: hir::FnHeader,
     pub decl: FnDecl,
     pub generics: Generics,
+    pub all_types: Vec<Type>,
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
@@ -1742,6 +1921,7 @@ pub struct Function {
     pub decl: FnDecl,
     pub generics: Generics,
     pub header: hir::FnHeader,
+    pub all_types: Vec<Type>,
 }
 
 impl Clean<Item> for doctree::Function {
@@ -1756,6 +1936,7 @@ impl Clean<Item> for doctree::Function {
         } else {
             hir::Constness::NotConst
         };
+        let all_types = get_all_types(&generics, &decl, cx);
         Item {
             name: Some(self.name.clean(cx)),
             attrs: self.attrs.clean(cx),
@@ -1768,6 +1949,7 @@ impl Clean<Item> for doctree::Function {
                 decl,
                 generics,
                 header: hir::FnHeader { constness, ..self.header },
+                all_types,
             }),
         }
     }
@@ -1855,7 +2037,7 @@ impl<'a, A: Copy> Clean<FnDecl> for (&'a hir::FnDecl, A)
         FnDecl {
             inputs: (&self.0.inputs[..], self.1).clean(cx),
             output: self.0.output.clean(cx),
-            attrs: Attributes::default()
+            attrs: Attributes::default(),
         }
     }
 }
@@ -2037,10 +2219,12 @@ impl Clean<Item> for hir::TraitItem {
                 let (generics, decl) = enter_impl_trait(cx, || {
                     (self.generics.clean(cx), (&*sig.decl, &names[..]).clean(cx))
                 });
+                let all_types = get_all_types(&generics, &decl, cx);
                 TyMethodItem(TyMethod {
                     header: sig.header,
                     decl,
                     generics,
+                    all_types,
                 })
             }
             hir::TraitItemKind::Type(ref bounds, ref default) => {
@@ -2138,6 +2322,7 @@ impl<'tcx> Clean<Item> for ty::AssociatedItem {
                     ty::ImplContainer(_) => true,
                     ty::TraitContainer(_) => self.defaultness.has_value()
                 };
+                let all_types = get_all_types(&generics, &decl, cx);
                 if provided {
                     let constness = if cx.tcx.is_min_const_fn(self.def_id) {
                         hir::Constness::Const
@@ -2154,6 +2339,7 @@ impl<'tcx> Clean<Item> for ty::AssociatedItem {
                             asyncness: hir::IsAsync::NotAsync,
                         },
                         defaultness: Some(self.defaultness),
+                        all_types,
                     })
                 } else {
                     TyMethodItem(TyMethod {
@@ -2164,7 +2350,8 @@ impl<'tcx> Clean<Item> for ty::AssociatedItem {
                             abi: sig.abi(),
                             constness: hir::Constness::NotConst,
                             asyncness: hir::IsAsync::NotAsync,
-                        }
+                        },
+                        all_types,
                     })
                 }
             }
@@ -2410,6 +2597,13 @@ impl Type {
             _ => None
         }
     }
+
+    pub fn is_full_generic(&self) -> bool {
+        match *self {
+            Type::Generic(_) => true,
+            _ => false,
+        }
+    }
 }
 
 impl GetDefId for Type {
@@ -3824,6 +4018,7 @@ impl Clean<Item> for hir::ForeignItem {
                 let (generics, decl) = enter_impl_trait(cx, || {
                     (generics.clean(cx), (&**decl, &names[..]).clean(cx))
                 });
+                let all_types = get_all_types(&generics, &decl, cx);
                 ForeignFunctionItem(Function {
                     decl,
                     generics,
@@ -3833,6 +4028,7 @@ impl Clean<Item> for hir::ForeignItem {
                         constness: hir::Constness::NotConst,
                         asyncness: hir::IsAsync::NotAsync,
                     },
+                    all_types,
                 })
             }
             hir::ForeignItemKind::Static(ref ty, mutbl) => {
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index a262a2f2885..402eb180082 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -5025,14 +5025,17 @@ fn make_item_keywords(it: &clean::Item) -> String {
 }
 
 fn get_index_search_type(item: &clean::Item) -> Option<IndexItemFunctionType> {
-    let decl = match item.inner {
-        clean::FunctionItem(ref f) => &f.decl,
-        clean::MethodItem(ref m) => &m.decl,
-        clean::TyMethodItem(ref m) => &m.decl,
+    let (decl, all_types) = match item.inner {
+        clean::FunctionItem(ref f) => (&f.decl, &f.all_types),
+        clean::MethodItem(ref m) => (&m.decl, &m.all_types),
+        clean::TyMethodItem(ref m) => (&m.decl, &m.all_types),
         _ => return None
     };
 
-    let inputs = decl.inputs.values.iter().map(|arg| get_index_type(&arg.type_)).collect();
+    println!("====> {:?}", all_types);
+    let inputs = all_types.iter().map(|arg| {
+        get_index_type(&arg)
+    }).collect();
     let output = match decl.output {
         clean::FunctionRetTy::Return(ref return_type) => Some(get_index_type(return_type)),
         _ => None