From bdfdc71d0f56a592fd888fcd89e6e9c6188b156c Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Wed, 29 Apr 2020 18:13:52 +0900 Subject: [PATCH 01/24] Implement FromStr for OsString --- src/libstd/ffi/os_str.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 4fde33169733e..7a05aaf71f2c1 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -4,6 +4,7 @@ use crate::fmt; use crate::hash::{Hash, Hasher}; use crate::ops; use crate::rc::Rc; +use crate::str::FromStr; use crate::sync::Arc; use crate::sys::os_str::{Buf, Slice}; @@ -1174,6 +1175,15 @@ impl AsInner for OsStr { } } +#[stable(feature = "osstring_from_str", since = "1.45.0")] +impl FromStr for OsString { + type Err = core::convert::Infallible; + + fn from_str(s: &str) -> Result { + Ok(OsString::from(s)) + } +} + #[cfg(test)] mod tests { use super::*; From cf5e4a749c13d3a472a6aed4097df5dc90194057 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Wed, 29 Apr 2020 10:58:36 -0400 Subject: [PATCH 02/24] Add explicit references to the BuildHasher trait --- src/libstd/collections/hash/map.rs | 10 ++++++++++ src/libstd/collections/hash/set.rs | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index e6da7426eb4af..56cf9be339194 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -251,6 +251,9 @@ impl HashMap { /// cause many collisions and very poor performance. Setting it /// manually using this function can expose a DoS attack vector. /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the HashMap to be useful, see its documentation for details. + /// /// # Examples /// /// ``` @@ -261,6 +264,8 @@ impl HashMap { /// let mut map = HashMap::with_hasher(s); /// map.insert(1, 2); /// ``` + /// + /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html #[inline] #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] pub fn with_hasher(hash_builder: S) -> HashMap { @@ -278,6 +283,9 @@ impl HashMap { /// cause many collisions and very poor performance. Setting it /// manually using this function can expose a DoS attack vector. /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the HashMap to be useful, see its documentation for details. + /// /// # Examples /// /// ``` @@ -288,6 +296,8 @@ impl HashMap { /// let mut map = HashMap::with_capacity_and_hasher(10, s); /// map.insert(1, 2); /// ``` + /// + /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html #[inline] #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> HashMap { diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index c1a57f2ce6129..ca06457291cae 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -273,6 +273,9 @@ impl HashSet { /// cause many collisions and very poor performance. Setting it /// manually using this function can expose a DoS attack vector. /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the HashMap to be useful, see its documentation for details. + /// /// # Examples /// /// ``` @@ -283,6 +286,8 @@ impl HashSet { /// let mut set = HashSet::with_hasher(s); /// set.insert(2); /// ``` + /// + /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html #[inline] #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] pub fn with_hasher(hasher: S) -> HashSet { @@ -300,6 +305,9 @@ impl HashSet { /// cause many collisions and very poor performance. Setting it /// manually using this function can expose a DoS attack vector. /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the HashMap to be useful, see its documentation for details. + /// /// # Examples /// /// ``` @@ -310,6 +318,8 @@ impl HashSet { /// let mut set = HashSet::with_capacity_and_hasher(10, s); /// set.insert(1); /// ``` + /// + /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html #[inline] #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> HashSet { From d80ac14fe69676c34efdec0c1cc589d28cd03ab1 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 30 Apr 2020 15:37:00 +0200 Subject: [PATCH 03/24] Extend rustdoc-js tester to allow to test multiple queries in one file --- src/tools/rustdoc-js/tester.js | 98 ++++++++++++++++++++++------------ 1 file changed, 65 insertions(+), 33 deletions(-) diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js index 03f06fc1c6c71..72bc496c5b5d3 100644 --- a/src/tools/rustdoc-js/tester.js +++ b/src/tools/rustdoc-js/tester.js @@ -181,7 +181,7 @@ function loadThings(thingsToLoad, kindOfLoad, funcToCall, fileContent) { for (var i = 0; i < thingsToLoad.length; ++i) { var tmp = funcToCall(fileContent, thingsToLoad[i]); if (tmp === null) { - console.error('unable to find ' + kindOfLoad + ' "' + thingsToLoad[i] + '"'); + console.log('unable to find ' + kindOfLoad + ' "' + thingsToLoad[i] + '"'); process.exit(1); } content += tmp; @@ -223,7 +223,8 @@ function loadMainJsAndIndex(mainJs, aliases, searchIndex, crate) { searchIndex.pop(); } searchIndex.pop(); - searchIndex = loadContent(searchIndex.join("\n") + '\nexports.searchIndex = searchIndex;'); + var fullSearchIndex = searchIndex.join("\n") + '\nexports.rawSearchIndex = searchIndex;'; + searchIndex = loadContent(fullSearchIndex); var finalJS = ""; var arraysToLoad = ["itemTypes"]; @@ -235,7 +236,7 @@ function loadMainJsAndIndex(mainJs, aliases, searchIndex, crate) { // execQuery last parameter is built in buildIndex. // buildIndex requires the hashmap from search-index. var functionsToLoad = ["buildHrefAndPath", "pathSplitter", "levenshtein", "validateResult", - "getQuery", "buildIndex", "execQuery", "execSearch"]; + "handleAliases", "getQuery", "buildIndex", "execQuery", "execSearch"]; finalJS += 'window = { "currentCrate": "' + crate + '" };\n'; finalJS += 'var rootPath = "../";\n'; @@ -245,24 +246,19 @@ function loadMainJsAndIndex(mainJs, aliases, searchIndex, crate) { finalJS += loadThings(functionsToLoad, 'function', extractFunction, mainJs); var loaded = loadContent(finalJS); - var index = loaded.buildIndex(searchIndex.searchIndex); + var index = loaded.buildIndex(searchIndex.rawSearchIndex); + // We make it "global" so that the "loaded.execSearch" function will find it. + rawSearchIndex = searchIndex.rawSearchIndex; return [loaded, index]; } -function runChecks(testFile, loaded, index) { - var errors = 0; - var loadedFile = loadContent( - readFile(testFile) + 'exports.QUERY = QUERY;exports.EXPECTED = EXPECTED;'); - - const expected = loadedFile.EXPECTED; - const query = loadedFile.QUERY; +function runSearch(query, expected, index, loaded, loadedFile, queryName) { const filter_crate = loadedFile.FILTER_CRATE; const ignore_order = loadedFile.ignore_order; const exact_check = loadedFile.exact_check; - const should_fail = loadedFile.should_fail; - var results = loaded.execSearch(loaded.getQuery(query), index); + var results = loaded.execSearch(loaded.getQuery(query), index, filter_crate); var error_text = []; for (var key in expected) { @@ -278,32 +274,68 @@ function runChecks(testFile, loaded, index) { for (var i = 0; i < entry.length; ++i) { var entry_pos = lookForEntry(entry[i], results[key]); if (entry_pos === null) { - error_text.push("==> Result not found in '" + key + "': '" + + error_text.push(queryName + "==> Result not found in '" + key + "': '" + JSON.stringify(entry[i]) + "'"); } else if (exact_check === true && prev_pos + 1 !== entry_pos) { - error_text.push("==> Exact check failed at position " + (prev_pos + 1) + ": " + - "expected '" + JSON.stringify(entry[i]) + "' but found '" + + error_text.push(queryName + "==> Exact check failed at position " + (prev_pos + 1) + + ": expected '" + JSON.stringify(entry[i]) + "' but found '" + JSON.stringify(results[key][i]) + "'"); } else if (ignore_order === false && entry_pos < prev_pos) { - error_text.push("==> '" + JSON.stringify(entry[i]) + "' was supposed to be " + - " before '" + JSON.stringify(results[key][entry_pos]) + "'"); + error_text.push(queryName + "==> '" + JSON.stringify(entry[i]) + "' was supposed " + + "to be before '" + JSON.stringify(results[key][entry_pos]) + "'"); } else { prev_pos = entry_pos; } } } - if (error_text.length === 0 && should_fail === true) { - errors += 1; - console.error("FAILED"); - console.error("==> Test was supposed to fail but all items were found..."); - } else if (error_text.length !== 0 && should_fail === false) { - errors += 1; - console.error("FAILED"); - console.error(error_text.join("\n")); + return error_text; +} + +function checkResult(error_text, loadedFile, displaySuccess) { + if (error_text.length === 0 && loadedFile.should_fail === true) { + console.log("FAILED"); + console.log("==> Test was supposed to fail but all items were found..."); + } else if (error_text.length !== 0 && loadedFile.should_fail === false) { + console.log("FAILED"); + console.log(error_text.join("\n")); } else { + if (displaySuccess) { + console.log("OK"); + } + return 0; + } + return 1; +} + +function runChecks(testFile, loaded, index) { + var loadedFile = loadContent( + readFile(testFile) + 'exports.QUERY = QUERY;exports.EXPECTED = EXPECTED;'); + + const expected = loadedFile.EXPECTED; + const query = loadedFile.QUERY; + + if (Array.isArray(query)) { + if (!Array.isArray(expected)) { + console.log("FAILED"); + console.log("==> If QUERY variable is an array, EXPECTED should be an array too"); + return 1; + } else if (query.length !== expected.length) { + console.log("FAILED"); + console.log("==> QUERY variable should have the same length as EXPECTED"); + return 1; + } + for (var i = 0; i < query.length; ++i) { + var error_text = runSearch(query[i], expected[i], index, loaded, loadedFile, + "[ query `" + query[i] + "`]"); + if (checkResult(error_text, loadedFile, false) !== 0) { + return 1; + } + } console.log("OK"); + return 0; } - return errors; + var error_text = runSearch(query, expected, index, loaded, loadedFile, ""); + return checkResult(error_text, loadedFile, true); } function load_files(doc_folder, resource_suffix, crate) { @@ -349,7 +381,7 @@ function parseOptions(args) { || args[i] === "--crate-name") { i += 1; if (i >= args.length) { - console.error("Missing argument after `" + args[i - 1] + "` option."); + console.log("Missing argument after `" + args[i - 1] + "` option."); return null; } opts[correspondances[args[i - 1]]] = args[i]; @@ -357,17 +389,17 @@ function parseOptions(args) { showHelp(); process.exit(0); } else { - console.error("Unknown option `" + args[i] + "`."); - console.error("Use `--help` to see the list of options"); + console.log("Unknown option `" + args[i] + "`."); + console.log("Use `--help` to see the list of options"); return null; } } if (opts["doc_folder"].length < 1) { - console.error("Missing `--doc-folder` option."); + console.log("Missing `--doc-folder` option."); } else if (opts["crate_name"].length < 1) { - console.error("Missing `--crate-name` option."); + console.log("Missing `--crate-name` option."); } else if (opts["test_folder"].length < 1 && opts["test_file"].length < 1) { - console.error("At least one of `--test-folder` or `--test-file` option is required."); + console.log("At least one of `--test-folder` or `--test-file` option is required."); } else { return opts; } From 7590c393dee055e9ce97f8a5f993fa0cc7e56217 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 30 Apr 2020 20:53:40 +0200 Subject: [PATCH 04/24] Improve doc alias JS code --- src/librustdoc/html/static/main.js | 73 ++++++++++++++++++++---------- 1 file changed, 50 insertions(+), 23 deletions(-) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index a023d5a2d95f1..411d2d44059b2 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -963,6 +963,50 @@ function getSearchElement() { return itemTypes[ty.ty] + ty.path + ty.name; } + function handleAliases(ret, query, filterCrates) { + if (ALIASES) { + var aliases = []; + if (filterCrates !== undefined && + ALIASES[filterCrates] && + ALIASES[filterCrates][query.search]) { + aliases = ALIASES[filterCrates][query.search]; + } else { + Object.keys(ALIASES).forEach(function(crate) { + if (ALIASES[crate][query.search]) { + for (var i = 0; i < ALIASES[crate][query.search].length; ++i) { + aliases.push(ALIASES[crate][query.search][i]); + } + } + }); + } + aliases.sort(function(aaa, bbb) { + if (aaa.path < bbb.path) { + return 1; + } else if (aaa.path === bbb.path) { + return 0; + } + return -1; + }); + for (var i = 0; i < aliases.length; ++i) { + var alias = aliases[i]; + alias.is_alias = true; + if (typeof alias.parent === "number") { + alias.parent = rawSearchIndex[alias.crate].p[alias.parent]; + } + alias.alias = query.raw; + alias.path = alias.p || alias.crate; + var res = buildHrefAndPath(aliases[i]); + alias.displayPath = pathSplitter(res[0]); + alias.fullPath = alias.displayPath + alias.name; + alias.href = res[1]; + ret.others.unshift(alias); + if (ret.others.length > MAX_RESULTS) { + ret.others.pop(); + } + } + } + } + // quoted values mean literal search var nSearchWords = searchWords.length; var i; @@ -1190,23 +1234,7 @@ function getSearchElement() { "returned": sortResults(results_returned, true), "others": sortResults(results), }; - if (ALIASES && ALIASES[window.currentCrate] && - ALIASES[window.currentCrate][query.raw]) { - var aliases = ALIASES[window.currentCrate][query.raw]; - for (i = 0; i < aliases.length; ++i) { - aliases[i].is_alias = true; - aliases[i].alias = query.raw; - aliases[i].path = aliases[i].p; - var res = buildHrefAndPath(aliases[i]); - aliases[i].displayPath = pathSplitter(res[0]); - aliases[i].fullPath = aliases[i].displayPath + aliases[i].name; - aliases[i].href = res[1]; - ret.others.unshift(aliases[i]); - if (ret.others.length > MAX_RESULTS) { - ret.others.pop(); - } - } - } + handleAliases(ret, query, filterCrates); return ret; } @@ -1599,13 +1627,12 @@ function getSearchElement() { "returned": mergeArrays(results.returned), "others": mergeArrays(results.others), }; - } else { - return { - "in_args": results.in_args[0], - "returned": results.returned[0], - "others": results.others[0], - }; } + return { + "in_args": results.in_args[0], + "returned": results.returned[0], + "others": results.others[0], + }; } function getFilterCrates() { From cf41b1d3a5fc5e4c209ab101b159095178dea916 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 30 Apr 2020 20:54:06 +0200 Subject: [PATCH 05/24] Improve doc alias discovery --- src/librustdoc/html/render.rs | 11 +++- src/librustdoc/html/render/cache.rs | 89 +++++++++++++++++------------ 2 files changed, 61 insertions(+), 39 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 666e59b9a045e..4ed367a5c80d3 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -278,7 +278,7 @@ pub struct RenderInfo { /// Struct representing one entry in the JS search index. These are all emitted /// by hand to a large JS file at the end of cache-creation. #[derive(Debug)] -struct IndexItem { +pub struct IndexItem { ty: ItemType, name: String, path: String, @@ -293,7 +293,12 @@ impl Serialize for IndexItem { where S: Serializer, { - assert_eq!(self.parent.is_some(), self.parent_idx.is_some()); + assert_eq!( + self.parent.is_some(), + self.parent_idx.is_some(), + "`{}` is missing idx", + self.name + ); (self.ty, &self.name, &self.path, &self.desc, self.parent_idx, &self.search_type) .serialize(serializer) @@ -836,7 +841,7 @@ themePicker.onblur = handleThemeButtonsBlur; { let (mut all_aliases, _) = try_err!(collect(&dst, &krate.name, "ALIASES"), &dst); let mut output = String::with_capacity(100); - for (alias, items) in &cx.cache.aliases { + for (alias, items) in cx.cache.get_aliases() { if items.is_empty() { continue; } diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs index 5b09029122718..17003334bc856 100644 --- a/src/librustdoc/html/render/cache.rs +++ b/src/librustdoc/html/render/cache.rs @@ -120,7 +120,7 @@ crate struct Cache { /// Aliases added through `#[doc(alias = "...")]`. Since a few items can have the same alias, /// we need the alias element to have an array of items. - pub(super) aliases: FxHashMap>, + pub(super) aliases: FxHashMap>, } impl Cache { @@ -311,7 +311,7 @@ impl DocFolder for Cache { }; match parent { - (parent, Some(path)) if is_inherent_impl_item || (!self.stripped_mod) => { + (parent, Some(path)) if is_inherent_impl_item || !self.stripped_mod => { debug_assert!(!item.is_stripped()); // A crate has a module at its root, containing all items, @@ -327,6 +327,21 @@ impl DocFolder for Cache { parent_idx: None, search_type: get_index_search_type(&item), }); + + for alias in item + .attrs + .lists(sym::doc) + .filter(|a| a.check_name(sym::alias)) + .filter_map(|a| a.value_str().map(|s| s.to_string().replace("\"", ""))) + .filter(|v| !v.is_empty()) + .collect::>() + .into_iter() + { + self.aliases + .entry(alias.to_lowercase()) + .or_insert(Vec::with_capacity(1)) + .push(self.search_index.len() - 1); + } } } (Some(parent), None) if is_inherent_impl_item => { @@ -363,6 +378,9 @@ impl DocFolder for Cache { | clean::MacroItem(..) | clean::ProcMacroItem(..) | clean::VariantItem(..) + | clean::StructFieldItem(..) + | clean::TyMethodItem(..) + | clean::MethodItem(..) if !self.stripped_mod => { // Re-exported items mean that the same id can show up twice @@ -376,11 +394,8 @@ impl DocFolder for Cache { { self.paths.insert(item.def_id, (self.stack.clone(), item.type_())); } - self.add_aliases(&item); } - clean::PrimitiveItem(..) => { - self.add_aliases(&item); self.paths.insert(item.def_id, (self.stack.clone(), item.type_())); } @@ -489,36 +504,23 @@ impl DocFolder for Cache { } impl Cache { - fn add_aliases(&mut self, item: &clean::Item) { - if item.def_id.index == CRATE_DEF_INDEX { - return; - } - if let Some(ref item_name) = item.name { - let path = self - .paths - .get(&item.def_id) - .map(|p| p.0[..p.0.len() - 1].join("::")) - .unwrap_or("std".to_owned()); - for alias in item - .attrs - .lists(sym::doc) - .filter(|a| a.check_name(sym::alias)) - .filter_map(|a| a.value_str().map(|s| s.to_string().replace("\"", ""))) - .filter(|v| !v.is_empty()) - .collect::>() - .into_iter() - { - self.aliases.entry(alias).or_insert(Vec::with_capacity(1)).push(IndexItem { - ty: item.type_(), - name: item_name.to_string(), - path: path.clone(), - desc: shorten(plain_summary_line(item.doc_value())), - parent: None, - parent_idx: None, - search_type: get_index_search_type(&item), - }); - } - } + pub fn get_aliases<'a>(&'a self) -> FxHashMap> { + self.aliases + .iter() + .map(|(k, values)| { + ( + k.clone(), + values + .iter() + .filter(|v| { + let x = &self.search_index[**v]; + x.parent_idx.is_some() == x.parent.is_some() + }) + .map(|v| &self.search_index[*v]) + .collect::>(), + ) + }) + .collect() } } @@ -567,7 +569,8 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { let mut crate_items = Vec::with_capacity(cache.search_index.len()); let mut crate_paths = vec![]; - let Cache { ref mut search_index, ref orphan_impl_items, ref paths, .. } = *cache; + let Cache { ref mut search_index, ref orphan_impl_items, ref paths, ref mut aliases, .. } = + *cache; // Attach all orphan items to the type's definition if the type // has since been learned. @@ -582,6 +585,20 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { parent_idx: None, search_type: get_index_search_type(&item), }); + for alias in item + .attrs + .lists(sym::doc) + .filter(|a| a.check_name(sym::alias)) + .filter_map(|a| a.value_str().map(|s| s.to_string().replace("\"", ""))) + .filter(|v| !v.is_empty()) + .collect::>() + .into_iter() + { + aliases + .entry(alias.to_lowercase()) + .or_insert(Vec::with_capacity(1)) + .push(search_index.len() - 1); + } } } From 3a0727e84e29318ee41eb63bac27bfc1a379bfc5 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 1 May 2020 00:27:24 +0200 Subject: [PATCH 06/24] Add more tests for doc aliases --- src/test/rustdoc-js/doc-alias.js | 237 +++++++++++++++++++++++++++++++ src/test/rustdoc-js/doc-alias.rs | 80 +++++++++++ 2 files changed, 317 insertions(+) create mode 100644 src/test/rustdoc-js/doc-alias.js create mode 100644 src/test/rustdoc-js/doc-alias.rs diff --git a/src/test/rustdoc-js/doc-alias.js b/src/test/rustdoc-js/doc-alias.js new file mode 100644 index 0000000000000..e6310b625e533 --- /dev/null +++ b/src/test/rustdoc-js/doc-alias.js @@ -0,0 +1,237 @@ +// exact-check + +const QUERY = [ + 'StructItem', + 'StructFieldItem', + 'StructMethodItem', + 'ImplTraitItem', + 'ImplAssociatedConstItem', + 'ImplTraitFunction', + 'EnumItem', + 'VariantItem', + 'EnumMethodItem', + 'TypedefItem', + 'TraitItem', + 'TraitTypeItem', + 'AssociatedConstItem', + 'TraitFunctionItem', + 'FunctionItem', + 'ModuleItem', + 'ConstItem', + 'StaticItem', + 'UnionItem', + 'UnionFieldItem', + 'UnionMethodItem', + 'MacroItem', +]; + +const EXPECTED = [ + { + 'others': [ + { + 'path': 'doc_alias', + 'name': 'Struct', + 'alias': 'StructItem', + 'href': '../doc_alias/struct.Struct.html' + }, + ], + }, + { + 'others': [ + { + 'path': 'doc_alias::Struct', + 'name': 'field', + 'alias': 'StructFieldItem', + 'href': '../doc_alias/struct.Struct.html#structfield.field' + }, + ], + }, + { + 'others': [ + { + 'path': 'doc_alias::Struct', + 'name': 'method', + 'alias': 'StructMethodItem', + 'href': '../doc_alias/struct.Struct.html#method.method' + }, + ], + }, + { + // ImplTraitItem + 'others': [], + }, + { + // ImplAssociatedConstItem + 'others': [], + }, + { + // ImplTraitFunction + 'others': [], + }, + { + 'others': [ + { + 'path': 'doc_alias', + 'name': 'Enum', + 'alias': 'EnumItem', + 'href': '../doc_alias/enum.Enum.html' + }, + ], + }, + { + 'others': [ + { + 'path': 'doc_alias::Enum', + 'name': 'Variant', + 'alias': 'VariantItem', + 'href': '../doc_alias/enum.Enum.html#variant.Variant' + }, + ], + }, + { + 'others': [ + { + 'path': 'doc_alias::Enum', + 'name': 'method', + 'alias': 'EnumMethodItem', + 'href': '../doc_alias/enum.Enum.html#method.method' + }, + ], + }, + { + 'others': [ + { + 'path': 'doc_alias', + 'name': 'Typedef', + 'alias': 'TypedefItem', + 'href': '../doc_alias/type.Typedef.html' + }, + ], + }, + { + 'others': [ + { + 'path': 'doc_alias', + 'name': 'Trait', + 'alias': 'TraitItem', + 'href': '../doc_alias/trait.Trait.html' + }, + ], + }, + { + 'others': [ + { + 'path': 'doc_alias::Trait', + 'name': 'Target', + 'alias': 'TraitTypeItem', + 'href': '../doc_alias/trait.Trait.html#associatedtype.Target' + }, + ], + }, + { + 'others': [ + { + 'path': 'doc_alias::Trait', + 'name': 'AssociatedConst', + 'alias': 'AssociatedConstItem', + 'href': '../doc_alias/trait.Trait.html#associatedconstant.AssociatedConst' + }, + ], + }, + { + 'others': [ + { + 'path': 'doc_alias::Trait', + 'name': 'function', + 'alias': 'TraitFunctionItem', + 'href': '../doc_alias/trait.Trait.html#tymethod.function' + }, + ], + }, + { + 'others': [ + { + 'path': 'doc_alias', + 'name': 'function', + 'alias': 'FunctionItem', + 'href': '../doc_alias/fn.function.html' + }, + ], + }, + { + 'others': [ + { + 'path': 'doc_alias', + 'name': 'Module', + 'alias': 'ModuleItem', + 'href': '../doc_alias/Module/index.html' + }, + ], + }, + { + 'others': [ + { + 'path': 'doc_alias', + 'name': 'Const', + 'alias': 'ConstItem', + 'href': '../doc_alias/constant.Const.html' + }, + ], + }, + { + 'others': [ + { + 'path': 'doc_alias', + 'name': 'Static', + 'alias': 'StaticItem', + 'href': '../doc_alias/static.Static.html' + }, + ], + }, + { + 'others': [ + { + 'path': 'doc_alias', + 'name': 'Union', + 'alias': 'UnionItem', + 'href': '../doc_alias/union.Union.html' + }, + // Not an alias! + { + 'path': 'doc_alias::Union', + 'name': 'union_item', + 'href': '../doc_alias/union.Union.html#structfield.union_item' + }, + ], + }, + { + 'others': [ + { + 'path': 'doc_alias::Union', + 'name': 'union_item', + 'alias': 'UnionFieldItem', + 'href': '../doc_alias/union.Union.html#structfield.union_item' + }, + ], + }, + { + 'others': [ + { + 'path': 'doc_alias::Union', + 'name': 'method', + 'alias': 'UnionMethodItem', + 'href': '../doc_alias/union.Union.html#method.method' + }, + ], + }, + { + 'others': [ + { + 'path': 'doc_alias', + 'name': 'Macro', + 'alias': 'MacroItem', + 'href': '../doc_alias/macro.Macro.html' + }, + ], + }, +]; diff --git a/src/test/rustdoc-js/doc-alias.rs b/src/test/rustdoc-js/doc-alias.rs new file mode 100644 index 0000000000000..8cd0a82997414 --- /dev/null +++ b/src/test/rustdoc-js/doc-alias.rs @@ -0,0 +1,80 @@ +#![feature(doc_alias)] + +#[doc(alias = "StructItem")] +pub struct Struct { + #[doc(alias = "StructFieldItem")] + pub field: u32, +} + +impl Struct { + #[doc(alias = "StructMethodItem")] + pub fn method(&self) {} +} + +impl Trait for Struct { + // Shouldn't be listed in aliases! + #[doc(alias = "ImplTraitItem")] + type Target = u32; + // Shouldn't be listed in aliases! + #[doc(alias = "ImplAssociatedConstItem")] + const AssociatedConst: i32 = 12; + + // Shouldn't be listed in aliases! + #[doc(alias = "ImplTraitFunction")] + fn function() -> Self::Target { 0 } +} + +#[doc(alias = "EnumItem")] +pub enum Enum { + #[doc(alias = "VariantItem")] + Variant, +} + +impl Enum { + #[doc(alias = "EnumMethodItem")] + pub fn method(&self) {} +} + +#[doc(alias = "TypedefItem")] +pub type Typedef = i32; + +#[doc(alias = "TraitItem")] +pub trait Trait { + #[doc(alias = "TraitTypeItem")] + type Target; + #[doc(alias = "AssociatedConstItem")] + const AssociatedConst: i32; + + #[doc(alias = "TraitFunctionItem")] + fn function() -> Self::Target; +} + +#[doc(alias = "FunctionItem")] +pub fn function() {} + +#[doc(alias = "ModuleItem")] +pub mod Module {} + +#[doc(alias = "ConstItem")] +pub const Const: u32 = 0; + +#[doc(alias = "StaticItem")] +pub static Static: u32 = 0; + +#[doc(alias = "UnionItem")] +pub union Union { + #[doc(alias = "UnionFieldItem")] + pub union_item: u32, + pub y: f32, +} + +impl Union { + #[doc(alias = "UnionMethodItem")] + pub fn method(&self) {} +} + +#[doc(alias = "MacroItem")] +#[macro_export] +macro_rules! Macro { + () => {} +} From 9697c467aca28f40d8ef7c59b9f5bc670c1b85f8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 1 May 2020 00:43:55 +0200 Subject: [PATCH 07/24] Update std tests --- src/test/rustdoc-js-std/alias-2.js | 4 +++- src/test/rustdoc-js-std/alias.js | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/test/rustdoc-js-std/alias-2.js b/src/test/rustdoc-js-std/alias-2.js index f3c6713692b59..0ce1b87b76153 100644 --- a/src/test/rustdoc-js-std/alias-2.js +++ b/src/test/rustdoc-js-std/alias-2.js @@ -4,7 +4,9 @@ const QUERY = '+'; const EXPECTED = { 'others': [ - { 'path': 'std::ops', 'name': 'AddAssign' }, + { 'path': 'core', 'name': 'AddAssign' }, + { 'path': 'core', 'name': 'Add' }, + { 'path': 'std', 'name': 'AddAssign' }, { 'path': 'std::ops', 'name': 'Add' }, ], }; diff --git a/src/test/rustdoc-js-std/alias.js b/src/test/rustdoc-js-std/alias.js index 2b709c99119ae..0b1e983117f2f 100644 --- a/src/test/rustdoc-js-std/alias.js +++ b/src/test/rustdoc-js-std/alias.js @@ -5,7 +5,7 @@ const QUERY = '['; const EXPECTED = { 'others': [ { 'path': 'std', 'name': 'slice' }, - { 'path': 'std::ops', 'name': 'IndexMut' }, - { 'path': 'std::ops', 'name': 'Index' }, + { 'path': 'std', 'name': 'IndexMut' }, + { 'path': 'std', 'name': 'Index' }, ], }; From f581cf754492f9f122193b8d8a7750ab38a87485 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 4 May 2020 14:51:06 +0200 Subject: [PATCH 08/24] Merge aliases and search-index --- src/librustdoc/html/layout.rs | 1 - src/librustdoc/html/render.rs | 36 -------- src/librustdoc/html/render/cache.rs | 44 +++++----- src/librustdoc/html/static/main.js | 126 +++++++++++++++++++--------- src/test/rustdoc-js-std/alias-2.js | 6 +- src/test/rustdoc-js-std/alias.js | 4 +- src/tools/rustdoc-js/tester.js | 9 +- 7 files changed, 118 insertions(+), 108 deletions(-) diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index 0922c8cdd1200..ea65b3905272e 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -114,7 +114,6 @@ pub fn render( window.rootPath = \"{root_path}\";\ window.currentCrate = \"{krate}\";\ \ - \ \ {static_extra_scripts}\ {extra_scripts}\ diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 4ed367a5c80d3..9454baf764097 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -825,42 +825,6 @@ themePicker.onblur = handleThemeButtonsBlur; Ok((ret, krates)) } - fn show_item(item: &IndexItem, krate: &str) -> String { - format!( - "{{'crate':'{}','ty':{},'name':'{}','desc':'{}','p':'{}'{}}}", - krate, - item.ty as usize, - item.name, - item.desc.replace("'", "\\'"), - item.path, - if let Some(p) = item.parent_idx { format!(",'parent':{}", p) } else { String::new() } - ) - } - - let dst = cx.dst.join(&format!("aliases{}.js", cx.shared.resource_suffix)); - { - let (mut all_aliases, _) = try_err!(collect(&dst, &krate.name, "ALIASES"), &dst); - let mut output = String::with_capacity(100); - for (alias, items) in cx.cache.get_aliases() { - if items.is_empty() { - continue; - } - output.push_str(&format!( - "\"{}\":[{}],", - alias, - items.iter().map(|v| show_item(v, &krate.name)).collect::>().join(",") - )); - } - all_aliases.push(format!("ALIASES[\"{}\"] = {{{}}};", krate.name, output)); - all_aliases.sort(); - let mut v = Buffer::html(); - writeln!(&mut v, "var ALIASES = {{}};"); - for aliases in &all_aliases { - writeln!(&mut v, "{}", aliases); - } - cx.shared.fs.write(&dst, v.into_inner().into_bytes())?; - } - use std::ffi::OsString; #[derive(Debug)] diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs index 17003334bc856..53cf1abb16d56 100644 --- a/src/librustdoc/html/render/cache.rs +++ b/src/librustdoc/html/render/cache.rs @@ -503,27 +503,6 @@ impl DocFolder for Cache { } } -impl Cache { - pub fn get_aliases<'a>(&'a self) -> FxHashMap> { - self.aliases - .iter() - .map(|(k, values)| { - ( - k.clone(), - values - .iter() - .filter(|v| { - let x = &self.search_index[**v]; - x.parent_idx.is_some() == x.parent.is_some() - }) - .map(|v| &self.search_index[*v]) - .collect::>(), - ) - }) - .collect() - } -} - /// Attempts to find where an external crate is located, given that we're /// rendering in to the specified source destination. fn extern_location( @@ -640,6 +619,23 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { .map(|module| shorten(plain_summary_line(module.doc_value()))) .unwrap_or(String::new()); + let crate_aliases = aliases + .iter() + .map(|(k, values)| { + ( + k.clone(), + values + .iter() + .filter_map(|v| { + let x = &crate_items[*v]; + if x.parent_idx.is_some() == x.parent.is_some() { Some(*v) } else { None } + }) + .collect::>(), + ) + }) + .filter(|(_, values)| !values.is_empty()) + .collect::>(); + #[derive(Serialize)] struct CrateData<'a> { doc: String, @@ -647,6 +643,11 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { items: Vec<&'a IndexItem>, #[serde(rename = "p")] paths: Vec<(ItemType, String)>, + // The String is alias name and the vec is the list of the elements with this alias. + // + // To be noted: the `usize` elements are indexes to `items`. + #[serde(rename = "a")] + aliases: Option)>>, } // Collect the index into a string @@ -657,6 +658,7 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { doc: crate_doc, items: crate_items, paths: crate_paths, + aliases: if crate_aliases.is_empty() { None } else { Some(crate_aliases) }, }) .expect("failed serde conversion") // All these `replace` calls are because we have to go through JS string for JSON content. diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 411d2d44059b2..94ae69fde57fd 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -531,6 +531,7 @@ function getSearchElement() { var OUTPUT_DATA = 1; var NO_TYPE_FILTER = -1; var currentResults, index, searchIndex; + var ALIASES = {}; var params = getQueryStringParams(); // Populate search bar with query string search term when provided, @@ -963,46 +964,60 @@ function getSearchElement() { return itemTypes[ty.ty] + ty.path + ty.name; } + function createAliasFromItem(item) { + return { + crate: item.crate, + name: item.name, + path: item.path, + desc: item.desc, + ty: item.ty, + parent: item.parent, + type: item.parent, + is_alias: true, + }; + } + function handleAliases(ret, query, filterCrates) { - if (ALIASES) { - var aliases = []; - if (filterCrates !== undefined && - ALIASES[filterCrates] && - ALIASES[filterCrates][query.search]) { - aliases = ALIASES[filterCrates][query.search]; - } else { - Object.keys(ALIASES).forEach(function(crate) { - if (ALIASES[crate][query.search]) { - for (var i = 0; i < ALIASES[crate][query.search].length; ++i) { - aliases.push(ALIASES[crate][query.search][i]); - } - } - }); + var aliases = []; + var i; + if (filterCrates !== undefined && + ALIASES[filterCrates] && + ALIASES[filterCrates][query.search]) { + for (i = 0; i < ALIASES[crate][query.search].length; ++i) { + aliases.push( + createAliasFromItem(searchIndex[ALIASES[filterCrates][query.search]])); } - aliases.sort(function(aaa, bbb) { - if (aaa.path < bbb.path) { - return 1; - } else if (aaa.path === bbb.path) { - return 0; + } else { + Object.keys(ALIASES).forEach(function(crate) { + if (ALIASES[crate][query.search]) { + for (i = 0; i < ALIASES[crate][query.search].length; ++i) { + aliases.push( + createAliasFromItem( + searchIndex[ALIASES[crate][query.search][i]])); + } } - return -1; }); - for (var i = 0; i < aliases.length; ++i) { - var alias = aliases[i]; - alias.is_alias = true; - if (typeof alias.parent === "number") { - alias.parent = rawSearchIndex[alias.crate].p[alias.parent]; - } - alias.alias = query.raw; - alias.path = alias.p || alias.crate; - var res = buildHrefAndPath(aliases[i]); - alias.displayPath = pathSplitter(res[0]); - alias.fullPath = alias.displayPath + alias.name; - alias.href = res[1]; - ret.others.unshift(alias); - if (ret.others.length > MAX_RESULTS) { - ret.others.pop(); - } + } + aliases.sort(function(aaa, bbb) { + if (aaa.path < bbb.path) { + return 1; + } else if (aaa.path === bbb.path) { + return 0; + } + return -1; + }); + for (i = 0; i < aliases.length; ++i) { + var alias = aliases[i]; + + alias.alias = query.raw; + var res = buildHrefAndPath(alias); + alias.displayPath = pathSplitter(res[0]); + alias.fullPath = alias.displayPath + alias.name; + alias.href = res[1]; + + ret.others.unshift(alias); + if (ret.others.length > MAX_RESULTS) { + ret.others.pop(); } } } @@ -1683,10 +1698,13 @@ function getSearchElement() { searchIndex = []; var searchWords = []; var i; + var currentIndex = 0; for (var crate in rawSearchIndex) { if (!rawSearchIndex.hasOwnProperty(crate)) { continue; } + var crateSize = 0; + searchWords.push(crate); searchIndex.push({ crate: crate, @@ -1696,6 +1714,7 @@ function getSearchElement() { desc: rawSearchIndex[crate].doc, type: null, }); + currentIndex += 1; // an array of [(Number) item type, // (String) name, @@ -1707,6 +1726,9 @@ function getSearchElement() { // an array of [(Number) item type, // (String) name] var paths = rawSearchIndex[crate].p; + // a array of [(String) alias name + // [Number] index to items] + var aliases = rawSearchIndex[crate].a; // convert `rawPaths` entries into object form var len = paths.length; @@ -1725,9 +1747,18 @@ function getSearchElement() { var lastPath = ""; for (i = 0; i < len; ++i) { var rawRow = items[i]; - var row = {crate: crate, ty: rawRow[0], name: rawRow[1], - path: rawRow[2] || lastPath, desc: rawRow[3], - parent: paths[rawRow[4]], type: rawRow[5]}; + if (!rawRow[2]) { + rawRow[2] = lastPath; + } + var row = { + crate: crate, + ty: rawRow[0], + name: rawRow[1], + path: rawRow[2], + desc: rawRow[3], + parent: paths[rawRow[4]], + type: rawRow[5], + }; searchIndex.push(row); if (typeof row.name === "string") { var word = row.name.toLowerCase(); @@ -1736,7 +1767,24 @@ function getSearchElement() { searchWords.push(""); } lastPath = row.path; + crateSize += 1; + } + + if (aliases) { + ALIASES[crate] = {}; + var j, local_aliases; + for (i = 0; i < aliases.length; ++i) { + var alias_name = aliases[i][0]; + if (!ALIASES[crate].hasOwnProperty(alias_name)) { + ALIASES[crate][alias_name] = []; + } + local_aliases = aliases[i][1]; + for (j = 0; j < local_aliases.length; ++j) { + ALIASES[crate][alias_name].push(local_aliases[j] + currentIndex); + } + } } + currentIndex += crateSize; } return searchWords; } diff --git a/src/test/rustdoc-js-std/alias-2.js b/src/test/rustdoc-js-std/alias-2.js index 0ce1b87b76153..cb6ec4f8fed4e 100644 --- a/src/test/rustdoc-js-std/alias-2.js +++ b/src/test/rustdoc-js-std/alias-2.js @@ -4,9 +4,9 @@ const QUERY = '+'; const EXPECTED = { 'others': [ - { 'path': 'core', 'name': 'AddAssign' }, - { 'path': 'core', 'name': 'Add' }, - { 'path': 'std', 'name': 'AddAssign' }, + { 'path': 'core::ops', 'name': 'AddAssign' }, + { 'path': 'core::ops', 'name': 'Add' }, + { 'path': 'std::ops', 'name': 'AddAssign' }, { 'path': 'std::ops', 'name': 'Add' }, ], }; diff --git a/src/test/rustdoc-js-std/alias.js b/src/test/rustdoc-js-std/alias.js index 0b1e983117f2f..2b709c99119ae 100644 --- a/src/test/rustdoc-js-std/alias.js +++ b/src/test/rustdoc-js-std/alias.js @@ -5,7 +5,7 @@ const QUERY = '['; const EXPECTED = { 'others': [ { 'path': 'std', 'name': 'slice' }, - { 'path': 'std', 'name': 'IndexMut' }, - { 'path': 'std', 'name': 'Index' }, + { 'path': 'std::ops', 'name': 'IndexMut' }, + { 'path': 'std::ops', 'name': 'Index' }, ], }; diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js index 72bc496c5b5d3..90315d6f64431 100644 --- a/src/tools/rustdoc-js/tester.js +++ b/src/tools/rustdoc-js/tester.js @@ -218,7 +218,7 @@ function lookForEntry(entry, data) { return null; } -function loadMainJsAndIndex(mainJs, aliases, searchIndex, crate) { +function loadMainJsAndIndex(mainJs, searchIndex, crate) { if (searchIndex[searchIndex.length - 1].length === 0) { searchIndex.pop(); } @@ -238,17 +238,15 @@ function loadMainJsAndIndex(mainJs, aliases, searchIndex, crate) { var functionsToLoad = ["buildHrefAndPath", "pathSplitter", "levenshtein", "validateResult", "handleAliases", "getQuery", "buildIndex", "execQuery", "execSearch"]; + ALIASES = {}; finalJS += 'window = { "currentCrate": "' + crate + '" };\n'; finalJS += 'var rootPath = "../";\n'; - finalJS += aliases; finalJS += loadThings(arraysToLoad, 'array', extractArrayVariable, mainJs); finalJS += loadThings(variablesToLoad, 'variable', extractVariable, mainJs); finalJS += loadThings(functionsToLoad, 'function', extractFunction, mainJs); var loaded = loadContent(finalJS); var index = loaded.buildIndex(searchIndex.rawSearchIndex); - // We make it "global" so that the "loaded.execSearch" function will find it. - rawSearchIndex = searchIndex.rawSearchIndex; return [loaded, index]; } @@ -340,11 +338,10 @@ function runChecks(testFile, loaded, index) { function load_files(doc_folder, resource_suffix, crate) { var mainJs = readFile(path.join(doc_folder, "main" + resource_suffix + ".js")); - var aliases = readFile(path.join(doc_folder, "aliases" + resource_suffix + ".js")); var searchIndex = readFile( path.join(doc_folder, "search-index" + resource_suffix + ".js")).split("\n"); - return loadMainJsAndIndex(mainJs, aliases, searchIndex, crate); + return loadMainJsAndIndex(mainJs, searchIndex, crate); } function showHelp() { From 32a46e91155de70eeca062a1ece74cea56574649 Mon Sep 17 00:00:00 2001 From: csmoe Date: Wed, 6 May 2020 18:43:56 +0800 Subject: [PATCH 09/24] add test case for issue-61076 --- src/test/ui/async-await/issue-61076.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/test/ui/async-await/issue-61076.rs diff --git a/src/test/ui/async-await/issue-61076.rs b/src/test/ui/async-await/issue-61076.rs new file mode 100644 index 0000000000000..0c6c531199773 --- /dev/null +++ b/src/test/ui/async-await/issue-61076.rs @@ -0,0 +1,12 @@ +// edition:2018 + +async fn foo() -> Result<(), ()> { + Ok(()) +} + +async fn bar() -> Result<(), ()> { + foo()?; + Ok(()) +} + +fn main() {} From 2e2aac4f57b6bd4ca8e17b9143d49c14371e071f Mon Sep 17 00:00:00 2001 From: csmoe Date: Wed, 6 May 2020 18:44:14 +0800 Subject: [PATCH 10/24] add try trait as lang item --- src/libcore/ops/try.rs | 1 + src/librustc_hir/lang_items.rs | 1 + src/librustc_typeck/check/mod.rs | 32 ++++++++++++++++++++++---------- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/libcore/ops/try.rs b/src/libcore/ops/try.rs index 996a01d413cbc..ed8c614b10979 100644 --- a/src/libcore/ops/try.rs +++ b/src/libcore/ops/try.rs @@ -25,6 +25,7 @@ ) )] #[doc(alias = "?")] + #[cfg_attr(not(bootstrap), lang = "try_trait")] pub trait Try { /// The type of this value when viewed as successful. #[unstable(feature = "try_trait", issue = "42327")] diff --git a/src/librustc_hir/lang_items.rs b/src/librustc_hir/lang_items.rs index 53f72804a848d..2ffa77031f33b 100644 --- a/src/librustc_hir/lang_items.rs +++ b/src/librustc_hir/lang_items.rs @@ -194,6 +194,7 @@ language_item_table! { ShrAssignTraitLangItem, "shr_assign", shr_assign_trait, Target::Trait; IndexTraitLangItem, "index", index_trait, Target::Trait; IndexMutTraitLangItem, "index_mut", index_mut_trait, Target::Trait; + TryTraitLangItem, "try_trait", try_trait, Target::Trait; UnsafeCellTypeLangItem, "unsafe_cell", unsafe_cell_type, Target::Struct; VaListTypeLangItem, "va_list", va_list, Target::Struct; diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 956e09ec52b4a..53891a4fd9fd6 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -5289,6 +5289,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, found: Ty<'tcx>, ) { + debug!("suggest_missing_await: expr={:?} expected={:?}, found={:?}", expr, expected, found); // `.await` is not permitted outside of `async` bodies, so don't bother to suggest if the // body isn't `async`. let item_id = self.tcx().hir().get_parent_node(self.body_id); @@ -5306,22 +5307,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .next() .unwrap() .def_id; + // `::Output` + let projection_ty = ty::ProjectionTy { + // `T` + substs: self + .tcx + .mk_substs_trait(found, self.fresh_substs_for_item(sp, item_def_id)), + // `Future::Output` + item_def_id, + }; + let predicate = ty::Predicate::Projection(ty::Binder::bind(ty::ProjectionPredicate { - // `::Output` - projection_ty: ty::ProjectionTy { - // `T` - substs: self.tcx.mk_substs_trait( - found, - self.fresh_substs_for_item(sp, item_def_id), - ), - // `Future::Output` - item_def_id, - }, + projection_ty, ty: expected, })); let obligation = traits::Obligation::new(self.misc(sp), self.param_env, predicate); debug!("suggest_missing_await: trying obligation {:?}", obligation); + + //let try_trait_def_id = self.tcx.require_lang_item(lang_items::TryTraitLangItem, None); + //let try_trait_ref = ty::TraitRef { + // def_id: try_trait_def_id, + // substs: self.tcx.mk_substs_trait(self.tcx.type_of(item_def_id), &[]), + //}; + //let try_obligation = traits::Obligation::new(self.misc(sp), self.param_env, try_trait_ref.without_const().to_predicate()); + //let try_trait_is_implemented = self.predicate_must_hold_modulo_regions(&try_obligation); + //debug!("suggest_missing_await: try trait is implemented {}", try_trait_is_implemented); + if self.infcx.predicate_may_hold(&obligation) { debug!("suggest_missing_await: obligation held: {:?}", obligation); if let Ok(code) = self.sess().source_map().span_to_snippet(sp) { From 114cd006f52272618bd64382213cd08eaa313136 Mon Sep 17 00:00:00 2001 From: csmoe Date: Sat, 9 May 2020 22:04:02 +0800 Subject: [PATCH 11/24] normalize Future::Ouput --- src/librustc_typeck/check/mod.rs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 53891a4fd9fd6..bd5049446e615 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -5317,22 +5317,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { item_def_id, }; + let cause = traits::ObligationCause::misc(sp, self.body_id); + let normalized_ty = self.fulfillment_cx.borrow_mut().normalize_projection_type( + &self.infcx, + self.param_env, + projection_ty, + cause, + ); + debug!("suggest_missing_await: projection_type {:?}", normalized_ty); + let predicate = ty::Predicate::Projection(ty::Binder::bind(ty::ProjectionPredicate { projection_ty, ty: expected, })); let obligation = traits::Obligation::new(self.misc(sp), self.param_env, predicate); - debug!("suggest_missing_await: trying obligation {:?}", obligation); - //let try_trait_def_id = self.tcx.require_lang_item(lang_items::TryTraitLangItem, None); - //let try_trait_ref = ty::TraitRef { - // def_id: try_trait_def_id, - // substs: self.tcx.mk_substs_trait(self.tcx.type_of(item_def_id), &[]), - //}; - //let try_obligation = traits::Obligation::new(self.misc(sp), self.param_env, try_trait_ref.without_const().to_predicate()); - //let try_trait_is_implemented = self.predicate_must_hold_modulo_regions(&try_obligation); - //debug!("suggest_missing_await: try trait is implemented {}", try_trait_is_implemented); + debug!("suggest_missing_await: trying obligation {:?}", obligation); if self.infcx.predicate_may_hold(&obligation) { debug!("suggest_missing_await: obligation held: {:?}", obligation); From 627f473dd426497972cce58ba64e8b0ff2409078 Mon Sep 17 00:00:00 2001 From: csmoe Date: Sun, 10 May 2020 20:07:42 +0800 Subject: [PATCH 12/24] suggest await before try when performing trait selection --- src/libcore/ops/try.rs | 2 +- .../traits/error_reporting/mod.rs | 11 +++ .../traits/error_reporting/suggestions.rs | 80 +++++++++++++++++++ src/librustc_typeck/check/mod.rs | 9 --- 4 files changed, 92 insertions(+), 10 deletions(-) diff --git a/src/libcore/ops/try.rs b/src/libcore/ops/try.rs index ed8c614b10979..ef748bcee6e2d 100644 --- a/src/libcore/ops/try.rs +++ b/src/libcore/ops/try.rs @@ -25,7 +25,7 @@ ) )] #[doc(alias = "?")] - #[cfg_attr(not(bootstrap), lang = "try_trait")] +#[cfg_attr(not(bootstrap), lang = "try_trait")] pub trait Try { /// The type of this value when viewed as successful. #[unstable(feature = "try_trait", issue = "42327")] diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index 405c656bad562..272827cfef830 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -400,6 +400,17 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { self.suggest_remove_reference(&obligation, &mut err, &trait_ref); self.suggest_semicolon_removal(&obligation, &mut err, span, &trait_ref); self.note_version_mismatch(&mut err, &trait_ref); + //self.sugggest_await_before_try(&mut err, &obligation, &trait_ref); + debug!( + "suggest_await_befor_try: trait_predicate={:?} obligation={:?}, trait_ref={:?}", + trait_predicate, obligation, trait_ref + ); + self.suggest_await_befor_try( + &mut err, + &obligation, + trait_ref.self_ty(), + span, + ); if self.suggest_impl_trait(&mut err, span, &obligation, &trait_ref) { err.emit(); return; diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index 74dd47a91c279..d0b39d6016af2 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -1,8 +1,10 @@ use super::{ EvaluationResult, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation, + SelectionContext, }; use crate::infer::InferCtxt; +use crate::traits::normalize_projection_type; use rustc_errors::{error_code, struct_span_err, Applicability, DiagnosticBuilder, Style}; use rustc_hir as hir; @@ -150,6 +152,15 @@ pub trait InferCtxtExt<'tcx> { T: fmt::Display; fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder<'_>); + + /// Suggest to await before try: future? => future.await? + fn suggest_await_befor_try( + &self, + err: &mut DiagnosticBuilder<'_>, + obligation: &PredicateObligation<'tcx>, + ty: Ty<'tcx>, + span: Span, + ); } fn predicate_constraint(generics: &hir::Generics<'_>, pred: String) -> (Span, String) { @@ -1765,6 +1776,75 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { suggested_limit, self.tcx.crate_name, )); } + + fn suggest_await_befor_try( + &self, + err: &mut DiagnosticBuilder<'_>, + obligation: &PredicateObligation<'tcx>, + ty: Ty<'tcx>, + span: Span, + ) { + debug!("suggest_await_befor_try: obligation={:?}, span={:?}", obligation, span); + let body_hir_id = obligation.cause.body_id; + let item_id = self.tcx.hir().get_parent_node(body_hir_id); + if let Some(body_id) = self.tcx.hir().maybe_body_owned_by(item_id) { + let body = self.tcx.hir().body(body_id); + if let Some(hir::GeneratorKind::Async(_)) = body.generator_kind { + // Check for `Future` implementations by constructing a predicate to + // prove: `::Output == U` + let future_trait = self.tcx.lang_items().future_trait().unwrap(); + let item_def_id = self + .tcx + .associated_items(future_trait) + .in_definition_order() + .next() + .unwrap() + .def_id; + // `::Output` + let projection_ty = ty::ProjectionTy { + // `T` + substs: self + .tcx + .mk_substs_trait(ty, self.fresh_substs_for_item(span, item_def_id)), + // `Future::Output` + item_def_id, + }; + + let cause = ObligationCause::misc(span, body_hir_id); + let mut selcx = SelectionContext::new(self); + + let mut obligations = vec![]; + let normalized_ty = normalize_projection_type( + &mut selcx, + obligation.param_env, + projection_ty, + obligation.cause.clone(), + 0, + &mut obligations, + ); + + debug!("suggest_await_befor_try: normalized_projection_type {:?}", normalized_ty); + let try_trait_ref_id = self.tcx.lang_items().try_trait().unwrap(); + if let Some(try_trait_ref) = self.tcx.impl_trait_ref(try_trait_ref_id) { + let try_predicate = try_trait_ref.without_const().to_predicate(); + let try_obligation = + Obligation::new(cause, obligation.param_env, try_predicate); + debug!("suggest_await_befor_try: try_trait_obligation {:?}", try_obligation); + if self.predicate_may_hold(&try_obligation) { + debug!("try_obligation holds"); + if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { + err.span_suggestion( + span, + "consider using `.await` here", + format!("{}.await", snippet), + Applicability::MaybeIncorrect, + ); + } + } + } + } + } + } } /// Collect all the returned expressions within the input expression. diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index bd5049446e615..c142e88b7de55 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -5317,15 +5317,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { item_def_id, }; - let cause = traits::ObligationCause::misc(sp, self.body_id); - let normalized_ty = self.fulfillment_cx.borrow_mut().normalize_projection_type( - &self.infcx, - self.param_env, - projection_ty, - cause, - ); - debug!("suggest_missing_await: projection_type {:?}", normalized_ty); - let predicate = ty::Predicate::Projection(ty::Binder::bind(ty::ProjectionPredicate { projection_ty, From c7e64f54c86a05ddd09fc3da4e98a8d748658337 Mon Sep 17 00:00:00 2001 From: csmoe Date: Sun, 10 May 2020 22:34:01 +0800 Subject: [PATCH 13/24] remove try_trait lang item --- src/libcore/ops/try.rs | 1 - src/librustc_hir/lang_items.rs | 2 - .../traits/error_reporting/mod.rs | 12 +---- .../traits/error_reporting/suggestions.rs | 46 ++++++++++--------- 4 files changed, 26 insertions(+), 35 deletions(-) diff --git a/src/libcore/ops/try.rs b/src/libcore/ops/try.rs index ef748bcee6e2d..996a01d413cbc 100644 --- a/src/libcore/ops/try.rs +++ b/src/libcore/ops/try.rs @@ -25,7 +25,6 @@ ) )] #[doc(alias = "?")] -#[cfg_attr(not(bootstrap), lang = "try_trait")] pub trait Try { /// The type of this value when viewed as successful. #[unstable(feature = "try_trait", issue = "42327")] diff --git a/src/librustc_hir/lang_items.rs b/src/librustc_hir/lang_items.rs index 2ffa77031f33b..a503e3534e3bd 100644 --- a/src/librustc_hir/lang_items.rs +++ b/src/librustc_hir/lang_items.rs @@ -194,8 +194,6 @@ language_item_table! { ShrAssignTraitLangItem, "shr_assign", shr_assign_trait, Target::Trait; IndexTraitLangItem, "index", index_trait, Target::Trait; IndexMutTraitLangItem, "index_mut", index_mut_trait, Target::Trait; - TryTraitLangItem, "try_trait", try_trait, Target::Trait; - UnsafeCellTypeLangItem, "unsafe_cell", unsafe_cell_type, Target::Struct; VaListTypeLangItem, "va_list", va_list, Target::Struct; diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index 272827cfef830..c74870306869b 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -400,17 +400,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { self.suggest_remove_reference(&obligation, &mut err, &trait_ref); self.suggest_semicolon_removal(&obligation, &mut err, span, &trait_ref); self.note_version_mismatch(&mut err, &trait_ref); - //self.sugggest_await_before_try(&mut err, &obligation, &trait_ref); - debug!( - "suggest_await_befor_try: trait_predicate={:?} obligation={:?}, trait_ref={:?}", - trait_predicate, obligation, trait_ref - ); - self.suggest_await_befor_try( - &mut err, - &obligation, - trait_ref.self_ty(), - span, - ); + self.suggest_await_before_try(&mut err, &obligation, &trait_ref, span); if self.suggest_impl_trait(&mut err, span, &obligation, &trait_ref) { err.emit(); return; diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index d0b39d6016af2..b28f0001cd974 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -154,11 +154,11 @@ pub trait InferCtxtExt<'tcx> { fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder<'_>); /// Suggest to await before try: future? => future.await? - fn suggest_await_befor_try( + fn suggest_await_before_try( &self, err: &mut DiagnosticBuilder<'_>, obligation: &PredicateObligation<'tcx>, - ty: Ty<'tcx>, + trait_ref: &ty::Binder>, span: Span, ); } @@ -1777,21 +1777,23 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { )); } - fn suggest_await_befor_try( + fn suggest_await_before_try( &self, err: &mut DiagnosticBuilder<'_>, obligation: &PredicateObligation<'tcx>, - ty: Ty<'tcx>, + trait_ref: &ty::Binder>, span: Span, ) { - debug!("suggest_await_befor_try: obligation={:?}, span={:?}", obligation, span); + debug!( + "suggest_await_befor_try: obligation={:?}, span={:?}, trait_ref={:?}", + obligation, span, trait_ref + ); let body_hir_id = obligation.cause.body_id; let item_id = self.tcx.hir().get_parent_node(body_hir_id); + if let Some(body_id) = self.tcx.hir().maybe_body_owned_by(item_id) { let body = self.tcx.hir().body(body_id); if let Some(hir::GeneratorKind::Async(_)) = body.generator_kind { - // Check for `Future` implementations by constructing a predicate to - // prove: `::Output == U` let future_trait = self.tcx.lang_items().future_trait().unwrap(); let item_def_id = self .tcx @@ -1803,14 +1805,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // `::Output` let projection_ty = ty::ProjectionTy { // `T` - substs: self - .tcx - .mk_substs_trait(ty, self.fresh_substs_for_item(span, item_def_id)), + substs: self.tcx.mk_substs_trait( + trait_ref.self_ty(), + self.fresh_substs_for_item(span, item_def_id), + ), // `Future::Output` item_def_id, }; - let cause = ObligationCause::misc(span, body_hir_id); + //let cause = ObligationCause::misc(span, body_hir_id); let mut selcx = SelectionContext::new(self); let mut obligations = vec![]; @@ -1824,19 +1827,20 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ); debug!("suggest_await_befor_try: normalized_projection_type {:?}", normalized_ty); - let try_trait_ref_id = self.tcx.lang_items().try_trait().unwrap(); - if let Some(try_trait_ref) = self.tcx.impl_trait_ref(try_trait_ref_id) { - let try_predicate = try_trait_ref.without_const().to_predicate(); - let try_obligation = - Obligation::new(cause, obligation.param_env, try_predicate); - debug!("suggest_await_befor_try: try_trait_obligation {:?}", try_obligation); - if self.predicate_may_hold(&try_obligation) { - debug!("try_obligation holds"); - if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { + let try_obligation = self.mk_obligation_for_def_id( + trait_ref.def_id(), + normalized_ty, + obligation.cause.clone(), + obligation.param_env, + ); + debug!("suggest_await_befor_try: try_trait_obligation {:?}", try_obligation); + if self.predicate_may_hold(&try_obligation) { + if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { + if snippet.ends_with('?') { err.span_suggestion( span, "consider using `.await` here", - format!("{}.await", snippet), + format!("{}.await?", snippet.trim_end_matches('?')), Applicability::MaybeIncorrect, ); } From 23d880b127c346be631d2a9dbcef3bd5dff7d305 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 10 May 2020 23:36:41 +0200 Subject: [PATCH 14/24] rustc_driver: factor out computing the exit code --- src/librustc_driver/lib.rs | 19 ++++++++++++------- src/tools/clippy/src/driver.rs | 4 +--- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 913ccf8e68089..f8afaecf21858 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -1138,6 +1138,16 @@ pub fn catch_fatal_errors R, R>(f: F) -> Result }) } +/// Variant of `catch_fatal_errors` for the `interface::Result` return type +/// that also computes the exit code. +pub fn catch_with_exit_code(f: impl FnOnce() -> interface::Result<()>) -> i32 { + let result = catch_fatal_errors(f).and_then(|result| result); + match result { + Ok(()) => EXIT_SUCCESS, + Err(_) => EXIT_FAILURE, + } +} + lazy_static! { static ref DEFAULT_HOOK: Box) + Sync + Send + 'static> = { let hook = panic::take_hook(); @@ -1233,7 +1243,7 @@ pub fn main() { init_rustc_env_logger(); let mut callbacks = TimePassesCallbacks::default(); install_ice_hook(); - let result = catch_fatal_errors(|| { + let exit_code = catch_with_exit_code(|| { let args = env::args_os() .enumerate() .map(|(i, arg)| { @@ -1246,12 +1256,7 @@ pub fn main() { }) .collect::>(); run_compiler(&args, &mut callbacks, None, None) - }) - .and_then(|result| result); - let exit_code = match result { - Ok(_) => EXIT_SUCCESS, - Err(_) => EXIT_FAILURE, - }; + }); // The extra `\t` is necessary to align this label with the others. print_time_passes_entry(callbacks.time_passes, "\ttotal", start.elapsed()); process::exit(exit_code); diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs index 2c699998ea90e..1ce0300f23904 100644 --- a/src/tools/clippy/src/driver.rs +++ b/src/tools/clippy/src/driver.rs @@ -296,7 +296,7 @@ pub fn main() { rustc_driver::init_rustc_env_logger(); lazy_static::initialize(&ICE_HOOK); exit( - rustc_driver::catch_fatal_errors(move || { + rustc_driver::catch_with_exit_code(move || { let mut orig_args: Vec = env::args().collect(); if orig_args.iter().any(|a| a == "--version" || a == "-V") { @@ -411,7 +411,5 @@ pub fn main() { if clippy_enabled { &mut clippy } else { &mut default }; rustc_driver::run_compiler(&args, callbacks, None, None) }) - .and_then(|result| result) - .is_err() as i32, ) } From 51e466de3cbfb94b7d0736066a765d8ea31394e4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 11 May 2020 00:11:42 +0200 Subject: [PATCH 15/24] rustc_driver::main: more informative return type --- src/librustc_driver/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index f8afaecf21858..6847b175e60eb 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -1238,7 +1238,7 @@ pub fn init_rustc_env_logger() { env_logger::init_from_env("RUSTC_LOG"); } -pub fn main() { +pub fn main() -> ! { let start = Instant::now(); init_rustc_env_logger(); let mut callbacks = TimePassesCallbacks::default(); @@ -1259,5 +1259,5 @@ pub fn main() { }); // The extra `\t` is necessary to align this label with the others. print_time_passes_entry(callbacks.time_passes, "\ttotal", start.elapsed()); - process::exit(exit_code); + process::exit(exit_code) } From a1104b4dea0e0d3b35fa73c7f7c186f76b23db78 Mon Sep 17 00:00:00 2001 From: csmoe Date: Sun, 10 May 2020 22:34:20 +0800 Subject: [PATCH 16/24] bless ui tests --- src/librustc_hir/lang_items.rs | 1 + src/librustc_middle/hir/map/mod.rs | 6 +---- .../traits/error_reporting/suggestions.rs | 22 ++++++++++++++++--- .../incorrect-syntax-suggestions.stderr | 5 ++++- src/test/ui/async-await/issue-61076.rs | 2 +- src/test/ui/async-await/issue-61076.stderr | 15 +++++++++++++ 6 files changed, 41 insertions(+), 10 deletions(-) create mode 100644 src/test/ui/async-await/issue-61076.stderr diff --git a/src/librustc_hir/lang_items.rs b/src/librustc_hir/lang_items.rs index a503e3534e3bd..53f72804a848d 100644 --- a/src/librustc_hir/lang_items.rs +++ b/src/librustc_hir/lang_items.rs @@ -194,6 +194,7 @@ language_item_table! { ShrAssignTraitLangItem, "shr_assign", shr_assign_trait, Target::Trait; IndexTraitLangItem, "index", index_trait, Target::Trait; IndexMutTraitLangItem, "index_mut", index_mut_trait, Target::Trait; + UnsafeCellTypeLangItem, "unsafe_cell", unsafe_cell_type, Target::Struct; VaListTypeLangItem, "va_list", va_list, Target::Struct; diff --git a/src/librustc_middle/hir/map/mod.rs b/src/librustc_middle/hir/map/mod.rs index de0373c138497..a3f8cd1ee36fe 100644 --- a/src/librustc_middle/hir/map/mod.rs +++ b/src/librustc_middle/hir/map/mod.rs @@ -390,11 +390,7 @@ impl<'hir> Map<'hir> { /// Given a `HirId`, returns the `BodyId` associated with it, /// if the node is a body owner, otherwise returns `None`. pub fn maybe_body_owned_by(&self, hir_id: HirId) -> Option { - if let Some(node) = self.find(hir_id) { - associated_body(node) - } else { - bug!("no entry for id `{}`", hir_id) - } + if let Some(node) = self.find(hir_id) { associated_body(node) } else { None } } /// Given a body owner's id, returns the `BodyId` associated with it. diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index b28f0001cd974..5e3b383ff2580 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -1791,6 +1791,19 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let body_hir_id = obligation.cause.body_id; let item_id = self.tcx.hir().get_parent_node(body_hir_id); + let mut is_future = false; + if let ty::Opaque(def_id, substs) = trait_ref.self_ty().kind { + let preds = self.tcx.predicates_of(def_id).instantiate(self.tcx, substs); + for p in preds.predicates { + if let Some(trait_ref) = p.to_opt_poly_trait_ref() { + if Some(trait_ref.def_id()) == self.tcx.lang_items().future_trait() { + is_future = true; + break; + } + } + } + } + if let Some(body_id) = self.tcx.hir().maybe_body_owned_by(item_id) { let body = self.tcx.hir().body(body_id); if let Some(hir::GeneratorKind::Async(_)) = body.generator_kind { @@ -1802,6 +1815,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { .next() .unwrap() .def_id; + debug!("trait_ref_self_ty: {:?}", trait_ref.self_ty()); // `::Output` let projection_ty = ty::ProjectionTy { // `T` @@ -1813,7 +1827,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { item_def_id, }; - //let cause = ObligationCause::misc(span, body_hir_id); let mut selcx = SelectionContext::new(self); let mut obligations = vec![]; @@ -1826,7 +1839,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { &mut obligations, ); - debug!("suggest_await_befor_try: normalized_projection_type {:?}", normalized_ty); + debug!( + "suggest_await_befor_try: normalized_projection_type {:?}", + self.resolve_vars_if_possible(&normalized_ty) + ); let try_obligation = self.mk_obligation_for_def_id( trait_ref.def_id(), normalized_ty, @@ -1834,7 +1850,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { obligation.param_env, ); debug!("suggest_await_befor_try: try_trait_obligation {:?}", try_obligation); - if self.predicate_may_hold(&try_obligation) { + if self.predicate_may_hold(&try_obligation) && is_future { if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { if snippet.ends_with('?') { err.span_suggestion( diff --git a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr index 61f2570b2ff93..96158fc0e0496 100644 --- a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr +++ b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr @@ -237,7 +237,10 @@ error[E0277]: the `?` operator can only be applied to values that implement `std --> $DIR/incorrect-syntax-suggestions.rs:16:19 | LL | let _ = await bar()?; - | ^^^^^^ the `?` operator cannot be applied to type `impl std::future::Future` + | ^^^^^^ + | | + | the `?` operator cannot be applied to type `impl std::future::Future` + | help: consider using `.await` here: `bar().await?` | = help: the trait `std::ops::Try` is not implemented for `impl std::future::Future` = note: required by `std::ops::Try::into_result` diff --git a/src/test/ui/async-await/issue-61076.rs b/src/test/ui/async-await/issue-61076.rs index 0c6c531199773..04a9148ae2413 100644 --- a/src/test/ui/async-await/issue-61076.rs +++ b/src/test/ui/async-await/issue-61076.rs @@ -5,7 +5,7 @@ async fn foo() -> Result<(), ()> { } async fn bar() -> Result<(), ()> { - foo()?; + foo()?; //~ ERROR the `?` operator can only be applied to values that implement `std::ops::Try` Ok(()) } diff --git a/src/test/ui/async-await/issue-61076.stderr b/src/test/ui/async-await/issue-61076.stderr new file mode 100644 index 0000000000000..fb1eead04e6bd --- /dev/null +++ b/src/test/ui/async-await/issue-61076.stderr @@ -0,0 +1,15 @@ +error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` + --> $DIR/issue-61076.rs:8:5 + | +LL | foo()?; + | ^^^^^^ + | | + | the `?` operator cannot be applied to type `impl std::future::Future` + | help: consider using `.await` here: `foo().await?` + | + = help: the trait `std::ops::Try` is not implemented for `impl std::future::Future` + = note: required by `std::ops::Try::into_result` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From 883c177abb216fcef5b2d2369970394b0967f302 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 4 May 2020 15:26:17 +0200 Subject: [PATCH 17/24] Move doc alias discovery into the Attributes struct and some code improvements --- src/librustdoc/clean/types.rs | 9 +++++++ src/librustdoc/html/render.rs | 2 +- src/librustdoc/html/render/cache.rs | 41 +++-------------------------- src/librustdoc/html/static/main.js | 2 +- 4 files changed, 15 insertions(+), 39 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 0a682857b1825..cd767802714b0 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -643,6 +643,15 @@ impl Attributes { }) .collect() } + + pub fn get_doc_aliases(&self) -> FxHashSet { + self.other_attrs + .lists(sym::doc) + .filter(|a| a.check_name(sym::alias)) + .filter_map(|a| a.value_str().map(|s| s.to_string().replace("\"", ""))) + .filter(|v| !v.is_empty()) + .collect::>() + } } impl PartialEq for Attributes { diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 9454baf764097..abca8ab778cc3 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -278,7 +278,7 @@ pub struct RenderInfo { /// Struct representing one entry in the JS search index. These are all emitted /// by hand to a large JS file at the end of cache-creation. #[derive(Debug)] -pub struct IndexItem { +struct IndexItem { ty: ItemType, name: String, path: String, diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs index 53cf1abb16d56..b8d97c2ac503b 100644 --- a/src/librustdoc/html/render/cache.rs +++ b/src/librustdoc/html/render/cache.rs @@ -328,15 +328,7 @@ impl DocFolder for Cache { search_type: get_index_search_type(&item), }); - for alias in item - .attrs - .lists(sym::doc) - .filter(|a| a.check_name(sym::alias)) - .filter_map(|a| a.value_str().map(|s| s.to_string().replace("\"", ""))) - .filter(|v| !v.is_empty()) - .collect::>() - .into_iter() - { + for alias in item.attrs.get_doc_aliases() { self.aliases .entry(alias.to_lowercase()) .or_insert(Vec::with_capacity(1)) @@ -378,9 +370,6 @@ impl DocFolder for Cache { | clean::MacroItem(..) | clean::ProcMacroItem(..) | clean::VariantItem(..) - | clean::StructFieldItem(..) - | clean::TyMethodItem(..) - | clean::MethodItem(..) if !self.stripped_mod => { // Re-exported items mean that the same id can show up twice @@ -564,15 +553,7 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { parent_idx: None, search_type: get_index_search_type(&item), }); - for alias in item - .attrs - .lists(sym::doc) - .filter(|a| a.check_name(sym::alias)) - .filter_map(|a| a.value_str().map(|s| s.to_string().replace("\"", ""))) - .filter(|v| !v.is_empty()) - .collect::>() - .into_iter() - { + for alias in item.attrs.get_doc_aliases().into_iter() { aliases .entry(alias.to_lowercase()) .or_insert(Vec::with_capacity(1)) @@ -619,22 +600,8 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { .map(|module| shorten(plain_summary_line(module.doc_value()))) .unwrap_or(String::new()); - let crate_aliases = aliases - .iter() - .map(|(k, values)| { - ( - k.clone(), - values - .iter() - .filter_map(|v| { - let x = &crate_items[*v]; - if x.parent_idx.is_some() == x.parent.is_some() { Some(*v) } else { None } - }) - .collect::>(), - ) - }) - .filter(|(_, values)| !values.is_empty()) - .collect::>(); + let crate_aliases = + aliases.iter().map(|(k, values)| (k.clone(), values.clone())).collect::>(); #[derive(Serialize)] struct CrateData<'a> { diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 94ae69fde57fd..22e312e13c011 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -972,7 +972,7 @@ function getSearchElement() { desc: item.desc, ty: item.ty, parent: item.parent, - type: item.parent, + type: item.type, is_alias: true, }; } From c4d9318be6a493da4c6aa307dd4de7e24a15120a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 7 May 2020 21:42:41 +0200 Subject: [PATCH 18/24] Make current crate aliases go first --- src/librustdoc/html/static/main.js | 20 ++++++--- src/test/rustdoc-js-std/alias-2.js | 6 +-- src/test/rustdoc-js/doc-alias.js | 68 +++++++++++++++++++++--------- src/test/rustdoc-js/doc-alias.rs | 1 - src/tools/rustdoc-js/tester.js | 6 ++- 5 files changed, 67 insertions(+), 34 deletions(-) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 22e312e13c011..7592331dd656d 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -978,7 +978,10 @@ function getSearchElement() { } function handleAliases(ret, query, filterCrates) { + // We separate aliases and crate aliases because we want to have current crate + // aliases to be before the others in the displayed results. var aliases = []; + var crateAliases = []; var i; if (filterCrates !== undefined && ALIASES[filterCrates] && @@ -990,25 +993,28 @@ function getSearchElement() { } else { Object.keys(ALIASES).forEach(function(crate) { if (ALIASES[crate][query.search]) { + var pushTo = crate === window.currentCrate ? crateAliases : aliases; for (i = 0; i < ALIASES[crate][query.search].length; ++i) { - aliases.push( + pushTo.push( createAliasFromItem( searchIndex[ALIASES[crate][query.search][i]])); } } }); } - aliases.sort(function(aaa, bbb) { + + var sortFunc = function(aaa, bbb) { if (aaa.path < bbb.path) { return 1; } else if (aaa.path === bbb.path) { return 0; } return -1; - }); - for (i = 0; i < aliases.length; ++i) { - var alias = aliases[i]; + }; + crateAliases.sort(sortFunc); + aliases.sort(sortFunc); + var pushFunc = function(alias) { alias.alias = query.raw; var res = buildHrefAndPath(alias); alias.displayPath = pathSplitter(res[0]); @@ -1019,7 +1025,9 @@ function getSearchElement() { if (ret.others.length > MAX_RESULTS) { ret.others.pop(); } - } + }; + onEach(aliases, pushFunc); + onEach(crateAliases, pushFunc); } // quoted values mean literal search diff --git a/src/test/rustdoc-js-std/alias-2.js b/src/test/rustdoc-js-std/alias-2.js index cb6ec4f8fed4e..798fa29efbd2d 100644 --- a/src/test/rustdoc-js-std/alias-2.js +++ b/src/test/rustdoc-js-std/alias-2.js @@ -1,12 +1,10 @@ -// ignore-order - const QUERY = '+'; const EXPECTED = { 'others': [ - { 'path': 'core::ops', 'name': 'AddAssign' }, - { 'path': 'core::ops', 'name': 'Add' }, { 'path': 'std::ops', 'name': 'AddAssign' }, { 'path': 'std::ops', 'name': 'Add' }, + { 'path': 'core::ops', 'name': 'AddAssign' }, + { 'path': 'core::ops', 'name': 'Add' }, ], }; diff --git a/src/test/rustdoc-js/doc-alias.js b/src/test/rustdoc-js/doc-alias.js index e6310b625e533..896808d415780 100644 --- a/src/test/rustdoc-js/doc-alias.js +++ b/src/test/rustdoc-js/doc-alias.js @@ -32,7 +32,8 @@ const EXPECTED = [ 'path': 'doc_alias', 'name': 'Struct', 'alias': 'StructItem', - 'href': '../doc_alias/struct.Struct.html' + 'href': '../doc_alias/struct.Struct.html', + 'is_alias': true }, ], }, @@ -42,7 +43,8 @@ const EXPECTED = [ 'path': 'doc_alias::Struct', 'name': 'field', 'alias': 'StructFieldItem', - 'href': '../doc_alias/struct.Struct.html#structfield.field' + 'href': '../doc_alias/struct.Struct.html#structfield.field', + 'is_alias': true }, ], }, @@ -52,7 +54,8 @@ const EXPECTED = [ 'path': 'doc_alias::Struct', 'name': 'method', 'alias': 'StructMethodItem', - 'href': '../doc_alias/struct.Struct.html#method.method' + 'href': '../doc_alias/struct.Struct.html#method.method', + 'is_alias': true }, ], }, @@ -65,8 +68,15 @@ const EXPECTED = [ 'others': [], }, { - // ImplTraitFunction - 'others': [], + 'others': [ + { + 'path': 'doc_alias::Struct', + 'name': 'function', + 'alias': 'ImplTraitFunction', + 'href': '../doc_alias/struct.Struct.html#method.function', + 'is_alias': true + }, + ], }, { 'others': [ @@ -74,7 +84,8 @@ const EXPECTED = [ 'path': 'doc_alias', 'name': 'Enum', 'alias': 'EnumItem', - 'href': '../doc_alias/enum.Enum.html' + 'href': '../doc_alias/enum.Enum.html', + 'is_alias': true }, ], }, @@ -84,7 +95,8 @@ const EXPECTED = [ 'path': 'doc_alias::Enum', 'name': 'Variant', 'alias': 'VariantItem', - 'href': '../doc_alias/enum.Enum.html#variant.Variant' + 'href': '../doc_alias/enum.Enum.html#variant.Variant', + 'is_alias': true }, ], }, @@ -94,7 +106,8 @@ const EXPECTED = [ 'path': 'doc_alias::Enum', 'name': 'method', 'alias': 'EnumMethodItem', - 'href': '../doc_alias/enum.Enum.html#method.method' + 'href': '../doc_alias/enum.Enum.html#method.method', + 'is_alias': true }, ], }, @@ -104,7 +117,8 @@ const EXPECTED = [ 'path': 'doc_alias', 'name': 'Typedef', 'alias': 'TypedefItem', - 'href': '../doc_alias/type.Typedef.html' + 'href': '../doc_alias/type.Typedef.html', + 'is_alias': true }, ], }, @@ -114,7 +128,8 @@ const EXPECTED = [ 'path': 'doc_alias', 'name': 'Trait', 'alias': 'TraitItem', - 'href': '../doc_alias/trait.Trait.html' + 'href': '../doc_alias/trait.Trait.html', + 'is_alias': true }, ], }, @@ -124,7 +139,8 @@ const EXPECTED = [ 'path': 'doc_alias::Trait', 'name': 'Target', 'alias': 'TraitTypeItem', - 'href': '../doc_alias/trait.Trait.html#associatedtype.Target' + 'href': '../doc_alias/trait.Trait.html#associatedtype.Target', + 'is_alias': true }, ], }, @@ -134,7 +150,8 @@ const EXPECTED = [ 'path': 'doc_alias::Trait', 'name': 'AssociatedConst', 'alias': 'AssociatedConstItem', - 'href': '../doc_alias/trait.Trait.html#associatedconstant.AssociatedConst' + 'href': '../doc_alias/trait.Trait.html#associatedconstant.AssociatedConst', + 'is_alias': true }, ], }, @@ -144,7 +161,8 @@ const EXPECTED = [ 'path': 'doc_alias::Trait', 'name': 'function', 'alias': 'TraitFunctionItem', - 'href': '../doc_alias/trait.Trait.html#tymethod.function' + 'href': '../doc_alias/trait.Trait.html#tymethod.function', + 'is_alias': true }, ], }, @@ -154,7 +172,8 @@ const EXPECTED = [ 'path': 'doc_alias', 'name': 'function', 'alias': 'FunctionItem', - 'href': '../doc_alias/fn.function.html' + 'href': '../doc_alias/fn.function.html', + 'is_alias': true }, ], }, @@ -164,7 +183,8 @@ const EXPECTED = [ 'path': 'doc_alias', 'name': 'Module', 'alias': 'ModuleItem', - 'href': '../doc_alias/Module/index.html' + 'href': '../doc_alias/Module/index.html', + 'is_alias': true }, ], }, @@ -174,7 +194,8 @@ const EXPECTED = [ 'path': 'doc_alias', 'name': 'Const', 'alias': 'ConstItem', - 'href': '../doc_alias/constant.Const.html' + 'href': '../doc_alias/constant.Const.html', + 'is_alias': true }, ], }, @@ -184,7 +205,8 @@ const EXPECTED = [ 'path': 'doc_alias', 'name': 'Static', 'alias': 'StaticItem', - 'href': '../doc_alias/static.Static.html' + 'href': '../doc_alias/static.Static.html', + 'is_alias': true }, ], }, @@ -194,7 +216,8 @@ const EXPECTED = [ 'path': 'doc_alias', 'name': 'Union', 'alias': 'UnionItem', - 'href': '../doc_alias/union.Union.html' + 'href': '../doc_alias/union.Union.html', + 'is_alias': true }, // Not an alias! { @@ -210,7 +233,8 @@ const EXPECTED = [ 'path': 'doc_alias::Union', 'name': 'union_item', 'alias': 'UnionFieldItem', - 'href': '../doc_alias/union.Union.html#structfield.union_item' + 'href': '../doc_alias/union.Union.html#structfield.union_item', + 'is_alias': true }, ], }, @@ -220,7 +244,8 @@ const EXPECTED = [ 'path': 'doc_alias::Union', 'name': 'method', 'alias': 'UnionMethodItem', - 'href': '../doc_alias/union.Union.html#method.method' + 'href': '../doc_alias/union.Union.html#method.method', + 'is_alias': true }, ], }, @@ -230,7 +255,8 @@ const EXPECTED = [ 'path': 'doc_alias', 'name': 'Macro', 'alias': 'MacroItem', - 'href': '../doc_alias/macro.Macro.html' + 'href': '../doc_alias/macro.Macro.html', + 'is_alias': true }, ], }, diff --git a/src/test/rustdoc-js/doc-alias.rs b/src/test/rustdoc-js/doc-alias.rs index 8cd0a82997414..84c638a199507 100644 --- a/src/test/rustdoc-js/doc-alias.rs +++ b/src/test/rustdoc-js/doc-alias.rs @@ -19,7 +19,6 @@ impl Trait for Struct { #[doc(alias = "ImplAssociatedConstItem")] const AssociatedConst: i32 = 12; - // Shouldn't be listed in aliases! #[doc(alias = "ImplTraitFunction")] fn function() -> Self::Target { 0 } } diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js index 90315d6f64431..1fa46ce99f5e6 100644 --- a/src/tools/rustdoc-js/tester.js +++ b/src/tools/rustdoc-js/tester.js @@ -218,7 +218,7 @@ function lookForEntry(entry, data) { return null; } -function loadMainJsAndIndex(mainJs, searchIndex, crate) { +function loadMainJsAndIndex(mainJs, searchIndex, storageJs, crate) { if (searchIndex[searchIndex.length - 1].length === 0) { searchIndex.pop(); } @@ -241,6 +241,7 @@ function loadMainJsAndIndex(mainJs, searchIndex, crate) { ALIASES = {}; finalJS += 'window = { "currentCrate": "' + crate + '" };\n'; finalJS += 'var rootPath = "../";\n'; + finalJS += loadThings(["onEach"], 'function', extractFunction, storageJs); finalJS += loadThings(arraysToLoad, 'array', extractArrayVariable, mainJs); finalJS += loadThings(variablesToLoad, 'variable', extractVariable, mainJs); finalJS += loadThings(functionsToLoad, 'function', extractFunction, mainJs); @@ -338,10 +339,11 @@ function runChecks(testFile, loaded, index) { function load_files(doc_folder, resource_suffix, crate) { var mainJs = readFile(path.join(doc_folder, "main" + resource_suffix + ".js")); + var storageJs = readFile(path.join(doc_folder, "storage" + resource_suffix + ".js")); var searchIndex = readFile( path.join(doc_folder, "search-index" + resource_suffix + ".js")).split("\n"); - return loadMainJsAndIndex(mainJs, searchIndex, crate); + return loadMainJsAndIndex(mainJs, searchIndex, storageJs, crate); } function showHelp() { From e17ac668997410a1a9d2da8725329afb8b5f2901 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 13 May 2020 17:03:37 +0200 Subject: [PATCH 19/24] * Update aliases data struct from HashMap to BTreeMap to have more deterministic results * Update Javascript to take this change into account * Update CrateData::aliases field to take a reference instead (it allowed to remove a conversion loop) --- src/librustdoc/html/render/cache.rs | 16 +++++++--------- src/librustdoc/html/static/main.js | 7 ++++--- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs index b8d97c2ac503b..57d385de32096 100644 --- a/src/librustdoc/html/render/cache.rs +++ b/src/librustdoc/html/render/cache.rs @@ -120,7 +120,7 @@ crate struct Cache { /// Aliases added through `#[doc(alias = "...")]`. Since a few items can have the same alias, /// we need the alias element to have an array of items. - pub(super) aliases: FxHashMap>, + pub(super) aliases: BTreeMap>, } impl Cache { @@ -331,7 +331,7 @@ impl DocFolder for Cache { for alias in item.attrs.get_doc_aliases() { self.aliases .entry(alias.to_lowercase()) - .or_insert(Vec::with_capacity(1)) + .or_insert(Vec::new()) .push(self.search_index.len() - 1); } } @@ -553,10 +553,10 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { parent_idx: None, search_type: get_index_search_type(&item), }); - for alias in item.attrs.get_doc_aliases().into_iter() { + for alias in item.attrs.get_doc_aliases() { aliases .entry(alias.to_lowercase()) - .or_insert(Vec::with_capacity(1)) + .or_insert(Vec::new()) .push(search_index.len() - 1); } } @@ -600,9 +600,6 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { .map(|module| shorten(plain_summary_line(module.doc_value()))) .unwrap_or(String::new()); - let crate_aliases = - aliases.iter().map(|(k, values)| (k.clone(), values.clone())).collect::>(); - #[derive(Serialize)] struct CrateData<'a> { doc: String, @@ -614,7 +611,8 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { // // To be noted: the `usize` elements are indexes to `items`. #[serde(rename = "a")] - aliases: Option)>>, + #[serde(skip_serializing_if = "BTreeMap::is_empty")] + aliases: &'a BTreeMap>, } // Collect the index into a string @@ -625,7 +623,7 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { doc: crate_doc, items: crate_items, paths: crate_paths, - aliases: if crate_aliases.is_empty() { None } else { Some(crate_aliases) }, + aliases, }) .expect("failed serde conversion") // All these `replace` calls are because we have to go through JS string for JSON content. diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 7592331dd656d..9b498d66249e2 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -1781,12 +1781,13 @@ function getSearchElement() { if (aliases) { ALIASES[crate] = {}; var j, local_aliases; - for (i = 0; i < aliases.length; ++i) { - var alias_name = aliases[i][0]; + for (var alias_name in aliases) { + if (!aliases.hasOwnProperty(alias_name)) { continue; } + if (!ALIASES[crate].hasOwnProperty(alias_name)) { ALIASES[crate][alias_name] = []; } - local_aliases = aliases[i][1]; + local_aliases = aliases[alias_name]; for (j = 0; j < local_aliases.length; ++j) { ALIASES[crate][alias_name].push(local_aliases[j] + currentIndex); } From 0dc74dc0c6beb0bf2fd4fcc32cf3461a07f44521 Mon Sep 17 00:00:00 2001 From: sergey-melnychuk Date: Thu, 14 May 2020 20:02:40 +0200 Subject: [PATCH 20/24] cleanup stale FIXME(#64197) --- src/librustc_expand/parse/lexer/tests.rs | 4 ++-- src/librustc_parse/lexer/mod.rs | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/librustc_expand/parse/lexer/tests.rs b/src/librustc_expand/parse/lexer/tests.rs index 2cb6267e0f6aa..2932475430bbf 100644 --- a/src/librustc_expand/parse/lexer/tests.rs +++ b/src/librustc_expand/parse/lexer/tests.rs @@ -50,13 +50,13 @@ fn t1() { assert_eq!(string_reader.next_token(), token::Whitespace); // Read another token. let tok3 = string_reader.next_token(); - assert_eq!(string_reader.pos.clone(), BytePos(28)); + assert_eq!(string_reader.pos(), BytePos(28)); let tok4 = Token::new(mk_ident("main"), Span::with_root_ctxt(BytePos(24), BytePos(28))); assert_eq!(tok3.kind, tok4.kind); assert_eq!(tok3.span, tok4.span); assert_eq!(string_reader.next_token(), token::OpenDelim(token::Paren)); - assert_eq!(string_reader.pos.clone(), BytePos(29)) + assert_eq!(string_reader.pos(), BytePos(29)) }) } diff --git a/src/librustc_parse/lexer/mod.rs b/src/librustc_parse/lexer/mod.rs index f676a34a1d12b..aa048d682c2da 100644 --- a/src/librustc_parse/lexer/mod.rs +++ b/src/librustc_parse/lexer/mod.rs @@ -31,8 +31,7 @@ pub struct StringReader<'a> { /// Initial position, read-only. start_pos: BytePos, /// The absolute offset within the source_map of the current character. - // FIXME(#64197): `pub` is needed by tests for now. - pub pos: BytePos, + pos: BytePos, /// Stop reading src at this index. end_src_index: usize, /// Source text to tokenize. @@ -436,6 +435,10 @@ impl<'a> StringReader<'a> { } } + pub fn pos(&self) -> BytePos { + self.pos + } + #[inline] fn src_index(&self, pos: BytePos) -> usize { (pos - self.start_pos).to_usize() From 89543793126b142b8c40b4cc83e284a91cccb499 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 14 May 2020 23:29:50 +0200 Subject: [PATCH 21/24] make sure even unleashed miri does not do pointer stuff --- .../ui/consts/miri_unleashed/ptr_arith.rs | 29 ++++++++++++++ .../ui/consts/miri_unleashed/ptr_arith.stderr | 39 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 src/test/ui/consts/miri_unleashed/ptr_arith.rs create mode 100644 src/test/ui/consts/miri_unleashed/ptr_arith.stderr diff --git a/src/test/ui/consts/miri_unleashed/ptr_arith.rs b/src/test/ui/consts/miri_unleashed/ptr_arith.rs new file mode 100644 index 0000000000000..81985f9f625a5 --- /dev/null +++ b/src/test/ui/consts/miri_unleashed/ptr_arith.rs @@ -0,0 +1,29 @@ +// compile-flags: -Zunleash-the-miri-inside-of-you +#![feature(core_intrinsics)] +#![allow(const_err)] + +// A test demonstrating that we prevent doing even trivial +// pointer arithmetic or comparison during CTFE. + +static CMP: () = { + let x = &0 as *const _; + let _v = x == x; + //~^ ERROR could not evaluate static initializer + //~| NOTE pointer arithmetic or comparison +}; + +static INT_PTR_ARITH: () = unsafe { + let x: usize = std::mem::transmute(&0); + let _v = x + 0; + //~^ ERROR could not evaluate static initializer + //~| NOTE pointer-to-integer cast +}; + +static PTR_ARITH: () = unsafe { + let x = &0 as *const _; + let _v = core::intrinsics::offset(x, 0); + //~^ ERROR could not evaluate static initializer + //~| NOTE calling intrinsic `offset` +}; + +fn main() {} diff --git a/src/test/ui/consts/miri_unleashed/ptr_arith.stderr b/src/test/ui/consts/miri_unleashed/ptr_arith.stderr new file mode 100644 index 0000000000000..5bd534a16b863 --- /dev/null +++ b/src/test/ui/consts/miri_unleashed/ptr_arith.stderr @@ -0,0 +1,39 @@ +error[E0080]: could not evaluate static initializer + --> $DIR/ptr_arith.rs:10:14 + | +LL | let _v = x == x; + | ^^^^^^ "pointer arithmetic or comparison" needs an rfc before being allowed inside constants + +error[E0080]: could not evaluate static initializer + --> $DIR/ptr_arith.rs:17:14 + | +LL | let _v = x + 0; + | ^^^^^ "pointer-to-integer cast" needs an rfc before being allowed inside constants + +error[E0080]: could not evaluate static initializer + --> $DIR/ptr_arith.rs:24:14 + | +LL | let _v = core::intrinsics::offset(x, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ "calling intrinsic `offset`" needs an rfc before being allowed inside constants + +warning: skipping const checks + | +help: skipping check for `const_compare_raw_pointers` feature + --> $DIR/ptr_arith.rs:10:14 + | +LL | let _v = x == x; + | ^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/ptr_arith.rs:16:20 + | +LL | let x: usize = std::mem::transmute(&0); + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: skipping check that does not even have a feature gate + --> $DIR/ptr_arith.rs:24:14 + | +LL | let _v = core::intrinsics::offset(x, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0080`. From e84b379351577cae8cc3e89bf66c71bcabf547d7 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Thu, 23 Apr 2020 17:09:21 -0400 Subject: [PATCH 22/24] [const-prop] Don't replace Rvalues that are already constants --- src/librustc_mir/transform/const_prop.rs | 7 +++++++ .../const_prop/mutable_variable/rustc.main.ConstProp.diff | 3 +-- .../mutable_variable_aggregate/rustc.main.ConstProp.diff | 3 +-- .../rustc.arg_src.CopyPropagation.diff | 2 +- .../copy_propagation_arg/rustc.bar.CopyPropagation.diff | 2 +- 5 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index e898f22ec230d..bdf2193c6af45 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -616,6 +616,13 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { value: OpTy<'tcx>, source_info: SourceInfo, ) { + if let Rvalue::Use(Operand::Constant(c)) = rval { + if !matches!(c.literal.val, ConstKind::Unevaluated(..)) { + trace!("skipping replace of Rvalue::Use({:?} because it is already a const", c); + return; + } + } + trace!("attepting to replace {:?} with {:?}", rval, value); if let Err(e) = self.ecx.const_validate_operand( value, diff --git a/src/test/mir-opt/const_prop/mutable_variable/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable/rustc.main.ConstProp.diff index c6c5b0cf72635..187c17454350a 100644 --- a/src/test/mir-opt/const_prop/mutable_variable/rustc.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/mutable_variable/rustc.main.ConstProp.diff @@ -26,8 +26,7 @@ // + ty: i32 // + val: Value(Scalar(0x00000063)) // mir::Constant -- // + span: $DIR/mutable_variable.rs:6:9: 6:11 -+ // + span: $DIR/mutable_variable.rs:6:5: 6:11 + // + span: $DIR/mutable_variable.rs:6:9: 6:11 // + literal: Const { ty: i32, val: Value(Scalar(0x00000063)) } StorageLive(_2); // scope 1 at $DIR/mutable_variable.rs:7:9: 7:10 - _2 = _1; // scope 1 at $DIR/mutable_variable.rs:7:13: 7:14 diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_aggregate/rustc.main.ConstProp.diff index 26f0250d94c0b..cf432b2acc1c5 100644 --- a/src/test/mir-opt/const_prop/mutable_variable_aggregate/rustc.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate/rustc.main.ConstProp.diff @@ -34,8 +34,7 @@ // + ty: i32 // + val: Value(Scalar(0x00000063)) // mir::Constant -- // + span: $DIR/mutable_variable_aggregate.rs:6:11: 6:13 -+ // + span: $DIR/mutable_variable_aggregate.rs:6:5: 6:13 + // + span: $DIR/mutable_variable_aggregate.rs:6:11: 6:13 // + literal: Const { ty: i32, val: Value(Scalar(0x00000063)) } StorageLive(_2); // scope 1 at $DIR/mutable_variable_aggregate.rs:7:9: 7:10 - _2 = _1; // scope 1 at $DIR/mutable_variable_aggregate.rs:7:13: 7:14 diff --git a/src/test/mir-opt/copy_propagation_arg/rustc.arg_src.CopyPropagation.diff b/src/test/mir-opt/copy_propagation_arg/rustc.arg_src.CopyPropagation.diff index b976449ca6d32..1e0271a560f65 100644 --- a/src/test/mir-opt/copy_propagation_arg/rustc.arg_src.CopyPropagation.diff +++ b/src/test/mir-opt/copy_propagation_arg/rustc.arg_src.CopyPropagation.diff @@ -17,7 +17,7 @@ // + ty: i32 // + val: Value(Scalar(0x0000007b)) // mir::Constant - // + span: $DIR/copy_propagation_arg.rs:29:5: 29:12 + // + span: $DIR/copy_propagation_arg.rs:29:9: 29:12 // + literal: Const { ty: i32, val: Value(Scalar(0x0000007b)) } _0 = _2; // scope 1 at $DIR/copy_propagation_arg.rs:30:5: 30:6 StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:31:1: 31:2 diff --git a/src/test/mir-opt/copy_propagation_arg/rustc.bar.CopyPropagation.diff b/src/test/mir-opt/copy_propagation_arg/rustc.bar.CopyPropagation.diff index 26f8068f674ef..b875bbea67bdf 100644 --- a/src/test/mir-opt/copy_propagation_arg/rustc.bar.CopyPropagation.diff +++ b/src/test/mir-opt/copy_propagation_arg/rustc.bar.CopyPropagation.diff @@ -28,7 +28,7 @@ // + ty: u8 // + val: Value(Scalar(0x05)) // mir::Constant - // + span: $DIR/copy_propagation_arg.rs:17:5: 17:10 + // + span: $DIR/copy_propagation_arg.rs:17:9: 17:10 // + literal: Const { ty: u8, val: Value(Scalar(0x05)) } _0 = const (); // scope 0 at $DIR/copy_propagation_arg.rs:15:19: 18:2 // ty::Const From 257e3772cb1b434a3c3fc8ac61ef808929036558 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Fri, 15 May 2020 04:49:23 +0000 Subject: [PATCH 23/24] doc: add links to rotate_(left|right) --- src/libcore/num/mod.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index a259e293b0c1a..9039e71b82864 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -1448,8 +1448,8 @@ any high-order bits of `rhs` that would cause the shift to exceed the bitwidth o Note that this is *not* the same as a rotate-left; the RHS of a wrapping shift-left is restricted to the range of the type, rather than the bits shifted out of the LHS being returned to the other end. -The primitive integer types all implement a `rotate_left` function, which may be what you want -instead. +The primitive integer types all implement a `[`rotate_left`](#method.rotate_left) function, +which may be what you want instead. # Examples @@ -1480,8 +1480,8 @@ removes any high-order bits of `rhs` that would cause the shift to exceed the bi Note that this is *not* the same as a rotate-right; the RHS of a wrapping shift-right is restricted to the range of the type, rather than the bits shifted out of the LHS being returned to the other -end. The primitive integer types all implement a `rotate_right` function, which may be what you want -instead. +end. The primitive integer types all implement a [`rotate_right`](#method.rotate_right) function, +which may be what you want instead. # Examples @@ -3508,8 +3508,8 @@ Note that this is *not* the same as a rotate-left; the RHS of a wrapping shift-left is restricted to the range of the type, rather than the bits shifted out of the LHS being returned to the other end. The primitive integer -types all implement a `rotate_left` function, which may -be what you want instead. +types all implement a [`rotate_left`](#method.rotate_left) function, +which may be what you want instead. # Examples @@ -3542,8 +3542,8 @@ Note that this is *not* the same as a rotate-right; the RHS of a wrapping shift-right is restricted to the range of the type, rather than the bits shifted out of the LHS being returned to the other end. The primitive integer -types all implement a `rotate_right` function, which may -be what you want instead. +types all implement a [`rotate_right`](#method.rotate_right) function, +which may be what you want instead. # Examples From 10d7da4e0b07f469c9d2b8215b563528adfc7e99 Mon Sep 17 00:00:00 2001 From: csmoe Date: Thu, 14 May 2020 23:07:46 +0800 Subject: [PATCH 24/24] implement type_implments_trait query --- src/librustc_middle/hir/map/mod.rs | 2 +- src/librustc_middle/query/mod.rs | 6 +++ src/librustc_middle/ty/query/keys.rs | 12 ++++++ .../traits/error_reporting/suggestions.rs | 37 ++++++++-------- src/librustc_trait_selection/traits/mod.rs | 42 ++++++++++++++++++- src/test/ui/async-await/issue-61076.rs | 20 +++++++++ src/test/ui/async-await/issue-61076.stderr | 16 ++++++- .../ui/async-await/try-on-option-in-async.rs | 3 +- .../async-await/try-on-option-in-async.stderr | 6 +-- .../clippy/clippy_lints/src/utils/mod.rs | 18 +------- 10 files changed, 120 insertions(+), 42 deletions(-) diff --git a/src/librustc_middle/hir/map/mod.rs b/src/librustc_middle/hir/map/mod.rs index a3f8cd1ee36fe..b823516d64f3b 100644 --- a/src/librustc_middle/hir/map/mod.rs +++ b/src/librustc_middle/hir/map/mod.rs @@ -390,7 +390,7 @@ impl<'hir> Map<'hir> { /// Given a `HirId`, returns the `BodyId` associated with it, /// if the node is a body owner, otherwise returns `None`. pub fn maybe_body_owned_by(&self, hir_id: HirId) -> Option { - if let Some(node) = self.find(hir_id) { associated_body(node) } else { None } + self.find(hir_id).map(associated_body).flatten() } /// Given a body owner's id, returns the `BodyId` associated with it. diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs index 2ceba51949420..13cf9a934b72c 100644 --- a/src/librustc_middle/query/mod.rs +++ b/src/librustc_middle/query/mod.rs @@ -1164,6 +1164,12 @@ rustc_queries! { desc { "evaluating trait selection obligation `{}`", goal.value } } + query type_implements_trait( + key: (DefId, Ty<'tcx>, SubstsRef<'tcx>, ty::ParamEnv<'tcx>, ) + ) -> bool { + desc { "evaluating `type_implements_trait` `{:?}`", key } + } + /// Do not call this query directly: part of the `Eq` type-op query type_op_ascribe_user_type( goal: CanonicalTypeOpAscribeUserTypeGoal<'tcx> diff --git a/src/librustc_middle/ty/query/keys.rs b/src/librustc_middle/ty/query/keys.rs index 239691dbd17ac..4acf766f033d8 100644 --- a/src/librustc_middle/ty/query/keys.rs +++ b/src/librustc_middle/ty/query/keys.rs @@ -295,3 +295,15 @@ impl Key for (Symbol, u32, u32) { DUMMY_SP } } + +impl<'tcx> Key for (DefId, Ty<'tcx>, SubstsRef<'tcx>, ty::ParamEnv<'tcx>) { + type CacheSelector = DefaultCacheSelector; + + fn query_crate(&self) -> CrateNum { + LOCAL_CRATE + } + + fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { + DUMMY_SP + } +} diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index 5e3b383ff2580..d5b2b765e939f 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -11,6 +11,7 @@ use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; +use rustc_hir::lang_items; use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node}; use rustc_middle::ty::TypeckTables; use rustc_middle::ty::{ @@ -1785,29 +1786,30 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { span: Span, ) { debug!( - "suggest_await_befor_try: obligation={:?}, span={:?}, trait_ref={:?}", - obligation, span, trait_ref + "suggest_await_befor_try: obligation={:?}, span={:?}, trait_ref={:?}, trait_ref_self_ty={:?}", + obligation, + span, + trait_ref, + trait_ref.self_ty() ); let body_hir_id = obligation.cause.body_id; let item_id = self.tcx.hir().get_parent_node(body_hir_id); - let mut is_future = false; - if let ty::Opaque(def_id, substs) = trait_ref.self_ty().kind { - let preds = self.tcx.predicates_of(def_id).instantiate(self.tcx, substs); - for p in preds.predicates { - if let Some(trait_ref) = p.to_opt_poly_trait_ref() { - if Some(trait_ref.def_id()) == self.tcx.lang_items().future_trait() { - is_future = true; - break; - } - } - } - } - if let Some(body_id) = self.tcx.hir().maybe_body_owned_by(item_id) { let body = self.tcx.hir().body(body_id); if let Some(hir::GeneratorKind::Async(_)) = body.generator_kind { - let future_trait = self.tcx.lang_items().future_trait().unwrap(); + let future_trait = + self.tcx.require_lang_item(lang_items::FutureTraitLangItem, None); + + let self_ty = self.resolve_vars_if_possible(&trait_ref.self_ty()); + + let impls_future = self.tcx.type_implements_trait(( + future_trait, + self_ty, + ty::List::empty(), + obligation.param_env, + )); + let item_def_id = self .tcx .associated_items(future_trait) @@ -1815,7 +1817,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { .next() .unwrap() .def_id; - debug!("trait_ref_self_ty: {:?}", trait_ref.self_ty()); // `::Output` let projection_ty = ty::ProjectionTy { // `T` @@ -1850,7 +1851,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { obligation.param_env, ); debug!("suggest_await_befor_try: try_trait_obligation {:?}", try_obligation); - if self.predicate_may_hold(&try_obligation) && is_future { + if self.predicate_may_hold(&try_obligation) && impls_future { if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { if snippet.ends_with('?') { err.span_suggestion( diff --git a/src/librustc_trait_selection/traits/mod.rs b/src/librustc_trait_selection/traits/mod.rs index 778430fc2ca9c..9592f93ce2e76 100644 --- a/src/librustc_trait_selection/traits/mod.rs +++ b/src/librustc_trait_selection/traits/mod.rs @@ -31,7 +31,9 @@ use rustc_hir::def_id::DefId; use rustc_middle::middle::region; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::{InternalSubsts, SubstsRef}; -use rustc_middle::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, WithConstness}; +use rustc_middle::ty::{ + self, GenericParamDefKind, ParamEnv, ToPredicate, Ty, TyCtxt, WithConstness, +}; use rustc_span::Span; use std::fmt::Debug; @@ -523,6 +525,43 @@ fn vtable_methods<'tcx>( })) } +/// Check whether a `ty` implements given trait(trait_def_id). +/// +/// NOTE: Always return `false` for a type which needs inference. +fn type_implements_trait<'tcx>( + tcx: TyCtxt<'tcx>, + key: ( + DefId, // trait_def_id, + Ty<'tcx>, // type + SubstsRef<'tcx>, + ParamEnv<'tcx>, + ), +) -> bool { + let (trait_def_id, ty, params, param_env) = key; + + debug!( + "type_implements_trait: trait_def_id={:?}, type={:?}, params={:?}, param_env={:?}", + trait_def_id, ty, params, param_env + ); + + // Do not check on infer_types to avoid panic in evaluate_obligation. + if ty.has_infer_types() { + return false; + } + + let ty = tcx.erase_regions(&ty); + + let trait_ref = ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(ty, params) }; + + let obligation = Obligation { + cause: ObligationCause::dummy(), + param_env, + recursion_depth: 0, + predicate: trait_ref.without_const().to_predicate(), + }; + tcx.infer_ctxt().enter(|infcx| infcx.predicate_must_hold_modulo_regions(&obligation)) +} + pub fn provide(providers: &mut ty::query::Providers<'_>) { object_safety::provide(providers); *providers = ty::query::Providers { @@ -531,6 +570,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) { codegen_fulfill_obligation: codegen::codegen_fulfill_obligation, vtable_methods, substitute_normalize_and_test_predicates, + type_implements_trait, ..*providers }; } diff --git a/src/test/ui/async-await/issue-61076.rs b/src/test/ui/async-await/issue-61076.rs index 04a9148ae2413..13b45df64eabe 100644 --- a/src/test/ui/async-await/issue-61076.rs +++ b/src/test/ui/async-await/issue-61076.rs @@ -1,5 +1,19 @@ // edition:2018 +use core::future::Future; +use core::pin::Pin; +use core::task::{Context, Poll}; + +struct T; + +impl Future for T { + type Output = Result<(), ()>; + + fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll { + Poll::Pending + } +} + async fn foo() -> Result<(), ()> { Ok(()) } @@ -9,4 +23,10 @@ async fn bar() -> Result<(), ()> { Ok(()) } +async fn baz() -> Result<(), ()> { + let t = T; + t?; //~ ERROR the `?` operator can only be applied to values that implement `std::ops::Try` + Ok(()) +} + fn main() {} diff --git a/src/test/ui/async-await/issue-61076.stderr b/src/test/ui/async-await/issue-61076.stderr index fb1eead04e6bd..e71f4e7136dad 100644 --- a/src/test/ui/async-await/issue-61076.stderr +++ b/src/test/ui/async-await/issue-61076.stderr @@ -1,5 +1,5 @@ error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` - --> $DIR/issue-61076.rs:8:5 + --> $DIR/issue-61076.rs:22:5 | LL | foo()?; | ^^^^^^ @@ -10,6 +10,18 @@ LL | foo()?; = help: the trait `std::ops::Try` is not implemented for `impl std::future::Future` = note: required by `std::ops::Try::into_result` -error: aborting due to previous error +error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` + --> $DIR/issue-61076.rs:28:5 + | +LL | t?; + | ^^ + | | + | the `?` operator cannot be applied to type `T` + | help: consider using `.await` here: `t.await?` + | + = help: the trait `std::ops::Try` is not implemented for `T` + = note: required by `std::ops::Try::into_result` + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/async-await/try-on-option-in-async.rs b/src/test/ui/async-await/try-on-option-in-async.rs index 51ac522017cb3..c520a07abc172 100644 --- a/src/test/ui/async-await/try-on-option-in-async.rs +++ b/src/test/ui/async-await/try-on-option-in-async.rs @@ -7,7 +7,8 @@ async fn an_async_block() -> u32 { let x: Option = None; x?; //~ ERROR the `?` operator 22 - }.await + } + .await } async fn async_closure_containing_fn() -> u32 { diff --git a/src/test/ui/async-await/try-on-option-in-async.stderr b/src/test/ui/async-await/try-on-option-in-async.stderr index 46f8f41076bf5..700296d674784 100644 --- a/src/test/ui/async-await/try-on-option-in-async.stderr +++ b/src/test/ui/async-await/try-on-option-in-async.stderr @@ -7,14 +7,14 @@ LL | | let x: Option = None; LL | | x?; | | ^^ cannot use the `?` operator in an async block that returns `{integer}` LL | | 22 -LL | | }.await +LL | | } | |_____- this function should return `Result` or `Option` to accept `?` | = help: the trait `std::ops::Try` is not implemented for `{integer}` = note: required by `std::ops::Try::from_error` error[E0277]: the `?` operator can only be used in an async closure that returns `Result` or `Option` (or another type that implements `std::ops::Try`) - --> $DIR/try-on-option-in-async.rs:16:9 + --> $DIR/try-on-option-in-async.rs:17:9 | LL | let async_closure = async || { | __________________________________- @@ -29,7 +29,7 @@ LL | | }; = note: required by `std::ops::Try::from_error` error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `std::ops::Try`) - --> $DIR/try-on-option-in-async.rs:25:5 + --> $DIR/try-on-option-in-async.rs:26:5 | LL | async fn an_async_function() -> u32 { | _____________________________________- diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs index 2fd080e9ef0f8..84a324f76c5b6 100644 --- a/src/tools/clippy/clippy_lints/src/utils/mod.rs +++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs @@ -40,15 +40,12 @@ use rustc_hir::{ use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, Level, Lint, LintContext}; use rustc_middle::hir::map::Map; -use rustc_middle::traits; use rustc_middle::ty::{self, layout::IntegerExt, subst::GenericArg, Binder, Ty, TyCtxt, TypeFoldable}; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::original_sp; use rustc_span::symbol::{self, kw, Symbol}; use rustc_span::{BytePos, Pos, Span, DUMMY_SP}; use rustc_target::abi::Integer; -use rustc_trait_selection::traits::predicate_for_trait_def; -use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::query::normalize::AtExt; use smallvec::SmallVec; @@ -326,19 +323,8 @@ pub fn implements_trait<'a, 'tcx>( trait_id: DefId, ty_params: &[GenericArg<'tcx>], ) -> bool { - let ty = cx.tcx.erase_regions(&ty); - let obligation = predicate_for_trait_def( - cx.tcx, - cx.param_env, - traits::ObligationCause::dummy(), - trait_id, - 0, - ty, - ty_params, - ); - cx.tcx - .infer_ctxt() - .enter(|infcx| infcx.predicate_must_hold_modulo_regions(&obligation)) + let ty_params = cx.tcx.mk_substs(ty_params.iter()); + cx.tcx.type_implements_trait((trait_id, ty, ty_params, cx.param_env)) } /// Gets the `hir::TraitRef` of the trait the given method is implemented for.