From a63b5d3c846b74b917b8029aa00cb448faba409f Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 18 Jul 2022 20:30:07 +0200 Subject: [PATCH 01/77] feat: Only flycheck workspace that belongs to saved file --- crates/flycheck/src/lib.rs | 7 ++- crates/paths/src/lib.rs | 8 ++++ crates/rust-analyzer/src/main_loop.rs | 62 ++++++++++++++++++++++++--- 3 files changed, 70 insertions(+), 7 deletions(-) diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs index f683fe61fe3..973f2a53c1a 100644 --- a/crates/flycheck/src/lib.rs +++ b/crates/flycheck/src/lib.rs @@ -55,6 +55,7 @@ pub struct FlycheckHandle { // XXX: drop order is significant sender: Sender, _thread: jod_thread::JoinHandle, + id: usize, } impl FlycheckHandle { @@ -70,13 +71,17 @@ impl FlycheckHandle { .name("Flycheck".to_owned()) .spawn(move || actor.run(receiver)) .expect("failed to spawn thread"); - FlycheckHandle { sender, _thread: thread } + FlycheckHandle { id, sender, _thread: thread } } /// Schedule a re-start of the cargo check worker. pub fn update(&self) { self.sender.send(Restart).unwrap(); } + + pub fn id(&self) -> usize { + self.id + } } pub enum Message { diff --git a/crates/paths/src/lib.rs b/crates/paths/src/lib.rs index b4beb40e746..cf06bf0c27b 100644 --- a/crates/paths/src/lib.rs +++ b/crates/paths/src/lib.rs @@ -103,6 +103,14 @@ impl AsRef for AbsPath { } } +impl ToOwned for AbsPath { + type Owned = AbsPathBuf; + + fn to_owned(&self) -> Self::Owned { + AbsPathBuf(self.0.to_owned()) + } +} + impl<'a> TryFrom<&'a Path> for &'a AbsPath { type Error = &'a Path; fn try_from(path: &'a Path) -> Result<&'a AbsPath, &'a Path> { diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 49b83941119..262c30f132c 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -2,6 +2,7 @@ //! requests/replies and notifications back to the client. use std::{ fmt, + ops::Deref, sync::Arc, time::{Duration, Instant}, }; @@ -720,13 +721,62 @@ impl GlobalState { Ok(()) })? .on::(|this, params| { - for flycheck in &this.flycheck { - flycheck.update(); + let mut updated = false; + if let Ok(vfs_path) = from_proto::vfs_path(¶ms.text_document.uri) { + let (vfs, _) = &*this.vfs.read(); + if let Some(file_id) = vfs.file_id(&vfs_path) { + let analysis = this.analysis_host.analysis(); + let crate_ids = analysis.crate_for(file_id)?; + + let paths: Vec<_> = crate_ids + .iter() + .filter_map(|&crate_id| { + analysis + .crate_root(crate_id) + .map(|file_id| { + vfs.file_path(file_id).as_path().map(ToOwned::to_owned) + }) + .transpose() + }) + .collect::>()?; + let paths: Vec<_> = paths.iter().map(Deref::deref).collect(); + + let workspace_ids = + this.workspaces.iter().enumerate().filter(|(_, ws)| match ws { + project_model::ProjectWorkspace::Cargo { cargo, .. } => { + cargo.packages().filter(|&pkg| cargo[pkg].is_member).any( + |pkg| { + cargo[pkg].targets.iter().any(|&it| { + paths.contains(&cargo[it].root.as_path()) + }) + }, + ) + } + project_model::ProjectWorkspace::Json { project, .. } => project + .crates() + .any(|(c, _)| crate_ids.iter().any(|&crate_id| crate_id == c)), + project_model::ProjectWorkspace::DetachedFiles { .. } => false, + }); + 'workspace: for (id, _) in workspace_ids { + for flycheck in &this.flycheck { + if id == flycheck.id() { + updated = true; + flycheck.update(); + continue 'workspace; + } + } + } + } + if let Some(abs_path) = vfs_path.as_path() { + if reload::should_refresh_for_change(&abs_path, ChangeKind::Modify) { + this.fetch_workspaces_queue + .request_op(format!("DidSaveTextDocument {}", abs_path.display())); + } + } } - if let Ok(abs_path) = from_proto::abs_path(¶ms.text_document.uri) { - if reload::should_refresh_for_change(&abs_path, ChangeKind::Modify) { - this.fetch_workspaces_queue - .request_op(format!("DidSaveTextDocument {}", abs_path.display())); + if !updated { + for flycheck in &this.flycheck { + flycheck.update(); } } Ok(()) From 25391e6d44e3dc740349198c309e08782691da7e Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 20 Jul 2022 11:49:36 +0200 Subject: [PATCH 02/77] Only clear diagnostics of workspaces who have been flychecked --- crates/flycheck/src/lib.rs | 8 ++++--- crates/rust-analyzer/src/diagnostics.rs | 27 ++++++++++++++++++------ crates/rust-analyzer/src/global_state.rs | 1 + crates/rust-analyzer/src/handlers.rs | 4 +++- crates/rust-analyzer/src/main_loop.rs | 5 +++-- crates/rust-analyzer/src/reload.rs | 2 +- 6 files changed, 33 insertions(+), 14 deletions(-) diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs index 973f2a53c1a..7f14fe5798a 100644 --- a/crates/flycheck/src/lib.rs +++ b/crates/flycheck/src/lib.rs @@ -86,7 +86,7 @@ impl FlycheckHandle { pub enum Message { /// Request adding a diagnostic with fixes included to a file - AddDiagnostic { workspace_root: AbsPathBuf, diagnostic: Diagnostic }, + AddDiagnostic { id: usize, workspace_root: AbsPathBuf, diagnostic: Diagnostic }, /// Request check progress notification to client Progress { @@ -99,8 +99,9 @@ pub enum Message { impl fmt::Debug for Message { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Message::AddDiagnostic { workspace_root, diagnostic } => f + Message::AddDiagnostic { id, workspace_root, diagnostic } => f .debug_struct("AddDiagnostic") + .field("id", id) .field("workspace_root", workspace_root) .field("diagnostic_code", &diagnostic.code.as_ref().map(|it| &it.code)) .finish(), @@ -186,7 +187,7 @@ impl FlycheckActor { } } Event::CheckEvent(None) => { - tracing::debug!("flycheck finished"); + tracing::debug!(flycheck_id = self.id, "flycheck finished"); // Watcher finished let cargo_handle = self.cargo_handle.take().unwrap(); @@ -206,6 +207,7 @@ impl FlycheckActor { CargoMessage::Diagnostic(msg) => { self.send(Message::AddDiagnostic { + id: self.id, workspace_root: self.workspace_root.clone(), diagnostic: msg, }); diff --git a/crates/rust-analyzer/src/diagnostics.rs b/crates/rust-analyzer/src/diagnostics.rs index 202a01adf71..7917ced666a 100644 --- a/crates/rust-analyzer/src/diagnostics.rs +++ b/crates/rust-analyzer/src/diagnostics.rs @@ -8,7 +8,7 @@ use rustc_hash::{FxHashMap, FxHashSet}; use crate::lsp_ext; -pub(crate) type CheckFixes = Arc>>; +pub(crate) type CheckFixes = Arc>>>; #[derive(Debug, Default, Clone)] pub struct DiagnosticsMapConfig { @@ -22,7 +22,7 @@ pub(crate) struct DiagnosticCollection { // FIXME: should be FxHashMap> pub(crate) native: FxHashMap>, // FIXME: should be Vec - pub(crate) check: FxHashMap>, + pub(crate) check: FxHashMap>>, pub(crate) check_fixes: CheckFixes, changes: FxHashSet, } @@ -35,9 +35,19 @@ pub(crate) struct Fix { } impl DiagnosticCollection { - pub(crate) fn clear_check(&mut self) { + pub(crate) fn clear_check(&mut self, flycheck_id: usize) { + if let Some(it) = Arc::make_mut(&mut self.check_fixes).get_mut(&flycheck_id) { + it.clear(); + } + if let Some(it) = self.check.get_mut(&flycheck_id) { + self.changes.extend(it.drain().map(|(key, _value)| key)); + } + } + + pub(crate) fn clear_check_all(&mut self) { Arc::make_mut(&mut self.check_fixes).clear(); - self.changes.extend(self.check.drain().map(|(key, _value)| key)) + self.changes + .extend(self.check.values_mut().flat_map(|it| it.drain().map(|(key, _value)| key))) } pub(crate) fn clear_native_for(&mut self, file_id: FileId) { @@ -47,11 +57,12 @@ impl DiagnosticCollection { pub(crate) fn add_check_diagnostic( &mut self, + flycheck_id: usize, file_id: FileId, diagnostic: lsp_types::Diagnostic, fix: Option, ) { - let diagnostics = self.check.entry(file_id).or_default(); + let diagnostics = self.check.entry(flycheck_id).or_default().entry(file_id).or_default(); for existing_diagnostic in diagnostics.iter() { if are_diagnostics_equal(existing_diagnostic, &diagnostic) { return; @@ -59,8 +70,9 @@ impl DiagnosticCollection { } let check_fixes = Arc::make_mut(&mut self.check_fixes); - check_fixes.entry(file_id).or_default().extend(fix); + check_fixes.entry(flycheck_id).or_default().entry(file_id).or_default().extend(fix); diagnostics.push(diagnostic); + tracing::warn!(?flycheck_id, ?file_id, "add_check_diagnostic changes pushed"); self.changes.insert(file_id); } @@ -89,7 +101,8 @@ impl DiagnosticCollection { file_id: FileId, ) -> impl Iterator { let native = self.native.get(&file_id).into_iter().flatten(); - let check = self.check.get(&file_id).into_iter().flatten(); + let check = + self.check.values().filter_map(move |it| it.get(&file_id)).into_iter().flatten(); native.chain(check) } diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index 4af60035a20..2cd2044aeff 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -201,6 +201,7 @@ impl GlobalState { } } + // Clear native diagnostics when their file gets deleted if !file.exists() { self.diagnostics.clear_native_for(file.file_id); } diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index e3875228a18..a64dc57ec64 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs @@ -1094,7 +1094,9 @@ pub(crate) fn handle_code_action( } // Fixes from `cargo check`. - for fix in snap.check_fixes.get(&frange.file_id).into_iter().flatten() { + for fix in + snap.check_fixes.values().filter_map(|it| it.get(&frange.file_id)).into_iter().flatten() + { // FIXME: this mapping is awkward and shouldn't exist. Refactor // `snap.check_fixes` to not convert to LSP prematurely. let intersect_fix_range = fix diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 262c30f132c..572466cdfa7 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -372,7 +372,7 @@ impl GlobalState { let _p = profile::span("GlobalState::handle_event/flycheck"); loop { match task { - flycheck::Message::AddDiagnostic { workspace_root, diagnostic } => { + flycheck::Message::AddDiagnostic { id, workspace_root, diagnostic } => { let snap = self.snapshot(); let diagnostics = crate::diagnostics::to_proto::map_rust_diagnostic_to_lsp( @@ -384,6 +384,7 @@ impl GlobalState { for diag in diagnostics { match url_to_file_id(&self.vfs.read().0, &diag.url) { Ok(file_id) => self.diagnostics.add_check_diagnostic( + id, file_id, diag.diagnostic, diag.fix, @@ -401,7 +402,7 @@ impl GlobalState { flycheck::Message::Progress { id, progress } => { let (state, message) = match progress { flycheck::Progress::DidStart => { - self.diagnostics.clear_check(); + self.diagnostics.clear_check(id); (Progress::Begin, None) } flycheck::Progress::DidCheckCrate(target) => { diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 13bcb7dfa23..579ba380273 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -417,7 +417,7 @@ impl GlobalState { Some(it) => it, None => { self.flycheck = Vec::new(); - self.diagnostics.clear_check(); + self.diagnostics.clear_check_all(); return; } }; From d73b0d5fc6c6be434bd0e31ddc6572a6efaf6400 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 20 Jul 2022 11:52:44 +0200 Subject: [PATCH 03/77] Don't filter flychecks by package member status --- crates/rust-analyzer/src/main_loop.rs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 572466cdfa7..561c2d7aef7 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -745,25 +745,24 @@ impl GlobalState { let workspace_ids = this.workspaces.iter().enumerate().filter(|(_, ws)| match ws { project_model::ProjectWorkspace::Cargo { cargo, .. } => { - cargo.packages().filter(|&pkg| cargo[pkg].is_member).any( - |pkg| { - cargo[pkg].targets.iter().any(|&it| { - paths.contains(&cargo[it].root.as_path()) - }) - }, - ) + cargo.packages().any(|pkg| { + cargo[pkg] + .targets + .iter() + .any(|&it| paths.contains(&cargo[it].root.as_path())) + }) } project_model::ProjectWorkspace::Json { project, .. } => project .crates() .any(|(c, _)| crate_ids.iter().any(|&crate_id| crate_id == c)), project_model::ProjectWorkspace::DetachedFiles { .. } => false, }); - 'workspace: for (id, _) in workspace_ids { - for flycheck in &this.flycheck { + for flycheck in &this.flycheck { + for (id, _) in workspace_ids.clone() { if id == flycheck.id() { updated = true; flycheck.update(); - continue 'workspace; + continue; } } } From 177af4710464d9f743d64f8792afcb0ee553ba6b Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Wed, 27 Apr 2022 18:14:19 +0400 Subject: [PATCH 04/77] Implement `#[rustc_default_body_unstable]` This attribute allows to mark default body of a trait function as unstable. This means that implementing the trait without implementing the function will require enabling unstable feature. This is useful in conjunction with `#[rustc_must_implement_one_of]`, we may want to relax requirements for a trait, for example allowing implementing either of `PartialEq::{eq, ne}`, but do so in a safe way -- making implementation of only `PartialEq::ne` unstable. --- compiler/rustc_ast_passes/src/feature_gate.rs | 1 + compiler/rustc_attr/src/builtin.rs | 31 +++++++-- compiler/rustc_expand/src/base.rs | 13 +++- compiler/rustc_feature/src/builtin_attrs.rs | 4 ++ .../src/rmeta/decoder/cstore_impl.rs | 1 + compiler/rustc_metadata/src/rmeta/encoder.rs | 13 ++++ compiler/rustc_metadata/src/rmeta/mod.rs | 1 + compiler/rustc_middle/src/middle/stability.rs | 64 ++++++++++++++++++- compiler/rustc_middle/src/query/mod.rs | 5 ++ compiler/rustc_middle/src/ty/parameterized.rs | 1 + compiler/rustc_passes/src/stability.rs | 36 +++++++++-- compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_typeck/src/check/check.rs | 30 +++++++-- compiler/rustc_typeck/src/check/mod.rs | 22 ++++++- 14 files changed, 206 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index ad9ed798e55..3b58996e501 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -417,6 +417,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { || attr.has_name(sym::stable) || attr.has_name(sym::rustc_const_unstable) || attr.has_name(sym::rustc_const_stable) + || attr.has_name(sym::rustc_default_body_unstable) { struct_span_err!( self.sess, diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 10a9cfb626e..2eb50d64802 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -131,6 +131,14 @@ impl ConstStability { } } +/// Represents the `#[rustc_default_body_unstable]` attribute. +#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(HashStable_Generic)] +pub struct DefaultBodyStability { + pub level: StabilityLevel, + pub feature: Symbol, +} + /// The available stability levels. #[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)] #[derive(HashStable_Generic)] @@ -214,7 +222,8 @@ pub fn find_stability( sess: &Session, attrs: &[Attribute], item_sp: Span, -) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>) { +) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>, Option<(DefaultBodyStability, Span)>) +{ find_stability_generic(sess, attrs.iter(), item_sp) } @@ -222,7 +231,7 @@ fn find_stability_generic<'a, I>( sess: &Session, attrs_iter: I, item_sp: Span, -) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>) +) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>, Option<(DefaultBodyStability, Span)>) where I: Iterator, { @@ -230,6 +239,7 @@ where let mut stab: Option<(Stability, Span)> = None; let mut const_stab: Option<(ConstStability, Span)> = None; + let mut body_stab: Option<(DefaultBodyStability, Span)> = None; let mut promotable = false; let mut allowed_through_unstable_modules = false; @@ -243,6 +253,7 @@ where sym::stable, sym::rustc_promotable, sym::rustc_allowed_through_unstable_modules, + sym::rustc_default_body_unstable, ] .iter() .any(|&s| attr.has_name(s)) @@ -280,7 +291,7 @@ where let meta_name = meta.name_or_empty(); match meta_name { - sym::rustc_const_unstable | sym::unstable => { + sym::rustc_const_unstable | sym::rustc_default_body_unstable | sym::unstable => { if meta_name == sym::unstable && stab.is_some() { handle_errors( &sess.parse_sess, @@ -295,6 +306,13 @@ where AttrError::MultipleStabilityLevels, ); break; + } else if meta_name == sym::rustc_default_body_unstable && body_stab.is_some() { + handle_errors( + &sess.parse_sess, + attr.span, + AttrError::MultipleStabilityLevels, + ); + break; } let mut feature = None; @@ -405,11 +423,14 @@ where }; if sym::unstable == meta_name { stab = Some((Stability { level, feature }, attr.span)); - } else { + } else if sym::rustc_const_unstable == meta_name { const_stab = Some(( ConstStability { level, feature, promotable: false }, attr.span, )); + } else { + body_stab = + Some((DefaultBodyStability { level, feature }, attr.span)); } } (None, _, _) => { @@ -542,7 +563,7 @@ where } } - (stab, const_stab) + (stab, const_stab, body_stab) } pub fn find_crate_name(sess: &Session, attrs: &[Attribute]) -> Option { diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 6e093811fcf..852ea806b20 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -772,7 +772,7 @@ impl SyntaxExtension { ) }) .unwrap_or_else(|| (None, helper_attrs)); - let (stability, const_stability) = attr::find_stability(&sess, attrs, span); + let (stability, const_stability, body_stability) = attr::find_stability(&sess, attrs, span); if let Some((_, sp)) = const_stability { sess.parse_sess .span_diagnostic @@ -784,6 +784,17 @@ impl SyntaxExtension { ) .emit(); } + if let Some((_, sp)) = body_stability { + sess.parse_sess + .span_diagnostic + .struct_span_err(sp, "macros cannot have body stability attributes") + .span_label(sp, "invalid body stability attribute") + .span_label( + sess.source_map().guess_head_span(span), + "body stability attribute affects this macro", + ) + .emit(); + } SyntaxExtension { kind, diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index c806df82145..d8fd627c100 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -499,6 +499,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), ungated!(rustc_const_unstable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk), ungated!(rustc_const_stable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk), + ungated!( + rustc_default_body_unstable, Normal, + template!(List: r#"feature = "name", reason = "...", issue = "N""#), DuplicatesOk + ), gated!( allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."), DuplicatesOk, "allow_internal_unstable side-steps feature gating and stability checks", diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 65cae29c58d..35a6719a2fb 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -207,6 +207,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, def_ident_span => { table } lookup_stability => { table } lookup_const_stability => { table } + lookup_default_body_stability => { table } lookup_deprecation_entry => { table } visibility => { table } unused_generic_params => { table } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 50d983754e8..f30f139584a 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1029,6 +1029,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { if should_encode_stability(def_kind) { self.encode_stability(def_id); self.encode_const_stability(def_id); + self.encode_default_body_stability(def_id); self.encode_deprecation(def_id); } if should_encode_variances(def_kind) { @@ -1397,6 +1398,18 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } + fn encode_default_body_stability(&mut self, def_id: DefId) { + debug!("EncodeContext::encode_default_body_stability({:?})", def_id); + + // The query lookup can take a measurable amount of time in crates with many items. Check if + // the stability attributes are even enabled before using their queries. + if self.feat.staged_api || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked { + if let Some(stab) = self.tcx.lookup_default_body_stability(def_id) { + record!(self.tables.lookup_default_body_stability[def_id] <- stab) + } + } + } + fn encode_deprecation(&mut self, def_id: DefId) { debug!("EncodeContext::encode_deprecation({:?})", def_id); if let Some(depr) = self.tcx.lookup_deprecation(def_id) { diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 0f291f92647..a1d3c918ebd 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -343,6 +343,7 @@ define_tables! { def_ident_span: Table>, lookup_stability: Table>, lookup_const_stability: Table>, + lookup_default_body_stability: Table>, lookup_deprecation_entry: Table>, // As an optimization, a missing entry indicates an empty `&[]`. explicit_item_bounds: Table, Span)>>, diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 414912dd0f7..24b74b7f65f 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -5,7 +5,7 @@ pub use self::StabilityLevel::*; use crate::ty::{self, DefIdTree, TyCtxt}; use rustc_ast::NodeId; -use rustc_attr::{self as attr, ConstStability, Deprecation, Stability}; +use rustc_attr::{self as attr, ConstStability, DefaultBodyStability, Deprecation, Stability}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, Diagnostic}; use rustc_feature::GateIssue; @@ -61,6 +61,7 @@ pub struct Index { /// are filled by the annotator. pub stab_map: FxHashMap, pub const_stab_map: FxHashMap, + pub default_body_stab_map: FxHashMap, pub depr_map: FxHashMap, /// Mapping from feature name to feature name based on the `implied_by` field of `#[unstable]` /// attributes. If a `#[unstable(feature = "implier", implied_by = "impliee")]` attribute @@ -86,6 +87,10 @@ impl Index { self.const_stab_map.get(&def_id).copied() } + pub fn local_default_body_stability(&self, def_id: LocalDefId) -> Option { + self.default_body_stab_map.get(&def_id).copied() + } + pub fn local_deprecation_entry(&self, def_id: LocalDefId) -> Option { self.depr_map.get(&def_id).cloned() } @@ -492,6 +497,63 @@ impl<'tcx> TyCtxt<'tcx> { } } + /// Evaluates the default-impl stability of an item. + /// + /// Returns `EvalResult::Allow` if the item's default implementation is stable, or unstable but the corresponding + /// `#![feature]` has been provided. Returns `EvalResult::Deny` which describes the offending + /// unstable feature otherwise. + pub fn eval_default_body_stability(self, def_id: DefId, span: Span) -> EvalResult { + let is_staged_api = self.lookup_stability(def_id.krate.as_def_id()).is_some(); + if !is_staged_api { + return EvalResult::Allow; + } + + let stability = self.lookup_default_body_stability(def_id); + debug!( + "body stability: inspecting def_id={def_id:?} span={span:?} of stability={stability:?}" + ); + + // Only the cross-crate scenario matters when checking unstable APIs + let cross_crate = !def_id.is_local(); + if !cross_crate { + return EvalResult::Allow; + } + + // Issue #38412: private items lack stability markers. + if skip_stability_check_due_to_privacy(self, def_id) { + return EvalResult::Allow; + } + + match stability { + Some(DefaultBodyStability { + level: attr::Unstable { reason, issue, is_soft, .. }, + feature, + }) => { + if span.allows_unstable(feature) { + debug!("body stability: skipping span={:?} since it is internal", span); + return EvalResult::Allow; + } + if self.features().active(feature) { + return EvalResult::Allow; + } + + //let suggestion = suggestion_for_allocator_api(self, def_id, span, feature); + EvalResult::Deny { + feature, + reason: reason.to_opt_reason(), + issue, + suggestion: None, + is_soft, + } + } + Some(_) => { + // Stable APIs are always ok to call + EvalResult::Allow + } + None => EvalResult::Unmarked, + } + } + /// Checks if an item is stable or error out. /// /// If the item defined by `def_id` is unstable and the corresponding `#![feature]` does not diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 466a0fc25f7..0d03f506aac 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1094,6 +1094,11 @@ rustc_queries! { separate_provide_extern } + query lookup_default_body_stability(def_id: DefId) -> Option { + desc { |tcx| "looking up default body stability of `{}`", tcx.def_path_str(def_id) } + separate_provide_extern + } + query should_inherit_track_caller(def_id: DefId) -> bool { desc { |tcx| "computing should_inherit_track_caller of `{}`", tcx.def_path_str(def_id) } } diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index e189ee2fc4d..ae6e2eecbff 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -64,6 +64,7 @@ trivially_parameterized_over_tcx! { rustc_ast::Attribute, rustc_ast::MacArgs, rustc_attr::ConstStability, + rustc_attr::DefaultBodyStability, rustc_attr::Deprecation, rustc_attr::Stability, rustc_hir::Constness, diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index ca6a2ac3db3..2a3da4ec30e 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -1,8 +1,10 @@ //! A pass that annotates every item and method with its stability level, //! propagating default levels lexically from parent to children ast nodes. -use attr::StabilityLevel; -use rustc_attr::{self as attr, ConstStability, Stability, Unstable, UnstableReason}; +use rustc_attr::{ + self as attr, ConstStability, DefaultBodyStability, Stability, StabilityLevel, Unstable, + UnstableReason, +}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_errors::{struct_span_err, Applicability}; use rustc_hir as hir; @@ -89,6 +91,7 @@ struct Annotator<'a, 'tcx> { index: &'a mut Index, parent_stab: Option, parent_const_stab: Option, + parent_body_stab: Option, parent_depr: Option, in_trait_impl: bool, } @@ -156,12 +159,13 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { depr.map(|(d, _)| DeprecationEntry::local(d, def_id)), None, None, + None, visit_children, ); return; } - let (stab, const_stab) = attr::find_stability(&self.tcx.sess, attrs, item_sp); + let (stab, const_stab, body_stab) = attr::find_stability(&self.tcx.sess, attrs, item_sp); let mut const_span = None; let const_stab = const_stab.map(|(const_stab, const_span_node)| { @@ -209,6 +213,15 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } } + let body_stab = body_stab.map(|(body_stab, _span)| { + // FIXME: check that this item can have body stability + + self.index.default_body_stab_map.insert(def_id, body_stab); + debug!(?self.index.default_body_stab_map); + + body_stab + }); + let stab = stab.map(|(stab, span)| { // Error if prohibited, or can't inherit anything from a container. if kind == AnnotationKind::Prohibited @@ -286,6 +299,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { depr.map(|(d, _)| DeprecationEntry::local(d, def_id)), stab, if inherit_const_stability.yes() { const_stab } else { None }, + body_stab, visit_children, ); } @@ -295,12 +309,14 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { depr: Option, stab: Option, const_stab: Option, + body_stab: Option, f: impl FnOnce(&mut Self), ) { // These will be `Some` if this item changes the corresponding stability attribute. let mut replaced_parent_depr = None; let mut replaced_parent_stab = None; let mut replaced_parent_const_stab = None; + let mut replaced_parent_body_stab = None; if let Some(depr) = depr { replaced_parent_depr = Some(replace(&mut self.parent_depr, Some(depr))); @@ -312,6 +328,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { replaced_parent_const_stab = Some(replace(&mut self.parent_const_stab, Some(const_stab))); } + if let Some(body_stab) = body_stab { + replaced_parent_body_stab = Some(self.parent_body_stab.replace(body_stab)); + } f(self); @@ -324,6 +343,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { if let Some(orig_parent_const_stab) = replaced_parent_const_stab { self.parent_const_stab = orig_parent_const_stab; } + if let Some(orig_parent_body_stab) = replaced_parent_body_stab { + self.parent_body_stab = orig_parent_body_stab; + } } } @@ -613,6 +635,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { let mut index = Index { stab_map: Default::default(), const_stab_map: Default::default(), + default_body_stab_map: Default::default(), depr_map: Default::default(), implications: Default::default(), }; @@ -623,6 +646,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { index: &mut index, parent_stab: None, parent_const_stab: None, + parent_body_stab: None, parent_depr: None, in_trait_impl: false, }; @@ -673,6 +697,9 @@ pub(crate) fn provide(providers: &mut Providers) { stability_implications: |tcx, _| tcx.stability().implications.clone(), lookup_stability: |tcx, id| tcx.stability().local_stability(id.expect_local()), lookup_const_stability: |tcx, id| tcx.stability().local_const_stability(id.expect_local()), + lookup_default_body_stability: |tcx, id| { + tcx.stability().local_default_body_stability(id.expect_local()) + }, lookup_deprecation_entry: |tcx, id| { tcx.stability().local_deprecation_entry(id.expect_local()) }, @@ -723,7 +750,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { let features = self.tcx.features(); if features.staged_api { let attrs = self.tcx.hir().attrs(item.hir_id()); - let (stab, const_stab) = attr::find_stability(&self.tcx.sess, attrs, item.span); + let (stab, const_stab, _) = + attr::find_stability(&self.tcx.sess, attrs, item.span); // If this impl block has an #[unstable] attribute, give an // error if all involved types and traits are stable, because diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 54d67c52541..036f087e2d2 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1215,6 +1215,7 @@ symbols! { rustc_const_unstable, rustc_conversion_suggestion, rustc_def_path, + rustc_default_body_unstable, rustc_diagnostic_item, rustc_diagnostic_macros, rustc_dirty, diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 9497d5c4528..6254825d96d 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -18,6 +18,7 @@ use rustc_infer::infer::{DefiningAnchor, RegionVariableOrigin, TyCtxtInferExt}; use rustc_infer::traits::Obligation; use rustc_lint::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS; use rustc_middle::hir::nested_filter; +use rustc_middle::middle::stability::EvalResult; use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES}; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::util::{Discr, IntTypeExt}; @@ -1104,12 +1105,31 @@ fn check_impl_items_against_trait<'tcx>( missing_items.push(tcx.associated_item(trait_item_id)); } - if let Some(required_items) = &must_implement_one_of { - // true if this item is specifically implemented in this impl - let is_implemented_here = ancestors - .leaf_def(tcx, trait_item_id) - .map_or(false, |node_item| !node_item.defining_node.is_from_trait()); + // true if this item is specifically implemented in this impl + let is_implemented_here = ancestors + .leaf_def(tcx, trait_item_id) + .map_or(false, |node_item| !node_item.defining_node.is_from_trait()); + if !is_implemented_here { + match tcx.eval_default_body_stability(trait_item_id, full_impl_span) { + EvalResult::Deny { feature, reason, issue, is_soft, .. } => { + default_body_is_unstable( + tcx, + full_impl_span, + trait_item_id, + feature, + reason, + issue, + is_soft, + ) + } + + // Unmarked default bodies are considered stable (at least for now). + EvalResult::Allow | EvalResult::Unmarked => {} + } + } + + if let Some(required_items) = &must_implement_one_of { if is_implemented_here { let trait_item = tcx.associated_item(trait_item_id); if required_items.contains(&trait_item.ident(tcx)) { diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index 17c2e4868aa..acd7e76fe25 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -99,6 +99,7 @@ pub use expectation::Expectation; pub use fn_ctxt::*; use hir::def::CtorOf; pub use inherited::{Inherited, InheritedBuilder}; +use rustc_middle::middle::stability::report_unstable; use crate::astconv::AstConv; use crate::check::gather_locals::GatherLocalsVisitor; @@ -122,13 +123,14 @@ use rustc_session::parse::feature_err; use rustc_session::Session; use rustc_span::source_map::DUMMY_SP; use rustc_span::symbol::{kw, Ident}; -use rustc_span::{self, BytePos, Span}; +use rustc_span::{self, BytePos, Span, Symbol}; use rustc_target::abi::VariantIdx; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits; use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error; use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor; use std::cell::RefCell; +use std::num::NonZeroU32; use crate::require_c_abi_if_c_variadic; use crate::util::common::indenter; @@ -662,6 +664,24 @@ fn missing_items_must_implement_one_of_err( err.emit(); } +fn default_body_is_unstable( + tcx: TyCtxt<'_>, + impl_span: Span, + _item_did: DefId, + feature: Symbol, + reason: Option, + issue: Option, + is_soft: bool, +) { + let soft_handler = |lint, span, msg: &_| { + tcx.struct_span_lint_hir(lint, hir::CRATE_HIR_ID, span, |lint| { + lint.build(msg).emit(); + }) + }; + + report_unstable(tcx.sess, feature, reason, issue, None, is_soft, impl_span, soft_handler) +} + /// Re-sugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions. fn bounds_from_generic_predicates<'tcx>( tcx: TyCtxt<'tcx>, From 9015a5110fd7b887dafaa1007afc02da90963f2a Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Wed, 27 Apr 2022 19:00:17 +0400 Subject: [PATCH 05/77] Collect features from `#[rustc_default_body_unstable]` --- compiler/rustc_passes/src/lib_features.rs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs index e05994f13e4..868887c66cd 100644 --- a/compiler/rustc_passes/src/lib_features.rs +++ b/compiler/rustc_passes/src/lib_features.rs @@ -29,11 +29,16 @@ impl<'tcx> LibFeatureCollector<'tcx> { } fn extract(&self, attr: &Attribute) -> Option<(Symbol, Option, Span)> { - let stab_attrs = - [sym::stable, sym::unstable, sym::rustc_const_stable, sym::rustc_const_unstable]; + let stab_attrs = [ + sym::stable, + sym::unstable, + sym::rustc_const_stable, + sym::rustc_const_unstable, + sym::rustc_default_body_unstable, + ]; // Find a stability attribute: one of #[stable(…)], #[unstable(…)], - // #[rustc_const_stable(…)], or #[rustc_const_unstable(…)]. + // #[rustc_const_stable(…)], #[rustc_const_unstable(…)] or #[rustc_default_body_unstable]. if let Some(stab_attr) = stab_attrs.iter().find(|stab_attr| attr.has_name(**stab_attr)) { let meta_kind = attr.meta_kind(); if let Some(MetaItemKind::List(ref metas)) = meta_kind { @@ -53,8 +58,12 @@ impl<'tcx> LibFeatureCollector<'tcx> { // This additional check for stability is to make sure we // don't emit additional, irrelevant errors for malformed // attributes. - let is_unstable = - matches!(*stab_attr, sym::unstable | sym::rustc_const_unstable); + let is_unstable = matches!( + *stab_attr, + sym::unstable + | sym::rustc_const_unstable + | sym::rustc_default_body_unstable + ); if since.is_some() || is_unstable { return Some((feature, since, attr.span)); } From d65fa276f3f2a239805f8458e210fb92fcfdca24 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Wed, 27 Apr 2022 19:01:05 +0400 Subject: [PATCH 06/77] Add tests for `#[rustc_default_body_unstable]` --- .../auxiliary/default_body.rs | 29 +++++++++++++++++ .../default-body-stability-err.rs | 19 +++++++++++ .../default-body-stability-err.stderr | 32 +++++++++++++++++++ .../default-body-stability-ok-enables.rs | 18 +++++++++++ .../default-body-stability-ok-impls.rs | 21 ++++++++++++ 5 files changed, 119 insertions(+) create mode 100644 src/test/ui/stability-attribute/auxiliary/default_body.rs create mode 100644 src/test/ui/stability-attribute/default-body-stability-err.rs create mode 100644 src/test/ui/stability-attribute/default-body-stability-err.stderr create mode 100644 src/test/ui/stability-attribute/default-body-stability-ok-enables.rs create mode 100644 src/test/ui/stability-attribute/default-body-stability-ok-impls.rs diff --git a/src/test/ui/stability-attribute/auxiliary/default_body.rs b/src/test/ui/stability-attribute/auxiliary/default_body.rs new file mode 100644 index 00000000000..3a177419d66 --- /dev/null +++ b/src/test/ui/stability-attribute/auxiliary/default_body.rs @@ -0,0 +1,29 @@ +#![crate_type = "lib"] +#![feature(staged_api, rustc_attrs)] +#![stable(feature = "stable_feature", since = "1.0.0")] + +#[stable(feature = "stable_feature", since = "1.0.0")] +pub trait JustTrait { + #[stable(feature = "stable_feature", since = "1.0.0")] + #[rustc_default_body_unstable(feature = "constant_default_body", issue = "none")] + const CONSTANT: usize = 0; + + #[rustc_default_body_unstable(feature = "fun_default_body", issue = "none")] + #[stable(feature = "stable_feature", since = "1.0.0")] + fn fun() {} +} + +#[rustc_must_implement_one_of(eq, neq)] +#[stable(feature = "stable_feature", since = "1.0.0")] +pub trait Equal { + #[rustc_default_body_unstable(feature = "eq_default_body", issue = "none")] + #[stable(feature = "stable_feature", since = "1.0.0")] + fn eq(&self, other: &Self) -> bool { + !self.neq(other) + } + + #[stable(feature = "stable_feature", since = "1.0.0")] + fn neq(&self, other: &Self) -> bool { + !self.eq(other) + } +} diff --git a/src/test/ui/stability-attribute/default-body-stability-err.rs b/src/test/ui/stability-attribute/default-body-stability-err.rs new file mode 100644 index 00000000000..8f970d0c9f6 --- /dev/null +++ b/src/test/ui/stability-attribute/default-body-stability-err.rs @@ -0,0 +1,19 @@ +// aux-build:default_body.rs +#![crate_type = "lib"] + +extern crate default_body; + +use default_body::{Equal, JustTrait}; + +struct Type; + +impl JustTrait for Type {} +//~^ ERROR use of unstable library feature 'fun_default_body' +//~| ERROR use of unstable library feature 'constant_default_body' + +impl Equal for Type { + //~^ ERROR use of unstable library feature 'eq_default_body' + fn neq(&self, other: &Self) -> bool { + false + } +} diff --git a/src/test/ui/stability-attribute/default-body-stability-err.stderr b/src/test/ui/stability-attribute/default-body-stability-err.stderr new file mode 100644 index 00000000000..6abf68bbcae --- /dev/null +++ b/src/test/ui/stability-attribute/default-body-stability-err.stderr @@ -0,0 +1,32 @@ +error[E0658]: use of unstable library feature 'constant_default_body' + --> $DIR/default-body-stability-err.rs:10:1 + | +LL | impl JustTrait for Type {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(constant_default_body)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'fun_default_body' + --> $DIR/default-body-stability-err.rs:10:1 + | +LL | impl JustTrait for Type {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(fun_default_body)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'eq_default_body' + --> $DIR/default-body-stability-err.rs:14:1 + | +LL | / impl Equal for Type { +LL | | +LL | | fn neq(&self, other: &Self) -> bool { +LL | | false +LL | | } +LL | | } + | |_^ + | + = help: add `#![feature(eq_default_body)]` to the crate attributes to enable + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/stability-attribute/default-body-stability-ok-enables.rs b/src/test/ui/stability-attribute/default-body-stability-ok-enables.rs new file mode 100644 index 00000000000..bdc7522f48d --- /dev/null +++ b/src/test/ui/stability-attribute/default-body-stability-ok-enables.rs @@ -0,0 +1,18 @@ +// check-pass +// aux-build:default_body.rs +#![crate_type = "lib"] +#![feature(fun_default_body, eq_default_body, constant_default_body)] + +extern crate default_body; + +use default_body::{Equal, JustTrait}; + +struct Type; + +impl JustTrait for Type {} + +impl Equal for Type { + fn neq(&self, other: &Self) -> bool { + false + } +} diff --git a/src/test/ui/stability-attribute/default-body-stability-ok-impls.rs b/src/test/ui/stability-attribute/default-body-stability-ok-impls.rs new file mode 100644 index 00000000000..e1f5c017096 --- /dev/null +++ b/src/test/ui/stability-attribute/default-body-stability-ok-impls.rs @@ -0,0 +1,21 @@ +// check-pass +// aux-build:default_body.rs +#![crate_type = "lib"] + +extern crate default_body; + +use default_body::{Equal, JustTrait}; + +struct Type; + +impl JustTrait for Type { + const CONSTANT: usize = 1; + + fn fun() {} +} + +impl Equal for Type { + fn eq(&self, other: &Self) -> bool { + false + } +} From 198443711501234a5d98b6d621aae2cead73c8cb Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 20 Jun 2022 15:24:04 +0400 Subject: [PATCH 07/77] remove commented out code --- compiler/rustc_middle/src/middle/stability.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 24b74b7f65f..0d1223ed289 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -537,7 +537,6 @@ impl<'tcx> TyCtxt<'tcx> { return EvalResult::Allow; } - //let suggestion = suggestion_for_allocator_api(self, def_id, span, feature); EvalResult::Deny { feature, reason: reason.to_opt_reason(), From 1e1d6fe84dd086a9075fcfe5fc63d81738c02f12 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 20 Jun 2022 16:07:14 +0400 Subject: [PATCH 08/77] Improve error message for unstable default body --- Cargo.lock | 1 + compiler/rustc_typeck/Cargo.toml | 1 + compiler/rustc_typeck/src/check/check.rs | 19 ++++++------- compiler/rustc_typeck/src/check/mod.rs | 28 +++++++++++++------ .../default-body-stability-err.rs | 6 ++-- .../default-body-stability-err.stderr | 14 +++++++--- 6 files changed, 43 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ed3e30342f2..bb7598bbf3e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4616,6 +4616,7 @@ dependencies = [ "rustc_attr", "rustc_data_structures", "rustc_errors", + "rustc_feature", "rustc_graphviz", "rustc_hir", "rustc_hir_pretty", diff --git a/compiler/rustc_typeck/Cargo.toml b/compiler/rustc_typeck/Cargo.toml index faf52e2695a..cae29c1d3c5 100644 --- a/compiler/rustc_typeck/Cargo.toml +++ b/compiler/rustc_typeck/Cargo.toml @@ -30,3 +30,4 @@ rustc_ty_utils = { path = "../rustc_ty_utils" } rustc_lint = { path = "../rustc_lint" } rustc_serialize = { path = "../rustc_serialize" } rustc_type_ir = { path = "../rustc_type_ir" } +rustc_feature = { path = "../rustc_feature" } diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 6254825d96d..0293bf7803a 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -1112,17 +1112,14 @@ fn check_impl_items_against_trait<'tcx>( if !is_implemented_here { match tcx.eval_default_body_stability(trait_item_id, full_impl_span) { - EvalResult::Deny { feature, reason, issue, is_soft, .. } => { - default_body_is_unstable( - tcx, - full_impl_span, - trait_item_id, - feature, - reason, - issue, - is_soft, - ) - } + EvalResult::Deny { feature, reason, issue, .. } => default_body_is_unstable( + tcx, + full_impl_span, + trait_item_id, + feature, + reason, + issue, + ), // Unmarked default bodies are considered stable (at least for now). EvalResult::Allow | EvalResult::Unmarked => {} diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index acd7e76fe25..b5201c737df 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -99,7 +99,6 @@ pub use expectation::Expectation; pub use fn_ctxt::*; use hir::def::CtorOf; pub use inherited::{Inherited, InheritedBuilder}; -use rustc_middle::middle::stability::report_unstable; use crate::astconv::AstConv; use crate::check::gather_locals::GatherLocalsVisitor; @@ -667,19 +666,32 @@ fn missing_items_must_implement_one_of_err( fn default_body_is_unstable( tcx: TyCtxt<'_>, impl_span: Span, - _item_did: DefId, + item_did: DefId, feature: Symbol, reason: Option, issue: Option, - is_soft: bool, ) { - let soft_handler = |lint, span, msg: &_| { - tcx.struct_span_lint_hir(lint, hir::CRATE_HIR_ID, span, |lint| { - lint.build(msg).emit(); - }) + let missing_item_name = &tcx.associated_item(item_did).name; + let use_of_unstable_library_feature_note = match reason { + Some(r) => format!("use of unstable library feature '{feature}': {r}"), + None => format!("use of unstable library feature '{feature}'"), }; - report_unstable(tcx.sess, feature, reason, issue, None, is_soft, impl_span, soft_handler) + let mut err = struct_span_err!( + tcx.sess, + impl_span, + E0046, + "not all trait items implemented, missing: `{missing_item_name}`", + ); + err.note(format!("default implementation of `{missing_item_name}` is unstable")); + err.note(use_of_unstable_library_feature_note); + rustc_session::parse::add_feature_diagnostics_for_issue( + &mut err, + &tcx.sess.parse_sess, + feature, + rustc_feature::GateIssue::Library(issue), + ); + err.emit(); } /// Re-sugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions. diff --git a/src/test/ui/stability-attribute/default-body-stability-err.rs b/src/test/ui/stability-attribute/default-body-stability-err.rs index 8f970d0c9f6..ecb281bccf6 100644 --- a/src/test/ui/stability-attribute/default-body-stability-err.rs +++ b/src/test/ui/stability-attribute/default-body-stability-err.rs @@ -8,11 +8,11 @@ use default_body::{Equal, JustTrait}; struct Type; impl JustTrait for Type {} -//~^ ERROR use of unstable library feature 'fun_default_body' -//~| ERROR use of unstable library feature 'constant_default_body' +//~^ ERROR not all trait items implemented, missing: `CONSTANT` [E0046] +//~| ERROR not all trait items implemented, missing: `fun` [E0046] impl Equal for Type { - //~^ ERROR use of unstable library feature 'eq_default_body' + //~^ ERROR not all trait items implemented, missing: `eq` [E0046] fn neq(&self, other: &Self) -> bool { false } diff --git a/src/test/ui/stability-attribute/default-body-stability-err.stderr b/src/test/ui/stability-attribute/default-body-stability-err.stderr index 6abf68bbcae..ef666f30fc2 100644 --- a/src/test/ui/stability-attribute/default-body-stability-err.stderr +++ b/src/test/ui/stability-attribute/default-body-stability-err.stderr @@ -1,20 +1,24 @@ -error[E0658]: use of unstable library feature 'constant_default_body' +error[E0046]: not all trait items implemented, missing: `CONSTANT` --> $DIR/default-body-stability-err.rs:10:1 | LL | impl JustTrait for Type {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: default implementation of `CONSTANT` is unstable + = note: use of unstable library feature 'constant_default_body' = help: add `#![feature(constant_default_body)]` to the crate attributes to enable -error[E0658]: use of unstable library feature 'fun_default_body' +error[E0046]: not all trait items implemented, missing: `fun` --> $DIR/default-body-stability-err.rs:10:1 | LL | impl JustTrait for Type {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: default implementation of `fun` is unstable + = note: use of unstable library feature 'fun_default_body' = help: add `#![feature(fun_default_body)]` to the crate attributes to enable -error[E0658]: use of unstable library feature 'eq_default_body' +error[E0046]: not all trait items implemented, missing: `eq` --> $DIR/default-body-stability-err.rs:14:1 | LL | / impl Equal for Type { @@ -25,8 +29,10 @@ LL | | } LL | | } | |_^ | + = note: default implementation of `eq` is unstable + = note: use of unstable library feature 'eq_default_body' = help: add `#![feature(eq_default_body)]` to the crate attributes to enable error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0658`. +For more information about this error, try `rustc --explain E0046`. From a96948195227f98dd18eecea8cd85c58406b6388 Mon Sep 17 00:00:00 2001 From: Paul Lange Date: Tue, 26 Jul 2022 16:10:26 +0200 Subject: [PATCH 09/77] Add syntax fixup for while loops --- crates/hir-expand/src/fixup.rs | 76 +++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/crates/hir-expand/src/fixup.rs b/crates/hir-expand/src/fixup.rs index 9999790fae7..6d0766020bd 100644 --- a/crates/hir-expand/src/fixup.rs +++ b/crates/hir-expand/src/fixup.rs @@ -5,7 +5,7 @@ use std::mem; use mbe::{SyntheticToken, SyntheticTokenId, TokenMap}; use rustc_hash::FxHashMap; use syntax::{ - ast::{self, AstNode}, + ast::{self, AstNode, HasLoopBody}, match_ast, SyntaxElement, SyntaxKind, SyntaxNode, TextRange, }; use tt::Subtree; @@ -142,6 +142,39 @@ pub(crate) fn fixup_syntax(node: &SyntaxNode) -> SyntaxFixups { ]); } }, + ast::WhileExpr(it) => { + if it.condition().is_none() { + // insert placeholder token after the while token + let while_token = match it.while_token() { + Some(t) => t, + None => continue, + }; + append.insert(while_token.into(), vec![ + SyntheticToken { + kind: SyntaxKind::IDENT, + text: "__ra_fixup".into(), + range: end_range, + id: EMPTY_ID, + }, + ]); + } + if it.loop_body().is_none() { + append.insert(node.clone().into(), vec![ + SyntheticToken { + kind: SyntaxKind::L_CURLY, + text: "{".into(), + range: end_range, + id: EMPTY_ID, + }, + SyntheticToken { + kind: SyntaxKind::R_CURLY, + text: "}".into(), + range: end_range, + id: EMPTY_ID, + }, + ]); + } + }, // FIXME: foo:: // FIXME: for, loop, match etc. _ => (), @@ -376,6 +409,47 @@ fn foo() { // the {} gets parsed as the condition, I think? expect![[r#" fn foo () {if {} {}} +"#]], + ) + } + + #[test] + fn fixup_while_1() { + check( + r#" +fn foo() { + while +} +"#, + expect![[r#" +fn foo () {while __ra_fixup {}} +"#]], + ) + } + + #[test] + fn fixup_while_2() { + check( + r#" +fn foo() { + while foo +} +"#, + expect![[r#" +fn foo () {while foo {}} +"#]], + ) + } + #[test] + fn fixup_while_3() { + check( + r#" +fn foo() { + while {} +} +"#, + expect![[r#" +fn foo () {while __ra_fixup {}} "#]], ) } From c16e4f260fb6b915767d18a59ab395cb46d82449 Mon Sep 17 00:00:00 2001 From: Paul Lange Date: Wed, 27 Jul 2022 18:18:51 +0200 Subject: [PATCH 10/77] Add syntax fixup for `loop` --- crates/hir-expand/src/fixup.rs | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/crates/hir-expand/src/fixup.rs b/crates/hir-expand/src/fixup.rs index 6d0766020bd..e46f43a878f 100644 --- a/crates/hir-expand/src/fixup.rs +++ b/crates/hir-expand/src/fixup.rs @@ -175,8 +175,26 @@ pub(crate) fn fixup_syntax(node: &SyntaxNode) -> SyntaxFixups { ]); } }, + ast::LoopExpr(it) => { + if it.loop_body().is_none() { + append.insert(node.clone().into(), vec![ + SyntheticToken { + kind: SyntaxKind::L_CURLY, + text: "{".into(), + range: end_range, + id: EMPTY_ID, + }, + SyntheticToken { + kind: SyntaxKind::R_CURLY, + text: "}".into(), + range: end_range, + id: EMPTY_ID, + }, + ]); + } + }, // FIXME: foo:: - // FIXME: for, loop, match etc. + // FIXME: for, match etc. _ => (), } } @@ -450,6 +468,20 @@ fn foo() { "#, expect![[r#" fn foo () {while __ra_fixup {}} +"#]], + ) + } + + #[test] + fn fixup_loop() { + check( + r#" +fn foo() { + loop +} +"#, + expect![[r#" +fn foo () {loop {}} "#]], ) } From 95729dcc733edd9f639855081cae8e24bc44fb30 Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Tue, 26 Jul 2022 14:34:26 +0100 Subject: [PATCH 11/77] check_missing_items.py: Don't overwrite `ty` in loop Because python doesn't have lexical scope, loop variables persist after the loop is exited, set to the value of the last itteration ``` >>> i = 0 >>> for i in range(10): pass ... >>> i 9 ``` This causes the `ty` variable to be changed, causing unexpected crashes on ``` pub type RefFn<'a> = &'a dyn for<'b> Fn(&'a i32) -> i32; ``` --- src/etc/check_missing_items.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/etc/check_missing_items.py b/src/etc/check_missing_items.py index 343dd0387f4..a705e238495 100644 --- a/src/etc/check_missing_items.py +++ b/src/etc/check_missing_items.py @@ -88,8 +88,8 @@ def check_type(ty): for bound in binding["binding"]["constraint"]: check_generic_bound(bound) elif "parenthesized" in args: - for ty in args["parenthesized"]["inputs"]: - check_type(ty) + for input_ty in args["parenthesized"]["inputs"]: + check_type(input_ty) if args["parenthesized"]["output"]: check_type(args["parenthesized"]["output"]) if not valid_id(ty["inner"]["id"]): From 2143e48e36e48223e00fffed71acadaf5330f61a Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Tue, 26 Jul 2022 15:02:01 +0100 Subject: [PATCH 12/77] Rustdoc-Json: Add tests for dyn and HRTBs --- src/test/rustdoc-json/type/dyn.rs | 19 +++++++++++++++++-- src/test/rustdoc-json/type/hrtb.rs | 23 +++++++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 src/test/rustdoc-json/type/hrtb.rs diff --git a/src/test/rustdoc-json/type/dyn.rs b/src/test/rustdoc-json/type/dyn.rs index f53dc03f4b4..79eeb996dcc 100644 --- a/src/test/rustdoc-json/type/dyn.rs +++ b/src/test/rustdoc-json/type/dyn.rs @@ -1,8 +1,10 @@ // ignore-tidy-linelength -// @count dyn.json "$.index[*][?(@.name=='dyn')].inner.items" 1 +// @count dyn.json "$.index[*][?(@.name=='dyn')].inner.items[*]" 2 // @set sync_int_gen = - "$.index[*][?(@.name=='SyncIntGen')].id" -// @is - "$.index[*][?(@.name=='dyn')].inner.items[0]" $sync_int_gen +// @set ref_fn = - "$.index[*][?(@.name=='RefFn')].id" +// @has - "$.index[*][?(@.name=='dyn')].inner.items[*]" $sync_int_gen +// @has - "$.index[*][?(@.name=='dyn')].inner.items[*]" $ref_fn // @is - "$.index[*][?(@.name=='SyncIntGen')].kind" \"typedef\" // @is - "$.index[*][?(@.name=='SyncIntGen')].inner.generics" '{"params": [], "where_predicates": []}' @@ -19,3 +21,16 @@ // @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[2]" "{\"outlives\": \"'static\"}" // @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.args" '{"parenthesized": {"inputs": [],"output": {"inner": "i32","kind": "primitive"}}}' pub type SyncIntGen = Box i32 + Send + Sync + 'static>; + +// @is - "$.index[*][?(@.name=='RefFn')].kind" \"typedef\" +// @is - "$.index[*][?(@.name=='RefFn')].inner.generics" '{"params": [{"kind": {"lifetime": {"outlives": []}},"name": "'\''a"}],"where_predicates": []}' +// @is - "$.index[*][?(@.name=='RefFn')].inner.type.kind" '"borrowed_ref"' +// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.mutable" 'false' +// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.lifetime" "\"'a\"" +// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.kind" '"resolved_path"' +// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.name" '"Fn"' +// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.args.parenthesized.inputs[0].kind" '"borrowed_ref"' +// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.args.parenthesized.inputs[0].inner.lifetime" "\"'b\"" +// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.args.parenthesized.output.kind" '"borrowed_ref"' +// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.args.parenthesized.output.inner.lifetime" "\"'b\"" +pub type RefFn<'a> = &'a dyn for<'b> Fn(&'b i32) -> &'b i32; diff --git a/src/test/rustdoc-json/type/hrtb.rs b/src/test/rustdoc-json/type/hrtb.rs new file mode 100644 index 00000000000..55bc043ad29 --- /dev/null +++ b/src/test/rustdoc-json/type/hrtb.rs @@ -0,0 +1,23 @@ + +// @has hrtb.json + +// @is - "$.index[*][?(@.name=='genfn')].inner.generics.where_predicates[0].bound_predicate.type" '{"inner": "F","kind": "generic"}' +// @is - "$.index[*][?(@.name=='genfn')].inner.generics.where_predicates[0].bound_predicate.generic_params" '[{"kind": {"lifetime": {"outlives": []}},"name": "'\''a"},{"kind": {"lifetime": {"outlives": []}},"name": "'\''b"}]' +pub fn genfn(f: F) +where + for<'a, 'b> F: Fn(&'a i32, &'b i32), +{ + let zero = 0; + f(&zero, &zero); +} + +// @is - "$.index[*][?(@.name=='dynfn')].inner.generics" '{"params": [], "where_predicates": []}' +// @is - "$.index[*][?(@.name=='dynfn')].inner.generics" '{"params": [], "where_predicates": []}' +// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].kind" '"borrowed_ref"' +// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].kind" '"borrowed_ref"' +// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.kind" '"resolved_path"' +// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.inner.name" '"Fn"' +pub fn dynfn(f: &dyn for<'a, 'b> Fn(&'a i32, &'b i32)) { + let zero = 0; + f(&zero, &zero); +} From e11b4b8e02495e9753df983de7bcec9ef2b8ae31 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Sun, 31 Jul 2022 16:02:45 +0400 Subject: [PATCH 13/77] Panic when checking an unknown stability attribute --- compiler/rustc_attr/src/builtin.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 2eb50d64802..62ccd734fe7 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -428,9 +428,11 @@ where ConstStability { level, feature, promotable: false }, attr.span, )); - } else { + } else if sym::rustc_default_body_unstable == meta_name { body_stab = Some((DefaultBodyStability { level, feature }, attr.span)); + } else { + unreachable!("Unknown stability attribute {meta_name}"); } } (None, _, _) => { From 963e402f4384806a4cfb9020208287972e5534d2 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Sun, 31 Jul 2022 16:29:31 +0400 Subject: [PATCH 14/77] Don't track parent body stability (it wasn't used anyway) --- compiler/rustc_passes/src/stability.rs | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 2a3da4ec30e..be920601ee4 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -2,8 +2,7 @@ //! propagating default levels lexically from parent to children ast nodes. use rustc_attr::{ - self as attr, ConstStability, DefaultBodyStability, Stability, StabilityLevel, Unstable, - UnstableReason, + self as attr, ConstStability, Stability, StabilityLevel, Unstable, UnstableReason, }; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_errors::{struct_span_err, Applicability}; @@ -91,7 +90,6 @@ struct Annotator<'a, 'tcx> { index: &'a mut Index, parent_stab: Option, parent_const_stab: Option, - parent_body_stab: Option, parent_depr: Option, in_trait_impl: bool, } @@ -159,7 +157,6 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { depr.map(|(d, _)| DeprecationEntry::local(d, def_id)), None, None, - None, visit_children, ); return; @@ -213,14 +210,12 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } } - let body_stab = body_stab.map(|(body_stab, _span)| { + if let Some((body_stab, _span)) = body_stab { // FIXME: check that this item can have body stability self.index.default_body_stab_map.insert(def_id, body_stab); debug!(?self.index.default_body_stab_map); - - body_stab - }); + } let stab = stab.map(|(stab, span)| { // Error if prohibited, or can't inherit anything from a container. @@ -299,7 +294,6 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { depr.map(|(d, _)| DeprecationEntry::local(d, def_id)), stab, if inherit_const_stability.yes() { const_stab } else { None }, - body_stab, visit_children, ); } @@ -309,14 +303,12 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { depr: Option, stab: Option, const_stab: Option, - body_stab: Option, f: impl FnOnce(&mut Self), ) { // These will be `Some` if this item changes the corresponding stability attribute. let mut replaced_parent_depr = None; let mut replaced_parent_stab = None; let mut replaced_parent_const_stab = None; - let mut replaced_parent_body_stab = None; if let Some(depr) = depr { replaced_parent_depr = Some(replace(&mut self.parent_depr, Some(depr))); @@ -328,9 +320,6 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { replaced_parent_const_stab = Some(replace(&mut self.parent_const_stab, Some(const_stab))); } - if let Some(body_stab) = body_stab { - replaced_parent_body_stab = Some(self.parent_body_stab.replace(body_stab)); - } f(self); @@ -343,9 +332,6 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { if let Some(orig_parent_const_stab) = replaced_parent_const_stab { self.parent_const_stab = orig_parent_const_stab; } - if let Some(orig_parent_body_stab) = replaced_parent_body_stab { - self.parent_body_stab = orig_parent_body_stab; - } } } @@ -646,7 +632,6 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { index: &mut index, parent_stab: None, parent_const_stab: None, - parent_body_stab: None, parent_depr: None, in_trait_impl: false, }; From d40ab66186fa477177a10d01eb16960a5f20c7ac Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Mon, 1 Aug 2022 16:48:33 +0900 Subject: [PATCH 15/77] fix: remove whitespaces from doctest names --- crates/ide/src/runnables.rs | 77 ++++++++++++++++++++++++++++++++++--- 1 file changed, 71 insertions(+), 6 deletions(-) diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs index bec770ed99f..3155f97f258 100644 --- a/crates/ide/src/runnables.rs +++ b/crates/ide/src/runnables.rs @@ -373,11 +373,13 @@ pub(crate) fn runnable_impl( let adt_name = ty.as_adt()?.name(sema.db); let mut ty_args = ty.type_arguments().peekable(); let params = if ty_args.peek().is_some() { - format!("<{}>", ty_args.format_with(", ", |ty, cb| cb(&ty.display(sema.db)))) + format!("<{}>", ty_args.format_with(",", |ty, cb| cb(&ty.display(sema.db)))) } else { String::new() }; - let test_id = TestId::Path(format!("{}{}", adt_name, params)); + let mut test_id = format!("{}{}", adt_name, params); + test_id.retain(|c| c != ' '); + let test_id = TestId::Path(test_id); Some(Runnable { use_name_in_title: false, nav, kind: RunnableKind::DocTest { test_id }, cfg }) } @@ -441,10 +443,11 @@ fn module_def_doctest(db: &RootDatabase, def: Definition) -> Option { format_to!( path, "<{}>", - ty_args.format_with(", ", |ty, cb| cb(&ty.display(db))) + ty_args.format_with(",", |ty, cb| cb(&ty.display(db))) ); } format_to!(path, "::{}", def_name); + path.retain(|c| c != ' '); return Some(path); } } @@ -2067,13 +2070,23 @@ mod tests { $0 struct Foo; +/// ``` +/// ``` impl Foo { /// ```rust /// ```` fn t() {} } + +/// ``` +/// ``` +impl Foo, ()> { + /// ``` + /// ``` + fn t() {} +} "#, - &[DocTest], + &[DocTest, DocTest, DocTest, DocTest], expect![[r#" [ Runnable { @@ -2082,12 +2095,64 @@ impl Foo { file_id: FileId( 0, ), - full_range: 47..85, + full_range: 20..103, + focus_range: 47..56, + name: "impl", + kind: Impl, + }, + kind: DocTest { + test_id: Path( + "Foo", + ), + }, + cfg: None, + }, + Runnable { + use_name_in_title: false, + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 63..101, name: "t", }, kind: DocTest { test_id: Path( - "Foo::t", + "Foo::t", + ), + }, + cfg: None, + }, + Runnable { + use_name_in_title: false, + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 105..188, + focus_range: 126..146, + name: "impl", + kind: Impl, + }, + kind: DocTest { + test_id: Path( + "Foo,()>", + ), + }, + cfg: None, + }, + Runnable { + use_name_in_title: false, + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 153..186, + name: "t", + }, + kind: DocTest { + test_id: Path( + "Foo,()>::t", ), }, cfg: None, From bd7dfac5ebbd8ba3bd63384000759fb4bb49b329 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 1 Aug 2022 13:47:09 +0200 Subject: [PATCH 16/77] Fix r-a spelling in some places --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- README.md | 2 +- crates/hir-def/src/item_tree.rs | 2 +- crates/ide-db/src/apply_change.rs | 2 +- crates/ide-ssr/src/lib.rs | 2 +- crates/ide/src/expand_macro.rs | 4 +- crates/ide/src/inlay_hints.rs | 2 +- crates/ide/src/join_lines.rs | 2 +- crates/ide/src/matching_brace.rs | 2 +- crates/ide/src/move_item.rs | 4 +- crates/ide/src/parent_module.rs | 2 +- crates/ide/src/runnables.rs | 4 +- crates/ide/src/shuffle_crate_graph.rs | 2 +- crates/ide/src/status.rs | 2 +- crates/ide/src/syntax_tree.rs | 2 +- crates/ide/src/view_crate_graph.rs | 2 +- crates/ide/src/view_hir.rs | 2 +- crates/ide/src/view_item_tree.rs | 2 +- crates/proc-macro-api/src/lib.rs | 2 +- crates/proc-macro-srv/src/abis/mod.rs | 2 +- crates/project-model/src/cargo_workspace.rs | 2 +- .../src/integrated_benchmarks.rs | 4 +- crates/syntax/src/lib.rs | 2 +- docs/dev/README.md | 8 +-- docs/dev/architecture.md | 2 +- docs/dev/guide.md | 2 +- docs/user/manual.adoc | 4 +- editors/code/package.json | 58 +++++++++---------- 28 files changed, 64 insertions(+), 64 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 7ba06356a37..1f246ed79b6 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -19,7 +19,7 @@ Before submitting, please make sure that you're not running into one of these kn Otherwise please try to provide information which will help us to fix the issue faster. Minimal reproducible examples with few dependencies are especially lovely <3. --> -**rust-analyzer version**: (eg. output of "Rust Analyzer: Show RA Version" command) +**rust-analyzer version**: (eg. output of "rust-analyzer: Show RA Version" command) **rustc version**: (eg. output of `rustc -V`) diff --git a/README.md b/README.md index 8bb0517ed5a..8c3f6f8468b 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frust-analyzer ## License -Rust analyzer is primarily distributed under the terms of both the MIT +rust-analyzer is primarily distributed under the terms of both the MIT license and the Apache License (Version 2.0). See LICENSE-APACHE and LICENSE-MIT for details. diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs index 375587ee935..3342d4db4aa 100644 --- a/crates/hir-def/src/item_tree.rs +++ b/crates/hir-def/src/item_tree.rs @@ -14,7 +14,7 @@ //! unaffected, so we don't have to recompute name resolution results or item data (see `data.rs`). //! //! The `ItemTree` for the currently open file can be displayed by using the VS Code command -//! "Rust Analyzer: Debug ItemTree". +//! "rust-analyzer: Debug ItemTree". //! //! Compared to rustc's architecture, `ItemTree` has properties from both rustc's AST and HIR: many //! syntax-level Rust features are already desugared to simpler forms in the `ItemTree`, but name diff --git a/crates/ide-db/src/apply_change.rs b/crates/ide-db/src/apply_change.rs index 98b0e9c947a..f8134c552f7 100644 --- a/crates/ide-db/src/apply_change.rs +++ b/crates/ide-db/src/apply_change.rs @@ -45,7 +45,7 @@ impl RootDatabase { // |=== // | Editor | Action Name // - // | VS Code | **Rust Analyzer: Memory Usage (Clears Database)** + // | VS Code | **rust-analyzer: Memory Usage (Clears Database)** // |=== // image::https://user-images.githubusercontent.com/48062697/113065592-08559f00-91b1-11eb-8c96-64b88068ec02.gif[] pub fn per_query_memory_usage(&mut self) -> Vec<(String, Bytes)> { diff --git a/crates/ide-ssr/src/lib.rs b/crates/ide-ssr/src/lib.rs index a5e24daa9fa..739e0ccb436 100644 --- a/crates/ide-ssr/src/lib.rs +++ b/crates/ide-ssr/src/lib.rs @@ -57,7 +57,7 @@ // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: Structural Search Replace** +// | VS Code | **rust-analyzer: Structural Search Replace** // |=== // // Also available as an assist, by writing a comment containing the structural diff --git a/crates/ide/src/expand_macro.rs b/crates/ide/src/expand_macro.rs index efa8551a00d..93252339cd4 100644 --- a/crates/ide/src/expand_macro.rs +++ b/crates/ide/src/expand_macro.rs @@ -19,7 +19,7 @@ pub struct ExpandedMacro { // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: Expand macro recursively** +// | VS Code | **rust-analyzer: Expand macro recursively** // |=== // // image::https://user-images.githubusercontent.com/48062697/113020648-b3973180-917a-11eb-84a9-ecb921293dc5.gif[] @@ -32,7 +32,7 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option< _ => 0, })?; - // due to how Rust Analyzer works internally, we need to special case derive attributes, + // due to how rust-analyzer works internally, we need to special case derive attributes, // otherwise they might not get found, e.g. here with the cursor at $0 `#[attr]` would expand: // ``` // #[attr] diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 5aae669aa4d..ed19784d1fa 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -100,7 +100,7 @@ pub enum InlayTooltip { // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: Toggle inlay hints* +// | VS Code | **rust-analyzer: Toggle inlay hints* // |=== // // image::https://user-images.githubusercontent.com/48062697/113020660-b5f98b80-917a-11eb-8d70-3be3fd558cdd.png[] diff --git a/crates/ide/src/join_lines.rs b/crates/ide/src/join_lines.rs index 08621addeef..edc48e84d72 100644 --- a/crates/ide/src/join_lines.rs +++ b/crates/ide/src/join_lines.rs @@ -28,7 +28,7 @@ pub struct JoinLinesConfig { // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: Join lines** +// | VS Code | **rust-analyzer: Join lines** // |=== // // image::https://user-images.githubusercontent.com/48062697/113020661-b6922200-917a-11eb-87c4-b75acc028f11.gif[] diff --git a/crates/ide/src/matching_brace.rs b/crates/ide/src/matching_brace.rs index da70cecdd8e..6e8a6d020cc 100644 --- a/crates/ide/src/matching_brace.rs +++ b/crates/ide/src/matching_brace.rs @@ -12,7 +12,7 @@ use syntax::{ // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: Find matching brace** +// | VS Code | **rust-analyzer: Find matching brace** // |=== // // image::https://user-images.githubusercontent.com/48062697/113065573-04298180-91b1-11eb-8dec-d4e2a202f304.gif[] diff --git a/crates/ide/src/move_item.rs b/crates/ide/src/move_item.rs index 02e9fb8b5e2..ffc4bdd7da3 100644 --- a/crates/ide/src/move_item.rs +++ b/crates/ide/src/move_item.rs @@ -19,8 +19,8 @@ pub enum Direction { // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: Move item up** -// | VS Code | **Rust Analyzer: Move item down** +// | VS Code | **rust-analyzer: Move item up** +// | VS Code | **rust-analyzer: Move item down** // |=== // // image::https://user-images.githubusercontent.com/48062697/113065576-04298180-91b1-11eb-91ce-4505e99ed598.gif[] diff --git a/crates/ide/src/parent_module.rs b/crates/ide/src/parent_module.rs index 9b1f480446a..8f3cc86873f 100644 --- a/crates/ide/src/parent_module.rs +++ b/crates/ide/src/parent_module.rs @@ -18,7 +18,7 @@ use crate::NavigationTarget; // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: Locate parent module** +// | VS Code | **rust-analyzer: Locate parent module** // |=== // // image::https://user-images.githubusercontent.com/48062697/113065580-04c21800-91b1-11eb-9a32-00086161c0bd.gif[] diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs index 3155f97f258..b0853b10fde 100644 --- a/crates/ide/src/runnables.rs +++ b/crates/ide/src/runnables.rs @@ -116,7 +116,7 @@ impl Runnable { // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: Run** +// | VS Code | **rust-analyzer: Run** // |=== // image::https://user-images.githubusercontent.com/48062697/113065583-055aae80-91b1-11eb-958f-d67efcaf6a2f.gif[] pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec { @@ -202,7 +202,7 @@ pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec { // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: Peek related tests** +// | VS Code | **rust-analyzer: Peek related tests** // |=== pub(crate) fn related_tests( db: &RootDatabase, diff --git a/crates/ide/src/shuffle_crate_graph.rs b/crates/ide/src/shuffle_crate_graph.rs index 15cb89dcce9..2d86627643d 100644 --- a/crates/ide/src/shuffle_crate_graph.rs +++ b/crates/ide/src/shuffle_crate_graph.rs @@ -12,7 +12,7 @@ use ide_db::{ // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: Shuffle Crate Graph** +// | VS Code | **rust-analyzer: Shuffle Crate Graph** // |=== pub(crate) fn shuffle_crate_graph(db: &mut RootDatabase) { let crate_graph = db.crate_graph(); diff --git a/crates/ide/src/status.rs b/crates/ide/src/status.rs index 3191870eb5e..32e39f82a0e 100644 --- a/crates/ide/src/status.rs +++ b/crates/ide/src/status.rs @@ -29,7 +29,7 @@ fn macro_syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats { // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: Status** +// | VS Code | **rust-analyzer: Status** // |=== // image::https://user-images.githubusercontent.com/48062697/113065584-05f34500-91b1-11eb-98cc-5c196f76be7f.gif[] pub(crate) fn status(db: &RootDatabase, file_id: Option) -> String { diff --git a/crates/ide/src/syntax_tree.rs b/crates/ide/src/syntax_tree.rs index 9003e7cd34d..4256fea0f81 100644 --- a/crates/ide/src/syntax_tree.rs +++ b/crates/ide/src/syntax_tree.rs @@ -12,7 +12,7 @@ use syntax::{ // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: Show Syntax Tree** +// | VS Code | **rust-analyzer: Show Syntax Tree** // |=== // image::https://user-images.githubusercontent.com/48062697/113065586-068bdb80-91b1-11eb-9507-fee67f9f45a0.gif[] pub(crate) fn syntax_tree( diff --git a/crates/ide/src/view_crate_graph.rs b/crates/ide/src/view_crate_graph.rs index 51291a64532..bf7b7efe282 100644 --- a/crates/ide/src/view_crate_graph.rs +++ b/crates/ide/src/view_crate_graph.rs @@ -16,7 +16,7 @@ use ide_db::{ // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: View Crate Graph** +// | VS Code | **rust-analyzer: View Crate Graph** // |=== pub(crate) fn view_crate_graph(db: &RootDatabase, full: bool) -> Result { let crate_graph = db.crate_graph(); diff --git a/crates/ide/src/view_hir.rs b/crates/ide/src/view_hir.rs index 7312afe5310..bf0835ed7e0 100644 --- a/crates/ide/src/view_hir.rs +++ b/crates/ide/src/view_hir.rs @@ -8,7 +8,7 @@ use syntax::{algo::find_node_at_offset, ast, AstNode}; // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: View Hir** +// | VS Code | **rust-analyzer: View Hir** // |=== // image::https://user-images.githubusercontent.com/48062697/113065588-068bdb80-91b1-11eb-9a78-0b4ef1e972fb.gif[] pub(crate) fn view_hir(db: &RootDatabase, position: FilePosition) -> String { diff --git a/crates/ide/src/view_item_tree.rs b/crates/ide/src/view_item_tree.rs index 3dc03085d65..9c1f93356ee 100644 --- a/crates/ide/src/view_item_tree.rs +++ b/crates/ide/src/view_item_tree.rs @@ -9,7 +9,7 @@ use ide_db::RootDatabase; // |=== // | Editor | Action Name // -// | VS Code | **Rust Analyzer: Debug ItemTree** +// | VS Code | **rust-analyzer: Debug ItemTree** // |=== pub(crate) fn view_item_tree(db: &RootDatabase, file_id: FileId) -> String { db.file_item_tree(file_id.into()).pretty_print() diff --git a/crates/proc-macro-api/src/lib.rs b/crates/proc-macro-api/src/lib.rs index d7010e825aa..a3ea05f4aff 100644 --- a/crates/proc-macro-api/src/lib.rs +++ b/crates/proc-macro-api/src/lib.rs @@ -60,7 +60,7 @@ impl MacroDylib { let info = version::read_dylib_info(&path)?; if info.version.0 < 1 || info.version.1 < 47 { - let msg = format!("proc-macro {} built by {:#?} is not supported by Rust Analyzer, please update your rust version.", path.display(), info); + let msg = format!("proc-macro {} built by {:#?} is not supported by rust-analyzer, please update your Rust version.", path.display(), info); return Err(io::Error::new(io::ErrorKind::InvalidData, msg)); } diff --git a/crates/proc-macro-srv/src/abis/mod.rs b/crates/proc-macro-srv/src/abis/mod.rs index bcf3f1184cf..705d09ea945 100644 --- a/crates/proc-macro-srv/src/abis/mod.rs +++ b/crates/proc-macro-srv/src/abis/mod.rs @@ -5,7 +5,7 @@ //! compiler into submodules of this module (e.g proc_macro_srv::abis::abi_1_47). //! //! All of these ABIs are subsumed in the `Abi` enum, which exposes a simple -//! interface the rest of rust analyzer can use to talk to the macro +//! interface the rest of rust-analyzer can use to talk to the macro //! provider. //! //! # Adding a new ABI diff --git a/crates/project-model/src/cargo_workspace.rs b/crates/project-model/src/cargo_workspace.rs index 597880c2ca2..eed955b42da 100644 --- a/crates/project-model/src/cargo_workspace.rs +++ b/crates/project-model/src/cargo_workspace.rs @@ -19,7 +19,7 @@ use crate::{utf8_stdout, ManifestPath}; /// [`CargoWorkspace`] represents the logical structure of, well, a Cargo /// workspace. It pretty closely mirrors `cargo metadata` output. /// -/// Note that internally, rust analyzer uses a different structure: +/// Note that internally, rust-analyzer uses a different structure: /// `CrateGraph`. `CrateGraph` is lower-level: it knows only about the crates, /// while this knows about `Packages` & `Targets`: purely cargo-related /// concepts. diff --git a/crates/rust-analyzer/src/integrated_benchmarks.rs b/crates/rust-analyzer/src/integrated_benchmarks.rs index 47cdd8dfc75..e49a98685a7 100644 --- a/crates/rust-analyzer/src/integrated_benchmarks.rs +++ b/crates/rust-analyzer/src/integrated_benchmarks.rs @@ -6,8 +6,8 @@ //! code here exercise this specific completion, and thus have a fast //! edit/compile/test cycle. //! -//! Note that "Rust Analyzer: Run" action does not allow running a single test -//! in release mode in VS Code. There's however "Rust Analyzer: Copy Run Command Line" +//! Note that "rust-analyzer: Run" action does not allow running a single test +//! in release mode in VS Code. There's however "rust-analyzer: Copy Run Command Line" //! which you can use to paste the command in terminal and add `--release` manually. use std::sync::Arc; diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs index 7fa354c0c46..4f5e273a520 100644 --- a/crates/syntax/src/lib.rs +++ b/crates/syntax/src/lib.rs @@ -1,4 +1,4 @@ -//! Syntax Tree library used throughout the rust analyzer. +//! Syntax Tree library used throughout the rust-analyzer. //! //! Properties: //! - easy and fast incremental re-parsing diff --git a/docs/dev/README.md b/docs/dev/README.md index 76bbd1e9188..c7f152acc26 100644 --- a/docs/dev/README.md +++ b/docs/dev/README.md @@ -82,7 +82,7 @@ There's **"Run Extension (Debug Build)"** launch configuration for this in VS Co In general, I use one of the following workflows for fixing bugs and implementing features: If the problem concerns only internal parts of rust-analyzer (i.e. I don't need to touch the `rust-analyzer` crate or TypeScript code), there is a unit-test for it. -So, I use **Rust Analyzer: Run** action in VS Code to run this single test, and then just do printf-driven development/debugging. +So, I use **rust-analyzer: Run** action in VS Code to run this single test, and then just do printf-driven development/debugging. As a sanity check after I'm done, I use `cargo xtask install --server` and **Reload Window** action in VS Code to verify that the thing works as I expect. If the problem concerns only the VS Code extension, I use **Run Installed Extension** launch configuration from `launch.json`. @@ -152,11 +152,11 @@ To log all communication between the server and the client, there are two choice There are also several VS Code commands which might be of interest: -* `Rust Analyzer: Status` shows some memory-usage statistics. +* `rust-analyzer: Status` shows some memory-usage statistics. -* `Rust Analyzer: Syntax Tree` shows syntax tree of the current file/selection. +* `rust-analyzer: Syntax Tree` shows syntax tree of the current file/selection. -* `Rust Analyzer: View Hir` shows the HIR expressions within the function containing the cursor. +* `rust-analyzer: View Hir` shows the HIR expressions within the function containing the cursor. You can hover over syntax nodes in the opened text file to see the appropriate rust code that it refers to and the rust editor will also highlight the proper diff --git a/docs/dev/architecture.md b/docs/dev/architecture.md index ea4035baf11..51e26c58a91 100644 --- a/docs/dev/architecture.md +++ b/docs/dev/architecture.md @@ -371,7 +371,7 @@ That is, rust-analyzer requires unwinding. ### Testing -Rust Analyzer has three interesting [system boundaries](https://www.tedinski.com/2018/04/10/making-tests-a-positive-influence-on-design.html) to concentrate tests on. +rust-analyzer has three interesting [system boundaries](https://www.tedinski.com/2018/04/10/making-tests-a-positive-influence-on-design.html) to concentrate tests on. The outermost boundary is the `rust-analyzer` crate, which defines an LSP interface in terms of stdio. We do integration testing of this component, by feeding it with a stream of LSP requests and checking responses. diff --git a/docs/dev/guide.md b/docs/dev/guide.md index 47ae3f3e6a9..808eb5d10bf 100644 --- a/docs/dev/guide.md +++ b/docs/dev/guide.md @@ -63,7 +63,7 @@ Next, let's talk about what the inputs to the `Analysis` are, precisely. ## Inputs -Rust Analyzer never does any I/O itself, all inputs get passed explicitly via +rust-analyzer never does any I/O itself, all inputs get passed explicitly via the `AnalysisHost::apply_change` method, which accepts a single argument, a `Change`. [`Change`] is a builder for a single change "transaction", so it suffices to study its methods to understand all of the diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc index 999a6437ab9..c482fcbed0e 100644 --- a/docs/user/manual.adoc +++ b/docs/user/manual.adoc @@ -479,7 +479,7 @@ You can follow instructions for installing < Date: Mon, 1 Aug 2022 14:26:20 +0200 Subject: [PATCH 17/77] Publish extension for 32-bit ARM systems --- .github/workflows/release.yaml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 4e62f2cde27..abc0a34c5ee 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -5,6 +5,8 @@ on: workflow_dispatch: + pull_request: + push: branches: - release @@ -36,6 +38,9 @@ jobs: - os: ubuntu-18.04 target: aarch64-unknown-linux-gnu code-target: linux-arm64 + - os: ubuntu-18.04 + target: arm-unknown-linux-gnueabihf + code-target: linux-armhf - os: macos-11 target: x86_64-apple-darwin code-target: darwin-x64 @@ -67,13 +72,17 @@ jobs: node-version: 14.x - name: Update apt repositories - if: matrix.target == 'aarch64-unknown-linux-gnu' + if: matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'gcc-arm-linux-gnueabihf' run: sudo apt-get update - - name: Install target toolchain + - name: Install AArch64 target toolchain if: matrix.target == 'aarch64-unknown-linux-gnu' run: sudo apt-get install gcc-aarch64-linux-gnu + - name: Install ARM target toolchain + if: matrix.target == 'gcc-arm-linux-gnueabihf' + run: sudo apt-get install gcc-arm-linux-gnueabihf + - name: Dist run: cargo xtask dist --client-patch-version ${{ github.run_number }} From caf8a6454a0ee4a045537cfdbe5ab859b3dc6b6d Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 1 Aug 2022 15:09:45 +0200 Subject: [PATCH 18/77] Set linker --- .github/workflows/release.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index abc0a34c5ee..56ee876cf1f 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -20,6 +20,7 @@ env: FETCH_DEPTH: 0 # pull in the tags for the version string MACOSX_DEPLOYMENT_TARGET: 10.15 CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc + CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHD_LINKER: arm-linux-gnueabihf-gcc jobs: dist: From 64090ee27cc630778fabd25a4d2ffd70329d62db Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 1 Aug 2022 15:22:02 +0200 Subject: [PATCH 19/77] Fix target check --- .github/workflows/release.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 56ee876cf1f..4845168282e 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -73,7 +73,7 @@ jobs: node-version: 14.x - name: Update apt repositories - if: matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'gcc-arm-linux-gnueabihf' + if: matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'arm-unknown-linux-gnueabihf' run: sudo apt-get update - name: Install AArch64 target toolchain @@ -81,7 +81,7 @@ jobs: run: sudo apt-get install gcc-aarch64-linux-gnu - name: Install ARM target toolchain - if: matrix.target == 'gcc-arm-linux-gnueabihf' + if: matrix.target == 'arm-unknown-linux-gnueabihf' run: sudo apt-get install gcc-arm-linux-gnueabihf - name: Dist From b72ff95901bcd65931b600f36e3a79b92b6cab3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Mon, 1 Aug 2022 16:46:18 +0300 Subject: [PATCH 20/77] Fix linker env var name --- .github/workflows/release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 4845168282e..7ffe2748b76 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -20,7 +20,7 @@ env: FETCH_DEPTH: 0 # pull in the tags for the version string MACOSX_DEPLOYMENT_TARGET: 10.15 CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc - CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHD_LINKER: arm-linux-gnueabihf-gcc + CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER: arm-linux-gnueabihf-gcc jobs: dist: From cfbada4e0fbdb0fbde515df21be934d12cad63bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Mon, 1 Aug 2022 16:54:54 +0300 Subject: [PATCH 21/77] Upload arm-unknown-linux-gnueabihf build artifact --- .github/workflows/release.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 7ffe2748b76..015614c8b4d 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -214,6 +214,10 @@ jobs: with: name: dist-aarch64-unknown-linux-gnu path: dist + - uses: actions/download-artifact@v1 + with: + name: dist-arm-unknown-linux-gnueabihf + path: dist - uses: actions/download-artifact@v1 with: name: dist-x86_64-pc-windows-msvc From c71f1e70a87bfbaab7095a297628ff78acfc14df Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 1 Aug 2022 16:16:22 +0200 Subject: [PATCH 22/77] Don't run on PRs --- .github/workflows/release.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 015614c8b4d..ca8eb1309de 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -5,8 +5,6 @@ on: workflow_dispatch: - pull_request: - push: branches: - release From 405dd77d30382f417f033e4feba2b2bd02ebe00e Mon Sep 17 00:00:00 2001 From: Dorian Scheidt Date: Wed, 20 Jul 2022 12:03:18 -0500 Subject: [PATCH 23/77] Support adding variants via structural editing --- crates/syntax/src/ast/edit_in_place.rs | 171 +++++++++++++++++++++---- crates/syntax/src/ast/make.rs | 5 +- 2 files changed, 148 insertions(+), 28 deletions(-) diff --git a/crates/syntax/src/ast/edit_in_place.rs b/crates/syntax/src/ast/edit_in_place.rs index e3e928aecd4..8efd58e2c39 100644 --- a/crates/syntax/src/ast/edit_in_place.rs +++ b/crates/syntax/src/ast/edit_in_place.rs @@ -11,7 +11,7 @@ use crate::{ ted::{self, Position}, AstNode, AstToken, Direction, SyntaxKind::{ATTR, COMMENT, WHITESPACE}, - SyntaxNode, + SyntaxNode, SyntaxToken, }; use super::HasName; @@ -506,19 +506,7 @@ impl ast::RecordExprFieldList { let position = match self.fields().last() { Some(last_field) => { - let comma = match last_field - .syntax() - .siblings_with_tokens(Direction::Next) - .filter_map(|it| it.into_token()) - .find(|it| it.kind() == T![,]) - { - Some(it) => it, - None => { - let comma = ast::make::token(T![,]); - ted::insert(Position::after(last_field.syntax()), &comma); - comma - } - }; + let comma = get_or_insert_comma_after(last_field.syntax()); Position::after(comma) } None => match self.l_curly_token() { @@ -579,19 +567,8 @@ impl ast::RecordPatFieldList { let position = match self.fields().last() { Some(last_field) => { - let comma = match last_field - .syntax() - .siblings_with_tokens(Direction::Next) - .filter_map(|it| it.into_token()) - .find(|it| it.kind() == T![,]) - { - Some(it) => it, - None => { - let comma = ast::make::token(T![,]); - ted::insert(Position::after(last_field.syntax()), &comma); - comma - } - }; + let syntax = last_field.syntax(); + let comma = get_or_insert_comma_after(syntax); Position::after(comma) } None => match self.l_curly_token() { @@ -606,12 +583,53 @@ impl ast::RecordPatFieldList { } } } + +fn get_or_insert_comma_after(syntax: &SyntaxNode) -> SyntaxToken { + let comma = match syntax + .siblings_with_tokens(Direction::Next) + .filter_map(|it| it.into_token()) + .find(|it| it.kind() == T![,]) + { + Some(it) => it, + None => { + let comma = ast::make::token(T![,]); + ted::insert(Position::after(syntax), &comma); + comma + } + }; + comma +} + impl ast::StmtList { pub fn push_front(&self, statement: ast::Stmt) { ted::insert(Position::after(self.l_curly_token().unwrap()), statement.syntax()); } } +impl ast::VariantList { + pub fn add_variant(&self, variant: ast::Variant) { + let (indent, position) = match self.variants().last() { + Some(last_item) => ( + IndentLevel::from_node(last_item.syntax()), + Position::after(get_or_insert_comma_after(last_item.syntax())), + ), + None => match self.l_curly_token() { + Some(l_curly) => { + normalize_ws_between_braces(self.syntax()); + (IndentLevel::from_token(&l_curly) + 1, Position::after(&l_curly)) + } + None => (IndentLevel::single(), Position::last_child_of(self.syntax())), + }, + }; + let elements: Vec> = vec![ + make::tokens::whitespace(&format!("{}{}", "\n", indent)).into(), + variant.syntax().clone().into(), + ast::make::token(T![,]).into(), + ]; + ted::insert_all(position, elements); + } +} + fn normalize_ws_between_braces(node: &SyntaxNode) -> Option<()> { let l = node .children_with_tokens() @@ -661,6 +679,9 @@ impl Indent for N {} mod tests { use std::fmt; + use stdx::trim_indent; + use test_utils::assert_eq_text; + use crate::SourceFile; use super::*; @@ -714,4 +735,100 @@ mod tests { }", ); } + + #[test] + fn add_variant_to_empty_enum() { + let variant = make::variant(make::name("Bar"), None).clone_for_update(); + + check_add_variant( + r#" +enum Foo {} +"#, + r#" +enum Foo { + Bar, +} +"#, + variant, + ); + } + + #[test] + fn add_variant_to_non_empty_enum() { + let variant = make::variant(make::name("Baz"), None).clone_for_update(); + + check_add_variant( + r#" +enum Foo { + Bar, +} +"#, + r#" +enum Foo { + Bar, + Baz, +} +"#, + variant, + ); + } + + #[test] + fn add_variant_with_tuple_field_list() { + let variant = make::variant( + make::name("Baz"), + Some(ast::FieldList::TupleFieldList(make::tuple_field_list(std::iter::once( + make::tuple_field(None, make::ty("bool")), + )))), + ) + .clone_for_update(); + + check_add_variant( + r#" +enum Foo { + Bar, +} +"#, + r#" +enum Foo { + Bar, + Baz(bool), +} +"#, + variant, + ); + } + + #[test] + fn add_variant_with_record_field_list() { + let variant = make::variant( + make::name("Baz"), + Some(ast::FieldList::RecordFieldList(make::record_field_list(std::iter::once( + make::record_field(None, make::name("x"), make::ty("bool")), + )))), + ) + .clone_for_update(); + + check_add_variant( + r#" +enum Foo { + Bar, +} +"#, + r#" +enum Foo { + Bar, + Baz { x: bool }, +} +"#, + variant, + ); + } + + fn check_add_variant(before: &str, expected: &str, variant: ast::Variant) { + let enum_ = ast_mut_from_text::(before); + enum_.variant_list().map(|it| it.add_variant(variant)); + let after = enum_.to_string(); + assert_eq_text!(&trim_indent(expected.trim()), &trim_indent(&after.trim())); + } } diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs index 5908dda8e63..037de876d45 100644 --- a/crates/syntax/src/ast/make.rs +++ b/crates/syntax/src/ast/make.rs @@ -745,7 +745,10 @@ pub fn tuple_field(visibility: Option, ty: ast::Type) -> ast::T pub fn variant(name: ast::Name, field_list: Option) -> ast::Variant { let field_list = match field_list { None => String::new(), - Some(it) => format!("{}", it), + Some(it) => match it { + ast::FieldList::RecordFieldList(record) => format!(" {}", record), + ast::FieldList::TupleFieldList(tuple) => format!("{}", tuple), + }, }; ast_from_text(&format!("enum f {{ {}{} }}", name, field_list)) } From bea1fec7a2c949d6470f2182d34c5b349605f7a1 Mon Sep 17 00:00:00 2001 From: Dorian Scheidt Date: Wed, 20 Jul 2022 12:11:00 -0500 Subject: [PATCH 24/77] convert generate_enum_variant to use add_variant --- .../src/handlers/generate_enum_variant.rs | 20 +++++-------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/crates/ide-assists/src/handlers/generate_enum_variant.rs b/crates/ide-assists/src/handlers/generate_enum_variant.rs index 4461fbd5ac8..04620645e6d 100644 --- a/crates/ide-assists/src/handlers/generate_enum_variant.rs +++ b/crates/ide-assists/src/handlers/generate_enum_variant.rs @@ -1,8 +1,8 @@ use hir::{HasSource, InFile}; use ide_db::assists::{AssistId, AssistKind}; use syntax::{ - ast::{self, edit::IndentLevel}, - AstNode, TextSize, + ast::{self, make}, + AstNode, }; use crate::assist_context::{AssistContext, Assists}; @@ -65,26 +65,16 @@ fn add_variant_to_accumulator( ) -> Option<()> { let db = ctx.db(); let InFile { file_id, value: enum_node } = adt.source(db)?.original_ast_node(db)?; - let enum_indent = IndentLevel::from_node(&enum_node.syntax()); - - let variant_list = enum_node.variant_list()?; - let offset = variant_list.syntax().text_range().end() - TextSize::of('}'); - let empty_enum = variant_list.variants().next().is_none(); + let variant = make::variant(make::name(&name_ref.text()), None); acc.add( AssistId("generate_enum_variant", AssistKind::Generate), "Generate variant", target, |builder| { builder.edit_file(file_id.original_file(db)); - let text = format!( - "{maybe_newline}{indent_1}{name},\n{enum_indent}", - maybe_newline = if empty_enum { "\n" } else { "" }, - indent_1 = IndentLevel(1), - name = name_ref, - enum_indent = enum_indent - ); - builder.insert(offset, text) + let node = builder.make_mut(enum_node); + node.variant_list().map(|it| it.add_variant(variant.clone_for_update())); }, ) } From 15d8049fa9a9cd3ecbd19401336c4c150606522c Mon Sep 17 00:00:00 2001 From: Dorian Scheidt Date: Wed, 20 Jul 2022 12:26:27 -0500 Subject: [PATCH 25/77] Support tuple fields in generate_enum_variant --- .../src/handlers/generate_enum_variant.rs | 115 +++++++++++++++++- 1 file changed, 111 insertions(+), 4 deletions(-) diff --git a/crates/ide-assists/src/handlers/generate_enum_variant.rs b/crates/ide-assists/src/handlers/generate_enum_variant.rs index 04620645e6d..f671877e521 100644 --- a/crates/ide-assists/src/handlers/generate_enum_variant.rs +++ b/crates/ide-assists/src/handlers/generate_enum_variant.rs @@ -1,7 +1,7 @@ -use hir::{HasSource, InFile}; +use hir::{HasSource, HirDisplay, InFile}; use ide_db::assists::{AssistId, AssistKind}; use syntax::{ - ast::{self, make}, + ast::{self, make, HasArgList}, AstNode, }; @@ -50,7 +50,7 @@ pub(crate) fn generate_enum_variant(acc: &mut Assists, ctx: &AssistContext<'_>) ctx.sema.resolve_path(&path.qualifier()?) { let target = path.syntax().text_range(); - return add_variant_to_accumulator(acc, ctx, target, e, &name_ref); + return add_variant_to_accumulator(acc, ctx, target, e, &name_ref, &path); } None @@ -62,11 +62,11 @@ fn add_variant_to_accumulator( target: syntax::TextRange, adt: hir::Enum, name_ref: &ast::NameRef, + path: &ast::Path, ) -> Option<()> { let db = ctx.db(); let InFile { file_id, value: enum_node } = adt.source(db)?.original_ast_node(db)?; - let variant = make::variant(make::name(&name_ref.text()), None); acc.add( AssistId("generate_enum_variant", AssistKind::Generate), "Generate variant", @@ -74,11 +74,53 @@ fn add_variant_to_accumulator( |builder| { builder.edit_file(file_id.original_file(db)); let node = builder.make_mut(enum_node); + let variant = make_variant(ctx, name_ref, &path); node.variant_list().map(|it| it.add_variant(variant.clone_for_update())); }, ) } +fn make_variant( + ctx: &AssistContext<'_>, + name_ref: &ast::NameRef, + path: &ast::Path, +) -> ast::Variant { + let field_list = make_field_list(ctx, path); + make::variant(make::name(&name_ref.text()), field_list) +} + +fn make_field_list(ctx: &AssistContext<'_>, path: &ast::Path) -> Option { + let scope = ctx.sema.scope(&path.syntax())?; + if let Some(call_expr) = + path.syntax().parent().and_then(|it| it.parent()).and_then(ast::CallExpr::cast) + { + make_tuple_field_list(call_expr, ctx, &scope) + } else { + None + } +} + +fn make_tuple_field_list( + call_expr: ast::CallExpr, + ctx: &AssistContext<'_>, + scope: &hir::SemanticsScope<'_>, +) -> Option { + let args = call_expr.arg_list()?.args(); + let tuple_fields = args.map(|arg| { + let ty = expr_ty(ctx, arg, &scope); + make::tuple_field(None, ty) + }); + Some(make::tuple_field_list(tuple_fields).into()) +} + +fn expr_ty(ctx: &AssistContext<'_>, arg: ast::Expr, scope: &hir::SemanticsScope<'_>) -> ast::Type { + let ty = ctx.sema.type_of_expr(&arg).map(|it| it.adjusted()); + let text = ty + .and_then(|it| it.display_source_code(ctx.db(), scope.module().into()).ok()) + .unwrap_or_else(|| "_".to_string()); + make::ty(&text) +} + #[cfg(test)] mod tests { use crate::tests::{check_assist, check_assist_not_applicable}; @@ -211,6 +253,71 @@ mod m { fn main() { m::Foo::Baz } +", + ) + } + + #[test] + fn associated_single_element_tuple() { + check_assist( + generate_enum_variant, + r" +enum Foo {} +fn main() { + Foo::Bar$0(true) +} +", + r" +enum Foo { + Bar(bool), +} +fn main() { + Foo::Bar(true) +} +", + ) + } + + #[test] + fn associated_single_element_tuple_unknown_type() { + check_assist( + generate_enum_variant, + r" +enum Foo {} +fn main() { + Foo::Bar$0(x) +} +", + r" +enum Foo { + Bar(_), +} +fn main() { + Foo::Bar(x) +} +", + ) + } + + #[test] + fn associated_multi_element_tuple() { + check_assist( + generate_enum_variant, + r" +struct Struct {} +enum Foo {} +fn main() { + Foo::Bar$0(true, x, Struct {}) +} +", + r" +struct Struct {} +enum Foo { + Bar(bool, _, Struct), +} +fn main() { + Foo::Bar(true, x, Struct {}) +} ", ) } From e4638def7aedd8d69ec2670abf6a08b876ad75d9 Mon Sep 17 00:00:00 2001 From: Dorian Scheidt Date: Wed, 20 Jul 2022 13:02:21 -0500 Subject: [PATCH 26/77] Support record fields in generate_enum_variant --- .../src/handlers/generate_enum_variant.rs | 165 +++++++++++++++++- 1 file changed, 156 insertions(+), 9 deletions(-) diff --git a/crates/ide-assists/src/handlers/generate_enum_variant.rs b/crates/ide-assists/src/handlers/generate_enum_variant.rs index f671877e521..afbfc74b72a 100644 --- a/crates/ide-assists/src/handlers/generate_enum_variant.rs +++ b/crates/ide-assists/src/handlers/generate_enum_variant.rs @@ -32,8 +32,7 @@ use crate::assist_context::{AssistContext, Assists}; // } // ``` pub(crate) fn generate_enum_variant(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { - let path_expr: ast::PathExpr = ctx.find_node_at_offset()?; - let path = path_expr.path()?; + let path: ast::Path = ctx.find_node_at_offset()?; if ctx.sema.resolve_path(&path).is_some() { // No need to generate anything if the path resolves @@ -95,11 +94,48 @@ fn make_field_list(ctx: &AssistContext<'_>, path: &ast::Path) -> Option, + scope: &hir::SemanticsScope<'_>, +) -> Option { + let fields = record.record_expr_field_list()?.fields(); + let record_fields = fields.map(|field| { + let name = name_from_field(&field); + + let ty = field + .expr() + .and_then(|it| expr_ty(ctx, it, scope)) + .unwrap_or_else(make::ty_placeholder); + + make::record_field(None, name, ty) + }); + Some(make::record_field_list(record_fields).into()) +} + +fn name_from_field(field: &ast::RecordExprField) -> ast::Name { + let text = match field.name_ref() { + Some(it) => it.to_string(), + None => name_from_field_shorthand(field).unwrap_or("unknown".to_string()), + }; + make::name(&text) +} + +fn name_from_field_shorthand(field: &ast::RecordExprField) -> Option { + let path = match field.expr()? { + ast::Expr::PathExpr(path_expr) => path_expr.path(), + _ => None, + }?; + Some(path.as_single_name_ref()?.to_string()) +} + fn make_tuple_field_list( call_expr: ast::CallExpr, ctx: &AssistContext<'_>, @@ -107,18 +143,20 @@ fn make_tuple_field_list( ) -> Option { let args = call_expr.arg_list()?.args(); let tuple_fields = args.map(|arg| { - let ty = expr_ty(ctx, arg, &scope); + let ty = expr_ty(ctx, arg, &scope).unwrap_or_else(make::ty_placeholder); make::tuple_field(None, ty) }); Some(make::tuple_field_list(tuple_fields).into()) } -fn expr_ty(ctx: &AssistContext<'_>, arg: ast::Expr, scope: &hir::SemanticsScope<'_>) -> ast::Type { - let ty = ctx.sema.type_of_expr(&arg).map(|it| it.adjusted()); - let text = ty - .and_then(|it| it.display_source_code(ctx.db(), scope.module().into()).ok()) - .unwrap_or_else(|| "_".to_string()); - make::ty(&text) +fn expr_ty( + ctx: &AssistContext<'_>, + arg: ast::Expr, + scope: &hir::SemanticsScope<'_>, +) -> Option { + let ty = ctx.sema.type_of_expr(&arg).map(|it| it.adjusted())?; + let text = ty.display_source_code(ctx.db(), scope.module().into()).ok()?; + Some(make::ty(&text)) } #[cfg(test)] @@ -318,6 +356,115 @@ enum Foo { fn main() { Foo::Bar(true, x, Struct {}) } +", + ) + } + + #[test] + fn associated_record() { + check_assist( + generate_enum_variant, + r" +enum Foo {} +fn main() { + Foo::$0Bar { x: true } +} +", + r" +enum Foo { + Bar { x: bool }, +} +fn main() { + Foo::Bar { x: true } +} +", + ) + } + + #[test] + fn associated_record_unknown_type() { + check_assist( + generate_enum_variant, + r" +enum Foo {} +fn main() { + Foo::$0Bar { x: y } +} +", + r" +enum Foo { + Bar { x: _ }, +} +fn main() { + Foo::Bar { x: y } +} +", + ) + } + + #[test] + fn associated_record_field_shorthand() { + check_assist( + generate_enum_variant, + r" +enum Foo {} +fn main() { + let x = true; + Foo::$0Bar { x } +} +", + r" +enum Foo { + Bar { x: bool }, +} +fn main() { + let x = true; + Foo::Bar { x } +} +", + ) + } + + #[test] + fn associated_record_field_shorthand_unknown_type() { + check_assist( + generate_enum_variant, + r" +enum Foo {} +fn main() { + Foo::$0Bar { x } +} +", + r" +enum Foo { + Bar { x: _ }, +} +fn main() { + Foo::Bar { x } +} +", + ) + } + + #[test] + fn associated_record_field_multiple_fields() { + check_assist( + generate_enum_variant, + r" +struct Struct {} +enum Foo {} +fn main() { + Foo::$0Bar { x, y: x, s: Struct {} } +} +", + r" +struct Struct {} +enum Foo { + Bar { x: _, y: _, s: Struct }, +} +fn main() { + Foo::Bar { x, y: x, s: Struct {} } +} ", ) } From 111694d85bc64e3604599668c5b2db574e07abf0 Mon Sep 17 00:00:00 2001 From: Dorian Scheidt Date: Tue, 2 Aug 2022 11:54:00 -0400 Subject: [PATCH 27/77] Be more strict about supported Paths in generate_enum_variant PathType path parents don't support this assist --- .../src/handlers/generate_enum_variant.rs | 105 ++++++++++++++---- 1 file changed, 85 insertions(+), 20 deletions(-) diff --git a/crates/ide-assists/src/handlers/generate_enum_variant.rs b/crates/ide-assists/src/handlers/generate_enum_variant.rs index afbfc74b72a..b3dd29b7710 100644 --- a/crates/ide-assists/src/handlers/generate_enum_variant.rs +++ b/crates/ide-assists/src/handlers/generate_enum_variant.rs @@ -2,7 +2,7 @@ use hir::{HasSource, HirDisplay, InFile}; use ide_db::assists::{AssistId, AssistKind}; use syntax::{ ast::{self, make, HasArgList}, - AstNode, + match_ast, AstNode, SyntaxNode, }; use crate::assist_context::{AssistContext, Assists}; @@ -33,6 +33,7 @@ use crate::assist_context::{AssistContext, Assists}; // ``` pub(crate) fn generate_enum_variant(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let path: ast::Path = ctx.find_node_at_offset()?; + let parent = path_parent(&path)?; if ctx.sema.resolve_path(&path).is_some() { // No need to generate anything if the path resolves @@ -49,19 +50,65 @@ pub(crate) fn generate_enum_variant(acc: &mut Assists, ctx: &AssistContext<'_>) ctx.sema.resolve_path(&path.qualifier()?) { let target = path.syntax().text_range(); - return add_variant_to_accumulator(acc, ctx, target, e, &name_ref, &path); + return add_variant_to_accumulator(acc, ctx, target, e, &name_ref, parent); } None } +#[derive(Debug)] +enum PathParent { + PathExpr(ast::PathExpr), + RecordExpr(ast::RecordExpr), + UseTree(ast::UseTree), +} + +impl PathParent { + fn syntax(&self) -> &SyntaxNode { + match self { + PathParent::PathExpr(it) => it.syntax(), + PathParent::RecordExpr(it) => it.syntax(), + PathParent::UseTree(it) => it.syntax(), + } + } + + fn make_field_list(&self, ctx: &AssistContext<'_>) -> Option { + let scope = ctx.sema.scope(self.syntax())?; + + match self { + PathParent::PathExpr(it) => { + if let Some(call_expr) = it.syntax().parent().and_then(ast::CallExpr::cast) { + make_tuple_field_list(call_expr, ctx, &scope) + } else { + None + } + } + PathParent::RecordExpr(it) => make_record_field_list(it, ctx, &scope), + PathParent::UseTree(_) => None, + } + } +} + +fn path_parent(path: &ast::Path) -> Option { + let parent = path.syntax().parent()?; + + match_ast! { + match parent { + ast::PathExpr(it) => Some(PathParent::PathExpr(it)), + ast::RecordExpr(it) => Some(PathParent::RecordExpr(it)), + ast::UseTree(it) => Some(PathParent::UseTree(it)), + _ => None + } + } +} + fn add_variant_to_accumulator( acc: &mut Assists, ctx: &AssistContext<'_>, target: syntax::TextRange, adt: hir::Enum, name_ref: &ast::NameRef, - path: &ast::Path, + parent: PathParent, ) -> Option<()> { let db = ctx.db(); let InFile { file_id, value: enum_node } = adt.source(db)?.original_ast_node(db)?; @@ -73,7 +120,7 @@ fn add_variant_to_accumulator( |builder| { builder.edit_file(file_id.original_file(db)); let node = builder.make_mut(enum_node); - let variant = make_variant(ctx, name_ref, &path); + let variant = make_variant(ctx, name_ref, parent); node.variant_list().map(|it| it.add_variant(variant.clone_for_update())); }, ) @@ -82,27 +129,14 @@ fn add_variant_to_accumulator( fn make_variant( ctx: &AssistContext<'_>, name_ref: &ast::NameRef, - path: &ast::Path, + parent: PathParent, ) -> ast::Variant { - let field_list = make_field_list(ctx, path); + let field_list = parent.make_field_list(ctx); make::variant(make::name(&name_ref.text()), field_list) } -fn make_field_list(ctx: &AssistContext<'_>, path: &ast::Path) -> Option { - let scope = ctx.sema.scope(&path.syntax())?; - if let Some(call_expr) = - path.syntax().parent().and_then(|it| it.parent()).and_then(ast::CallExpr::cast) - { - make_tuple_field_list(call_expr, ctx, &scope) - } else if let Some(record_expr) = path.syntax().parent().and_then(ast::RecordExpr::cast) { - make_record_field_list(record_expr, ctx, &scope) - } else { - None - } -} - fn make_record_field_list( - record: ast::RecordExpr, + record: &ast::RecordExpr, ctx: &AssistContext<'_>, scope: &hir::SemanticsScope<'_>, ) -> Option { @@ -465,6 +499,37 @@ enum Foo { fn main() { Foo::Bar { x, y: x, s: Struct {} } } +", + ) + } + + #[test] + fn use_tree() { + check_assist( + generate_enum_variant, + r" +//- /main.rs +mod foo; +use foo::Foo::Bar$0; + +//- /foo.rs +enum Foo {} +", + r" +enum Foo { + Bar, +} +", + ) + } + + #[test] + fn not_applicable_for_path_type() { + check_assist_not_applicable( + generate_enum_variant, + r" +enum Foo {} +impl Foo::Bar$0 {} ", ) } From 1980c1192c7bcfb10e1ed380ee90bcaa7153d58d Mon Sep 17 00:00:00 2001 From: Dorian Scheidt Date: Tue, 2 Aug 2022 12:11:32 -0400 Subject: [PATCH 28/77] Support PathPat paths in generate_enum_variant --- .../src/handlers/generate_enum_variant.rs | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/crates/ide-assists/src/handlers/generate_enum_variant.rs b/crates/ide-assists/src/handlers/generate_enum_variant.rs index b3dd29b7710..35cd42908af 100644 --- a/crates/ide-assists/src/handlers/generate_enum_variant.rs +++ b/crates/ide-assists/src/handlers/generate_enum_variant.rs @@ -60,6 +60,7 @@ pub(crate) fn generate_enum_variant(acc: &mut Assists, ctx: &AssistContext<'_>) enum PathParent { PathExpr(ast::PathExpr), RecordExpr(ast::RecordExpr), + PathPat(ast::PathPat), UseTree(ast::UseTree), } @@ -68,6 +69,7 @@ impl PathParent { match self { PathParent::PathExpr(it) => it.syntax(), PathParent::RecordExpr(it) => it.syntax(), + PathParent::PathPat(it) => it.syntax(), PathParent::UseTree(it) => it.syntax(), } } @@ -84,7 +86,7 @@ impl PathParent { } } PathParent::RecordExpr(it) => make_record_field_list(it, ctx, &scope), - PathParent::UseTree(_) => None, + PathParent::UseTree(_) | PathParent::PathPat(_) => None, } } } @@ -96,6 +98,7 @@ fn path_parent(path: &ast::Path) -> Option { match parent { ast::PathExpr(it) => Some(PathParent::PathExpr(it)), ast::RecordExpr(it) => Some(PathParent::RecordExpr(it)), + ast::PathPat(it) => Some(PathParent::PathPat(it)), ast::UseTree(it) => Some(PathParent::UseTree(it)), _ => None } @@ -530,6 +533,31 @@ enum Foo { r" enum Foo {} impl Foo::Bar$0 {} +", + ) + } + + #[test] + fn path_pat() { + check_assist( + generate_enum_variant, + r" +enum Foo {} +fn foo(x: Foo) { + match x { + Foo::Bar$0 => + } +} +", + r" +enum Foo { + Bar, +} +fn foo(x: Foo) { + match x { + Foo::Bar => + } +} ", ) } From 9a447c04f6c07ec6b835b3577610cfaf3f7667cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Wed, 3 Aug 2022 09:48:44 +0300 Subject: [PATCH 29/77] Use the release branch in xtask promote --- xtask/src/release.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xtask/src/release.rs b/xtask/src/release.rs index 17ada515640..eda8fceef05 100644 --- a/xtask/src/release.rs +++ b/xtask/src/release.rs @@ -81,7 +81,7 @@ impl flags::Promote { let date = date_iso(sh)?; let branch = format!("rust-analyzer-{date}"); cmd!(sh, "git switch -c {branch}").run()?; - cmd!(sh, "git subtree pull -P src/tools/rust-analyzer rust-analyzer master").run()?; + cmd!(sh, "git subtree pull -m ':arrow_up: rust-analyzer' -P src/tools/rust-analyzer rust-analyzer release").run()?; if !self.dry_run { cmd!(sh, "git push -u origin {branch}").run()?; From c203ac2cf5aaf7b7ed759e0f84426debc063d3e8 Mon Sep 17 00:00:00 2001 From: oxalica Date: Wed, 3 Aug 2022 17:35:31 +0800 Subject: [PATCH 30/77] Add more constructors for la-arena --- lib/la-arena/src/lib.rs | 10 ++++++++++ lib/la-arena/src/map.rs | 12 +++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/lib/la-arena/src/lib.rs b/lib/la-arena/src/lib.rs index dadee43b108..a6766edd419 100644 --- a/lib/la-arena/src/lib.rs +++ b/lib/la-arena/src/lib.rs @@ -208,6 +208,16 @@ impl Arena { Arena { data: Vec::new() } } + /// Create a new empty arena with specific capacity. + /// + /// ``` + /// let arena: la_arena::Arena = la_arena::Arena::with_capacity(42); + /// assert!(arena.is_empty()); + /// ``` + pub fn with_capacity(capacity: usize) -> Arena { + Arena { data: Vec::with_capacity(capacity) } + } + /// Empties the arena, removing all contained values. /// /// ``` diff --git a/lib/la-arena/src/map.rs b/lib/la-arena/src/map.rs index d27f086d37b..b5c49b3435d 100644 --- a/lib/la-arena/src/map.rs +++ b/lib/la-arena/src/map.rs @@ -11,6 +11,16 @@ pub struct ArenaMap { } impl ArenaMap, V> { + /// Creates a new empty map. + pub const fn new() -> Self { + Self { v: Vec::new(), _ty: PhantomData } + } + + /// Create a new empty map with specific capacity. + pub fn with_capacity(capacity: usize) -> Self { + Self { v: Vec::with_capacity(capacity), _ty: PhantomData } + } + /// Inserts a value associated with a given arena index into the map. pub fn insert(&mut self, idx: Idx, t: V) { let idx = Self::to_idx(idx); @@ -70,6 +80,6 @@ impl std::ops::IndexMut> for ArenaMap, T> { impl Default for ArenaMap, T> { fn default() -> Self { - ArenaMap { v: Vec::new(), _ty: PhantomData } + Self::new() } } From 10f870eff44f07e3e8dc241e5cc11e0fa4d50ae3 Mon Sep 17 00:00:00 2001 From: oxalica Date: Wed, 3 Aug 2022 18:16:05 +0800 Subject: [PATCH 31/77] Impl entry-API for la_arena::ArenaMap We enforce integral and `Copy` key, so some key-related functions are not necessary since user can just reuse the index for the `entry` call. --- lib/la-arena/src/lib.rs | 2 +- lib/la-arena/src/map.rs | 107 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+), 1 deletion(-) diff --git a/lib/la-arena/src/lib.rs b/lib/la-arena/src/lib.rs index a6766edd419..a3fe59e946e 100644 --- a/lib/la-arena/src/lib.rs +++ b/lib/la-arena/src/lib.rs @@ -12,7 +12,7 @@ use std::{ }; mod map; -pub use map::ArenaMap; +pub use map::{ArenaMap, Entry, OccupiedEntry, VacantEntry}; /// The raw index of a value in an arena. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] diff --git a/lib/la-arena/src/map.rs b/lib/la-arena/src/map.rs index b5c49b3435d..f74ec5d97cb 100644 --- a/lib/la-arena/src/map.rs +++ b/lib/la-arena/src/map.rs @@ -56,6 +56,16 @@ impl ArenaMap, V> { self.v.iter().enumerate().filter_map(|(idx, o)| Some((Self::from_idx(idx), o.as_ref()?))) } + /// Gets the given key's corresponding entry in the map for in-place manipulation. + pub fn entry(&mut self, idx: Idx) -> Entry<'_, Idx, V> { + let idx = Self::to_idx(idx); + self.v.resize_with((idx + 1).max(self.v.len()), || None); + match &mut self.v[idx] { + slot @ Some(_) => Entry::Occupied(OccupiedEntry { slot, _ty: PhantomData }), + slot @ None => Entry::Vacant(VacantEntry { slot, _ty: PhantomData }), + } + } + fn to_idx(idx: Idx) -> usize { u32::from(idx.into_raw()) as usize } @@ -83,3 +93,100 @@ impl Default for ArenaMap, T> { Self::new() } } + +/// A view into a single entry in a map, which may either be vacant or occupied. +/// +/// This `enum` is constructed from the [`entry`] method on [`ArenaMap`]. +/// +/// [`entry`]: ArenaMap::entry +pub enum Entry<'a, IDX, V> { + /// A vacant entry. + Vacant(VacantEntry<'a, IDX, V>), + /// An occupied entry. + Occupied(OccupiedEntry<'a, IDX, V>), +} + +impl<'a, IDX, V> Entry<'a, IDX, V> { + /// Ensures a value is in the entry by inserting the default if empty, and returns a mutable reference to + /// the value in the entry. + pub fn or_insert(self, default: V) -> &'a mut V { + match self { + Self::Vacant(ent) => ent.insert(default), + Self::Occupied(ent) => ent.into_mut(), + } + } + + /// Ensures a value is in the entry by inserting the result of the default function if empty, and returns + /// a mutable reference to the value in the entry. + pub fn or_insert_with V>(self, default: F) -> &'a mut V { + match self { + Self::Vacant(ent) => ent.insert(default()), + Self::Occupied(ent) => ent.into_mut(), + } + } + + /// Provides in-place mutable access to an occupied entry before any potential inserts into the map. + pub fn and_modify(mut self, f: F) -> Self { + if let Self::Occupied(ent) = &mut self { + f(ent.get_mut()); + } + self + } +} + +impl<'a, IDX, V> Entry<'a, IDX, V> +where + V: Default, +{ + /// Ensures a value is in the entry by inserting the default value if empty, and returns a mutable reference + /// to the value in the entry. + pub fn or_default(self) -> &'a mut V { + self.or_insert_with(Default::default) + } +} + +/// A view into an vacant entry in a [`ArenaMap`]. It is part of the [`Entry`] enum. +pub struct VacantEntry<'a, IDX, V> { + slot: &'a mut Option, + _ty: PhantomData, +} + +impl<'a, IDX, V> VacantEntry<'a, IDX, V> { + /// Sets the value of the entry with the `VacantEntry`’s key, and returns a mutable reference to it. + pub fn insert(self, value: V) -> &'a mut V { + self.slot.insert(value) + } +} + +/// A view into an occupied entry in a [`ArenaMap`]. It is part of the [`Entry`] enum. +pub struct OccupiedEntry<'a, IDX, V> { + slot: &'a mut Option, + _ty: PhantomData, +} + +impl<'a, IDX, V> OccupiedEntry<'a, IDX, V> { + /// Gets a reference to the value in the entry. + pub fn get(&self) -> &V { + self.slot.as_ref().expect("Occupied") + } + + /// Gets a mutable reference to the value in the entry. + pub fn get_mut(&mut self) -> &mut V { + self.slot.as_mut().expect("Occupied") + } + + /// Converts the entry into a mutable reference to its value. + pub fn into_mut(self) -> &'a mut V { + self.slot.as_mut().expect("Occupied") + } + + /// Sets the value of the entry with the `OccupiedEntry`’s key, and returns the entry’s old value. + pub fn insert(&mut self, value: V) -> V { + self.slot.replace(value).expect("Occupied") + } + + /// Takes the value of the entry out of the map, and returns it. + pub fn remove(self) -> V { + self.slot.take().expect("Occupied") + } +} From a856e57f6cc8ba8bb83c5abadce338f589df6b10 Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Tue, 26 Jul 2022 17:51:55 +0100 Subject: [PATCH 32/77] Rustdoc-Json: Document HRTB's on DynTrait Closes #99118 --- src/librustdoc/json/conversions.rs | 48 ++++++++++++++---------------- src/rustdoc-json-types/lib.rs | 38 ++++++++++++++++++++--- src/test/rustdoc-json/type/dyn.rs | 45 ++++++++++++++++++---------- src/test/rustdoc-json/type/hrtb.rs | 9 ++++-- 4 files changed, 91 insertions(+), 49 deletions(-) diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 716a4c9ea43..f5c089ce1e4 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -244,7 +244,7 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum { TraitAliasItem(t) => ItemEnum::TraitAlias(t.into_tcx(tcx)), MethodItem(m, _) => ItemEnum::Method(from_function_method(m, true, header.unwrap(), tcx)), TyMethodItem(m) => ItemEnum::Method(from_function_method(m, false, header.unwrap(), tcx)), - ImplItem(i) => ItemEnum::Impl(i.into_tcx(tcx)), + ImplItem(i) => ItemEnum::Impl((*i).into_tcx(tcx)), StaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)), ForeignStaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)), ForeignTypeItem => ItemEnum::ForeignType, @@ -447,8 +447,8 @@ pub(crate) fn from_trait_bound_modifier( impl FromWithTcx for Type { fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self { use clean::Type::{ - Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive, - QPath, RawPointer, Slice, Tuple, + Array, BareFunction, BorrowedRef, Generic, ImplTrait, Infer, Primitive, QPath, + RawPointer, Slice, Tuple, }; match ty { @@ -458,26 +458,10 @@ impl FromWithTcx for Type { args: path.segments.last().map(|args| Box::new(args.clone().args.into_tcx(tcx))), param_names: Vec::new(), }, - DynTrait(mut bounds, lt) => { - let first_trait = bounds.remove(0).trait_; - - Type::ResolvedPath { - name: first_trait.whole_name(), - id: from_item_id(first_trait.def_id().into(), tcx), - args: first_trait - .segments - .last() - .map(|args| Box::new(args.clone().args.into_tcx(tcx))), - param_names: bounds - .into_iter() - .map(|t| { - clean::GenericBound::TraitBound(t, rustc_hir::TraitBoundModifier::None) - }) - .chain(lt.map(clean::GenericBound::Outlives)) - .map(|bound| bound.into_tcx(tcx)) - .collect(), - } - } + clean::Type::DynTrait(bounds, lt) => Type::DynTrait(DynTrait { + lifetime: lt.map(|lt| lt.0.to_string()), + traits: bounds.into_iter().map(|t| t.into_tcx(tcx)).collect(), + }), Generic(s) => Type::Generic(s.to_string()), Primitive(p) => Type::Primitive(p.as_sym().to_string()), BareFunction(f) => Type::FunctionPointer(Box::new((*f).into_tcx(tcx))), @@ -568,10 +552,22 @@ impl FromWithTcx for Trait { } } -impl FromWithTcx> for Impl { - fn from_tcx(impl_: Box, tcx: TyCtxt<'_>) -> Self { +impl FromWithTcx for PolyTrait { + fn from_tcx( + clean::PolyTrait { trait_, generic_params }: clean::PolyTrait, + tcx: TyCtxt<'_>, + ) -> Self { + PolyTrait { + trait_: clean::Type::Path { path: trait_ }.into_tcx(tcx), + generic_params: generic_params.into_iter().map(|x| x.into_tcx(tcx)).collect(), + } + } +} + +impl FromWithTcx for Impl { + fn from_tcx(impl_: clean::Impl, tcx: TyCtxt<'_>) -> Self { let provided_trait_methods = impl_.provided_trait_methods(tcx); - let clean::Impl { unsafety, generics, trait_, for_, items, polarity, kind } = *impl_; + let clean::Impl { unsafety, generics, trait_, for_, items, polarity, kind } = impl_; // FIXME: should `trait_` be a clean::Path equivalent in JSON? let trait_ = trait_.map(|path| clean::Type::Path { path }.into_tcx(tcx)); // FIXME: use something like ImplKind in JSON? diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 761e94c7ebb..bd4ea98441d 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -9,7 +9,7 @@ use std::path::PathBuf; use serde::{Deserialize, Serialize}; /// rustdoc format-version. -pub const FORMAT_VERSION: u32 = 16; +pub const FORMAT_VERSION: u32 = 17; /// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information /// about the language items in the local crate, as well as info about external items to allow @@ -115,6 +115,35 @@ pub enum Visibility { }, } +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub struct DynTrait { + /// All the traits implemented. One of them is the vtable, and the rest must be auto traits. + pub traits: Vec, + /// The lifetime of the whole dyn object + /// ```text + /// dyn Debug + 'static + /// ^^^^^^^ + /// | + /// this part + /// ``` + pub lifetime: Option, +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +/// A trait and potential HRTBs +pub struct PolyTrait { + #[serde(rename = "trait")] + pub trait_: Type, + /// Used for Higher-Rank Trait Bounds (HRTBs) + /// ```text + /// dyn for<'a> Fn() -> &'a i32" + /// ^^^^^^^ + /// | + /// this part + /// ``` + pub generic_params: Vec, +} + #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum GenericArgs { @@ -395,7 +424,7 @@ pub enum WherePredicate { type_: Type, bounds: Vec, /// Used for Higher-Rank Trait Bounds (HRTBs) - /// ```plain + /// ```text /// where for<'a> &'a T: Iterator," /// ^^^^^^^ /// | @@ -420,7 +449,7 @@ pub enum GenericBound { #[serde(rename = "trait")] trait_: Type, /// Used for Higher-Rank Trait Bounds (HRTBs) - /// ```plain + /// ```text /// where F: for<'a, 'b> Fn(&'a u8, &'b u8) /// ^^^^^^^^^^^ /// | @@ -458,6 +487,7 @@ pub enum Type { args: Option>, param_names: Vec, }, + DynTrait(DynTrait), /// Parameterized types Generic(String), /// Fixed-size numeric types (plus int/usize/float), char, arrays, slices, and tuples @@ -505,7 +535,7 @@ pub enum Type { pub struct FunctionPointer { pub decl: FnDecl, /// Used for Higher-Rank Trait Bounds (HRTBs) - /// ```plain + /// ```text /// for<'c> fn(val: &'c i32) -> i32 /// ^^^^^^^ /// | diff --git a/src/test/rustdoc-json/type/dyn.rs b/src/test/rustdoc-json/type/dyn.rs index 79eeb996dcc..c18b54d1fdf 100644 --- a/src/test/rustdoc-json/type/dyn.rs +++ b/src/test/rustdoc-json/type/dyn.rs @@ -1,10 +1,13 @@ // ignore-tidy-linelength +use std::fmt::Debug; -// @count dyn.json "$.index[*][?(@.name=='dyn')].inner.items[*]" 2 +// @count dyn.json "$.index[*][?(@.name=='dyn')].inner.items[*]" 3 // @set sync_int_gen = - "$.index[*][?(@.name=='SyncIntGen')].id" -// @set ref_fn = - "$.index[*][?(@.name=='RefFn')].id" +// @set ref_fn = - "$.index[*][?(@.name=='RefFn')].id" +// @set weird_order = - "$.index[*][?(@.name=='WeirdOrder')].id" // @has - "$.index[*][?(@.name=='dyn')].inner.items[*]" $sync_int_gen // @has - "$.index[*][?(@.name=='dyn')].inner.items[*]" $ref_fn +// @has - "$.index[*][?(@.name=='dyn')].inner.items[*]" $weird_order // @is - "$.index[*][?(@.name=='SyncIntGen')].kind" \"typedef\" // @is - "$.index[*][?(@.name=='SyncIntGen')].inner.generics" '{"params": [], "where_predicates": []}' @@ -12,14 +15,16 @@ // @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.name" \"Box\" // @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.bindings" [] // @count - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args" 1 -// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.kind" \"resolved_path\" -// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.kind" \"resolved_path\" -// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.name" \"Fn\" -// @count - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[*]" 3 -// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[0].trait_bound.trait.inner.name" \"Send\" -// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[1].trait_bound.trait.inner.name" \"Sync\" -// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[2]" "{\"outlives\": \"'static\"}" -// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.args" '{"parenthesized": {"inputs": [],"output": {"inner": "i32","kind": "primitive"}}}' +// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.kind" \"dyn_trait\" +// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.lifetime" \"\'static\" +// @count - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[*]" 3 +// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[0].generic_params" [] +// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[1].generic_params" [] +// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[2].generic_params" [] +// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[0].trait.inner.name" '"Fn"' +// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[1].trait.inner.name" '"Send"' +// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[2].trait.inner.name" '"Sync"' +// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[0].trait.inner.args" '{"parenthesized": {"inputs": [],"output": {"inner": "i32","kind": "primitive"}}}' pub type SyncIntGen = Box i32 + Send + Sync + 'static>; // @is - "$.index[*][?(@.name=='RefFn')].kind" \"typedef\" @@ -27,10 +32,18 @@ pub type SyncIntGen = Box i32 + Send + Sync + 'static>; // @is - "$.index[*][?(@.name=='RefFn')].inner.type.kind" '"borrowed_ref"' // @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.mutable" 'false' // @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.lifetime" "\"'a\"" -// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.kind" '"resolved_path"' -// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.name" '"Fn"' -// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.args.parenthesized.inputs[0].kind" '"borrowed_ref"' -// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.args.parenthesized.inputs[0].inner.lifetime" "\"'b\"" -// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.args.parenthesized.output.kind" '"borrowed_ref"' -// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.args.parenthesized.output.inner.lifetime" "\"'b\"" +// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.kind" '"dyn_trait"' +// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.lifetime" null +// @count - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[*]" 1 +// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].generic_params" '[{"kind": {"lifetime": {"outlives": []}},"name": "'\''b"}]' +// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].trait.kind" '"resolved_path"' +// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].trait.inner.name" '"Fn"' +// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].trait.inner.args.parenthesized.inputs[0].kind" '"borrowed_ref"' +// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].trait.inner.args.parenthesized.inputs[0].inner.lifetime" "\"'b\"" +// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].trait.inner.args.parenthesized.output.kind" '"borrowed_ref"' +// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].trait.inner.args.parenthesized.output.inner.lifetime" "\"'b\"" pub type RefFn<'a> = &'a dyn for<'b> Fn(&'b i32) -> &'b i32; + +// @is - "$.index[*][?(@.name=='WeirdOrder')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[0].trait.inner.name" '"Send"' +// @is - "$.index[*][?(@.name=='WeirdOrder')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[1].trait.inner.name" '"Debug"' +pub type WeirdOrder = Box; diff --git a/src/test/rustdoc-json/type/hrtb.rs b/src/test/rustdoc-json/type/hrtb.rs index 55bc043ad29..9311737be0f 100644 --- a/src/test/rustdoc-json/type/hrtb.rs +++ b/src/test/rustdoc-json/type/hrtb.rs @@ -1,3 +1,4 @@ +// ignore-tidy-linelength // @has hrtb.json @@ -14,9 +15,11 @@ where // @is - "$.index[*][?(@.name=='dynfn')].inner.generics" '{"params": [], "where_predicates": []}' // @is - "$.index[*][?(@.name=='dynfn')].inner.generics" '{"params": [], "where_predicates": []}' // @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].kind" '"borrowed_ref"' -// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].kind" '"borrowed_ref"' -// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.kind" '"resolved_path"' -// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.inner.name" '"Fn"' +// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.kind" '"dyn_trait"' +// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.inner.lifetime" null +// @count - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.inner.traits[*]" 1 +// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.inner.traits[0].generic_params" '[{"kind": {"lifetime": {"outlives": []}},"name": "'\''a"},{"kind": {"lifetime": {"outlives": []}},"name": "'\''b"}]' +// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.inner.traits[0].trait.inner.name" '"Fn"' pub fn dynfn(f: &dyn for<'a, 'b> Fn(&'a i32, &'b i32)) { let zero = 0; f(&zero, &zero); From 625c4d70ffa53e36d2b724d191f759937a131bff Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Tue, 26 Jul 2022 17:55:40 +0100 Subject: [PATCH 33/77] Rustdoc-Json: Extract `convert_lifetime` to function --- src/librustdoc/json/conversions.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index f5c089ce1e4..8d63c3409c2 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -145,7 +145,7 @@ impl FromWithTcx for GenericArg { fn from_tcx(arg: clean::GenericArg, tcx: TyCtxt<'_>) -> Self { use clean::GenericArg::*; match arg { - Lifetime(l) => GenericArg::Lifetime(l.0.to_string()), + Lifetime(l) => GenericArg::Lifetime(convert_lifetime(l)), Type(t) => GenericArg::Type(t.into_tcx(tcx)), Const(box c) => GenericArg::Const(c.into_tcx(tcx)), Infer => GenericArg::Infer, @@ -347,6 +347,10 @@ fn convert_abi(a: RustcAbi) -> Abi { } } +fn convert_lifetime(l: clean::Lifetime) -> String { + l.0.to_string() +} + impl FromWithTcx for Generics { fn from_tcx(generics: clean::Generics, tcx: TyCtxt<'_>) -> Self { Generics { @@ -374,7 +378,7 @@ impl FromWithTcx for GenericParamDefKind { use clean::GenericParamDefKind::*; match kind { Lifetime { outlives } => GenericParamDefKind::Lifetime { - outlives: outlives.into_iter().map(|lt| lt.0.to_string()).collect(), + outlives: outlives.into_iter().map(convert_lifetime).collect(), }, Type { did: _, bounds, default, synthetic } => GenericParamDefKind::Type { bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(), @@ -405,7 +409,7 @@ impl FromWithTcx for WherePredicate { .collect(), }, RegionPredicate { lifetime, bounds } => WherePredicate::RegionPredicate { - lifetime: lifetime.0.to_string(), + lifetime: convert_lifetime(lifetime) bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(), }, EqPredicate { lhs, rhs } => { @@ -428,7 +432,7 @@ impl FromWithTcx for GenericBound { modifier: from_trait_bound_modifier(modifier), } } - Outlives(lifetime) => GenericBound::Outlives(lifetime.0.to_string()), + Outlives(lifetime) => GenericBound::Outlives(convert_lifetime(lifetime)), } } } @@ -459,7 +463,7 @@ impl FromWithTcx for Type { param_names: Vec::new(), }, clean::Type::DynTrait(bounds, lt) => Type::DynTrait(DynTrait { - lifetime: lt.map(|lt| lt.0.to_string()), + lifetime: lt.map(convert_lifetime), traits: bounds.into_iter().map(|t| t.into_tcx(tcx)).collect(), }), Generic(s) => Type::Generic(s.to_string()), @@ -475,7 +479,7 @@ impl FromWithTcx for Type { type_: Box::new((*type_).into_tcx(tcx)), }, BorrowedRef { lifetime, mutability, type_ } => Type::BorrowedRef { - lifetime: lifetime.map(|l| l.0.to_string()), + lifetime: lifetime.map(convert_lifetime), mutable: mutability == ast::Mutability::Mut, type_: Box::new((*type_).into_tcx(tcx)), }, From 6290f92d07fd7ecdbd2f752fde9b12f926b592fa Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Wed, 27 Jul 2022 00:58:59 +0100 Subject: [PATCH 34/77] Rustdoc-Json: Add and use `FromWithTcx` for `Vec` --- src/librustdoc/json/conversions.rs | 64 +++++++++++++++--------------- 1 file changed, 31 insertions(+), 33 deletions(-) diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 8d63c3409c2..8caba8cb902 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -119,6 +119,16 @@ where } } +impl FromWithTcx for Vec +where + I: IntoIterator, + U: FromWithTcx, +{ + fn from_tcx(f: I, tcx: TyCtxt<'_>) -> Vec { + f.into_iter().map(|x| x.into_tcx(tcx)).collect() + } +} + pub(crate) fn from_deprecation(deprecation: rustc_attr::Deprecation) -> Deprecation { #[rustfmt::skip] let rustc_attr::Deprecation { since, note, is_since_rustc_version: _, suggestion: _ } = deprecation; @@ -130,11 +140,11 @@ impl FromWithTcx for GenericArgs { use clean::GenericArgs::*; match args { AngleBracketed { args, bindings } => GenericArgs::AngleBracketed { - args: args.into_vec().into_iter().map(|a| a.into_tcx(tcx)).collect(), - bindings: bindings.into_iter().map(|a| a.into_tcx(tcx)).collect(), + args: args.into_vec().into_tcx(tcx), + bindings: bindings.into_tcx(tcx), }, Parenthesized { inputs, output } => GenericArgs::Parenthesized { - inputs: inputs.into_vec().into_iter().map(|a| a.into_tcx(tcx)).collect(), + inputs: inputs.into_vec().into_tcx(tcx), output: output.map(|a| (*a).into_tcx(tcx)), }, } @@ -177,9 +187,7 @@ impl FromWithTcx for TypeBindingKind { use clean::TypeBindingKind::*; match kind { Equality { term } => TypeBindingKind::Equality(term.into_tcx(tcx)), - Constraint { bounds } => { - TypeBindingKind::Constraint(bounds.into_iter().map(|a| a.into_tcx(tcx)).collect()) - } + Constraint { bounds } => TypeBindingKind::Constraint(bounds.into_tcx(tcx)), } } } @@ -260,12 +268,12 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum { } TyAssocTypeItem(g, b) => ItemEnum::AssocType { generics: (*g).into_tcx(tcx), - bounds: b.into_iter().map(|x| x.into_tcx(tcx)).collect(), + bounds: b.into_tcx(tcx), default: None, }, AssocTypeItem(t, b) => ItemEnum::AssocType { generics: t.generics.into_tcx(tcx), - bounds: b.into_iter().map(|x| x.into_tcx(tcx)).collect(), + bounds: b.into_tcx(tcx), default: Some(t.item_type.unwrap_or(t.type_).into_tcx(tcx)), }, // `convert_item` early returns `None` for stripped items and keywords. @@ -354,12 +362,8 @@ fn convert_lifetime(l: clean::Lifetime) -> String { impl FromWithTcx for Generics { fn from_tcx(generics: clean::Generics, tcx: TyCtxt<'_>) -> Self { Generics { - params: generics.params.into_iter().map(|x| x.into_tcx(tcx)).collect(), - where_predicates: generics - .where_predicates - .into_iter() - .map(|x| x.into_tcx(tcx)) - .collect(), + params: generics.params.into_tcx(tcx), + where_predicates: generics.where_predicates.into_tcx(tcx), } } } @@ -381,7 +385,7 @@ impl FromWithTcx for GenericParamDefKind { outlives: outlives.into_iter().map(convert_lifetime).collect(), }, Type { did: _, bounds, default, synthetic } => GenericParamDefKind::Type { - bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(), + bounds: bounds.into_tcx(tcx), default: default.map(|x| (*x).into_tcx(tcx)), synthetic, }, @@ -399,7 +403,7 @@ impl FromWithTcx for WherePredicate { match predicate { BoundPredicate { ty, bounds, bound_params } => WherePredicate::BoundPredicate { type_: ty.into_tcx(tcx), - bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(), + bounds: bounds.into_tcx(tcx), generic_params: bound_params .into_iter() .map(|x| GenericParamDef { @@ -409,8 +413,8 @@ impl FromWithTcx for WherePredicate { .collect(), }, RegionPredicate { lifetime, bounds } => WherePredicate::RegionPredicate { - lifetime: convert_lifetime(lifetime) - bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(), + lifetime: convert_lifetime(lifetime), + bounds: bounds.into_tcx(tcx), }, EqPredicate { lhs, rhs } => { WherePredicate::EqPredicate { lhs: lhs.into_tcx(tcx), rhs: rhs.into_tcx(tcx) } @@ -428,7 +432,7 @@ impl FromWithTcx for GenericBound { let trait_ = clean::Type::Path { path: trait_ }.into_tcx(tcx); GenericBound::TraitBound { trait_, - generic_params: generic_params.into_iter().map(|x| x.into_tcx(tcx)).collect(), + generic_params: generic_params.into_tcx(tcx), modifier: from_trait_bound_modifier(modifier), } } @@ -464,15 +468,15 @@ impl FromWithTcx for Type { }, clean::Type::DynTrait(bounds, lt) => Type::DynTrait(DynTrait { lifetime: lt.map(convert_lifetime), - traits: bounds.into_iter().map(|t| t.into_tcx(tcx)).collect(), + traits: bounds.into_tcx(tcx), }), Generic(s) => Type::Generic(s.to_string()), Primitive(p) => Type::Primitive(p.as_sym().to_string()), BareFunction(f) => Type::FunctionPointer(Box::new((*f).into_tcx(tcx))), - Tuple(t) => Type::Tuple(t.into_iter().map(|x| x.into_tcx(tcx)).collect()), + Tuple(t) => Type::Tuple(t.into_tcx(tcx)), Slice(t) => Type::Slice(Box::new((*t).into_tcx(tcx))), Array(t, s) => Type::Array { type_: Box::new((*t).into_tcx(tcx)), len: s }, - ImplTrait(g) => Type::ImplTrait(g.into_iter().map(|x| x.into_tcx(tcx)).collect()), + ImplTrait(g) => Type::ImplTrait(g.into_tcx(tcx)), Infer => Type::Infer, RawPointer(mutability, type_) => Type::RawPointer { mutable: mutability == ast::Mutability::Mut, @@ -516,7 +520,7 @@ impl FromWithTcx for FunctionPointer { async_: false, abi: convert_abi(abi), }, - generic_params: generic_params.into_iter().map(|x| x.into_tcx(tcx)).collect(), + generic_params: generic_params.into_tcx(tcx), decl: decl.into_tcx(tcx), } } @@ -550,7 +554,7 @@ impl FromWithTcx for Trait { is_unsafe, items: ids(items, tcx), generics: generics.into_tcx(tcx), - bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(), + bounds: bounds.into_tcx(tcx), implementations: Vec::new(), // Added in JsonRenderer::item } } @@ -563,7 +567,7 @@ impl FromWithTcx for PolyTrait { ) -> Self { PolyTrait { trait_: clean::Type::Path { path: trait_ }.into_tcx(tcx), - generic_params: generic_params.into_iter().map(|x| x.into_tcx(tcx)).collect(), + generic_params: generic_params.into_tcx(tcx), } } } @@ -730,10 +734,7 @@ impl FromWithTcx> for Typedef { impl FromWithTcx for OpaqueTy { fn from_tcx(opaque: clean::OpaqueTy, tcx: TyCtxt<'_>) -> Self { - OpaqueTy { - bounds: opaque.bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(), - generics: opaque.generics.into_tcx(tcx), - } + OpaqueTy { bounds: opaque.bounds.into_tcx(tcx), generics: opaque.generics.into_tcx(tcx) } } } @@ -749,10 +750,7 @@ impl FromWithTcx for Static { impl FromWithTcx for TraitAlias { fn from_tcx(alias: clean::TraitAlias, tcx: TyCtxt<'_>) -> Self { - TraitAlias { - generics: alias.generics.into_tcx(tcx), - params: alias.bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(), - } + TraitAlias { generics: alias.generics.into_tcx(tcx), params: alias.bounds.into_tcx(tcx) } } } From a8a6c160be157ee7fe130d2c99521a2f76d3b4be Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 3 Aug 2022 18:10:15 +0200 Subject: [PATCH 35/77] Use an empty expander for ignored non-attribute proc-macros --- crates/rust-analyzer/src/reload.rs | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index eaab275bc68..9a9a9dd4d84 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -621,7 +621,10 @@ pub(crate) fn load_proc_macro( }; let expander: Arc = if dummy_replace.iter().any(|replace| &**replace == name) { - Arc::new(DummyExpander) + match kind { + ProcMacroKind::Attr => Arc::new(IdentityExpander), + _ => Arc::new(EmptyExpander), + } } else { Arc::new(Expander(expander)) }; @@ -647,11 +650,11 @@ pub(crate) fn load_proc_macro( } } - /// Dummy identity expander, used for proc-macros that are deliberately ignored by the user. + /// Dummy identity expander, used for attribute proc-macros that are deliberately ignored by the user. #[derive(Debug)] - struct DummyExpander; + struct IdentityExpander; - impl ProcMacroExpander for DummyExpander { + impl ProcMacroExpander for IdentityExpander { fn expand( &self, subtree: &tt::Subtree, @@ -661,6 +664,21 @@ pub(crate) fn load_proc_macro( Ok(subtree.clone()) } } + + /// Empty expander, used for proc-macros that are deliberately ignored by the user. + #[derive(Debug)] + struct EmptyExpander; + + impl ProcMacroExpander for EmptyExpander { + fn expand( + &self, + _: &tt::Subtree, + _: Option<&tt::Subtree>, + _: &Env, + ) -> Result { + Ok(tt::Subtree::default()) + } + } } pub(crate) fn should_refresh_for_change(path: &AbsPath, change_kind: ChangeKind) -> bool { From 46d6357994eb8ced835a69390dfbf01abed40ee1 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 3 Aug 2022 18:22:45 +0200 Subject: [PATCH 36/77] Add a setting to disable comment continuation in VSCode --- editors/code/package.json | 5 +++++ editors/code/src/config.ts | 14 +++++++++++--- editors/code/src/main.ts | 4 +++- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/editors/code/package.json b/editors/code/package.json index a13798d8b36..39ff3eb0855 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -380,6 +380,11 @@ "default": false, "type": "boolean" }, + "rust-analyzer.typing.continueCommentsOnNewline": { + "markdownDescription": "Whether to prefix newlines after comments with the corresponding comment prefix.", + "default": true, + "type": "boolean" + }, "$generated-start": {}, "rust-analyzer.assist.expressionFillDefault": { "markdownDescription": "Placeholder expression to use for missing expressions in assists.", diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index b04f18890b9..1c58040d58c 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts @@ -16,9 +16,13 @@ export class Config { readonly extensionId = "rust-lang.rust-analyzer"; readonly rootSection = "rust-analyzer"; - private readonly requiresWorkspaceReloadOpts = ["serverPath", "server"].map( - (opt) => `${this.rootSection}.${opt}` - ); + private readonly requiresWorkspaceReloadOpts = [ + "serverPath", + "server", + // FIXME: This shouldn't be here, changing this setting should reload + // `continueCommentsOnNewline` behavior without restart + "typing", + ].map((opt) => `${this.rootSection}.${opt}`); private readonly requiresReloadOpts = [ "cargo", "procMacro", @@ -140,6 +144,10 @@ export class Config { return this.get("restartServerOnConfigChange"); } + get typingContinueCommentsOnNewline() { + return this.get("typing.continueCommentsOnNewline"); + } + get debug() { let sourceFileMap = this.get | "auto">("debug.sourceFileMap"); if (sourceFileMap !== "auto") { diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index 9ae20ddc4ac..d78b711a47a 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts @@ -84,7 +84,9 @@ async function tryActivate(context: vscode.ExtensionContext): Promise From 845009d0718d07415d774c930f6cbe32509d03b8 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 25 Jun 2022 16:18:44 +0200 Subject: [PATCH 37/77] Only fetch HIR for naked functions that have the attribute. --- compiler/rustc_passes/src/naked_functions.rs | 94 +++++++++----------- 1 file changed, 41 insertions(+), 53 deletions(-) diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index 20765abf392..296b6ed5d99 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -1,11 +1,12 @@ //! Checks validity of naked functions. -use rustc_ast::{Attribute, InlineAsmOptions}; +use rustc_ast::InlineAsmOptions; use rustc_errors::{struct_span_err, Applicability}; use rustc_hir as hir; +use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; -use rustc_hir::intravisit::{FnKind, Visitor}; -use rustc_hir::{ExprKind, HirId, InlineAsmOperand, StmtKind}; +use rustc_hir::intravisit::Visitor; +use rustc_hir::{ExprKind, InlineAsmOperand, StmtKind}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::lint::builtin::UNDEFINED_NAKED_FUNCTION_ABI; @@ -13,71 +14,58 @@ use rustc_span::symbol::sym; use rustc_span::Span; use rustc_target::spec::abi::Abi; -fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { - tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckNakedFunctions { tcx }); -} - pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { check_mod_naked_functions, ..*providers }; } -struct CheckNakedFunctions<'tcx> { - tcx: TyCtxt<'tcx>, -} - -impl<'tcx> Visitor<'tcx> for CheckNakedFunctions<'tcx> { - fn visit_fn( - &mut self, - fk: FnKind<'_>, - _fd: &'tcx hir::FnDecl<'tcx>, - body_id: hir::BodyId, - span: Span, - hir_id: HirId, - ) { - let ident_span; - let fn_header; - - match fk { - FnKind::Closure => { - // Closures with a naked attribute are rejected during attribute - // check. Don't validate them any further. - return; - } - FnKind::ItemFn(ident, _, ref header, ..) => { - ident_span = ident.span; - fn_header = header; - } - - FnKind::Method(ident, ref sig, ..) => { - ident_span = ident.span; - fn_header = &sig.header; - } +fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { + let items = tcx.hir_module_items(module_def_id); + for def_id in items.definitions() { + if !matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn) { + continue; } - let attrs = self.tcx.hir().attrs(hir_id); - let naked = attrs.iter().any(|attr| attr.has_name(sym::naked)); - if naked { - let body = self.tcx.hir().body(body_id); - check_abi(self.tcx, hir_id, fn_header.abi, ident_span); - check_no_patterns(self.tcx, body.params); - check_no_parameters_use(self.tcx, body); - check_asm(self.tcx, body, span); - check_inline(self.tcx, attrs); + let naked = tcx.has_attr(def_id.to_def_id(), sym::naked); + if !naked { + continue; } + + let (fn_header, body_id) = match tcx.hir().get_by_def_id(def_id) { + hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. }) + | hir::Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)), + .. + }) + | hir::Node::ImplItem(hir::ImplItem { + kind: hir::ImplItemKind::Fn(sig, body_id), + .. + }) => (sig.header, *body_id), + _ => continue, + }; + + let body = tcx.hir().body(body_id); + check_abi(tcx, def_id, fn_header.abi); + check_no_patterns(tcx, body.params); + check_no_parameters_use(tcx, body); + check_asm(tcx, def_id, body); + check_inline(tcx, def_id); } } /// Check that the function isn't inlined. -fn check_inline(tcx: TyCtxt<'_>, attrs: &[Attribute]) { - for attr in attrs.iter().filter(|attr| attr.has_name(sym::inline)) { +fn check_inline(tcx: TyCtxt<'_>, def_id: LocalDefId) { + let attrs = tcx.get_attrs(def_id.to_def_id(), sym::inline); + for attr in attrs { tcx.sess.struct_span_err(attr.span, "naked functions cannot be inlined").emit(); } } /// Checks that function uses non-Rust ABI. -fn check_abi(tcx: TyCtxt<'_>, hir_id: HirId, abi: Abi, fn_ident_span: Span) { +fn check_abi(tcx: TyCtxt<'_>, def_id: LocalDefId, abi: Abi) { if abi == Abi::Rust { - tcx.struct_span_lint_hir(UNDEFINED_NAKED_FUNCTION_ABI, hir_id, fn_ident_span, |lint| { + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let span = tcx.def_span(def_id); + tcx.struct_span_lint_hir(UNDEFINED_NAKED_FUNCTION_ABI, hir_id, span, |lint| { lint.build("Rust ABI is unsupported in naked functions").emit(); }); } @@ -141,7 +129,7 @@ impl<'tcx> Visitor<'tcx> for CheckParameters<'tcx> { } /// Checks that function body contains a single inline assembly block. -fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, body: &'tcx hir::Body<'tcx>, fn_span: Span) { +fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body<'tcx>) { let mut this = CheckInlineAssembly { tcx, items: Vec::new() }; this.visit_body(body); if let [(ItemKind::Asm | ItemKind::Err, _)] = this.items[..] { @@ -149,7 +137,7 @@ fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, body: &'tcx hir::Body<'tcx>, fn_span: Span } else { let mut diag = struct_span_err!( tcx.sess, - fn_span, + tcx.def_span(def_id), E0787, "naked functions must contain a single asm block" ); From 6eb0c89f6bbe0f81a03b9faa1dca0577a56d8def Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 25 Jun 2022 17:45:42 +0200 Subject: [PATCH 38/77] Bless ui tests. --- src/test/ui/asm/naked-functions.stderr | 103 +++++++++++-------------- 1 file changed, 45 insertions(+), 58 deletions(-) diff --git a/src/test/ui/asm/naked-functions.stderr b/src/test/ui/asm/naked-functions.stderr index 1828066b692..f90967fbe6e 100644 --- a/src/test/ui/asm/naked-functions.stderr +++ b/src/test/ui/asm/naked-functions.stderr @@ -57,13 +57,11 @@ LL | a + 1 error[E0787]: naked functions must contain a single asm block --> $DIR/naked-functions.rs:33:1 | -LL | / pub unsafe extern "C" fn inc(a: u32) -> u32 { -LL | | -LL | | a + 1 - | | ----- non-asm is unsupported in naked functions -LL | | -LL | | } - | |_^ +LL | pub unsafe extern "C" fn inc(a: u32) -> u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | a + 1 + | ----- non-asm is unsupported in naked functions error: referencing function parameters is not allowed in naked functions --> $DIR/naked-functions.rs:42:31 @@ -82,12 +80,11 @@ LL | asm!("/* {0} */", in(reg) a, options(noreturn)); error[E0787]: naked functions must contain a single asm block --> $DIR/naked-functions.rs:48:1 | -LL | / pub unsafe extern "C" fn inc_closure(a: u32) -> u32 { -LL | | -LL | | (|| a + 1)() - | | ------------ non-asm is unsupported in naked functions -LL | | } - | |_^ +LL | pub unsafe extern "C" fn inc_closure(a: u32) -> u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | (|| a + 1)() + | ------------ non-asm is unsupported in naked functions error[E0787]: only `const` and `sym` operands are supported in naked functions --> $DIR/naked-functions.rs:65:10 @@ -124,30 +121,25 @@ LL | sym G, options(noreturn), error[E0787]: naked functions must contain a single asm block --> $DIR/naked-functions.rs:54:1 | -LL | / pub unsafe extern "C" fn unsupported_operands() { -LL | | -LL | | let mut a = 0usize; - | | ------------------- non-asm is unsupported in naked functions -LL | | let mut b = 0usize; - | | ------------------- non-asm is unsupported in naked functions -LL | | let mut c = 0usize; - | | ------------------- non-asm is unsupported in naked functions -LL | | let mut d = 0usize; - | | ------------------- non-asm is unsupported in naked functions -LL | | let mut e = 0usize; - | | ------------------- non-asm is unsupported in naked functions -... | -LL | | ); -LL | | } - | |_^ +LL | pub unsafe extern "C" fn unsupported_operands() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | let mut a = 0usize; + | ------------------- non-asm is unsupported in naked functions +LL | let mut b = 0usize; + | ------------------- non-asm is unsupported in naked functions +LL | let mut c = 0usize; + | ------------------- non-asm is unsupported in naked functions +LL | let mut d = 0usize; + | ------------------- non-asm is unsupported in naked functions +LL | let mut e = 0usize; + | ------------------- non-asm is unsupported in naked functions error[E0787]: naked functions must contain a single asm block --> $DIR/naked-functions.rs:77:1 | -LL | / pub extern "C" fn missing_assembly() { -LL | | -LL | | } - | |_^ +LL | pub extern "C" fn missing_assembly() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0787]: asm in naked functions must use `noreturn` option --> $DIR/naked-functions.rs:84:5 @@ -185,20 +177,17 @@ LL | asm!("", options(noreturn)); error[E0787]: naked functions must contain a single asm block --> $DIR/naked-functions.rs:82:1 | -LL | / pub extern "C" fn too_many_asm_blocks() { -LL | | -LL | | asm!(""); -LL | | -LL | | asm!(""); - | | -------- multiple asm blocks are unsupported in naked functions -LL | | -LL | | asm!(""); - | | -------- multiple asm blocks are unsupported in naked functions -LL | | -LL | | asm!("", options(noreturn)); - | | --------------------------- multiple asm blocks are unsupported in naked functions -LL | | } - | |_^ +LL | pub extern "C" fn too_many_asm_blocks() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | asm!(""); + | -------- multiple asm blocks are unsupported in naked functions +LL | +LL | asm!(""); + | -------- multiple asm blocks are unsupported in naked functions +LL | +LL | asm!("", options(noreturn)); + | --------------------------- multiple asm blocks are unsupported in naked functions error: referencing function parameters is not allowed in naked functions --> $DIR/naked-functions.rs:97:11 @@ -211,13 +200,11 @@ LL | *&y error[E0787]: naked functions must contain a single asm block --> $DIR/naked-functions.rs:95:5 | -LL | / pub extern "C" fn inner(y: usize) -> usize { -LL | | -LL | | *&y - | | --- non-asm is unsupported in naked functions -LL | | -LL | | } - | |_____^ +LL | pub extern "C" fn inner(y: usize) -> usize { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | *&y + | --- non-asm is unsupported in naked functions error[E0787]: asm options unsupported in naked functions: `nomem`, `preserves_flags` --> $DIR/naked-functions.rs:105:5 @@ -249,18 +236,18 @@ LL | asm!("", options(noreturn, may_unwind)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: Rust ABI is unsupported in naked functions - --> $DIR/naked-functions.rs:124:15 + --> $DIR/naked-functions.rs:124:1 | LL | pub unsafe fn default_abi() { - | ^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `#[warn(undefined_naked_function_abi)]` on by default warning: Rust ABI is unsupported in naked functions - --> $DIR/naked-functions.rs:130:15 + --> $DIR/naked-functions.rs:130:1 | LL | pub unsafe fn rust_abi() { - | ^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ error: naked functions cannot be inlined --> $DIR/naked-functions.rs:170:1 From 49dac4070cf731ad53bfe12e784975b38262d6ab Mon Sep 17 00:00:00 2001 From: Jean santos Date: Wed, 3 Aug 2022 17:37:11 -0300 Subject: [PATCH 39/77] on hover fallback error, adds ast::type as possible node --- crates/ide/src/hover.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 59c97f2dcf9..f74b981a28b 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs @@ -235,7 +235,11 @@ fn hover_type_fallback( let node = token .parent_ancestors() .take_while(|it| !ast::Item::can_cast(it.kind())) - .find(|n| ast::Expr::can_cast(n.kind()) || ast::Pat::can_cast(n.kind()))?; + .find(|n| { + ast::Expr::can_cast(n.kind()) + || ast::Pat::can_cast(n.kind()) + || ast::Type::can_cast(n.kind()) + })?; let expr_or_pat = match_ast! { match node { From df9d3db82f1d0dce5f74faf8ae0501a534953f84 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 4 Aug 2022 13:22:15 +0200 Subject: [PATCH 40/77] Trigger flycheck on all transitive dependencies as well --- crates/rust-analyzer/src/main_loop.rs | 32 ++++++++++++++++++++------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 561c2d7aef7..5c93874ca2a 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -9,7 +9,8 @@ use std::{ use always_assert::always; use crossbeam_channel::{select, Receiver}; -use ide_db::base_db::{SourceDatabaseExt, VfsPath}; +use ide_db::base_db::{SourceDatabase, SourceDatabaseExt, VfsPath}; +use itertools::Itertools; use lsp_server::{Connection, Notification, Request}; use lsp_types::notification::Notification as _; use vfs::{ChangeKind, FileId}; @@ -727,9 +728,21 @@ impl GlobalState { let (vfs, _) = &*this.vfs.read(); if let Some(file_id) = vfs.file_id(&vfs_path) { let analysis = this.analysis_host.analysis(); - let crate_ids = analysis.crate_for(file_id)?; + // Crates containing or depending on the saved file + let crate_ids: Vec<_> = analysis + .crate_for(file_id)? + .into_iter() + .flat_map(|id| { + this.analysis_host + .raw_database() + .crate_graph() + .transitive_rev_deps(id) + }) + .sorted() + .unique() + .collect(); - let paths: Vec<_> = crate_ids + let crate_root_paths: Vec<_> = crate_ids .iter() .filter_map(|&crate_id| { analysis @@ -740,16 +753,17 @@ impl GlobalState { .transpose() }) .collect::>()?; - let paths: Vec<_> = paths.iter().map(Deref::deref).collect(); + let crate_root_paths: Vec<_> = + crate_root_paths.iter().map(Deref::deref).collect(); + // Find all workspaces that have at least one target containing the saved file let workspace_ids = this.workspaces.iter().enumerate().filter(|(_, ws)| match ws { project_model::ProjectWorkspace::Cargo { cargo, .. } => { cargo.packages().any(|pkg| { - cargo[pkg] - .targets - .iter() - .any(|&it| paths.contains(&cargo[it].root.as_path())) + cargo[pkg].targets.iter().any(|&it| { + crate_root_paths.contains(&cargo[it].root.as_path()) + }) }) } project_model::ProjectWorkspace::Json { project, .. } => project @@ -757,6 +771,8 @@ impl GlobalState { .any(|(c, _)| crate_ids.iter().any(|&crate_id| crate_id == c)), project_model::ProjectWorkspace::DetachedFiles { .. } => false, }); + + // Find and trigger corresponding flychecks for flycheck in &this.flycheck { for (id, _) in workspace_ids.clone() { if id == flycheck.id() { From 5698e51027a8f60e0fd7b8ae5f7c077b051197c6 Mon Sep 17 00:00:00 2001 From: Jean santos Date: Thu, 4 Aug 2022 09:28:34 -0300 Subject: [PATCH 41/77] tidy formatting --- crates/ide/src/hover.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index f74b981a28b..784f85dbbef 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs @@ -232,10 +232,8 @@ fn hover_type_fallback( token: &SyntaxToken, original_token: &SyntaxToken, ) -> Option> { - let node = token - .parent_ancestors() - .take_while(|it| !ast::Item::can_cast(it.kind())) - .find(|n| { + let node = + token.parent_ancestors().take_while(|it| !ast::Item::can_cast(it.kind())).find(|n| { ast::Expr::can_cast(n.kind()) || ast::Pat::can_cast(n.kind()) || ast::Type::can_cast(n.kind()) From df7f755e3b08e58a30bdbb39685bea76be7762ba Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 4 Aug 2022 14:01:33 +0200 Subject: [PATCH 42/77] Don't flycheck while the workspace is being loaded --- crates/rust-analyzer/src/diagnostics.rs | 1 - crates/rust-analyzer/src/global_state.rs | 1 + crates/rust-analyzer/src/main_loop.rs | 5 ++++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/crates/rust-analyzer/src/diagnostics.rs b/crates/rust-analyzer/src/diagnostics.rs index 7917ced666a..09150c77d7d 100644 --- a/crates/rust-analyzer/src/diagnostics.rs +++ b/crates/rust-analyzer/src/diagnostics.rs @@ -72,7 +72,6 @@ impl DiagnosticCollection { let check_fixes = Arc::make_mut(&mut self.check_fixes); check_fixes.entry(flycheck_id).or_default().entry(file_id).or_default().extend(fix); diagnostics.push(diagnostic); - tracing::warn!(?flycheck_id, ?file_id, "add_check_diagnostic changes pushed"); self.changes.insert(file_id); } diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index 2cd2044aeff..55c4cfcf860 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -192,6 +192,7 @@ impl GlobalState { if let Some(path) = vfs.file_path(file.file_id).as_path() { let path = path.to_path_buf(); if reload::should_refresh_for_change(&path, file.change_kind) { + tracing::warn!("fetch-fiel_change"); self.fetch_workspaces_queue .request_op(format!("vfs file change: {}", path.display())); } diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 5c93874ca2a..4ed34df01ca 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -447,7 +447,10 @@ impl GlobalState { let memdocs_added_or_removed = self.mem_docs.take_changes(); if self.is_quiescent() { - if !was_quiescent { + if !was_quiescent + && !self.fetch_workspaces_queue.op_requested() + && !self.fetch_build_data_queue.op_requested() + { for flycheck in &self.flycheck { flycheck.update(); } From 30c4f9fa7d31cd60f1fcc5998af6c17f69178fae Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 5 Aug 2022 08:42:13 +0200 Subject: [PATCH 43/77] Update bug_report.md --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 1f246ed79b6..5566b3d1f8d 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -19,7 +19,7 @@ Before submitting, please make sure that you're not running into one of these kn Otherwise please try to provide information which will help us to fix the issue faster. Minimal reproducible examples with few dependencies are especially lovely <3. --> -**rust-analyzer version**: (eg. output of "rust-analyzer: Show RA Version" command) +**rust-analyzer version**: (eg. output of "rust-analyzer: Show RA Version" command, accessible in VSCode via Ctrl+Shift+P) **rustc version**: (eg. output of `rustc -V`) From d94a42d652f4c402891bd2b1004364d32bc41253 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 5 Aug 2022 09:04:27 +0200 Subject: [PATCH 44/77] Update bug_report.md --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 5566b3d1f8d..a038dce3248 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -19,7 +19,7 @@ Before submitting, please make sure that you're not running into one of these kn Otherwise please try to provide information which will help us to fix the issue faster. Minimal reproducible examples with few dependencies are especially lovely <3. --> -**rust-analyzer version**: (eg. output of "rust-analyzer: Show RA Version" command, accessible in VSCode via Ctrl+Shift+P) +**rust-analyzer version**: (eg. output of "rust-analyzer: Show RA Version" command, accessible in VSCode via Ctrl/⌘+Shift+P) **rustc version**: (eg. output of `rustc -V`) From f6d42aa336d3c399a4f8d7443d25332d1754b5f9 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Fri, 5 Aug 2022 18:14:15 +0900 Subject: [PATCH 45/77] remove an unnecessary `str::rfind` --- compiler/rustc_typeck/src/check/expr.rs | 53 ++++++++----------- .../ui/typeck/issue-91210-ptr-method.stderr | 9 ++-- 2 files changed, 28 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index e20c6a2d99a..fc54eedcffe 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -50,7 +50,6 @@ use rustc_span::hygiene::DesugaringKind; use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::source_map::{Span, Spanned}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{BytePos, Pos}; use rustc_target::spec::abi::Abi::RustIntrinsic; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::{self, ObligationCauseCode}; @@ -2391,37 +2390,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr, Some(span), ); + } else if let ty::RawPtr(ty_and_mut) = expr_t.kind() + && let ty::Adt(adt_def, _) = ty_and_mut.ty.kind() + && let ExprKind::Field(base_expr, _) = expr.kind + && adt_def.variants().len() == 1 + && adt_def + .variants() + .iter() + .next() + .unwrap() + .fields + .iter() + .any(|f| f.ident(self.tcx) == field) + { + err.multipart_suggestion( + "to access the field, dereference first", + vec![ + (base_expr.span.shrink_to_lo(), "(*".to_string()), + (base_expr.span.shrink_to_hi(), ")".to_string()), + ], + Applicability::MaybeIncorrect, + ); } else { - let mut found = false; - - if let ty::RawPtr(ty_and_mut) = expr_t.kind() - && let ty::Adt(adt_def, _) = ty_and_mut.ty.kind() - { - if adt_def.variants().len() == 1 - && adt_def - .variants() - .iter() - .next() - .unwrap() - .fields - .iter() - .any(|f| f.ident(self.tcx) == field) - { - if let Some(dot_loc) = expr_snippet.rfind('.') { - found = true; - err.span_suggestion( - expr.span.with_hi(expr.span.lo() + BytePos::from_usize(dot_loc)), - "to access the field, dereference first", - format!("(*{})", &expr_snippet[0..dot_loc]), - Applicability::MaybeIncorrect, - ); - } - } - } - - if !found { - err.help("methods are immutable and cannot be assigned to"); - } + err.help("methods are immutable and cannot be assigned to"); } err.emit(); diff --git a/src/test/ui/typeck/issue-91210-ptr-method.stderr b/src/test/ui/typeck/issue-91210-ptr-method.stderr index 503a32373d5..7a0cfb2cf51 100644 --- a/src/test/ui/typeck/issue-91210-ptr-method.stderr +++ b/src/test/ui/typeck/issue-91210-ptr-method.stderr @@ -2,9 +2,12 @@ error[E0615]: attempted to take value of method `read` on type `*mut Foo` --> $DIR/issue-91210-ptr-method.rs:10:7 | LL | x.read = 4; - | - ^^^^ method, not a field - | | - | help: to access the field, dereference first: `(*x)` + | ^^^^ method, not a field + | +help: to access the field, dereference first + | +LL | (*x).read = 4; + | ++ + error: aborting due to previous error From 6a1737242b75ae96bae03885c3d3e75b61a3f8ed Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 5 Aug 2022 12:06:31 +0200 Subject: [PATCH 46/77] Don't switch workspace on vfs file changes from libraries When r-a starts up, it starts switching the workspace before all vfs events have been processed which causes us to switch workspace multiple times until all vfs changes have been processed. This scales with the size of the project and its dependencies. If workspace files from dependencies as well as the sysroot get loaded, we shouldn't switch the workspace as those have no impact on the project workspace. --- crates/rust-analyzer/src/global_state.rs | 34 +++++++++++-------- crates/rust-analyzer/src/reload.rs | 42 +++++++++++------------- crates/vfs-notify/src/lib.rs | 7 +++- 3 files changed, 47 insertions(+), 36 deletions(-) diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index 932a31e08f6..b5f6aef2e1a 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -8,7 +8,7 @@ use std::{sync::Arc, time::Instant}; use crossbeam_channel::{unbounded, Receiver, Sender}; use flycheck::FlycheckHandle; use ide::{Analysis, AnalysisHost, Cancellable, Change, FileId}; -use ide_db::base_db::{CrateId, FileLoader, SourceDatabase}; +use ide_db::base_db::{CrateId, FileLoader, SourceDatabase, SourceDatabaseExt}; use lsp_types::{SemanticTokens, Url}; use parking_lot::{Mutex, RwLock}; use proc_macro_api::ProcMacroServer; @@ -176,7 +176,7 @@ impl GlobalState { pub(crate) fn process_changes(&mut self) -> bool { let _p = profile::span("GlobalState::process_changes"); - let mut fs_changes = Vec::new(); + let mut fs_refresh_changes = Vec::new(); // A file was added or deleted let mut has_structure_changes = false; @@ -192,11 +192,8 @@ impl GlobalState { if let Some(path) = vfs.file_path(file.file_id).as_path() { let path = path.to_path_buf(); if reload::should_refresh_for_change(&path, file.change_kind) { - tracing::warn!("fetch-fiel_change"); - self.fetch_workspaces_queue - .request_op(format!("vfs file change: {}", path.display())); + fs_refresh_changes.push((path, file.file_id)); } - fs_changes.push((path, file.change_kind)); if file.is_created_or_deleted() { has_structure_changes = true; } @@ -228,14 +225,25 @@ impl GlobalState { self.analysis_host.apply_change(change); - let raw_database = &self.analysis_host.raw_database(); - self.proc_macro_changed = - changed_files.iter().filter(|file| !file.is_created_or_deleted()).any(|file| { - let crates = raw_database.relevant_crates(file.file_id); - let crate_graph = raw_database.crate_graph(); + { + let raw_database = self.analysis_host.raw_database(); + let workspace_structure_change = + fs_refresh_changes.into_iter().find(|&(_, file_id)| { + !raw_database.source_root(raw_database.file_source_root(file_id)).is_library + }); + if let Some((path, _)) = workspace_structure_change { + self.fetch_workspaces_queue + .request_op(format!("workspace vfs file change: {}", path.display())); + } + self.proc_macro_changed = + changed_files.iter().filter(|file| !file.is_created_or_deleted()).any(|file| { + let crates = raw_database.relevant_crates(file.file_id); + let crate_graph = raw_database.crate_graph(); + + crates.iter().any(|&krate| crate_graph[krate].is_proc_macro) + }); + } - crates.iter().any(|&krate| crate_graph[krate].is_proc_macro) - }); true } diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index c90291eb5e2..49ccad71a10 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -196,10 +196,7 @@ impl GlobalState { } if let Err(error) = self.fetch_build_data_error() { - self.show_and_log_error( - "rust-analyzer failed to run build scripts".to_string(), - Some(error), - ); + self.show_and_log_error("failed to run build scripts".to_string(), Some(error)); } let workspaces = self @@ -308,6 +305,7 @@ impl GlobalState { if self.proc_macro_clients.is_empty() { if let Some((path, args)) = self.config.proc_macro_srv() { + tracing::info!("Spawning proc-macro servers"); self.proc_macro_clients = self .workspaces .iter() @@ -316,20 +314,20 @@ impl GlobalState { let mut path = path.clone(); if let ProjectWorkspace::Cargo { sysroot, .. } = ws { - tracing::info!("Found a cargo workspace..."); + tracing::debug!("Found a cargo workspace..."); if let Some(sysroot) = sysroot.as_ref() { - tracing::info!("Found a cargo workspace with a sysroot..."); + tracing::debug!("Found a cargo workspace with a sysroot..."); let server_path = sysroot.root().join("libexec").join(&standalone_server_name); if std::fs::metadata(&server_path).is_ok() { - tracing::info!( + tracing::debug!( "And the server exists at {}", server_path.display() ); path = server_path; args = vec![]; } else { - tracing::info!( + tracing::debug!( "And the server does not exist at {}", server_path.display() ); @@ -337,14 +335,10 @@ impl GlobalState { } } - tracing::info!( - "Using proc-macro server at {} with args {:?}", - path.display(), - args - ); + tracing::info!(?args, "Using proc-macro server at {}", path.display(),); ProcMacroServer::spawn(path.clone(), args.clone()).map_err(|err| { let error = format!( - "Failed to run proc_macro_srv from path {}, error: {:?}", + "Failed to run proc-macro server from path {}, error: {:?}", path.display(), err ); @@ -684,22 +678,26 @@ pub(crate) fn load_proc_macro( pub(crate) fn should_refresh_for_change(path: &AbsPath, change_kind: ChangeKind) -> bool { const IMPLICIT_TARGET_FILES: &[&str] = &["build.rs", "src/main.rs", "src/lib.rs"]; const IMPLICIT_TARGET_DIRS: &[&str] = &["src/bin", "examples", "tests", "benches"]; - let file_name = path.file_name().unwrap_or_default(); - if file_name == "Cargo.toml" || file_name == "Cargo.lock" { + let file_name = match path.file_name().unwrap_or_default().to_str() { + Some(it) => it, + None => return false, + }; + + if let "Cargo.toml" | "Cargo.lock" = file_name { return true; } if change_kind == ChangeKind::Modify { return false; } + + // .cargo/config{.toml} if path.extension().unwrap_or_default() != "rs" { - if (file_name == "config.toml" || file_name == "config") - && path.parent().map(|parent| parent.as_ref().ends_with(".cargo")) == Some(true) - { - return true; - } - return false; + let is_cargo_config = matches!(file_name, "config.toml" | "config") + && path.parent().map(|parent| parent.as_ref().ends_with(".cargo")).unwrap_or(false); + return is_cargo_config; } + if IMPLICIT_TARGET_FILES.iter().any(|it| path.as_ref().ends_with(it)) { return true; } diff --git a/crates/vfs-notify/src/lib.rs b/crates/vfs-notify/src/lib.rs index 4d33a9afb96..d6d9c66159f 100644 --- a/crates/vfs-notify/src/lib.rs +++ b/crates/vfs-notify/src/lib.rs @@ -40,12 +40,15 @@ impl loader::Handle for NotifyHandle { .expect("failed to spawn thread"); NotifyHandle { sender, _thread: thread } } + fn set_config(&mut self, config: loader::Config) { self.sender.send(Message::Config(config)).unwrap(); } + fn invalidate(&mut self, path: AbsPathBuf) { self.sender.send(Message::Invalidate(path)).unwrap(); } + fn load_sync(&mut self, path: &AbsPath) -> Option> { read(path) } @@ -70,6 +73,7 @@ impl NotifyActor { fn new(sender: loader::Sender) -> NotifyActor { NotifyActor { sender, watched_entries: Vec::new(), watcher: None } } + fn next_event(&self, receiver: &Receiver) -> Option { let watcher_receiver = self.watcher.as_ref().map(|(_, receiver)| receiver); select! { @@ -77,9 +81,10 @@ impl NotifyActor { recv(watcher_receiver.unwrap_or(&never())) -> it => Some(Event::NotifyEvent(it.unwrap())), } } + fn run(mut self, inbox: Receiver) { while let Some(event) = self.next_event(&inbox) { - tracing::debug!("vfs-notify event: {:?}", event); + tracing::debug!(?event, "vfs-notify event"); match event { Event::Message(msg) => match msg { Message::Config(config) => { From d6e78b04d00c9144b70b2477d21076b516d5fca7 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 5 Aug 2022 14:16:36 +0200 Subject: [PATCH 47/77] feat: Handle operators like their trait functions in the IDE --- crates/hir-expand/src/name.rs | 2 + crates/hir-ty/src/infer/expr.rs | 63 ++----------- crates/hir-ty/src/method_resolution.rs | 51 ++++++++++- crates/hir/src/semantics.rs | 40 ++++++++ crates/hir/src/source_analyzer.rs | 116 ++++++++++++++++++++++- crates/ide-db/src/defs.rs | 80 ++++++++++++++++ crates/ide/src/goto_definition.rs | 122 ++++++++++++++++++++++++- crates/ide/src/highlight_related.rs | 3 +- crates/ide/src/hover.rs | 12 ++- crates/ide/src/hover/tests.rs | 34 +++++++ crates/ide/src/moniker.rs | 2 +- crates/ide/src/static_index.rs | 2 +- 12 files changed, 459 insertions(+), 68 deletions(-) diff --git a/crates/hir-expand/src/name.rs b/crates/hir-expand/src/name.rs index 85b0a7735fe..47d191822d8 100644 --- a/crates/hir-expand/src/name.rs +++ b/crates/hir-expand/src/name.rs @@ -381,6 +381,7 @@ pub mod known { bitor, bitxor_assign, bitxor, + branch, deref_mut, deref, div_assign, @@ -396,6 +397,7 @@ pub mod known { not, owned_box, partial_ord, + poll, r#fn, rem_assign, rem, diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index d164e64a8be..2a13106390d 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -10,13 +10,13 @@ use chalk_ir::{ cast::Cast, fold::Shift, DebruijnIndex, GenericArgData, Mutability, TyVariableKind, }; use hir_def::{ - expr::{ArithOp, Array, BinaryOp, CmpOp, Expr, ExprId, Literal, Ordering, Statement, UnaryOp}, + expr::{ArithOp, Array, BinaryOp, CmpOp, Expr, ExprId, Literal, Statement, UnaryOp}, generics::TypeOrConstParamData, path::{GenericArg, GenericArgs}, resolver::resolver_for_expr, - ConstParamId, FieldId, FunctionId, ItemContainerId, Lookup, + ConstParamId, FieldId, ItemContainerId, Lookup, }; -use hir_expand::name::{name, Name}; +use hir_expand::name::Name; use stdx::always; use syntax::ast::RangeOp; @@ -28,7 +28,7 @@ use crate::{ const_or_path_to_chalk, generic_arg_to_chalk, lower_to_chalk_mutability, ParamLoweringMode, }, mapping::{from_chalk, ToChalk}, - method_resolution::{self, VisibleFromModule}, + method_resolution::{self, lang_names_for_bin_op, VisibleFromModule}, primitive::{self, UintTy}, static_lifetime, to_chalk_trait_id, utils::{generics, Generics}, @@ -947,7 +947,9 @@ impl<'a> InferenceContext<'a> { let lhs_ty = self.infer_expr(lhs, &lhs_expectation); let rhs_ty = self.table.new_type_var(); - let func = self.resolve_binop_method(op); + let func = lang_names_for_bin_op(op).and_then(|(name, lang_item)| { + self.db.trait_data(self.resolve_lang_item(lang_item)?.as_trait()?).method_by_name(&name) + }); let func = match func { Some(func) => func, None => { @@ -1473,55 +1475,4 @@ impl<'a> InferenceContext<'a> { }, }) } - - fn resolve_binop_method(&self, op: BinaryOp) -> Option { - let (name, lang_item) = match op { - BinaryOp::LogicOp(_) => return None, - BinaryOp::ArithOp(aop) => match aop { - ArithOp::Add => (name!(add), name!(add)), - ArithOp::Mul => (name!(mul), name!(mul)), - ArithOp::Sub => (name!(sub), name!(sub)), - ArithOp::Div => (name!(div), name!(div)), - ArithOp::Rem => (name!(rem), name!(rem)), - ArithOp::Shl => (name!(shl), name!(shl)), - ArithOp::Shr => (name!(shr), name!(shr)), - ArithOp::BitXor => (name!(bitxor), name!(bitxor)), - ArithOp::BitOr => (name!(bitor), name!(bitor)), - ArithOp::BitAnd => (name!(bitand), name!(bitand)), - }, - BinaryOp::Assignment { op: Some(aop) } => match aop { - ArithOp::Add => (name!(add_assign), name!(add_assign)), - ArithOp::Mul => (name!(mul_assign), name!(mul_assign)), - ArithOp::Sub => (name!(sub_assign), name!(sub_assign)), - ArithOp::Div => (name!(div_assign), name!(div_assign)), - ArithOp::Rem => (name!(rem_assign), name!(rem_assign)), - ArithOp::Shl => (name!(shl_assign), name!(shl_assign)), - ArithOp::Shr => (name!(shr_assign), name!(shr_assign)), - ArithOp::BitXor => (name!(bitxor_assign), name!(bitxor_assign)), - ArithOp::BitOr => (name!(bitor_assign), name!(bitor_assign)), - ArithOp::BitAnd => (name!(bitand_assign), name!(bitand_assign)), - }, - BinaryOp::CmpOp(cop) => match cop { - CmpOp::Eq { negated: false } => (name!(eq), name!(eq)), - CmpOp::Eq { negated: true } => (name!(ne), name!(eq)), - CmpOp::Ord { ordering: Ordering::Less, strict: false } => { - (name!(le), name!(partial_ord)) - } - CmpOp::Ord { ordering: Ordering::Less, strict: true } => { - (name!(lt), name!(partial_ord)) - } - CmpOp::Ord { ordering: Ordering::Greater, strict: false } => { - (name!(ge), name!(partial_ord)) - } - CmpOp::Ord { ordering: Ordering::Greater, strict: true } => { - (name!(gt), name!(partial_ord)) - } - }, - BinaryOp::Assignment { op: None } => return None, - }; - - let trait_ = self.resolve_lang_item(lang_item)?.as_trait()?; - - self.db.trait_data(trait_).method_by_name(&name) - } } diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index 15df7b3dd2b..64622545f84 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -336,7 +336,7 @@ impl InherentImpls { } } -pub fn inherent_impl_crates_query( +pub(crate) fn inherent_impl_crates_query( db: &dyn HirDatabase, krate: CrateId, fp: TyFingerprint, @@ -419,6 +419,55 @@ pub fn def_crates( } } +pub fn lang_names_for_bin_op(op: syntax::ast::BinaryOp) -> Option<(Name, Name)> { + use hir_expand::name; + use syntax::ast::{ArithOp, BinaryOp, CmpOp, Ordering}; + Some(match op { + BinaryOp::LogicOp(_) => return None, + BinaryOp::ArithOp(aop) => match aop { + ArithOp::Add => (name!(add), name!(add)), + ArithOp::Mul => (name!(mul), name!(mul)), + ArithOp::Sub => (name!(sub), name!(sub)), + ArithOp::Div => (name!(div), name!(div)), + ArithOp::Rem => (name!(rem), name!(rem)), + ArithOp::Shl => (name!(shl), name!(shl)), + ArithOp::Shr => (name!(shr), name!(shr)), + ArithOp::BitXor => (name!(bitxor), name!(bitxor)), + ArithOp::BitOr => (name!(bitor), name!(bitor)), + ArithOp::BitAnd => (name!(bitand), name!(bitand)), + }, + BinaryOp::Assignment { op: Some(aop) } => match aop { + ArithOp::Add => (name!(add_assign), name!(add_assign)), + ArithOp::Mul => (name!(mul_assign), name!(mul_assign)), + ArithOp::Sub => (name!(sub_assign), name!(sub_assign)), + ArithOp::Div => (name!(div_assign), name!(div_assign)), + ArithOp::Rem => (name!(rem_assign), name!(rem_assign)), + ArithOp::Shl => (name!(shl_assign), name!(shl_assign)), + ArithOp::Shr => (name!(shr_assign), name!(shr_assign)), + ArithOp::BitXor => (name!(bitxor_assign), name!(bitxor_assign)), + ArithOp::BitOr => (name!(bitor_assign), name!(bitor_assign)), + ArithOp::BitAnd => (name!(bitand_assign), name!(bitand_assign)), + }, + BinaryOp::CmpOp(cop) => match cop { + CmpOp::Eq { negated: false } => (name!(eq), name!(eq)), + CmpOp::Eq { negated: true } => (name!(ne), name!(eq)), + CmpOp::Ord { ordering: Ordering::Less, strict: false } => { + (name!(le), name!(partial_ord)) + } + CmpOp::Ord { ordering: Ordering::Less, strict: true } => { + (name!(lt), name!(partial_ord)) + } + CmpOp::Ord { ordering: Ordering::Greater, strict: false } => { + (name!(ge), name!(partial_ord)) + } + CmpOp::Ord { ordering: Ordering::Greater, strict: true } => { + (name!(gt), name!(partial_ord)) + } + }, + BinaryOp::Assignment { op: None } => return None, + }) +} + /// Look up the method with the given name. pub(crate) fn lookup_method( ty: &Canonical, diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index c84318b2fb8..36756866f99 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -357,6 +357,26 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { self.imp.resolve_method_call(call).map(Function::from) } + pub fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option { + self.imp.resolve_await_to_poll(await_expr).map(Function::from) + } + + pub fn resolve_prefix_expr(&self, prefix_expr: &ast::PrefixExpr) -> Option { + self.imp.resolve_prefix_expr(prefix_expr).map(Function::from) + } + + pub fn resolve_index_expr(&self, index_expr: &ast::IndexExpr) -> Option { + self.imp.resolve_index_expr(index_expr).map(Function::from) + } + + pub fn resolve_bin_expr(&self, bin_expr: &ast::BinExpr) -> Option { + self.imp.resolve_bin_expr(bin_expr).map(Function::from) + } + + pub fn resolve_try_expr(&self, try_expr: &ast::TryExpr) -> Option { + self.imp.resolve_try_expr(try_expr).map(Function::from) + } + pub fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option { self.imp.resolve_method_call_as_callable(call) } @@ -1066,6 +1086,26 @@ impl<'db> SemanticsImpl<'db> { self.analyze(call.syntax())?.resolve_method_call(self.db, call) } + pub fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option { + self.analyze(await_expr.syntax())?.resolve_await_to_poll(self.db, await_expr) + } + + pub fn resolve_prefix_expr(&self, prefix_expr: &ast::PrefixExpr) -> Option { + self.analyze(prefix_expr.syntax())?.resolve_prefix_expr(self.db, prefix_expr) + } + + pub fn resolve_index_expr(&self, index_expr: &ast::IndexExpr) -> Option { + self.analyze(index_expr.syntax())?.resolve_index_expr(self.db, index_expr) + } + + pub fn resolve_bin_expr(&self, bin_expr: &ast::BinExpr) -> Option { + self.analyze(bin_expr.syntax())?.resolve_bin_expr(self.db, bin_expr) + } + + pub fn resolve_try_expr(&self, try_expr: &ast::TryExpr) -> Option { + self.analyze(try_expr.syntax())?.resolve_try_expr(self.db, try_expr) + } + fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option { self.analyze(call.syntax())?.resolve_method_call_as_callable(self.db, call) } diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 1eb51b20c35..45879ff9c6a 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -25,15 +25,17 @@ use hir_def::{ Lookup, ModuleDefId, VariantId, }; use hir_expand::{ - builtin_fn_macro::BuiltinFnLikeExpander, hygiene::Hygiene, name::AsName, HirFileId, InFile, + builtin_fn_macro::BuiltinFnLikeExpander, hygiene::Hygiene, name, name::AsName, HirFileId, + InFile, }; use hir_ty::{ diagnostics::{ record_literal_missing_fields, record_pattern_missing_fields, unsafe_expressions, UnsafeExpr, }, - method_resolution, Adjust, Adjustment, AutoBorrow, InferenceResult, Interner, Substitution, - TyExt, TyKind, TyLoweringContext, + method_resolution::{self, lang_names_for_bin_op}, + Adjust, Adjustment, AutoBorrow, InferenceResult, Interner, Substitution, TyExt, TyKind, + TyLoweringContext, }; use itertools::Itertools; use smallvec::SmallVec; @@ -255,8 +257,103 @@ impl SourceAnalyzer { ) -> Option { let expr_id = self.expr_id(db, &call.clone().into())?; let (f_in_trait, substs) = self.infer.as_ref()?.method_resolution(expr_id)?; - let f_in_impl = self.resolve_impl_method(db, f_in_trait, &substs); - f_in_impl.or(Some(f_in_trait)) + + Some(self.resolve_impl_method_or_trait_def(db, f_in_trait, &substs)) + } + + pub fn resolve_await_to_poll( + &self, + db: &dyn HirDatabase, + await_expr: &ast::AwaitExpr, + ) -> Option { + let expr_id = self.expr_id(db, &await_expr.expr()?.into())?; + let ty = self.infer.as_ref()?.type_of_expr.get(expr_id)?; + + let op_fn = db + .lang_item(self.resolver.krate(), hir_expand::name![poll].to_smol_str())? + .as_function()?; + let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(ty.clone()).build(); + + Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs)) + } + + pub fn resolve_prefix_expr( + &self, + db: &dyn HirDatabase, + prefix_expr: &ast::PrefixExpr, + ) -> Option { + let lang_item_name = match prefix_expr.op_kind()? { + ast::UnaryOp::Deref => name![deref], + ast::UnaryOp::Not => name![not], + ast::UnaryOp::Neg => name![neg], + }; + let expr_id = self.expr_id(db, &prefix_expr.expr()?.into())?; + let ty = self.infer.as_ref()?.type_of_expr.get(expr_id)?; + + let trait_ = + db.lang_item(self.resolver.krate(), lang_item_name.to_smol_str())?.as_trait()?; + let op_fn = db.trait_data(trait_).method_by_name(&lang_item_name)?; + let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(ty.clone()).build(); + + Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs)) + } + + pub fn resolve_index_expr( + &self, + db: &dyn HirDatabase, + index_expr: &ast::IndexExpr, + ) -> Option { + let base_expr_id = self.expr_id(db, &index_expr.base()?.into())?; + let index_expr_id = self.expr_id(db, &index_expr.index()?.into())?; + let base_ty = self.infer.as_ref()?.type_of_expr.get(base_expr_id)?; + let index_ty = self.infer.as_ref()?.type_of_expr.get(index_expr_id)?; + + let lang_item_name = name![index]; + + let trait_ = + db.lang_item(self.resolver.krate(), lang_item_name.to_smol_str())?.as_trait()?; + let op_fn = db.trait_data(trait_).method_by_name(&lang_item_name)?; + let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn) + .push(base_ty.clone()) + .push(index_ty.clone()) + .build(); + Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs)) + } + + pub fn resolve_bin_expr( + &self, + db: &dyn HirDatabase, + binop_expr: &ast::BinExpr, + ) -> Option { + let op = binop_expr.op_kind()?; + let lhs_expr_id = self.expr_id(db, &binop_expr.lhs()?.into())?; + let rhs_expr_id = self.expr_id(db, &binop_expr.rhs()?.into())?; + let lhs = self.infer.as_ref()?.type_of_expr.get(lhs_expr_id)?; + let rhs = self.infer.as_ref()?.type_of_expr.get(rhs_expr_id)?; + + let op_fn = lang_names_for_bin_op(op).and_then(|(name, lang_item)| { + db.trait_data(db.lang_item(self.resolver.krate(), lang_item.to_smol_str())?.as_trait()?) + .method_by_name(&name) + })?; + let substs = + hir_ty::TyBuilder::subst_for_def(db, op_fn).push(lhs.clone()).push(rhs.clone()).build(); + + Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs)) + } + + pub fn resolve_try_expr( + &self, + db: &dyn HirDatabase, + try_expr: &ast::TryExpr, + ) -> Option { + let expr_id = self.expr_id(db, &try_expr.expr()?.into())?; + let ty = self.infer.as_ref()?.type_of_expr.get(expr_id)?; + + let op_fn = + db.lang_item(self.resolver.krate(), name![branch].to_smol_str())?.as_function()?; + let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(ty.clone()).build(); + + Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs)) } pub(crate) fn resolve_field( @@ -666,6 +763,15 @@ impl SourceAnalyzer { let fun_data = db.function_data(func); method_resolution::lookup_impl_method(self_ty, db, trait_env, impled_trait, &fun_data.name) } + + fn resolve_impl_method_or_trait_def( + &self, + db: &dyn HirDatabase, + func: FunctionId, + substs: &Substitution, + ) -> FunctionId { + self.resolve_impl_method(db, func, substs).unwrap_or(func) + } } fn scope_for( diff --git a/crates/ide-db/src/defs.rs b/crates/ide-db/src/defs.rs index aeaca00ec65..6c13c039723 100644 --- a/crates/ide-db/src/defs.rs +++ b/crates/ide-db/src/defs.rs @@ -127,10 +127,12 @@ impl Definition { } } +// FIXME: IdentClass as a name no longer fits #[derive(Debug)] pub enum IdentClass { NameClass(NameClass), NameRefClass(NameRefClass), + Operator(OperatorClass), } impl IdentClass { @@ -147,6 +149,11 @@ impl IdentClass { .map(IdentClass::NameClass) .or_else(|| NameRefClass::classify_lifetime(sema, &lifetime).map(IdentClass::NameRefClass)) }, + ast::AwaitExpr(await_expr) => OperatorClass::classify_await(sema, &await_expr).map(IdentClass::Operator), + ast::BinExpr(bin_expr) => OperatorClass::classify_bin(sema, &bin_expr).map(IdentClass::Operator), + ast::IndexExpr(index_expr) => OperatorClass::classify_index(sema, &index_expr).map(IdentClass::Operator), + ast::PrefixExpr(prefix_expr) => OperatorClass::classify_prefix(sema,&prefix_expr).map(IdentClass::Operator), + ast::TryExpr(try_expr) => OperatorClass::classify_try(sema,&try_expr).map(IdentClass::Operator), _ => None, } } @@ -184,6 +191,33 @@ impl IdentClass { res.push(Definition::Local(local_ref)); res.push(Definition::Field(field_ref)); } + IdentClass::Operator( + OperatorClass::Await(func) + | OperatorClass::Prefix(func) + | OperatorClass::Bin(func) + | OperatorClass::Index(func) + | OperatorClass::Try(func), + ) => res.push(Definition::Function(func)), + } + res + } + + pub fn definitions_no_ops(self) -> ArrayVec { + let mut res = ArrayVec::new(); + match self { + IdentClass::NameClass(NameClass::Definition(it) | NameClass::ConstReference(it)) => { + res.push(it) + } + IdentClass::NameClass(NameClass::PatFieldShorthand { local_def, field_ref }) => { + res.push(Definition::Local(local_def)); + res.push(Definition::Field(field_ref)); + } + IdentClass::NameRefClass(NameRefClass::Definition(it)) => res.push(it), + IdentClass::NameRefClass(NameRefClass::FieldShorthand { local_ref, field_ref }) => { + res.push(Definition::Local(local_ref)); + res.push(Definition::Field(field_ref)); + } + IdentClass::Operator(_) => (), } res } @@ -332,6 +366,52 @@ impl NameClass { } } +#[derive(Debug)] +pub enum OperatorClass { + Await(Function), + Prefix(Function), + Index(Function), + Try(Function), + Bin(Function), +} + +impl OperatorClass { + pub fn classify_await( + sema: &Semantics<'_, RootDatabase>, + await_expr: &ast::AwaitExpr, + ) -> Option { + sema.resolve_await_to_poll(await_expr).map(OperatorClass::Await) + } + + pub fn classify_prefix( + sema: &Semantics<'_, RootDatabase>, + prefix_expr: &ast::PrefixExpr, + ) -> Option { + sema.resolve_prefix_expr(prefix_expr).map(OperatorClass::Prefix) + } + + pub fn classify_try( + sema: &Semantics<'_, RootDatabase>, + try_expr: &ast::TryExpr, + ) -> Option { + sema.resolve_try_expr(try_expr).map(OperatorClass::Try) + } + + pub fn classify_index( + sema: &Semantics<'_, RootDatabase>, + index_expr: &ast::IndexExpr, + ) -> Option { + sema.resolve_index_expr(index_expr).map(OperatorClass::Index) + } + + pub fn classify_bin( + sema: &Semantics<'_, RootDatabase>, + bin_expr: &ast::BinExpr, + ) -> Option { + sema.resolve_bin_expr(bin_expr).map(OperatorClass::Bin) + } +} + /// This is similar to [`NameClass`], but works for [`ast::NameRef`] rather than /// for [`ast::Name`]. Similarly, what looks like a reference in syntax is a /// reference most of the time, but there are a couple of annoying exceptions. diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs index d9c97751c95..b2123b9a879 100644 --- a/crates/ide/src/goto_definition.rs +++ b/crates/ide/src/goto_definition.rs @@ -39,7 +39,11 @@ pub(crate) fn goto_definition( | T![super] | T![crate] | T![Self] - | COMMENT => 2, + | COMMENT => 4, + // index and prefix ops + T!['['] | T![']'] | T![?] | T![*] | T![-] | T![!] => 3, + kind if kind.is_keyword() => 2, + T!['('] | T![')'] => 2, kind if kind.is_trivia() => 0, _ => 1, })?; @@ -1628,6 +1632,122 @@ macro_rules! foo { } foo!(bar$0); +"#, + ); + } + + #[test] + fn goto_await_poll() { + check( + r#" +//- minicore: future + +struct MyFut; + +impl core::future::Future for MyFut { + type Output = (); + + fn poll( + //^^^^ + self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_> + ) -> std::task::Poll + { + () + } +} + +fn f() { + MyFut.await$0; +} +"#, + ); + } + + #[test] + fn goto_try_op() { + check( + r#" +//- minicore: try + +struct Struct; + +impl core::ops::Try for Struct { + fn branch( + //^^^^^^ + self + ) {} +} + +fn f() { + Struct?$0; +} +"#, + ); + } + + #[test] + fn goto_index_op() { + check( + r#" +//- minicore: index + +struct Struct; + +impl core::ops::Index for Struct { + fn index( + //^^^^^ + self + ) {} +} + +fn f() { + Struct[0]$0; +} +"#, + ); + } + + #[test] + fn goto_prefix_op() { + check( + r#" +//- minicore: deref + +struct Struct; + +impl core::ops::Deref for Struct { + fn deref( + //^^^^^ + self + ) {} +} + +fn f() { + $0*Struct; +} +"#, + ); + } + + #[test] + fn goto_bin_op() { + check( + r#" +//- minicore: add + +struct Struct; + +impl core::ops::Add for Struct { + fn add( + //^^^ + self + ) {} +} + +fn f() { + Struct +$0 Struct; +} "#, ); } diff --git a/crates/ide/src/highlight_related.rs b/crates/ide/src/highlight_related.rs index f2d7029eab1..f190da326e4 100644 --- a/crates/ide/src/highlight_related.rs +++ b/crates/ide/src/highlight_related.rs @@ -333,7 +333,8 @@ fn cover_range(r0: Option, r1: Option) -> Option, token: SyntaxToken) -> FxHashSet { sema.descend_into_macros(token) .into_iter() - .filter_map(|token| IdentClass::classify_token(sema, &token).map(IdentClass::definitions)) + .filter_map(|token| IdentClass::classify_token(sema, &token)) + .map(IdentClass::definitions_no_ops) .flatten() .collect() } diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 784f85dbbef..3ada181f1ed 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs @@ -9,7 +9,7 @@ use either::Either; use hir::{HasSource, Semantics}; use ide_db::{ base_db::FileRange, - defs::{Definition, IdentClass}, + defs::{Definition, IdentClass, OperatorClass}, famous_defs::FamousDefs, helpers::pick_best_token, FxIndexSet, RootDatabase, @@ -101,7 +101,10 @@ pub(crate) fn hover( let offset = range.start(); let original_token = pick_best_token(file.token_at_offset(offset), |kind| match kind { - IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] | T![Self] => 3, + IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] | T![Self] => 4, + // index and prefix ops + T!['['] | T![']'] | T![?] | T![*] | T![-] | T![!] => 3, + kind if kind.is_keyword() => 2, T!['('] | T![')'] => 2, kind if kind.is_trivia() => 0, _ => 1, @@ -136,6 +139,11 @@ pub(crate) fn hover( .filter_map(|token| { let node = token.parent()?; let class = IdentClass::classify_token(sema, token)?; + if let IdentClass::Operator(OperatorClass::Await(_)) = class { + // It's better for us to fall back to the keyword hover here, + // rendering poll is very confusing + return None; + } Some(class.definitions().into_iter().zip(iter::once(node).cycle())) }) .flatten() diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index 867d1f54d4f..c6274264b8f 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -5051,3 +5051,37 @@ fn f() { ```"#]], ); } + +#[test] +fn hover_deref() { + check( + r#" +//- minicore: deref + +struct Struct(usize); + +impl core::ops::Deref for Struct { + type Target = usize; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +fn f() { + $0*Struct(0); +} +"#, + expect![[r#" + *** + + ```rust + test::Struct + ``` + + ```rust + fn deref(&self) -> &Self::Target + ``` + "#]], + ); +} diff --git a/crates/ide/src/moniker.rs b/crates/ide/src/moniker.rs index 6bab9fa1ebb..4f758967b46 100644 --- a/crates/ide/src/moniker.rs +++ b/crates/ide/src/moniker.rs @@ -90,7 +90,7 @@ pub(crate) fn moniker( .descend_into_macros(original_token.clone()) .into_iter() .filter_map(|token| { - IdentClass::classify_token(sema, &token).map(IdentClass::definitions).map(|it| { + IdentClass::classify_token(sema, &token).map(IdentClass::definitions_no_ops).map(|it| { it.into_iter().flat_map(|def| def_to_moniker(sema.db, def, current_crate)) }) }) diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs index d74b640415c..cc79ee55b7d 100644 --- a/crates/ide/src/static_index.rs +++ b/crates/ide/src/static_index.rs @@ -204,7 +204,7 @@ impl StaticIndex<'_> { fn get_definition(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> Option { for token in sema.descend_into_macros(token) { - let def = IdentClass::classify_token(sema, &token).map(IdentClass::definitions); + let def = IdentClass::classify_token(sema, &token).map(IdentClass::definitions_no_ops); if let Some(&[x]) = def.as_deref() { return Some(x); } else { From 352d3c6e50f4c64cded06b51ef81d4ac83b4e34c Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 5 Aug 2022 14:28:36 +0200 Subject: [PATCH 48/77] Fix visibilities --- crates/hir/src/semantics.rs | 10 +++++----- crates/hir/src/source_analyzer.rs | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 36756866f99..416b6f58061 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -1086,23 +1086,23 @@ impl<'db> SemanticsImpl<'db> { self.analyze(call.syntax())?.resolve_method_call(self.db, call) } - pub fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option { + fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option { self.analyze(await_expr.syntax())?.resolve_await_to_poll(self.db, await_expr) } - pub fn resolve_prefix_expr(&self, prefix_expr: &ast::PrefixExpr) -> Option { + fn resolve_prefix_expr(&self, prefix_expr: &ast::PrefixExpr) -> Option { self.analyze(prefix_expr.syntax())?.resolve_prefix_expr(self.db, prefix_expr) } - pub fn resolve_index_expr(&self, index_expr: &ast::IndexExpr) -> Option { + fn resolve_index_expr(&self, index_expr: &ast::IndexExpr) -> Option { self.analyze(index_expr.syntax())?.resolve_index_expr(self.db, index_expr) } - pub fn resolve_bin_expr(&self, bin_expr: &ast::BinExpr) -> Option { + fn resolve_bin_expr(&self, bin_expr: &ast::BinExpr) -> Option { self.analyze(bin_expr.syntax())?.resolve_bin_expr(self.db, bin_expr) } - pub fn resolve_try_expr(&self, try_expr: &ast::TryExpr) -> Option { + fn resolve_try_expr(&self, try_expr: &ast::TryExpr) -> Option { self.analyze(try_expr.syntax())?.resolve_try_expr(self.db, try_expr) } diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 45879ff9c6a..5e0bf7c5fb9 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -261,7 +261,7 @@ impl SourceAnalyzer { Some(self.resolve_impl_method_or_trait_def(db, f_in_trait, &substs)) } - pub fn resolve_await_to_poll( + pub(crate) fn resolve_await_to_poll( &self, db: &dyn HirDatabase, await_expr: &ast::AwaitExpr, @@ -277,7 +277,7 @@ impl SourceAnalyzer { Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs)) } - pub fn resolve_prefix_expr( + pub(crate) fn resolve_prefix_expr( &self, db: &dyn HirDatabase, prefix_expr: &ast::PrefixExpr, @@ -298,7 +298,7 @@ impl SourceAnalyzer { Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs)) } - pub fn resolve_index_expr( + pub(crate) fn resolve_index_expr( &self, db: &dyn HirDatabase, index_expr: &ast::IndexExpr, @@ -320,7 +320,7 @@ impl SourceAnalyzer { Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs)) } - pub fn resolve_bin_expr( + pub(crate) fn resolve_bin_expr( &self, db: &dyn HirDatabase, binop_expr: &ast::BinExpr, @@ -341,7 +341,7 @@ impl SourceAnalyzer { Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs)) } - pub fn resolve_try_expr( + pub(crate) fn resolve_try_expr( &self, db: &dyn HirDatabase, try_expr: &ast::TryExpr, From 8aa50e08af4bd2ecc6b2132d2db48edabe51f352 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 5 Aug 2022 14:54:14 +0200 Subject: [PATCH 49/77] Simplify --- crates/hir/src/source_analyzer.rs | 58 +++++++++++++++++-------------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 5e0bf7c5fb9..f5e2e443070 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -25,8 +25,11 @@ use hir_def::{ Lookup, ModuleDefId, VariantId, }; use hir_expand::{ - builtin_fn_macro::BuiltinFnLikeExpander, hygiene::Hygiene, name, name::AsName, HirFileId, - InFile, + builtin_fn_macro::BuiltinFnLikeExpander, + hygiene::Hygiene, + name, + name::{AsName, Name}, + HirFileId, InFile, }; use hir_ty::{ diagnostics::{ @@ -34,7 +37,7 @@ use hir_ty::{ UnsafeExpr, }, method_resolution::{self, lang_names_for_bin_op}, - Adjust, Adjustment, AutoBorrow, InferenceResult, Interner, Substitution, TyExt, TyKind, + Adjust, Adjustment, AutoBorrow, InferenceResult, Interner, Substitution, Ty, TyExt, TyKind, TyLoweringContext, }; use itertools::Itertools; @@ -266,8 +269,7 @@ impl SourceAnalyzer { db: &dyn HirDatabase, await_expr: &ast::AwaitExpr, ) -> Option { - let expr_id = self.expr_id(db, &await_expr.expr()?.into())?; - let ty = self.infer.as_ref()?.type_of_expr.get(expr_id)?; + let ty = self.ty_of_expr(db, &await_expr.expr()?.into())?; let op_fn = db .lang_item(self.resolver.krate(), hir_expand::name![poll].to_smol_str())? @@ -287,12 +289,9 @@ impl SourceAnalyzer { ast::UnaryOp::Not => name![not], ast::UnaryOp::Neg => name![neg], }; - let expr_id = self.expr_id(db, &prefix_expr.expr()?.into())?; - let ty = self.infer.as_ref()?.type_of_expr.get(expr_id)?; + let ty = self.ty_of_expr(db, &prefix_expr.expr()?.into())?; - let trait_ = - db.lang_item(self.resolver.krate(), lang_item_name.to_smol_str())?.as_trait()?; - let op_fn = db.trait_data(trait_).method_by_name(&lang_item_name)?; + let op_fn = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?; let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(ty.clone()).build(); Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs)) @@ -303,16 +302,12 @@ impl SourceAnalyzer { db: &dyn HirDatabase, index_expr: &ast::IndexExpr, ) -> Option { - let base_expr_id = self.expr_id(db, &index_expr.base()?.into())?; - let index_expr_id = self.expr_id(db, &index_expr.index()?.into())?; - let base_ty = self.infer.as_ref()?.type_of_expr.get(base_expr_id)?; - let index_ty = self.infer.as_ref()?.type_of_expr.get(index_expr_id)?; + let base_ty = self.ty_of_expr(db, &index_expr.base()?.into())?; + let index_ty = self.ty_of_expr(db, &index_expr.index()?.into())?; let lang_item_name = name![index]; - let trait_ = - db.lang_item(self.resolver.krate(), lang_item_name.to_smol_str())?.as_trait()?; - let op_fn = db.trait_data(trait_).method_by_name(&lang_item_name)?; + let op_fn = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?; let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn) .push(base_ty.clone()) .push(index_ty.clone()) @@ -326,15 +321,11 @@ impl SourceAnalyzer { binop_expr: &ast::BinExpr, ) -> Option { let op = binop_expr.op_kind()?; - let lhs_expr_id = self.expr_id(db, &binop_expr.lhs()?.into())?; - let rhs_expr_id = self.expr_id(db, &binop_expr.rhs()?.into())?; - let lhs = self.infer.as_ref()?.type_of_expr.get(lhs_expr_id)?; - let rhs = self.infer.as_ref()?.type_of_expr.get(rhs_expr_id)?; + let lhs = self.ty_of_expr(db, &binop_expr.lhs()?.into())?; + let rhs = self.ty_of_expr(db, &binop_expr.rhs()?.into())?; - let op_fn = lang_names_for_bin_op(op).and_then(|(name, lang_item)| { - db.trait_data(db.lang_item(self.resolver.krate(), lang_item.to_smol_str())?.as_trait()?) - .method_by_name(&name) - })?; + let op_fn = lang_names_for_bin_op(op) + .and_then(|(name, lang_item)| self.lang_trait_fn(db, &lang_item, &name))?; let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(lhs.clone()).push(rhs.clone()).build(); @@ -346,8 +337,7 @@ impl SourceAnalyzer { db: &dyn HirDatabase, try_expr: &ast::TryExpr, ) -> Option { - let expr_id = self.expr_id(db, &try_expr.expr()?.into())?; - let ty = self.infer.as_ref()?.type_of_expr.get(expr_id)?; + let ty = self.ty_of_expr(db, &try_expr.expr()?.into())?; let op_fn = db.lang_item(self.resolver.krate(), name![branch].to_smol_str())?.as_function()?; @@ -772,6 +762,20 @@ impl SourceAnalyzer { ) -> FunctionId { self.resolve_impl_method(db, func, substs).unwrap_or(func) } + + fn lang_trait_fn( + &self, + db: &dyn HirDatabase, + lang_trait: &Name, + method_name: &Name, + ) -> Option { + db.trait_data(db.lang_item(self.resolver.krate(), lang_trait.to_smol_str())?.as_trait()?) + .method_by_name(method_name) + } + + fn ty_of_expr(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<&Ty> { + self.infer.as_ref()?.type_of_expr.get(self.expr_id(db, &expr)?) + } } fn scope_for( From 6bf674c8e4ddcccb4fc7eaa8754bdc431c6cad33 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 5 Aug 2022 14:59:26 +0200 Subject: [PATCH 50/77] fix: Fix incorrect token pick rankings --- crates/ide/src/call_hierarchy.rs | 4 ++-- crates/ide/src/goto_implementation.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/ide/src/call_hierarchy.rs b/crates/ide/src/call_hierarchy.rs index a18a6bea979..5a8cda8fb3d 100644 --- a/crates/ide/src/call_hierarchy.rs +++ b/crates/ide/src/call_hierarchy.rs @@ -7,7 +7,7 @@ use ide_db::{ search::FileReference, FxIndexMap, RootDatabase, }; -use syntax::{ast, AstNode, SyntaxKind::NAME, TextRange}; +use syntax::{ast, AstNode, SyntaxKind::IDENT, TextRange}; use crate::{goto_definition, FilePosition, NavigationTarget, RangeInfo, TryToNav}; @@ -79,7 +79,7 @@ pub(crate) fn outgoing_calls(db: &RootDatabase, position: FilePosition) -> Optio let file = sema.parse(file_id); let file = file.syntax(); let token = pick_best_token(file.token_at_offset(position.offset), |kind| match kind { - NAME => 1, + IDENT => 1, _ => 0, })?; let mut calls = CallLocations::default(); diff --git a/crates/ide/src/goto_implementation.rs b/crates/ide/src/goto_implementation.rs index 04b51c83940..b3f711b6b88 100644 --- a/crates/ide/src/goto_implementation.rs +++ b/crates/ide/src/goto_implementation.rs @@ -30,7 +30,7 @@ pub(crate) fn goto_implementation( let original_token = pick_best_token(syntax.token_at_offset(position.offset), |kind| match kind { - IDENT | T![self] => 1, + IDENT | T![self] | INT_NUMBER => 1, _ => 0, })?; let range = original_token.text_range(); From 95bf0fb917577c61e4a9d41d837e6fa132515b3d Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Fri, 5 Aug 2022 18:13:22 +0400 Subject: [PATCH 51/77] Move stability lookup after cross-crate check --- compiler/rustc_middle/src/middle/stability.rs | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 0d1223ed289..7a9ad44d1d9 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -421,6 +421,12 @@ impl<'tcx> TyCtxt<'tcx> { return EvalResult::Allow; } + // Only the cross-crate scenario matters when checking unstable APIs + let cross_crate = !def_id.is_local(); + if !cross_crate { + return EvalResult::Allow; + } + let stability = self.lookup_stability(def_id); debug!( "stability: \ @@ -428,12 +434,6 @@ impl<'tcx> TyCtxt<'tcx> { def_id, span, stability ); - // Only the cross-crate scenario matters when checking unstable APIs - let cross_crate = !def_id.is_local(); - if !cross_crate { - return EvalResult::Allow; - } - // Issue #38412: private items lack stability markers. if skip_stability_check_due_to_privacy(self, def_id) { return EvalResult::Allow; @@ -508,17 +508,17 @@ impl<'tcx> TyCtxt<'tcx> { return EvalResult::Allow; } - let stability = self.lookup_default_body_stability(def_id); - debug!( - "body stability: inspecting def_id={def_id:?} span={span:?} of stability={stability:?}" - ); - // Only the cross-crate scenario matters when checking unstable APIs let cross_crate = !def_id.is_local(); if !cross_crate { return EvalResult::Allow; } + let stability = self.lookup_default_body_stability(def_id); + debug!( + "body stability: inspecting def_id={def_id:?} span={span:?} of stability={stability:?}" + ); + // Issue #38412: private items lack stability markers. if skip_stability_check_due_to_privacy(self, def_id) { return EvalResult::Allow; From d5e9e94741fd16320f5491397645fb137195eb06 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Aug 2022 16:39:06 -0400 Subject: [PATCH 52/77] add method to get the mutability of an AllocId --- compiler/rustc_const_eval/src/interpret/memory.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index ed2c4edf9dd..75528d6140c 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -520,6 +520,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Gives raw access to the `Allocation`, without bounds or alignment checks. /// The caller is responsible for calling the access hooks! + /// + /// You almost certainly want to use `get_ptr_alloc`/`get_ptr_alloc_mut` instead. fn get_alloc_raw( &self, id: AllocId, @@ -589,6 +591,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(&self.get_alloc_raw(id)?.extra) } + /// Return the `mutability` field of the given allocation. + pub fn get_alloc_mutability<'a>(&'a self, id: AllocId) -> InterpResult<'tcx, Mutability> { + Ok(self.get_alloc_raw(id)?.mutability) + } + /// Gives raw mutable access to the `Allocation`, without bounds or alignment checks. /// The caller is responsible for calling the access hooks! /// From 54b122e9132937bb0aa3514b3d5852b68e7ddf04 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Aug 2022 17:59:47 -0400 Subject: [PATCH 53/77] propagate --bless to Miri --- src/bootstrap/test.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 05403cf48c7..782cbd8f5ff 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -628,6 +628,10 @@ impl Step for Miri { cargo.env("MIRI_HOST_SYSROOT", sysroot); cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler)); cargo.env("MIRI", miri); + // propagate --bless + if builder.config.cmd.bless() { + cargo.env("MIRI_BLESS", "Gesundheit"); + } cargo.arg("--").args(builder.config.cmd.test_args()); From e8a9bc09a3f0ddf4d5f5706a6b101eceb0d90960 Mon Sep 17 00:00:00 2001 From: Adrian Stanciu Date: Sat, 6 Aug 2022 17:12:13 +0300 Subject: [PATCH 54/77] run stable fmt through rustup --- crates/rust-analyzer/tests/slow-tests/tidy.rs | 7 +++---- crates/sourcegen/src/lib.rs | 14 ++++++++------ 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/crates/rust-analyzer/tests/slow-tests/tidy.rs b/crates/rust-analyzer/tests/slow-tests/tidy.rs index 18f95925d9a..58099a58de0 100644 --- a/crates/rust-analyzer/tests/slow-tests/tidy.rs +++ b/crates/rust-analyzer/tests/slow-tests/tidy.rs @@ -13,9 +13,8 @@ use xshell::cmd; fn check_code_formatting() { let sh = &Shell::new().unwrap(); sh.change_dir(sourcegen::project_root()); - sh.set_var("RUSTUP_TOOLCHAIN", "stable"); - let out = cmd!(sh, "rustfmt --version").read().unwrap(); + let out = cmd!(sh, "rustup run stable rustfmt --version").read().unwrap(); if !out.contains("stable") { panic!( "Failed to run rustfmt from toolchain 'stable'. \ @@ -23,9 +22,9 @@ fn check_code_formatting() { ) } - let res = cmd!(sh, "cargo fmt -- --check").run(); + let res = cmd!(sh, "rustup run stable cargo fmt -- --check").run(); if res.is_err() { - let _ = cmd!(sh, "cargo fmt").run(); + let _ = cmd!(sh, "rustup run stable cargo fmt").run(); } res.unwrap() } diff --git a/crates/sourcegen/src/lib.rs b/crates/sourcegen/src/lib.rs index ce0224ec744..4e0ee63f32f 100644 --- a/crates/sourcegen/src/lib.rs +++ b/crates/sourcegen/src/lib.rs @@ -136,7 +136,7 @@ impl fmt::Display for Location { } fn ensure_rustfmt(sh: &Shell) { - let version = cmd!(sh, "rustfmt --version").read().unwrap_or_default(); + let version = cmd!(sh, "rustup run stable rustfmt --version").read().unwrap_or_default(); if !version.contains("stable") { panic!( "Failed to run rustfmt from toolchain 'stable'. \ @@ -147,13 +147,15 @@ fn ensure_rustfmt(sh: &Shell) { pub fn reformat(text: String) -> String { let sh = Shell::new().unwrap(); - sh.set_var("RUSTUP_TOOLCHAIN", "stable"); ensure_rustfmt(&sh); let rustfmt_toml = project_root().join("rustfmt.toml"); - let mut stdout = cmd!(sh, "rustfmt --config-path {rustfmt_toml} --config fn_single_line=true") - .stdin(text) - .read() - .unwrap(); + let mut stdout = cmd!( + sh, + "rustup run stable rustfmt --config-path {rustfmt_toml} --config fn_single_line=true" + ) + .stdin(text) + .read() + .unwrap(); if !stdout.ends_with('\n') { stdout.push('\n'); } From a6cfabc88a79fe039a9c3d0c541f6517fb9767e2 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 6 Aug 2022 19:42:52 +0200 Subject: [PATCH 55/77] Avoid ICE in rustdoc. --- src/librustdoc/clean/auto_trait.rs | 12 +++++++----- src/test/rustdoc/fn-bound.rs | 17 +++++++++++++++++ 2 files changed, 24 insertions(+), 5 deletions(-) create mode 100644 src/test/rustdoc/fn-bound.rs diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 71f070f2678..6697952293e 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -354,9 +354,7 @@ where ty_to_bounds .into_iter() .flat_map(|(ty, mut bounds)| { - if let Some(data) = ty_to_fn.get(&ty) { - let (poly_trait, output) = - (data.0.as_ref().unwrap().clone(), data.1.as_ref().cloned().map(Box::new)); + if let Some((Some(ref poly_trait), ref output)) = ty_to_fn.get(&ty) { let mut new_path = poly_trait.trait_.clone(); let last_segment = new_path.segments.pop().expect("segments were empty"); @@ -374,8 +372,9 @@ where GenericArgs::Parenthesized { inputs, output } => (inputs, output), }; + let output = output.as_ref().cloned().map(Box::new); if old_output.is_some() && old_output != output { - panic!("Output mismatch for {:?} {:?} {:?}", ty, old_output, data.1); + panic!("Output mismatch for {:?} {:?} {:?}", ty, old_output, output); } let new_params = GenericArgs::Parenthesized { inputs: old_input, output }; @@ -385,7 +384,10 @@ where .push(PathSegment { name: last_segment.name, args: new_params }); bounds.insert(GenericBound::TraitBound( - PolyTrait { trait_: new_path, generic_params: poly_trait.generic_params }, + PolyTrait { + trait_: new_path, + generic_params: poly_trait.generic_params.clone(), + }, hir::TraitBoundModifier::None, )); } diff --git a/src/test/rustdoc/fn-bound.rs b/src/test/rustdoc/fn-bound.rs new file mode 100644 index 00000000000..7b44ee7b4b5 --- /dev/null +++ b/src/test/rustdoc/fn-bound.rs @@ -0,0 +1,17 @@ +use std::iter::Peekable; + +pub struct Span { + inner: Peekable>, +} + +struct ConditionalIterator { + f: F, +} + +impl Iterator for ConditionalIterator { + type Item = (); + + fn next(&mut self) -> Option { + todo!() + } +} From 22899555463a9e813801af60eec8f11839672c54 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sat, 6 Aug 2022 13:17:40 -0700 Subject: [PATCH 56/77] rustdoc: do not mark the contents of a skipped module as inlined --- src/librustdoc/clean/inline.rs | 37 ++++++++++++++++--- src/librustdoc/clean/mod.rs | 27 ++++++-------- .../rustdoc/auxiliary/issue-100204-aux.rs | 13 +++++++ ...-100204-inline-impl-through-glob-import.rs | 14 +++++++ 4 files changed, 70 insertions(+), 21 deletions(-) create mode 100644 src/test/rustdoc/auxiliary/issue-100204-aux.rs create mode 100644 src/test/rustdoc/issue-100204-inline-impl-through-glob-import.rs diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index f644ecb88b9..58d0aedb023 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -145,6 +145,7 @@ pub(crate) fn try_inline_glob( cx: &mut DocContext<'_>, res: Res, visited: &mut FxHashSet, + inlined_names: &mut FxHashSet<(ItemType, Symbol)>, ) -> Option> { let did = res.opt_def_id()?; if did.is_local() { @@ -153,8 +154,17 @@ pub(crate) fn try_inline_glob( match res { Res::Def(DefKind::Mod, did) => { - let m = build_module(cx, did, visited); - Some(m.items) + let mut items = build_module_items(cx, did, visited, inlined_names); + items.drain_filter(|item| { + if let Some(name) = item.name { + // If an item with the same type and name already exists, + // it takes priority over the inlined stuff. + !inlined_names.insert((item.type_(), name)) + } else { + false + } + }); + Some(items) } // glob imports on things like enums aren't inlined even for local exports, so just bail _ => None, @@ -517,6 +527,18 @@ fn build_module( did: DefId, visited: &mut FxHashSet, ) -> clean::Module { + let items = build_module_items(cx, did, visited, &mut FxHashSet::default()); + + let span = clean::Span::new(cx.tcx.def_span(did)); + clean::Module { items, span } +} + +fn build_module_items( + cx: &mut DocContext<'_>, + did: DefId, + visited: &mut FxHashSet, + inlined_names: &mut FxHashSet<(ItemType, Symbol)>, +) -> Vec { let mut items = Vec::new(); // If we're re-exporting a re-export it may actually re-export something in @@ -526,7 +548,13 @@ fn build_module( if item.vis.is_public() { let res = item.res.expect_non_local(); if let Some(def_id) = res.mod_def_id() { - if did == def_id || !visited.insert(def_id) { + // If we're inlining a glob import, it's possible to have + // two distinct modules with the same name. We don't want to + // inline it, or mark any of its contents as visited. + if did == def_id + || inlined_names.contains(&(ItemType::Module, item.ident.name)) + || !visited.insert(def_id) + { continue; } } @@ -563,8 +591,7 @@ fn build_module( } } - let span = clean::Span::new(cx.tcx.def_span(did)); - clean::Module { items, span } + items } pub(crate) fn print_inlined_const(tcx: TyCtxt<'_>, did: DefId) -> String { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 5fb9747a944..e18b0c2a77f 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -71,7 +71,7 @@ impl<'tcx> Clean<'tcx, Item> for DocModule<'tcx> { // priority to the not-imported one, so we should, too. items.extend(self.items.iter().flat_map(|(item, renamed)| { // First, lower everything other than imports. - if matches!(item.kind, hir::ItemKind::Use(..)) { + if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) { return Vec::new(); } let v = clean_maybe_renamed_item(cx, item, *renamed); @@ -84,20 +84,13 @@ impl<'tcx> Clean<'tcx, Item> for DocModule<'tcx> { })); items.extend(self.items.iter().flat_map(|(item, renamed)| { // Now we actually lower the imports, skipping everything else. - if !matches!(item.kind, hir::ItemKind::Use(..)) { - return Vec::new(); + if let hir::ItemKind::Use(path, hir::UseKind::Glob) = item.kind { + let name = renamed.unwrap_or_else(|| cx.tcx.hir().name(item.hir_id())); + clean_use_statement(item, name, path, hir::UseKind::Glob, cx, &mut inserted) + } else { + // skip everything else + Vec::new() } - let mut v = clean_maybe_renamed_item(cx, item, *renamed); - v.drain_filter(|item| { - if let Some(name) = item.name { - // If an item with the same type and name already exists, - // it takes priority over the inlined stuff. - !inserted.insert((item.type_(), name)) - } else { - false - } - }); - v })); // determine if we should display the inner contents or @@ -1962,7 +1955,7 @@ fn clean_maybe_renamed_item<'tcx>( return clean_extern_crate(item, name, orig_name, cx); } ItemKind::Use(path, kind) => { - return clean_use_statement(item, name, path, kind, cx); + return clean_use_statement(item, name, path, kind, cx, &mut FxHashSet::default()); } _ => unreachable!("not yet converted"), }; @@ -2083,6 +2076,7 @@ fn clean_use_statement<'tcx>( path: &hir::Path<'tcx>, kind: hir::UseKind, cx: &mut DocContext<'tcx>, + inlined_names: &mut FxHashSet<(ItemType, Symbol)>, ) -> Vec { // We need this comparison because some imports (for std types for example) // are "inserted" as well but directly by the compiler and they should not be @@ -2148,7 +2142,8 @@ fn clean_use_statement<'tcx>( let inner = if kind == hir::UseKind::Glob { if !denied { let mut visited = FxHashSet::default(); - if let Some(items) = inline::try_inline_glob(cx, path.res, &mut visited) { + if let Some(items) = inline::try_inline_glob(cx, path.res, &mut visited, inlined_names) + { return items; } } diff --git a/src/test/rustdoc/auxiliary/issue-100204-aux.rs b/src/test/rustdoc/auxiliary/issue-100204-aux.rs new file mode 100644 index 00000000000..df1b59069be --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-100204-aux.rs @@ -0,0 +1,13 @@ +#![crate_name="first"] + +pub mod prelude { + pub use crate::Bot; +} + +pub struct Bot; + +impl Bot { + pub fn new() -> Bot { + Bot + } +} diff --git a/src/test/rustdoc/issue-100204-inline-impl-through-glob-import.rs b/src/test/rustdoc/issue-100204-inline-impl-through-glob-import.rs new file mode 100644 index 00000000000..3e20c5c0741 --- /dev/null +++ b/src/test/rustdoc/issue-100204-inline-impl-through-glob-import.rs @@ -0,0 +1,14 @@ +// aux-build:issue-100204-aux.rs +// build-aux-docs +// ignore-cross-compile + +#![crate_name="second"] + +extern crate first; + +pub mod prelude {} + +// @has first/struct.Bot.html '//h4[@class="code-header"]' 'pub fn new() -> Bot' +// @has second/struct.Bot.html '//h4[@class="code-header"]' 'pub fn new() -> Bot' +#[doc(inline)] +pub use first::*; From 1a94193602e65c99344ba313c71d4298b0d4c0cc Mon Sep 17 00:00:00 2001 From: oxalica Date: Sun, 7 Aug 2022 04:17:04 +0800 Subject: [PATCH 57/77] Impl more methods and traits for la_arena::ArenaMap --- lib/la-arena/src/map.rs | 43 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/lib/la-arena/src/map.rs b/lib/la-arena/src/map.rs index f74ec5d97cb..3034e33a788 100644 --- a/lib/la-arena/src/map.rs +++ b/lib/la-arena/src/map.rs @@ -21,6 +21,33 @@ impl ArenaMap, V> { Self { v: Vec::with_capacity(capacity), _ty: PhantomData } } + /// Reserves capacity for at least additional more elements to be inserted in the map. + pub fn reserve(&mut self, additional: usize) { + self.v.reserve(additional); + } + + /// Clears the map, removing all elements. + pub fn clear(&mut self) { + self.v.clear(); + } + + /// Shrinks the capacity of the map as much as possible. + pub fn shrink_to_fit(&mut self) { + let min_len = self.v.iter().rposition(|slot| slot.is_some()).map_or(0, |i| i + 1); + self.v.truncate(min_len); + self.v.shrink_to_fit(); + } + + /// Returns whether the map contains a value for the specified index. + pub fn contains_idx(&self, idx: Idx) -> bool { + matches!(self.v.get(Self::to_idx(idx)), Some(Some(_))) + } + + /// Removes an index from the map, returning the value at the index if the index was previously in the map. + pub fn remove(&mut self, idx: Idx) -> Option { + self.v.get_mut(Self::to_idx(idx))?.take() + } + /// Inserts a value associated with a given arena index into the map. pub fn insert(&mut self, idx: Idx, t: V) { let idx = Self::to_idx(idx); @@ -94,6 +121,22 @@ impl Default for ArenaMap, T> { } } +impl Extend<(Idx, T)> for ArenaMap, T> { + fn extend, T)>>(&mut self, iter: I) { + iter.into_iter().for_each(move |(k, v)| { + self.insert(k, v); + }); + } +} + +impl FromIterator<(Idx, T)> for ArenaMap, T> { + fn from_iter, T)>>(iter: I) -> Self { + let mut this = Self::new(); + this.extend(iter); + this + } +} + /// A view into a single entry in a map, which may either be vacant or occupied. /// /// This `enum` is constructed from the [`entry`] method on [`ArenaMap`]. From 326ffee5b71e0113be20fc3b3b2aefbd4cd3b6d9 Mon Sep 17 00:00:00 2001 From: oxalica Date: Sun, 7 Aug 2022 04:48:52 +0800 Subject: [PATCH 58/77] Returns the old value for la_arena::ArenaMap::insert --- crates/hir-def/src/generics.rs | 2 +- crates/hir-def/src/visibility.rs | 2 +- crates/hir-ty/src/lower.rs | 2 +- lib/la-arena/src/map.rs | 7 +++++-- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/crates/hir-def/src/generics.rs b/crates/hir-def/src/generics.rs index 2397cf50158..469b28c2d9e 100644 --- a/crates/hir-def/src/generics.rs +++ b/crates/hir-def/src/generics.rs @@ -451,7 +451,7 @@ impl HasChildSource for GenericDefId { if let GenericDefId::TraitId(id) = *self { let trait_ref = id.lookup(db).source(db).value; let idx = idx_iter.next().unwrap(); - params.insert(idx, Either::Right(trait_ref)) + params.insert(idx, Either::Right(trait_ref)); } if let Some(generic_params_list) = generic_params_list { diff --git a/crates/hir-def/src/visibility.rs b/crates/hir-def/src/visibility.rs index 6e22a877a9f..087268a9ece 100644 --- a/crates/hir-def/src/visibility.rs +++ b/crates/hir-def/src/visibility.rs @@ -224,7 +224,7 @@ pub(crate) fn field_visibilities_query( let resolver = variant_id.module(db).resolver(db); let mut res = ArenaMap::default(); for (field_id, field_data) in var_data.fields().iter() { - res.insert(field_id, field_data.visibility.resolve(db, &resolver)) + res.insert(field_id, field_data.visibility.resolve(db, &resolver)); } Arc::new(res) } diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index 3ed9c941f47..239f66bcb7e 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -1126,7 +1126,7 @@ pub(crate) fn field_types_query( let ctx = TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable); for (field_id, field_data) in var_data.fields().iter() { - res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(&field_data.type_ref))) + res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(&field_data.type_ref))); } Arc::new(res) } diff --git a/lib/la-arena/src/map.rs b/lib/la-arena/src/map.rs index 3034e33a788..5f347e27450 100644 --- a/lib/la-arena/src/map.rs +++ b/lib/la-arena/src/map.rs @@ -49,11 +49,14 @@ impl ArenaMap, V> { } /// Inserts a value associated with a given arena index into the map. - pub fn insert(&mut self, idx: Idx, t: V) { + /// + /// If the map did not have this index present, None is returned. + /// Otherwise, the value is updated, and the old value is returned. + pub fn insert(&mut self, idx: Idx, t: V) -> Option { let idx = Self::to_idx(idx); self.v.resize_with((idx + 1).max(self.v.len()), || None); - self.v[idx] = Some(t); + self.v[idx].replace(t) } /// Returns a reference to the value associated with the provided index From 61c0b12d177c507f767f9169ed966ef83597eb44 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 7 Aug 2022 00:30:18 +0200 Subject: [PATCH 59/77] remove Clean trait implementation for hir::WherePredicate --- src/librustdoc/clean/mod.rs | 81 ++++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 38 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 14d81fc0946..4c4a7f77a90 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -266,44 +266,45 @@ pub(crate) fn clean_middle_region<'tcx>(region: ty::Region<'tcx>) -> Option Clean<'tcx, Option> for hir::WherePredicate<'tcx> { - fn clean(&self, cx: &mut DocContext<'tcx>) -> Option { - if !self.in_where_clause() { - return None; - } - Some(match *self { - hir::WherePredicate::BoundPredicate(ref wbp) => { - let bound_params = wbp - .bound_generic_params - .iter() - .map(|param| { - // Higher-ranked params must be lifetimes. - // Higher-ranked lifetimes can't have bounds. - assert_matches!( - param, - hir::GenericParam { kind: hir::GenericParamKind::Lifetime { .. }, .. } - ); - Lifetime(param.name.ident().name) - }) - .collect(); - WherePredicate::BoundPredicate { - ty: clean_ty(wbp.bounded_ty, cx), - bounds: wbp.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(), - bound_params, - } - } - - hir::WherePredicate::RegionPredicate(ref wrp) => WherePredicate::RegionPredicate { - lifetime: clean_lifetime(wrp.lifetime, cx), - bounds: wrp.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(), - }, - - hir::WherePredicate::EqPredicate(ref wrp) => WherePredicate::EqPredicate { - lhs: clean_ty(wrp.lhs_ty, cx), - rhs: clean_ty(wrp.rhs_ty, cx).into(), - }, - }) +fn clean_where_predicate<'tcx>( + predicate: &hir::WherePredicate<'tcx>, + cx: &mut DocContext<'tcx>, +) -> Option { + if !predicate.in_where_clause() { + return None; } + Some(match *predicate { + hir::WherePredicate::BoundPredicate(ref wbp) => { + let bound_params = wbp + .bound_generic_params + .iter() + .map(|param| { + // Higher-ranked params must be lifetimes. + // Higher-ranked lifetimes can't have bounds. + assert_matches!( + param, + hir::GenericParam { kind: hir::GenericParamKind::Lifetime { .. }, .. } + ); + Lifetime(param.name.ident().name) + }) + .collect(); + WherePredicate::BoundPredicate { + ty: clean_ty(wbp.bounded_ty, cx), + bounds: wbp.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(), + bound_params, + } + } + + hir::WherePredicate::RegionPredicate(ref wrp) => WherePredicate::RegionPredicate { + lifetime: clean_lifetime(wrp.lifetime, cx), + bounds: wrp.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(), + }, + + hir::WherePredicate::EqPredicate(ref wrp) => WherePredicate::EqPredicate { + lhs: clean_ty(wrp.lhs_ty, cx), + rhs: clean_ty(wrp.rhs_ty, cx).into(), + }, + }) } impl<'tcx> Clean<'tcx, Option> for ty::Predicate<'tcx> { @@ -601,7 +602,11 @@ impl<'tcx> Clean<'tcx, Generics> for hir::Generics<'tcx> { let mut generics = Generics { params, - where_predicates: self.predicates.iter().filter_map(|x| x.clean(cx)).collect(), + where_predicates: self + .predicates + .iter() + .filter_map(|x| clean_where_predicate(x, cx)) + .collect(), }; // Some duplicates are generated for ?Sized bounds between type params and where From a238d1284e3efc67bf97687a0701d8b1449bfae3 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 7 Aug 2022 00:36:23 +0200 Subject: [PATCH 60/77] remove Clean trait implementation for ty::Predicate --- src/librustdoc/clean/auto_trait.rs | 2 +- src/librustdoc/clean/mod.rs | 43 +++++++++++++++--------------- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 71f070f2678..5a208768a75 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -474,7 +474,7 @@ where let mut ty_to_fn: FxHashMap, Option)> = Default::default(); for p in clean_where_predicates { - let (orig_p, p) = (p, p.clean(self.cx)); + let (orig_p, p) = (p, clean_predicate(p, self.cx)); if p.is_none() { continue; } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 4c4a7f77a90..b5244616309 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -307,26 +307,27 @@ fn clean_where_predicate<'tcx>( }) } -impl<'tcx> Clean<'tcx, Option> for ty::Predicate<'tcx> { - fn clean(&self, cx: &mut DocContext<'tcx>) -> Option { - let bound_predicate = self.kind(); - match bound_predicate.skip_binder() { - ty::PredicateKind::Trait(pred) => { - clean_poly_trait_predicate(bound_predicate.rebind(pred), cx) - } - ty::PredicateKind::RegionOutlives(pred) => clean_region_outlives_predicate(pred), - ty::PredicateKind::TypeOutlives(pred) => clean_type_outlives_predicate(pred, cx), - ty::PredicateKind::Projection(pred) => Some(clean_projection_predicate(pred, cx)), - ty::PredicateKind::ConstEvaluatable(..) => None, - ty::PredicateKind::WellFormed(..) => None, - - ty::PredicateKind::Subtype(..) - | ty::PredicateKind::Coerce(..) - | ty::PredicateKind::ObjectSafe(..) - | ty::PredicateKind::ClosureKind(..) - | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::TypeWellFormedFromEnv(..) => panic!("not user writable"), +pub(crate) fn clean_predicate<'tcx>( + predicate: ty::Predicate<'tcx>, + cx: &mut DocContext<'tcx>, +) -> Option { + let bound_predicate = predicate.kind(); + match bound_predicate.skip_binder() { + ty::PredicateKind::Trait(pred) => { + clean_poly_trait_predicate(bound_predicate.rebind(pred), cx) } + ty::PredicateKind::RegionOutlives(pred) => clean_region_outlives_predicate(pred), + ty::PredicateKind::TypeOutlives(pred) => clean_type_outlives_predicate(pred, cx), + ty::PredicateKind::Projection(pred) => Some(clean_projection_predicate(pred, cx)), + ty::PredicateKind::ConstEvaluatable(..) => None, + ty::PredicateKind::WellFormed(..) => None, + + ty::PredicateKind::Subtype(..) + | ty::PredicateKind::Coerce(..) + | ty::PredicateKind::ObjectSafe(..) + | ty::PredicateKind::ClosureKind(..) + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::TypeWellFormedFromEnv(..) => panic!("not user writable"), } } @@ -707,7 +708,7 @@ fn clean_ty_generics<'tcx>( if let Some(param_idx) = param_idx { if let Some(b) = impl_trait.get_mut(¶m_idx.into()) { - let p: WherePredicate = p.clean(cx)?; + let p: WherePredicate = clean_predicate(*p, cx)?; b.extend( p.get_bounds() @@ -764,7 +765,7 @@ fn clean_ty_generics<'tcx>( // Now that `cx.impl_trait_bounds` is populated, we can process // remaining predicates which could contain `impl Trait`. let mut where_predicates = - where_predicates.into_iter().flat_map(|p| p.clean(cx)).collect::>(); + where_predicates.into_iter().flat_map(|p| clean_predicate(*p, cx)).collect::>(); // Type parameters have a Sized bound by default unless removed with // ?Sized. Scan through the predicates and mark any type parameter with From eca6f2e897a0c09546fd8d8faba79ec2ce45be52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Sun, 7 Aug 2022 09:29:26 +0300 Subject: [PATCH 61/77] Fix test_rainbow_highlighting gate --- crates/ide/src/syntax_highlighting/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs index 99be7c66486..382735cb368 100644 --- a/crates/ide/src/syntax_highlighting/tests.rs +++ b/crates/ide/src/syntax_highlighting/tests.rs @@ -958,7 +958,7 @@ pub struct Struct; #[test] #[cfg_attr( - all(unix, not(target_pointer_width = "64")), + not(all(unix, target_pointer_width = "64")), ignore = "depends on `DefaultHasher` outputs" )] fn test_rainbow_highlighting() { From fc83a0cb57eaad7104cc8861ba354fc76da79684 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Sun, 7 Aug 2022 04:03:28 -0700 Subject: [PATCH 62/77] Don't ICE while suggesting updating item path. When an item isn't found, we may suggest an appropriate import to `use`. Along with that, we also suggest updating the path to work with the `use`. Unfortunately, if the code in question originates from a macro, the span used to indicate which part of the path needs updating may not be suitable and cause an ICE. Since, such code is not adjustable directly by the user without modifying the macro, just skip the suggestion in such cases. --- compiler/rustc_resolve/src/diagnostics.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 8839fb1a151..325b0458638 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -2544,12 +2544,15 @@ fn show_candidates( Applicability::MaybeIncorrect, ); if let [first, .., last] = &path[..] { - err.span_suggestion_verbose( - first.ident.span.until(last.ident.span), - &format!("if you import `{}`, refer to it directly", last.ident), - "", - Applicability::Unspecified, - ); + let sp = first.ident.span.until(last.ident.span); + if sp.can_be_used_for_suggestions() { + err.span_suggestion_verbose( + sp, + &format!("if you import `{}`, refer to it directly", last.ident), + "", + Applicability::Unspecified, + ); + } } } else { msg.push(':'); From 4ee2fe308bc68a0d93a86a09a1fd2506cc41e9b2 Mon Sep 17 00:00:00 2001 From: Bryysen Date: Sun, 7 Aug 2022 17:24:25 +0200 Subject: [PATCH 63/77] Further improve error message for E0081 Multiple duplicate assignments of the same discriminant are now reported in the samme error. We now point out the incrementation start point for discriminants that are not explicitly assigned that are also duplicates. Removed old test related to E0081 that is now covered by error-codes/E0081.rs. Also refactored parts of the `check_enum` function. --- compiler/rustc_typeck/src/check/check.rs | 147 ++++++++++-------- compiler/rustc_typeck/src/check/mod.rs | 1 - src/test/ui/enum/enum-discrim-autosizing.rs | 4 +- .../ui/enum/enum-discrim-autosizing.stderr | 4 +- src/test/ui/error-codes/E0081.rs | 32 +++- src/test/ui/error-codes/E0081.stderr | 37 ++++- src/test/ui/issues/issue-15524.rs | 16 -- src/test/ui/issues/issue-15524.stderr | 40 ----- src/test/ui/tag-variant-disr-dup.stderr | 4 +- 9 files changed, 143 insertions(+), 142 deletions(-) delete mode 100644 src/test/ui/issues/issue-15524.rs delete mode 100644 src/test/ui/issues/issue-15524.stderr diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 9c1fd9b30b4..82d4e235cb3 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -32,7 +32,6 @@ use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; use rustc_trait_selection::traits::{self, ObligationCtxt}; use rustc_ty_utils::representability::{self, Representability}; -use std::iter; use std::ops::ControlFlow; pub(super) fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) { @@ -1494,76 +1493,96 @@ fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: L } } - let mut disr_vals: Vec> = Vec::with_capacity(vs.len()); - // This tracks the previous variant span (in the loop) incase we need it for diagnostics - let mut prev_variant_span: Span = DUMMY_SP; - for ((_, discr), v) in iter::zip(def.discriminants(tcx), vs) { - // Check for duplicate discriminant values - if let Some(i) = disr_vals.iter().position(|&x| x.val == discr.val) { - let variant_did = def.variant(VariantIdx::new(i)).def_id; - let variant_i_hir_id = tcx.hir().local_def_id_to_hir_id(variant_did.expect_local()); - let variant_i = tcx.hir().expect_variant(variant_i_hir_id); - let i_span = match variant_i.disr_expr { - Some(ref expr) => tcx.hir().span(expr.hir_id), - None => tcx.def_span(variant_did), - }; - let span = match v.disr_expr { - Some(ref expr) => tcx.hir().span(expr.hir_id), - None => v.span, - }; - let display_discr = format_discriminant_overflow(tcx, v, discr); - let display_discr_i = format_discriminant_overflow(tcx, variant_i, disr_vals[i]); - let no_disr = v.disr_expr.is_none(); - let mut err = struct_span_err!( - tcx.sess, - sp, - E0081, - "discriminant value `{}` assigned more than once", - discr, - ); - - err.span_label(i_span, format!("first assignment of {display_discr_i}")); - err.span_label(span, format!("second assignment of {display_discr}")); - - if no_disr { - err.span_label( - prev_variant_span, - format!( - "assigned discriminant for `{}` was incremented from this discriminant", - v.ident - ), - ); - } - err.emit(); - } - - disr_vals.push(discr); - prev_variant_span = v.span; - } + detect_discriminant_duplicate(tcx, def.discriminants(tcx).collect(), vs, sp); check_representable(tcx, sp, def_id); check_transparent(tcx, sp, def); } -/// In the case that a discriminant is both a duplicate and an overflowing literal, -/// we insert both the assigned discriminant and the literal it overflowed from into the formatted -/// output. Otherwise we format the discriminant normally. -fn format_discriminant_overflow<'tcx>( +fn detect_discriminant_duplicate<'tcx>( tcx: TyCtxt<'tcx>, - variant: &hir::Variant<'_>, - dis: Discr<'tcx>, -) -> String { - if let Some(expr) = &variant.disr_expr { - let body = &tcx.hir().body(expr.body).value; - if let hir::ExprKind::Lit(lit) = &body.kind - && let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node - && dis.val != *lit_value - { - return format!("`{dis}` (overflowed from `{lit_value}`)"); - } - } + mut discrs: Vec<(VariantIdx, Discr<'tcx>)>, + vs: &'tcx [hir::Variant<'tcx>], + self_span: Span, +) { + let report = |var: &hir::Variant<'_>, + dis: Discr<'tcx>, + idx: usize, + err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>| { + let (span, display_discr) = match var.disr_expr { + Some(ref expr) => { + // In the case the discriminant is both a duplicate and overflowed, let the user know + if let hir::ExprKind::Lit(lit) = &tcx.hir().body(expr.body).value.kind + && let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node + && *lit_value != dis.val + { + (tcx.hir().span(expr.hir_id), format!("`{dis}` (overflowed from `{lit_value}`)")) + } else { + (tcx.hir().span(expr.hir_id), format!("`{dis}`")) + } + } + None => { + if let Some((n, hir::Variant { span, ident, .. })) = + vs[..idx].iter().rev().enumerate().find(|v| v.1.disr_expr.is_some()) + { + let ve_ident = var.ident; + let sp = if n > 1 { "variants" } else { "variant" }; + let n = n + 1; - format!("`{dis}`") + err.span_label( + *span, + format!("discriminant for `{ve_ident}` incremented from this startpoint (`{ident}` + {n} {sp} later => `{ve_ident}` = {dis})"), + ); + } + + (vs[idx].span, format!("`{dis}`")) + } + }; + + err.span_label(span, format!("{display_discr} assigned here")); + }; + + let mut i = 0; + while i < discrs.len() { + let hir_var_i_idx = discrs[i].0.index(); + let hir_var_i = &vs[hir_var_i_idx]; + let mut error: Option> = None; + + let mut o = i + 1; + while o < discrs.len() { + let hir_var_o_idx = discrs[o].0.index(); + let hir_var_o = &vs[hir_var_o_idx]; + + if discrs[i].1.val == discrs[o].1.val { + let err = error.get_or_insert_with(|| { + let mut ret = struct_span_err!( + tcx.sess, + self_span, + E0081, + "discriminant value `{}` assigned more than once", + discrs[i].1, + ); + + report(hir_var_i, discrs[i].1, hir_var_i_idx, &mut ret); + + ret + }); + + report(hir_var_o, discrs[o].1, hir_var_o_idx, err); + + discrs[o] = *discrs.last().unwrap(); + discrs.pop(); + } else { + o += 1; + } + } + + if let Some(mut e) = error { + e.emit(); + } + + i += 1; + } } pub(super) fn check_type_params_are_used<'tcx>( diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index 17c2e4868aa..199277abbc4 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -112,7 +112,6 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_hir::{HirIdMap, ImplicitSelfKind, Node}; use rustc_index::bit_set::BitSet; -use rustc_index::vec::Idx; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef}; diff --git a/src/test/ui/enum/enum-discrim-autosizing.rs b/src/test/ui/enum/enum-discrim-autosizing.rs index 27fab1bb505..fc94d281c77 100644 --- a/src/test/ui/enum/enum-discrim-autosizing.rs +++ b/src/test/ui/enum/enum-discrim-autosizing.rs @@ -6,9 +6,9 @@ enum Eu64 { //~^ ERROR discriminant value `0` assigned more than once Au64 = 0, - //~^NOTE first assignment of `0` + //~^NOTE `0` assigned here Bu64 = 0x8000_0000_0000_0000 - //~^NOTE second assignment of `0` (overflowed from `9223372036854775808`) + //~^NOTE `0` (overflowed from `9223372036854775808`) assigned here } fn main() {} diff --git a/src/test/ui/enum/enum-discrim-autosizing.stderr b/src/test/ui/enum/enum-discrim-autosizing.stderr index eacea86d67e..be3d7c64e28 100644 --- a/src/test/ui/enum/enum-discrim-autosizing.stderr +++ b/src/test/ui/enum/enum-discrim-autosizing.stderr @@ -5,10 +5,10 @@ LL | enum Eu64 { | ^^^^^^^^^ LL | LL | Au64 = 0, - | - first assignment of `0` + | - `0` assigned here LL | LL | Bu64 = 0x8000_0000_0000_0000 - | --------------------- second assignment of `0` (overflowed from `9223372036854775808`) + | --------------------- `0` (overflowed from `9223372036854775808`) assigned here error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0081.rs b/src/test/ui/error-codes/E0081.rs index 5aa6a786339..5e970a89307 100644 --- a/src/test/ui/error-codes/E0081.rs +++ b/src/test/ui/error-codes/E0081.rs @@ -1,9 +1,9 @@ enum Enum { //~^ ERROR discriminant value `3` assigned more than once P = 3, - //~^ NOTE first assignment of `3` + //~^ NOTE `3` assigned here X = 3, - //~^ NOTE second assignment of `3` + //~^ NOTE `3` assigned here Y = 5 } @@ -11,20 +11,38 @@ enum Enum { enum EnumOverflowRepr { //~^ ERROR discriminant value `1` assigned more than once P = 257, - //~^ NOTE first assignment of `1` (overflowed from `257`) + //~^ NOTE `1` (overflowed from `257`) assigned here X = 513, - //~^ NOTE second assignment of `1` (overflowed from `513`) + //~^ NOTE `1` (overflowed from `513`) assigned here } #[repr(i8)] enum NegDisEnum { //~^ ERROR discriminant value `-1` assigned more than once First = -1, - //~^ NOTE first assignment of `-1` + //~^ NOTE `-1` assigned here Second = -2, - //~^ NOTE assigned discriminant for `Last` was incremented from this discriminant + //~^ NOTE discriminant for `Last` incremented from this startpoint (`Second` + 1 variant later => `Last` = -1) Last, - //~^ NOTE second assignment of `-1` + //~^ NOTE `-1` assigned here +} + +#[repr(i32)] +enum MultipleDuplicates { + //~^ ERROR discriminant value `0` assigned more than once + V0, + //~^ NOTE `0` assigned here + V1 = 0, + //~^ NOTE `0` assigned here + V2, + V3, + V4 = 0, + //~^ NOTE `0` assigned here + V5 = -2, + //~^ NOTE discriminant for `V7` incremented from this startpoint (`V5` + 2 variant later => `V7` = 0) + V6, + V7, + //~^ NOTE `0` assigned here } fn main() { diff --git a/src/test/ui/error-codes/E0081.stderr b/src/test/ui/error-codes/E0081.stderr index ff6113646bb..d27861aca5f 100644 --- a/src/test/ui/error-codes/E0081.stderr +++ b/src/test/ui/error-codes/E0081.stderr @@ -5,10 +5,10 @@ LL | enum Enum { | ^^^^^^^^^ LL | LL | P = 3, - | - first assignment of `3` + | - `3` assigned here LL | LL | X = 3, - | - second assignment of `3` + | - `3` assigned here error[E0081]: discriminant value `1` assigned more than once --> $DIR/E0081.rs:11:1 @@ -17,10 +17,10 @@ LL | enum EnumOverflowRepr { | ^^^^^^^^^^^^^^^^^^^^^ LL | LL | P = 257, - | --- first assignment of `1` (overflowed from `257`) + | --- `1` (overflowed from `257`) assigned here LL | LL | X = 513, - | --- second assignment of `1` (overflowed from `513`) + | --- `1` (overflowed from `513`) assigned here error[E0081]: discriminant value `-1` assigned more than once --> $DIR/E0081.rs:20:1 @@ -29,14 +29,35 @@ LL | enum NegDisEnum { | ^^^^^^^^^^^^^^^ LL | LL | First = -1, - | -- first assignment of `-1` + | -- `-1` assigned here LL | LL | Second = -2, - | ----------- assigned discriminant for `Last` was incremented from this discriminant + | ----------- discriminant for `Last` incremented from this startpoint (`Second` + 1 variant later => `Last` = -1) LL | LL | Last, - | ---- second assignment of `-1` + | ---- `-1` assigned here -error: aborting due to 3 previous errors +error[E0081]: discriminant value `0` assigned more than once + --> $DIR/E0081.rs:31:1 + | +LL | enum MultipleDuplicates { + | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | V0, + | -- `0` assigned here +LL | +LL | V1 = 0, + | - `0` assigned here +... +LL | V4 = 0, + | - `0` assigned here +LL | +LL | V5 = -2, + | ------- discriminant for `V7` incremented from this startpoint (`V5` + 2 variant later => `V7` = 0) +... +LL | V7, + | -- `0` assigned here + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0081`. diff --git a/src/test/ui/issues/issue-15524.rs b/src/test/ui/issues/issue-15524.rs deleted file mode 100644 index 565db2d0fca..00000000000 --- a/src/test/ui/issues/issue-15524.rs +++ /dev/null @@ -1,16 +0,0 @@ -const N: isize = 1; - -enum Foo { - //~^ ERROR discriminant value `1` assigned more than once - //~| ERROR discriminant value `1` assigned more than once - //~| ERROR discriminant value `1` assigned more than once - A = 1, - B = 1, - C = 0, - D, - - E = N, - -} - -fn main() {} diff --git a/src/test/ui/issues/issue-15524.stderr b/src/test/ui/issues/issue-15524.stderr deleted file mode 100644 index 1195e0a346d..00000000000 --- a/src/test/ui/issues/issue-15524.stderr +++ /dev/null @@ -1,40 +0,0 @@ -error[E0081]: discriminant value `1` assigned more than once - --> $DIR/issue-15524.rs:3:1 - | -LL | enum Foo { - | ^^^^^^^^ -... -LL | A = 1, - | - first assignment of `1` -LL | B = 1, - | - second assignment of `1` - -error[E0081]: discriminant value `1` assigned more than once - --> $DIR/issue-15524.rs:3:1 - | -LL | enum Foo { - | ^^^^^^^^ -... -LL | A = 1, - | - first assignment of `1` -LL | B = 1, -LL | C = 0, - | ----- assigned discriminant for `D` was incremented from this discriminant -LL | D, - | - second assignment of `1` - -error[E0081]: discriminant value `1` assigned more than once - --> $DIR/issue-15524.rs:3:1 - | -LL | enum Foo { - | ^^^^^^^^ -... -LL | A = 1, - | - first assignment of `1` -... -LL | E = N, - | - second assignment of `1` - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0081`. diff --git a/src/test/ui/tag-variant-disr-dup.stderr b/src/test/ui/tag-variant-disr-dup.stderr index 6b1ba43d2ba..4932cde0b18 100644 --- a/src/test/ui/tag-variant-disr-dup.stderr +++ b/src/test/ui/tag-variant-disr-dup.stderr @@ -5,9 +5,9 @@ LL | enum Color { | ^^^^^^^^^^ ... LL | Black = 0x000000, - | -------- first assignment of `0` + | -------- `0` assigned here LL | White = 0x000000, - | -------- second assignment of `0` + | -------- `0` assigned here error: aborting due to previous error From 399796d2b351b6ec3d58c47db610926f73ad779e Mon Sep 17 00:00:00 2001 From: Bryysen Date: Sun, 7 Aug 2022 22:28:16 +0200 Subject: [PATCH 64/77] Add comments to obscure code, remove unnesecary parameter from closure --- compiler/rustc_typeck/src/check/check.rs | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 82d4e235cb3..e2527b78d78 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -1499,16 +1499,18 @@ fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: L check_transparent(tcx, sp, def); } +/// Part of enum check, errors if two or more discriminants are equal fn detect_discriminant_duplicate<'tcx>( tcx: TyCtxt<'tcx>, mut discrs: Vec<(VariantIdx, Discr<'tcx>)>, vs: &'tcx [hir::Variant<'tcx>], self_span: Span, ) { - let report = |var: &hir::Variant<'_>, - dis: Discr<'tcx>, + // Helper closure to reduce duplicate code. This gets called everytime we detect a duplicate + let report = |dis: Discr<'tcx>, idx: usize, err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>| { + let var = &vs[idx]; let (span, display_discr) = match var.disr_expr { Some(ref expr) => { // In the case the discriminant is both a duplicate and overflowed, let the user know @@ -1517,11 +1519,16 @@ fn detect_discriminant_duplicate<'tcx>( && *lit_value != dis.val { (tcx.hir().span(expr.hir_id), format!("`{dis}` (overflowed from `{lit_value}`)")) + // Otherwise, format the value as-is } else { (tcx.hir().span(expr.hir_id), format!("`{dis}`")) } } None => { + // At this point we know this discriminant is a duplicate, and was not explicitly + // assigned by the user. Here we iterate backwards to fetch the hir for the last + // explictly assigned discriminant, and letting the user know that this was the + // increment startpoint, and how many steps from there leading to the duplicate if let Some((n, hir::Variant { span, ident, .. })) = vs[..idx].iter().rev().enumerate().find(|v| v.1.disr_expr.is_some()) { @@ -1542,16 +1549,20 @@ fn detect_discriminant_duplicate<'tcx>( err.span_label(span, format!("{display_discr} assigned here")); }; + // Here we are looping through the discriminant vec, comparing each discriminant to oneanother. + // When a duplicate is detected, we instatiate an error and add a spanned note pointing to both + // initial and duplicate value. The duplicate discriminant is then discarded from the vec by swapping + // it with the last element and decrementing the vec.len by 1 (which is why we have to evaluate + // `discrs.len()` anew every iteration, and why this could be tricky to do in a functional style as + // we are mutating `discrs` on the fly). let mut i = 0; while i < discrs.len() { let hir_var_i_idx = discrs[i].0.index(); - let hir_var_i = &vs[hir_var_i_idx]; let mut error: Option> = None; let mut o = i + 1; while o < discrs.len() { let hir_var_o_idx = discrs[o].0.index(); - let hir_var_o = &vs[hir_var_o_idx]; if discrs[i].1.val == discrs[o].1.val { let err = error.get_or_insert_with(|| { @@ -1563,13 +1574,14 @@ fn detect_discriminant_duplicate<'tcx>( discrs[i].1, ); - report(hir_var_i, discrs[i].1, hir_var_i_idx, &mut ret); + report(discrs[i].1, hir_var_i_idx, &mut ret); ret }); - report(hir_var_o, discrs[o].1, hir_var_o_idx, err); + report(discrs[o].1, hir_var_o_idx, err); + // Safe to unwrap here, as we wouldn't reach this point if `discrs` was empty discrs[o] = *discrs.last().unwrap(); discrs.pop(); } else { From 15b1daaca3fd4020d7a93cff14507b9104ec6d02 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Sun, 7 Aug 2022 13:55:36 -0700 Subject: [PATCH 65/77] Add UI test for #100199 --- src/test/ui/macros/auxiliary/issue-100199.rs | 18 ++++++++++++++++++ src/test/ui/macros/issue-100199.rs | 16 ++++++++++++++++ src/test/ui/macros/issue-100199.stderr | 15 +++++++++++++++ 3 files changed, 49 insertions(+) create mode 100644 src/test/ui/macros/auxiliary/issue-100199.rs create mode 100644 src/test/ui/macros/issue-100199.rs create mode 100644 src/test/ui/macros/issue-100199.stderr diff --git a/src/test/ui/macros/auxiliary/issue-100199.rs b/src/test/ui/macros/auxiliary/issue-100199.rs new file mode 100644 index 00000000000..9e190b542db --- /dev/null +++ b/src/test/ui/macros/auxiliary/issue-100199.rs @@ -0,0 +1,18 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] +#![feature(proc_macro_quote)] + +extern crate proc_macro; + +use proc_macro::{quote, Ident, Span, TokenStream, TokenTree}; + +#[proc_macro_attribute] +pub fn struct_with_bound(_: TokenStream, _: TokenStream) -> TokenStream { + let crate_ident = TokenTree::Ident(Ident::new("crate", Span::call_site())); + let trait_ident = TokenTree::Ident(Ident::new("MyTrait", Span::call_site())); + quote!( + struct Foo {} + ) +} diff --git a/src/test/ui/macros/issue-100199.rs b/src/test/ui/macros/issue-100199.rs new file mode 100644 index 00000000000..6e50afa0759 --- /dev/null +++ b/src/test/ui/macros/issue-100199.rs @@ -0,0 +1,16 @@ +#[issue_100199::struct_with_bound] //~ ERROR cannot find trait `MyTrait` in the crate root +struct Foo {} +// The above must be on the first line so that it's span points to pos 0. +// This used to trigger an ICE because the diagnostic emitter would get +// an unexpected dummy span (lo == 0 == hi) while attempting to print a +// suggestion. + +// aux-build: issue-100199.rs + +extern crate issue_100199; + +mod traits { + pub trait MyTrait {} +} + +fn main() {} diff --git a/src/test/ui/macros/issue-100199.stderr b/src/test/ui/macros/issue-100199.stderr new file mode 100644 index 00000000000..2cb45dc1247 --- /dev/null +++ b/src/test/ui/macros/issue-100199.stderr @@ -0,0 +1,15 @@ +error[E0405]: cannot find trait `MyTrait` in the crate root + --> $DIR/issue-100199.rs:1:1 + | +LL | #[issue_100199::struct_with_bound] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in the crate root + | + = note: this error originates in the attribute macro `issue_100199::struct_with_bound` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider importing this trait + | +LL | use traits::MyTrait; + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0405`. From bfd7535130692af426f1230777f313cf7610f45e Mon Sep 17 00:00:00 2001 From: Bryysen Date: Sun, 7 Aug 2022 23:50:12 +0200 Subject: [PATCH 66/77] Fix wording on comment --- compiler/rustc_typeck/src/check/check.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index e2527b78d78..1943d3de3ad 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -1526,7 +1526,7 @@ fn detect_discriminant_duplicate<'tcx>( } None => { // At this point we know this discriminant is a duplicate, and was not explicitly - // assigned by the user. Here we iterate backwards to fetch the hir for the last + // assigned by the user. Here we iterate backwards to fetch the HIR for the last // explictly assigned discriminant, and letting the user know that this was the // increment startpoint, and how many steps from there leading to the duplicate if let Some((n, hir::Variant { span, ident, .. })) = @@ -1549,12 +1549,12 @@ fn detect_discriminant_duplicate<'tcx>( err.span_label(span, format!("{display_discr} assigned here")); }; - // Here we are looping through the discriminant vec, comparing each discriminant to oneanother. - // When a duplicate is detected, we instatiate an error and add a spanned note pointing to both - // initial and duplicate value. The duplicate discriminant is then discarded from the vec by swapping - // it with the last element and decrementing the vec.len by 1 (which is why we have to evaluate - // `discrs.len()` anew every iteration, and why this could be tricky to do in a functional style as - // we are mutating `discrs` on the fly). + // Here we are loop through the discriminants, comparing each discriminant to another. + // When a duplicate is detected, we instatiate an error and point to both + // initial and duplicate value. The duplicate discriminant is then discarded by swapping + // it with the last element and decrementing the `vec.len` (which is why we have to evaluate + // `discrs.len()` anew every iteration, and why this could be tricky to do in a functional + // style as we are mutating `discrs` on the fly). let mut i = 0; while i < discrs.len() { let hir_var_i_idx = discrs[i].0.index(); From b3b23aada9382e7768c0bd4d8f79319d73558259 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 7 Aug 2022 05:47:32 +0000 Subject: [PATCH 67/77] Don't document impossible to call default trait items on impls --- compiler/rustc_middle/src/query/mod.rs | 8 ++ .../rustc_trait_selection/src/traits/mod.rs | 78 ++++++++++++++++++- src/librustdoc/html/render/mod.rs | 9 +++ src/test/rustdoc/impossible-default.rs | 20 +++++ 4 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 src/test/rustdoc/impossible-default.rs diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index d8483e7e409..9db193dc0ce 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1951,6 +1951,14 @@ rustc_queries! { } } + query is_impossible_method(key: (DefId, DefId)) -> bool { + desc { |tcx| + "checking if {} is impossible to call within {}", + tcx.def_path_str(key.1), + tcx.def_path_str(key.0), + } + } + query method_autoderef_steps( goal: CanonicalTyGoal<'tcx> ) -> MethodAutoderefStepsResult<'tcx> { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 9c6bb0731f4..06aeafa26c0 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -30,10 +30,14 @@ use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; +use rustc_infer::traits::TraitEngineExt as _; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::{InternalSubsts, SubstsRef}; use rustc_middle::ty::visit::TypeVisitable; -use rustc_middle::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry}; +use rustc_middle::ty::{ + self, DefIdTree, GenericParamDefKind, Subst, ToPredicate, Ty, TyCtxt, TypeSuperVisitable, + VtblEntry, +}; use rustc_span::{sym, Span}; use smallvec::SmallVec; @@ -474,6 +478,77 @@ fn subst_and_check_impossible_predicates<'tcx>( result } +/// Checks whether a trait's method is impossible to call on a given impl. +/// +/// This only considers predicates that reference the impl's generics, and not +/// those that reference the method's generics. +fn is_impossible_method<'tcx>( + tcx: TyCtxt<'tcx>, + (impl_def_id, trait_item_def_id): (DefId, DefId), +) -> bool { + struct ReferencesOnlyParentGenerics<'tcx> { + tcx: TyCtxt<'tcx>, + generics: &'tcx ty::Generics, + trait_item_def_id: DefId, + } + impl<'tcx> ty::TypeVisitor<'tcx> for ReferencesOnlyParentGenerics<'tcx> { + type BreakTy = (); + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { + // If this is a parameter from the trait item's own generics, then bail + if let ty::Param(param) = t.kind() + && let param_def_id = self.generics.type_param(param, self.tcx).def_id + && self.tcx.parent(param_def_id) == self.trait_item_def_id + { + return ControlFlow::BREAK; + } + t.super_visit_with(self) + } + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { + if let ty::ReEarlyBound(param) = r.kind() + && let param_def_id = self.generics.region_param(¶m, self.tcx).def_id + && self.tcx.parent(param_def_id) == self.trait_item_def_id + { + return ControlFlow::BREAK; + } + r.super_visit_with(self) + } + fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow { + if let ty::ConstKind::Param(param) = ct.kind() + && let param_def_id = self.generics.const_param(¶m, self.tcx).def_id + && self.tcx.parent(param_def_id) == self.trait_item_def_id + { + return ControlFlow::BREAK; + } + ct.super_visit_with(self) + } + } + + let generics = tcx.generics_of(trait_item_def_id); + let predicates = tcx.predicates_of(trait_item_def_id); + let impl_trait_ref = + tcx.impl_trait_ref(impl_def_id).expect("expected impl to correspond to trait"); + let param_env = tcx.param_env(impl_def_id); + + let mut visitor = ReferencesOnlyParentGenerics { tcx, generics, trait_item_def_id }; + let predicates_for_trait = predicates.predicates.iter().filter_map(|(pred, span)| { + if pred.visit_with(&mut visitor).is_continue() { + Some(Obligation::new( + ObligationCause::dummy_with_span(*span), + param_env, + ty::EarlyBinder(*pred).subst(tcx, impl_trait_ref.substs), + )) + } else { + None + } + }); + + tcx.infer_ctxt().ignoring_regions().enter(|ref infcx| { + let mut fulfill_ctxt = >::new(tcx); + fulfill_ctxt.register_predicate_obligations(infcx, predicates_for_trait); + !fulfill_ctxt.select_all_or_error(infcx).is_empty() + }) +} + #[derive(Clone, Debug)] enum VtblSegment<'tcx> { MetadataDSA, @@ -854,6 +929,7 @@ pub fn provide(providers: &mut ty::query::Providers) { vtable_entries, vtable_trait_upcasting_coercion_new_vptr_slot, subst_and_check_impossible_predicates, + is_impossible_method, try_unify_abstract_consts: |tcx, param_env_and| { let (param_env, (a, b)) = param_env_and.into_parts(); const_evaluatable::try_unify_abstract_consts(tcx, (a, b), param_env) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index a262c8f7d19..ae7d8c108d3 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1550,6 +1550,15 @@ fn render_impl( rendering_params: ImplRenderingParameters, ) { for trait_item in &t.items { + // Skip over any default trait items that are impossible to call + // (e.g. if it has a `Self: Sized` bound on an unsized type). + if let Some(impl_def_id) = parent.item_id.as_def_id() + && let Some(trait_item_def_id) = trait_item.item_id.as_def_id() + && cx.tcx().is_impossible_method((impl_def_id, trait_item_def_id)) + { + continue; + } + let n = trait_item.name; if i.items.iter().any(|m| m.name == n) { continue; diff --git a/src/test/rustdoc/impossible-default.rs b/src/test/rustdoc/impossible-default.rs new file mode 100644 index 00000000000..24d6e3bdac1 --- /dev/null +++ b/src/test/rustdoc/impossible-default.rs @@ -0,0 +1,20 @@ +#![crate_name = "foo"] + +// Check that default trait items that are impossible to satisfy + +pub trait Foo { + fn needs_sized(&self) + where + Self: Sized, + {} + + fn no_needs_sized(&self) {} +} + +// @!has foo/struct.Bar.html '//*[@id="method.needs_sized"]//h4[@class="code-header"]' \ +// "fn needs_sized" +// @has foo/struct.Bar.html '//*[@id="method.no_needs_sized"]//h4[@class="code-header"]' \ +// "fn no_needs_sized" +pub struct Bar([u8]); + +impl Foo for Bar {} From 750f04d30973b5615e54ee27c7336846d19943ee Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 3 Jul 2022 20:17:08 +0000 Subject: [PATCH 68/77] Implement special-cased projection error message for some common traits --- .../src/traits/error_reporting/mod.rs | 62 +++++++++++++++---- .../associated-types-overridden-binding-2.rs | 2 +- ...sociated-types-overridden-binding-2.stderr | 2 +- ...ync-block-control-flow-static-semantics.rs | 4 +- ...block-control-flow-static-semantics.stderr | 4 +- src/test/ui/hrtb/issue-62203-hrtb-ice.rs | 2 +- src/test/ui/hrtb/issue-62203-hrtb-ice.stderr | 2 +- src/test/ui/impl-trait/issues/issue-78722.rs | 2 +- .../ui/impl-trait/issues/issue-78722.stderr | 2 +- .../ui/intrinsics/const-eval-select-bad.rs | 2 +- .../intrinsics/const-eval-select-bad.stderr | 2 +- src/test/ui/issues/issue-31173.rs | 2 +- src/test/ui/issues/issue-31173.stderr | 2 +- src/test/ui/issues/issue-33941.rs | 6 +- src/test/ui/issues/issue-33941.stderr | 6 +- .../fallback-closure-wrap.fallback.stderr | 2 +- .../ui/never_type/fallback-closure-wrap.rs | 2 +- src/test/ui/traits/assoc-type-in-superbad.rs | 3 +- .../ui/traits/assoc-type-in-superbad.stderr | 2 +- .../ui/type-alias-impl-trait/issue-57961.rs | 2 +- .../type-alias-impl-trait/issue-57961.stderr | 2 +- .../ui/type-alias-impl-trait/issue-98604.rs | 2 +- .../type-alias-impl-trait/issue-98604.stderr | 2 +- .../ui/type-alias-impl-trait/issue-98608.rs | 2 +- .../type-alias-impl-trait/issue-98608.stderr | 2 +- 25 files changed, 80 insertions(+), 43 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index e442c5c9189..911fb094b0c 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1315,6 +1315,13 @@ trait InferCtxtPrivExt<'hir, 'tcx> { error: &MismatchedProjectionTypes<'tcx>, ); + fn maybe_detailed_projection_msg( + &self, + pred: ty::ProjectionPredicate<'tcx>, + normalized_ty: ty::Term<'tcx>, + expected_ty: ty::Term<'tcx>, + ) -> Option; + fn fuzzy_match_tys( &self, a: Ty<'tcx>, @@ -1542,23 +1549,19 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { normalized_ty, data.term, ) { - values = Some(infer::ValuePairs::Terms(ExpectedFound::new( - is_normalized_ty_expected, - normalized_ty, - data.term, - ))); + values = Some((data, is_normalized_ty_expected, normalized_ty, data.term)); err_buf = error; err = &err_buf; } } - let mut diag = struct_span_err!( - self.tcx.sess, - obligation.cause.span, - E0271, - "type mismatch resolving `{}`", - predicate - ); + let msg = values + .and_then(|(predicate, _, normalized_ty, expected_ty)| { + self.maybe_detailed_projection_msg(predicate, normalized_ty, expected_ty) + }) + .unwrap_or_else(|| format!("type mismatch resolving `{}`", predicate)); + let mut diag = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271, "{msg}"); + let secondary_span = match predicate.kind().skip_binder() { ty::PredicateKind::Projection(proj) => self .tcx @@ -1596,7 +1599,13 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { &mut diag, &obligation.cause, secondary_span, - values, + values.map(|(_, is_normalized_ty_expected, normalized_ty, term)| { + infer::ValuePairs::Terms(ExpectedFound::new( + is_normalized_ty_expected, + normalized_ty, + term, + )) + }), err, true, false, @@ -1606,6 +1615,33 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { }); } + fn maybe_detailed_projection_msg( + &self, + pred: ty::ProjectionPredicate<'tcx>, + normalized_ty: ty::Term<'tcx>, + expected_ty: ty::Term<'tcx>, + ) -> Option { + let trait_def_id = pred.projection_ty.trait_def_id(self.tcx); + let self_ty = pred.projection_ty.self_ty(); + + if Some(pred.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output() { + Some(format!( + "expected `{self_ty}` to be a {fn_kind} that returns `{expected_ty}`, but it actually returns `{normalized_ty}`", + fn_kind = self_ty.prefix_string(self.tcx) + )) + } else if Some(trait_def_id) == self.tcx.lang_items().future_trait() { + Some(format!( + "expected `{self_ty}` to be a future that yields `{expected_ty}`, but it actually yields `{normalized_ty}`" + )) + } else if Some(trait_def_id) == self.tcx.get_diagnostic_item(sym::Iterator) { + Some(format!( + "expected `{self_ty}` to be an iterator of `{expected_ty}`, but it actually returns items of `{normalized_ty}`" + )) + } else { + None + } + } + fn fuzzy_match_tys( &self, mut a: Ty<'tcx>, diff --git a/src/test/ui/associated-types/associated-types-overridden-binding-2.rs b/src/test/ui/associated-types/associated-types-overridden-binding-2.rs index 109feb8e969..525c4c81ed9 100644 --- a/src/test/ui/associated-types/associated-types-overridden-binding-2.rs +++ b/src/test/ui/associated-types/associated-types-overridden-binding-2.rs @@ -4,5 +4,5 @@ trait I32Iterator = Iterator; fn main() { let _: &dyn I32Iterator = &vec![42].into_iter(); - //~^ ERROR type mismatch + //~^ ERROR expected `std::vec::IntoIter` to be an iterator of `i32`, but it actually returns items of `u32` } diff --git a/src/test/ui/associated-types/associated-types-overridden-binding-2.stderr b/src/test/ui/associated-types/associated-types-overridden-binding-2.stderr index dbd9a44ed97..f7a1603844b 100644 --- a/src/test/ui/associated-types/associated-types-overridden-binding-2.stderr +++ b/src/test/ui/associated-types/associated-types-overridden-binding-2.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving ` as Iterator>::Item == i32` +error[E0271]: expected `std::vec::IntoIter` to be an iterator of `i32`, but it actually returns items of `u32` --> $DIR/associated-types-overridden-binding-2.rs:6:43 | LL | let _: &dyn I32Iterator = &vec![42].into_iter(); diff --git a/src/test/ui/async-await/async-block-control-flow-static-semantics.rs b/src/test/ui/async-await/async-block-control-flow-static-semantics.rs index b831d610232..3f8cb7a5291 100644 --- a/src/test/ui/async-await/async-block-control-flow-static-semantics.rs +++ b/src/test/ui/async-await/async-block-control-flow-static-semantics.rs @@ -15,7 +15,7 @@ fn return_targets_async_block_not_fn() -> u8 { return 0u8; }; let _: &dyn Future = █ - //~^ ERROR type mismatch + //~^ ERROR expected `impl Future` to be a future that yields `()`, but it actually yields `u8` } async fn return_targets_async_block_not_async_fn() -> u8 { @@ -24,7 +24,7 @@ async fn return_targets_async_block_not_async_fn() -> u8 { return 0u8; }; let _: &dyn Future = █ - //~^ ERROR type mismatch resolving ` as Future>::Output == ()` + //~^ ERROR expected `impl Future` to be a future that yields `()`, but it actually yields `u8` } fn no_break_in_async_block() { diff --git a/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr b/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr index e5887689690..3d9adc04e17 100644 --- a/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr +++ b/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr @@ -31,7 +31,7 @@ LL | | LL | | } | |_^ expected `u8`, found `()` -error[E0271]: type mismatch resolving ` as Future>::Output == ()` +error[E0271]: expected `impl Future` to be a future that yields `()`, but it actually yields `u8` --> $DIR/async-block-control-flow-static-semantics.rs:26:39 | LL | let _: &dyn Future = █ @@ -47,7 +47,7 @@ LL | fn return_targets_async_block_not_fn() -> u8 { | | | implicitly returns `()` as its body has no tail or `return` expression -error[E0271]: type mismatch resolving ` as Future>::Output == ()` +error[E0271]: expected `impl Future` to be a future that yields `()`, but it actually yields `u8` --> $DIR/async-block-control-flow-static-semantics.rs:17:39 | LL | let _: &dyn Future = █ diff --git a/src/test/ui/hrtb/issue-62203-hrtb-ice.rs b/src/test/ui/hrtb/issue-62203-hrtb-ice.rs index 80f099ce3c8..19d7ff804e4 100644 --- a/src/test/ui/hrtb/issue-62203-hrtb-ice.rs +++ b/src/test/ui/hrtb/issue-62203-hrtb-ice.rs @@ -38,7 +38,7 @@ fn main() { let v = Unit2.m( //~^ ERROR type mismatch L { - //~^ ERROR type mismatch + //~^ ERROR to be a closure that returns `Unit3`, but it actually returns `Unit4` f : |x| { drop(x); Unit4 } }); } diff --git a/src/test/ui/hrtb/issue-62203-hrtb-ice.stderr b/src/test/ui/hrtb/issue-62203-hrtb-ice.stderr index 79ef56b9fa5..e3055c1265e 100644 --- a/src/test/ui/hrtb/issue-62203-hrtb-ice.stderr +++ b/src/test/ui/hrtb/issue-62203-hrtb-ice.stderr @@ -22,7 +22,7 @@ LL | where LL | F: for<'r> T0<'r, (>::V,), O = >::V>, | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `T1::m` -error[E0271]: type mismatch resolving `for<'r> <[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:20] as FnOnce<((&'r u8,),)>>::Output == Unit3` +error[E0271]: expected `[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:20]` to be a closure that returns `Unit3`, but it actually returns `Unit4` --> $DIR/issue-62203-hrtb-ice.rs:40:9 | LL | let v = Unit2.m( diff --git a/src/test/ui/impl-trait/issues/issue-78722.rs b/src/test/ui/impl-trait/issues/issue-78722.rs index 002e4cde40a..2d2b8192adc 100644 --- a/src/test/ui/impl-trait/issues/issue-78722.rs +++ b/src/test/ui/impl-trait/issues/issue-78722.rs @@ -7,7 +7,7 @@ type F = impl core::future::Future; struct Bug { V1: [(); { fn concrete_use() -> F { - //~^ ERROR type mismatch + //~^ ERROR expected `impl Future` to be a future that yields `u8`, but it actually yields `()` async {} } let f: F = async { 1 }; diff --git a/src/test/ui/impl-trait/issues/issue-78722.stderr b/src/test/ui/impl-trait/issues/issue-78722.stderr index 690d6abc766..f98655e9dff 100644 --- a/src/test/ui/impl-trait/issues/issue-78722.stderr +++ b/src/test/ui/impl-trait/issues/issue-78722.stderr @@ -16,7 +16,7 @@ LL | let f: F = async { 1 }; LL | }], | - value is dropped here -error[E0271]: type mismatch resolving ` as Future>::Output == u8` +error[E0271]: expected `impl Future` to be a future that yields `u8`, but it actually yields `()` --> $DIR/issue-78722.rs:9:30 | LL | fn concrete_use() -> F { diff --git a/src/test/ui/intrinsics/const-eval-select-bad.rs b/src/test/ui/intrinsics/const-eval-select-bad.rs index 52f4e594f1a..23b3f4fd825 100644 --- a/src/test/ui/intrinsics/const-eval-select-bad.rs +++ b/src/test/ui/intrinsics/const-eval-select-bad.rs @@ -27,7 +27,7 @@ fn baz(n: bool) -> i32 { const fn return_ty_mismatch() { const_eval_select((1,), foo, bar); - //~^ ERROR type mismatch + //~^ ERROR expected `fn(i32) -> bool {bar}` to be a fn item that returns `i32`, but it actually returns `bool` } const fn args_ty_mismatch() { diff --git a/src/test/ui/intrinsics/const-eval-select-bad.stderr b/src/test/ui/intrinsics/const-eval-select-bad.stderr index 89dba12c818..efdb5c86508 100644 --- a/src/test/ui/intrinsics/const-eval-select-bad.stderr +++ b/src/test/ui/intrinsics/const-eval-select-bad.stderr @@ -51,7 +51,7 @@ note: required by a bound in `const_eval_select` LL | G: FnOnce + ~const Destruct, | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select` -error[E0271]: type mismatch resolving ` bool {bar} as FnOnce<(i32,)>>::Output == i32` +error[E0271]: expected `fn(i32) -> bool {bar}` to be a fn item that returns `i32`, but it actually returns `bool` --> $DIR/const-eval-select-bad.rs:29:5 | LL | const_eval_select((1,), foo, bar); diff --git a/src/test/ui/issues/issue-31173.rs b/src/test/ui/issues/issue-31173.rs index 48061ae54ae..04e19c41756 100644 --- a/src/test/ui/issues/issue-31173.rs +++ b/src/test/ui/issues/issue-31173.rs @@ -8,7 +8,7 @@ pub fn get_tok(it: &mut IntoIter) { false }) .cloned() - //~^ ERROR type mismatch resolving + //~^ ERROR to be an iterator of `&_`, but it actually returns items of `u8` .collect(); //~ ERROR the method } diff --git a/src/test/ui/issues/issue-31173.stderr b/src/test/ui/issues/issue-31173.stderr index 68337a715e1..43011d0d355 100644 --- a/src/test/ui/issues/issue-31173.stderr +++ b/src/test/ui/issues/issue-31173.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving `, [closure@$DIR/issue-31173.rs:6:39: 6:43]> as Iterator>::Item == &_` +error[E0271]: expected `TakeWhile<&mut std::vec::IntoIter, [closure@$DIR/issue-31173.rs:6:39: 6:43]>` to be an iterator of `&_`, but it actually returns items of `u8` --> $DIR/issue-31173.rs:10:10 | LL | .cloned() diff --git a/src/test/ui/issues/issue-33941.rs b/src/test/ui/issues/issue-33941.rs index a1213623e6f..906f77559b4 100644 --- a/src/test/ui/issues/issue-33941.rs +++ b/src/test/ui/issues/issue-33941.rs @@ -3,7 +3,7 @@ use std::collections::HashMap; fn main() { - for _ in HashMap::new().iter().cloned() {} //~ ERROR type mismatch - //~^ ERROR type mismatch - //~| ERROR type mismatch + for _ in HashMap::new().iter().cloned() {} //~ ERROR expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator of `&_`, but it actually returns items of `(&_, &_)` + //~^ ERROR expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator of `&_`, but it actually returns items of `(&_, &_)` + //~| ERROR expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator of `&_`, but it actually returns items of `(&_, &_)` } diff --git a/src/test/ui/issues/issue-33941.stderr b/src/test/ui/issues/issue-33941.stderr index e1ce6eed98e..750f14c8239 100644 --- a/src/test/ui/issues/issue-33941.stderr +++ b/src/test/ui/issues/issue-33941.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving ` as Iterator>::Item == &_` +error[E0271]: expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator of `&_`, but it actually returns items of `(&_, &_)` --> $DIR/issue-33941.rs:6:36 | LL | for _ in HashMap::new().iter().cloned() {} @@ -12,7 +12,7 @@ note: required by a bound in `cloned` LL | Self: Sized + Iterator, | ^^^^^^^^^^^^ required by this bound in `cloned` -error[E0271]: type mismatch resolving ` as Iterator>::Item == &_` +error[E0271]: expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator of `&_`, but it actually returns items of `(&_, &_)` --> $DIR/issue-33941.rs:6:14 | LL | for _ in HashMap::new().iter().cloned() {} @@ -23,7 +23,7 @@ LL | for _ in HashMap::new().iter().cloned() {} = note: required because of the requirements on the impl of `Iterator` for `Cloned>` = note: required because of the requirements on the impl of `IntoIterator` for `Cloned>` -error[E0271]: type mismatch resolving ` as Iterator>::Item == &_` +error[E0271]: expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator of `&_`, but it actually returns items of `(&_, &_)` --> $DIR/issue-33941.rs:6:14 | LL | for _ in HashMap::new().iter().cloned() {} diff --git a/src/test/ui/never_type/fallback-closure-wrap.fallback.stderr b/src/test/ui/never_type/fallback-closure-wrap.fallback.stderr index 2acf44432c6..e1b6fee2ccc 100644 --- a/src/test/ui/never_type/fallback-closure-wrap.fallback.stderr +++ b/src/test/ui/never_type/fallback-closure-wrap.fallback.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving `<[closure@$DIR/fallback-closure-wrap.rs:18:40: 18:47] as FnOnce<()>>::Output == ()` +error[E0271]: expected `[closure@$DIR/fallback-closure-wrap.rs:18:40: 18:47]` to be a closure that returns `()`, but it actually returns `!` --> $DIR/fallback-closure-wrap.rs:18:31 | LL | let error = Closure::wrap(Box::new(move || { diff --git a/src/test/ui/never_type/fallback-closure-wrap.rs b/src/test/ui/never_type/fallback-closure-wrap.rs index af0577ac060..e9c343efb66 100644 --- a/src/test/ui/never_type/fallback-closure-wrap.rs +++ b/src/test/ui/never_type/fallback-closure-wrap.rs @@ -16,7 +16,7 @@ use std::marker::PhantomData; fn main() { let error = Closure::wrap(Box::new(move || { - //[fallback]~^ ERROR type mismatch resolving + //[fallback]~^ to be a closure that returns `()`, but it actually returns `!` panic!("Can't connect to server."); }) as Box); } diff --git a/src/test/ui/traits/assoc-type-in-superbad.rs b/src/test/ui/traits/assoc-type-in-superbad.rs index 579ce7cf706..925f84db37a 100644 --- a/src/test/ui/traits/assoc-type-in-superbad.rs +++ b/src/test/ui/traits/assoc-type-in-superbad.rs @@ -9,7 +9,8 @@ pub trait Foo: Iterator::Key> { } impl Foo for IntoIter { - type Key = u32; //~ ERROR type mismatch + type Key = u32; + //~^ ERROR expected `std::vec::IntoIter` to be an iterator of `u32`, but it actually returns items of `i32` } fn main() { diff --git a/src/test/ui/traits/assoc-type-in-superbad.stderr b/src/test/ui/traits/assoc-type-in-superbad.stderr index f3694791417..db691210b9c 100644 --- a/src/test/ui/traits/assoc-type-in-superbad.stderr +++ b/src/test/ui/traits/assoc-type-in-superbad.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving ` as Iterator>::Item == u32` +error[E0271]: expected `std::vec::IntoIter` to be an iterator of `u32`, but it actually returns items of `i32` --> $DIR/assoc-type-in-superbad.rs:12:16 | LL | type Key = u32; diff --git a/src/test/ui/type-alias-impl-trait/issue-57961.rs b/src/test/ui/type-alias-impl-trait/issue-57961.rs index 472886c9caa..639f3b72165 100644 --- a/src/test/ui/type-alias-impl-trait/issue-57961.rs +++ b/src/test/ui/type-alias-impl-trait/issue-57961.rs @@ -8,7 +8,7 @@ trait Foo { impl Foo for () { type Bar = std::vec::IntoIter; - //~^ ERROR type mismatch resolving ` as Iterator>::Item == X + //~^ ERROR expected `std::vec::IntoIter` to be an iterator of `X`, but it actually returns items of `u32` } fn incoherent() { diff --git a/src/test/ui/type-alias-impl-trait/issue-57961.stderr b/src/test/ui/type-alias-impl-trait/issue-57961.stderr index ed4caf6ce68..907f10cc9a5 100644 --- a/src/test/ui/type-alias-impl-trait/issue-57961.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-57961.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving ` as Iterator>::Item == X` +error[E0271]: expected `std::vec::IntoIter` to be an iterator of `X`, but it actually returns items of `u32` --> $DIR/issue-57961.rs:10:16 | LL | type X = impl Sized; diff --git a/src/test/ui/type-alias-impl-trait/issue-98604.rs b/src/test/ui/type-alias-impl-trait/issue-98604.rs index a4fd8a82a04..a2f29afd94c 100644 --- a/src/test/ui/type-alias-impl-trait/issue-98604.rs +++ b/src/test/ui/type-alias-impl-trait/issue-98604.rs @@ -9,5 +9,5 @@ async fn test() {} #[allow(unused_must_use)] fn main() { Box::new(test) as AsyncFnPtr; - //~^ ERROR type mismatch + //~^ ERROR expected `fn() -> impl Future {test}` to be a fn item that returns `Pin + 'static)>>`, but it actually returns `impl Future` } diff --git a/src/test/ui/type-alias-impl-trait/issue-98604.stderr b/src/test/ui/type-alias-impl-trait/issue-98604.stderr index f04d1b4d787..5c8aae0da2e 100644 --- a/src/test/ui/type-alias-impl-trait/issue-98604.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-98604.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving ` impl Future {test} as FnOnce<()>>::Output == Pin + 'static)>>` +error[E0271]: expected `fn() -> impl Future {test}` to be a fn item that returns `Pin + 'static)>>`, but it actually returns `impl Future` --> $DIR/issue-98604.rs:11:5 | LL | Box::new(test) as AsyncFnPtr; diff --git a/src/test/ui/type-alias-impl-trait/issue-98608.rs b/src/test/ui/type-alias-impl-trait/issue-98608.rs index d75762a8b62..2f4cf7a0521 100644 --- a/src/test/ui/type-alias-impl-trait/issue-98608.rs +++ b/src/test/ui/type-alias-impl-trait/issue-98608.rs @@ -2,7 +2,7 @@ fn hi() -> impl Sized { std::ptr::null::() } fn main() { let b: Box Box> = Box::new(hi); - //~^ ERROR type mismatch resolving ` impl Sized {hi} as FnOnce<()>>::Output == Box` + //~^ ERROR expected `fn() -> impl Sized {hi}` to be a fn item that returns `Box`, but it actually returns `impl Sized` let boxed = b(); let null = *boxed; println!("{null:?}"); diff --git a/src/test/ui/type-alias-impl-trait/issue-98608.stderr b/src/test/ui/type-alias-impl-trait/issue-98608.stderr index 8f3ec7d9d16..c5eed7561c0 100644 --- a/src/test/ui/type-alias-impl-trait/issue-98608.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-98608.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving ` impl Sized {hi} as FnOnce<()>>::Output == Box` +error[E0271]: expected `fn() -> impl Sized {hi}` to be a fn item that returns `Box`, but it actually returns `impl Sized` --> $DIR/issue-98608.rs:4:39 | LL | fn hi() -> impl Sized { std::ptr::null::() } From 3fdf3cb80cc262e71461b6809b0e320a1958b03c Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 8 Aug 2022 00:13:41 +0000 Subject: [PATCH 69/77] Adjust wording --- .../src/traits/error_reporting/mod.rs | 6 +++--- .../associated-types-overridden-binding-2.rs | 2 +- ...ssociated-types-overridden-binding-2.stderr | 2 +- ...sync-block-control-flow-static-semantics.rs | 8 +++++--- ...-block-control-flow-static-semantics.stderr | 8 ++++---- src/test/ui/hrtb/issue-62203-hrtb-ice.rs | 10 +++++++--- src/test/ui/hrtb/issue-62203-hrtb-ice.stderr | 15 +++++++++------ src/test/ui/impl-trait/issues/issue-78722.rs | 2 +- .../ui/impl-trait/issues/issue-78722.stderr | 2 +- .../ui/intrinsics/const-eval-select-bad.rs | 2 +- .../ui/intrinsics/const-eval-select-bad.stderr | 2 +- src/test/ui/issues/issue-31173.rs | 11 ++++++----- src/test/ui/issues/issue-31173.stderr | 18 +++++++++--------- src/test/ui/issues/issue-33941.rs | 6 +++--- src/test/ui/issues/issue-33941.stderr | 6 +++--- .../fallback-closure-wrap.fallback.stderr | 2 +- .../ui/never_type/fallback-closure-wrap.rs | 2 +- src/test/ui/traits/assoc-type-in-superbad.rs | 7 +++---- .../ui/traits/assoc-type-in-superbad.stderr | 6 +++--- .../ui/type-alias-impl-trait/issue-57961.rs | 2 +- .../type-alias-impl-trait/issue-57961.stderr | 2 +- .../ui/type-alias-impl-trait/issue-98604.rs | 6 ++---- .../type-alias-impl-trait/issue-98604.stderr | 6 +++--- .../ui/type-alias-impl-trait/issue-98608.rs | 6 ++++-- .../type-alias-impl-trait/issue-98608.stderr | 6 +++--- 25 files changed, 77 insertions(+), 68 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 911fb094b0c..e4f918b4b0e 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1626,16 +1626,16 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { if Some(pred.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output() { Some(format!( - "expected `{self_ty}` to be a {fn_kind} that returns `{expected_ty}`, but it actually returns `{normalized_ty}`", + "expected `{self_ty}` to be a {fn_kind} that returns `{expected_ty}`, but it returns `{normalized_ty}`", fn_kind = self_ty.prefix_string(self.tcx) )) } else if Some(trait_def_id) == self.tcx.lang_items().future_trait() { Some(format!( - "expected `{self_ty}` to be a future that yields `{expected_ty}`, but it actually yields `{normalized_ty}`" + "expected `{self_ty}` to be a future that resolves to `{expected_ty}`, but it resolves to `{normalized_ty}`" )) } else if Some(trait_def_id) == self.tcx.get_diagnostic_item(sym::Iterator) { Some(format!( - "expected `{self_ty}` to be an iterator of `{expected_ty}`, but it actually returns items of `{normalized_ty}`" + "expected `{self_ty}` to be an iterator that yields `{expected_ty}`, but it yields `{normalized_ty}`" )) } else { None diff --git a/src/test/ui/associated-types/associated-types-overridden-binding-2.rs b/src/test/ui/associated-types/associated-types-overridden-binding-2.rs index 525c4c81ed9..26b9f4b3a92 100644 --- a/src/test/ui/associated-types/associated-types-overridden-binding-2.rs +++ b/src/test/ui/associated-types/associated-types-overridden-binding-2.rs @@ -4,5 +4,5 @@ trait I32Iterator = Iterator; fn main() { let _: &dyn I32Iterator = &vec![42].into_iter(); - //~^ ERROR expected `std::vec::IntoIter` to be an iterator of `i32`, but it actually returns items of `u32` + //~^ ERROR expected `std::vec::IntoIter` to be an iterator that yields `i32`, but it yields `u32` } diff --git a/src/test/ui/associated-types/associated-types-overridden-binding-2.stderr b/src/test/ui/associated-types/associated-types-overridden-binding-2.stderr index f7a1603844b..2d25f68de44 100644 --- a/src/test/ui/associated-types/associated-types-overridden-binding-2.stderr +++ b/src/test/ui/associated-types/associated-types-overridden-binding-2.stderr @@ -1,4 +1,4 @@ -error[E0271]: expected `std::vec::IntoIter` to be an iterator of `i32`, but it actually returns items of `u32` +error[E0271]: expected `std::vec::IntoIter` to be an iterator that yields `i32`, but it yields `u32` --> $DIR/associated-types-overridden-binding-2.rs:6:43 | LL | let _: &dyn I32Iterator = &vec![42].into_iter(); diff --git a/src/test/ui/async-await/async-block-control-flow-static-semantics.rs b/src/test/ui/async-await/async-block-control-flow-static-semantics.rs index 3f8cb7a5291..446212ca767 100644 --- a/src/test/ui/async-await/async-block-control-flow-static-semantics.rs +++ b/src/test/ui/async-await/async-block-control-flow-static-semantics.rs @@ -15,7 +15,7 @@ fn return_targets_async_block_not_fn() -> u8 { return 0u8; }; let _: &dyn Future = █ - //~^ ERROR expected `impl Future` to be a future that yields `()`, but it actually yields `u8` + //~^ ERROR expected `impl Future` to be a future that resolves to `()`, but it resolves to `u8` } async fn return_targets_async_block_not_async_fn() -> u8 { @@ -24,7 +24,7 @@ async fn return_targets_async_block_not_async_fn() -> u8 { return 0u8; }; let _: &dyn Future = █ - //~^ ERROR expected `impl Future` to be a future that yields `()`, but it actually yields `u8` + //~^ ERROR expected `impl Future` to be a future that resolves to `()`, but it resolves to `u8` } fn no_break_in_async_block() { @@ -42,7 +42,9 @@ fn no_break_in_async_block_even_with_outer_loop() { } struct MyErr; -fn err() -> Result { Err(MyErr) } +fn err() -> Result { + Err(MyErr) +} fn rethrow_targets_async_block_not_fn() -> Result { //~^ ERROR mismatched types diff --git a/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr b/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr index 3d9adc04e17..2a08d5d6ce5 100644 --- a/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr +++ b/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr @@ -31,7 +31,7 @@ LL | | LL | | } | |_^ expected `u8`, found `()` -error[E0271]: expected `impl Future` to be a future that yields `()`, but it actually yields `u8` +error[E0271]: expected `impl Future` to be a future that resolves to `()`, but it resolves to `u8` --> $DIR/async-block-control-flow-static-semantics.rs:26:39 | LL | let _: &dyn Future = █ @@ -47,7 +47,7 @@ LL | fn return_targets_async_block_not_fn() -> u8 { | | | implicitly returns `()` as its body has no tail or `return` expression -error[E0271]: expected `impl Future` to be a future that yields `()`, but it actually yields `u8` +error[E0271]: expected `impl Future` to be a future that resolves to `()`, but it resolves to `u8` --> $DIR/async-block-control-flow-static-semantics.rs:17:39 | LL | let _: &dyn Future = █ @@ -56,7 +56,7 @@ LL | let _: &dyn Future = █ = note: required for the cast from `impl Future` to the object type `dyn Future` error[E0308]: mismatched types - --> $DIR/async-block-control-flow-static-semantics.rs:47:44 + --> $DIR/async-block-control-flow-static-semantics.rs:49:44 | LL | fn rethrow_targets_async_block_not_fn() -> Result { | ---------------------------------- ^^^^^^^^^^^^^^^^^ expected enum `Result`, found `()` @@ -67,7 +67,7 @@ LL | fn rethrow_targets_async_block_not_fn() -> Result { found unit type `()` error[E0308]: mismatched types - --> $DIR/async-block-control-flow-static-semantics.rs:56:50 + --> $DIR/async-block-control-flow-static-semantics.rs:58:50 | LL | fn rethrow_targets_async_block_not_async_fn() -> Result { | ---------------------------------------- ^^^^^^^^^^^^^^^^^ expected enum `Result`, found `()` diff --git a/src/test/ui/hrtb/issue-62203-hrtb-ice.rs b/src/test/ui/hrtb/issue-62203-hrtb-ice.rs index 19d7ff804e4..ae21dbce011 100644 --- a/src/test/ui/hrtb/issue-62203-hrtb-ice.rs +++ b/src/test/ui/hrtb/issue-62203-hrtb-ice.rs @@ -38,9 +38,13 @@ fn main() { let v = Unit2.m( //~^ ERROR type mismatch L { - //~^ ERROR to be a closure that returns `Unit3`, but it actually returns `Unit4` - f : |x| { drop(x); Unit4 } - }); + //~^ ERROR to be a closure that returns `Unit3`, but it returns `Unit4` + f: |x| { + drop(x); + Unit4 + }, + }, + ); } impl<'a> Ty<'a> for Unit2 { diff --git a/src/test/ui/hrtb/issue-62203-hrtb-ice.stderr b/src/test/ui/hrtb/issue-62203-hrtb-ice.stderr index e3055c1265e..8365fd0c79e 100644 --- a/src/test/ui/hrtb/issue-62203-hrtb-ice.stderr +++ b/src/test/ui/hrtb/issue-62203-hrtb-ice.stderr @@ -1,8 +1,8 @@ -error[E0271]: type mismatch resolving `for<'r> as T0<'r, (&'r u8,)>>::O == <_ as Ty<'r>>::V` +error[E0271]: type mismatch resolving `for<'r> as T0<'r, (&'r u8,)>>::O == <_ as Ty<'r>>::V` --> $DIR/issue-62203-hrtb-ice.rs:38:19 | LL | let v = Unit2.m( - | ^ type mismatch resolving `for<'r> as T0<'r, (&'r u8,)>>::O == <_ as Ty<'r>>::V` + | ^ type mismatch resolving `for<'r> as T0<'r, (&'r u8,)>>::O == <_ as Ty<'r>>::V` | note: expected this to be `<_ as Ty<'_>>::V` --> $DIR/issue-62203-hrtb-ice.rs:21:14 @@ -22,7 +22,7 @@ LL | where LL | F: for<'r> T0<'r, (>::V,), O = >::V>, | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `T1::m` -error[E0271]: expected `[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:20]` to be a closure that returns `Unit3`, but it actually returns `Unit4` +error[E0271]: expected `[closure@$DIR/issue-62203-hrtb-ice.rs:42:16: 42:19]` to be a closure that returns `Unit3`, but it returns `Unit4` --> $DIR/issue-62203-hrtb-ice.rs:40:9 | LL | let v = Unit2.m( @@ -30,11 +30,14 @@ LL | let v = Unit2.m( LL | LL | / L { LL | | -LL | | f : |x| { drop(x); Unit4 } -LL | | }); +LL | | f: |x| { +LL | | drop(x); +LL | | Unit4 +LL | | }, +LL | | }, | |_________^ expected struct `Unit3`, found struct `Unit4` | -note: required because of the requirements on the impl of `for<'r> T0<'r, (&'r u8,)>` for `L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:20]>` +note: required because of the requirements on the impl of `for<'r> T0<'r, (&'r u8,)>` for `L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:16: 42:19]>` --> $DIR/issue-62203-hrtb-ice.rs:17:16 | LL | impl<'a, A, T> T0<'a, A> for L diff --git a/src/test/ui/impl-trait/issues/issue-78722.rs b/src/test/ui/impl-trait/issues/issue-78722.rs index 2d2b8192adc..90d1cd3798a 100644 --- a/src/test/ui/impl-trait/issues/issue-78722.rs +++ b/src/test/ui/impl-trait/issues/issue-78722.rs @@ -7,7 +7,7 @@ type F = impl core::future::Future; struct Bug { V1: [(); { fn concrete_use() -> F { - //~^ ERROR expected `impl Future` to be a future that yields `u8`, but it actually yields `()` + //~^ ERROR expected `impl Future` to be a future that resolves to `u8`, but it resolves to `()` async {} } let f: F = async { 1 }; diff --git a/src/test/ui/impl-trait/issues/issue-78722.stderr b/src/test/ui/impl-trait/issues/issue-78722.stderr index f98655e9dff..9a0ffbc89d9 100644 --- a/src/test/ui/impl-trait/issues/issue-78722.stderr +++ b/src/test/ui/impl-trait/issues/issue-78722.stderr @@ -16,7 +16,7 @@ LL | let f: F = async { 1 }; LL | }], | - value is dropped here -error[E0271]: expected `impl Future` to be a future that yields `u8`, but it actually yields `()` +error[E0271]: expected `impl Future` to be a future that resolves to `u8`, but it resolves to `()` --> $DIR/issue-78722.rs:9:30 | LL | fn concrete_use() -> F { diff --git a/src/test/ui/intrinsics/const-eval-select-bad.rs b/src/test/ui/intrinsics/const-eval-select-bad.rs index 23b3f4fd825..e5640f5ab53 100644 --- a/src/test/ui/intrinsics/const-eval-select-bad.rs +++ b/src/test/ui/intrinsics/const-eval-select-bad.rs @@ -27,7 +27,7 @@ fn baz(n: bool) -> i32 { const fn return_ty_mismatch() { const_eval_select((1,), foo, bar); - //~^ ERROR expected `fn(i32) -> bool {bar}` to be a fn item that returns `i32`, but it actually returns `bool` + //~^ ERROR expected `fn(i32) -> bool {bar}` to be a fn item that returns `i32`, but it returns `bool` } const fn args_ty_mismatch() { diff --git a/src/test/ui/intrinsics/const-eval-select-bad.stderr b/src/test/ui/intrinsics/const-eval-select-bad.stderr index efdb5c86508..e7b7e4a4a91 100644 --- a/src/test/ui/intrinsics/const-eval-select-bad.stderr +++ b/src/test/ui/intrinsics/const-eval-select-bad.stderr @@ -51,7 +51,7 @@ note: required by a bound in `const_eval_select` LL | G: FnOnce + ~const Destruct, | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select` -error[E0271]: expected `fn(i32) -> bool {bar}` to be a fn item that returns `i32`, but it actually returns `bool` +error[E0271]: expected `fn(i32) -> bool {bar}` to be a fn item that returns `i32`, but it returns `bool` --> $DIR/const-eval-select-bad.rs:29:5 | LL | const_eval_select((1,), foo, bar); diff --git a/src/test/ui/issues/issue-31173.rs b/src/test/ui/issues/issue-31173.rs index 04e19c41756..472a95d4636 100644 --- a/src/test/ui/issues/issue-31173.rs +++ b/src/test/ui/issues/issue-31173.rs @@ -3,12 +3,13 @@ use std::vec::IntoIter; pub fn get_tok(it: &mut IntoIter) { let mut found_e = false; - let temp: Vec = it.take_while(|&x| { - found_e = true; - false - }) + let temp: Vec = it + .take_while(|&x| { + found_e = true; + false + }) .cloned() - //~^ ERROR to be an iterator of `&_`, but it actually returns items of `u8` + //~^ ERROR to be an iterator that yields `&_`, but it yields `u8` .collect(); //~ ERROR the method } diff --git a/src/test/ui/issues/issue-31173.stderr b/src/test/ui/issues/issue-31173.stderr index 43011d0d355..e89105540df 100644 --- a/src/test/ui/issues/issue-31173.stderr +++ b/src/test/ui/issues/issue-31173.stderr @@ -1,5 +1,5 @@ -error[E0271]: expected `TakeWhile<&mut std::vec::IntoIter, [closure@$DIR/issue-31173.rs:6:39: 6:43]>` to be an iterator of `&_`, but it actually returns items of `u8` - --> $DIR/issue-31173.rs:10:10 +error[E0271]: expected `TakeWhile<&mut std::vec::IntoIter, [closure@$DIR/issue-31173.rs:7:21: 7:25]>` to be an iterator that yields `&_`, but it yields `u8` + --> $DIR/issue-31173.rs:11:10 | LL | .cloned() | ^^^^^^ expected reference, found `u8` @@ -12,11 +12,11 @@ note: required by a bound in `cloned` LL | Self: Sized + Iterator, | ^^^^^^^^^^^^ required by this bound in `cloned` -error[E0599]: the method `collect` exists for struct `Cloned, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>`, but its trait bounds were not satisfied - --> $DIR/issue-31173.rs:12:10 +error[E0599]: the method `collect` exists for struct `Cloned, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>`, but its trait bounds were not satisfied + --> $DIR/issue-31173.rs:13:10 | LL | .collect(); - | ^^^^^^^ method cannot be called on `Cloned, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>` due to unsatisfied trait bounds + | ^^^^^^^ method cannot be called on `Cloned, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>` due to unsatisfied trait bounds | ::: $SRC_DIR/core/src/iter/adapters/cloned.rs:LL:COL | @@ -29,10 +29,10 @@ LL | pub struct TakeWhile { | -------------------------- doesn't satisfy `<_ as Iterator>::Item = &_` | = note: the following trait bounds were not satisfied: - `, [closure@$DIR/issue-31173.rs:6:39: 6:43]> as Iterator>::Item = &_` - which is required by `Cloned, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>: Iterator` - `Cloned, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>: Iterator` - which is required by `&mut Cloned, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>: Iterator` + `, [closure@$DIR/issue-31173.rs:7:21: 7:25]> as Iterator>::Item = &_` + which is required by `Cloned, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>: Iterator` + `Cloned, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>: Iterator` + which is required by `&mut Cloned, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>: Iterator` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-33941.rs b/src/test/ui/issues/issue-33941.rs index 906f77559b4..8430e85df87 100644 --- a/src/test/ui/issues/issue-33941.rs +++ b/src/test/ui/issues/issue-33941.rs @@ -3,7 +3,7 @@ use std::collections::HashMap; fn main() { - for _ in HashMap::new().iter().cloned() {} //~ ERROR expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator of `&_`, but it actually returns items of `(&_, &_)` - //~^ ERROR expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator of `&_`, but it actually returns items of `(&_, &_)` - //~| ERROR expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator of `&_`, but it actually returns items of `(&_, &_)` + for _ in HashMap::new().iter().cloned() {} //~ ERROR expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)` + //~^ ERROR expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)` + //~| ERROR expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)` } diff --git a/src/test/ui/issues/issue-33941.stderr b/src/test/ui/issues/issue-33941.stderr index 750f14c8239..565a7fef379 100644 --- a/src/test/ui/issues/issue-33941.stderr +++ b/src/test/ui/issues/issue-33941.stderr @@ -1,4 +1,4 @@ -error[E0271]: expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator of `&_`, but it actually returns items of `(&_, &_)` +error[E0271]: expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)` --> $DIR/issue-33941.rs:6:36 | LL | for _ in HashMap::new().iter().cloned() {} @@ -12,7 +12,7 @@ note: required by a bound in `cloned` LL | Self: Sized + Iterator, | ^^^^^^^^^^^^ required by this bound in `cloned` -error[E0271]: expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator of `&_`, but it actually returns items of `(&_, &_)` +error[E0271]: expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)` --> $DIR/issue-33941.rs:6:14 | LL | for _ in HashMap::new().iter().cloned() {} @@ -23,7 +23,7 @@ LL | for _ in HashMap::new().iter().cloned() {} = note: required because of the requirements on the impl of `Iterator` for `Cloned>` = note: required because of the requirements on the impl of `IntoIterator` for `Cloned>` -error[E0271]: expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator of `&_`, but it actually returns items of `(&_, &_)` +error[E0271]: expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)` --> $DIR/issue-33941.rs:6:14 | LL | for _ in HashMap::new().iter().cloned() {} diff --git a/src/test/ui/never_type/fallback-closure-wrap.fallback.stderr b/src/test/ui/never_type/fallback-closure-wrap.fallback.stderr index e1b6fee2ccc..45cf3723483 100644 --- a/src/test/ui/never_type/fallback-closure-wrap.fallback.stderr +++ b/src/test/ui/never_type/fallback-closure-wrap.fallback.stderr @@ -1,4 +1,4 @@ -error[E0271]: expected `[closure@$DIR/fallback-closure-wrap.rs:18:40: 18:47]` to be a closure that returns `()`, but it actually returns `!` +error[E0271]: expected `[closure@$DIR/fallback-closure-wrap.rs:18:40: 18:47]` to be a closure that returns `()`, but it returns `!` --> $DIR/fallback-closure-wrap.rs:18:31 | LL | let error = Closure::wrap(Box::new(move || { diff --git a/src/test/ui/never_type/fallback-closure-wrap.rs b/src/test/ui/never_type/fallback-closure-wrap.rs index e9c343efb66..35052da6760 100644 --- a/src/test/ui/never_type/fallback-closure-wrap.rs +++ b/src/test/ui/never_type/fallback-closure-wrap.rs @@ -16,7 +16,7 @@ use std::marker::PhantomData; fn main() { let error = Closure::wrap(Box::new(move || { - //[fallback]~^ to be a closure that returns `()`, but it actually returns `!` + //[fallback]~^ to be a closure that returns `()`, but it returns `!` panic!("Can't connect to server."); }) as Box); } diff --git a/src/test/ui/traits/assoc-type-in-superbad.rs b/src/test/ui/traits/assoc-type-in-superbad.rs index 925f84db37a..d7d6241ef70 100644 --- a/src/test/ui/traits/assoc-type-in-superbad.rs +++ b/src/test/ui/traits/assoc-type-in-superbad.rs @@ -4,14 +4,13 @@ use std::vec::IntoIter; -pub trait Foo: Iterator::Key> { +pub trait Foo: Iterator::Key> { type Key; } impl Foo for IntoIter { type Key = u32; - //~^ ERROR expected `std::vec::IntoIter` to be an iterator of `u32`, but it actually returns items of `i32` + //~^ ERROR expected `std::vec::IntoIter` to be an iterator that yields `u32`, but it yields `i32` } -fn main() { -} +fn main() {} diff --git a/src/test/ui/traits/assoc-type-in-superbad.stderr b/src/test/ui/traits/assoc-type-in-superbad.stderr index db691210b9c..3e2d9d9038a 100644 --- a/src/test/ui/traits/assoc-type-in-superbad.stderr +++ b/src/test/ui/traits/assoc-type-in-superbad.stderr @@ -1,4 +1,4 @@ -error[E0271]: expected `std::vec::IntoIter` to be an iterator of `u32`, but it actually returns items of `i32` +error[E0271]: expected `std::vec::IntoIter` to be an iterator that yields `u32`, but it yields `i32` --> $DIR/assoc-type-in-superbad.rs:12:16 | LL | type Key = u32; @@ -7,8 +7,8 @@ LL | type Key = u32; note: required by a bound in `Foo` --> $DIR/assoc-type-in-superbad.rs:7:25 | -LL | pub trait Foo: Iterator::Key> { - | ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo` +LL | pub trait Foo: Iterator::Key> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo` error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/issue-57961.rs b/src/test/ui/type-alias-impl-trait/issue-57961.rs index 639f3b72165..24b3a045856 100644 --- a/src/test/ui/type-alias-impl-trait/issue-57961.rs +++ b/src/test/ui/type-alias-impl-trait/issue-57961.rs @@ -8,7 +8,7 @@ trait Foo { impl Foo for () { type Bar = std::vec::IntoIter; - //~^ ERROR expected `std::vec::IntoIter` to be an iterator of `X`, but it actually returns items of `u32` + //~^ ERROR expected `std::vec::IntoIter` to be an iterator that yields `X`, but it yields `u32` } fn incoherent() { diff --git a/src/test/ui/type-alias-impl-trait/issue-57961.stderr b/src/test/ui/type-alias-impl-trait/issue-57961.stderr index 907f10cc9a5..fb40895c49f 100644 --- a/src/test/ui/type-alias-impl-trait/issue-57961.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-57961.stderr @@ -1,4 +1,4 @@ -error[E0271]: expected `std::vec::IntoIter` to be an iterator of `X`, but it actually returns items of `u32` +error[E0271]: expected `std::vec::IntoIter` to be an iterator that yields `X`, but it yields `u32` --> $DIR/issue-57961.rs:10:16 | LL | type X = impl Sized; diff --git a/src/test/ui/type-alias-impl-trait/issue-98604.rs b/src/test/ui/type-alias-impl-trait/issue-98604.rs index a2f29afd94c..32c2f9ed51e 100644 --- a/src/test/ui/type-alias-impl-trait/issue-98604.rs +++ b/src/test/ui/type-alias-impl-trait/issue-98604.rs @@ -1,13 +1,11 @@ // edition:2018 -type AsyncFnPtr = Box< - dyn Fn() -> std::pin::Pin>>, ->; +type AsyncFnPtr = Box std::pin::Pin>>>; async fn test() {} #[allow(unused_must_use)] fn main() { Box::new(test) as AsyncFnPtr; - //~^ ERROR expected `fn() -> impl Future {test}` to be a fn item that returns `Pin + 'static)>>`, but it actually returns `impl Future` + //~^ ERROR expected `fn() -> impl Future {test}` to be a fn item that returns `Pin + 'static)>>`, but it returns `impl Future` } diff --git a/src/test/ui/type-alias-impl-trait/issue-98604.stderr b/src/test/ui/type-alias-impl-trait/issue-98604.stderr index 5c8aae0da2e..92d01eb0d3d 100644 --- a/src/test/ui/type-alias-impl-trait/issue-98604.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-98604.stderr @@ -1,11 +1,11 @@ -error[E0271]: expected `fn() -> impl Future {test}` to be a fn item that returns `Pin + 'static)>>`, but it actually returns `impl Future` - --> $DIR/issue-98604.rs:11:5 +error[E0271]: expected `fn() -> impl Future {test}` to be a fn item that returns `Pin + 'static)>>`, but it returns `impl Future` + --> $DIR/issue-98604.rs:9:5 | LL | Box::new(test) as AsyncFnPtr; | ^^^^^^^^^^^^^^ expected struct `Pin`, found opaque type | note: while checking the return type of the `async fn` - --> $DIR/issue-98604.rs:7:17 + --> $DIR/issue-98604.rs:5:17 | LL | async fn test() {} | ^ checked the `Output` of this `async fn`, found opaque type diff --git a/src/test/ui/type-alias-impl-trait/issue-98608.rs b/src/test/ui/type-alias-impl-trait/issue-98608.rs index 2f4cf7a0521..1f89af04576 100644 --- a/src/test/ui/type-alias-impl-trait/issue-98608.rs +++ b/src/test/ui/type-alias-impl-trait/issue-98608.rs @@ -1,8 +1,10 @@ -fn hi() -> impl Sized { std::ptr::null::() } +fn hi() -> impl Sized { + std::ptr::null::() +} fn main() { let b: Box Box> = Box::new(hi); - //~^ ERROR expected `fn() -> impl Sized {hi}` to be a fn item that returns `Box`, but it actually returns `impl Sized` + //~^ ERROR expected `fn() -> impl Sized {hi}` to be a fn item that returns `Box`, but it returns `impl Sized` let boxed = b(); let null = *boxed; println!("{null:?}"); diff --git a/src/test/ui/type-alias-impl-trait/issue-98608.stderr b/src/test/ui/type-alias-impl-trait/issue-98608.stderr index c5eed7561c0..916a58451ba 100644 --- a/src/test/ui/type-alias-impl-trait/issue-98608.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-98608.stderr @@ -1,7 +1,7 @@ -error[E0271]: expected `fn() -> impl Sized {hi}` to be a fn item that returns `Box`, but it actually returns `impl Sized` - --> $DIR/issue-98608.rs:4:39 +error[E0271]: expected `fn() -> impl Sized {hi}` to be a fn item that returns `Box`, but it returns `impl Sized` + --> $DIR/issue-98608.rs:6:39 | -LL | fn hi() -> impl Sized { std::ptr::null::() } +LL | fn hi() -> impl Sized { | ---------- the found opaque type ... LL | let b: Box Box> = Box::new(hi); From b3bc2111accc45af73ac50d537a679520cf1fc83 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Mon, 8 Aug 2022 19:50:10 +0900 Subject: [PATCH 70/77] add regression test for #79148 --- src/test/ui/proc-macro/auxiliary/re-export.rs | 19 +++++++++++++++++++ src/test/ui/proc-macro/issue-79148.rs | 10 ++++++++++ src/test/ui/proc-macro/issue-79148.stderr | 16 ++++++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 src/test/ui/proc-macro/auxiliary/re-export.rs create mode 100644 src/test/ui/proc-macro/issue-79148.rs create mode 100644 src/test/ui/proc-macro/issue-79148.stderr diff --git a/src/test/ui/proc-macro/auxiliary/re-export.rs b/src/test/ui/proc-macro/auxiliary/re-export.rs new file mode 100644 index 00000000000..e8e9c9d3ecb --- /dev/null +++ b/src/test/ui/proc-macro/auxiliary/re-export.rs @@ -0,0 +1,19 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; + +use proc_macro::TokenStream; + +#[proc_macro] +pub fn cause_ice(_: TokenStream) -> TokenStream { + " + enum IceCause { + Variant, + } + + pub use IceCause::Variant; + ".parse().unwrap() +} diff --git a/src/test/ui/proc-macro/issue-79148.rs b/src/test/ui/proc-macro/issue-79148.rs new file mode 100644 index 00000000000..3f01187a8bf --- /dev/null +++ b/src/test/ui/proc-macro/issue-79148.rs @@ -0,0 +1,10 @@ +// aux-build:re-export.rs +// edition:2018 + +extern crate re_export; + +use re_export::cause_ice; + +cause_ice!(); //~ ERROR `Variant` is only public within the crate, and cannot be re-exported outside + +fn main() {} diff --git a/src/test/ui/proc-macro/issue-79148.stderr b/src/test/ui/proc-macro/issue-79148.stderr new file mode 100644 index 00000000000..a3b2de01ddf --- /dev/null +++ b/src/test/ui/proc-macro/issue-79148.stderr @@ -0,0 +1,16 @@ +error[E0364]: `Variant` is only public within the crate, and cannot be re-exported outside + --> $DIR/issue-79148.rs:8:1 + | +LL | cause_ice!(); + | ^^^^^^^^^^^^ + | +note: consider marking `Variant` as `pub` in the imported module + --> $DIR/issue-79148.rs:8:1 + | +LL | cause_ice!(); + | ^^^^^^^^^^^^ + = note: this error originates in the macro `cause_ice` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0364`. From eab3b05b622890228e001feff5f5751196cc12ed Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 8 Aug 2022 21:09:09 +0200 Subject: [PATCH 71/77] Synthetize a trait ref when none is available. --- src/librustdoc/clean/auto_trait.rs | 18 ++++++++++++------ src/test/rustdoc/fn-bound.rs | 4 +++- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 6697952293e..af33c1a6ada 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -348,13 +348,13 @@ where fn make_final_bounds( &self, ty_to_bounds: FxHashMap>, - ty_to_fn: FxHashMap, Option)>, + ty_to_fn: FxHashMap)>, lifetime_to_bounds: FxHashMap>, ) -> Vec { ty_to_bounds .into_iter() .flat_map(|(ty, mut bounds)| { - if let Some((Some(ref poly_trait), ref output)) = ty_to_fn.get(&ty) { + if let Some((ref poly_trait, ref output)) = ty_to_fn.get(&ty) { let mut new_path = poly_trait.trait_.clone(); let last_segment = new_path.segments.pop().expect("segments were empty"); @@ -473,7 +473,7 @@ where let mut lifetime_to_bounds: FxHashMap<_, FxHashSet<_>> = Default::default(); let mut ty_to_traits: FxHashMap> = Default::default(); - let mut ty_to_fn: FxHashMap, Option)> = Default::default(); + let mut ty_to_fn: FxHashMap)> = Default::default(); for p in clean_where_predicates { let (orig_p, p) = (p, p.clean(self.cx)); @@ -537,8 +537,8 @@ where if is_fn { ty_to_fn .entry(ty.clone()) - .and_modify(|e| *e = (Some(poly_trait.clone()), e.1.clone())) - .or_insert(((Some(poly_trait.clone())), None)); + .and_modify(|e| *e = (poly_trait.clone(), e.1.clone())) + .or_insert(((poly_trait.clone()), None)); ty_to_bounds.entry(ty.clone()).or_default(); } else { @@ -561,7 +561,13 @@ where .and_modify(|e| { *e = (e.0.clone(), Some(rhs.ty().unwrap().clone())) }) - .or_insert((None, Some(rhs.ty().unwrap().clone()))); + .or_insert(( + PolyTrait { + trait_: trait_.clone(), + generic_params: Vec::new(), + }, + Some(rhs.ty().unwrap().clone()), + )); continue; } diff --git a/src/test/rustdoc/fn-bound.rs b/src/test/rustdoc/fn-bound.rs index 7b44ee7b4b5..d5d5838d375 100644 --- a/src/test/rustdoc/fn-bound.rs +++ b/src/test/rustdoc/fn-bound.rs @@ -4,10 +4,12 @@ pub struct Span { inner: Peekable>, } -struct ConditionalIterator { +pub struct ConditionalIterator { f: F, } + +// @has 'fn_bound/struct.ConditionalIterator.html' '//h3[@class="code-header in-band"]' 'impl Iterator for ConditionalIterator' impl Iterator for ConditionalIterator { type Item = (); From 74e71da5472f92988bed09d3b79470901ef8632f Mon Sep 17 00:00:00 2001 From: Bryysen Date: Mon, 8 Aug 2022 21:34:55 +0200 Subject: [PATCH 72/77] Fix plural form of `variant` in error message not formatting correctly due to ordering, added/improved comments and removed redundant test already caught by `E0081.rs` --- compiler/rustc_typeck/src/check/check.rs | 11 ++++++----- src/test/ui/error-codes/E0081.rs | 9 +++++++-- src/test/ui/error-codes/E0081.stderr | 23 +++++++++++++++++++---- src/test/ui/tag-variant-disr-dup.rs | 12 ------------ src/test/ui/tag-variant-disr-dup.stderr | 14 -------------- 5 files changed, 32 insertions(+), 37 deletions(-) delete mode 100644 src/test/ui/tag-variant-disr-dup.rs delete mode 100644 src/test/ui/tag-variant-disr-dup.stderr diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 1943d3de3ad..c5fa8a5db03 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -1499,18 +1499,19 @@ fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: L check_transparent(tcx, sp, def); } -/// Part of enum check, errors if two or more discriminants are equal +/// Part of enum check. Given the discriminants of an enum, errors if two or more discriminants are equal fn detect_discriminant_duplicate<'tcx>( tcx: TyCtxt<'tcx>, mut discrs: Vec<(VariantIdx, Discr<'tcx>)>, vs: &'tcx [hir::Variant<'tcx>], self_span: Span, ) { - // Helper closure to reduce duplicate code. This gets called everytime we detect a duplicate + // Helper closure to reduce duplicate code. This gets called everytime we detect a duplicate. + // Here `idx` refers to the order of which the discriminant appears, and its index in `vs` let report = |dis: Discr<'tcx>, idx: usize, err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>| { - let var = &vs[idx]; + let var = &vs[idx]; // HIR for the duplicate discriminant let (span, display_discr) = match var.disr_expr { Some(ref expr) => { // In the case the discriminant is both a duplicate and overflowed, let the user know @@ -1533,8 +1534,8 @@ fn detect_discriminant_duplicate<'tcx>( vs[..idx].iter().rev().enumerate().find(|v| v.1.disr_expr.is_some()) { let ve_ident = var.ident; - let sp = if n > 1 { "variants" } else { "variant" }; let n = n + 1; + let sp = if n > 1 { "variants" } else { "variant" }; err.span_label( *span, @@ -1549,7 +1550,7 @@ fn detect_discriminant_duplicate<'tcx>( err.span_label(span, format!("{display_discr} assigned here")); }; - // Here we are loop through the discriminants, comparing each discriminant to another. + // Here we loop through the discriminants, comparing each discriminant to another. // When a duplicate is detected, we instatiate an error and point to both // initial and duplicate value. The duplicate discriminant is then discarded by swapping // it with the last element and decrementing the `vec.len` (which is why we have to evaluate diff --git a/src/test/ui/error-codes/E0081.rs b/src/test/ui/error-codes/E0081.rs index 5e970a89307..f53fda864d6 100644 --- a/src/test/ui/error-codes/E0081.rs +++ b/src/test/ui/error-codes/E0081.rs @@ -27,9 +27,9 @@ enum NegDisEnum { //~^ NOTE `-1` assigned here } -#[repr(i32)] enum MultipleDuplicates { //~^ ERROR discriminant value `0` assigned more than once + //~^^ ERROR discriminant value `-2` assigned more than once V0, //~^ NOTE `0` assigned here V1 = 0, @@ -39,10 +39,15 @@ enum MultipleDuplicates { V4 = 0, //~^ NOTE `0` assigned here V5 = -2, - //~^ NOTE discriminant for `V7` incremented from this startpoint (`V5` + 2 variant later => `V7` = 0) + //~^ NOTE discriminant for `V7` incremented from this startpoint (`V5` + 2 variants later => `V7` = 0) + //~^^ NOTE `-2` assigned here V6, V7, //~^ NOTE `0` assigned here + V8 = -3, + //~^ NOTE discriminant for `V9` incremented from this startpoint (`V8` + 1 variant later => `V9` = -2) + V9, + //~^ NOTE `-2` assigned here } fn main() { diff --git a/src/test/ui/error-codes/E0081.stderr b/src/test/ui/error-codes/E0081.stderr index d27861aca5f..64562fefc86 100644 --- a/src/test/ui/error-codes/E0081.stderr +++ b/src/test/ui/error-codes/E0081.stderr @@ -38,11 +38,11 @@ LL | Last, | ---- `-1` assigned here error[E0081]: discriminant value `0` assigned more than once - --> $DIR/E0081.rs:31:1 + --> $DIR/E0081.rs:30:1 | LL | enum MultipleDuplicates { | ^^^^^^^^^^^^^^^^^^^^^^^ -LL | +... LL | V0, | -- `0` assigned here LL | @@ -53,11 +53,26 @@ LL | V4 = 0, | - `0` assigned here LL | LL | V5 = -2, - | ------- discriminant for `V7` incremented from this startpoint (`V5` + 2 variant later => `V7` = 0) + | ------- discriminant for `V7` incremented from this startpoint (`V5` + 2 variants later => `V7` = 0) ... LL | V7, | -- `0` assigned here -error: aborting due to 4 previous errors +error[E0081]: discriminant value `-2` assigned more than once + --> $DIR/E0081.rs:30:1 + | +LL | enum MultipleDuplicates { + | ^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | V5 = -2, + | -- `-2` assigned here +... +LL | V8 = -3, + | ------- discriminant for `V9` incremented from this startpoint (`V8` + 1 variant later => `V9` = -2) +LL | +LL | V9, + | -- `-2` assigned here + +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0081`. diff --git a/src/test/ui/tag-variant-disr-dup.rs b/src/test/ui/tag-variant-disr-dup.rs deleted file mode 100644 index e497f993da2..00000000000 --- a/src/test/ui/tag-variant-disr-dup.rs +++ /dev/null @@ -1,12 +0,0 @@ -// Black and White have the same discriminator value ... - -enum Color { - //~^ ERROR discriminant value `0` assigned more than once - Red = 0xff0000, - Green = 0x00ff00, - Blue = 0x0000ff, - Black = 0x000000, - White = 0x000000, -} - -fn main() { } diff --git a/src/test/ui/tag-variant-disr-dup.stderr b/src/test/ui/tag-variant-disr-dup.stderr deleted file mode 100644 index 4932cde0b18..00000000000 --- a/src/test/ui/tag-variant-disr-dup.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0081]: discriminant value `0` assigned more than once - --> $DIR/tag-variant-disr-dup.rs:3:1 - | -LL | enum Color { - | ^^^^^^^^^^ -... -LL | Black = 0x000000, - | -------- `0` assigned here -LL | White = 0x000000, - | -------- `0` assigned here - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0081`. From 28e4b9e64e436f52b03ba53e0f859a206ef3c93e Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Mon, 8 Aug 2022 14:09:55 -0700 Subject: [PATCH 73/77] Add regression test comment --- src/test/rustdoc/fn-bound.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/rustdoc/fn-bound.rs b/src/test/rustdoc/fn-bound.rs index d5d5838d375..4c4ffddc8a6 100644 --- a/src/test/rustdoc/fn-bound.rs +++ b/src/test/rustdoc/fn-bound.rs @@ -1,3 +1,5 @@ +// Regression test for #100143 + use std::iter::Peekable; pub struct Span { From 63be9a95b66ddb097a585ca58b23e291e40706e0 Mon Sep 17 00:00:00 2001 From: Anton Romanov Date: Mon, 8 Aug 2022 17:51:17 -0700 Subject: [PATCH 74/77] Update Duration::as_secs doc to point to as_secs_f64/32 for including fractional part Rather than suggesting to calculate manually --- library/core/src/time.rs | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/library/core/src/time.rs b/library/core/src/time.rs index 756f1a1663c..48353756741 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -318,19 +318,11 @@ impl Duration { /// assert_eq!(duration.as_secs(), 5); /// ``` /// - /// To determine the total number of seconds represented by the `Duration`, - /// use `as_secs` in combination with [`subsec_nanos`]: - /// - /// ``` - /// use std::time::Duration; - /// - /// let duration = Duration::new(5, 730023852); - /// - /// assert_eq!(5.730023852, - /// duration.as_secs() as f64 - /// + duration.subsec_nanos() as f64 * 1e-9); - /// ``` + /// To determine the total number of seconds represented by the `Duration` + /// including the fractional part, use [`as_secs_f64`] or [`as_secs_f32`] /// + /// [`as_secs_f32`]: Duration::as_secs_f64 + /// [`as_secs_f64`]: Duration::as_secs_f32 /// [`subsec_nanos`]: Duration::subsec_nanos #[stable(feature = "duration", since = "1.3.0")] #[rustc_const_stable(feature = "duration_consts", since = "1.32.0")] From abbd34d00e0a5ee15060ef92dc6b0225dd2897a5 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Tue, 9 Aug 2022 12:27:53 +0900 Subject: [PATCH 75/77] avoid `&str` to `String` conversions --- compiler/rustc_typeck/src/check/coercion.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index 21d0a7869d6..540a8c3a83d 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -1589,11 +1589,11 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { ) { let hir::ExprKind::Loop(_, _, _, loop_span) = expr.kind else { return;}; let mut span: MultiSpan = vec![loop_span].into(); - span.push_span_label(loop_span, "this might have zero elements to iterate on".to_string()); + span.push_span_label(loop_span, "this might have zero elements to iterate on"); for ret_expr in ret_exprs { span.push_span_label( ret_expr.span, - "if the loop doesn't execute, this value would never get returned".to_string(), + "if the loop doesn't execute, this value would never get returned", ); } err.span_note( From 56ec5bec1ee9ecf6cbacb2378dbc75238a9fc8fe Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Tue, 9 Aug 2022 14:27:26 +0900 Subject: [PATCH 76/77] suggest adding an appropriate missing pattern excluding comments --- .../src/thir/pattern/check_match.rs | 28 +++++++++---------- ...e-missing-pattern-excluding-comments.fixed | 10 +++++++ ...iate-missing-pattern-excluding-comments.rs | 9 ++++++ ...-missing-pattern-excluding-comments.stderr | 24 ++++++++++++++++ 4 files changed, 57 insertions(+), 14 deletions(-) create mode 100644 src/test/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.fixed create mode 100644 src/test/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.rs create mode 100644 src/test/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.stderr diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 063c076474e..69a8c98b27a 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -849,22 +849,22 @@ fn non_exhaustive_match<'p, 'tcx>( )); } [.., prev, last] if prev.span.eq_ctxt(last.span) => { - if let Ok(snippet) = sm.span_to_snippet(prev.span.between(last.span)) { - let comma = if matches!(last.body.kind, hir::ExprKind::Block(..)) - && last.span.eq_ctxt(last.body.span) - { - "" - } else { - "," - }; + let comma = if matches!(last.body.kind, hir::ExprKind::Block(..)) + && last.span.eq_ctxt(last.body.span) + { + "" + } else { + "," + }; + let spacing = if sm.is_multiline(prev.span.between(last.span)) { + sm.indentation_before(last.span).map(|indent| format!("\n{indent}")) + } else { + Some(" ".to_string()) + }; + if let Some(spacing) = spacing { suggestion = Some(( last.span.shrink_to_hi(), - format!( - "{}{}{} => todo!()", - comma, - snippet.strip_prefix(',').unwrap_or(&snippet), - pattern - ), + format!("{}{}{} => todo!()", comma, spacing, pattern), )); } } diff --git a/src/test/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.fixed b/src/test/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.fixed new file mode 100644 index 00000000000..b28dce88105 --- /dev/null +++ b/src/test/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.fixed @@ -0,0 +1,10 @@ +// run-rustfix + +fn main() { + match Some(1) { //~ ERROR non-exhaustive patterns: `None` not covered + Some(1) => {} + // hello + Some(_) => {} + None => todo!() + } +} diff --git a/src/test/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.rs b/src/test/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.rs new file mode 100644 index 00000000000..42493a63271 --- /dev/null +++ b/src/test/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.rs @@ -0,0 +1,9 @@ +// run-rustfix + +fn main() { + match Some(1) { //~ ERROR non-exhaustive patterns: `None` not covered + Some(1) => {} + // hello + Some(_) => {} + } +} diff --git a/src/test/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.stderr b/src/test/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.stderr new file mode 100644 index 00000000000..f3dca9bcb07 --- /dev/null +++ b/src/test/ui/pattern/suggest-adding-appropriate-missing-pattern-excluding-comments.stderr @@ -0,0 +1,24 @@ +error[E0004]: non-exhaustive patterns: `None` not covered + --> $DIR/suggest-adding-appropriate-missing-pattern-excluding-comments.rs:4:11 + | +LL | match Some(1) { + | ^^^^^^^ pattern `None` not covered + | +note: `Option` defined here + --> $SRC_DIR/core/src/option.rs:LL:COL + | +LL | pub enum Option { + | ------------------ +... +LL | None, + | ^^^^ not covered + = note: the matched value is of type `Option` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ Some(_) => {} +LL + None => todo!() + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. From 7547084ff673dcfdb2c6bcf7dc7a81190513ed40 Mon Sep 17 00:00:00 2001 From: Jakob Degen Date: Tue, 2 Aug 2022 20:06:16 -0700 Subject: [PATCH 77/77] Add option to `mir::MutVisitor` to not invalidate CFG. This also applies that option to some uses of the visitor --- compiler/rustc_middle/src/mir/visit.rs | 155 +++++++++++------- .../src/cleanup_post_borrowck.rs | 2 +- .../rustc_mir_transform/src/const_prop.rs | 2 +- .../src/deref_separator.rs | 2 +- .../src/elaborate_box_derefs.rs | 2 +- compiler/rustc_mir_transform/src/nrvo.rs | 4 +- .../rustc_mir_transform/src/reveal_all.rs | 2 +- compiler/rustc_mir_transform/src/simplify.rs | 4 +- 8 files changed, 101 insertions(+), 72 deletions(-) diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 89160876401..4a85defb1ed 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -80,6 +80,8 @@ macro_rules! make_mir_visitor { self.super_body(body); } + extra_body_methods!($($mutability)?); + fn visit_basic_block_data( &mut self, block: BasicBlock, @@ -287,63 +289,7 @@ macro_rules! make_mir_visitor { &mut self, body: &$($mutability)? Body<'tcx>, ) { - let span = body.span; - if let Some(gen) = &$($mutability)? body.generator { - if let Some(yield_ty) = $(& $mutability)? gen.yield_ty { - self.visit_ty( - yield_ty, - TyContext::YieldTy(SourceInfo::outermost(span)) - ); - } - } - - // for best performance, we want to use an iterator rather - // than a for-loop, to avoid calling `body::Body::invalidate` for - // each basic block. - #[allow(unused_macro_rules)] - macro_rules! basic_blocks { - (mut) => (body.basic_blocks_mut().iter_enumerated_mut()); - () => (body.basic_blocks().iter_enumerated()); - } - for (bb, data) in basic_blocks!($($mutability)?) { - self.visit_basic_block_data(bb, data); - } - - for scope in &$($mutability)? body.source_scopes { - self.visit_source_scope_data(scope); - } - - self.visit_ty( - $(& $mutability)? body.return_ty(), - TyContext::ReturnTy(SourceInfo::outermost(body.span)) - ); - - for local in body.local_decls.indices() { - self.visit_local_decl(local, & $($mutability)? body.local_decls[local]); - } - - #[allow(unused_macro_rules)] - macro_rules! type_annotations { - (mut) => (body.user_type_annotations.iter_enumerated_mut()); - () => (body.user_type_annotations.iter_enumerated()); - } - - for (index, annotation) in type_annotations!($($mutability)?) { - self.visit_user_type_annotation( - index, annotation - ); - } - - for var_debug_info in &$($mutability)? body.var_debug_info { - self.visit_var_debug_info(var_debug_info); - } - - self.visit_span($(& $mutability)? body.span); - - for const_ in &$($mutability)? body.required_consts { - let location = START_BLOCK.start_location(); - self.visit_constant(const_, location); - } + super_body!(self, body, $($mutability, true)?); } fn super_basic_block_data(&mut self, @@ -982,12 +928,7 @@ macro_rules! make_mir_visitor { body: &$($mutability)? Body<'tcx>, location: Location ) { - #[allow(unused_macro_rules)] - macro_rules! basic_blocks { - (mut) => (body.basic_blocks_mut()); - () => (body.basic_blocks()); - } - let basic_block = & $($mutability)? basic_blocks!($($mutability)?)[location.block]; + let basic_block = & $($mutability)? basic_blocks!(body, $($mutability, true)?)[location.block]; if basic_block.statements.len() == location.statement_index { if let Some(ref $($mutability)? terminator) = basic_block.terminator { self.visit_terminator(terminator, location) @@ -1002,6 +943,94 @@ macro_rules! make_mir_visitor { } } +macro_rules! basic_blocks { + ($body:ident, mut, true) => { + $body.basic_blocks.as_mut() + }; + ($body:ident, mut, false) => { + $body.basic_blocks.as_mut_preserves_cfg() + }; + ($body:ident,) => { + $body.basic_blocks() + }; +} + +macro_rules! basic_blocks_iter { + ($body:ident, mut, $invalidate:tt) => { + basic_blocks!($body, mut, $invalidate).iter_enumerated_mut() + }; + ($body:ident,) => { + basic_blocks!($body,).iter_enumerated() + }; +} + +macro_rules! extra_body_methods { + (mut) => { + fn visit_body_preserves_cfg(&mut self, body: &mut Body<'tcx>) { + self.super_body_preserves_cfg(body); + } + + fn super_body_preserves_cfg(&mut self, body: &mut Body<'tcx>) { + super_body!(self, body, mut, false); + } + }; + () => {}; +} + +macro_rules! super_body { + ($self:ident, $body:ident, $($mutability:ident, $invalidate:tt)?) => { + let span = $body.span; + if let Some(gen) = &$($mutability)? $body.generator { + if let Some(yield_ty) = $(& $mutability)? gen.yield_ty { + $self.visit_ty( + yield_ty, + TyContext::YieldTy(SourceInfo::outermost(span)) + ); + } + } + + for (bb, data) in basic_blocks_iter!($body, $($mutability, $invalidate)?) { + $self.visit_basic_block_data(bb, data); + } + + for scope in &$($mutability)? $body.source_scopes { + $self.visit_source_scope_data(scope); + } + + $self.visit_ty( + $(& $mutability)? $body.return_ty(), + TyContext::ReturnTy(SourceInfo::outermost($body.span)) + ); + + for local in $body.local_decls.indices() { + $self.visit_local_decl(local, & $($mutability)? $body.local_decls[local]); + } + + #[allow(unused_macro_rules)] + macro_rules! type_annotations { + (mut) => ($body.user_type_annotations.iter_enumerated_mut()); + () => ($body.user_type_annotations.iter_enumerated()); + } + + for (index, annotation) in type_annotations!($($mutability)?) { + $self.visit_user_type_annotation( + index, annotation + ); + } + + for var_debug_info in &$($mutability)? $body.var_debug_info { + $self.visit_var_debug_info(var_debug_info); + } + + $self.visit_span($(& $mutability)? $body.span); + + for const_ in &$($mutability)? $body.required_consts { + let location = START_BLOCK.start_location(); + $self.visit_constant(const_, location); + } + } +} + macro_rules! visit_place_fns { (mut) => { fn tcx<'a>(&'a self) -> TyCtxt<'tcx>; diff --git a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs index 611d29a4ee2..3378923c22c 100644 --- a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs +++ b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs @@ -33,7 +33,7 @@ pub struct DeleteNonCodegenStatements<'tcx> { impl<'tcx> MirPass<'tcx> for CleanupNonCodegenStatements { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let mut delete = DeleteNonCodegenStatements { tcx }; - delete.visit_body(body); + delete.visit_body_preserves_cfg(body); body.user_type_annotations.raw.clear(); for decl in &mut body.local_decls { diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index fbc0a767f07..98016659a05 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -951,7 +951,7 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> { } fn visit_body(&mut self, body: &mut Body<'tcx>) { - for (bb, data) in body.basic_blocks_mut().iter_enumerated_mut() { + for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() { self.visit_basic_block_data(bb, data); } } diff --git a/compiler/rustc_mir_transform/src/deref_separator.rs b/compiler/rustc_mir_transform/src/deref_separator.rs index a00bb16f7ac..87d7b664015 100644 --- a/compiler/rustc_mir_transform/src/deref_separator.rs +++ b/compiler/rustc_mir_transform/src/deref_separator.rs @@ -90,7 +90,7 @@ pub fn deref_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let patch = MirPatch::new(body); let mut checker = DerefChecker { tcx, patcher: patch, local_decls: body.local_decls.clone() }; - for (bb, data) in body.basic_blocks_mut().iter_enumerated_mut() { + for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() { checker.visit_basic_block_data(bb, data); } diff --git a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs index 44e3945d6fc..76b4cdd2ecd 100644 --- a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs +++ b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs @@ -116,7 +116,7 @@ impl<'tcx> MirPass<'tcx> for ElaborateBoxDerefs { ElaborateBoxDerefVisitor { tcx, unique_did, nonnull_did, local_decls, patch }; for (block, BasicBlockData { statements, terminator, .. }) in - body.basic_blocks.as_mut().iter_enumerated_mut() + body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() { let mut index = 0; for statement in statements { diff --git a/compiler/rustc_mir_transform/src/nrvo.rs b/compiler/rustc_mir_transform/src/nrvo.rs index bb063915f55..42d732730ec 100644 --- a/compiler/rustc_mir_transform/src/nrvo.rs +++ b/compiler/rustc_mir_transform/src/nrvo.rs @@ -53,10 +53,10 @@ impl<'tcx> MirPass<'tcx> for RenameReturnPlace { def_id, returned_local ); - RenameToReturnPlace { tcx, to_rename: returned_local }.visit_body(body); + RenameToReturnPlace { tcx, to_rename: returned_local }.visit_body_preserves_cfg(body); // Clean up the `NOP`s we inserted for statements made useless by our renaming. - for block_data in body.basic_blocks_mut() { + for block_data in body.basic_blocks.as_mut_preserves_cfg() { block_data.statements.retain(|stmt| stmt.kind != mir::StatementKind::Nop); } diff --git a/compiler/rustc_mir_transform/src/reveal_all.rs b/compiler/rustc_mir_transform/src/reveal_all.rs index 4919ad40098..abe6cb285f5 100644 --- a/compiler/rustc_mir_transform/src/reveal_all.rs +++ b/compiler/rustc_mir_transform/src/reveal_all.rs @@ -19,7 +19,7 @@ impl<'tcx> MirPass<'tcx> for RevealAll { } let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); - RevealAllVisitor { tcx, param_env }.visit_body(body); + RevealAllVisitor { tcx, param_env }.visit_body_preserves_cfg(body); } } diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index 180f4c7dcd6..7a6ca917d0f 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -412,7 +412,7 @@ pub fn simplify_locals<'tcx>(body: &mut Body<'tcx>, tcx: TyCtxt<'tcx>) { if map.iter().any(Option::is_none) { // Update references to all vars and tmps now let mut updater = LocalUpdater { map, tcx }; - updater.visit_body(body); + updater.visit_body_preserves_cfg(body); body.local_decls.shrink_to_fit(); } @@ -548,7 +548,7 @@ fn remove_unused_definitions(used_locals: &mut UsedLocals, body: &mut Body<'_>) while modified { modified = false; - for data in body.basic_blocks_mut() { + for data in body.basic_blocks.as_mut_preserves_cfg() { // Remove unnecessary StorageLive and StorageDead annotations. data.statements.retain(|statement| { let keep = match &statement.kind {