From e62663492b2773d50e37a70420f41e758d5af722 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Mon, 2 May 2022 00:00:00 +0000 Subject: [PATCH 01/21] Collect function instance used in `global_asm!` sym operand The constants used in SymFn operands have FnDef type, so the type of the constant identifies the function. --- compiler/rustc_monomorphize/src/collector.rs | 9 +++------ src/test/assembly/asm/global_asm.rs | 5 +++++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 1828aecb375c4..18f32b04fadca 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -445,12 +445,9 @@ fn collect_items_rec<'tcx>( // depend on any other items. } hir::InlineAsmOperand::SymFn { anon_const } => { - let def_id = tcx.hir().body_owner_def_id(anon_const.body).to_def_id(); - if let Ok(val) = tcx.const_eval_poly(def_id) { - rustc_data_structures::stack::ensure_sufficient_stack(|| { - collect_const_value(tcx, val, &mut neighbors); - }); - } + let fn_ty = + tcx.typeck_body(anon_const.body).node_type(anon_const.hir_id); + visit_fn_use(tcx, fn_ty, false, *op_sp, &mut neighbors); } hir::InlineAsmOperand::SymStatic { path: _, def_id } => { let instance = Instance::mono(tcx, *def_id); diff --git a/src/test/assembly/asm/global_asm.rs b/src/test/assembly/asm/global_asm.rs index b76ce7ac387fa..4cf73b40faf0b 100644 --- a/src/test/assembly/asm/global_asm.rs +++ b/src/test/assembly/asm/global_asm.rs @@ -2,6 +2,7 @@ // only-linux // assembly-output: emit-asm // compile-flags: -C llvm-args=--x86-asm-syntax=intel +// compile-flags: -C symbol-mangling-version=v0 #![feature(asm_const, asm_sym)] #![crate_type = "rlib"] @@ -24,3 +25,7 @@ global_asm!("movl ${}, %ecx", const 5, options(att_syntax)); global_asm!("call {}", sym my_func); // CHECK: lea rax, [rip + MY_STATIC] global_asm!("lea rax, [rip + {}]", sym MY_STATIC); +// CHECK: call _RNvCsiubXh4Yz005_10global_asm6foobar +global_asm!("call {}", sym foobar); +// CHECK: _RNvCsiubXh4Yz005_10global_asm6foobar: +fn foobar() { loop {} } From bf4d7fa43fbd4352a4c1c909b5791e2b5f0b07ef Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Fri, 29 Apr 2022 15:27:05 +0100 Subject: [PATCH 02/21] Hide InlineConst's generic arg during print The generic arg is for type inference only and shouldn't be exposed to users. --- compiler/rustc_middle/src/ty/print/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index 3fe68f723ec14..a1d1b6b3a785b 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -136,6 +136,10 @@ pub trait Printer<'tcx>: Sized { match key.disambiguated_data.data { // Closures' own generics are only captures, don't print them. DefPathData::ClosureExpr => {} + // This covers both `DefKind::AnonConst` and `DefKind::InlineConst`. + // Anon consts doesn't have their own generics, and inline consts' own + // generics are their inferred types, so don't print them. + DefPathData::AnonConst => {} // If we have any generic arguments to print, we do that // on top of the same path, but without its own generics. From 6baaa527ce47d835e40afc238bab067ccacabe28 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Fri, 29 Apr 2022 15:27:59 +0100 Subject: [PATCH 03/21] Allow inline consts to reference generic params --- compiler/rustc_resolve/src/late.rs | 9 +++++- .../ui/inline-const/const-expr-generic-err.rs | 15 ++++++++++ .../const-expr-generic-err.stderr | 29 +++++++++++++++++++ .../inline-const/const-expr-generic-err2.rs | 10 +++++++ .../const-expr-generic-err2.stderr | 10 +++++++ .../ui/inline-const/const-expr-generic.rs | 15 ++++++++++ .../inline-const/const-match-pat-generic.rs | 3 +- .../const-match-pat-generic.stderr | 6 ++-- 8 files changed, 91 insertions(+), 6 deletions(-) create mode 100644 src/test/ui/inline-const/const-expr-generic-err.rs create mode 100644 src/test/ui/inline-const/const-expr-generic-err.stderr create mode 100644 src/test/ui/inline-const/const-expr-generic-err2.rs create mode 100644 src/test/ui/inline-const/const-expr-generic-err2.stderr create mode 100644 src/test/ui/inline-const/const-expr-generic.rs diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index ab353128cbcce..16ab22409fd70 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -3101,6 +3101,13 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ); } + fn resolve_inline_const(&mut self, constant: &'ast AnonConst) { + debug!("resolve_anon_const {constant:?}"); + self.with_constant_rib(IsRepeatExpr::No, HasGenericParams::Yes, None, |this| { + visit::walk_anon_const(this, constant); + }); + } + fn resolve_expr(&mut self, expr: &'ast Expr, parent: Option<&'ast Expr>) { // First, record candidate traits for this expression if it could // result in the invocation of a method call. @@ -3257,7 +3264,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { }); } ExprKind::ConstBlock(ref ct) => { - self.resolve_anon_const(ct, IsRepeatExpr::No); + self.resolve_inline_const(ct); } ExprKind::Index(ref elem, ref idx) => { self.resolve_expr(elem, Some(expr)); diff --git a/src/test/ui/inline-const/const-expr-generic-err.rs b/src/test/ui/inline-const/const-expr-generic-err.rs new file mode 100644 index 0000000000000..4e8879af54aff --- /dev/null +++ b/src/test/ui/inline-const/const-expr-generic-err.rs @@ -0,0 +1,15 @@ +// build-fail +#![feature(inline_const)] + +fn foo() { + const { assert!(std::mem::size_of::() == 0); } //~ ERROR E0080 +} + +fn bar() -> usize { + const { N - 1 } //~ ERROR E0080 +} + +fn main() { + foo::(); + bar::<0>(); +} diff --git a/src/test/ui/inline-const/const-expr-generic-err.stderr b/src/test/ui/inline-const/const-expr-generic-err.stderr new file mode 100644 index 0000000000000..db0d85a2d4e74 --- /dev/null +++ b/src/test/ui/inline-const/const-expr-generic-err.stderr @@ -0,0 +1,29 @@ +error[E0080]: evaluation of `foo::::{constant#0}` failed + --> $DIR/const-expr-generic-err.rs:5:13 + | +LL | const { assert!(std::mem::size_of::() == 0); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'assertion failed: std::mem::size_of::() == 0', $DIR/const-expr-generic-err.rs:5:13 + | + = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: the above error was encountered while instantiating `fn foo::` + --> $DIR/const-expr-generic-err.rs:13:5 + | +LL | foo::(); + | ^^^^^^^^^^^^ + +error[E0080]: evaluation of `bar::<0_usize>::{constant#0}` failed + --> $DIR/const-expr-generic-err.rs:9:13 + | +LL | const { N - 1 } + | ^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow + +note: the above error was encountered while instantiating `fn bar::<0_usize>` + --> $DIR/const-expr-generic-err.rs:14:5 + | +LL | bar::<0>(); + | ^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/inline-const/const-expr-generic-err2.rs b/src/test/ui/inline-const/const-expr-generic-err2.rs new file mode 100644 index 0000000000000..e097cbe9dd6d1 --- /dev/null +++ b/src/test/ui/inline-const/const-expr-generic-err2.rs @@ -0,0 +1,10 @@ +#![feature(inline_const)] + +fn foo() { + let _ = [0u8; const { std::mem::size_of::() }]; + //~^ ERROR: constant expression depends on a generic parameter +} + +fn main() { + foo::(); +} diff --git a/src/test/ui/inline-const/const-expr-generic-err2.stderr b/src/test/ui/inline-const/const-expr-generic-err2.stderr new file mode 100644 index 0000000000000..00b716cd25965 --- /dev/null +++ b/src/test/ui/inline-const/const-expr-generic-err2.stderr @@ -0,0 +1,10 @@ +error: constant expression depends on a generic parameter + --> $DIR/const-expr-generic-err2.rs:4:19 + | +LL | let _ = [0u8; const { std::mem::size_of::() }]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error + diff --git a/src/test/ui/inline-const/const-expr-generic.rs b/src/test/ui/inline-const/const-expr-generic.rs new file mode 100644 index 0000000000000..3207bfa0e89e6 --- /dev/null +++ b/src/test/ui/inline-const/const-expr-generic.rs @@ -0,0 +1,15 @@ +// check-pass +#![feature(inline_const)] + +fn foo() -> usize { + const { std::mem::size_of::() } +} + +fn bar() -> usize { + const { N + 1 } +} + +fn main() { + foo::(); + bar::<1>(); +} diff --git a/src/test/ui/inline-const/const-match-pat-generic.rs b/src/test/ui/inline-const/const-match-pat-generic.rs index be7e1d8d44984..e1946467583e9 100644 --- a/src/test/ui/inline-const/const-match-pat-generic.rs +++ b/src/test/ui/inline-const/const-match-pat-generic.rs @@ -1,6 +1,5 @@ #![allow(incomplete_features)] #![feature(inline_const_pat)] -#![feature(generic_const_exprs)] // rust-lang/rust#82518: ICE with inline-const in match referencing const-generic parameter @@ -16,7 +15,7 @@ const fn f(x: usize) -> usize { x + 1 } -fn bar() where [(); f(V)]: { +fn bar() { match 0 { const { f(V) } => {}, //~^ ERROR constant pattern depends on a generic parameter diff --git a/src/test/ui/inline-const/const-match-pat-generic.stderr b/src/test/ui/inline-const/const-match-pat-generic.stderr index 5fe5a7a6dad41..ade200d99ba39 100644 --- a/src/test/ui/inline-const/const-match-pat-generic.stderr +++ b/src/test/ui/inline-const/const-match-pat-generic.stderr @@ -1,17 +1,17 @@ error[E0158]: const parameters cannot be referenced in patterns - --> $DIR/const-match-pat-generic.rs:9:9 + --> $DIR/const-match-pat-generic.rs:8:9 | LL | const { V } => {}, | ^^^^^^^^^^^ error: constant pattern depends on a generic parameter - --> $DIR/const-match-pat-generic.rs:21:9 + --> $DIR/const-match-pat-generic.rs:20:9 | LL | const { f(V) } => {}, | ^^^^^^^^^^^^^^ error: constant pattern depends on a generic parameter - --> $DIR/const-match-pat-generic.rs:21:9 + --> $DIR/const-match-pat-generic.rs:20:9 | LL | const { f(V) } => {}, | ^^^^^^^^^^^^^^ From 5b5ac28c64ce695c7cb85f365b385892d78f1be6 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Thu, 5 May 2022 14:27:11 +0100 Subject: [PATCH 04/21] Bless clippy error msg --- src/tools/clippy/tests/ui/indexing_slicing_index.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/clippy/tests/ui/indexing_slicing_index.stderr b/src/tools/clippy/tests/ui/indexing_slicing_index.stderr index 83a36f407d5d8..6ae700753f06d 100644 --- a/src/tools/clippy/tests/ui/indexing_slicing_index.stderr +++ b/src/tools/clippy/tests/ui/indexing_slicing_index.stderr @@ -1,4 +1,4 @@ -error[E0080]: evaluation of `main::{constant#3}::<&i32>` failed +error[E0080]: evaluation of `main::{constant#3}` failed --> $DIR/indexing_slicing_index.rs:31:14 | LL | const { &ARR[idx4()] }; // Ok, let rustc handle const contexts. From 6c8a2d4715ffc5e8ce8b1aec613c091f0198eaea Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sat, 30 Apr 2022 13:05:40 -0700 Subject: [PATCH 05/21] rustdoc: when running a function-signature search, tweak the tab bar --- src/librustdoc/html/static/css/rustdoc.css | 5 +++ src/librustdoc/html/static/js/search.js | 25 +++++++-------- .../search-tab-change-title-fn-sig.goml | 32 +++++++++++++++++++ ...rch-tab-selection-if-current-is-empty.goml | 23 ------------- 4 files changed, 49 insertions(+), 36 deletions(-) create mode 100644 src/test/rustdoc-gui/search-tab-change-title-fn-sig.goml delete mode 100644 src/test/rustdoc-gui/search-tab-selection-if-current-is-empty.goml diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 81c12be8e83c0..9999c68860715 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1333,6 +1333,11 @@ pre.rust { border-top: 2px solid; } +#titles > button:first-child:last-child { + margin-right: 1px; + width: calc(100% - 1px); +} + #titles > button:not(:last-child) { margin-right: 1px; width: calc(33.3% - 1px); diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 60ad431ba7a99..f93f21af817a0 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -1407,18 +1407,12 @@ window.initSearch = rawSearchIndex => { for (i = 0, nSearchWords = searchWords.length; i < nSearchWords; ++i) { row = searchIndex[i]; in_returned = checkReturned(row, elem, parsedQuery.typeFilter); - addIntoResults(results_returned, row.id, i, -1, in_returned); + addIntoResults(results_others, row.id, i, -1, in_returned); } } } else if (parsedQuery.foundElems > 0) { - let container = results_others; - // In the special case where only a "returned" information is available, we want to - // put the information into the "results_returned" dict. - if (parsedQuery.returned.length !== 0 && parsedQuery.elems.length === 0) { - container = results_returned; - } for (i = 0, nSearchWords = searchWords.length; i < nSearchWords; ++i) { - handleArgs(searchIndex[i], i, container); + handleArgs(searchIndex[i], i, results_others); } } } @@ -1723,12 +1717,17 @@ window.initSearch = rawSearchIndex => { `${typeFilter} in ${crates} `; if (results.query.error !== null) { output += `

Query parser error: "${results.query.error}".

`; + } else if (results.query.foundElems <= 1 && results.query.returned.length === 0) { + output += `
` + + makeTabHeader(0, "In Names", ret_others[1]) + + makeTabHeader(1, "In Parameters", ret_in_args[1]) + + makeTabHeader(2, "In Return Types", ret_returned[1]) + + "
"; + } else { + output += '
' + + makeTabHeader(0, "In Function Signature", ret_others[1]) + + "
"; } - output += `
` + - makeTabHeader(0, "In Names", ret_others[1]) + - makeTabHeader(1, "In Parameters", ret_in_args[1]) + - makeTabHeader(2, "In Return Types", ret_returned[1]) + - "
"; const resultsElem = document.createElement("div"); resultsElem.id = "results"; diff --git a/src/test/rustdoc-gui/search-tab-change-title-fn-sig.goml b/src/test/rustdoc-gui/search-tab-change-title-fn-sig.goml new file mode 100644 index 0000000000000..3269305331b19 --- /dev/null +++ b/src/test/rustdoc-gui/search-tab-change-title-fn-sig.goml @@ -0,0 +1,32 @@ +// Checks that the search tab results work correctly with function signature syntax +// First, try a search-by-name +goto: file://|DOC_PATH|/test_docs/index.html +write: (".search-input", "Foo") +// Waiting for the search results to appear... +wait-for: "#titles" +assert-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"}) +assert-text: ("#titles > button:nth-of-type(1)", "In Names", CONTAINS) + +// Now try search-by-return +goto: file://|DOC_PATH|/test_docs/index.html +write: (".search-input", "-> String") +// Waiting for the search results to appear... +wait-for: "#titles" +assert-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"}) +assert-text: ("#titles > button:nth-of-type(1)", "In Function Signature", CONTAINS) + +// Try with a search-by-return with no results +goto: file://|DOC_PATH|/test_docs/index.html +write: (".search-input", "-> Something") +// Waiting for the search results to appear... +wait-for: "#titles" +assert-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"}) +assert-text: ("#titles > button:nth-of-type(1)", "In Function Signature", CONTAINS) + +// Try with a search-by-return with no results +goto: file://|DOC_PATH|/test_docs/index.html +write: (".search-input", "usize pattern") +// Waiting for the search results to appear... +wait-for: "#titles" +assert-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"}) +assert-text: ("#titles > button:nth-of-type(1)", "In Function Signature", CONTAINS) diff --git a/src/test/rustdoc-gui/search-tab-selection-if-current-is-empty.goml b/src/test/rustdoc-gui/search-tab-selection-if-current-is-empty.goml deleted file mode 100644 index 52b3ceae7b115..0000000000000 --- a/src/test/rustdoc-gui/search-tab-selection-if-current-is-empty.goml +++ /dev/null @@ -1,23 +0,0 @@ -// Checks that the first non-empty search result tab is selected if the default/currently selected -// one is empty. -goto: file://|DOC_PATH|/test_docs/index.html -write: (".search-input", "Foo") -// Waiting for the search results to appear... -wait-for: "#titles" -assert-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"}) - -// To go back to the original "state" -goto: file://|DOC_PATH|/test_docs/index.html -write: (".search-input", "-> String") -// Waiting for the search results to appear... -wait-for: "#titles" -// With this search, only the last tab shouldn't be empty so it should be selected. -assert-attribute: ("#titles > button:nth-of-type(3)", {"class": "selected"}) - -// To go back to the original "state" -goto: file://|DOC_PATH|/test_docs/index.html -write: (".search-input", "-> Something") -// Waiting for the search results to appear... -wait-for: "#titles" -// With this search, all the tabs are empty so the first one should remain selected. -assert-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"}) From 345a580e8d19c59cdd7d6ab5889311d2f07d7931 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sun, 1 May 2022 15:40:46 -0700 Subject: [PATCH 06/21] Use STARTS_WITH, since it's more specific Co-Authored-By: Guillaume Gomez --- src/test/rustdoc-gui/search-tab-change-title-fn-sig.goml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/rustdoc-gui/search-tab-change-title-fn-sig.goml b/src/test/rustdoc-gui/search-tab-change-title-fn-sig.goml index 3269305331b19..3cf34c2f43210 100644 --- a/src/test/rustdoc-gui/search-tab-change-title-fn-sig.goml +++ b/src/test/rustdoc-gui/search-tab-change-title-fn-sig.goml @@ -5,7 +5,7 @@ write: (".search-input", "Foo") // Waiting for the search results to appear... wait-for: "#titles" assert-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"}) -assert-text: ("#titles > button:nth-of-type(1)", "In Names", CONTAINS) +assert-text: ("#titles > button:nth-of-type(1)", "In Names", STARTS_WITH) // Now try search-by-return goto: file://|DOC_PATH|/test_docs/index.html @@ -13,7 +13,7 @@ write: (".search-input", "-> String") // Waiting for the search results to appear... wait-for: "#titles" assert-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"}) -assert-text: ("#titles > button:nth-of-type(1)", "In Function Signature", CONTAINS) +assert-text: ("#titles > button:nth-of-type(1)", "In Function Signature", STARTS_WITH) // Try with a search-by-return with no results goto: file://|DOC_PATH|/test_docs/index.html @@ -21,7 +21,7 @@ write: (".search-input", "-> Something") // Waiting for the search results to appear... wait-for: "#titles" assert-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"}) -assert-text: ("#titles > button:nth-of-type(1)", "In Function Signature", CONTAINS) +assert-text: ("#titles > button:nth-of-type(1)", "In Function Signature", STARTS_WITH) // Try with a search-by-return with no results goto: file://|DOC_PATH|/test_docs/index.html @@ -29,4 +29,4 @@ write: (".search-input", "usize pattern") // Waiting for the search results to appear... wait-for: "#titles" assert-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"}) -assert-text: ("#titles > button:nth-of-type(1)", "In Function Signature", CONTAINS) +assert-text: ("#titles > button:nth-of-type(1)", "In Function Signature", STARTS_WITH) From 21a121332b4c5e2302c46956564879c447d555b2 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Mon, 2 May 2022 09:45:32 -0700 Subject: [PATCH 07/21] rustdoc: change the "In Function Signatures" to context-sensitive * If it's just `-> a`, use "In Function Return Types" * If it's just `a b`, use "In Function Parameters" * Otherwise, still use "In Function Signatures" --- src/librustdoc/html/static/js/search.js | 6 +++++- .../search-tab-change-title-fn-sig.goml | 16 ++++++++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index f93f21af817a0..2468d39ebc702 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -1724,8 +1724,12 @@ window.initSearch = rawSearchIndex => { makeTabHeader(2, "In Return Types", ret_returned[1]) + ""; } else { + const signatureTabTitle = + results.query.elems.length === 0 ? "In Function Return Types" : + results.query.returned.length === 0 ? "In Function Parameters" : + "In Function Signatures"; output += '
' + - makeTabHeader(0, "In Function Signature", ret_others[1]) + + makeTabHeader(0, signatureTabTitle, ret_others[1]) + "
"; } diff --git a/src/test/rustdoc-gui/search-tab-change-title-fn-sig.goml b/src/test/rustdoc-gui/search-tab-change-title-fn-sig.goml index 3cf34c2f43210..fc6b0696bf0db 100644 --- a/src/test/rustdoc-gui/search-tab-change-title-fn-sig.goml +++ b/src/test/rustdoc-gui/search-tab-change-title-fn-sig.goml @@ -13,7 +13,7 @@ write: (".search-input", "-> String") // Waiting for the search results to appear... wait-for: "#titles" assert-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"}) -assert-text: ("#titles > button:nth-of-type(1)", "In Function Signature", STARTS_WITH) +assert-text: ("#titles > button:nth-of-type(1)", "In Function Return Types", STARTS_WITH) // Try with a search-by-return with no results goto: file://|DOC_PATH|/test_docs/index.html @@ -21,12 +21,20 @@ write: (".search-input", "-> Something") // Waiting for the search results to appear... wait-for: "#titles" assert-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"}) -assert-text: ("#titles > button:nth-of-type(1)", "In Function Signature", STARTS_WITH) +assert-text: ("#titles > button:nth-of-type(1)", "In Function Return Types", STARTS_WITH) -// Try with a search-by-return with no results +// Try with a search-by-parameter goto: file://|DOC_PATH|/test_docs/index.html write: (".search-input", "usize pattern") // Waiting for the search results to appear... wait-for: "#titles" assert-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"}) -assert-text: ("#titles > button:nth-of-type(1)", "In Function Signature", STARTS_WITH) +assert-text: ("#titles > button:nth-of-type(1)", "In Function Parameters", STARTS_WITH) + +// Try with a search-by-parameter-and-return +goto: file://|DOC_PATH|/test_docs/index.html +write: (".search-input", "pattern -> str") +// Waiting for the search results to appear... +wait-for: "#titles" +assert-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"}) +assert-text: ("#titles > button:nth-of-type(1)", "In Function Signatures", STARTS_WITH) From 8b2147b4970a06377defd142fa932d2264d2aa5d Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Mon, 2 May 2022 15:50:01 -0700 Subject: [PATCH 08/21] rustdoc: fix keyboard shortcuts and console log on search page --- src/librustdoc/html/static/js/search.js | 36 ++++++++++++------- .../search-tab-change-title-fn-sig.goml | 20 +++++++++++ 2 files changed, 44 insertions(+), 12 deletions(-) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 2468d39ebc702..2bb850f994d0d 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -43,26 +43,33 @@ const TY_KEYWORD = itemTypes.indexOf("keyword"); // In the search display, allows to switch between tabs. function printTab(nb) { - if (nb === 0 || nb === 1 || nb === 2) { - searchState.currentTab = nb; - } - let nb_copy = nb; + let iter = 0; + let foundCurrentTab = false; + let foundCurrentResultSet = false; onEachLazy(document.getElementById("titles").childNodes, elem => { - if (nb_copy === 0) { + if (nb === iter) { addClass(elem, "selected"); + foundCurrentTab = true; } else { removeClass(elem, "selected"); } - nb_copy -= 1; + iter += 1; }); + iter = 0; onEachLazy(document.getElementById("results").childNodes, elem => { - if (nb === 0) { + if (nb === iter) { addClass(elem, "active"); + foundCurrentResultSet = true; } else { removeClass(elem, "active"); } - nb -= 1; + iter += 1; }); + if (foundCurrentTab && foundCurrentResultSet) { + searchState.currentTab = nb; + } else if (nb != 0) { + printTab(0); + } } /** @@ -1731,6 +1738,7 @@ window.initSearch = rawSearchIndex => { output += '
' + makeTabHeader(0, signatureTabTitle, ret_others[1]) + "
"; + currentTab = 0; } const resultsElem = document.createElement("div"); @@ -1746,12 +1754,16 @@ window.initSearch = rawSearchIndex => { } search.appendChild(resultsElem); // Reset focused elements. - searchState.focusedByTab = [null, null, null]; searchState.showResults(search); const elems = document.getElementById("titles").childNodes; - elems[0].onclick = () => { printTab(0); }; - elems[1].onclick = () => { printTab(1); }; - elems[2].onclick = () => { printTab(2); }; + searchState.focusedByTab = []; + let i = 0; + for (const elem of elems) { + const j = i; + elem.onclick = () => { printTab(j); }; + searchState.focusedByTab.push(null); + i += 1; + } printTab(currentTab); } diff --git a/src/test/rustdoc-gui/search-tab-change-title-fn-sig.goml b/src/test/rustdoc-gui/search-tab-change-title-fn-sig.goml index fc6b0696bf0db..7bc837bfaeb68 100644 --- a/src/test/rustdoc-gui/search-tab-change-title-fn-sig.goml +++ b/src/test/rustdoc-gui/search-tab-change-title-fn-sig.goml @@ -6,6 +6,16 @@ write: (".search-input", "Foo") wait-for: "#titles" assert-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"}) assert-text: ("#titles > button:nth-of-type(1)", "In Names", STARTS_WITH) +// Use left-right keys +press-key: "ArrowDown" +press-key: "ArrowRight" +wait-for-attribute: ("#titles > button:nth-of-type(2)", {"class": "selected"}) +press-key: "ArrowRight" +wait-for-attribute: ("#titles > button:nth-of-type(3)", {"class": "selected"}) +press-key: "ArrowRight" +wait-for-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"}) +press-key: "ArrowLeft" +wait-for-attribute: ("#titles > button:nth-of-type(3)", {"class": "selected"}) // Now try search-by-return goto: file://|DOC_PATH|/test_docs/index.html @@ -14,6 +24,16 @@ write: (".search-input", "-> String") wait-for: "#titles" assert-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"}) assert-text: ("#titles > button:nth-of-type(1)", "In Function Return Types", STARTS_WITH) +// Use left-right keys +press-key: "ArrowDown" +press-key: "ArrowRight" +wait-for-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"}) +press-key: "ArrowRight" +wait-for-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"}) +press-key: "ArrowRight" +wait-for-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"}) +press-key: "ArrowLeft" +wait-for-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"}) // Try with a search-by-return with no results goto: file://|DOC_PATH|/test_docs/index.html From 75790fabedbb2abd0a9ec30b65655398c89c10e1 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 3 May 2022 09:20:22 -0700 Subject: [PATCH 09/21] rustdoc: add test case assertions for ArrowDown highlight first result --- src/test/rustdoc-gui/search-tab-change-title-fn-sig.goml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/test/rustdoc-gui/search-tab-change-title-fn-sig.goml b/src/test/rustdoc-gui/search-tab-change-title-fn-sig.goml index 7bc837bfaeb68..763927f9d0fe9 100644 --- a/src/test/rustdoc-gui/search-tab-change-title-fn-sig.goml +++ b/src/test/rustdoc-gui/search-tab-change-title-fn-sig.goml @@ -6,8 +6,10 @@ write: (".search-input", "Foo") wait-for: "#titles" assert-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"}) assert-text: ("#titles > button:nth-of-type(1)", "In Names", STARTS_WITH) +assert: "input.search-input:focus" // Use left-right keys press-key: "ArrowDown" +assert: "#results > .search-results.active > a:nth-of-type(1):focus" press-key: "ArrowRight" wait-for-attribute: ("#titles > button:nth-of-type(2)", {"class": "selected"}) press-key: "ArrowRight" @@ -24,8 +26,10 @@ write: (".search-input", "-> String") wait-for: "#titles" assert-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"}) assert-text: ("#titles > button:nth-of-type(1)", "In Function Return Types", STARTS_WITH) +assert: "input.search-input:focus" // Use left-right keys press-key: "ArrowDown" +assert: "#results > .search-results.active > a:nth-of-type(1):focus" press-key: "ArrowRight" wait-for-attribute: ("#titles > button:nth-of-type(1)", {"class": "selected"}) press-key: "ArrowRight" From 4c183cd2d41abfe22b20ff1c9d5a1bb712ef1d71 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 3 May 2022 09:20:45 -0700 Subject: [PATCH 10/21] rustdoc: fix JS error when rendering parse error --- src/librustdoc/html/static/js/search.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 2bb850f994d0d..e755d27f73784 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -1724,6 +1724,10 @@ window.initSearch = rawSearchIndex => { `${typeFilter} in ${crates} `; if (results.query.error !== null) { output += `

Query parser error: "${results.query.error}".

`; + output += '
' + + makeTabHeader(0, "In Names", ret_others[1]) + + "
"; + currentTab = 0; } else if (results.query.foundElems <= 1 && results.query.returned.length === 0) { output += `
` + makeTabHeader(0, "In Names", ret_others[1]) + From 30309db9722699743f54026b2837ef6a217c0b9d Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Tue, 3 May 2022 19:17:57 -0700 Subject: [PATCH 11/21] Put the 2229 migration errors in alphabetical order Looks like they were in FxHash order before, so it might just be luck that this used to be consistent across different word lengths. --- compiler/rustc_typeck/src/check/upvar.rs | 4 ++++ .../2229_closure_analysis/migrations/auto_traits.stderr | 2 +- .../migrations/mir_calls_to_shims.stderr | 2 +- .../2229_closure_analysis/migrations/multi_diagnostics.stderr | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 9dbb813293263..c1d4bb92173da 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -914,6 +914,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { reasons.auto_traits.extend(auto_trait_reasons); reasons.drop_order = drop_order; + // `auto_trait_reasons` are in hashset order, so sort them to put the + // diagnostics we emit later in a cross-platform-consistent order. + reasons.auto_traits.sort_unstable(); + reasons } diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr index ee4907bb755cc..a8367766ae1cf 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr @@ -29,8 +29,8 @@ error: changes to closure capture in Rust 2021 will affect which traits the clos LL | thread::spawn(move || unsafe { | ^^^^^^^^^^^^^^ | | - | in Rust 2018, this closure implements `Sync` as `fptr` implements `Sync`, but in Rust 2021, this closure will no longer implement `Sync` because `fptr` is not fully captured and `fptr.0.0` does not implement `Sync` | in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` because `fptr` is not fully captured and `fptr.0.0` does not implement `Send` + | in Rust 2018, this closure implements `Sync` as `fptr` implements `Sync`, but in Rust 2021, this closure will no longer implement `Sync` because `fptr` is not fully captured and `fptr.0.0` does not implement `Sync` ... LL | *fptr.0.0 = 20; | --------- in Rust 2018, this closure captures all of `fptr`, but in Rust 2021, it will only capture `fptr.0.0` diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr index 6594ec316532a..2648b00435b31 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/mir_calls_to_shims.stderr @@ -4,8 +4,8 @@ error: changes to closure capture in Rust 2021 will affect which traits the clos LL | let result = panic::catch_unwind(move || { | ^^^^^^^ | | - | in Rust 2018, this closure implements `UnwindSafe` as `f` implements `UnwindSafe`, but in Rust 2021, this closure will no longer implement `UnwindSafe` because `f` is not fully captured and `f.0` does not implement `UnwindSafe` | in Rust 2018, this closure implements `RefUnwindSafe` as `f` implements `RefUnwindSafe`, but in Rust 2021, this closure will no longer implement `RefUnwindSafe` because `f` is not fully captured and `f.0` does not implement `RefUnwindSafe` + | in Rust 2018, this closure implements `UnwindSafe` as `f` implements `UnwindSafe`, but in Rust 2021, this closure will no longer implement `UnwindSafe` because `f` is not fully captured and `f.0` does not implement `UnwindSafe` ... LL | f.0() | --- in Rust 2018, this closure captures all of `f`, but in Rust 2021, it will only capture `f.0` diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr index 0008f1b2c07ed..483eae6bb4b1f 100644 --- a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr +++ b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr @@ -94,8 +94,8 @@ error: changes to closure capture in Rust 2021 will affect which traits the clos LL | thread::spawn(move || unsafe { | ^^^^^^^^^^^^^^ | | - | in Rust 2018, this closure implements `Sync` as `fptr1` implements `Sync`, but in Rust 2021, this closure will no longer implement `Sync` because `fptr1` is not fully captured and `fptr1.0.0` does not implement `Sync` | in Rust 2018, this closure implements `Send` as `fptr1` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` because `fptr1` is not fully captured and `fptr1.0.0` does not implement `Send` + | in Rust 2018, this closure implements `Sync` as `fptr1` implements `Sync`, but in Rust 2021, this closure will no longer implement `Sync` because `fptr1` is not fully captured and `fptr1.0.0` does not implement `Sync` | in Rust 2018, this closure implements `Send` as `fptr2` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` because `fptr2` is not fully captured and `fptr2.0` does not implement `Send` ... LL | *fptr1.0.0 = 20; From 20010d759718ade4ae33a173539ff808854ac269 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Thu, 5 May 2022 17:20:14 -0700 Subject: [PATCH 12/21] rustdoc: ensure HTML/JS side implementors don't have dups --- src/librustdoc/html/render/print_item.rs | 102 +++++++++++++++--- src/librustdoc/html/render/write_shared.rs | 9 +- src/librustdoc/html/static/js/main.js | 8 +- src/test/rustdoc-gui/implementors.goml | 7 ++ .../rustdoc-gui/src/lib2/implementors/lib.rs | 9 ++ src/test/rustdoc-gui/src/lib2/lib.rs | 7 ++ 6 files changed, 126 insertions(+), 16 deletions(-) diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index f1915920b6d05..b6ac687731e49 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -3,7 +3,7 @@ use clean::AttributesExt; use std::cmp::Ordering; use std::fmt; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; use rustc_hir::def::CtorKind; use rustc_hir::def_id::DefId; @@ -790,16 +790,18 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra render_assoc_items(w, cx, it, it.item_id.expect_def_id(), AssocItemRender::All); let cache = cx.cache(); + let mut extern_crates = FxHashSet::default(); if let Some(implementors) = cache.implementors.get(&it.item_id.expect_def_id()) { // The DefId is for the first Type found with that name. The bool is // if any Types with the same name but different DefId have been found. let mut implementor_dups: FxHashMap = FxHashMap::default(); for implementor in implementors { - match implementor.inner_impl().for_ { - clean::Type::Path { ref path } - | clean::BorrowedRef { type_: box clean::Type::Path { ref path }, .. } - if !path.is_assoc_ty() => - { + if let Some(did) = implementor.inner_impl().for_.without_borrowed_ref().def_id(cx.cache()) && + !did.is_local() { + extern_crates.insert(did.krate); + } + match implementor.inner_impl().for_.without_borrowed_ref() { + clean::Type::Path { ref path } if !path.is_assoc_ty() => { let did = path.def_id(); let &mut (prev_did, ref mut has_duplicates) = implementor_dups.entry(path.last()).or_insert((did, false)); @@ -898,20 +900,96 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra } } + // Include implementors in crates that depend on the current crate. + // + // This is complicated by the way rustdoc is invoked, which is basically + // the same way rustc is invoked: it gets called, one at a time, for each + // crate. When building the rustdocs for the current crate, rustdoc can + // see crate metadata for its dependencies, but cannot see metadata for its + // dependents. + // + // To make this work, we generate a "hook" at this stage, and our + // dependents can "plug in" to it when they build. For simplicity's sake, + // it's [JSONP]: a JavaScript file with the data we need (and can parse), + // surrounded by a tiny wrapper that the Rust side ignores, but allows the + // JavaScript side to include without having to worry about Same Origin + // Policy. The code for *that* is in `write_shared.rs`. + // + // This is further complicated by `#[doc(inline)]`. We want all copies + // of an inlined trait to reference the same JS file, to address complex + // dependency graphs like this one (lower crates depend on higher crates): + // + // ```text + // -------------------------------------------- + // | crate A: trait Foo | + // -------------------------------------------- + // | | + // -------------------------------- | + // | crate B: impl A::Foo for Bar | | + // -------------------------------- | + // | | + // --------------------------------------------- + // | crate C: #[doc(inline)] use A::Foo as Baz | + // | impl Baz for Quux | + // --------------------------------------------- + // ``` + // + // Basically, we want `C::Baz` and `A::Foo` to show the same set of + // impls, which is easier if they both treat `/implementors/A/trait.Foo.js` + // as the Single Source of Truth. + // + // We also want the `impl Baz for Quux` to be written to + // `trait.Foo.js`. However, when we generate plain HTML for `C::Baz`, + // we're going to want to generate plain HTML for `impl Baz for Quux` too, + // because that'll load faster, and it's better for SEO. And we don't want + // the same impl to show up twice on the same page. + // + // To make this work, the implementors JS file has a structure kinda + // like this: + // + // ```js + // JSONP({ + // "B": {"impl A::Foo for Bar"}, + // "C": {"impl Baz for Quux"}, + // }); + // ``` + // + // First of all, this means we can rebuild a crate, and it'll replace its own + // data if something changes. That is, `rustdoc` is idempotent. The other + // advantage is that we can list the crates that get included in the HTML, + // and ignore them when doing the JavaScript-based part of rendering. + // So C's HTML will have something like this: + // + // ```html + // + // ``` + // + // And, when the JS runs, anything in data-ignore-extern-crates is known + // to already be in the HTML, and will be ignored. + // + // [JSONP]: https://en.wikipedia.org/wiki/JSONP let mut js_src_path: UrlPartsBuilder = std::iter::repeat("..") .take(cx.current.len()) .chain(std::iter::once("implementors")) .collect(); - if it.item_id.is_local() { - js_src_path.extend(cx.current.iter().copied()); + if let Some(did) = it.item_id.as_def_id() && + let get_extern = { || cache.external_paths.get(&did).map(|s| s.0.clone()) } && + let Some(fqp) = cache.exact_paths.get(&did).cloned().or_else(get_extern) { + js_src_path.extend(fqp[..fqp.len() - 1].iter().copied()); + js_src_path.push_fmt(format_args!("{}.{}.js", it.type_(), fqp.last().unwrap())); } else { - let (ref path, _) = cache.external_paths[&it.item_id.expect_def_id()]; - js_src_path.extend(path[..path.len() - 1].iter().copied()); + js_src_path.extend(cx.current.iter().copied()); + js_src_path.push_fmt(format_args!("{}.{}.js", it.type_(), it.name.unwrap())); } - js_src_path.push_fmt(format_args!("{}.{}.js", it.type_(), it.name.unwrap())); + let extern_crates = extern_crates + .into_iter() + .map(|cnum| cx.shared.tcx.crate_name(cnum).to_string()) + .collect::>() + .join(","); write!( w, - "", + "", src = js_src_path.finish(), ); } diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index 7c202e471adbe..e8e5fa1799333 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -501,10 +501,13 @@ pub(super) fn write_shared( // // FIXME: this is a vague explanation for why this can't be a `get`, in // theory it should be... - let &(ref remote_path, remote_item_type) = match cache.paths.get(&did) { - Some(p) => p, + let (remote_path, remote_item_type) = match cache.exact_paths.get(&did) { + Some(p) => match cache.paths.get(&did).or_else(|| cache.external_paths.get(&did)) { + Some((_, t)) => (p, t), + None => continue, + }, None => match cache.external_paths.get(&did) { - Some(p) => p, + Some((p, t)) => (p, t), None => continue, }, }; diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 1dfd9c762c46e..272b129362dff 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -756,8 +756,14 @@ function loadCss(cssFileName) { const traitName = document.querySelector("h1.fqn > .in-band > .trait").textContent; const baseIdName = "impl-" + traitName + "-"; const libs = Object.getOwnPropertyNames(imp); + // We don't want to include impls from this JS file, when the HTML already has them. + // The current crate should always be ignored. Other crates that should also be + // ignored are included in the attribute `data-ignore-extern-crates`. + const ignoreExternCrates = document + .querySelector("script[data-ignore-extern-crates]") + .getAttribute("data-ignore-extern-crates"); for (const lib of libs) { - if (lib === window.currentCrate) { + if (lib === window.currentCrate || ignoreExternCrates.indexOf(lib) !== -1) { continue; } const structs = imp[lib]; diff --git a/src/test/rustdoc-gui/implementors.goml b/src/test/rustdoc-gui/implementors.goml index 6460a917e92d0..ccc69cc6bd7a7 100644 --- a/src/test/rustdoc-gui/implementors.goml +++ b/src/test/rustdoc-gui/implementors.goml @@ -18,3 +18,10 @@ assert: "#implementors-list .impl:nth-child(2) > .code-header.in-band" goto: file://|DOC_PATH|/test_docs/struct.HasEmptyTraits.html compare-elements-position-near-false: ("#impl-EmptyTrait1", "#impl-EmptyTrait2", {"y": 30}) compare-elements-position-near: ("#impl-EmptyTrait3 h3", "#impl-EmptyTrait3 .item-info", {"y": 30}) + +// Now check that re-exports work correctly. +// There should be exactly one impl shown on both of these pages. +goto: file://|DOC_PATH|/lib2/trait.TraitToReexport.html +assert-count: ("#implementors-list .impl", 1) +goto: file://|DOC_PATH|/implementors/trait.TraitToReexport.html +assert-count: ("#implementors-list .impl", 1) \ No newline at end of file diff --git a/src/test/rustdoc-gui/src/lib2/implementors/lib.rs b/src/test/rustdoc-gui/src/lib2/implementors/lib.rs index 6417a6ac5af6d..1620e84229191 100644 --- a/src/test/rustdoc-gui/src/lib2/implementors/lib.rs +++ b/src/test/rustdoc-gui/src/lib2/implementors/lib.rs @@ -9,3 +9,12 @@ pub struct Struct; impl Whatever for Struct { type Foo = u8; } + +mod traits { + pub trait TraitToReexport { + fn method() {} + } +} + +#[doc(inline)] +pub use traits::TraitToReexport; diff --git a/src/test/rustdoc-gui/src/lib2/lib.rs b/src/test/rustdoc-gui/src/lib2/lib.rs index 83e86c439344a..d06b46f952d0e 100644 --- a/src/test/rustdoc-gui/src/lib2/lib.rs +++ b/src/test/rustdoc-gui/src/lib2/lib.rs @@ -43,6 +43,13 @@ impl implementors::Whatever for Foo { type Foo = u32; } +#[doc(inline)] +pub use implementors::TraitToReexport; + +pub struct StructToImplOnReexport; + +impl TraitToReexport for StructToImplOnReexport {} + pub mod sub_mod { /// ```txt /// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa From 903aebe318f638ddc46e0b799e6fcc022492887c Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Thu, 5 May 2022 18:26:47 -0700 Subject: [PATCH 13/21] Fix test case checking for where the JS goes --- src/test/rustdoc/hidden-impls.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/rustdoc/hidden-impls.rs b/src/test/rustdoc/hidden-impls.rs index 935bfb268637f..8f33a6604c219 100644 --- a/src/test/rustdoc/hidden-impls.rs +++ b/src/test/rustdoc/hidden-impls.rs @@ -12,6 +12,6 @@ pub mod __hidden { // @has foo/trait.Clone.html // @!has - 'Foo' -// @has implementors/foo/trait.Clone.js +// @has implementors/core/clone/trait.Clone.js // @!has - 'Foo' pub use std::clone::Clone; From 8ff01894a010690b9c7232d1217931dbc5d63333 Mon Sep 17 00:00:00 2001 From: SparrowLii Date: Fri, 6 May 2022 12:11:42 +0800 Subject: [PATCH 14/21] turn `append_place_to_string` from recursion into iteration --- .../rustc_borrowck/src/diagnostics/mod.rs | 210 +++++++----------- 1 file changed, 78 insertions(+), 132 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 368c0be794bcc..05d29503180ef 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -1,5 +1,6 @@ //! Borrow checker diagnostics. +use itertools::Itertools; use rustc_const_eval::util::{call_kind, CallDesugaringKind}; use rustc_errors::{Applicability, Diagnostic}; use rustc_hir as hir; @@ -161,158 +162,103 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } /// End-user visible description of `place` if one can be found. - /// If the place is a temporary for instance, None will be returned. + /// If the place is a temporary for instance, `None` will be returned. pub(super) fn describe_place(&self, place_ref: PlaceRef<'tcx>) -> Option { self.describe_place_with_options(place_ref, IncludingDowncast(false)) } - /// End-user visible description of `place` if one can be found. If the - /// place is a temporary for instance, None will be returned. - /// `IncludingDowncast` parameter makes the function return `Err` if `ProjectionElem` is + /// End-user visible description of `place` if one can be found. If the place is a temporary + /// for instance, `None` will be returned. + /// `IncludingDowncast` parameter makes the function return `None` if `ProjectionElem` is /// `Downcast` and `IncludingDowncast` is true pub(super) fn describe_place_with_options( &self, place: PlaceRef<'tcx>, including_downcast: IncludingDowncast, ) -> Option { + let local = place.local; + let mut autoderef_index = None; let mut buf = String::new(); - match self.append_place_to_string(place, &mut buf, false, &including_downcast) { - Ok(()) => Some(buf), - Err(()) => None, - } - } - - /// Appends end-user visible description of `place` to `buf`. - fn append_place_to_string( - &self, - place: PlaceRef<'tcx>, - buf: &mut String, - mut autoderef: bool, - including_downcast: &IncludingDowncast, - ) -> Result<(), ()> { - match place { - PlaceRef { local, projection: [] } => { - self.append_local_to_string(local, buf)?; - } - PlaceRef { local, projection: [ProjectionElem::Deref] } - if self.body.local_decls[local].is_ref_for_guard() => - { - self.append_place_to_string( - PlaceRef { local, projection: &[] }, - buf, - autoderef, - &including_downcast, - )?; - } - PlaceRef { local, projection: [ProjectionElem::Deref] } - if self.body.local_decls[local].is_ref_to_static() => - { - let local_info = &self.body.local_decls[local].local_info; - if let Some(box LocalInfo::StaticRef { def_id, .. }) = *local_info { - buf.push_str(self.infcx.tcx.item_name(def_id).as_str()); - } else { - unreachable!(); - } - } - PlaceRef { local, projection: [proj_base @ .., elem] } => { - match elem { - ProjectionElem::Deref => { - let upvar_field_projection = self.is_upvar_field_projection(place); - if let Some(field) = upvar_field_projection { - let var_index = field.index(); - let name = self.upvars[var_index].place.to_string(self.infcx.tcx); - if self.upvars[var_index].by_ref { - buf.push_str(&name); - } else { - buf.push('*'); - buf.push_str(&name); - } - } else { - if autoderef { - // FIXME turn this recursion into iteration - self.append_place_to_string( - PlaceRef { local, projection: proj_base }, - buf, - autoderef, - &including_downcast, - )?; - } else { - buf.push('*'); - self.append_place_to_string( - PlaceRef { local, projection: proj_base }, - buf, - autoderef, - &including_downcast, - )?; - } + let mut ok = self.append_local_to_string(local, &mut buf); + + for (index, elem) in place.projection.into_iter().enumerate() { + match elem { + ProjectionElem::Deref => { + if index == 0 { + if self.body.local_decls[local].is_ref_for_guard() { + continue; } - } - ProjectionElem::Downcast(..) => { - self.append_place_to_string( - PlaceRef { local, projection: proj_base }, - buf, - autoderef, - &including_downcast, - )?; - if including_downcast.0 { - return Err(()); + if let Some(box LocalInfo::StaticRef { def_id, .. }) = + &self.body.local_decls[local].local_info + { + buf.push_str(self.infcx.tcx.item_name(*def_id).as_str()); + ok = Ok(()); + continue; } } - ProjectionElem::Field(field, _ty) => { - autoderef = true; - - // FIXME(project-rfc_2229#36): print capture precisely here. - let upvar_field_projection = self.is_upvar_field_projection(place); - if let Some(field) = upvar_field_projection { - let var_index = field.index(); - let name = self.upvars[var_index].place.to_string(self.infcx.tcx); - buf.push_str(&name); - } else { - let field_name = self - .describe_field(PlaceRef { local, projection: proj_base }, *field); - self.append_place_to_string( - PlaceRef { local, projection: proj_base }, - buf, - autoderef, - &including_downcast, - )?; - buf.push('.'); - buf.push_str(&field_name); + if let Some(field) = self.is_upvar_field_projection(PlaceRef { + local, + projection: place.projection.split_at(index + 1).0, + }) { + let var_index = field.index(); + buf = self.upvars[var_index].place.to_string(self.infcx.tcx); + ok = Ok(()); + if !self.upvars[var_index].by_ref { + buf.insert(0, '*'); } - } - ProjectionElem::Index(index) => { - autoderef = true; - - self.append_place_to_string( - PlaceRef { local, projection: proj_base }, - buf, - autoderef, - &including_downcast, - )?; - buf.push('['); - if self.append_local_to_string(*index, buf).is_err() { - buf.push('_'); + } else { + if autoderef_index.is_none() { + autoderef_index = + match place.projection.into_iter().rev().find_position(|elem| { + !matches!( + elem, + ProjectionElem::Deref | ProjectionElem::Downcast(..) + ) + }) { + Some((index, _)) => Some(place.projection.len() - index), + None => Some(0), + }; + } + if index >= autoderef_index.unwrap() { + buf.insert(0, '*'); } - buf.push(']'); } - ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => { - autoderef = true; - // Since it isn't possible to borrow an element on a particular index and - // then use another while the borrow is held, don't output indices details - // to avoid confusing the end-user - self.append_place_to_string( - PlaceRef { local, projection: proj_base }, - buf, - autoderef, - &including_downcast, - )?; - buf.push_str("[..]"); + } + ProjectionElem::Downcast(..) if including_downcast.0 => return None, + ProjectionElem::Downcast(..) => (), + ProjectionElem::Field(field, _ty) => { + // FIXME(project-rfc_2229#36): print capture precisely here. + if let Some(field) = self.is_upvar_field_projection(PlaceRef { + local, + projection: place.projection.split_at(index + 1).0, + }) { + buf = self.upvars[field.index()].place.to_string(self.infcx.tcx); + ok = Ok(()); + } else { + let field_name = self.describe_field( + PlaceRef { local, projection: place.projection.split_at(index).0 }, + *field, + ); + buf.push('.'); + buf.push_str(&field_name); } - }; + } + ProjectionElem::Index(index) => { + buf.push('['); + if self.append_local_to_string(*index, &mut buf).is_err() { + buf.push('_'); + } + buf.push(']'); + } + ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => { + // Since it isn't possible to borrow an element on a particular index and + // then use another while the borrow is held, don't output indices details + // to avoid confusing the end-user + buf.push_str("[..]"); + } } } - - Ok(()) + ok.ok().map(|_| buf) } /// Appends end-user visible description of the `local` place to `buf`. If `local` doesn't have From 279dee5374dbaaf7c33ddb584bf29061a4971e05 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 5 May 2022 21:56:03 +0200 Subject: [PATCH 15/21] Fix reexports missing from the search index --- src/librustdoc/formats/cache.rs | 11 ++++++++++- src/librustdoc/html/render/mod.rs | 11 ++++++++++- src/librustdoc/html/render/print_item.rs | 7 ++++++- src/librustdoc/html/static/js/search.js | 3 +++ 4 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index b4d2772b31da2..30190138750ca 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -248,7 +248,16 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { } // Index this method for searching later on. - if let Some(ref s) = item.name { + if let Some(ref s) = item.name.or_else(|| { + if item.is_stripped() { + None + } else if let clean::ImportItem(ref i) = *item.kind && + let clean::ImportKind::Simple(s) = i.kind { + Some(s) + } else { + None + } + }) { let (parent, is_inherent_impl_item) = match *item.kind { clean::StrippedItem(..) => ((None, None), false), clean::AssocConstItem(..) | clean::AssocTypeItem(..) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index fedeb449b2e0e..1958248191017 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -2542,7 +2542,16 @@ fn sidebar_module(buf: &mut Buffer, items: &[clean::Item]) { let item_sections_in_use: FxHashSet<_> = items .iter() - .filter(|it| !it.is_stripped() && it.name.is_some()) + .filter(|it| { + !it.is_stripped() + && it + .name + .or_else(|| { + if let clean::ImportItem(ref i) = *it.kind && + let clean::ImportKind::Simple(s) = i.kind { Some(s) } else { None } + }) + .is_some() + }) .map(|it| item_ty_to_section(it.type_())) .collect(); for &sec in ItemSection::ALL.iter().filter(|sec| item_sections_in_use.contains(sec)) { diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index f1915920b6d05..0ad54abf807a5 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -346,7 +346,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl w.write_str(ITEM_TABLE_ROW_OPEN); write!( w, - "
\ + "
\ {vis}{imp}\
\
{stab_tags}
", @@ -355,6 +355,11 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl vis = myitem.visibility.print_with_space(myitem.item_id, cx), imp = import.print(cx), stab_tags = stab_tags.unwrap_or_default(), + id = match import.kind { + clean::ImportKind::Simple(s) => + format!(" id=\"{}\"", cx.derive_id(format!("reexport.{}", s))), + clean::ImportKind::Glob => String::new(), + }, ); w.write_str(ITEM_TABLE_ROW_CLOSE); } diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 60ad431ba7a99..ba4e3f82565a3 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -1507,6 +1507,9 @@ window.initSearch = rawSearchIndex => { displayPath = path + "::"; href = window.rootPath + path.replace(/::/g, "/") + "/" + name + "/index.html"; + } else if (type === "import") { + displayPath = item.path + "::"; + href = window.rootPath + item.path.replace(/::/g, "/") + "/index.html#reexport." + name; } else if (type === "primitive" || type === "keyword") { displayPath = ""; href = window.rootPath + path.replace(/::/g, "/") + From fb2f97a37e8a3541368004daa5ddb38ec3048fe8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 5 May 2022 21:56:40 +0200 Subject: [PATCH 16/21] Add GUI test for search reexports --- src/test/rustdoc-gui/search-reexport.goml | 29 +++++++++++++++++++++++ src/test/rustdoc-gui/sidebar.goml | 19 ++++++++------- src/test/rustdoc-gui/src/test_docs/lib.rs | 3 +++ 3 files changed, 42 insertions(+), 9 deletions(-) create mode 100644 src/test/rustdoc-gui/search-reexport.goml diff --git a/src/test/rustdoc-gui/search-reexport.goml b/src/test/rustdoc-gui/search-reexport.goml new file mode 100644 index 0000000000000..557781d481092 --- /dev/null +++ b/src/test/rustdoc-gui/search-reexport.goml @@ -0,0 +1,29 @@ +// Checks that the reexports are present in the search index, can have +// doc aliases and are highligted when their ID is the hash of the page. +goto: file://|DOC_PATH|/test_docs/index.html +local-storage: {"rustdoc-theme": "dark", "rustdoc-use-system-theme": "false"} +reload: +// First we check that the reexport has the correct ID and no background color. +assert-text: ("//*[@id='reexport.TheStdReexport']", "pub use ::std as TheStdReexport;") +assert-css: ("//*[@id='reexport.TheStdReexport']", {"background-color": "rgba(0, 0, 0, 0)"}) +write: (".search-input", "TheStdReexport") +wait-for: "//a[@class='result-import']" +assert-attribute: ( + "//a[@class='result-import']", + {"href": "../test_docs/index.html#reexport.TheStdReexport"}, +) +assert-text: ("//a[@class='result-import']", "test_docs::TheStdReexport") +click: "//a[@class='result-import']" +// We check that it has the background modified thanks to the focus. +wait-for-css: ("//*[@id='reexport.TheStdReexport']", {"background-color": "rgb(73, 74, 61)"}) + +// We now check that the alias is working as well on the reexport. +write: (".search-input", "AliasForTheStdReexport") +wait-for: "//a[@class='result-import']" +assert-text: ( + "//a[@class='result-import']", + "AliasForTheStdReexport - see test_docs::TheStdReexport", +) +// Same thing again, we click on it to ensure the background is once again set as expected. +click: "//a[@class='result-import']" +wait-for-css: ("//*[@id='reexport.TheStdReexport']", {"background-color": "rgb(73, 74, 61)"}) diff --git a/src/test/rustdoc-gui/sidebar.goml b/src/test/rustdoc-gui/sidebar.goml index 6b79b00d3f786..32fe3334f3644 100644 --- a/src/test/rustdoc-gui/sidebar.goml +++ b/src/test/rustdoc-gui/sidebar.goml @@ -13,15 +13,16 @@ assert-css: ("#all-types", {"color": "rgb(53, 109, 164)"}) // We check that we have the crates list and that the "current" on is "test_docs". assert-text: (".sidebar-elems .crate > ul > li > a.current", "test_docs") // And we're also supposed to have the list of items in the current module. -assert-text: (".sidebar-elems section ul > li:nth-child(1)", "Modules") -assert-text: (".sidebar-elems section ul > li:nth-child(2)", "Macros") -assert-text: (".sidebar-elems section ul > li:nth-child(3)", "Structs") -assert-text: (".sidebar-elems section ul > li:nth-child(4)", "Enums") -assert-text: (".sidebar-elems section ul > li:nth-child(5)", "Traits") -assert-text: (".sidebar-elems section ul > li:nth-child(6)", "Functions") -assert-text: (".sidebar-elems section ul > li:nth-child(7)", "Type Definitions") -assert-text: (".sidebar-elems section ul > li:nth-child(8)", "Unions") -assert-text: (".sidebar-elems section ul > li:nth-child(9)", "Keywords") +assert-text: (".sidebar-elems section ul > li:nth-child(1)", "Re-exports") +assert-text: (".sidebar-elems section ul > li:nth-child(2)", "Modules") +assert-text: (".sidebar-elems section ul > li:nth-child(3)", "Macros") +assert-text: (".sidebar-elems section ul > li:nth-child(4)", "Structs") +assert-text: (".sidebar-elems section ul > li:nth-child(5)", "Enums") +assert-text: (".sidebar-elems section ul > li:nth-child(6)", "Traits") +assert-text: (".sidebar-elems section ul > li:nth-child(7)", "Functions") +assert-text: (".sidebar-elems section ul > li:nth-child(8)", "Type Definitions") +assert-text: (".sidebar-elems section ul > li:nth-child(9)", "Unions") +assert-text: (".sidebar-elems section ul > li:nth-child(10)", "Keywords") assert-text: ("#structs + .item-table .item-left > a", "Foo") click: "#structs + .item-table .item-left > a" diff --git a/src/test/rustdoc-gui/src/test_docs/lib.rs b/src/test/rustdoc-gui/src/test_docs/lib.rs index 348b1a65c786c..b6fe9eb2565bd 100644 --- a/src/test/rustdoc-gui/src/test_docs/lib.rs +++ b/src/test/rustdoc-gui/src/test_docs/lib.rs @@ -274,3 +274,6 @@ impl EmptyTrait3 for HasEmptyTraits {} mod macros; pub use macros::*; + +#[doc(alias = "AliasForTheStdReexport")] +pub use ::std as TheStdReexport; From bd11e22203c0d7bb87375a3a39c53649af50593c Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 6 May 2022 05:18:32 -0700 Subject: [PATCH 17/21] Add missing newline --- src/test/rustdoc-gui/implementors.goml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/rustdoc-gui/implementors.goml b/src/test/rustdoc-gui/implementors.goml index ccc69cc6bd7a7..f29613f78b1b2 100644 --- a/src/test/rustdoc-gui/implementors.goml +++ b/src/test/rustdoc-gui/implementors.goml @@ -24,4 +24,4 @@ compare-elements-position-near: ("#impl-EmptyTrait3 h3", "#impl-EmptyTrait3 .ite goto: file://|DOC_PATH|/lib2/trait.TraitToReexport.html assert-count: ("#implementors-list .impl", 1) goto: file://|DOC_PATH|/implementors/trait.TraitToReexport.html -assert-count: ("#implementors-list .impl", 1) \ No newline at end of file +assert-count: ("#implementors-list .impl", 1) From 857eb02abe3931271db6d85a899fccba6d3ab65e Mon Sep 17 00:00:00 2001 From: Takayuki Maeda <41065217+TaKO8Ki@users.noreply.github.com> Date: Fri, 6 May 2022 23:14:11 +0900 Subject: [PATCH 18/21] suggest fully qualified path with appropriate params --- .../infer/error_reporting/need_type_info.rs | 23 ++++++- ...-qualified-path-with-appropriate-params.rs | 24 ++++++++ ...lified-path-with-appropriate-params.stderr | 61 +++++++++++++++++++ 3 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/traits/suggest-fully-qualified-path-with-appropriate-params.rs create mode 100644 src/test/ui/traits/suggest-fully-qualified-path-with-appropriate-params.stderr diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index b1eb9f0da87f7..78e0864d918d9 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -731,6 +731,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // | help: specify type like: `>::into(foo_impl)` // | // = note: cannot satisfy `Impl: Into<_>` + debug!(?segment); if !impl_candidates.is_empty() && e.span.contains(span) && let Some(expr) = exprs.first() && let ExprKind::Path(hir::QPath::Resolved(_, path)) = expr.kind @@ -739,9 +740,29 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let mut eraser = TypeParamEraser(self.tcx); let candidate_len = impl_candidates.len(); let mut suggestions: Vec<_> = impl_candidates.iter().map(|candidate| { + let trait_item = self.tcx + .associated_items(candidate.def_id) + .find_by_name_and_kind( + self.tcx, + segment.ident, + ty::AssocKind::Fn, + candidate.def_id + ); + let prefix = if let Some(trait_item) = trait_item + && let Some(trait_m) = trait_item.def_id.as_local() + && let hir::TraitItemKind::Fn(fn_, _) = &self.tcx.hir().trait_item(hir::TraitItemId { def_id: trait_m }).kind + { + match fn_.decl.implicit_self { + hir::ImplicitSelfKind::ImmRef => "&", + hir::ImplicitSelfKind::MutRef => "&mut ", + _ => "", + } + } else { + "" + }; let candidate = candidate.super_fold_with(&mut eraser); vec![ - (expr.span.shrink_to_lo(), format!("{}::{}(", candidate, segment.ident)), + (expr.span.shrink_to_lo(), format!("{}::{}({}", candidate, segment.ident, prefix)), if exprs.len() == 1 { (expr.span.shrink_to_hi().with_hi(e.span.hi()), ")".to_string()) } else { diff --git a/src/test/ui/traits/suggest-fully-qualified-path-with-appropriate-params.rs b/src/test/ui/traits/suggest-fully-qualified-path-with-appropriate-params.rs new file mode 100644 index 0000000000000..da68b996be999 --- /dev/null +++ b/src/test/ui/traits/suggest-fully-qualified-path-with-appropriate-params.rs @@ -0,0 +1,24 @@ +struct Thing; + +trait Method { + fn method(&self) -> T; + fn mut_method(&mut self) -> T; +} + +impl Method for Thing { + fn method(&self) -> i32 { 0 } + fn mut_method(&mut self) -> i32 { 0 } +} + +impl Method for Thing { + fn method(&self) -> u32 { 0 } + fn mut_method(&mut self) -> u32 { 0 } +} + +fn main() { + let thing = Thing; + thing.method(); + //~^ ERROR type annotations needed + //~| ERROR type annotations needed + thing.mut_method(); //~ ERROR type annotations needed +} diff --git a/src/test/ui/traits/suggest-fully-qualified-path-with-appropriate-params.stderr b/src/test/ui/traits/suggest-fully-qualified-path-with-appropriate-params.stderr new file mode 100644 index 0000000000000..0c4962417e9bc --- /dev/null +++ b/src/test/ui/traits/suggest-fully-qualified-path-with-appropriate-params.stderr @@ -0,0 +1,61 @@ +error[E0282]: type annotations needed + --> $DIR/suggest-fully-qualified-path-with-appropriate-params.rs:20:11 + | +LL | thing.method(); + | ------^^^^^^-- + | | | + | | cannot infer type for type parameter `T` declared on the trait `Method` + | this method call resolves to `T` + +error[E0283]: type annotations needed + --> $DIR/suggest-fully-qualified-path-with-appropriate-params.rs:20:11 + | +LL | thing.method(); + | ------^^^^^^-- + | | | + | | cannot infer type for type parameter `T` declared on the trait `Method` + | this method call resolves to `T` + | +note: multiple `impl`s satisfying `Thing: Method<_>` found + --> $DIR/suggest-fully-qualified-path-with-appropriate-params.rs:8:1 + | +LL | impl Method for Thing { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | impl Method for Thing { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: use the fully qualified path for the potential candidates + | +LL | >::method(&thing); + | ++++++++++++++++++++++++++++++++ ~ +LL | >::method(&thing); + | ++++++++++++++++++++++++++++++++ ~ + +error[E0283]: type annotations needed + --> $DIR/suggest-fully-qualified-path-with-appropriate-params.rs:23:11 + | +LL | thing.mut_method(); + | ------^^^^^^^^^^-- + | | | + | | cannot infer type for type parameter `T` declared on the trait `Method` + | this method call resolves to `T` + | +note: multiple `impl`s satisfying `Thing: Method<_>` found + --> $DIR/suggest-fully-qualified-path-with-appropriate-params.rs:8:1 + | +LL | impl Method for Thing { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | impl Method for Thing { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: use the fully qualified path for the potential candidates + | +LL | >::mut_method(&mut thing); + | +++++++++++++++++++++++++++++++++++++++ ~ +LL | >::mut_method(&mut thing); + | +++++++++++++++++++++++++++++++++++++++ ~ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0282, E0283. +For more information about an error, try `rustc --explain E0282`. From 85e688e4c3c14df05b6430ae7d736ffc9180e9c7 Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Fri, 6 May 2022 14:59:40 +0000 Subject: [PATCH 19/21] Fix comment for async closure variant --- compiler/rustc_hir/src/hir.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index dfeee3f356ffb..9f3072e169c6c 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1441,7 +1441,7 @@ pub enum AsyncGeneratorKind { /// An explicit `async` block written by the user. Block, - /// An explicit `async` block written by the user. + /// An explicit `async` closure written by the user. Closure, /// The `async` block generated as the body of an async function. From fcb385cfb116d4689ddc4ffc121d650bdc94ad91 Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Fri, 6 May 2022 15:00:48 +0000 Subject: [PATCH 20/21] Use matches! for YieldSource::is_await --- compiler/rustc_hir/src/hir.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 9f3072e169c6c..cc6ddad2e15df 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2078,10 +2078,7 @@ pub enum YieldSource { impl YieldSource { pub fn is_await(&self) -> bool { - match self { - YieldSource::Await { .. } => true, - YieldSource::Yield => false, - } + matches!(self, YieldSource::Await { .. }) } } From a87fa6314f0ba8bb1b75c129301c57e08bce3a29 Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 6 May 2022 19:00:37 +0200 Subject: [PATCH 21/21] `mirror_expr` cleanup --- compiler/rustc_mir_build/src/thir/cx/expr.rs | 37 +++++++++----------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index f382f79af29db..147c136e651dd 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -158,6 +158,7 @@ impl<'tcx> Cx<'tcx> { } fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx> { + let tcx = self.tcx; let expr_ty = self.typeck_results().expr_ty(expr); let expr_span = expr.span; let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id); @@ -196,7 +197,7 @@ impl<'tcx> Cx<'tcx> { let arg_tys = args.iter().map(|e| self.typeck_results().expr_ty_adjusted(e)); let tupled_args = Expr { - ty: self.tcx.mk_tup(arg_tys), + ty: tcx.mk_tup(arg_tys), temp_lifetime, span: expr.span, kind: ExprKind::Tuple { fields: self.mirror_exprs(args) }, @@ -488,24 +489,24 @@ impl<'tcx> Cx<'tcx> { out_expr: out_expr.as_ref().map(|expr| self.mirror_expr(expr)), }, hir::InlineAsmOperand::Const { ref anon_const } => { - let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id); + let anon_const_def_id = tcx.hir().local_def_id(anon_const.hir_id); let value = mir::ConstantKind::from_anon_const( - self.tcx, + tcx, anon_const_def_id, self.param_env, ); - let span = self.tcx.hir().span(anon_const.hir_id); + let span = tcx.hir().span(anon_const.hir_id); InlineAsmOperand::Const { value, span } } hir::InlineAsmOperand::SymFn { ref anon_const } => { - let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id); + let anon_const_def_id = tcx.hir().local_def_id(anon_const.hir_id); let value = mir::ConstantKind::from_anon_const( - self.tcx, + tcx, anon_const_def_id, self.param_env, ); - let span = self.tcx.hir().span(anon_const.hir_id); + let span = tcx.hir().span(anon_const.hir_id); InlineAsmOperand::SymFn { value, span } } @@ -519,21 +520,16 @@ impl<'tcx> Cx<'tcx> { }, hir::ExprKind::ConstBlock(ref anon_const) => { - let tcx = self.tcx; - let local_def_id = tcx.hir().local_def_id(anon_const.hir_id); - let anon_const_def_id = local_def_id.to_def_id(); - - // Need to include the parent substs - let hir_id = tcx.hir().local_def_id_to_hir_id(local_def_id); - let ty = tcx.typeck(local_def_id).node_type(hir_id); - let typeck_root_def_id = tcx.typeck_root_def_id(anon_const_def_id); + let ty = self.typeck_results().node_type(anon_const.hir_id); + let did = tcx.hir().local_def_id(anon_const.hir_id).to_def_id(); + let typeck_root_def_id = tcx.typeck_root_def_id(did); let parent_substs = tcx.erase_regions(InternalSubsts::identity_for_item(tcx, typeck_root_def_id)); let substs = InlineConstSubsts::new(tcx, InlineConstSubstsParts { parent_substs, ty }) .substs; - ExprKind::ConstBlock { did: anon_const_def_id, substs } + ExprKind::ConstBlock { did, substs } } // Now comes the rote stuff: hir::ExprKind::Repeat(ref v, _) => { @@ -591,7 +587,7 @@ impl<'tcx> Cx<'tcx> { } hir::ExprKind::Field(ref source, ..) => ExprKind::Field { lhs: self.mirror_expr(source), - name: Field::new(self.tcx.field_index(expr.hir_id, self.typeck_results)), + name: Field::new(tcx.field_index(expr.hir_id, self.typeck_results)), }, hir::ExprKind::Cast(ref source, ref cast_ty) => { // Check for a user-given type annotation on this `cast` @@ -640,7 +636,7 @@ impl<'tcx> Cx<'tcx> { let (d, o) = adt_def.discriminant_def_for_variant(idx); use rustc_middle::ty::util::IntTypeExt; let ty = adt_def.repr().discr_type(); - let ty = ty.to_ty(self.tcx()); + let ty = ty.to_ty(tcx); Some((d, o, ty)) } _ => None, @@ -652,8 +648,7 @@ impl<'tcx> Cx<'tcx> { let source = if let Some((did, offset, var_ty)) = var { let param_env_ty = self.param_env.and(var_ty); - let size = self - .tcx + let size = tcx .layout_of(param_env_ty) .unwrap_or_else(|e| { panic!("could not compute layout for {:?}: {:?}", param_env_ty, e) @@ -671,7 +666,7 @@ impl<'tcx> Cx<'tcx> { Some(did) => { // in case we are offsetting from a computed discriminant // and not the beginning of discriminants (which is always `0`) - let substs = InternalSubsts::identity_for_item(self.tcx(), did); + let substs = InternalSubsts::identity_for_item(tcx, did); let kind = ExprKind::NamedConst { def_id: did, substs, user_ty: None }; let lhs = self.thir.exprs.push(Expr {