Skip to content
Merged
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
9625ed8
Move settings into full JS
GuillaumeGomez Jan 19, 2022
e7d7d75
Add GUI test for settings menu
GuillaumeGomez Jan 19, 2022
2f074de
Extend settings test to ensure settings text is as expected
GuillaumeGomez Apr 29, 2022
336bb0a
Rename run_lto_pass_manager to optimize_fat and remove thin parameter
bjorn3 Apr 30, 2022
ee94ff2
Let LtoModuleCodegen::optimize take self by value
bjorn3 Apr 30, 2022
fab7230
Remove config parameter of optimize_fat and avoid interior mutability…
bjorn3 Apr 30, 2022
78c65a5
Merge new_metadata into codegen_allocator
bjorn3 Apr 30, 2022
685f66b
Use source callsite in check_argument_types suggestion
Badel2 Apr 30, 2022
b37fb23
Update `RValue::Discriminant` documentation
tmiasko May 1, 2022
73688e4
* Add documentation for settings page rendering functions.
GuillaumeGomez May 1, 2022
18b12fa
Add a regression test for #92305
JohnTitor May 1, 2022
6c7f4de
Fix invalid keyword order for function declarations
ken-matsui May 2, 2022
0349f8b
Use a yes/no enum instead of a bool.
oli-obk May 2, 2022
7790b6e
Mitigate impact of subtle invalid call suggestion logic
estebank May 2, 2022
27d7615
Rollup merge of #93097 - GuillaumeGomez:settings-js, r=jsha
JohnTitor May 3, 2022
329a73d
Rollup merge of #96587 - bjorn3:refactor_backend_write, r=michaelwoer…
JohnTitor May 3, 2022
a587036
Rollup merge of #96589 - Badel2:source-callsite, r=michaelwoerister
JohnTitor May 3, 2022
61c687a
Rollup merge of #96599 - tmiasko:discriminant-docs, r=estebank
JohnTitor May 3, 2022
492d403
Rollup merge of #96614 - JohnTitor:test-92305, r=oli-obk
JohnTitor May 3, 2022
0340703
Rollup merge of #96629 - ken-matsui:fix-invalid-keyword-order-for-fun…
JohnTitor May 3, 2022
1e6b880
Rollup merge of #96641 - oli-obk:bool_args, r=wesleywiser
JohnTitor May 3, 2022
279d801
Rollup merge of #96646 - estebank:issue-96638, r=jackh726
JohnTitor May 3, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 12 additions & 14 deletions compiler/rustc_codegen_gcc/src/lib.rs
Original file line number Diff line number Diff line change
@@ -139,14 +139,12 @@ impl CodegenBackend for GccCodegenBackend {
}

impl ExtraBackendMethods for GccCodegenBackend {
fn new_metadata<'tcx>(&self, _tcx: TyCtxt<'tcx>, _mod_name: &str) -> Self::Module {
GccContext {
fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, module_name: &str, kind: AllocatorKind, has_alloc_error_handler: bool) -> Self::Module {
let mut mods = GccContext {
context: Context::default(),
}
}

fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, mods: &mut Self::Module, module_name: &str, kind: AllocatorKind, has_alloc_error_handler: bool) {
unsafe { allocator::codegen(tcx, mods, module_name, kind, has_alloc_error_handler) }
};
unsafe { allocator::codegen(tcx, &mut mods, module_name, kind, has_alloc_error_handler); }
mods
}

fn compile_codegen_unit<'tcx>(&self, tcx: TyCtxt<'tcx>, cgu_name: Symbol) -> (ModuleCodegen<Self::Module>, u64) {
@@ -213,7 +211,7 @@ impl WriteBackendMethods for GccCodegenBackend {
unimplemented!();
}
};
Ok(LtoModuleCodegen::Fat { module: Some(module), _serialized_bitcode: vec![] })
Ok(LtoModuleCodegen::Fat { module, _serialized_bitcode: vec![] })
}

fn run_thin_lto(_cgcx: &CodegenContext<Self>, _modules: Vec<(String, Self::ThinBuffer)>, _cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>) -> Result<(Vec<LtoModuleCodegen<Self>>, Vec<WorkProduct>), FatalError> {
@@ -229,7 +227,12 @@ impl WriteBackendMethods for GccCodegenBackend {
Ok(())
}

unsafe fn optimize_thin(_cgcx: &CodegenContext<Self>, _thin: &mut ThinModule<Self>) -> Result<ModuleCodegen<Self::Module>, FatalError> {
fn optimize_fat(_cgcx: &CodegenContext<Self>, _module: &mut ModuleCodegen<Self::Module>) -> Result<(), FatalError> {
// TODO(antoyo)
Ok(())
}

unsafe fn optimize_thin(_cgcx: &CodegenContext<Self>, _thin: ThinModule<Self>) -> Result<ModuleCodegen<Self::Module>, FatalError> {
unimplemented!();
}

@@ -245,11 +248,6 @@ impl WriteBackendMethods for GccCodegenBackend {
unimplemented!();
}

fn run_lto_pass_manager(_cgcx: &CodegenContext<Self>, _module: &ModuleCodegen<Self::Module>, _config: &ModuleConfig, _thin: bool) -> Result<(), FatalError> {
// TODO(antoyo)
Ok(())
}

fn run_link(cgcx: &CodegenContext<Self>, diag_handler: &Handler, modules: Vec<ModuleCodegen<Self::Module>>) -> Result<ModuleCodegen<Self::Module>, FatalError> {
back::write::link(cgcx, diag_handler, modules)
}
17 changes: 7 additions & 10 deletions compiler/rustc_codegen_llvm/src/back/lto.rs
Original file line number Diff line number Diff line change
@@ -6,9 +6,7 @@ use crate::llvm::{self, build_string, False, True};
use crate::{llvm_util, LlvmCodegenBackend, ModuleLlvm};
use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule, ThinShared};
use rustc_codegen_ssa::back::symbol_export;
use rustc_codegen_ssa::back::write::{
CodegenContext, FatLTOInput, ModuleConfig, TargetMachineFactoryConfig,
};
use rustc_codegen_ssa::back::write::{CodegenContext, FatLTOInput, TargetMachineFactoryConfig};
use rustc_codegen_ssa::traits::*;
use rustc_codegen_ssa::{looks_like_rust_object_file, ModuleCodegen, ModuleKind};
use rustc_data_structures::fx::FxHashMap;
@@ -353,7 +351,7 @@ fn fat_lto(
}
}

Ok(LtoModuleCodegen::Fat { module: Some(module), _serialized_bitcode: serialized_bitcode })
Ok(LtoModuleCodegen::Fat { module, _serialized_bitcode: serialized_bitcode })
}

crate struct Linker<'a>(&'a mut llvm::Linker<'a>);
@@ -578,11 +576,11 @@ fn thin_lto(
pub(crate) fn run_pass_manager(
cgcx: &CodegenContext<LlvmCodegenBackend>,
diag_handler: &Handler,
module: &ModuleCodegen<ModuleLlvm>,
config: &ModuleConfig,
module: &mut ModuleCodegen<ModuleLlvm>,
thin: bool,
) -> Result<(), FatalError> {
let _timer = cgcx.prof.extra_verbose_generic_activity("LLVM_lto_optimize", &*module.name);
let config = cgcx.config(module.kind);

// Now we have one massive module inside of llmod. Time to run the
// LTO-specific optimization passes that LLVM provides.
@@ -726,7 +724,7 @@ impl Drop for ThinBuffer {
}

pub unsafe fn optimize_thin_module(
thin_module: &mut ThinModule<LlvmCodegenBackend>,
thin_module: ThinModule<LlvmCodegenBackend>,
cgcx: &CodegenContext<LlvmCodegenBackend>,
) -> Result<ModuleCodegen<ModuleLlvm>, FatalError> {
let diag_handler = cgcx.create_diag_handler();
@@ -743,7 +741,7 @@ pub unsafe fn optimize_thin_module(
// that LLVM Context and Module.
let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names);
let llmod_raw = parse_module(llcx, module_name, thin_module.data(), &diag_handler)? as *const _;
let module = ModuleCodegen {
let mut module = ModuleCodegen {
module_llvm: ModuleLlvm { llmod_raw, llcx, tm },
name: thin_module.name().to_string(),
kind: ModuleKind::Regular,
@@ -859,8 +857,7 @@ pub unsafe fn optimize_thin_module(
// little differently.
{
info!("running thin lto passes over {}", module.name);
let config = cgcx.config(module.kind);
run_pass_manager(cgcx, &diag_handler, &module, config, true)?;
run_pass_manager(cgcx, &diag_handler, &mut module, true)?;
save_temp_bitcode(cgcx, &module, "thin-lto-after-pm");
}
}
31 changes: 14 additions & 17 deletions compiler/rustc_codegen_llvm/src/lib.rs
Original file line number Diff line number Diff line change
@@ -104,19 +104,18 @@ impl Drop for TimeTraceProfiler {
}

impl ExtraBackendMethods for LlvmCodegenBackend {
fn new_metadata(&self, tcx: TyCtxt<'_>, mod_name: &str) -> ModuleLlvm {
ModuleLlvm::new_metadata(tcx, mod_name)
}

fn codegen_allocator<'tcx>(
&self,
tcx: TyCtxt<'tcx>,
module_llvm: &mut ModuleLlvm,
module_name: &str,
kind: AllocatorKind,
has_alloc_error_handler: bool,
) {
unsafe { allocator::codegen(tcx, module_llvm, module_name, kind, has_alloc_error_handler) }
) -> ModuleLlvm {
let mut module_llvm = ModuleLlvm::new_metadata(tcx, module_name);
unsafe {
allocator::codegen(tcx, &mut module_llvm, module_name, kind, has_alloc_error_handler);
}
module_llvm
}
fn compile_codegen_unit(
&self,
@@ -210,9 +209,16 @@ impl WriteBackendMethods for LlvmCodegenBackend {
) -> Result<(), FatalError> {
back::write::optimize(cgcx, diag_handler, module, config)
}
fn optimize_fat(
cgcx: &CodegenContext<Self>,
module: &mut ModuleCodegen<Self::Module>,
) -> Result<(), FatalError> {
let diag_handler = cgcx.create_diag_handler();
back::lto::run_pass_manager(cgcx, &diag_handler, module, false)
}
unsafe fn optimize_thin(
cgcx: &CodegenContext<Self>,
thin: &mut ThinModule<Self>,
thin: ThinModule<Self>,
) -> Result<ModuleCodegen<Self::Module>, FatalError> {
back::lto::optimize_thin_module(thin, cgcx)
}
@@ -230,15 +236,6 @@ impl WriteBackendMethods for LlvmCodegenBackend {
fn serialize_module(module: ModuleCodegen<Self::Module>) -> (String, Self::ModuleBuffer) {
(module.name, back::lto::ModuleBuffer::new(module.module_llvm.llmod()))
}
fn run_lto_pass_manager(
cgcx: &CodegenContext<Self>,
module: &ModuleCodegen<Self::Module>,
config: &ModuleConfig,
thin: bool,
) -> Result<(), FatalError> {
let diag_handler = cgcx.create_diag_handler();
back::lto::run_pass_manager(cgcx, &diag_handler, module, config, thin)
}
}

unsafe impl Send for LlvmCodegenBackend {} // Llvm is on a per-thread basis
16 changes: 6 additions & 10 deletions compiler/rustc_codegen_ssa/src/back/lto.rs
Original file line number Diff line number Diff line change
@@ -42,7 +42,7 @@ pub struct ThinShared<B: WriteBackendMethods> {

pub enum LtoModuleCodegen<B: WriteBackendMethods> {
Fat {
module: Option<ModuleCodegen<B::Module>>,
module: ModuleCodegen<B::Module>,
_serialized_bitcode: Vec<SerializedModule<B::ModuleBuffer>>,
},

@@ -64,19 +64,15 @@ impl<B: WriteBackendMethods> LtoModuleCodegen<B> {
/// It's intended that the module returned is immediately code generated and
/// dropped, and then this LTO module is dropped.
pub unsafe fn optimize(
&mut self,
self,
cgcx: &CodegenContext<B>,
) -> Result<ModuleCodegen<B::Module>, FatalError> {
match *self {
LtoModuleCodegen::Fat { ref mut module, .. } => {
let module = module.take().unwrap();
{
let config = cgcx.config(module.kind);
B::run_lto_pass_manager(cgcx, &module, config, false)?;
}
match self {
LtoModuleCodegen::Fat { mut module, .. } => {
B::optimize_fat(cgcx, &mut module)?;
Ok(module)
}
LtoModuleCodegen::Thin(ref mut thin) => B::optimize_thin(cgcx, thin),
LtoModuleCodegen::Thin(thin) => B::optimize_thin(cgcx, thin),
}
}

2 changes: 1 addition & 1 deletion compiler/rustc_codegen_ssa/src/back/write.rs
Original file line number Diff line number Diff line change
@@ -889,7 +889,7 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>(

fn execute_lto_work_item<B: ExtraBackendMethods>(
cgcx: &CodegenContext<B>,
mut module: lto::LtoModuleCodegen<B>,
module: lto::LtoModuleCodegen<B>,
module_config: &ModuleConfig,
) -> Result<WorkItemResult<B>, FatalError> {
let module = unsafe { module.optimize(cgcx)? };
11 changes: 2 additions & 9 deletions compiler/rustc_codegen_ssa/src/base.rs
Original file line number Diff line number Diff line change
@@ -575,15 +575,8 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
} else if let Some(kind) = tcx.allocator_kind(()) {
let llmod_id =
cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("allocator")).to_string();
let mut module_llvm = backend.new_metadata(tcx, &llmod_id);
tcx.sess.time("write_allocator_module", || {
backend.codegen_allocator(
tcx,
&mut module_llvm,
&llmod_id,
kind,
tcx.lang_items().oom().is_some(),
)
let module_llvm = tcx.sess.time("write_allocator_module", || {
backend.codegen_allocator(tcx, &llmod_id, kind, tcx.lang_items().oom().is_some())
});

Some(ModuleCodegen { name: llmod_id, module_llvm, kind: ModuleKind::Allocator })
4 changes: 1 addition & 3 deletions compiler/rustc_codegen_ssa/src/traits/backend.rs
Original file line number Diff line number Diff line change
@@ -114,15 +114,13 @@ pub trait CodegenBackend {
}

pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Send + Sync {
fn new_metadata(&self, sess: TyCtxt<'_>, mod_name: &str) -> Self::Module;
fn codegen_allocator<'tcx>(
&self,
tcx: TyCtxt<'tcx>,
module_llvm: &mut Self::Module,
module_name: &str,
kind: AllocatorKind,
has_alloc_error_handler: bool,
);
) -> Self::Module;
/// This generates the codegen unit and returns it along with
/// a `u64` giving an estimate of the unit's processing cost.
fn compile_codegen_unit(
12 changes: 5 additions & 7 deletions compiler/rustc_codegen_ssa/src/traits/write.rs
Original file line number Diff line number Diff line change
@@ -41,9 +41,13 @@ pub trait WriteBackendMethods: 'static + Sized + Clone {
module: &ModuleCodegen<Self::Module>,
config: &ModuleConfig,
) -> Result<(), FatalError>;
fn optimize_fat(
cgcx: &CodegenContext<Self>,
llmod: &mut ModuleCodegen<Self::Module>,
) -> Result<(), FatalError>;
unsafe fn optimize_thin(
cgcx: &CodegenContext<Self>,
thin: &mut ThinModule<Self>,
thin: ThinModule<Self>,
) -> Result<ModuleCodegen<Self::Module>, FatalError>;
unsafe fn codegen(
cgcx: &CodegenContext<Self>,
@@ -53,12 +57,6 @@ pub trait WriteBackendMethods: 'static + Sized + Clone {
) -> Result<CompiledModule, FatalError>;
fn prepare_thin(module: ModuleCodegen<Self::Module>) -> (String, Self::ThinBuffer);
fn serialize_module(module: ModuleCodegen<Self::Module>) -> (String, Self::ModuleBuffer);
fn run_lto_pass_manager(
cgcx: &CodegenContext<Self>,
llmod: &ModuleCodegen<Self::Module>,
config: &ModuleConfig,
thin: bool,
) -> Result<(), FatalError>;
}

pub trait ThinBufferMethods: Send + Sync {
6 changes: 1 addition & 5 deletions compiler/rustc_middle/src/mir/mod.rs
Original file line number Diff line number Diff line change
@@ -2561,16 +2561,12 @@ pub enum Rvalue<'tcx> {
UnaryOp(UnOp, Operand<'tcx>),

/// Computes the discriminant of the place, returning it as an integer of type
/// [`discriminant_ty`].
/// [`discriminant_ty`]. Returns zero for types without discriminant.
///
/// The validity requirements for the underlying value are undecided for this rvalue, see
/// [#91095]. Note too that the value of the discriminant is not the same thing as the
/// variant index; use [`discriminant_for_variant`] to convert.
///
/// For types defined in the source code as enums, this is well behaved. This is also well
/// formed for other types, but yields no particular value - there is no reason it couldn't be
/// defined to yield eg zero though.
///
/// [`discriminant_ty`]: crate::ty::Ty::discriminant_ty
/// [#91095]: https://github.com/rust-lang/rust/issues/91095
/// [`discriminant_for_variant`]: crate::ty::Ty::discriminant_for_variant
4 changes: 2 additions & 2 deletions compiler/rustc_parse/src/parser/item.rs
Original file line number Diff line number Diff line change
@@ -1020,7 +1020,7 @@ impl<'a> Parser<'a> {
&format!("`{}` must come before `{}`", invalid_qual, current_qual),
format!("{} {}", invalid_qual, current_qual),
Applicability::MachineApplicable,
).note("keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`");
).note("keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`");
}
}
Err(err)
@@ -2086,7 +2086,7 @@ impl<'a> Parser<'a> {
&format!("`{misplaced_qual}` must come before `{current_qual}`"),
format!("{misplaced_qual} {current_qual}"),
Applicability::MachineApplicable,
).note("keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`");
).note("keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`");
}
}
// Recover incorrect visibility order such as `async pub`
4 changes: 2 additions & 2 deletions compiler/rustc_resolve/src/ident.rs
Original file line number Diff line number Diff line change
@@ -1179,7 +1179,7 @@ impl<'a> Resolver<'a> {
ConstantItemRibKind(trivial, _) => {
let features = self.session.features_untracked();
// HACK(min_const_generics): We currently only allow `N` or `{ N }`.
if !(trivial || features.generic_const_exprs) {
if !(trivial == HasGenericParams::Yes || features.generic_const_exprs) {
// HACK(min_const_generics): If we encounter `Self` in an anonymous constant
// we can't easily tell if it's generic at this stage, so we instead remember
// this and then enforce the self type to be concrete later on.
@@ -1267,7 +1267,7 @@ impl<'a> Resolver<'a> {
ConstantItemRibKind(trivial, _) => {
let features = self.session.features_untracked();
// HACK(min_const_generics): We currently only allow `N` or `{ N }`.
if !(trivial || features.generic_const_exprs) {
if !(trivial == HasGenericParams::Yes || features.generic_const_exprs) {
if let Some(span) = finalize {
self.report_error(
span,
74 changes: 48 additions & 26 deletions compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
@@ -94,6 +94,12 @@ crate enum HasGenericParams {
No,
}

impl HasGenericParams {
fn force_yes_if(self, b: bool) -> Self {
if b { Self::Yes } else { self }
}
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
crate enum ConstantItemKind {
Const,
@@ -125,9 +131,9 @@ crate enum RibKind<'a> {

/// We're in a constant item. Can't refer to dynamic stuff.
///
/// The `bool` indicates if this constant may reference generic parameters
/// and is used to only allow generic parameters to be used in trivial constant expressions.
ConstantItemRibKind(bool, Option<(Ident, ConstantItemKind)>),
/// The item may reference generic parameters in trivial constant expressions.
/// All other constants aren't allowed to use generic params at all.
ConstantItemRibKind(HasGenericParams, Option<(Ident, ConstantItemKind)>),

/// We passed through a module.
ModuleRibKind(Module<'a>),
@@ -826,19 +832,24 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
// 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, None, |this| {
this.smart_resolve_path(
ty.id,
qself.as_ref(),
path,
PathSource::Expr(None),
);

if let Some(ref qself) = *qself {
this.visit_ty(&qself.ty);
}
this.visit_path(path, ty.id);
});
self.with_constant_rib(
IsRepeatExpr::No,
HasGenericParams::Yes,
None,
|this| {
this.smart_resolve_path(
ty.id,
qself.as_ref(),
path,
PathSource::Expr(None),
);

if let Some(ref qself) = *qself {
this.visit_ty(&qself.ty);
}
this.visit_path(path, ty.id);
},
);

self.diagnostic_metadata.currently_processing_generics = prev;
return;
@@ -1684,7 +1695,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
// not used as part of the type system, this is far less surprising.
this.with_constant_rib(
IsRepeatExpr::No,
true,
HasGenericParams::Yes,
None,
|this| this.visit_expr(expr),
);
@@ -1763,7 +1774,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
// so it doesn't matter whether this is a trivial constant.
this.with_constant_rib(
IsRepeatExpr::No,
true,
HasGenericParams::Yes,
Some((item.ident, constant_item_kind)),
|this| this.visit_expr(expr),
);
@@ -1909,20 +1920,23 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
// 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.
#[instrument(level = "debug", skip(self, f))]
fn with_constant_rib(
&mut self,
is_repeat: IsRepeatExpr,
is_trivial: bool,
may_use_generics: HasGenericParams,
item: Option<(Ident, ConstantItemKind)>,
f: impl FnOnce(&mut Self),
) {
debug!("with_constant_rib: is_repeat={:?} is_trivial={}", is_repeat, is_trivial);
self.with_rib(ValueNS, ConstantItemRibKind(is_trivial, item), |this| {
self.with_rib(ValueNS, ConstantItemRibKind(may_use_generics, item), |this| {
this.with_rib(
TypeNS,
ConstantItemRibKind(is_repeat == IsRepeatExpr::Yes || is_trivial, item),
ConstantItemRibKind(
may_use_generics.force_yes_if(is_repeat == IsRepeatExpr::Yes),
item,
),
|this| {
this.with_label_rib(ConstantItemRibKind(is_trivial, item), f);
this.with_label_rib(ConstantItemRibKind(may_use_generics, item), f);
},
)
});
@@ -2064,7 +2078,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
// not used as part of the type system, this is far less surprising.
this.with_constant_rib(
IsRepeatExpr::No,
true,
HasGenericParams::Yes,
None,
|this| {
visit::walk_assoc_item(
@@ -3077,7 +3091,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
debug!("resolve_anon_const {:?} is_repeat: {:?}", constant, is_repeat);
self.with_constant_rib(
is_repeat,
constant.value.is_potential_trivial_const_param(),
if constant.value.is_potential_trivial_const_param() {
HasGenericParams::Yes
} else {
HasGenericParams::No
},
None,
|this| visit::walk_anon_const(this, constant),
);
@@ -3180,7 +3198,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
if const_args.contains(&idx) {
self.with_constant_rib(
IsRepeatExpr::No,
argument.is_potential_trivial_const_param(),
if argument.is_potential_trivial_const_param() {
HasGenericParams::Yes
} else {
HasGenericParams::No
},
None,
|this| {
this.resolve_expr(argument, None);
34 changes: 21 additions & 13 deletions compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
Original file line number Diff line number Diff line change
@@ -429,9 +429,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
errors.drain_filter(|error| {
let Error::Invalid(input_idx, Compatibility::Incompatible(error)) = error else { return false };
let expected_ty = expected_input_tys[*input_idx];
let provided_ty = final_arg_types[*input_idx].map(|ty| ty.0).unwrap();
let Some(Some((provided_ty, _))) = final_arg_types.get(*input_idx) else { return false };
let cause = &self.misc(provided_args[*input_idx].span);
let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
let trace = TypeTrace::types(cause, true, expected_ty, *provided_ty);
if let Some(e) = error {
if !matches!(trace.cause.as_failure_code(e), FailureCode::Error0308(_)) {
self.report_and_explain_type_error(trace, e).emit();
@@ -679,8 +679,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Error::Invalid(input_idx, compatibility) => {
let expected_ty = expected_input_tys[input_idx];
if let Compatibility::Incompatible(error) = &compatibility {
let provided_ty = final_arg_types[input_idx].map(|ty| ty.0).unwrap();
let cause = &self.misc(provided_args[input_idx].span);
let provided_ty = final_arg_types
.get(input_idx)
.and_then(|x| x.as_ref())
.map(|ty| ty.0)
.unwrap_or(tcx.ty_error());
let cause = &self.misc(
provided_args.get(input_idx).map(|i| i.span).unwrap_or(call_span),
);
let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
if let Some(e) = error {
self.note_type_err(
@@ -695,14 +701,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}

self.emit_coerce_suggestions(
&mut err,
&provided_args[input_idx],
final_arg_types[input_idx].map(|ty| ty.0).unwrap(),
final_arg_types[input_idx].map(|ty| ty.1).unwrap(),
None,
None,
);
if let Some(expr) = provided_args.get(input_idx) {
self.emit_coerce_suggestions(
&mut err,
&expr,
final_arg_types[input_idx].map(|ty| ty.0).unwrap(),
final_arg_types[input_idx].map(|ty| ty.1).unwrap(),
None,
None,
);
}
}
Error::Extra(arg_idx) => {
let arg_type = if let Some((_, ty)) = final_arg_types[arg_idx] {
@@ -980,7 +988,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
for (idx, arg) in matched_inputs.iter().enumerate() {
let suggestion_text = if let Some(arg) = arg {
let arg_span = provided_args[*arg].span;
let arg_span = provided_args[*arg].span.source_callsite();
let arg_text = source_map.span_to_snippet(arg_span).unwrap();
arg_text
} else {
5 changes: 4 additions & 1 deletion src/librustdoc/html/markdown.rs
Original file line number Diff line number Diff line change
@@ -1440,6 +1440,10 @@ fn init_id_map() -> FxHashMap<Cow<'static, str>, usize> {
let mut map = FxHashMap::default();
// This is the list of IDs used in Javascript.
map.insert("help".into(), 1);
map.insert("settings".into(), 1);
map.insert("not-displayed".into(), 1);
map.insert("alternative-display".into(), 1);
map.insert("search".into(), 1);
// This is the list of IDs used in HTML generated in Rust (including the ones
// used in tera template files).
map.insert("mainThemeStyle".into(), 1);
@@ -1449,7 +1453,6 @@ fn init_id_map() -> FxHashMap<Cow<'static, str>, usize> {
map.insert("settings-menu".into(), 1);
map.insert("help-button".into(), 1);
map.insert("main-content".into(), 1);
map.insert("search".into(), 1);
map.insert("crate-search".into(), 1);
map.insert("render-detail".into(), 1);
map.insert("toggle-all-docs".into(), 1);
23 changes: 10 additions & 13 deletions src/librustdoc/html/render/context.rs
Original file line number Diff line number Diff line change
@@ -17,8 +17,8 @@ use super::print_item::{full_path, item_path, print_item};
use super::search_index::build_index;
use super::write_shared::write_shared;
use super::{
collect_spans_and_sources, print_sidebar, scrape_examples_help, settings, AllTypes,
LinkFromSrc, NameDoc, StylePath, BASIC_KEYWORDS,
collect_spans_and_sources, print_sidebar, scrape_examples_help, AllTypes, LinkFromSrc, NameDoc,
StylePath, BASIC_KEYWORDS,
};

use crate::clean::{self, types::ExternalLocation, ExternalCrate};
@@ -589,21 +589,18 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
page.root_path = "./";

let sidebar = "<h2 class=\"location\">Settings</h2><div class=\"sidebar-elems\"></div>";
let theme_names: Vec<String> = self
.shared
.style_files
.iter()
.map(StylePath::basename)
.collect::<Result<_, Error>>()?;
let v = layout::render(
&self.shared.layout,
&page,
sidebar,
settings(
self.shared.static_root_path.as_deref().unwrap_or("./"),
&self.shared.resource_suffix,
theme_names,
)?,
|buf: &mut Buffer| {
write!(
buf,
"<script defer src=\"{}settings{}.js\"></script>",
page.static_root_path.unwrap_or(""),
page.resource_suffix
)
},
&self.shared.style_files,
);
self.shared.fs.write(settings_file, v)?;
128 changes: 0 additions & 128 deletions src/librustdoc/html/render/mod.rs
Original file line number Diff line number Diff line change
@@ -334,134 +334,6 @@ impl AllTypes {
}
}

#[derive(Debug)]
enum Setting {
Section {
description: &'static str,
sub_settings: Vec<Setting>,
},
Toggle {
js_data_name: &'static str,
description: &'static str,
default_value: bool,
},
Select {
js_data_name: &'static str,
description: &'static str,
default_value: &'static str,
options: Vec<String>,
},
}

impl Setting {
fn display(&self, root_path: &str, suffix: &str) -> String {
match *self {
Setting::Section { description, ref sub_settings } => format!(
"<div class=\"setting-line\">\
<div class=\"title\">{}</div>\
<div class=\"sub-settings\">{}</div>
</div>",
description,
sub_settings.iter().map(|s| s.display(root_path, suffix)).collect::<String>()
),
Setting::Toggle { js_data_name, description, default_value } => format!(
"<div class=\"setting-line\">\
<label class=\"toggle\">\
<input type=\"checkbox\" id=\"{}\" {}>\
<span class=\"slider\"></span>\
</label>\
<div>{}</div>\
</div>",
js_data_name,
if default_value { " checked" } else { "" },
description,
),
Setting::Select { js_data_name, description, default_value, ref options } => format!(
"<div class=\"setting-line\"><div class=\"radio-line\" id=\"{}\"><span class=\"setting-name\">{}</span><div class=\"choices\">{}</div></div></div>",
js_data_name,
description,
options
.iter()
.map(|opt| format!(
"<label for=\"{js_data_name}-{name}\" class=\"choice\">
<input type=\"radio\" name=\"{js_data_name}\" id=\"{js_data_name}-{name}\" value=\"{name}\" {checked}>\
{name}\
</label>",
js_data_name = js_data_name,
name = opt,
checked = if opt == default_value { "checked" } else { "" },
))
.collect::<String>(),
),
}
}
}

impl From<(&'static str, &'static str, bool)> for Setting {
fn from(values: (&'static str, &'static str, bool)) -> Setting {
Setting::Toggle { js_data_name: values.0, description: values.1, default_value: values.2 }
}
}

impl<T: Into<Setting>> From<(&'static str, Vec<T>)> for Setting {
fn from(values: (&'static str, Vec<T>)) -> Setting {
Setting::Section {
description: values.0,
sub_settings: values.1.into_iter().map(|v| v.into()).collect::<Vec<_>>(),
}
}
}

fn settings(root_path: &str, suffix: &str, theme_names: Vec<String>) -> Result<String, Error> {
// (id, explanation, default value)
let settings: &[Setting] = &[
Setting::from(("use-system-theme", "Use system theme", true)),
Setting::Select {
js_data_name: "theme",
description: "Theme",
default_value: "light",
options: theme_names.clone(),
},
Setting::Select {
js_data_name: "preferred-light-theme",
description: "Preferred light theme",
default_value: "light",
options: theme_names.clone(),
},
Setting::Select {
js_data_name: "preferred-dark-theme",
description: "Preferred dark theme",
default_value: "dark",
options: theme_names,
},
("auto-hide-large-items", "Auto-hide item contents for large items.", true).into(),
("auto-hide-method-docs", "Auto-hide item methods' documentation", false).into(),
("auto-hide-trait-implementations", "Auto-hide trait implementation documentation", false)
.into(),
("go-to-only-result", "Directly go to item in search if there is only one result", false)
.into(),
("line-numbers", "Show line numbers on code examples", false).into(),
("disable-shortcuts", "Disable keyboard shortcuts", false).into(),
];

Ok(format!(
"<div class=\"main-heading\">
<h1 class=\"fqn\">\
<span class=\"in-band\">Rustdoc settings</span>\
</h1>\
<span class=\"out-of-band\">\
<a id=\"back\" href=\"javascript:void(0)\">Back</a>\
</span>\
</div>\
<div class=\"settings\">{}</div>\
<link rel=\"stylesheet\" href=\"{root_path}settings{suffix}.css\">\
<script src=\"{root_path}settings{suffix}.js\"></script>",
settings.iter().map(|s| s.display(root_path, suffix)).collect::<String>(),
root_path = root_path,
suffix = suffix
))
}

fn scrape_examples_help(shared: &SharedContext<'_>) -> String {
let mut content = SCRAPE_EXAMPLES_HELP_MD.to_owned();
content.push_str(&format!(
179 changes: 145 additions & 34 deletions src/librustdoc/html/static/js/main.js
Original file line number Diff line number Diff line change
@@ -57,11 +57,20 @@ function resourcePath(basename, extension) {
return getVar("root-path") + basename + getVar("resource-suffix") + extension;
}

function hideMain() {
addClass(document.getElementById(MAIN_ID), "hidden");
}

function showMain() {
removeClass(document.getElementById(MAIN_ID), "hidden");
}

(function () {
window.rootPath = getVar("root-path");
window.currentCrate = getVar("current-crate");
window.searchJS = resourcePath("search", ".js");
window.searchIndexJS = resourcePath("search-index", ".js");
window.settingsJS = resourcePath("settings", ".js");
const sidebarVars = document.getElementById("sidebar-vars");
if (sidebarVars) {
window.sidebarCurrent = {
@@ -104,6 +113,9 @@ function getVirtualKey(ev) {
const THEME_PICKER_ELEMENT_ID = "theme-picker";
const THEMES_ELEMENT_ID = "theme-choices";
const MAIN_ID = "main-content";
const SETTINGS_BUTTON_ID = "settings-menu";
const ALTERNATIVE_DISPLAY_ID = "alternative-display";
const NOT_DISPLAYED_ID = "not-displayed";

function getThemesElement() {
return document.getElementById(THEMES_ELEMENT_ID);
@@ -113,6 +125,10 @@ function getThemePickerElement() {
return document.getElementById(THEME_PICKER_ELEMENT_ID);
}

function getSettingsButton() {
return document.getElementById(SETTINGS_BUTTON_ID);
}

// Returns the current URL without any query parameter or hash.
function getNakedUrl() {
return window.location.href.split("?")[0].split("#")[0];
@@ -136,6 +152,10 @@ function hideThemeButtonState() {
themePicker.style.borderBottomLeftRadius = "3px";
}

window.hideSettings = function() {
// Does nothing by default.
};

// Set up the theme picker list.
(function () {
if (!document.location.href.startsWith("file:///")) {
@@ -182,14 +202,120 @@ function hideThemeButtonState() {
});
}());

/**
* This function inserts `newNode` after `referenceNode`. It doesn't work if `referenceNode`
* doesn't have a parent node.
*
* @param {HTMLElement} newNode
* @param {HTMLElement} referenceNode
*/
function insertAfter(newNode, referenceNode) {
referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
}

/**
* This function creates a new `<section>` with the given `id` and `classes` if it doesn't already
* exist.
*
* More information about this in `switchDisplayedElement` documentation.
*
* @param {string} id
* @param {string} classes
*/
function getOrCreateSection(id, classes) {
let el = document.getElementById(id);

if (!el) {
el = document.createElement("section");
el.id = id;
el.className = classes;
insertAfter(el, document.getElementById(MAIN_ID));
}
return el;
}

/**
* Returns the `<section>` element which contains the displayed element.
*
* @return {HTMLElement}
*/
function getAlternativeDisplayElem() {
return getOrCreateSection(ALTERNATIVE_DISPLAY_ID, "content hidden");
}

/**
* Returns the `<section>` element which contains the not-displayed elements.
*
* @return {HTMLElement}
*/
function getNotDisplayedElem() {
return getOrCreateSection(NOT_DISPLAYED_ID, "hidden");
}

/**
* To nicely switch between displayed "extra" elements (such as search results or settings menu)
* and to alternate between the displayed and not displayed elements, we hold them in two different
* `<section>` elements. They work in pair: one holds the hidden elements while the other
* contains the displayed element (there can be only one at the same time!). So basically, we switch
* elements between the two `<section>` elements.
*
* @param {HTMLElement} elemToDisplay
*/
function switchDisplayedElement(elemToDisplay) {
const el = getAlternativeDisplayElem();

if (el.children.length > 0) {
getNotDisplayedElem().appendChild(el.firstElementChild);
}
if (elemToDisplay === null) {
addClass(el, "hidden");
showMain();
return;
}
el.appendChild(elemToDisplay);
hideMain();
removeClass(el, "hidden");
}

function browserSupportsHistoryApi() {
return window.history && typeof window.history.pushState === "function";
}

// eslint-disable-next-line no-unused-vars
function loadCss(cssFileName) {
const link = document.createElement("link");
link.href = resourcePath(cssFileName, ".css");
link.type = "text/css";
link.rel = "stylesheet";
document.getElementsByTagName("head")[0].appendChild(link);
}

(function() {
"use strict";

function loadScript(url) {
const script = document.createElement('script');
script.src = url;
document.head.append(script);
}


getSettingsButton().onclick = function(event) {
event.preventDefault();
loadScript(window.settingsJS);
};

window.searchState = {
loadingText: "Loading search results...",
input: document.getElementsByClassName("search-input")[0],
outputElement: function() {
return document.getElementById("search");
let el = document.getElementById("search");
if (!el) {
el = document.createElement("section");
el.id = "search";
getNotDisplayedElem().appendChild(el);
}
return el;
},
title: document.title,
titleBeforeSearch: document.title,
@@ -208,6 +334,9 @@ function hideThemeButtonState() {
searchState.timeout = null;
}
},
isDisplayed: function() {
return searchState.outputElement().parentElement.id === ALTERNATIVE_DISPLAY_ID;
},
// Sets the focus on the search bar at the top of the page
focus: function() {
searchState.input.focus();
@@ -220,20 +349,15 @@ function hideThemeButtonState() {
if (search === null || typeof search === 'undefined') {
search = searchState.outputElement();
}
addClass(main, "hidden");
removeClass(search, "hidden");
switchDisplayedElement(search);
searchState.mouseMovedAfterSearch = false;
document.title = searchState.title;
},
hideResults: function(search) {
if (search === null || typeof search === 'undefined') {
search = searchState.outputElement();
}
addClass(search, "hidden");
removeClass(main, "hidden");
hideResults: function() {
switchDisplayedElement(null);
document.title = searchState.titleBeforeSearch;
// We also remove the query parameter from the URL.
if (searchState.browserSupportsHistoryApi()) {
if (browserSupportsHistoryApi()) {
history.replaceState(null, window.currentCrate + " - Rust",
getNakedUrl() + window.location.hash);
}
@@ -248,20 +372,11 @@ function hideThemeButtonState() {
});
return params;
},
browserSupportsHistoryApi: function() {
return window.history && typeof window.history.pushState === "function";
},
setup: function() {
const search_input = searchState.input;
if (!searchState.input) {
return;
}
function loadScript(url) {
const script = document.createElement('script');
script.src = url;
document.head.append(script);
}

let searchLoaded = false;
function loadSearch() {
if (!searchLoaded) {
@@ -303,23 +418,20 @@ function hideThemeButtonState() {
}

const toggleAllDocsId = "toggle-all-docs";
const main = document.getElementById(MAIN_ID);
let savedHash = "";

function handleHashes(ev) {
let elem;
const search = searchState.outputElement();
if (ev !== null && search && !hasClass(search, "hidden") && ev.newURL) {
if (ev !== null && searchState.isDisplayed() && ev.newURL) {
// This block occurs when clicking on an element in the navbar while
// in a search.
searchState.hideResults(search);
switchDisplayedElement(null);
const hash = ev.newURL.slice(ev.newURL.indexOf("#") + 1);
if (searchState.browserSupportsHistoryApi()) {
if (browserSupportsHistoryApi()) {
// `window.location.search`` contains all the query parameters, not just `search`.
history.replaceState(null, "",
getNakedUrl() + window.location.search + "#" + hash);
}
elem = document.getElementById(hash);
const elem = document.getElementById(hash);
if (elem) {
elem.scrollIntoView();
}
@@ -389,14 +501,17 @@ function hideThemeButtonState() {
}

function handleEscape(ev) {
searchState.clearInputTimeout();
const help = getHelpElement(false);
const search = searchState.outputElement();
if (help && !hasClass(help, "hidden")) {
displayHelp(false, ev, help);
} else if (search && !hasClass(search, "hidden")) {
searchState.clearInputTimeout();
} else {
switchDisplayedElement(null);
if (browserSupportsHistoryApi()) {
history.replaceState(null, window.currentCrate + " - Rust",
getNakedUrl() + window.location.hash);
}
ev.preventDefault();
searchState.hideResults(search);
}
searchState.defocus();
hideThemeButtonState();
@@ -733,10 +848,6 @@ function hideThemeButtonState() {
innerToggle.children[0].innerText = labelForToggleButton(sectionIsCollapsed);
}

function insertAfter(newNode, referenceNode) {
referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
}

(function() {
const toggles = document.getElementById(toggleAllDocsId);
if (toggles) {
16 changes: 8 additions & 8 deletions src/librustdoc/html/static/js/search.js
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@
/* eslint no-var: "error" */
/* eslint prefer-const: "error" */
/* global addClass, getNakedUrl, getSettingValue, hasOwnPropertyRustdoc, initSearch, onEach */
/* global onEachLazy, removeClass, searchState, hasClass */
/* global onEachLazy, removeClass, searchState, browserSupportsHistoryApi */

(function() {
// This mapping table should match the discriminants of
@@ -1786,8 +1786,9 @@ window.initSearch = function(rawSearchIndex) {

// Because searching is incremental by character, only the most
// recent search query is added to the browser history.
if (searchState.browserSupportsHistoryApi()) {
if (browserSupportsHistoryApi()) {
const newURL = buildUrl(query.original, filterCrates);

if (!history.state && !params.search) {
history.pushState(null, "", newURL);
} else {
@@ -1965,10 +1966,9 @@ window.initSearch = function(rawSearchIndex) {
if (!searchState.input) {
return;
}
const search = searchState.outputElement();
if (search_input.value !== "" && hasClass(search, "hidden")) {
searchState.showResults(search);
if (searchState.browserSupportsHistoryApi()) {
if (search_input.value !== "" && !searchState.isDisplayed()) {
searchState.showResults();
if (browserSupportsHistoryApi()) {
history.replaceState(null, "",
buildUrl(search_input.value, getFilterCrates()));
}
@@ -1980,7 +1980,7 @@ window.initSearch = function(rawSearchIndex) {
const searchAfter500ms = function() {
searchState.clearInputTimeout();
if (searchState.input.value.length === 0) {
if (searchState.browserSupportsHistoryApi()) {
if (browserSupportsHistoryApi()) {
history.replaceState(null, window.currentCrate + " - Rust",
getNakedUrl() + window.location.hash);
}
@@ -2058,7 +2058,7 @@ window.initSearch = function(rawSearchIndex) {

// Push and pop states are used to add search results to the browser
// history.
if (searchState.browserSupportsHistoryApi()) {
if (browserSupportsHistoryApi()) {
// Store the previous <title> so we can revert back to it later.
const previousTitle = document.title;

195 changes: 185 additions & 10 deletions src/librustdoc/html/static/js/settings.js
Original file line number Diff line number Diff line change
@@ -2,10 +2,13 @@
/* eslint no-var: "error" */
/* eslint prefer-const: "error" */
// Local js definitions:
/* global getSettingValue, getVirtualKey, onEachLazy, updateLocalStorage, updateSystemTheme */
/* global addClass, removeClass */
/* global getSettingValue, getVirtualKey, updateLocalStorage, updateSystemTheme, loadCss */
/* global addClass, removeClass, onEach, onEachLazy, NOT_DISPLAYED_ID */
/* global MAIN_ID, getVar, getSettingsButton, switchDisplayedElement, getNotDisplayedElem */

(function () {
const isSettingsPage = window.location.pathname.endsWith("/settings.html");

function changeSetting(settingName, value) {
updateLocalStorage(settingName, value);

@@ -55,9 +58,9 @@
}
}

function setEvents() {
function setEvents(settingsElement) {
updateLightAndDark();
onEachLazy(document.getElementsByClassName("slider"), function(elem) {
onEachLazy(settingsElement.getElementsByClassName("slider"), function(elem) {
const toggle = elem.previousElementSibling;
const settingId = toggle.id;
const settingValue = getSettingValue(settingId);
@@ -70,7 +73,7 @@
toggle.onkeyup = handleKey;
toggle.onkeyrelease = handleKey;
});
onEachLazy(document.getElementsByClassName("select-wrapper"), function(elem) {
onEachLazy(settingsElement.getElementsByClassName("select-wrapper"), function(elem) {
const select = elem.getElementsByTagName("select")[0];
const settingId = select.id;
const settingValue = getSettingValue(settingId);
@@ -81,7 +84,7 @@
changeSetting(this.id, this.value);
};
});
onEachLazy(document.querySelectorAll("input[type=\"radio\"]"), function(elem) {
onEachLazy(settingsElement.querySelectorAll("input[type=\"radio\"]"), function(elem) {
const settingId = elem.name;
const settingValue = getSettingValue(settingId);
if (settingValue !== null && settingValue !== "null") {
@@ -91,10 +94,182 @@
changeSetting(ev.target.name, ev.target.value);
});
});
document.getElementById("back").addEventListener("click", function() {
history.back();
});
}

window.addEventListener("DOMContentLoaded", setEvents);
/**
* This function builds the sections inside the "settings page". It takes a `settings` list
* as argument which describes each setting and how to render it. It returns a string
* representing the raw HTML.
*
* @param {Array<Object>} settings
*
* @return {string}
*/
function buildSettingsPageSections(settings) {
let output = "";

for (const setting of settings) {
output += `<div class="setting-line">`;
const js_data_name = setting["js_name"];
const setting_name = setting["name"];

if (setting["options"] !== undefined) {
// This is a select setting.
output += `<div class="radio-line" id="${js_data_name}">\
<span class="setting-name">${setting_name}</span>\
<div class="choices">`;
onEach(setting["options"], function(option) {
const checked = option === setting["default"] ? " checked" : "";

output += `<label for="${js_data_name}-${option}" class="choice">\
<input type="radio" name="${js_data_name}" \
id="${js_data_name}-${option}" value="${option}"${checked}>\
${option}\
</label>`;
});
output += "</div></div>";
} else {
// This is a toggle.
const checked = setting["default"] === true ? " checked" : "";
output += `
<label class="toggle">
<input type="checkbox" id="${js_data_name}"${checked}>
<span class="slider"></span>
</label>
<div>${setting_name}</div>`;
}
output += "</div>";
}
return output;
}

/**
* This function builds the "settings page" and returns the generated HTML element.
*
* @return {HTMLElement}
*/
function buildSettingsPage() {
const themes = getVar("themes").split(",");
const settings = [
{
"name": "Use system theme",
"js_name": "use-system-theme",
"default": true,
},
{
"name": "Theme",
"js_name": "theme",
"default": "light",
"options": themes,
},
{
"name": "Preferred light theme",
"js_name": "preferred-light-theme",
"default": "light",
"options": themes,
},
{
"name": "Preferred dark theme",
"js_name": "preferred-dark-theme",
"default": "dark",
"options": themes,
},
{
"name": "Auto-hide item contents for large items",
"js_name": "auto-hide-large-items",
"default": true,
},
{
"name": "Auto-hide item methods' documentation",
"js_name": "auto-hide-method-docs",
"default": false,
},
{
"name": "Auto-hide trait implementation documentation",
"js_name": "auto-hide-trait-implementations",
"default": false,
},
{
"name": "Directly go to item in search if there is only one result",
"js_name": "go-to-only-result",
"default": false,
},
{
"name": "Show line numbers on code examples",
"js_name": "line-numbers",
"default": false,
},
{
"name": "Disable keyboard shortcuts",
"js_name": "disable-shortcuts",
"default": false,
},
];

// First, we add the settings.css file.
loadCss("settings");

// Then we build the DOM.
const el = document.createElement("section");
el.id = "settings";
let innerHTML = `
<div class="main-heading">
<h1 class="fqn">
<span class="in-band">Rustdoc settings</span>
</h1>
<span class="out-of-band">`;

if (isSettingsPage) {
innerHTML +=
`<a id="back" href="javascript:void(0)" onclick="history.back();">Back</a>`;
} else {
innerHTML +=
`<a id="back" href="javascript:void(0)" onclick="switchDisplayedElement(null);">\
Back</a>`;
}
innerHTML += `</span>
</div>
<div class="settings">${buildSettingsPageSections(settings)}</div>`;

el.innerHTML = innerHTML;

if (isSettingsPage) {
document.getElementById(MAIN_ID).appendChild(el);
} else {
getNotDisplayedElem().appendChild(el);
}
return el;
}

const settingsMenu = buildSettingsPage();

if (isSettingsPage) {
// We replace the existing "onclick" callback to do nothing if clicked.
getSettingsButton().onclick = function(event) {
event.preventDefault();
};
} else {
// We replace the existing "onclick" callback.
const settingsButton = getSettingsButton();
settingsButton.onclick = function(event) {
event.preventDefault();
if (settingsMenu.parentElement.id === NOT_DISPLAYED_ID) {
switchDisplayedElement(settingsMenu);
} else {
window.hideSettings();
}
};
window.hideSettings = function() {
switchDisplayedElement(null);
};
}

// We now wait a bit for the web browser to end re-computing the DOM...
setTimeout(function() {
setEvents(settingsMenu);
// The setting menu is already displayed if we're on the settings page.
if (!isSettingsPage) {
switchDisplayedElement(settingsMenu);
}
}, 0);
})();
4 changes: 2 additions & 2 deletions src/librustdoc/html/static/js/source-script.js
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@
/* global search, sourcesIndex */

// Local js definitions:
/* global addClass, getCurrentValue, hasClass, onEachLazy, removeClass, searchState */
/* global addClass, getCurrentValue, hasClass, onEachLazy, removeClass, browserSupportsHistoryApi */
/* global updateLocalStorage */
(function() {

@@ -195,7 +195,7 @@ const handleSourceHighlight = (function() {
const set_fragment = function(name) {
const x = window.scrollX,
y = window.scrollY;
if (searchState.browserSupportsHistoryApi()) {
if (browserSupportsHistoryApi()) {
history.replaceState(null, null, "#" + name);
highlightSourceLines();
} else {
1 change: 0 additions & 1 deletion src/librustdoc/html/templates/page.html
Original file line number Diff line number Diff line change
@@ -135,7 +135,6 @@ <h2 class="location"></h2>
</nav> {#- -#}
</div> {#- -#}
<section id="main-content" class="content">{{- content|safe -}}</section> {#- -#}
<section id="search" class="content hidden"></section> {#- -#}
</div> {#- -#}
</main> {#- -#}
{{- layout.external_html.after_content|safe -}}
14 changes: 9 additions & 5 deletions src/test/rustdoc-gui/escape-key.goml
Original file line number Diff line number Diff line change
@@ -4,17 +4,20 @@ goto: file://|DOC_PATH|/test_docs/index.html
// First, we check that the search results are hidden when the Escape key is pressed.
write: (".search-input", "test")
wait-for: "#search h1" // The search element is empty before the first search
assert-attribute: ("#search", {"class": "content"})
// Check that the currently displayed element is search.
wait-for: "#alternative-display #search"
assert-attribute: ("#main-content", {"class": "content hidden"})
assert-document-property: ({"URL": "index.html?search=test"}, ENDS_WITH)
press-key: "Escape"
assert-attribute: ("#search", {"class": "content hidden"})
// Checks that search is no longer in the displayed content.
wait-for: "#not-displayed #search"
assert-false: "#alternative-display #search"
assert-attribute: ("#main-content", {"class": "content"})
assert-document-property: ({"URL": "index.html"}, [ENDS_WITH])

// Check that focusing the search input brings back the search results
focus: ".search-input"
assert-attribute: ("#search", {"class": "content"})
wait-for: "#alternative-display #search"
assert-attribute: ("#main-content", {"class": "content hidden"})
assert-document-property: ({"URL": "index.html?search=test"}, ENDS_WITH)

@@ -24,8 +27,8 @@ click: "#help-button"
assert-document-property: ({"URL": "index.html?search=test"}, [ENDS_WITH])
assert-attribute: ("#help", {"class": ""})
press-key: "Escape"
wait-for: "#alternative-display #search"
assert-attribute: ("#help", {"class": "hidden"})
assert-attribute: ("#search", {"class": "content"})
assert-attribute: ("#main-content", {"class": "content hidden"})
assert-document-property: ({"URL": "index.html?search=test"}, [ENDS_WITH])

@@ -37,5 +40,6 @@ assert-false: ".search-input:focus"
assert: "#results a:focus"
press-key: "Escape"
assert-attribute: ("#help", {"class": "hidden"})
assert-attribute: ("#search", {"class": "content hidden"})
wait-for: "#not-displayed #search"
assert-false: "#alternative-display #search"
assert-attribute: ("#main-content", {"class": "content"})
67 changes: 67 additions & 0 deletions src/test/rustdoc-gui/settings.goml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// This test ensures that the settings menu display is working as expected.
goto: file://|DOC_PATH|/test_docs/index.html
// First, we check that the settings page doesn't exist.
assert-false: "#settings"
// We now click on the settings button.
click: "#settings-menu"
wait-for: "#settings"
assert: "#main-content.hidden"
assert-css: ("#settings", {"display": "block"})
// Let's close it by clicking on the same button.
click: "#settings-menu"
assert-false: "#alternative-display #settings"
assert: "#not-displayed #settings"
assert: "#main-content:not(.hidden)"

// Let's open and then close it again with the "close settings" button.
click: "#settings-menu"
wait-for: "#alternative-display #settings"
assert: "#main-content.hidden"
click: "#back"
wait-for: "#not-displayed #settings"
assert: "#main-content:not(.hidden)"

// Let's check that pressing "ESCAPE" is closing it.
click: "#settings-menu"
wait-for: "#alternative-display #settings"
press-key: "Escape"
wait-for: "#not-displayed #settings"
assert: "#main-content:not(.hidden)"

// Let's click on it when the search results are displayed.
focus: ".search-input"
write: "test"
wait-for: "#alternative-display #search"
click: "#settings-menu"
wait-for: "#alternative-display #settings"
assert: "#not-displayed #search"
assert: "#main-content.hidden"

// Now let's check the content of the settings menu.
local-storage: {"rustdoc-theme": "dark", "rustdoc-use-system-theme": "false"}
reload:
click: "#settings-menu"
wait-for: "#settings"

// We check that the "Use system theme" is disabled.
assert-property: ("#use-system-theme", {"checked": "false"})
assert: "//*[@class='setting-line']/*[text()='Use system theme']"
// Meaning that only the "theme" menu is showing up.
assert: ".setting-line:not(.hidden) #theme"
assert: ".setting-line.hidden #preferred-dark-theme"
assert: ".setting-line.hidden #preferred-light-theme"

// We check that the correct theme is selected.
assert-property: ("#theme .choices #theme-dark", {"checked": "true"})

// We now switch the display.
click: "#use-system-theme"
// Wait for the hidden element to show up.
wait-for: ".setting-line:not(.hidden) #preferred-dark-theme"
assert: ".setting-line:not(.hidden) #preferred-light-theme"
// Check that the theme picking is hidden.
assert: ".setting-line.hidden #theme"

// We check their text as well.
assert-text: ("#preferred-dark-theme .setting-name", "Preferred dark theme")
assert-text: ("#preferred-light-theme .setting-name", "Preferred light theme")
1 change: 1 addition & 0 deletions src/test/rustdoc-gui/theme-change.goml
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@ click: "#theme-choices > button:last-child"
wait-for-css: ("body", { "background-color": "rgb(255, 255, 255)" })

goto: file://|DOC_PATH|/settings.html
wait-for: "#settings"
click: "#theme-light"
wait-for-css: ("body", { "background-color": "rgb(255, 255, 255)" })
assert-local-storage: { "rustdoc-theme": "light" }
12 changes: 8 additions & 4 deletions src/test/rustdoc-gui/theme-in-history.goml
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
// Ensures that the theme is working when going back in history.
goto: file://|DOC_PATH|/test_docs/index.html
// Set the theme to dark.
local-storage: {"rustdoc-theme": "dark", "rustdoc-preferred-dark-theme": "dark", "rustdoc-use-system-theme": "false"}
local-storage: {
"rustdoc-theme": "dark",
"rustdoc-preferred-dark-theme": "dark",
"rustdoc-use-system-theme": "false",
}
// We reload the page so the local storage settings are being used.
reload:
assert-css: ("body", { "background-color": "rgb(53, 53, 53)" })
assert-local-storage: { "rustdoc-theme": "dark" }

// Now we go to the settings page.
click: "#settings-menu"
wait-for: ".settings"
goto: file://|DOC_PATH|/settings.html
wait-for: "#settings"
// We change the theme to "light".
click: "#theme-light"
wait-for-css: ("body", { "background-color": "rgb(255, 255, 255)" })
@@ -18,7 +22,7 @@ assert-local-storage: { "rustdoc-theme": "light" }
// We go back in history.
history-go-back:
// Confirm that we're not on the settings page.
assert-false: ".settings"
assert-false: "#settings"
// Check that the current theme is still "light".
assert-css: ("body", { "background-color": "rgb(255, 255, 255)" })
assert-local-storage: { "rustdoc-theme": "light" }
9 changes: 9 additions & 0 deletions src/test/ui/argument-suggestions/issue-96638.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
fn f(_: usize, _: &usize, _: usize) {}

fn arg<T>() -> T { todo!() }

fn main() {
let x = arg(); // `x` must be inferred
// The reference on `&x` is important to reproduce the ICE
f(&x, ""); //~ ERROR this function takes 3 arguments but 2 arguments were supplied
}
19 changes: 19 additions & 0 deletions src/test/ui/argument-suggestions/issue-96638.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
error[E0061]: this function takes 3 arguments but 2 arguments were supplied
--> $DIR/issue-96638.rs:8:5
|
LL | f(&x, "");
| ^ -- an argument of type `usize` is missing
|
note: function defined here
--> $DIR/issue-96638.rs:1:4
|
LL | fn f(_: usize, _: &usize, _: usize) {}
| ^ -------- --------- --------
help: provide the argument
|
LL | f({usize}, &x, {usize});
| ~~~~~~~~~~~~~~~~~~~~~~~

error: aborting due to previous error

For more information about this error, try `rustc --explain E0061`.
2 changes: 1 addition & 1 deletion src/test/ui/async-await/no-async-const.stderr
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@ LL | pub async const fn x() {}
| | expected one of `extern`, `fn`, or `unsafe`
| help: `const` must come before `async`: `const async`
|
= note: keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`
= note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`

error: aborting due to previous error

4 changes: 2 additions & 2 deletions src/test/ui/async-await/no-unsafe-async.stderr
Original file line number Diff line number Diff line change
@@ -12,7 +12,7 @@ LL | unsafe async fn g() {}
LL | }
| - the item list ends here
|
= note: keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`
= note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`

error: expected one of `extern` or `fn`, found keyword `async`
--> $DIR/no-unsafe-async.rs:11:8
@@ -23,7 +23,7 @@ LL | unsafe async fn f() {}
| | expected one of `extern` or `fn`
| help: `async` must come before `unsafe`: `async unsafe`
|
= note: keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`
= note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`

error: aborting due to 2 previous errors

6 changes: 6 additions & 0 deletions src/test/ui/fn/keyword-order.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// edition:2018

default pub const async unsafe extern fn err() {} //~ ERROR `default` is not followed by an item
//~^ ERROR expected item, found keyword `pub`

pub default const async unsafe extern fn ok() {}
16 changes: 16 additions & 0 deletions src/test/ui/fn/keyword-order.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
error: `default` is not followed by an item
--> $DIR/keyword-order.rs:3:1
|
LL | default pub const async unsafe extern fn err() {}
| ^^^^^^^ the `default` qualifier
|
= note: only `fn`, `const`, `type`, or `impl` items may be prefixed by `default`

error: expected item, found keyword `pub`
--> $DIR/keyword-order.rs:3:9
|
LL | default pub const async unsafe extern fn err() {}
| ^^^ expected item

error: aborting due to 2 previous errors

15 changes: 15 additions & 0 deletions src/test/ui/impl-trait/issues/issue-92305.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// edition:2021

use std::iter;

fn f<T>(data: &[T]) -> impl Iterator<Item = Vec> {
//~^ ERROR: missing generics for struct `Vec` [E0107]
iter::empty() //~ ERROR: type annotations needed [E0282]
}

fn g<T>(data: &[T], target: T) -> impl Iterator<Item = Vec<T>> {
//~^ ERROR: type annotations needed [E0282]
f(data).filter(|x| x == target)
}

fn main() {}
32 changes: 32 additions & 0 deletions src/test/ui/impl-trait/issues/issue-92305.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
error[E0107]: missing generics for struct `Vec`
--> $DIR/issue-92305.rs:5:45
|
LL | fn f<T>(data: &[T]) -> impl Iterator<Item = Vec> {
| ^^^ expected at least 1 generic argument
|
note: struct defined here, with at least 1 generic parameter: `T`
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
|
LL | pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
| ^^^ -
help: add missing generic argument
|
LL | fn f<T>(data: &[T]) -> impl Iterator<Item = Vec<T>> {
| ~~~~~~

error[E0282]: type annotations needed
--> $DIR/issue-92305.rs:7:5
|
LL | iter::empty()
| ^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the function `empty`

error[E0282]: type annotations needed
--> $DIR/issue-92305.rs:10:35
|
LL | fn g<T>(data: &[T], target: T) -> impl Iterator<Item = Vec<T>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type

error: aborting due to 3 previous errors

Some errors have detailed explanations: E0107, E0282.
For more information about an error, try `rustc --explain E0107`.
2 changes: 1 addition & 1 deletion src/test/ui/parser/issues/issue-19398.stderr
Original file line number Diff line number Diff line change
@@ -12,7 +12,7 @@ LL |
LL | }
| - the item list ends here
|
= note: keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`
= note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`

error: aborting due to previous error

Original file line number Diff line number Diff line change
@@ -11,4 +11,4 @@ async unsafe const fn test() {}
//~| NOTE expected one of `extern` or `fn`
//~| HELP `const` must come before `async unsafe`
//~| SUGGESTION const async unsafe
//~| NOTE keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`
//~| NOTE keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@ LL | async unsafe const fn test() {}
| | expected one of `extern` or `fn`
| help: `const` must come before `async unsafe`: `const async unsafe`
|
= note: keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`
= note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`

error: aborting due to previous error

Original file line number Diff line number Diff line change
@@ -11,4 +11,4 @@ unsafe async fn test() {}
//~| NOTE expected one of `extern` or `fn`
//~| HELP `async` must come before `unsafe`
//~| SUGGESTION async unsafe
//~| NOTE keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`
//~| NOTE keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@ LL | unsafe async fn test() {}
| | expected one of `extern` or `fn`
| help: `async` must come before `unsafe`: `async unsafe`
|
= note: keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`
= note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`

error: aborting due to previous error

Original file line number Diff line number Diff line change
@@ -11,4 +11,4 @@ unsafe const fn test() {}
//~| NOTE expected one of `extern` or `fn`
//~| HELP `const` must come before `unsafe`
//~| SUGGESTION const unsafe
//~| NOTE keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`
//~| NOTE keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@ LL | unsafe const fn test() {}
| | expected one of `extern` or `fn`
| help: `const` must come before `unsafe`: `const unsafe`
|
= note: keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`
= note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`

error: aborting due to previous error

Original file line number Diff line number Diff line change
@@ -11,4 +11,4 @@ extern unsafe fn test() {}
//~| NOTE expected `fn`
//~| HELP `unsafe` must come before `extern`
//~| SUGGESTION unsafe extern
//~| NOTE keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`
//~| NOTE keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@ LL | extern unsafe fn test() {}
| | expected `fn`
| help: `unsafe` must come before `extern`: `unsafe extern`
|
= note: keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`
= note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`

error: aborting due to previous error

9 changes: 9 additions & 0 deletions src/test/ui/typeck/remove-extra-argument.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// run-rustfix
// Check that the HELP suggestion is `l(vec![])` instead of `l($crate::vec::Vec::new())`
fn l(_a: Vec<u8>) {}

fn main() {
l(vec![])
//~^ ERROR this function takes 1 argument but 2 arguments were supplied
//~| HELP remove the extra argument
}
9 changes: 9 additions & 0 deletions src/test/ui/typeck/remove-extra-argument.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// run-rustfix
// Check that the HELP suggestion is `l(vec![])` instead of `l($crate::vec::Vec::new())`
fn l(_a: Vec<u8>) {}

fn main() {
l(vec![], vec![])
//~^ ERROR this function takes 1 argument but 2 arguments were supplied
//~| HELP remove the extra argument
}
19 changes: 19 additions & 0 deletions src/test/ui/typeck/remove-extra-argument.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
error[E0061]: this function takes 1 argument but 2 arguments were supplied
--> $DIR/remove-extra-argument.rs:6:5
|
LL | l(vec![], vec![])
| ^ ------ argument unexpected
|
note: function defined here
--> $DIR/remove-extra-argument.rs:3:4
|
LL | fn l(_a: Vec<u8>) {}
| ^ -----------
help: remove the extra argument
|
LL | l(vec![])
|

error: aborting due to previous error

For more information about this error, try `rustc --explain E0061`.