提交 49720d2b 编写于 作者: B bors

Auto merge of #78512 - JohnTitor:rollup-a7qwjah, r=JohnTitor

Rollup of 11 pull requests

Successful merges:

 - #77213 (rustdoc options to set default theme (and other settings))
 - #78224 (min_const_generics: allow ty param in repeat expr)
 - #78428 (MinConstGenerics UI test for invalid values for bool & char)
 - #78460 (Adjust turbofish help message for const generics)
 - #78470 (Clean up intra-doc links in `std::path`)
 - #78475 (fix a comment in validity check)
 - #78478 (Add const generics tests for supertraits + dyn traits.)
 - #78487 (Fix typo "compiltest")
 - #78491 (Inline NonZeroN::from(n))
 - #78492 (Update books)
 - #78494 (Fix typos)

Failed merges:

r? `@ghost`
......@@ -206,8 +206,10 @@ pub enum Res<Id = hir::HirId> {
/// ```rust
/// impl Foo { fn test() -> [u8; std::mem::size_of::<Self>()] {} }
/// ```
/// We do however allow `Self` in repeat expression even if it is generic to not break code
/// which already works on stable while causing the `const_evaluatable_unchecked` future compat lint.
///
/// FIXME(lazy_normalization_consts): Remove this bodge once this feature is stable.
/// FIXME(lazy_normalization_consts): Remove this bodge once that feature is stable.
SelfTy(Option<DefId> /* trait */, Option<(DefId, bool)> /* impl */),
ToolMod, // e.g., `rustfmt` in `#[rustfmt::skip]`
......
......@@ -678,8 +678,6 @@ pub fn type_is_unconstrained_numeric(&'a self, ty: Ty<'_>) -> UnconstrainedNumer
pub fn unsolved_variables(&self) -> Vec<Ty<'tcx>> {
let mut inner = self.inner.borrow_mut();
// FIXME(const_generics): should there be an equivalent function for const variables?
let mut vars: Vec<Ty<'_>> = inner
.type_variables()
.unsolved_variables()
......
......@@ -177,7 +177,7 @@ fn kill_loans_out_of_scope_at_location(
//
// We are careful always to call this function *before* we
// set up the gen-bits for the statement or
// termanator. That way, if the effect of the statement or
// terminator. That way, if the effect of the statement or
// terminator *does* introduce a new loan of the same
// region, then setting that gen-bit will override any
// potential kill introduced here.
......
......@@ -8,7 +8,7 @@
///
/// This analysis considers references as being used only at the point of the
/// borrow. In other words, this analysis does not track uses because of references that already
/// exist. See [this `mir-datalow` test][flow-test] for an example. You almost never want to use
/// exist. See [this `mir-dataflow` test][flow-test] for an example. You almost never want to use
/// this analysis without also looking at the results of [`MaybeBorrowedLocals`].
///
/// [`MaybeBorrowedLocals`]: ../struct.MaybeBorrowedLocals.html
......@@ -134,7 +134,7 @@ fn for_place(context: PlaceContext) -> Option<DefUse> {
// `MutatingUseContext::Call` and `MutatingUseContext::Yield` indicate that this is the
// destination place for a `Call` return or `Yield` resume respectively. Since this is
// only a `Def` when the function returns succesfully, we handle this case separately
// only a `Def` when the function returns successfully, we handle this case separately
// in `call_return_effect` above.
PlaceContext::MutatingUse(MutatingUseContext::Call | MutatingUseContext::Yield) => None,
......
......@@ -579,9 +579,8 @@ fn try_visit_primitive(
// Nothing to check.
Ok(true)
}
// The above should be all the (inhabited) primitive types. The rest is compound, we
// The above should be all the primitive types. The rest is compound, we
// check them by visiting their fields/variants.
// (`Str` UTF-8 check happens in `visit_aggregate`, too.)
ty::Adt(..)
| ty::Tuple(..)
| ty::Array(..)
......
......@@ -20,7 +20,8 @@
use tracing::{debug, trace};
const TURBOFISH: &str = "use `::<...>` instead of `<...>` to specify type arguments";
const TURBOFISH_SUGGESTION_STR: &str =
"use `::<...>` instead of `<...>` to specify type or const arguments";
/// Creates a placeholder argument.
pub(super) fn dummy_arg(ident: Ident) -> Param {
......@@ -659,7 +660,7 @@ pub(super) fn check_mistyped_turbofish_with_multiple_type_params(
Ok(_) => {
e.span_suggestion_verbose(
binop.span.shrink_to_lo(),
"use `::<...>` instead of `<...>` to specify type arguments",
TURBOFISH_SUGGESTION_STR,
"::".to_string(),
Applicability::MaybeIncorrect,
);
......@@ -814,7 +815,7 @@ pub(super) fn check_no_chained_comparison(
let suggest = |err: &mut DiagnosticBuilder<'_>| {
err.span_suggestion_verbose(
op.span.shrink_to_lo(),
TURBOFISH,
TURBOFISH_SUGGESTION_STR,
"::".to_string(),
Applicability::MaybeIncorrect,
);
......@@ -888,7 +889,7 @@ pub(super) fn check_no_chained_comparison(
{
// All we know is that this is `foo < bar >` and *nothing* else. Try to
// be helpful, but don't attempt to recover.
err.help(TURBOFISH);
err.help(TURBOFISH_SUGGESTION_STR);
err.help("or use `(...)` if you meant to specify fn arguments");
}
......
......@@ -57,6 +57,12 @@ enum PatternSource {
FnParam,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum IsRepeatExpr {
No,
Yes,
}
impl PatternSource {
fn descr(self) -> &'static str {
match self {
......@@ -437,10 +443,8 @@ fn visit_block(&mut self, block: &'ast Block) {
self.resolve_block(block);
}
fn visit_anon_const(&mut self, constant: &'ast AnonConst) {
debug!("visit_anon_const {:?}", constant);
self.with_constant_rib(constant.value.is_potential_trivial_const_param(), |this| {
visit::walk_anon_const(this, constant);
});
// We deal with repeat expressions explicitly in `resolve_expr`.
self.resolve_anon_const(constant, IsRepeatExpr::No);
}
fn visit_expr(&mut self, expr: &'ast Expr) {
self.resolve_expr(expr, None);
......@@ -647,7 +651,11 @@ fn visit_generic_arg(&mut self, arg: &'ast GenericArg) {
if !check_ns(TypeNS) && check_ns(ValueNS) {
// This must be equivalent to `visit_anon_const`, but we cannot call it
// directly due to visitor lifetimes so we have to copy-paste some code.
self.with_constant_rib(true, |this| {
//
// Note that we might not be inside of an repeat expression here,
// but considering that `IsRepeatExpr` is only relevant for
// non-trivial constants this is doesn't matter.
self.with_constant_rib(IsRepeatExpr::No, true, |this| {
this.smart_resolve_path(
ty.id,
qself.as_ref(),
......@@ -980,9 +988,11 @@ fn resolve_item(&mut self, item: &'ast Item) {
//
// Type parameters can already be used and as associated consts are
// not used as part of the type system, this is far less surprising.
this.with_constant_rib(true, |this| {
this.visit_expr(expr)
});
this.with_constant_rib(
IsRepeatExpr::No,
true,
|this| this.visit_expr(expr),
);
}
}
AssocItemKind::Fn(_, _, generics, _) => {
......@@ -1023,7 +1033,9 @@ fn resolve_item(&mut self, item: &'ast Item) {
self.with_item_rib(HasGenericParams::No, |this| {
this.visit_ty(ty);
if let Some(expr) = expr {
this.with_constant_rib(expr.is_potential_trivial_const_param(), |this| {
// We already forbid generic params because of the above item rib,
// so it doesn't matter whether this is a trivial constant.
this.with_constant_rib(IsRepeatExpr::No, true, |this| {
this.visit_expr(expr)
});
}
......@@ -1122,12 +1134,29 @@ fn with_item_rib(&mut self, has_generic_params: HasGenericParams, f: impl FnOnce
self.with_rib(ValueNS, kind, |this| this.with_rib(TypeNS, kind, f))
}
fn with_constant_rib(&mut self, trivial: bool, f: impl FnOnce(&mut Self)) {
debug!("with_constant_rib");
self.with_rib(ValueNS, ConstantItemRibKind(trivial), |this| {
this.with_rib(TypeNS, ConstantItemRibKind(trivial), |this| {
this.with_label_rib(ConstantItemRibKind(trivial), f);
})
// HACK(min_const_generics,const_evaluatable_unchecked): We
// want to keep allowing `[0; std::mem::size_of::<*mut T>()]`
// with a future compat lint for now. We do this by adding an
// additional special case for repeat expressions.
//
// Note that we intentionally still forbid `[0; N + 1]` during
// name resolution so that we don't extend the future
// compat lint to new cases.
fn with_constant_rib(
&mut self,
is_repeat: IsRepeatExpr,
is_trivial: bool,
f: impl FnOnce(&mut Self),
) {
debug!("with_constant_rib: is_repeat={:?} is_trivial={}", is_repeat, is_trivial);
self.with_rib(ValueNS, ConstantItemRibKind(is_trivial), |this| {
this.with_rib(
TypeNS,
ConstantItemRibKind(is_repeat == IsRepeatExpr::Yes || is_trivial),
|this| {
this.with_label_rib(ConstantItemRibKind(is_trivial), f);
},
)
});
}
......@@ -1272,9 +1301,17 @@ fn resolve_implementation(
//
// Type parameters can already be used and as associated consts are
// not used as part of the type system, this is far less surprising.
this.with_constant_rib(true, |this| {
visit::walk_assoc_item(this, item, AssocCtxt::Impl)
});
this.with_constant_rib(
IsRepeatExpr::No,
true,
|this| {
visit::walk_assoc_item(
this,
item,
AssocCtxt::Impl,
)
},
);
}
AssocItemKind::Fn(_, _, generics, _) => {
// We also need a new scope for the impl item type parameters.
......@@ -2199,6 +2236,17 @@ fn resolve_block(&mut self, block: &'ast Block) {
debug!("(resolving block) leaving block");
}
fn resolve_anon_const(&mut self, constant: &'ast AnonConst, is_repeat: IsRepeatExpr) {
debug!("resolve_anon_const {:?} is_repeat: {:?}", constant, is_repeat);
self.with_constant_rib(
is_repeat,
constant.value.is_potential_trivial_const_param(),
|this| {
visit::walk_anon_const(this, constant);
},
);
}
fn resolve_expr(&mut self, expr: &'ast Expr, parent: Option<&'ast Expr>) {
// First, record candidate traits for this expression if it could
// result in the invocation of a method call.
......@@ -2322,6 +2370,10 @@ fn resolve_expr(&mut self, expr: &'ast Expr, parent: Option<&'ast Expr>) {
ExprKind::Async(..) | ExprKind::Closure(..) => {
self.with_label_rib(ClosureOrAsyncRibKind, |this| visit::walk_expr(this, expr));
}
ExprKind::Repeat(ref elem, ref ct) => {
self.visit_expr(elem);
self.resolve_anon_const(ct, IsRepeatExpr::Yes);
}
_ => {
visit::walk_expr(self, expr);
}
......
......@@ -92,6 +92,7 @@ impl From<$Ty> for $Int {
doc_comment! {
concat!(
"Converts a `", stringify!($Ty), "` into an `", stringify!($Int), "`"),
#[inline]
fn from(nonzero: $Ty) -> Self {
nonzero.0
}
......
......@@ -446,7 +446,7 @@ fn hash<H: Hasher>(&self, h: &mut H) {
/// (`/` or `\`).
///
/// This `enum` is created by iterating over [`Components`], which in turn is
/// created by the [`components`][`Path::components`] method on [`Path`].
/// created by the [`components`](Path::components) method on [`Path`].
///
/// # Examples
///
......@@ -1319,7 +1319,7 @@ pub fn into_os_string(self) -> OsString {
self.inner
}
/// Converts this `PathBuf` into a [boxed][`Box`] [`Path`].
/// Converts this `PathBuf` into a [boxed](Box) [`Path`].
#[stable(feature = "into_boxed_path", since = "1.20.0")]
pub fn into_boxed_path(self) -> Box<Path> {
let rw = Box::into_raw(self.inner.into_boxed_os_str()) as *mut Path;
......@@ -1686,8 +1686,7 @@ pub struct Path {
inner: OsStr,
}
/// An error returned from [`Path::strip_prefix`][`strip_prefix`] if the prefix
/// was not found.
/// An error returned from [`Path::strip_prefix`] if the prefix was not found.
///
/// This `struct` is created by the [`strip_prefix`] method on [`Path`].
/// See its documentation for more.
......@@ -2470,7 +2469,7 @@ pub fn is_dir(&self) -> bool {
fs::metadata(self).map(|m| m.is_dir()).unwrap_or(false)
}
/// Converts a [`Box<Path>`][`Box`] into a [`PathBuf`] without copying or
/// Converts a [`Box<Path>`](Box) into a [`PathBuf`] without copying or
/// allocating.
#[stable(feature = "into_boxed_path", since = "1.20.0")]
pub fn into_path_buf(self: Box<Path>) -> PathBuf {
......@@ -2498,7 +2497,7 @@ fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
///
/// A [`Path`] might contain non-Unicode data. This `struct` implements the
/// [`Display`] trait in a way that mitigates that. It is created by the
/// [`display`][`Path::display`] method on [`Path`].
/// [`display`](Path::display) method on [`Path`].
///
/// # Examples
///
......
Subproject commit 451a1e30f2dd137aa04e142414eafb8d05f87f84
Subproject commit 13e1c05420bca86ecc79e4ba5b6d02de9bd53c62
Subproject commit 81f16863014de60b53de401d71ff904d163ee030
Subproject commit 7bc9b7a5e800f79df62947cb7d566fd2fbaf19fe
Subproject commit 6e57e64501f61873ab80cb78a07180a22751a5d6
Subproject commit 69333eddb1de92fd17e272ce4677cc983d3bd71d
Subproject commit 1b78182e71709169dc0f1c3acdc4541b6860e1c4
Subproject commit 10c16caebe475d0d11bec0531b95d7697856c13c
Subproject commit 152475937a8d8a1f508d8eeb57db79139bc803d9
Subproject commit 99eafee0cb14e6ec641bf02a69d7b30f6058349a
......@@ -348,7 +348,7 @@ Using this flag looks like this:
$ rustdoc src/lib.rs -Z unstable-options --enable-per-target-ignores
```
This flag allows you to tag doctests with compiltest style `ignore-foo` filters that prevent
This flag allows you to tag doctests with compiletest style `ignore-foo` filters that prevent
rustdoc from running that test if the target triple string contains foo. For example:
```rust
......
use std::collections::BTreeMap;
use std::collections::{BTreeMap, HashMap};
use std::convert::TryFrom;
use std::ffi::OsStr;
use std::fmt;
......@@ -216,6 +216,9 @@ pub struct RenderOptions {
pub extension_css: Option<PathBuf>,
/// A map of crate names to the URL to use instead of querying the crate's `html_root_url`.
pub extern_html_root_urls: BTreeMap<String, String>,
/// A map of the default settings (values are as for DOM storage API). Keys should lack the
/// `rustdoc-` prefix.
pub default_settings: HashMap<String, String>,
/// If present, suffix added to CSS/JavaScript files when referencing them in generated pages.
pub resource_suffix: String,
/// Whether to run the static CSS/JavaScript through a minifier when outputting them. `true` by
......@@ -374,6 +377,32 @@ fn println_condition(condition: Condition) {
}
};
let default_settings: Vec<Vec<(String, String)>> = vec![
matches
.opt_str("default-theme")
.iter()
.map(|theme| {
vec![
("use-system-theme".to_string(), "false".to_string()),
("theme".to_string(), theme.to_string()),
]
})
.flatten()
.collect(),
matches
.opt_strs("default-setting")
.iter()
.map(|s| {
let mut kv = s.splitn(2, '=');
// never panics because `splitn` always returns at least one element
let k = kv.next().unwrap().to_string();
let v = kv.next().unwrap_or("true").to_string();
(k, v)
})
.collect(),
];
let default_settings = default_settings.into_iter().flatten().collect();
let test_args = matches.opt_strs("test-args");
let test_args: Vec<String> =
test_args.iter().flat_map(|s| s.split_whitespace()).map(|s| s.to_string()).collect();
......@@ -596,6 +625,7 @@ fn println_condition(condition: Condition) {
themes,
extension_css,
extern_html_root_urls,
default_settings,
resource_suffix,
enable_minification,
enable_index_page,
......
use std::collections::HashMap;
use std::path::PathBuf;
use crate::externalfiles::ExternalHtml;
......@@ -10,6 +11,7 @@ pub struct Layout {
pub logo: String,
pub favicon: String,
pub external_html: ExternalHtml,
pub default_settings: HashMap<String, String>,
pub krate: String,
/// The given user css file which allow to customize the generated
/// documentation theme.
......@@ -53,6 +55,7 @@ pub fn render<T: Print, S: Print>(
<link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}rustdoc{suffix}.css\" \
id=\"mainThemeStyle\">\
{style_files}\
<script id=\"default-settings\"{default_settings}></script>\
<script src=\"{static_root_path}storage{suffix}.js\"></script>\
<noscript><link rel=\"stylesheet\" href=\"{static_root_path}noscript{suffix}.css\"></noscript>\
{css_extension}\
......@@ -172,6 +175,11 @@ pub fn render<T: Print, S: Print>(
after_content = layout.external_html.after_content,
sidebar = Buffer::html().to_display(sidebar),
krate = layout.krate,
default_settings = layout
.default_settings
.iter()
.map(|(k, v)| format!(r#" data-{}="{}""#, k.replace('-', "_"), Escape(v)))
.collect::<String>(),
style_files = style_files
.iter()
.filter_map(|t| {
......
......@@ -1228,6 +1228,7 @@ fn init_id_map() -> FxHashMap<String, usize> {
map.insert("render-detail".to_owned(), 1);
map.insert("toggle-all-docs".to_owned(), 1);
map.insert("all-types".to_owned(), 1);
map.insert("default-settings".to_owned(), 1);
// This is the list of IDs used by rustdoc sections.
map.insert("fields".to_owned(), 1);
map.insert("variants".to_owned(), 1);
......
......@@ -392,6 +392,7 @@ fn init(
playground_url,
sort_modules_alphabetically,
themes: style_files,
default_settings,
extension_css,
resource_suffix,
static_root_path,
......@@ -415,6 +416,7 @@ fn init(
logo: String::new(),
favicon: String::new(),
external_html,
default_settings,
krate: krate.name.clone(),
css_file_extension: extension_css,
generate_search_filter,
......
......@@ -89,7 +89,7 @@ function defocusSearchBar() {
"derive",
"traitalias"];
var disableShortcuts = getCurrentValue("rustdoc-disable-shortcuts") === "true";
var disableShortcuts = getSettingValue("disable-shortcuts") === "true";
var search_input = getSearchInput();
var searchTimeout = null;
var toggleAllDocsId = "toggle-all-docs";
......@@ -1580,7 +1580,7 @@ function defocusSearchBar() {
function showResults(results) {
var search = getSearchElement();
if (results.others.length === 1
&& getCurrentValue("rustdoc-go-to-only-result") === "true"
&& getSettingValue("go-to-only-result") === "true"
// By default, the search DOM element is "empty" (meaning it has no children not
// text content). Once a search has been run, it won't be empty, even if you press
// ESC or empty the search input (which also "cancels" the search).
......@@ -2296,7 +2296,7 @@ function defocusSearchBar() {
function autoCollapse(pageId, collapse) {
if (collapse) {
toggleAllDocs(pageId, true);
} else if (getCurrentValue("rustdoc-auto-hide-trait-implementations") !== "false") {
} else if (getSettingValue("auto-hide-trait-implementations") !== "false") {
var impl_list = document.getElementById("trait-implementations-list");
if (impl_list !== null) {
......@@ -2370,8 +2370,8 @@ function defocusSearchBar() {
}
var toggle = createSimpleToggle(false);
var hideMethodDocs = getCurrentValue("rustdoc-auto-hide-method-docs") === "true";
var hideImplementors = getCurrentValue("rustdoc-auto-collapse-implementors") !== "false";
var hideMethodDocs = getSettingValue("auto-hide-method-docs") === "true";
var hideImplementors = getSettingValue("auto-collapse-implementors") !== "false";
var pageId = getPageId();
var func = function(e) {
......@@ -2487,7 +2487,7 @@ function defocusSearchBar() {
});
}
}
var showItemDeclarations = getCurrentValue("rustdoc-auto-hide-" + className);
var showItemDeclarations = getSettingValue("auto-hide-" + className);
if (showItemDeclarations === null) {
if (className === "enum" || className === "macro") {
showItemDeclarations = "false";
......@@ -2495,7 +2495,7 @@ function defocusSearchBar() {
showItemDeclarations = "true";
} else {
// In case we found an unknown type, we just use the "parent" value.
showItemDeclarations = getCurrentValue("rustdoc-auto-hide-declarations");
showItemDeclarations = getSettingValue("auto-hide-declarations");
}
}
showItemDeclarations = showItemDeclarations === "false";
......@@ -2569,7 +2569,7 @@ function defocusSearchBar() {
onEachLazy(document.getElementsByClassName("sub-variant"), buildToggleWrapper);
var pageId = getPageId();
autoCollapse(pageId, getCurrentValue("rustdoc-collapse") === "true");
autoCollapse(pageId, getSettingValue("collapse") === "true");
if (pageId !== null) {
expandSection(pageId);
......@@ -2592,7 +2592,7 @@ function defocusSearchBar() {
(function() {
// To avoid checking on "rustdoc-item-attributes" value on every loop...
var itemAttributesFunc = function() {};
if (getCurrentValue("rustdoc-auto-hide-attributes") !== "false") {
if (getSettingValue("auto-hide-attributes") !== "false") {
itemAttributesFunc = function(x) {
collapseDocs(x.previousSibling.childNodes[0], "toggle");
};
......@@ -2611,7 +2611,7 @@ function defocusSearchBar() {
(function() {
// To avoid checking on "rustdoc-line-numbers" value on every loop...
var lineNumbersFunc = function() {};
if (getCurrentValue("rustdoc-line-numbers") === "true") {
if (getSettingValue("line-numbers") === "true") {
lineNumbersFunc = function(x) {
var count = x.textContent.split("\n").length;
var elems = [];
......@@ -2768,7 +2768,7 @@ function defocusSearchBar() {
}
return 0;
});
var savedCrate = getCurrentValue("rustdoc-saved-filter-crate");
var savedCrate = getSettingValue("saved-filter-crate");
for (var i = 0; i < crates_text.length; ++i) {
var option = document.createElement("option");
option.value = crates_text[i];
......
......@@ -14,10 +14,6 @@
}
}
function getSettingValue(settingName) {
return getCurrentValue("rustdoc-" + settingName);
}
function setEvents() {
var elems = {
toggles: document.getElementsByClassName("slider"),
......
// From rust:
/* global resourcesSuffix */
/* global resourcesSuffix, getSettingValue */
var darkThemes = ["dark", "ayu"];
var currentTheme = document.getElementById("themeStyle");
var mainTheme = document.getElementById("mainThemeStyle");
var localStoredTheme = getCurrentValue("rustdoc-theme");
var settingsDataset = (function () {
var settingsElement = document.getElementById("default-settings");
if (settingsElement === null) {
return null;
}
var dataset = settingsElement.dataset;
if (dataset === undefined) {
return null;
}
return dataset;
})();
function getSettingValue(settingName) {
var current = getCurrentValue('rustdoc-' + settingName);
if (current !== null) {
return current;
}
if (settingsDataset !== null) {
var def = settingsDataset[settingName.replace(/-/g,'_')];
if (def !== undefined) {
return def;
}
}
return null;
}
var localStoredTheme = getSettingValue("theme");
var savedHref = [];
......@@ -156,9 +183,9 @@ var updateSystemTheme = (function() {
function handlePreferenceChange(mql) {
// maybe the user has disabled the setting in the meantime!
if (getCurrentValue("rustdoc-use-system-theme") !== "false") {
var lightTheme = getCurrentValue("rustdoc-preferred-light-theme") || "light";
var darkTheme = getCurrentValue("rustdoc-preferred-dark-theme") || "dark";
if (getSettingValue("use-system-theme") !== "false") {
var lightTheme = getSettingValue("preferred-light-theme") || "light";
var darkTheme = getSettingValue("preferred-dark-theme") || "dark";
if (mql.matches) {
// prefers a dark theme
......@@ -181,11 +208,11 @@ var updateSystemTheme = (function() {
};
})();
if (getCurrentValue("rustdoc-use-system-theme") !== "false" && window.matchMedia) {
if (getSettingValue("use-system-theme") !== "false" && window.matchMedia) {
// update the preferred dark theme if the user is already using a dark theme
// See https://github.com/rust-lang/rust/pull/77809#issuecomment-707875732
if (getCurrentValue("rustdoc-use-system-theme") === null
&& getCurrentValue("rustdoc-preferred-dark-theme") === null
if (getSettingValue("use-system-theme") === null
&& getSettingValue("preferred-dark-theme") === null
&& darkThemes.indexOf(localStoredTheme) >= 0) {
updateLocalStorage("rustdoc-preferred-dark-theme", localStoredTheme);
}
......@@ -196,7 +223,7 @@ if (getCurrentValue("rustdoc-use-system-theme") !== "false" && window.matchMedia
switchTheme(
currentTheme,
mainTheme,
getCurrentValue("rustdoc-theme") || "light",
getSettingValue("theme") || "light",
false
);
}
......@@ -269,6 +269,26 @@ fn opts() -> Vec<RustcOptGroup> {
"sort modules by where they appear in the program, rather than alphabetically",
)
}),
unstable("default-theme", |o| {
o.optopt(
"",
"default-theme",
"Set the default theme. THEME should be the theme name, generally lowercase. \
If an unknown default theme is specified, the builtin default is used. \
The set of themes, and the rustdoc built-in default is not stable.",
"THEME",
)
}),
unstable("default-setting", |o| {
o.optmulti(
"",
"default-setting",
"Default value for a rustdoc setting (used when \"rustdoc-SETTING\" is absent \
from web browser Local Storage). If VALUE is not supplied, \"true\" is used. \
Supported SETTINGs and VALUEs are not documented and not stable.",
"SETTING[=VALUE]",
)
}),
stable("theme", |o| {
o.optmulti(
"",
......
// run-pass
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
#![cfg_attr(min, feature(min_const_generics))]
trait Foo<const N: usize> {
fn myfun(&self) -> usize;
}
trait Bar<const N: usize> : Foo<N> {}
trait Baz: Foo<3> {}
struct FooType<const N: usize>;
struct BarType<const N: usize>;
struct BazType;
impl<const N: usize> Foo<N> for FooType<N> {
fn myfun(&self) -> usize { N }
}
impl<const N: usize> Foo<N> for BarType<N> {
fn myfun(&self) -> usize { N + 1 }
}
impl<const N: usize> Bar<N> for BarType<N> {}
impl Foo<3> for BazType {
fn myfun(&self) -> usize { 999 }
}
impl Baz for BazType {}
trait Foz {}
trait Boz: Foo<3> + Foz {}
trait Bok<const N: usize>: Foo<N> + Foz {}
struct FozType;
struct BozType;
struct BokType<const N: usize>;
impl Foz for FozType {}
impl Foz for BozType {}
impl Foo<3> for BozType {
fn myfun(&self) -> usize { 9999 }
}
impl Boz for BozType {}
impl<const N: usize> Foz for BokType<N> {}
impl<const N: usize> Foo<N> for BokType<N> {
fn myfun(&self) -> usize { N + 2 }
}
impl<const N: usize> Bok<N> for BokType<N> {}
fn a<const N: usize>(x: &dyn Foo<N>) -> usize { x.myfun() }
fn b(x: &dyn Foo<3>) -> usize { x.myfun() }
fn c<T: Bok<N>, const N: usize>(x: T) -> usize { a::<N>(&x) }
fn d<T: ?Sized + Foo<3>>(x: &T) -> usize { x.myfun() }
fn e(x: &dyn Bar<3>) -> usize { d(x) }
fn main() {
let foo = FooType::<3> {};
assert!(a(&foo) == 3);
assert!(b(&foo) == 3);
assert!(d(&foo) == 3);
let bar = BarType::<3> {};
assert!(a(&bar) == 4);
assert!(b(&bar) == 4);
assert!(d(&bar) == 4);
assert!(e(&bar) == 4);
let baz = BazType {};
assert!(a(&baz) == 999);
assert!(b(&baz) == 999);
assert!(d(&baz) == 999);
let boz = BozType {};
assert!(a(&boz) == 9999);
assert!(b(&boz) == 9999);
assert!(d(&boz) == 9999);
let bok = BokType::<3> {};
assert!(a(&bok) == 5);
assert!(b(&bok) == 5);
assert!(d(&bok) == 5);
assert!(c(BokType::<3> {}) == 5);
}
error: generic `Self` types are currently not permitted in anonymous constants
error[E0308]: mismatched types
--> $DIR/issue-62504.rs:19:21
|
LL | ArrayHolder([0; Self::SIZE])
| ^^^^^^^^^^^^^^^ expected `X`, found `Self::SIZE`
|
= note: expected array `[u32; X]`
found array `[u32; _]`
error: constant expression depends on a generic parameter
--> $DIR/issue-62504.rs:19:25
|
LL | ArrayHolder([0; Self::SIZE])
| ^^^^^^^^^^
|
note: not a concrete type
--> $DIR/issue-62504.rs:17:22
|
LL | impl<const X: usize> ArrayHolder<X> {
| ^^^^^^^^^^^^^^
= note: this may fail depending on what value the parameter takes
error: aborting due to previous error
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0308`.
......@@ -17,8 +17,8 @@ impl<const X: usize> HasSize for ArrayHolder<X> {
impl<const X: usize> ArrayHolder<X> {
pub const fn new() -> Self {
ArrayHolder([0; Self::SIZE])
//[full]~^ ERROR constant expression depends on a generic parameter
//[min]~^^ ERROR generic `Self` types are currently
//~^ ERROR constant expression depends on a generic parameter
//[min]~| ERROR mismatched types
}
}
......
error: generic parameters may not be used in const operations
--> $DIR/issue-67739.rs:12:30
error: constant expression depends on a generic parameter
--> $DIR/issue-67739.rs:12:15
|
LL | [0u8; mem::size_of::<Self::Associated>()];
| ^^^^^^^^^^^^^^^^ cannot perform const operation using `Self`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: type parameters may not be used in const expressions
= note: this may fail depending on what value the parameter takes
error: aborting due to previous error
......@@ -10,8 +10,7 @@ pub trait Trait {
fn associated_size(&self) -> usize {
[0u8; mem::size_of::<Self::Associated>()];
//[full]~^ ERROR constant expression depends on a generic parameter
//[min]~^^ ERROR generic parameters may not be used in const operations
//~^ ERROR constant expression depends on a generic parameter
0
}
}
......
#![feature(min_const_generics)]
use std::mem::size_of;
fn test<const N: usize>() {}
fn ok<const M: usize>() -> [u8; M] {
......@@ -22,6 +24,24 @@ fn break3<const N: usize>() {
//~^ ERROR generic parameters may not be used in const operations
}
struct BreakTy0<T>(T, [u8; { size_of::<*mut T>() }]);
//~^ ERROR generic parameters may not be used in const operations
struct BreakTy1<T>(T, [u8; { { size_of::<*mut T>() } }]);
//~^ ERROR generic parameters may not be used in const operations
fn break_ty2<T>() {
let _: [u8; size_of::<*mut T>() + 1];
//~^ ERROR generic parameters may not be used in const operations
}
fn break_ty3<T>() {
let _ = [0; size_of::<*mut T>() + 1];
//~^ WARN cannot use constants which depend on generic parameters in types
//~| WARN this was previously accepted by the compiler but is being phased out
}
trait Foo {
const ASSOC: usize;
}
......
error: generic parameters may not be used in const operations
--> $DIR/complex-expression.rs:9:38
--> $DIR/complex-expression.rs:11:38
|
LL | struct Break0<const N: usize>([u8; { N + 1 }]);
| ^ cannot perform const operation using `N`
......@@ -7,7 +7,7 @@ LL | struct Break0<const N: usize>([u8; { N + 1 }]);
= help: const parameters may only be used as standalone arguments, i.e. `N`
error: generic parameters may not be used in const operations
--> $DIR/complex-expression.rs:12:40
--> $DIR/complex-expression.rs:14:40
|
LL | struct Break1<const N: usize>([u8; { { N } }]);
| ^ cannot perform const operation using `N`
......@@ -15,7 +15,7 @@ LL | struct Break1<const N: usize>([u8; { { N } }]);
= help: const parameters may only be used as standalone arguments, i.e. `N`
error: generic parameters may not be used in const operations
--> $DIR/complex-expression.rs:16:17
--> $DIR/complex-expression.rs:18:17
|
LL | let _: [u8; N + 1];
| ^ cannot perform const operation using `N`
......@@ -23,12 +23,46 @@ LL | let _: [u8; N + 1];
= help: const parameters may only be used as standalone arguments, i.e. `N`
error: generic parameters may not be used in const operations
--> $DIR/complex-expression.rs:21:17
--> $DIR/complex-expression.rs:23:17
|
LL | let _ = [0; N + 1];
| ^ cannot perform const operation using `N`
|
= help: const parameters may only be used as standalone arguments, i.e. `N`
error: aborting due to 4 previous errors
error: generic parameters may not be used in const operations
--> $DIR/complex-expression.rs:27:45
|
LL | struct BreakTy0<T>(T, [u8; { size_of::<*mut T>() }]);
| ^ cannot perform const operation using `T`
|
= note: type parameters may not be used in const expressions
error: generic parameters may not be used in const operations
--> $DIR/complex-expression.rs:30:47
|
LL | struct BreakTy1<T>(T, [u8; { { size_of::<*mut T>() } }]);
| ^ cannot perform const operation using `T`
|
= note: type parameters may not be used in const expressions
error: generic parameters may not be used in const operations
--> $DIR/complex-expression.rs:34:32
|
LL | let _: [u8; size_of::<*mut T>() + 1];
| ^ cannot perform const operation using `T`
|
= note: type parameters may not be used in const expressions
warning: cannot use constants which depend on generic parameters in types
--> $DIR/complex-expression.rs:39:17
|
LL | let _ = [0; size_of::<*mut T>() + 1];
| ^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(const_evaluatable_unchecked)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #76200 <https://github.com/rust-lang/rust/issues/76200>
error: aborting due to 7 previous errors; 1 warning emitted
// check-pass
#![feature(min_const_generics)]
#![allow(dead_code)]
fn foo<T>() {
[0; std::mem::size_of::<*mut T>()];
//~^ WARN cannot use constants which depend on generic parameters in types
//~| WARN this was previously accepted by the compiler but is being phased out
}
struct Foo<T>(T);
impl<T> Foo<T> {
const ASSOC: usize = 4;
fn test() {
let _ = [0; Self::ASSOC];
//~^ WARN cannot use constants which depend on generic parameters in types
//~| WARN this was previously accepted by the compiler but is being phased out
}
}
struct Bar<const N: usize>;
impl<const N: usize> Bar<N> {
const ASSOC: usize = 4;
fn test() {
let _ = [0; Self::ASSOC];
//~^ WARN cannot use constants which depend on generic parameters in types
//~| WARN this was previously accepted by the compiler but is being phased out
}
}
fn main() {}
warning: cannot use constants which depend on generic parameters in types
--> $DIR/const-evaluatable-unchecked.rs:6:9
|
LL | [0; std::mem::size_of::<*mut T>()];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(const_evaluatable_unchecked)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #76200 <https://github.com/rust-lang/rust/issues/76200>
warning: cannot use constants which depend on generic parameters in types
--> $DIR/const-evaluatable-unchecked.rs:17:21
|
LL | let _ = [0; Self::ASSOC];
| ^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #76200 <https://github.com/rust-lang/rust/issues/76200>
warning: cannot use constants which depend on generic parameters in types
--> $DIR/const-evaluatable-unchecked.rs:29:21
|
LL | let _ = [0; Self::ASSOC];
| ^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #76200 <https://github.com/rust-lang/rust/issues/76200>
warning: 3 warnings emitted
......@@ -4,7 +4,7 @@ error: comparison operators cannot be chained
LL | foo<BAR + 3>();
| ^ ^
|
help: use `::<...>` instead of `<...>` to specify type arguments
help: use `::<...>` instead of `<...>` to specify type or const arguments
|
LL | foo::<BAR + 3>();
| ^^
......@@ -15,7 +15,7 @@ error: comparison operators cannot be chained
LL | foo<BAR + BAR>();
| ^ ^
|
help: use `::<...>` instead of `<...>` to specify type arguments
help: use `::<...>` instead of `<...>` to specify type or const arguments
|
LL | foo::<BAR + BAR>();
| ^^
......@@ -26,7 +26,7 @@ error: comparison operators cannot be chained
LL | foo<3 + 3>();
| ^ ^
|
help: use `::<...>` instead of `<...>` to specify type arguments
help: use `::<...>` instead of `<...>` to specify type or const arguments
|
LL | foo::<3 + 3>();
| ^^
......@@ -37,7 +37,7 @@ error: comparison operators cannot be chained
LL | foo<BAR - 3>();
| ^ ^
|
help: use `::<...>` instead of `<...>` to specify type arguments
help: use `::<...>` instead of `<...>` to specify type or const arguments
|
LL | foo::<BAR - 3>();
| ^^
......@@ -48,7 +48,7 @@ error: comparison operators cannot be chained
LL | foo<BAR - BAR>();
| ^ ^
|
help: use `::<...>` instead of `<...>` to specify type arguments
help: use `::<...>` instead of `<...>` to specify type or const arguments
|
LL | foo::<BAR - BAR>();
| ^^
......@@ -59,7 +59,7 @@ error: comparison operators cannot be chained
LL | foo<100 - BAR>();
| ^ ^
|
help: use `::<...>` instead of `<...>` to specify type arguments
help: use `::<...>` instead of `<...>` to specify type or const arguments
|
LL | foo::<100 - BAR>();
| ^^
......@@ -70,7 +70,7 @@ error: comparison operators cannot be chained
LL | foo<bar<i32>()>();
| ^ ^
|
help: use `::<...>` instead of `<...>` to specify type arguments
help: use `::<...>` instead of `<...>` to specify type or const arguments
|
LL | foo::<bar<i32>()>();
| ^^
......@@ -87,7 +87,7 @@ error: comparison operators cannot be chained
LL | foo<bar::<i32>()>();
| ^ ^
|
help: use `::<...>` instead of `<...>` to specify type arguments
help: use `::<...>` instead of `<...>` to specify type or const arguments
|
LL | foo::<bar::<i32>()>();
| ^^
......@@ -98,7 +98,7 @@ error: comparison operators cannot be chained
LL | foo<bar::<i32>() + BAR>();
| ^ ^
|
help: use `::<...>` instead of `<...>` to specify type arguments
help: use `::<...>` instead of `<...>` to specify type or const arguments
|
LL | foo::<bar::<i32>() + BAR>();
| ^^
......@@ -109,7 +109,7 @@ error: comparison operators cannot be chained
LL | foo<bar::<i32>() - BAR>();
| ^ ^
|
help: use `::<...>` instead of `<...>` to specify type arguments
help: use `::<...>` instead of `<...>` to specify type or const arguments
|
LL | foo::<bar::<i32>() - BAR>();
| ^^
......@@ -120,7 +120,7 @@ error: comparison operators cannot be chained
LL | foo<BAR - bar::<i32>()>();
| ^ ^
|
help: use `::<...>` instead of `<...>` to specify type arguments
help: use `::<...>` instead of `<...>` to specify type or const arguments
|
LL | foo::<BAR - bar::<i32>()>();
| ^^
......@@ -131,7 +131,7 @@ error: comparison operators cannot be chained
LL | foo<BAR - bar::<i32>()>();
| ^ ^
|
help: use `::<...>` instead of `<...>` to specify type arguments
help: use `::<...>` instead of `<...>` to specify type or const arguments
|
LL | foo::<BAR - bar::<i32>()>();
| ^^
......
#![feature(min_const_generics)]
use std::mem::transmute;
fn get_flag<const FlagSet: bool, const ShortName: char>() -> Option<char> {
if FlagSet {
Some(ShortName)
} else {
None
}
}
union CharRaw {
byte: u8,
character: char,
}
union BoolRaw {
byte: u8,
boolean: bool,
}
const char_raw: CharRaw = CharRaw { byte: 0xFF };
const bool_raw: BoolRaw = BoolRaw { byte: 0x42 };
fn main() {
// Test that basic cases don't work
assert!(get_flag::<true, 'c'>().is_some());
assert!(get_flag::<false, 'x'>().is_none());
get_flag::<false, 0xFF>();
//~^ ERROR mismatched types
get_flag::<7, 'c'>();
//~^ ERROR mismatched types
get_flag::<42, 0x5ad>();
//~^ ERROR mismatched types
//~| ERROR mismatched types
get_flag::<false, { unsafe { char_raw.character } }>();
//~^ ERROR it is undefined behavior
get_flag::<{ unsafe { bool_raw.boolean } }, 'z'>();
//~^ ERROR it is undefined behavior
get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>();
//~^ ERROR it is undefined behavior
//~| ERROR it is undefined behavior
}
error[E0308]: mismatched types
--> $DIR/invalid-patterns.rs:29:21
|
LL | get_flag::<false, 0xFF>();
| ^^^^ expected `char`, found `u8`
error[E0308]: mismatched types
--> $DIR/invalid-patterns.rs:31:14
|
LL | get_flag::<7, 'c'>();
| ^ expected `bool`, found integer
error[E0308]: mismatched types
--> $DIR/invalid-patterns.rs:33:14
|
LL | get_flag::<42, 0x5ad>();
| ^^ expected `bool`, found integer
error[E0308]: mismatched types
--> $DIR/invalid-patterns.rs:33:18
|
LL | get_flag::<42, 0x5ad>();
| ^^^^^ expected `char`, found `u8`
error[E0080]: it is undefined behavior to use this value
--> $DIR/invalid-patterns.rs:38:21
|
LL | get_flag::<false, { unsafe { char_raw.character } }>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
error[E0080]: it is undefined behavior to use this value
--> $DIR/invalid-patterns.rs:40:14
|
LL | get_flag::<{ unsafe { bool_raw.boolean } }, 'z'>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x42, but expected a boolean
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
error[E0080]: it is undefined behavior to use this value
--> $DIR/invalid-patterns.rs:42:14
|
LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x42, but expected a boolean
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
error[E0080]: it is undefined behavior to use this value
--> $DIR/invalid-patterns.rs:42:47
|
LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
error: aborting due to 8 previous errors
Some errors have detailed explanations: E0080, E0308.
For more information about an error, try `rustc --explain E0080`.
......@@ -4,7 +4,7 @@ error: comparison operators cannot be chained
LL | (0..13).collect<Vec<i32>>();
| ^ ^
|
help: use `::<...>` instead of `<...>` to specify type arguments
help: use `::<...>` instead of `<...>` to specify type or const arguments
|
LL | (0..13).collect::<Vec<i32>>();
| ^^
......@@ -15,7 +15,7 @@ error: comparison operators cannot be chained
LL | Vec<i32>::new();
| ^ ^
|
help: use `::<...>` instead of `<...>` to specify type arguments
help: use `::<...>` instead of `<...>` to specify type or const arguments
|
LL | Vec::<i32>::new();
| ^^
......@@ -26,7 +26,7 @@ error: comparison operators cannot be chained
LL | (0..13).collect<Vec<i32>();
| ^ ^
|
help: use `::<...>` instead of `<...>` to specify type arguments
help: use `::<...>` instead of `<...>` to specify type or const arguments
|
LL | (0..13).collect::<Vec<i32>();
| ^^
......@@ -37,7 +37,7 @@ error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, or an operator, found `,`
LL | let x = std::collections::HashMap<i128, i128>::new();
| ^ expected one of 7 possible tokens
|
help: use `::<...>` instead of `<...>` to specify type arguments
help: use `::<...>` instead of `<...>` to specify type or const arguments
|
LL | let x = std::collections::HashMap::<i128, i128>::new();
| ^^
......@@ -48,7 +48,7 @@ error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found
LL | std::collections::HashMap<i128, i128>::new()
| ^ expected one of 8 possible tokens
|
help: use `::<...>` instead of `<...>` to specify type arguments
help: use `::<...>` instead of `<...>` to specify type or const arguments
|
LL | std::collections::HashMap::<i128, i128>::new()
| ^^
......@@ -59,7 +59,7 @@ error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found
LL | std::collections::HashMap<i128, i128>::new();
| ^ expected one of 8 possible tokens
|
help: use `::<...>` instead of `<...>` to specify type arguments
help: use `::<...>` instead of `<...>` to specify type or const arguments
|
LL | std::collections::HashMap::<i128, i128>::new();
| ^^
......@@ -70,7 +70,7 @@ error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found
LL | std::collections::HashMap<i128, i128>::new(1, 2);
| ^ expected one of 8 possible tokens
|
help: use `::<...>` instead of `<...>` to specify type arguments
help: use `::<...>` instead of `<...>` to specify type or const arguments
|
LL | std::collections::HashMap::<i128, i128>::new(1, 2);
| ^^
......
......@@ -12,15 +12,15 @@ fn main() {
f<X>();
//~^ ERROR comparison operators cannot be chained
//~| HELP use `::<...>` instead of `<...>` to specify type arguments
//~| HELP use `::<...>` instead of `<...>` to specify type or const arguments
f<Result<Option<X>, Option<Option<X>>>(1, 2);
//~^ ERROR comparison operators cannot be chained
//~| HELP use `::<...>` instead of `<...>` to specify type arguments
//~| HELP use `::<...>` instead of `<...>` to specify type or const arguments
use std::convert::identity;
let _ = identity<u8>;
//~^ ERROR comparison operators cannot be chained
//~| HELP use `::<...>` instead of `<...>` to specify type arguments
//~| HELP use `::<...>` instead of `<...>` to specify type or const arguments
//~| HELP or use `(...)` if you meant to specify fn arguments
}
......@@ -26,7 +26,7 @@ error: comparison operators cannot be chained
LL | f<X>();
| ^ ^
|
help: use `::<...>` instead of `<...>` to specify type arguments
help: use `::<...>` instead of `<...>` to specify type or const arguments
|
LL | f::<X>();
| ^^
......@@ -37,7 +37,7 @@ error: comparison operators cannot be chained
LL | f<Result<Option<X>, Option<Option<X>>>(1, 2);
| ^ ^
|
help: use `::<...>` instead of `<...>` to specify type arguments
help: use `::<...>` instead of `<...>` to specify type or const arguments
|
LL | f::<Result<Option<X>, Option<Option<X>>>(1, 2);
| ^^
......@@ -48,7 +48,7 @@ error: comparison operators cannot be chained
LL | let _ = identity<u8>;
| ^ ^
|
= help: use `::<...>` instead of `<...>` to specify type arguments
= help: use `::<...>` instead of `<...>` to specify type or const arguments
= help: or use `(...)` if you meant to specify fn arguments
error: aborting due to 5 previous errors
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册