diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 497a28354d813..58996a9db78ad 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -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, 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, _modules: Vec<(String, Self::ThinBuffer)>, _cached_modules: Vec<(SerializedModule, WorkProduct)>) -> Result<(Vec>, Vec), FatalError> { @@ -229,7 +227,12 @@ impl WriteBackendMethods for GccCodegenBackend { Ok(()) } - unsafe fn optimize_thin(_cgcx: &CodegenContext, _thin: &mut ThinModule) -> Result, FatalError> { + fn optimize_fat(_cgcx: &CodegenContext, _module: &mut ModuleCodegen) -> Result<(), FatalError> { + // TODO(antoyo) + Ok(()) + } + + unsafe fn optimize_thin(_cgcx: &CodegenContext, _thin: ThinModule) -> Result, FatalError> { unimplemented!(); } @@ -245,11 +248,6 @@ impl WriteBackendMethods for GccCodegenBackend { unimplemented!(); } - fn run_lto_pass_manager(_cgcx: &CodegenContext, _module: &ModuleCodegen, _config: &ModuleConfig, _thin: bool) -> Result<(), FatalError> { - // TODO(antoyo) - Ok(()) - } - fn run_link(cgcx: &CodegenContext, diag_handler: &Handler, modules: Vec>) -> Result, FatalError> { back::write::link(cgcx, diag_handler, modules) } diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 5c63bd8c1bd8d..b5b2a27d2378d 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -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, diag_handler: &Handler, - module: &ModuleCodegen, - config: &ModuleConfig, + module: &mut ModuleCodegen, 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, + thin_module: ThinModule, cgcx: &CodegenContext, ) -> Result, 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"); } } diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 3152c505af0e5..b035923956954 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -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, + module: &mut ModuleCodegen, + ) -> 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, - thin: &mut ThinModule, + thin: ThinModule, ) -> Result, FatalError> { back::lto::optimize_thin_module(thin, cgcx) } @@ -230,15 +236,6 @@ impl WriteBackendMethods for LlvmCodegenBackend { fn serialize_module(module: ModuleCodegen) -> (String, Self::ModuleBuffer) { (module.name, back::lto::ModuleBuffer::new(module.module_llvm.llmod())) } - fn run_lto_pass_manager( - cgcx: &CodegenContext, - module: &ModuleCodegen, - 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 diff --git a/compiler/rustc_codegen_ssa/src/back/lto.rs b/compiler/rustc_codegen_ssa/src/back/lto.rs index d6ae689f254b1..cb6244050df24 100644 --- a/compiler/rustc_codegen_ssa/src/back/lto.rs +++ b/compiler/rustc_codegen_ssa/src/back/lto.rs @@ -42,7 +42,7 @@ pub struct ThinShared { pub enum LtoModuleCodegen { Fat { - module: Option>, + module: ModuleCodegen, _serialized_bitcode: Vec>, }, @@ -64,19 +64,15 @@ impl LtoModuleCodegen { /// 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, ) -> Result, 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), } } diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 98dc5fe8d6424..88293dec01cac 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -889,7 +889,7 @@ fn execute_copy_from_cache_work_item( fn execute_lto_work_item( cgcx: &CodegenContext, - mut module: lto::LtoModuleCodegen, + module: lto::LtoModuleCodegen, module_config: &ModuleConfig, ) -> Result, FatalError> { let module = unsafe { module.optimize(cgcx)? }; diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 019c9c179d8e1..5bc95614c197c 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -575,15 +575,8 @@ pub fn codegen_crate( } 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 }) diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index 856b774258316..1e53c73d1bb4a 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -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( diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs index 93fbee2b49bb5..e54ec34f1ce37 100644 --- a/compiler/rustc_codegen_ssa/src/traits/write.rs +++ b/compiler/rustc_codegen_ssa/src/traits/write.rs @@ -41,9 +41,13 @@ pub trait WriteBackendMethods: 'static + Sized + Clone { module: &ModuleCodegen, config: &ModuleConfig, ) -> Result<(), FatalError>; + fn optimize_fat( + cgcx: &CodegenContext, + llmod: &mut ModuleCodegen, + ) -> Result<(), FatalError>; unsafe fn optimize_thin( cgcx: &CodegenContext, - thin: &mut ThinModule, + thin: ThinModule, ) -> Result, FatalError>; unsafe fn codegen( cgcx: &CodegenContext, @@ -53,12 +57,6 @@ pub trait WriteBackendMethods: 'static + Sized + Clone { ) -> Result; fn prepare_thin(module: ModuleCodegen) -> (String, Self::ThinBuffer); fn serialize_module(module: ModuleCodegen) -> (String, Self::ModuleBuffer); - fn run_lto_pass_manager( - cgcx: &CodegenContext, - llmod: &ModuleCodegen, - config: &ModuleConfig, - thin: bool, - ) -> Result<(), FatalError>; } pub trait ThinBufferMethods: Send + Sync { diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 0dff71be4b82c..188ca8048055c 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -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 diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 10f1daf112951..77a03428c1664 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -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` diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 18ce359524da2..baaab33d71f50 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -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, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index b89b9c376af63..ab353128cbcce 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -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); diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 616aa11f00a6b..75976ebdf2822 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -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 { diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 9e76af9829854..56a085c298250 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -1440,6 +1440,10 @@ fn init_id_map() -> FxHashMap, 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, 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); diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 8e643107353dd..a30c533aa48c8 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -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 = "

Settings

"; - let theme_names: Vec = self - .shared - .style_files - .iter() - .map(StylePath::basename) - .collect::>()?; 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, + "", + page.static_root_path.unwrap_or(""), + page.resource_suffix + ) + }, &self.shared.style_files, ); self.shared.fs.write(settings_file, v)?; diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 7a4289b8e60e9..fedeb449b2e0e 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -334,134 +334,6 @@ impl AllTypes { } } -#[derive(Debug)] -enum Setting { - Section { - description: &'static str, - sub_settings: Vec, - }, - 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, - }, -} - -impl Setting { - fn display(&self, root_path: &str, suffix: &str) -> String { - match *self { - Setting::Section { description, ref sub_settings } => format!( - "
\ -
{}
\ -
{}
-
", - description, - sub_settings.iter().map(|s| s.display(root_path, suffix)).collect::() - ), - Setting::Toggle { js_data_name, description, default_value } => format!( - "
\ - \ -
{}
\ -
", - js_data_name, - if default_value { " checked" } else { "" }, - description, - ), - Setting::Select { js_data_name, description, default_value, ref options } => format!( - "
{}
{}
", - js_data_name, - description, - options - .iter() - .map(|opt| format!( - "", - js_data_name = js_data_name, - name = opt, - checked = if opt == default_value { "checked" } else { "" }, - )) - .collect::(), - ), - } - } -} - -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> From<(&'static str, Vec)> for Setting { - fn from(values: (&'static str, Vec)) -> Setting { - Setting::Section { - description: values.0, - sub_settings: values.1.into_iter().map(|v| v.into()).collect::>(), - } - } -} - -fn settings(root_path: &str, suffix: &str, theme_names: Vec) -> Result { - // (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!( - "
-

\ - Rustdoc settings\ -

\ - \ - Back\ - \ -
\ -
{}
\ - \ - ", - settings.iter().map(|s| s.display(root_path, suffix)).collect::(), - 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!( diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 9e5de9a843ab1..f20061c65dd1b 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -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 `
` 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 `
` element which contains the displayed element. + * + * @return {HTMLElement} + */ +function getAlternativeDisplayElem() { + return getOrCreateSection(ALTERNATIVE_DISPLAY_ID, "content hidden"); +} + +/** + * Returns the `
` 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 + * `
` 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 `
` 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) { diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index a6f7dd74af6b0..84600fa3e094f 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -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 so we can revert back to it later. const previousTitle = document.title; diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js index 7bc6f6cfe043d..a2f8d56fb320b 100644 --- a/src/librustdoc/html/static/js/settings.js +++ b/src/librustdoc/html/static/js/settings.js @@ -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); })(); diff --git a/src/librustdoc/html/static/js/source-script.js b/src/librustdoc/html/static/js/source-script.js index c48a847665ef5..6aee0da69f8de 100644 --- a/src/librustdoc/html/static/js/source-script.js +++ b/src/librustdoc/html/static/js/source-script.js @@ -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 { diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html index 564731ab7354b..470cce93a5020 100644 --- a/src/librustdoc/html/templates/page.html +++ b/src/librustdoc/html/templates/page.html @@ -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 -}} diff --git a/src/test/rustdoc-gui/escape-key.goml b/src/test/rustdoc-gui/escape-key.goml index 6e305e81eeec0..8713bf65c8432 100644 --- a/src/test/rustdoc-gui/escape-key.goml +++ b/src/test/rustdoc-gui/escape-key.goml @@ -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"}) diff --git a/src/test/rustdoc-gui/settings.goml b/src/test/rustdoc-gui/settings.goml new file mode 100644 index 0000000000000..6c4611b1cb2a6 --- /dev/null +++ b/src/test/rustdoc-gui/settings.goml @@ -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") diff --git a/src/test/rustdoc-gui/theme-change.goml b/src/test/rustdoc-gui/theme-change.goml index 333391ba27970..9706511ea19c3 100644 --- a/src/test/rustdoc-gui/theme-change.goml +++ b/src/test/rustdoc-gui/theme-change.goml @@ -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" } diff --git a/src/test/rustdoc-gui/theme-in-history.goml b/src/test/rustdoc-gui/theme-in-history.goml index 3b66c85d8dad2..f576ced1c6208 100644 --- a/src/test/rustdoc-gui/theme-in-history.goml +++ b/src/test/rustdoc-gui/theme-in-history.goml @@ -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" } diff --git a/src/test/ui/argument-suggestions/issue-96638.rs b/src/test/ui/argument-suggestions/issue-96638.rs new file mode 100644 index 0000000000000..9c6e81ab8cc75 --- /dev/null +++ b/src/test/ui/argument-suggestions/issue-96638.rs @@ -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 +} diff --git a/src/test/ui/argument-suggestions/issue-96638.stderr b/src/test/ui/argument-suggestions/issue-96638.stderr new file mode 100644 index 0000000000000..35190e2ca0d82 --- /dev/null +++ b/src/test/ui/argument-suggestions/issue-96638.stderr @@ -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`. diff --git a/src/test/ui/async-await/no-async-const.stderr b/src/test/ui/async-await/no-async-const.stderr index ae13b90c3cfc0..a51dc88a4eded 100644 --- a/src/test/ui/async-await/no-async-const.stderr +++ b/src/test/ui/async-await/no-async-const.stderr @@ -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 diff --git a/src/test/ui/async-await/no-unsafe-async.stderr b/src/test/ui/async-await/no-unsafe-async.stderr index 0c362052501ed..f23d17d6bfa57 100644 --- a/src/test/ui/async-await/no-unsafe-async.stderr +++ b/src/test/ui/async-await/no-unsafe-async.stderr @@ -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 diff --git a/src/test/ui/fn/keyword-order.rs b/src/test/ui/fn/keyword-order.rs new file mode 100644 index 0000000000000..8a21db6733352 --- /dev/null +++ b/src/test/ui/fn/keyword-order.rs @@ -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() {} diff --git a/src/test/ui/fn/keyword-order.stderr b/src/test/ui/fn/keyword-order.stderr new file mode 100644 index 0000000000000..d3b140c852860 --- /dev/null +++ b/src/test/ui/fn/keyword-order.stderr @@ -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 + diff --git a/src/test/ui/impl-trait/issues/issue-92305.rs b/src/test/ui/impl-trait/issues/issue-92305.rs new file mode 100644 index 0000000000000..1518c116b3185 --- /dev/null +++ b/src/test/ui/impl-trait/issues/issue-92305.rs @@ -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() {} diff --git a/src/test/ui/impl-trait/issues/issue-92305.stderr b/src/test/ui/impl-trait/issues/issue-92305.stderr new file mode 100644 index 0000000000000..c4fc49225e9a0 --- /dev/null +++ b/src/test/ui/impl-trait/issues/issue-92305.stderr @@ -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`. diff --git a/src/test/ui/parser/issues/issue-19398.stderr b/src/test/ui/parser/issues/issue-19398.stderr index f9c3ca763f26e..bbd85374b4bcf 100644 --- a/src/test/ui/parser/issues/issue-19398.stderr +++ b/src/test/ui/parser/issues/issue-19398.stderr @@ -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 diff --git a/src/test/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.rs b/src/test/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.rs index 86fdb78cce8ab..bbebc99e94b82 100644 --- a/src/test/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.rs +++ b/src/test/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.rs @@ -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` diff --git a/src/test/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.stderr b/src/test/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.stderr index 65cce77be896b..f455caba158c7 100644 --- a/src/test/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.stderr +++ b/src/test/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.stderr @@ -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 diff --git a/src/test/ui/parser/issues/issue-87217-keyword-order/wrong-async.rs b/src/test/ui/parser/issues/issue-87217-keyword-order/wrong-async.rs index edfb330d6713a..4ff4cf5c8ca87 100644 --- a/src/test/ui/parser/issues/issue-87217-keyword-order/wrong-async.rs +++ b/src/test/ui/parser/issues/issue-87217-keyword-order/wrong-async.rs @@ -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` diff --git a/src/test/ui/parser/issues/issue-87217-keyword-order/wrong-async.stderr b/src/test/ui/parser/issues/issue-87217-keyword-order/wrong-async.stderr index 3acd9e4400432..e9eb14bf00e77 100644 --- a/src/test/ui/parser/issues/issue-87217-keyword-order/wrong-async.stderr +++ b/src/test/ui/parser/issues/issue-87217-keyword-order/wrong-async.stderr @@ -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 diff --git a/src/test/ui/parser/issues/issue-87217-keyword-order/wrong-const.rs b/src/test/ui/parser/issues/issue-87217-keyword-order/wrong-const.rs index abd692b80d54b..2f5fbc513ee36 100644 --- a/src/test/ui/parser/issues/issue-87217-keyword-order/wrong-const.rs +++ b/src/test/ui/parser/issues/issue-87217-keyword-order/wrong-const.rs @@ -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` diff --git a/src/test/ui/parser/issues/issue-87217-keyword-order/wrong-const.stderr b/src/test/ui/parser/issues/issue-87217-keyword-order/wrong-const.stderr index 9a3e07b1e87f6..0d2bc3472965f 100644 --- a/src/test/ui/parser/issues/issue-87217-keyword-order/wrong-const.stderr +++ b/src/test/ui/parser/issues/issue-87217-keyword-order/wrong-const.stderr @@ -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 diff --git a/src/test/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe.rs b/src/test/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe.rs index 7f0761e99386a..df2412e3e9b32 100644 --- a/src/test/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe.rs +++ b/src/test/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe.rs @@ -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` diff --git a/src/test/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe.stderr b/src/test/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe.stderr index 395ee9fedbc07..4224713ccb53a 100644 --- a/src/test/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe.stderr +++ b/src/test/ui/parser/issues/issue-87217-keyword-order/wrong-unsafe.stderr @@ -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 diff --git a/src/test/ui/typeck/remove-extra-argument.fixed b/src/test/ui/typeck/remove-extra-argument.fixed new file mode 100644 index 0000000000000..a9338c76cdc88 --- /dev/null +++ b/src/test/ui/typeck/remove-extra-argument.fixed @@ -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 +} diff --git a/src/test/ui/typeck/remove-extra-argument.rs b/src/test/ui/typeck/remove-extra-argument.rs new file mode 100644 index 0000000000000..659cb8b267fd5 --- /dev/null +++ b/src/test/ui/typeck/remove-extra-argument.rs @@ -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 +} diff --git a/src/test/ui/typeck/remove-extra-argument.stderr b/src/test/ui/typeck/remove-extra-argument.stderr new file mode 100644 index 0000000000000..815297765c18c --- /dev/null +++ b/src/test/ui/typeck/remove-extra-argument.stderr @@ -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`.