about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock1
-rw-r--r--src/bootstrap/Cargo.toml1
-rw-r--r--src/bootstrap/builder.rs2
-rw-r--r--src/bootstrap/doc.rs59
-rw-r--r--src/bootstrap/flags.rs14
-rw-r--r--src/libcore/future/into_future.rs27
-rw-r--r--src/libcore/future/mod.rs4
-rw-r--r--src/librustc_error_codes/error_codes/E0599.md15
-rw-r--r--src/librustc_error_codes/error_codes/E0600.md2
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs54
-rw-r--r--src/libstd/future.rs14
-rw-r--r--src/libstd/lib.rs3
-rw-r--r--src/test/rustdoc/intra-link-self.rs88
-rwxr-xr-xsrc/tools/publish_toolstate.py17
-rw-r--r--triagebot.toml6
15 files changed, 296 insertions, 11 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 2fdbfa26787..6ce5458ed7a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -213,6 +213,7 @@ dependencies = [
  "lazy_static 1.4.0",
  "libc",
  "num_cpus",
+ "opener",
  "pretty_assertions",
  "serde",
  "serde_json",
diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml
index f7856f6a7fc..c4918d7f2e7 100644
--- a/src/bootstrap/Cargo.toml
+++ b/src/bootstrap/Cargo.toml
@@ -48,6 +48,7 @@ toml = "0.5"
 lazy_static = "1.3.0"
 time = "0.1"
 ignore = "0.4.10"
+opener = "0.4"
 
 [target.'cfg(windows)'.dependencies.winapi]
 version = "0.3"
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index 4bc81a7b42d..5489b1bc66b 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -503,7 +503,7 @@ impl<'a> Builder<'a> {
             Subcommand::Check { ref paths } => (Kind::Check, &paths[..]),
             Subcommand::Clippy { ref paths } => (Kind::Clippy, &paths[..]),
             Subcommand::Fix { ref paths } => (Kind::Fix, &paths[..]),
-            Subcommand::Doc { ref paths } => (Kind::Doc, &paths[..]),
+            Subcommand::Doc { ref paths, .. } => (Kind::Doc, &paths[..]),
             Subcommand::Test { ref paths, .. } => (Kind::Test, &paths[..]),
             Subcommand::Bench { ref paths, .. } => (Kind::Bench, &paths[..]),
             Subcommand::Dist { ref paths } => (Kind::Dist, &paths[..]),
diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs
index 7eab92ddc92..5c01c5e852c 100644
--- a/src/bootstrap/doc.rs
+++ b/src/bootstrap/doc.rs
@@ -70,6 +70,35 @@ book!(
     RustdocBook, "src/doc/rustdoc", "rustdoc";
 );
 
+fn open(builder: &Builder<'_>, path: impl AsRef<Path>) {
+    if builder.config.dry_run || !builder.config.cmd.open() {
+        return;
+    }
+
+    let path = path.as_ref();
+    builder.info(&format!("Opening doc {}", path.display()));
+    if let Err(err) = opener::open(path) {
+        builder.info(&format!("{}\n", err));
+    }
+}
+
+// "src/libstd" -> ["src", "libstd"]
+//
+// Used for deciding whether a particular step is one requested by the user on
+// the `x.py doc` command line, which determines whether `--open` will open that
+// page.
+fn components_simplified(path: &PathBuf) -> Vec<&str> {
+    path.iter().map(|component| component.to_str().unwrap_or("???")).collect()
+}
+
+fn is_explicit_request(builder: &Builder<'_>, path: &str) -> bool {
+    builder
+        .paths
+        .iter()
+        .map(components_simplified)
+        .any(|requested| requested.iter().copied().eq(path.split("/")))
+}
+
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct UnstableBook {
     target: Interned<String>,
@@ -200,6 +229,12 @@ impl Step for TheBook {
 
             invoke_rustdoc(builder, compiler, target, path);
         }
+
+        if is_explicit_request(builder, "src/doc/book") {
+            let out = builder.doc_out(target);
+            let index = out.join("book").join("index.html");
+            open(builder, &index);
+        }
     }
 }
 
@@ -338,6 +373,13 @@ impl Step for Standalone {
             }
             builder.run(&mut cmd);
         }
+
+        // We open doc/index.html as the default if invoked as `x.py doc --open`
+        // with no particular explicit doc requested (e.g. src/libcore).
+        if builder.paths.is_empty() || is_explicit_request(builder, "src/doc") {
+            let index = out.join("index.html");
+            open(builder, &index);
+        }
     }
 }
 
@@ -418,10 +460,25 @@ impl Step for Std {
 
             builder.run(&mut cargo.into());
         };
-        for krate in &["alloc", "core", "std", "proc_macro", "test"] {
+        let krates = ["alloc", "core", "std", "proc_macro", "test"];
+        for krate in &krates {
             run_cargo_rustdoc_for(krate);
         }
         builder.cp_r(&my_out, &out);
+
+        // Look for src/libstd, src/libcore etc in the `x.py doc` arguments and
+        // open the corresponding rendered docs.
+        for path in builder.paths.iter().map(components_simplified) {
+            if path.get(0) == Some(&"src")
+                && path.get(1).map_or(false, |dir| dir.starts_with("lib"))
+            {
+                let requested_crate = &path[1][3..];
+                if krates.contains(&requested_crate) {
+                    let index = out.join(requested_crate).join("index.html");
+                    open(builder, &index);
+                }
+            }
+        }
     }
 }
 
diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs
index 646b9e05d99..cfaa43f3970 100644
--- a/src/bootstrap/flags.rs
+++ b/src/bootstrap/flags.rs
@@ -61,6 +61,7 @@ pub enum Subcommand {
     },
     Doc {
         paths: Vec<PathBuf>,
+        open: bool,
     },
     Test {
         paths: Vec<PathBuf>,
@@ -248,6 +249,9 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`",
             "bench" => {
                 opts.optmulti("", "test-args", "extra arguments", "ARGS");
             }
+            "doc" => {
+                opts.optflag("", "open", "open the docs in a browser");
+            }
             "clean" => {
                 opts.optflag("", "all", "clean all build artifacts");
             }
@@ -404,6 +408,7 @@ Arguments:
         ./x.py doc src/doc/book
         ./x.py doc src/doc/nomicon
         ./x.py doc src/doc/book src/libstd
+        ./x.py doc src/libstd --open
 
     If no arguments are passed then everything is documented:
 
@@ -479,7 +484,7 @@ Arguments:
                 },
             },
             "bench" => Subcommand::Bench { paths, test_args: matches.opt_strs("test-args") },
-            "doc" => Subcommand::Doc { paths },
+            "doc" => Subcommand::Doc { paths, open: matches.opt_present("open") },
             "clean" => {
                 if !paths.is_empty() {
                     println!("\nclean does not take a path argument\n");
@@ -613,6 +618,13 @@ impl Subcommand {
             _ => None,
         }
     }
+
+    pub fn open(&self) -> bool {
+        match *self {
+            Subcommand::Doc { open, .. } => open,
+            _ => false,
+        }
+    }
 }
 
 fn split(s: &[String]) -> Vec<String> {
diff --git a/src/libcore/future/into_future.rs b/src/libcore/future/into_future.rs
new file mode 100644
index 00000000000..4020c254446
--- /dev/null
+++ b/src/libcore/future/into_future.rs
@@ -0,0 +1,27 @@
+use crate::future::Future;
+
+/// Conversion into a `Future`.
+#[unstable(feature = "into_future", issue = "67644")]
+pub trait IntoFuture {
+    /// The output that the future will produce on completion.
+    #[unstable(feature = "into_future", issue = "67644")]
+    type Output;
+
+    /// Which kind of future are we turning this into?
+    #[unstable(feature = "into_future", issue = "67644")]
+    type Future: Future<Output = Self::Output>;
+
+    /// Creates a future from a value.
+    #[unstable(feature = "into_future", issue = "67644")]
+    fn into_future(self) -> Self::Future;
+}
+
+#[unstable(feature = "into_future", issue = "67644")]
+impl<F: Future> IntoFuture for F {
+    type Output = F::Output;
+    type Future = F;
+
+    fn into_future(self) -> Self::Future {
+        self
+    }
+}
diff --git a/src/libcore/future/mod.rs b/src/libcore/future/mod.rs
index b5a102916a0..6f6009b47e6 100644
--- a/src/libcore/future/mod.rs
+++ b/src/libcore/future/mod.rs
@@ -10,12 +10,16 @@ use crate::{
 };
 
 mod future;
+mod into_future;
 mod pending;
 mod ready;
 
 #[stable(feature = "futures_api", since = "1.36.0")]
 pub use self::future::Future;
 
+#[unstable(feature = "into_future", issue = "67644")]
+pub use into_future::IntoFuture;
+
 #[unstable(feature = "future_readiness_fns", issue = "70921")]
 pub use pending::{pending, Pending};
 #[unstable(feature = "future_readiness_fns", issue = "70921")]
diff --git a/src/librustc_error_codes/error_codes/E0599.md b/src/librustc_error_codes/error_codes/E0599.md
index c44e60571e1..5b1590b2999 100644
--- a/src/librustc_error_codes/error_codes/E0599.md
+++ b/src/librustc_error_codes/error_codes/E0599.md
@@ -9,3 +9,18 @@ let x = Mouth;
 x.chocolate(); // error: no method named `chocolate` found for type `Mouth`
                //        in the current scope
 ```
+
+In this case, you need to implement the `chocolate` method to fix the error:
+
+```
+struct Mouth;
+
+impl Mouth {
+    fn chocolate(&self) { // We implement the `chocolate` method here.
+        println!("Hmmm! I love chocolate!");
+    }
+}
+
+let x = Mouth;
+x.chocolate(); // ok!
+```
diff --git a/src/librustc_error_codes/error_codes/E0600.md b/src/librustc_error_codes/error_codes/E0600.md
index 172e2a346c5..356006c72f3 100644
--- a/src/librustc_error_codes/error_codes/E0600.md
+++ b/src/librustc_error_codes/error_codes/E0600.md
@@ -1,6 +1,6 @@
 An unary operator was used on a type which doesn't implement it.
 
-Example of erroneous code:
+Erroneous code example:
 
 ```compile_fail,E0600
 enum Question {
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 05f3b598ecd..adb7fc3eb9c 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -431,6 +431,43 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
 
         look_for_tests(&cx, &dox, &item, true);
 
+        // find item's parent to resolve `Self` in item's docs below
+        let parent_name = self.cx.as_local_hir_id(item.def_id).and_then(|item_hir| {
+            let parent_hir = self.cx.tcx.hir().get_parent_item(item_hir);
+            let item_parent = self.cx.tcx.hir().find(parent_hir);
+            match item_parent {
+                Some(hir::Node::Item(hir::Item {
+                    kind:
+                        hir::ItemKind::Impl {
+                            self_ty:
+                                hir::Ty {
+                                    kind:
+                                        hir::TyKind::Path(hir::QPath::Resolved(
+                                            _,
+                                            hir::Path { segments, .. },
+                                        )),
+                                    ..
+                                },
+                            ..
+                        },
+                    ..
+                })) => segments.first().and_then(|seg| Some(seg.ident.to_string())),
+                Some(hir::Node::Item(hir::Item {
+                    ident, kind: hir::ItemKind::Enum(..), ..
+                }))
+                | Some(hir::Node::Item(hir::Item {
+                    ident, kind: hir::ItemKind::Struct(..), ..
+                }))
+                | Some(hir::Node::Item(hir::Item {
+                    ident, kind: hir::ItemKind::Union(..), ..
+                }))
+                | Some(hir::Node::Item(hir::Item {
+                    ident, kind: hir::ItemKind::Trait(..), ..
+                })) => Some(ident.to_string()),
+                _ => None,
+            }
+        });
+
         for (ori_link, link_range) in markdown_links(&dox) {
             // Bail early for real links.
             if ori_link.contains('/') {
@@ -467,7 +504,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
             };
             let (res, fragment) = {
                 let mut kind = None;
-                let path_str = if let Some(prefix) =
+                let mut path_str = if let Some(prefix) =
                     ["struct@", "enum@", "type@", "trait@", "union@"]
                         .iter()
                         .find(|p| link.starts_with(**p))
@@ -521,6 +558,15 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
                 let base_node =
                     if item.is_mod() && item.attrs.inner_docs { None } else { parent_node };
 
+                let resolved_self;
+                // replace `Self` with suitable item's parent name
+                if path_str.starts_with("Self::") {
+                    if let Some(ref name) = parent_name {
+                        resolved_self = format!("{}::{}", name, &path_str[6..]);
+                        path_str = &resolved_self;
+                    }
+                }
+
                 match kind {
                     Some(ns @ ValueNS) => {
                         match self.resolve(
@@ -529,7 +575,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
                             &current_item,
                             base_node,
                             &extra_fragment,
-                            None,
+                            Some(&item),
                         ) {
                             Ok(res) => res,
                             Err(ErrorKind::ResolutionFailure) => {
@@ -552,7 +598,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
                             &current_item,
                             base_node,
                             &extra_fragment,
-                            None,
+                            Some(&item),
                         ) {
                             Ok(res) => res,
                             Err(ErrorKind::ResolutionFailure) => {
@@ -577,7 +623,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
                                 &current_item,
                                 base_node,
                                 &extra_fragment,
-                                None,
+                                Some(&item),
                             ) {
                                 Err(ErrorKind::AnchorFailure(msg)) => {
                                     anchor_failure(cx, &item, &ori_link, &dox, link_range, msg);
diff --git a/src/libstd/future.rs b/src/libstd/future.rs
index e2092cfefa3..89dd9fb9b2c 100644
--- a/src/libstd/future.rs
+++ b/src/libstd/future.rs
@@ -2,4 +2,16 @@
 
 #[doc(inline)]
 #[stable(feature = "futures_api", since = "1.36.0")]
-pub use core::future::*;
+pub use core::future::Future;
+
+#[doc(inline)]
+#[unstable(feature = "gen_future", issue = "50547")]
+pub use core::future::{from_generator, get_context, ResumeTy};
+
+#[doc(inline)]
+#[unstable(feature = "future_readiness_fns", issue = "70921")]
+pub use core::future::{pending, ready, Pending, Ready};
+
+#[doc(inline)]
+#[unstable(feature = "into_future", issue = "67644")]
+pub use core::future::IntoFuture;
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index ac07af5e278..cc3e613fa3d 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -266,12 +266,15 @@
 #![feature(external_doc)]
 #![feature(fn_traits)]
 #![feature(format_args_nl)]
+#![feature(future_readiness_fns)]
+#![feature(gen_future)]
 #![feature(generator_trait)]
 #![feature(global_asm)]
 #![feature(hash_raw_entry)]
 #![feature(hashmap_internals)]
 #![feature(int_error_internals)]
 #![feature(int_error_matching)]
+#![feature(into_future)]
 #![feature(integer_atomics)]
 #![feature(lang_items)]
 #![feature(libc)]
diff --git a/src/test/rustdoc/intra-link-self.rs b/src/test/rustdoc/intra-link-self.rs
index acf975f5c73..97752d5cfcb 100644
--- a/src/test/rustdoc/intra-link-self.rs
+++ b/src/test/rustdoc/intra-link-self.rs
@@ -1,5 +1,7 @@
 #![crate_name = "foo"]
 
+// ignore-tidy-linelength
+
 // @has foo/index.html '//a/@href' '../foo/struct.Foo.html#method.new'
 // @has foo/struct.Foo.html '//a/@href' '../foo/struct.Foo.html#method.new'
 
@@ -27,3 +29,89 @@ impl Bar {
         unimplemented!()
     }
 }
+
+pub struct MyStruct {
+    // @has foo/struct.MyStruct.html '//a/@href' '../foo/struct.MyStruct.html#structfield.struct_field'
+
+    /// [`struct_field`]
+    ///
+    /// [`struct_field`]: Self::struct_field
+    pub struct_field: u8,
+}
+
+pub enum MyEnum {
+    // @has foo/enum.MyEnum.html '//a/@href' '../foo/enum.MyEnum.html#EnumVariant.v'
+
+    /// [`EnumVariant`]
+    ///
+    /// [`EnumVariant`]: Self::EnumVariant
+    EnumVariant,
+}
+
+pub union MyUnion {
+    // @has foo/union.MyUnion.html '//a/@href' '../foo/union.MyUnion.html#structfield.union_field'
+
+    /// [`union_field`]
+    ///
+    /// [`union_field`]: Self::union_field
+    pub union_field: f32,
+}
+
+pub trait MyTrait {
+    // @has foo/trait.MyTrait.html '//a/@href' '../foo/trait.MyTrait.html#associatedtype.AssoType'
+
+    /// [`AssoType`]
+    ///
+    /// [`AssoType`]: Self::AssoType
+    type AssoType;
+
+    // @has foo/trait.MyTrait.html '//a/@href' '../foo/trait.MyTrait.html#associatedconstant.ASSO_CONST'
+
+    /// [`ASSO_CONST`]
+    ///
+    /// [`ASSO_CONST`]: Self::ASSO_CONST
+    const ASSO_CONST: i32 = 1;
+
+    // @has foo/trait.MyTrait.html '//a/@href' '../foo/trait.MyTrait.html#method.asso_fn'
+
+    /// [`asso_fn`]
+    ///
+    /// [`asso_fn`]: Self::asso_fn
+    fn asso_fn() {}
+}
+
+impl MyStruct {
+    // @has foo/struct.MyStruct.html '//a/@href' '../foo/struct.MyStruct.html#method.for_impl'
+
+    /// [`for_impl`]
+    ///
+    /// [`for_impl`]: Self::for_impl
+    pub fn for_impl() {
+        unimplemented!()
+    }
+}
+
+impl MyTrait for MyStruct {
+    // @has foo/struct.MyStruct.html '//a/@href' '../foo/struct.MyStruct.html#associatedtype.AssoType'
+
+    /// [`AssoType`]
+    ///
+    /// [`AssoType`]: Self::AssoType
+    type AssoType = u32;
+
+    // @has foo/struct.MyStruct.html '//a/@href' '../foo/struct.MyStruct.html#associatedconstant.ASSO_CONST'
+
+    /// [`ASSO_CONST`]
+    ///
+    /// [`ASSO_CONST`]: Self::ASSO_CONST
+    const ASSO_CONST: i32 = 10;
+
+    // @has foo/struct.MyStruct.html '//a/@href' '../foo/struct.MyStruct.html#method.asso_fn'
+
+    /// [`asso_fn`]
+    ///
+    /// [`asso_fn`]: Self::asso_fn
+    fn asso_fn() {
+        unimplemented!()
+    }
+}
diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py
index 988a226706d..72437e07004 100755
--- a/src/tools/publish_toolstate.py
+++ b/src/tools/publish_toolstate.py
@@ -39,6 +39,19 @@ MAINTAINERS = {
     'rustc-dev-guide': {'mark-i-m', 'spastorino', 'amanjeev', 'JohnTitor'},
 }
 
+LABELS = {
+    'miri': ['A-miri', 'C-bug'],
+    'rls': ['A-rls', 'C-bug'],
+    'rustfmt': ['C-bug'],
+    'book': ['C-bug'],
+    'nomicon': ['C-bug'],
+    'reference': ['C-bug'],
+    'rust-by-example': ['C-bug'],
+    'embedded-book': ['C-bug'],
+    'edition-guide': ['C-bug'],
+    'rustc-dev-guide': ['C-bug'],
+}
+
 REPOS = {
     'miri': 'https://github.com/rust-lang/miri',
     'rls': 'https://github.com/rust-lang/rls',
@@ -132,6 +145,7 @@ def issue(
     assignees,
     relevant_pr_number,
     relevant_pr_user,
+    labels,
 ):
     # Open an issue about the toolstate failure.
     if status == 'test-fail':
@@ -155,6 +169,7 @@ def issue(
         )),
         'title': '`{}` no longer builds after {}'.format(tool, relevant_pr_number),
         'assignees': list(assignees),
+        'labels': labels,
     })
     print("Creating issue:\n{}".format(request))
     response = urllib2.urlopen(urllib2.Request(
@@ -235,7 +250,7 @@ def update_latest(
                 try:
                     issue(
                         tool, create_issue_for_status, MAINTAINERS.get(tool, ''),
-                        relevant_pr_number, relevant_pr_user,
+                        relevant_pr_number, relevant_pr_user, LABELS.get(tool, ''),
                     )
                 except urllib2.HTTPError as e:
                     # network errors will simply end up not creating an issue, but that's better
diff --git a/triagebot.toml b/triagebot.toml
index 2210a8ff8e6..f12d5163763 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -37,5 +37,9 @@ label = "ICEBreaker-Cleanup-Crew"
 [prioritize]
 label = "I-prioritize"
 prioritize_on = ["regression-from-stable-to-stable", "regression-from-stable-to-beta", "regression-from-stable-to-nightly"]
-priority_labels = "P-*"
+exclude_labels = [
+    "P-*",
+    "T-infra",
+    "T-release",
+]
 zulip_stream = 227806