From 7c568961fd0e1d4ccce04797acfbb07e5f30b551 Mon Sep 17 00:00:00 2001 From: Tiddo Langerak Date: Tue, 9 Aug 2022 09:41:56 +0300 Subject: [PATCH 01/81] Feat: extracted method from trait impl is placed in existing impl Previously, when triggering a method extraction from within a trait impl block, then this would always create a new impl block for the struct, even if there already is one. Now, it'll put the extracted method in the matching existing block if it exists. --- .../src/handlers/extract_function.rs | 272 +++++++++++++++++- 1 file changed, 268 insertions(+), 4 deletions(-) diff --git a/crates/ide-assists/src/handlers/extract_function.rs b/crates/ide-assists/src/handlers/extract_function.rs index 52a55ead3af96..40d0327ef7188 100644 --- a/crates/ide-assists/src/handlers/extract_function.rs +++ b/crates/ide-assists/src/handlers/extract_function.rs @@ -109,8 +109,6 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op let params = body.extracted_function_params(ctx, &container_info, locals_used.iter().copied()); - let extracted_from_trait_impl = body.extracted_from_trait_impl(); - let name = make_function_name(&semantics_scope); let fun = Function { @@ -129,8 +127,13 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op builder.replace(target_range, make_call(ctx, &fun, old_indent)); + let has_impl_wrapper = insert_after + .ancestors() + .find(|a| a.kind() == SyntaxKind::IMPL && a != &insert_after) + .is_some(); + let fn_def = match fun.self_param_adt(ctx) { - Some(adt) if extracted_from_trait_impl => { + Some(adt) if anchor == Anchor::Method && !has_impl_wrapper => { let fn_def = format_function(ctx, module, &fun, old_indent, new_indent + 1); generate_impl_text(&adt, &fn_def).replace("{\n\n", "{") } @@ -271,7 +274,7 @@ enum FunType { } /// Where to put extracted function definition -#[derive(Debug)] +#[derive(Debug, Eq, PartialEq, Clone, Copy)] enum Anchor { /// Extract free function and put right after current top-level function Freestanding, @@ -1244,6 +1247,15 @@ fn node_to_insert_after(body: &FunctionBody, anchor: Anchor) -> Option break, + SyntaxKind::IMPL => { + if body.extracted_from_trait_impl() && matches!(anchor, Anchor::Method) { + let impl_node = find_non_trait_impl(&next_ancestor); + let target_node = impl_node.as_ref().and_then(last_impl_member); + if target_node.is_some() { + return target_node; + } + } + } SyntaxKind::ITEM_LIST if !matches!(anchor, Anchor::Freestanding) => continue, SyntaxKind::ITEM_LIST => { if ancestors.peek().map(SyntaxNode::kind) == Some(SyntaxKind::MODULE) { @@ -1264,6 +1276,28 @@ fn node_to_insert_after(body: &FunctionBody, anchor: Anchor) -> Option Option { + let impl_type = Some(impl_type_name(trait_impl)?); + + let mut sibblings = trait_impl.parent()?.children(); + sibblings.find(|s| impl_type_name(s) == impl_type && !is_trait_impl(s)) +} + +fn last_impl_member(impl_node: &SyntaxNode) -> Option { + impl_node.children().find(|c| c.kind() == SyntaxKind::ASSOC_ITEM_LIST)?.last_child() +} + +fn is_trait_impl(node: &SyntaxNode) -> bool { + match ast::Impl::cast(node.clone()) { + Some(c) => c.trait_().is_some(), + None => false, + } +} + +fn impl_type_name(impl_node: &SyntaxNode) -> Option { + Some(ast::Impl::cast(impl_node.clone())?.self_ty()?.to_string()) +} + fn make_call(ctx: &AssistContext<'_>, fun: &Function, indent: IndentLevel) -> String { let ret_ty = fun.return_type(ctx); @@ -5058,6 +5092,236 @@ impl Struct { ); } + #[test] + fn extract_method_from_trait_with_existing_non_empty_impl_block() { + check_assist( + extract_function, + r#" +struct Struct(i32); +trait Trait { + fn bar(&self) -> i32; +} + +impl Struct { + fn foo() {} +} + +impl Trait for Struct { + fn bar(&self) -> i32 { + $0self.0 + 2$0 + } +} +"#, + r#" +struct Struct(i32); +trait Trait { + fn bar(&self) -> i32; +} + +impl Struct { + fn foo() {} + + fn $0fun_name(&self) -> i32 { + self.0 + 2 + } +} + +impl Trait for Struct { + fn bar(&self) -> i32 { + self.fun_name() + } +} +"#, + ) + } + + #[test] + fn extract_function_from_trait_with_existing_non_empty_impl_block() { + check_assist( + extract_function, + r#" +struct Struct(i32); +trait Trait { + fn bar(&self) -> i32; +} + +impl Struct { + fn foo() {} +} + +impl Trait for Struct { + fn bar(&self) -> i32 { + let three_squared = $03 * 3$0; + self.0 + three_squared + } +} +"#, + r#" +struct Struct(i32); +trait Trait { + fn bar(&self) -> i32; +} + +impl Struct { + fn foo() {} +} + +impl Trait for Struct { + fn bar(&self) -> i32 { + let three_squared = fun_name(); + self.0 + three_squared + } +} + +fn $0fun_name() -> i32 { + 3 * 3 +} +"#, + ) + } + + #[test] + fn extract_method_from_trait_with_multiple_existing_impl_blocks() { + check_assist( + extract_function, + r#" +struct Struct(i32); +struct StructBefore(i32); +struct StructAfter(i32); +trait Trait { + fn bar(&self) -> i32; +} + +impl StructBefore { + fn foo(){} +} + +impl Struct { + fn foo(){} +} + +impl StructAfter { + fn foo(){} +} + +impl Trait for Struct { + fn bar(&self) -> i32 { + $0self.0 + 2$0 + } +} +"#, + r#" +struct Struct(i32); +struct StructBefore(i32); +struct StructAfter(i32); +trait Trait { + fn bar(&self) -> i32; +} + +impl StructBefore { + fn foo(){} +} + +impl Struct { + fn foo(){} + + fn $0fun_name(&self) -> i32 { + self.0 + 2 + } +} + +impl StructAfter { + fn foo(){} +} + +impl Trait for Struct { + fn bar(&self) -> i32 { + self.fun_name() + } +} +"#, + ) + } + + #[test] + fn extract_method_from_trait_with_multiple_existing_trait_impl_blocks() { + check_assist( + extract_function, + r#" +struct Struct(i32); +trait Trait { + fn bar(&self) -> i32; +} +trait TraitBefore { + fn before(&self) -> i32; +} +trait TraitAfter { + fn after(&self) -> i32; +} + +impl TraitBefore for Struct { + fn before(&self) -> i32 { + 42 + } +} + +impl Struct { + fn foo(){} +} + +impl TraitAfter for Struct { + fn after(&self) -> i32 { + 42 + } +} + +impl Trait for Struct { + fn bar(&self) -> i32 { + $0self.0 + 2$0 + } +} +"#, + r#" +struct Struct(i32); +trait Trait { + fn bar(&self) -> i32; +} +trait TraitBefore { + fn before(&self) -> i32; +} +trait TraitAfter { + fn after(&self) -> i32; +} + +impl TraitBefore for Struct { + fn before(&self) -> i32 { + 42 + } +} + +impl Struct { + fn foo(){} + + fn $0fun_name(&self) -> i32 { + self.0 + 2 + } +} + +impl TraitAfter for Struct { + fn after(&self) -> i32 { + 42 + } +} + +impl Trait for Struct { + fn bar(&self) -> i32 { + self.fun_name() + } +} +"#, + ) + } + #[test] fn closure_arguments() { check_assist( From 7402366877b3f50563cba4ba919cdc88c6220d14 Mon Sep 17 00:00:00 2001 From: Tiddo Langerak Date: Wed, 10 Aug 2022 17:03:15 +0300 Subject: [PATCH 02/81] Avoid cloning IMPL node if we don't have to --- crates/ide-assists/src/handlers/extract_function.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/crates/ide-assists/src/handlers/extract_function.rs b/crates/ide-assists/src/handlers/extract_function.rs index 40d0327ef7188..969b0c1fb3f36 100644 --- a/crates/ide-assists/src/handlers/extract_function.rs +++ b/crates/ide-assists/src/handlers/extract_function.rs @@ -1288,6 +1288,9 @@ fn last_impl_member(impl_node: &SyntaxNode) -> Option { } fn is_trait_impl(node: &SyntaxNode) -> bool { + if !ast::Impl::can_cast(node.kind()) { + return false; + } match ast::Impl::cast(node.clone()) { Some(c) => c.trait_().is_some(), None => false, @@ -1295,6 +1298,9 @@ fn is_trait_impl(node: &SyntaxNode) -> bool { } fn impl_type_name(impl_node: &SyntaxNode) -> Option { + if !ast::Impl::can_cast(impl_node.kind()) { + return None; + } Some(ast::Impl::cast(impl_node.clone())?.self_ty()?.to_string()) } From d5e6aa39c1cd6d45a6048fb41281ae23915cb89d Mon Sep 17 00:00:00 2001 From: Tiddo Langerak Date: Thu, 1 Sep 2022 08:37:30 +0300 Subject: [PATCH 03/81] Pre-cast impl nodes to ast::Impl in find_non_trait_impl --- .../src/handlers/extract_function.rs | 32 ++++++++----------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/crates/ide-assists/src/handlers/extract_function.rs b/crates/ide-assists/src/handlers/extract_function.rs index 969b0c1fb3f36..c40fb291a32a2 100644 --- a/crates/ide-assists/src/handlers/extract_function.rs +++ b/crates/ide-assists/src/handlers/extract_function.rs @@ -1276,32 +1276,26 @@ fn node_to_insert_after(body: &FunctionBody, anchor: Anchor) -> Option Option { - let impl_type = Some(impl_type_name(trait_impl)?); +fn find_non_trait_impl(trait_impl: &SyntaxNode) -> Option { + let as_impl = ast::Impl::cast(trait_impl.clone())?; + let impl_type = Some(impl_type_name(&as_impl)?); - let mut sibblings = trait_impl.parent()?.children(); - sibblings.find(|s| impl_type_name(s) == impl_type && !is_trait_impl(s)) + let sibblings = trait_impl.parent()?.children(); + sibblings.filter_map(ast::Impl::cast) + .find(|s| impl_type_name(s) == impl_type && !is_trait_impl(s)) } -fn last_impl_member(impl_node: &SyntaxNode) -> Option { - impl_node.children().find(|c| c.kind() == SyntaxKind::ASSOC_ITEM_LIST)?.last_child() +fn last_impl_member(impl_node: &ast::Impl) -> Option { + let last_child = impl_node.assoc_item_list()?.assoc_items().last()?; + Some(last_child.syntax().clone()) } -fn is_trait_impl(node: &SyntaxNode) -> bool { - if !ast::Impl::can_cast(node.kind()) { - return false; - } - match ast::Impl::cast(node.clone()) { - Some(c) => c.trait_().is_some(), - None => false, - } +fn is_trait_impl(node: &ast::Impl) -> bool { + node.trait_().is_some() } -fn impl_type_name(impl_node: &SyntaxNode) -> Option { - if !ast::Impl::can_cast(impl_node.kind()) { - return None; - } - Some(ast::Impl::cast(impl_node.clone())?.self_ty()?.to_string()) +fn impl_type_name(impl_node: &ast::Impl) -> Option { + Some(impl_node.self_ty()?.to_string()) } fn make_call(ctx: &AssistContext<'_>, fun: &Function, indent: IndentLevel) -> String { From c98fc537e6d2c0d3c9a19582962a3db8bf2c1827 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 4 Nov 2022 17:11:15 +0100 Subject: [PATCH 04/81] Generalize reborrow hints as adjustment hints --- crates/hir-ty/src/lib.rs | 2 +- crates/hir/src/lib.rs | 24 ++++- crates/hir/src/semantics.rs | 37 +++++-- crates/hir/src/source_analyzer.rs | 16 +-- crates/ide/src/inlay_hints.rs | 144 +++++++++++++++++++-------- crates/ide/src/lib.rs | 4 +- crates/ide/src/static_index.rs | 2 +- crates/rust-analyzer/src/config.rs | 9 +- crates/rust-analyzer/src/to_proto.rs | 22 ++-- 9 files changed, 182 insertions(+), 78 deletions(-) diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs index b68c764bdca09..ad33053ad095f 100644 --- a/crates/hir-ty/src/lib.rs +++ b/crates/hir-ty/src/lib.rs @@ -53,7 +53,7 @@ pub use builder::{ParamKind, TyBuilder}; pub use chalk_ext::*; pub use infer::{ could_coerce, could_unify, Adjust, Adjustment, AutoBorrow, BindingMode, InferenceDiagnostic, - InferenceResult, + InferenceResult, OverloadedDeref, PointerCast, }; pub use interner::Interner; pub use lower::{ diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index cbd9bf32a5486..9d77f343bc575 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -117,7 +117,7 @@ pub use { name::{known, Name}, ExpandResult, HirFileId, InFile, MacroFile, Origin, }, - hir_ty::display::HirDisplay, + hir_ty::{display::HirDisplay, PointerCast, Safety}, }; // These are negative re-exports: pub using these names is forbidden, they @@ -3651,6 +3651,28 @@ impl From for ScopeDef { } } +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum Adjust { + /// Go from ! to any type. + NeverToAny, + /// Dereference once, producing a place. + Deref(Option), + /// Take the address and produce either a `&` or `*` pointer. + Borrow(AutoBorrow), + Pointer(PointerCast), +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum AutoBorrow { + /// Converts from T to &T. + Ref(Mutability), + /// Converts from T to *T. + RawPtr(Mutability), +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub struct OverloadedDeref(pub Mutability); + pub trait HasVisibility { fn visibility(&self, db: &dyn HirDatabase) -> Visibility; fn is_visible_from(&self, db: &dyn HirDatabase, module: Module) -> bool { diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 119ec3210e175..2e1f88ba09043 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -29,9 +29,10 @@ use crate::{ db::HirDatabase, semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, source_analyzer::{resolve_hir_path, SourceAnalyzer}, - Access, BindingMode, BuiltinAttr, Callable, ConstParam, Crate, DeriveHelper, Field, Function, - HasSource, HirFileId, Impl, InFile, Label, LifetimeParam, Local, Macro, Module, ModuleDef, - Name, Path, ScopeDef, ToolModule, Trait, Type, TypeAlias, TypeParam, VariantDef, + Access, Adjust, AutoBorrow, BindingMode, BuiltinAttr, Callable, ConstParam, Crate, + DeriveHelper, Field, Function, HasSource, HirFileId, Impl, InFile, Label, LifetimeParam, Local, + Macro, Module, ModuleDef, Name, OverloadedDeref, Path, ScopeDef, ToolModule, Trait, Type, + TypeAlias, TypeParam, VariantDef, }; #[derive(Debug, Clone, PartialEq, Eq)] @@ -333,9 +334,8 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { self.imp.resolve_trait(trait_) } - // FIXME: Figure out a nice interface to inspect adjustments - pub fn is_implicit_reborrow(&self, expr: &ast::Expr) -> Option { - self.imp.is_implicit_reborrow(expr) + pub fn expr_adjustments(&self, expr: &ast::Expr) -> Option> { + self.imp.expr_adjustments(expr) } pub fn type_of_expr(&self, expr: &ast::Expr) -> Option { @@ -1067,8 +1067,29 @@ impl<'db> SemanticsImpl<'db> { } } - fn is_implicit_reborrow(&self, expr: &ast::Expr) -> Option { - self.analyze(expr.syntax())?.is_implicit_reborrow(self.db, expr) + fn expr_adjustments(&self, expr: &ast::Expr) -> Option> { + let mutability = |m| match m { + hir_ty::Mutability::Not => Mutability::Shared, + hir_ty::Mutability::Mut => Mutability::Mut, + }; + self.analyze(expr.syntax())?.expr_adjustments(self.db, expr).map(|it| { + it.iter() + .map(|adjust| match adjust.kind { + hir_ty::Adjust::NeverToAny => Adjust::NeverToAny, + hir_ty::Adjust::Deref(Some(hir_ty::OverloadedDeref(m))) => { + Adjust::Deref(Some(OverloadedDeref(mutability(m)))) + } + hir_ty::Adjust::Deref(None) => Adjust::Deref(None), + hir_ty::Adjust::Borrow(hir_ty::AutoBorrow::RawPtr(m)) => { + Adjust::Borrow(AutoBorrow::RawPtr(mutability(m))) + } + hir_ty::Adjust::Borrow(hir_ty::AutoBorrow::Ref(m)) => { + Adjust::Borrow(AutoBorrow::Ref(mutability(m))) + } + hir_ty::Adjust::Pointer(pc) => Adjust::Pointer(pc), + }) + .collect() + }) } fn type_of_expr(&self, expr: &ast::Expr) -> Option { diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index f86c571005367..91ea1c24d14f8 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -38,8 +38,7 @@ use hir_ty::{ UnsafeExpr, }, method_resolution::{self, lang_names_for_bin_op}, - Adjust, Adjustment, AutoBorrow, InferenceResult, Interner, Substitution, Ty, TyExt, TyKind, - TyLoweringContext, + Adjustment, InferenceResult, Interner, Substitution, Ty, TyExt, TyKind, TyLoweringContext, }; use itertools::Itertools; use smallvec::SmallVec; @@ -156,21 +155,14 @@ impl SourceAnalyzer { Some(res) } - pub(crate) fn is_implicit_reborrow( + pub(crate) fn expr_adjustments( &self, db: &dyn HirDatabase, expr: &ast::Expr, - ) -> Option { + ) -> Option<&[Adjustment]> { let expr_id = self.expr_id(db, expr)?; let infer = self.infer.as_ref()?; - let adjustments = infer.expr_adjustments.get(&expr_id)?; - adjustments.windows(2).find_map(|slice| match slice { - &[Adjustment {kind: Adjust::Deref(None), ..}, Adjustment {kind: Adjust::Borrow(AutoBorrow::Ref(m)), ..}] => Some(match m { - hir_ty::Mutability::Mut => Mutability::Mut, - hir_ty::Mutability::Not => Mutability::Shared, - }), - _ => None, - }) + infer.expr_adjustments.get(&expr_id).map(|v| &**v) } pub(crate) fn type_of_expr( diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 34d8bf67a3016..a26ff1893c740 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -1,7 +1,10 @@ use std::fmt; use either::Either; -use hir::{known, Callable, HasVisibility, HirDisplay, Mutability, Semantics, TypeInfo}; +use hir::{ + known, Adjust, AutoBorrow, Callable, HasVisibility, HirDisplay, Mutability, OverloadedDeref, + PointerCast, Safety, Semantics, TypeInfo, +}; use ide_db::{ base_db::FileRange, famous_defs::FamousDefs, syntax_helpers::node_ext::walk_ty, FxHashMap, RootDatabase, @@ -22,7 +25,7 @@ pub struct InlayHintsConfig { pub type_hints: bool, pub parameter_hints: bool, pub chaining_hints: bool, - pub reborrow_hints: ReborrowHints, + pub adjustment_hints: AdjustmentHints, pub closure_return_type_hints: ClosureReturnTypeHints, pub binding_mode_hints: bool, pub lifetime_elision_hints: LifetimeElisionHints, @@ -48,7 +51,7 @@ pub enum LifetimeElisionHints { } #[derive(Clone, Debug, PartialEq, Eq)] -pub enum ReborrowHints { +pub enum AdjustmentHints { Always, MutableOnly, Never, @@ -61,7 +64,8 @@ pub enum InlayKind { ClosingBraceHint, ClosureReturnTypeHint, GenericParamListHint, - ImplicitReborrowHint, + AdjustmentHint, + AdjustmentHintClosingParenthesis, LifetimeHint, ParameterHint, TypeHint, @@ -115,6 +119,12 @@ impl From for InlayHintLabel { } } +impl From<&str> for InlayHintLabel { + fn from(s: &str) -> Self { + Self { parts: vec![InlayHintLabelPart { text: s.into(), linked_location: None }] } + } +} + impl fmt::Display for InlayHintLabel { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.parts.iter().map(|part| &part.text).format("")) @@ -221,6 +231,7 @@ fn hints( match node { ast::Expr(expr) => { chaining_hints(hints, sema, &famous_defs, config, file_id, &expr); + adjustment_hints(hints, sema, config, &expr); match expr { ast::Expr::CallExpr(it) => param_name_hints(hints, sema, config, ast::Expr::from(it)), ast::Expr::MethodCallExpr(it) => { @@ -229,7 +240,7 @@ fn hints( ast::Expr::ClosureExpr(it) => closure_ret_hints(hints, sema, &famous_defs, config, file_id, it), // We could show reborrows for all expressions, but usually that is just noise to the user // and the main point here is to show why "moving" a mutable reference doesn't necessarily move it - ast::Expr::PathExpr(_) => reborrow_hints(hints, sema, config, &expr), + // ast::Expr::PathExpr(_) => reborrow_hints(hints, sema, config, &expr), _ => None, } }, @@ -617,30 +628,83 @@ fn closure_ret_hints( Some(()) } -fn reborrow_hints( +fn adjustment_hints( acc: &mut Vec, sema: &Semantics<'_, RootDatabase>, config: &InlayHintsConfig, expr: &ast::Expr, ) -> Option<()> { - if config.reborrow_hints == ReborrowHints::Never { - return None; + if config.adjustment_hints == AdjustmentHints::Never { + // return None; } + let parent = expr.syntax().parent().and_then(ast::Expr::cast); let descended = sema.descend_node_into_attributes(expr.clone()).pop(); let desc_expr = descended.as_ref().unwrap_or(expr); - let mutability = sema.is_implicit_reborrow(desc_expr)?; - let label = match mutability { - hir::Mutability::Shared if config.reborrow_hints != ReborrowHints::MutableOnly => "&*", - hir::Mutability::Mut => "&mut *", - _ => return None, + let adjustments = sema.expr_adjustments(desc_expr).filter(|it| !it.is_empty())?; + let needs_parens = match parent { + Some(parent) => { + match parent { + ast::Expr::AwaitExpr(_) + | ast::Expr::CallExpr(_) + | ast::Expr::CastExpr(_) + | ast::Expr::FieldExpr(_) + | ast::Expr::MethodCallExpr(_) + | ast::Expr::TryExpr(_) => true, + // FIXME: shorthands need special casing, though not sure if adjustments are even valid there + ast::Expr::RecordExpr(_) => false, + ast::Expr::IndexExpr(index) => index.base().as_ref() == Some(expr), + _ => false, + } + } + None => false, }; - acc.push(InlayHint { - range: expr.syntax().text_range(), - kind: InlayKind::ImplicitReborrowHint, - label: label.to_string().into(), - tooltip: Some(InlayTooltip::String("Compiler inserted reborrow".into())), - }); + if needs_parens { + acc.push(InlayHint { + range: expr.syntax().text_range(), + kind: InlayKind::AdjustmentHint, + label: "(".into(), + tooltip: None, + }); + } + for adjustment in adjustments.into_iter().rev() { + // FIXME: Add some nicer tooltips to each of these + let text = match adjustment { + Adjust::NeverToAny => "", + Adjust::Deref(None) => "*", + Adjust::Deref(Some(OverloadedDeref(Mutability::Mut))) => "*", + Adjust::Deref(Some(OverloadedDeref(Mutability::Shared))) => "*", + Adjust::Borrow(AutoBorrow::Ref(Mutability::Shared)) => "&", + Adjust::Borrow(AutoBorrow::Ref(Mutability::Mut)) => "&mut ", + Adjust::Borrow(AutoBorrow::RawPtr(Mutability::Shared)) => "&raw const ", + Adjust::Borrow(AutoBorrow::RawPtr(Mutability::Mut)) => "&raw mut ", + // some of these could be represented via `as` casts, but that's not too nice and + // handling everything as a prefix expr makes the `(` and `)` insertion easier + Adjust::Pointer(cast) => match cast { + PointerCast::ReifyFnPointer => "", + PointerCast::UnsafeFnPointer => "", + PointerCast::ClosureFnPointer(Safety::Unsafe) => "", + PointerCast::ClosureFnPointer(Safety::Safe) => "", + PointerCast::MutToConstPointer => "", + PointerCast::ArrayToPointer => "", + PointerCast::Unsize => "", + }, + }; + acc.push(InlayHint { + range: expr.syntax().text_range(), + kind: InlayKind::AdjustmentHint, + label: text.into(), + tooltip: None, + }); + } + if needs_parens { + acc.push(InlayHint { + range: expr.syntax().text_range(), + kind: InlayKind::AdjustmentHintClosingParenthesis, + label: ")".into(), + tooltip: None, + }); + } Some(()) } @@ -785,23 +849,23 @@ fn binding_mode_hints( tooltip: Some(InlayTooltip::String("Inferred binding mode".into())), }); }); - match pat { - ast::Pat::IdentPat(pat) if pat.ref_token().is_none() && pat.mut_token().is_none() => { - let bm = sema.binding_mode_of_pat(pat)?; - let bm = match bm { - hir::BindingMode::Move => return None, - hir::BindingMode::Ref(Mutability::Mut) => "ref mut", - hir::BindingMode::Ref(Mutability::Shared) => "ref", - }; - acc.push(InlayHint { - range, - kind: InlayKind::BindingModeHint, - label: bm.to_string().into(), - tooltip: Some(InlayTooltip::String("Inferred binding mode".into())), - }); - } - _ => (), - } + // match pat { + // ast::Pat::IdentPat(pat) if pat.ref_token().is_none() && pat.mut_token().is_none() => { + // let bm = sema.binding_mode_of_pat(pat)?; + // let bm = match bm { + // hir::BindingMode::Move => return None, + // hir::BindingMode::Ref(Mutability::Mut) => "ref mut", + // hir::BindingMode::Ref(Mutability::Shared) => "ref", + // }; + // acc.push(InlayHint { + // range, + // kind: InlayKind::BindingModeHint, + // label: bm.to_string().into(), + // tooltip: Some(InlayTooltip::String("Inferred binding mode".into())), + // }); + // } + // _ => (), + // } Some(()) } @@ -1218,7 +1282,7 @@ mod tests { use syntax::{TextRange, TextSize}; use test_utils::extract_annotations; - use crate::inlay_hints::ReborrowHints; + use crate::inlay_hints::AdjustmentHints; use crate::{fixture, inlay_hints::InlayHintsConfig, LifetimeElisionHints}; use super::ClosureReturnTypeHints; @@ -1230,7 +1294,7 @@ mod tests { chaining_hints: false, lifetime_elision_hints: LifetimeElisionHints::Never, closure_return_type_hints: ClosureReturnTypeHints::Never, - reborrow_hints: ReborrowHints::Always, + adjustment_hints: AdjustmentHints::Always, binding_mode_hints: false, hide_named_constructor_hints: false, hide_closure_initialization_hints: false, @@ -1242,7 +1306,7 @@ mod tests { type_hints: true, parameter_hints: true, chaining_hints: true, - reborrow_hints: ReborrowHints::Always, + adjustment_hints: AdjustmentHints::Always, closure_return_type_hints: ClosureReturnTypeHints::WithBlock, binding_mode_hints: true, lifetime_elision_hints: LifetimeElisionHints::Always, @@ -2849,7 +2913,7 @@ impl () { fn hints_implicit_reborrow() { check_with_config( InlayHintsConfig { - reborrow_hints: ReborrowHints::Always, + adjustment_hints: AdjustmentHints::Always, parameter_hints: true, ..DISABLED_CONFIG }, diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index 416817ca0b42c..568c53f8bdbfa 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -81,8 +81,8 @@ pub use crate::{ highlight_related::{HighlightRelatedConfig, HighlightedRange}, hover::{HoverAction, HoverConfig, HoverDocFormat, HoverGotoTypeData, HoverResult}, inlay_hints::{ - ClosureReturnTypeHints, InlayHint, InlayHintLabel, InlayHintsConfig, InlayKind, - InlayTooltip, LifetimeElisionHints, ReborrowHints, + AdjustmentHints, ClosureReturnTypeHints, InlayHint, InlayHintLabel, InlayHintsConfig, + InlayKind, InlayTooltip, LifetimeElisionHints, }, join_lines::JoinLinesConfig, markup::Markup, diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs index 27ad1a948d13b..6ebd6f713fb71 100644 --- a/crates/ide/src/static_index.rs +++ b/crates/ide/src/static_index.rs @@ -111,7 +111,7 @@ impl StaticIndex<'_> { chaining_hints: true, closure_return_type_hints: crate::ClosureReturnTypeHints::WithBlock, lifetime_elision_hints: crate::LifetimeElisionHints::Never, - reborrow_hints: crate::ReborrowHints::Never, + adjustment_hints: crate::AdjustmentHints::Never, hide_named_constructor_hints: false, hide_closure_initialization_hints: false, param_names_for_lifetime_elision_hints: false, diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 4072ae585dbd9..12c59edf9af10 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -261,6 +261,7 @@ config_data! { files_excludeDirs: Vec = "[]", /// Controls file watching implementation. files_watcher: FilesWatcherDef = "\"client\"", + /// Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords. highlightRelated_breakPoints_enable: bool = "true", /// Enables highlighting of all exit points while the cursor is on any `return`, `?`, `fn`, or return type arrow (`->`). @@ -1200,10 +1201,10 @@ impl Config { hide_closure_initialization_hints: self .data .inlayHints_typeHints_hideClosureInitialization, - reborrow_hints: match self.data.inlayHints_reborrowHints_enable { - ReborrowHintsDef::Always => ide::ReborrowHints::Always, - ReborrowHintsDef::Never => ide::ReborrowHints::Never, - ReborrowHintsDef::Mutable => ide::ReborrowHints::MutableOnly, + adjustment_hints: match self.data.inlayHints_reborrowHints_enable { + ReborrowHintsDef::Always => ide::AdjustmentHints::Always, + ReborrowHintsDef::Never => ide::AdjustmentHints::Never, + ReborrowHintsDef::Mutable => ide::AdjustmentHints::MutableOnly, }, binding_mode_hints: self.data.inlayHints_bindingModeHints_enable, param_names_for_lifetime_elision_hints: self diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 6c84a2069cd57..6f44a1de636d7 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs @@ -440,32 +440,35 @@ pub(crate) fn inlay_hint( Ok(lsp_types::InlayHint { position: match inlay_hint.kind { // before annotated thing - InlayKind::ParameterHint - | InlayKind::ImplicitReborrowHint - | InlayKind::BindingModeHint => position(line_index, inlay_hint.range.start()), + InlayKind::ParameterHint | InlayKind::AdjustmentHint | InlayKind::BindingModeHint => { + position(line_index, inlay_hint.range.start()) + } // after annotated thing InlayKind::ClosureReturnTypeHint | InlayKind::TypeHint | InlayKind::ChainingHint | InlayKind::GenericParamListHint + | InlayKind::AdjustmentHintClosingParenthesis | InlayKind::LifetimeHint | InlayKind::ClosingBraceHint => position(line_index, inlay_hint.range.end()), }, padding_left: Some(match inlay_hint.kind { InlayKind::TypeHint => !render_colons, InlayKind::ChainingHint | InlayKind::ClosingBraceHint => true, - InlayKind::BindingModeHint + InlayKind::AdjustmentHintClosingParenthesis + | InlayKind::BindingModeHint | InlayKind::ClosureReturnTypeHint | InlayKind::GenericParamListHint - | InlayKind::ImplicitReborrowHint + | InlayKind::AdjustmentHint | InlayKind::LifetimeHint | InlayKind::ParameterHint => false, }), padding_right: Some(match inlay_hint.kind { - InlayKind::ChainingHint + InlayKind::AdjustmentHintClosingParenthesis + | InlayKind::ChainingHint | InlayKind::ClosureReturnTypeHint | InlayKind::GenericParamListHint - | InlayKind::ImplicitReborrowHint + | InlayKind::AdjustmentHint | InlayKind::TypeHint | InlayKind::ClosingBraceHint => false, InlayKind::BindingModeHint => inlay_hint.label.as_simple_str() != Some("&"), @@ -476,10 +479,11 @@ pub(crate) fn inlay_hint( InlayKind::ClosureReturnTypeHint | InlayKind::TypeHint | InlayKind::ChainingHint => { Some(lsp_types::InlayHintKind::TYPE) } - InlayKind::BindingModeHint + InlayKind::AdjustmentHintClosingParenthesis + | InlayKind::BindingModeHint | InlayKind::GenericParamListHint | InlayKind::LifetimeHint - | InlayKind::ImplicitReborrowHint + | InlayKind::AdjustmentHint | InlayKind::ClosingBraceHint => None, }, text_edits: None, From 95d20fccd77869a98ed8db1e8b0d45d4d909f26b Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 4 Nov 2022 22:40:06 +0100 Subject: [PATCH 05/81] Add adjustment hint tests --- crates/ide/src/inlay_hints.rs | 121 ++++++++++++++++++++++------------ 1 file changed, 78 insertions(+), 43 deletions(-) diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index a26ff1893c740..9eef5aaeed005 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -635,7 +635,12 @@ fn adjustment_hints( expr: &ast::Expr, ) -> Option<()> { if config.adjustment_hints == AdjustmentHints::Never { - // return None; + return None; + } + + if let ast::Expr::ParenExpr(_) = expr { + // These inherit from the inner expression which would result in duplicate hints + return None; } let parent = expr.syntax().parent().and_then(ast::Expr::cast); @@ -2909,48 +2914,6 @@ impl () { ); } - #[test] - fn hints_implicit_reborrow() { - check_with_config( - InlayHintsConfig { - adjustment_hints: AdjustmentHints::Always, - parameter_hints: true, - ..DISABLED_CONFIG - }, - r#" -fn __() { - let unique = &mut (); - let r_mov = unique; - let foo: &mut _ = unique; - //^^^^^^ &mut * - ref_mut_id(unique); - //^^^^^^ mut_ref - //^^^^^^ &mut * - let shared = ref_id(unique); - //^^^^^^ shared_ref - //^^^^^^ &* - let mov = shared; - let r_mov: &_ = shared; - ref_id(shared); - //^^^^^^ shared_ref - - identity(unique); - identity(shared); -} -fn identity(t: T) -> T { - t -} -fn ref_mut_id(mut_ref: &mut ()) -> &mut () { - mut_ref - //^^^^^^^ &mut * -} -fn ref_id(shared_ref: &()) -> &() { - shared_ref -} -"#, - ); - } - #[test] fn hints_binding_modes() { check_with_config( @@ -3058,4 +3021,76 @@ fn f() { "#, ); } + + #[test] + fn adjustment_hints() { + check_with_config( + InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG }, + r#" +//- minicore: coerce_unsized +fn main() { + let _: u32 = loop {}; + //^^^^^^^ + let _: &u32 = &mut 0; + //^^^^^^& + //^^^^^^* + let _: &mut u32 = &mut 0; + //^^^^^^&mut $ + //^^^^^^* + let _: *const u32 = &mut 0; + //^^^^^^&raw const $ + //^^^^^^* + let _: *mut u32 = &mut 0; + //^^^^^^&raw mut $ + //^^^^^^* + let _: fn() = main; + //^^^^ + let _: unsafe fn() = main; + //^^^^ + //^^^^ + let _: unsafe fn() = main as fn(); + //^^^^^^^^^^^^ + let _: fn() = || {}; + //^^^^^ + let _: unsafe fn() = || {}; + //^^^^^ + let _: *const u32 = &mut 0u32 as *mut u32; + //^^^^^^^^^^^^^^^^^^^^^ + let _: &mut [_] = &mut [0; 0]; + //^^^^^^^^^^^ + //^^^^^^^^^^^&mut $ + //^^^^^^^^^^^* + + Struct.consume(); + Struct.by_ref(); + //^^^^^^( + //^^^^^^& + //^^^^^^) + Struct.by_ref_mut(); + //^^^^^^( + //^^^^^^&mut $ + //^^^^^^) + + (&Struct).consume(); + //^^^^^^^* + (&Struct).by_ref(); + + (&mut Struct).consume(); + //^^^^^^^^^^^* + (&mut Struct).by_ref(); + //^^^^^^^^^^^& + //^^^^^^^^^^^* + (&mut Struct).by_ref_mut(); +} + +#[derive(Copy, Clone)] +struct Struct; +impl Struct { + fn consume(self) {} + fn by_ref(&self) {} + fn by_ref_mut(&mut self) {} +} +"#, + ) + } } From d841ad116a3d438c4b04db1d895d9cc4991ca2c0 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 4 Nov 2022 22:59:07 +0100 Subject: [PATCH 06/81] Fix up adjustment hints configurations --- crates/ide/src/inlay_hints.rs | 29 ++++++++++++-------- crates/rust-analyzer/src/config.rs | 43 ++++++++++++++++++++++++++---- docs/user/generated_config.adoc | 8 +++++- editors/code/package.json | 17 +++++++++++- 4 files changed, 79 insertions(+), 18 deletions(-) diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 9eef5aaeed005..50934a27f89e3 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -53,7 +53,7 @@ pub enum LifetimeElisionHints { #[derive(Clone, Debug, PartialEq, Eq)] pub enum AdjustmentHints { Always, - MutableOnly, + ReborrowOnly, Never, } @@ -675,7 +675,9 @@ fn adjustment_hints( for adjustment in adjustments.into_iter().rev() { // FIXME: Add some nicer tooltips to each of these let text = match adjustment { - Adjust::NeverToAny => "", + Adjust::NeverToAny if config.adjustment_hints == AdjustmentHints::Always => { + "" + } Adjust::Deref(None) => "*", Adjust::Deref(Some(OverloadedDeref(Mutability::Mut))) => "*", Adjust::Deref(Some(OverloadedDeref(Mutability::Shared))) => "*", @@ -685,15 +687,20 @@ fn adjustment_hints( Adjust::Borrow(AutoBorrow::RawPtr(Mutability::Mut)) => "&raw mut ", // some of these could be represented via `as` casts, but that's not too nice and // handling everything as a prefix expr makes the `(` and `)` insertion easier - Adjust::Pointer(cast) => match cast { - PointerCast::ReifyFnPointer => "", - PointerCast::UnsafeFnPointer => "", - PointerCast::ClosureFnPointer(Safety::Unsafe) => "", - PointerCast::ClosureFnPointer(Safety::Safe) => "", - PointerCast::MutToConstPointer => "", - PointerCast::ArrayToPointer => "", - PointerCast::Unsize => "", - }, + Adjust::Pointer(cast) if config.adjustment_hints == AdjustmentHints::Always => { + match cast { + PointerCast::ReifyFnPointer => "", + PointerCast::UnsafeFnPointer => "", + PointerCast::ClosureFnPointer(Safety::Unsafe) => { + "" + } + PointerCast::ClosureFnPointer(Safety::Safe) => "", + PointerCast::MutToConstPointer => "", + PointerCast::ArrayToPointer => "", + PointerCast::Unsize => "", + } + } + _ => continue, }; acc.push(InlayHint { range: expr.syntax().text_range(), diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 12c59edf9af10..766937d444b78 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -321,6 +321,8 @@ config_data! { inlayHints_closingBraceHints_minLines: usize = "25", /// Whether to show inlay type hints for return types of closures. inlayHints_closureReturnTypeHints_enable: ClosureReturnTypeHintsDef = "\"never\"", + /// Whether to show inlay hints for type adjustments. + inlayHints_expressionAdjustmentHints_enable: AdjustmentHintsDef = "\"never\"", /// Whether to show inlay type hints for elided lifetimes in function signatures. inlayHints_lifetimeElisionHints_enable: LifetimeElisionDef = "\"never\"", /// Whether to prefer using parameter names as the name for elided lifetime hints if possible. @@ -330,7 +332,8 @@ config_data! { /// Whether to show function parameter name inlay hints at the call /// site. inlayHints_parameterHints_enable: bool = "true", - /// Whether to show inlay type hints for compiler inserted reborrows. + /// Whether to show inlay hints for compiler inserted reborrows. + /// This setting is deprecated in favor of #rust-analyzer.inlayHints.expressionAdjustmentHints.enable#. inlayHints_reborrowHints_enable: ReborrowHintsDef = "\"never\"", /// Whether to render leading colons for type hints, and trailing colons for parameter hints. inlayHints_renderColons: bool = "true", @@ -1201,10 +1204,15 @@ impl Config { hide_closure_initialization_hints: self .data .inlayHints_typeHints_hideClosureInitialization, - adjustment_hints: match self.data.inlayHints_reborrowHints_enable { - ReborrowHintsDef::Always => ide::AdjustmentHints::Always, - ReborrowHintsDef::Never => ide::AdjustmentHints::Never, - ReborrowHintsDef::Mutable => ide::AdjustmentHints::MutableOnly, + adjustment_hints: match self.data.inlayHints_expressionAdjustmentHints_enable { + AdjustmentHintsDef::Always => ide::AdjustmentHints::Always, + AdjustmentHintsDef::Never => match self.data.inlayHints_reborrowHints_enable { + ReborrowHintsDef::Always | ReborrowHintsDef::Mutable => { + ide::AdjustmentHints::ReborrowOnly + } + ReborrowHintsDef::Never => ide::AdjustmentHints::Never, + }, + AdjustmentHintsDef::Reborrow => ide::AdjustmentHints::ReborrowOnly, }, binding_mode_hints: self.data.inlayHints_bindingModeHints_enable, param_names_for_lifetime_elision_hints: self @@ -1539,6 +1547,7 @@ mod de_unit_v { named_unit_variant!(all); named_unit_variant!(skip_trivial); named_unit_variant!(mutable); + named_unit_variant!(reborrow); named_unit_variant!(with_block); } @@ -1688,6 +1697,17 @@ enum ReborrowHintsDef { Mutable, } +#[derive(Deserialize, Debug, Clone)] +#[serde(untagged)] +enum AdjustmentHintsDef { + #[serde(deserialize_with = "true_or_always")] + Always, + #[serde(deserialize_with = "false_or_never")] + Never, + #[serde(deserialize_with = "de_unit_v::reborrow")] + Reborrow, +} + #[derive(Deserialize, Debug, Clone)] #[serde(rename_all = "snake_case")] enum FilesWatcherDef { @@ -1997,6 +2017,19 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json "Only show mutable reborrow hints." ] }, + "AdjustmentHintsDef" => set! { + "type": "string", + "enum": [ + "always", + "never", + "reborrow" + ], + "enumDescriptions": [ + "Always show all adjustment hints.", + "Never show adjustment hints.", + "Only show auto borrow and dereference adjustment hints." + ] + }, "CargoFeaturesDef" => set! { "anyOf": [ { diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index 36794efe42726..4f40ab25a17f9 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc @@ -450,6 +450,11 @@ to always show them). -- Whether to show inlay type hints for return types of closures. -- +[[rust-analyzer.inlayHints.expressionAdjustmentHints.enable]]rust-analyzer.inlayHints.expressionAdjustmentHints.enable (default: `"never"`):: ++ +-- +Whether to show inlay hints for type adjustments. +-- [[rust-analyzer.inlayHints.lifetimeElisionHints.enable]]rust-analyzer.inlayHints.lifetimeElisionHints.enable (default: `"never"`):: + -- @@ -474,7 +479,8 @@ site. [[rust-analyzer.inlayHints.reborrowHints.enable]]rust-analyzer.inlayHints.reborrowHints.enable (default: `"never"`):: + -- -Whether to show inlay type hints for compiler inserted reborrows. +Whether to show inlay hints for compiler inserted reborrows. +This setting is deprecated in favor of #rust-analyzer.inlayHints.expressionAdjustmentHints.enable#. -- [[rust-analyzer.inlayHints.renderColons]]rust-analyzer.inlayHints.renderColons (default: `true`):: + diff --git a/editors/code/package.json b/editors/code/package.json index 8e8b59159db92..f14123469b3cb 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -935,6 +935,21 @@ "Only show type hints for return types of closures with blocks." ] }, + "rust-analyzer.inlayHints.expressionAdjustmentHints.enable": { + "markdownDescription": "Whether to show inlay hints for type adjustments.", + "default": "never", + "type": "string", + "enum": [ + "always", + "never", + "reborrow" + ], + "enumDescriptions": [ + "Always show all adjustment hints.", + "Never show adjustment hints.", + "Only show auto borrow and dereference adjustment hints." + ] + }, "rust-analyzer.inlayHints.lifetimeElisionHints.enable": { "markdownDescription": "Whether to show inlay type hints for elided lifetimes in function signatures.", "default": "never", @@ -970,7 +985,7 @@ "type": "boolean" }, "rust-analyzer.inlayHints.reborrowHints.enable": { - "markdownDescription": "Whether to show inlay type hints for compiler inserted reborrows.", + "markdownDescription": "Whether to show inlay hints for compiler inserted reborrows.\nThis setting is deprecated in favor of #rust-analyzer.inlayHints.expressionAdjustmentHints.enable#.", "default": "never", "type": "string", "enum": [ From e468a1af350f344067f7c44aae060e2977798dbb Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 5 Nov 2022 00:27:03 +0100 Subject: [PATCH 07/81] internal: Optimize `apply_document_changes` a bit --- crates/ide-db/src/line_index.rs | 7 +- crates/rust-analyzer/src/lsp_utils.rs | 111 ++++++++++++++------------ crates/rust-analyzer/src/main_loop.rs | 6 +- 3 files changed, 68 insertions(+), 56 deletions(-) diff --git a/crates/ide-db/src/line_index.rs b/crates/ide-db/src/line_index.rs index 75d49ff2fd77f..1b8f56187a02b 100644 --- a/crates/ide-db/src/line_index.rs +++ b/crates/ide-db/src/line_index.rs @@ -58,8 +58,11 @@ impl LineIndex { let mut utf16_lines = NoHashHashMap::default(); let mut utf16_chars = Vec::new(); - let mut newlines = vec![0.into()]; - let mut curr_row @ mut curr_col = 0.into(); + let mut newlines = Vec::with_capacity(16); + newlines.push(TextSize::from(0)); + + let mut curr_row = 0.into(); + let mut curr_col = 0.into(); let mut line = 0; for c in text.chars() { let c_len = TextSize::of(c); diff --git a/crates/rust-analyzer/src/lsp_utils.rs b/crates/rust-analyzer/src/lsp_utils.rs index c6a4db9a453ac..0971dc36f3a5c 100644 --- a/crates/rust-analyzer/src/lsp_utils.rs +++ b/crates/rust-analyzer/src/lsp_utils.rs @@ -1,5 +1,5 @@ //! Utilities for LSP-related boilerplate code. -use std::{ops::Range, sync::Arc}; +use std::{mem, ops::Range, sync::Arc}; use lsp_server::Notification; @@ -133,11 +133,37 @@ impl GlobalState { } pub(crate) fn apply_document_changes( - old_text: &mut String, - content_changes: Vec, -) { + file_contents: impl FnOnce() -> String, + mut content_changes: Vec, +) -> String { + // Skip to the last full document change, as it invalidates all previous changes anyways. + let mut start = content_changes + .iter() + .rev() + .position(|change| change.range.is_none()) + .map(|idx| content_changes.len() - idx - 1) + .unwrap_or(0); + + let mut text: String = match content_changes.get_mut(start) { + // peek at the first content change as an optimization + Some(lsp_types::TextDocumentContentChangeEvent { range: None, text, .. }) => { + let text = mem::take(text); + start += 1; + + // The only change is a full document update + if start == content_changes.len() { + return text; + } + text + } + Some(_) => file_contents(), + // we received no content changes + None => return file_contents(), + }; + let mut line_index = LineIndex { - index: Arc::new(ide::LineIndex::new(old_text)), + // the index will be overwritten in the bottom loop's first iteration + index: Arc::new(ide::LineIndex::new(&text)), // We don't care about line endings or offset encoding here. endings: LineEndings::Unix, encoding: PositionEncoding::Utf16, @@ -148,38 +174,20 @@ pub(crate) fn apply_document_changes( // Some clients (e.g. Code) sort the ranges in reverse. As an optimization, we // remember the last valid line in the index and only rebuild it if needed. // The VFS will normalize the end of lines to `\n`. - enum IndexValid { - All, - UpToLineExclusive(u32), - } - - impl IndexValid { - fn covers(&self, line: u32) -> bool { - match *self { - IndexValid::UpToLineExclusive(to) => to > line, - _ => true, - } - } - } - - let mut index_valid = IndexValid::All; + let mut index_valid = !0u32; for change in content_changes { - match change.range { - Some(range) => { - if !index_valid.covers(range.end.line) { - line_index.index = Arc::new(ide::LineIndex::new(old_text)); - } - index_valid = IndexValid::UpToLineExclusive(range.start.line); - if let Ok(range) = from_proto::text_range(&line_index, range) { - old_text.replace_range(Range::::from(range), &change.text); - } + // The None case can't happen as we have handled it above already + if let Some(range) = change.range { + if index_valid <= range.end.line { + *Arc::make_mut(&mut line_index.index) = ide::LineIndex::new(&text); } - None => { - *old_text = change.text; - index_valid = IndexValid::UpToLineExclusive(0); + index_valid = range.start.line; + if let Ok(range) = from_proto::text_range(&line_index, range) { + text.replace_range(Range::::from(range), &change.text); } } } + text } /// Checks that the edits inside the completion and the additional edits do not overlap. @@ -242,11 +250,10 @@ mod tests { }; } - let mut text = String::new(); - apply_document_changes(&mut text, vec![]); + let text = apply_document_changes(|| String::new(), vec![]); assert_eq!(text, ""); - apply_document_changes( - &mut text, + let text = apply_document_changes( + || text, vec![TextDocumentContentChangeEvent { range: None, range_length: None, @@ -254,39 +261,39 @@ mod tests { }], ); assert_eq!(text, "the"); - apply_document_changes(&mut text, c![0, 3; 0, 3 => " quick"]); + let text = apply_document_changes(|| text, c![0, 3; 0, 3 => " quick"]); assert_eq!(text, "the quick"); - apply_document_changes(&mut text, c![0, 0; 0, 4 => "", 0, 5; 0, 5 => " foxes"]); + let text = apply_document_changes(|| text, c![0, 0; 0, 4 => "", 0, 5; 0, 5 => " foxes"]); assert_eq!(text, "quick foxes"); - apply_document_changes(&mut text, c![0, 11; 0, 11 => "\ndream"]); + let text = apply_document_changes(|| text, c![0, 11; 0, 11 => "\ndream"]); assert_eq!(text, "quick foxes\ndream"); - apply_document_changes(&mut text, c![1, 0; 1, 0 => "have "]); + let text = apply_document_changes(|| text, c![1, 0; 1, 0 => "have "]); assert_eq!(text, "quick foxes\nhave dream"); - apply_document_changes( - &mut text, + let text = apply_document_changes( + || text, c![0, 0; 0, 0 => "the ", 1, 4; 1, 4 => " quiet", 1, 16; 1, 16 => "s\n"], ); assert_eq!(text, "the quick foxes\nhave quiet dreams\n"); - apply_document_changes(&mut text, c![0, 15; 0, 15 => "\n", 2, 17; 2, 17 => "\n"]); + let text = apply_document_changes(|| text, c![0, 15; 0, 15 => "\n", 2, 17; 2, 17 => "\n"]); assert_eq!(text, "the quick foxes\n\nhave quiet dreams\n\n"); - apply_document_changes( - &mut text, + let text = apply_document_changes( + || text, c![1, 0; 1, 0 => "DREAM", 2, 0; 2, 0 => "they ", 3, 0; 3, 0 => "DON'T THEY?"], ); assert_eq!(text, "the quick foxes\nDREAM\nthey have quiet dreams\nDON'T THEY?\n"); - apply_document_changes(&mut text, c![0, 10; 1, 5 => "", 2, 0; 2, 12 => ""]); + let text = apply_document_changes(|| text, c![0, 10; 1, 5 => "", 2, 0; 2, 12 => ""]); assert_eq!(text, "the quick \nthey have quiet dreams\n"); - text = String::from("❤️"); - apply_document_changes(&mut text, c![0, 0; 0, 0 => "a"]); + let text = String::from("❤️"); + let text = apply_document_changes(|| text, c![0, 0; 0, 0 => "a"]); assert_eq!(text, "a❤️"); - text = String::from("a\nb"); - apply_document_changes(&mut text, c![0, 1; 1, 0 => "\nțc", 0, 1; 1, 1 => "d"]); + let text = String::from("a\nb"); + let text = apply_document_changes(|| text, c![0, 1; 1, 0 => "\nțc", 0, 1; 1, 1 => "d"]); assert_eq!(text, "adcb"); - text = String::from("a\nb"); - apply_document_changes(&mut text, c![0, 1; 1, 0 => "ț\nc", 0, 2; 0, 2 => "c"]); + let text = String::from("a\nb"); + let text = apply_document_changes(|| text, c![0, 1; 1, 0 => "ț\nc", 0, 2; 0, 2 => "c"]); assert_eq!(text, "ațc\ncb"); } diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 7d10dc5d15b62..6e5da58fe372a 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -759,8 +759,10 @@ impl GlobalState { let vfs = &mut this.vfs.write().0; let file_id = vfs.file_id(&path).unwrap(); - let mut text = String::from_utf8(vfs.file_contents(file_id).to_vec()).unwrap(); - apply_document_changes(&mut text, params.content_changes); + let text = apply_document_changes( + || std::str::from_utf8(vfs.file_contents(file_id)).unwrap().into(), + params.content_changes, + ); vfs.set_file_contents(path, Some(text.into_bytes())); } From 28afe570682c98d7612c79a5ef523e2ed47ac7d0 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 5 Nov 2022 11:00:17 +0100 Subject: [PATCH 08/81] Add tests for LineEndings::normalize --- crates/rust-analyzer/src/line_index.rs | 60 +++++++++++++++++++++----- 1 file changed, 49 insertions(+), 11 deletions(-) diff --git a/crates/rust-analyzer/src/line_index.rs b/crates/rust-analyzer/src/line_index.rs index 0d424b915703a..7636c3da7f9af 100644 --- a/crates/rust-analyzer/src/line_index.rs +++ b/crates/rust-analyzer/src/line_index.rs @@ -27,10 +27,6 @@ pub(crate) enum LineEndings { impl LineEndings { /// Replaces `\r\n` with `\n` in-place in `src`. pub(crate) fn normalize(src: String) -> (String, LineEndings) { - if !src.as_bytes().contains(&b'\r') { - return (src, LineEndings::Unix); - } - // We replace `\r\n` with `\n` in-place, which doesn't break utf-8 encoding. // While we *can* call `as_mut_vec` and do surgery on the live string // directly, let's rather steal the contents of `src`. This makes the code @@ -39,10 +35,19 @@ impl LineEndings { let mut buf = src.into_bytes(); let mut gap_len = 0; let mut tail = buf.as_mut_slice(); + let mut crlf_seen = false; + + let find_crlf = |src: &[u8]| src.windows(2).position(|it| it == b"\r\n"); + loop { let idx = match find_crlf(&tail[gap_len..]) { - None => tail.len(), - Some(idx) => idx + gap_len, + None if crlf_seen => tail.len(), + // SAFETY: buf is unchanged and therefor still contains utf8 data + None => return (unsafe { String::from_utf8_unchecked(buf) }, LineEndings::Unix), + Some(idx) => { + crlf_seen = true; + idx + gap_len + } }; tail.copy_within(gap_len..idx, 0); tail = &mut tail[idx - gap_len..]; @@ -54,15 +59,48 @@ impl LineEndings { // Account for removed `\r`. // After `set_len`, `buf` is guaranteed to contain utf-8 again. - let new_len = buf.len() - gap_len; let src = unsafe { + let new_len = buf.len() - gap_len; buf.set_len(new_len); String::from_utf8_unchecked(buf) }; - return (src, LineEndings::Dos); + (src, LineEndings::Dos) + } +} - fn find_crlf(src: &[u8]) -> Option { - src.windows(2).position(|it| it == b"\r\n") - } +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn unix() { + let src = "a\nb\nc\n\n\n\n"; + let (res, endings) = LineEndings::normalize(src.into()); + assert_eq!(endings, LineEndings::Unix); + assert_eq!(res, src); + } + + #[test] + fn dos() { + let src = "\r\na\r\n\r\nb\r\nc\r\n\r\n\r\n\r\n"; + let (res, endings) = LineEndings::normalize(src.into()); + assert_eq!(endings, LineEndings::Dos); + assert_eq!(res, "\na\n\nb\nc\n\n\n\n"); + } + + #[test] + fn mixed() { + let src = "a\r\nb\r\nc\r\n\n\r\n\n"; + let (res, endings) = LineEndings::normalize(src.into()); + assert_eq!(endings, LineEndings::Dos); + assert_eq!(res, "a\nb\nc\n\n\n\n"); + } + + #[test] + fn none() { + let src = "abc"; + let (res, endings) = LineEndings::normalize(src.into()); + assert_eq!(endings, LineEndings::Unix); + assert_eq!(res, src); } } From b87a23b91bc28477068b7ce189ed30b380a7d91c Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Wed, 2 Nov 2022 23:26:29 +0900 Subject: [PATCH 09/81] Rename convertor -> converter --- crates/mbe/src/syntax_bridge.rs | 44 ++++++++++++++++----------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs index e4c56565b92d4..1df3a6f56f07a 100644 --- a/crates/mbe/src/syntax_bridge.rs +++ b/crates/mbe/src/syntax_bridge.rs @@ -35,7 +35,7 @@ pub fn syntax_node_to_token_tree_with_modifications( append: FxHashMap>, ) -> (tt::Subtree, TokenMap, u32) { let global_offset = node.text_range().start(); - let mut c = Convertor::new(node, global_offset, existing_token_map, next_id, replace, append); + let mut c = Converter::new(node, global_offset, existing_token_map, next_id, replace, append); let subtree = convert_tokens(&mut c); c.id_alloc.map.shrink_to_fit(); always!(c.replace.is_empty(), "replace: {:?}", c.replace); @@ -100,7 +100,7 @@ pub fn parse_to_token_tree(text: &str) -> Option<(tt::Subtree, TokenMap)> { return None; } - let mut conv = RawConvertor { + let mut conv = RawConverter { lexed, pos: 0, id_alloc: TokenIdAlloc { @@ -148,7 +148,7 @@ pub fn parse_exprs_with_sep(tt: &tt::Subtree, sep: char) -> Vec { res } -fn convert_tokens(conv: &mut C) -> tt::Subtree { +fn convert_tokens(conv: &mut C) -> tt::Subtree { struct StackEntry { subtree: tt::Subtree, idx: usize, @@ -425,8 +425,8 @@ impl TokenIdAlloc { } } -/// A raw token (straight from lexer) convertor -struct RawConvertor<'a> { +/// A raw token (straight from lexer) converter +struct RawConverter<'a> { lexed: parser::LexedStr<'a>, pos: usize, id_alloc: TokenIdAlloc, @@ -442,7 +442,7 @@ trait SrcToken: std::fmt::Debug { fn synthetic_id(&self, ctx: &Ctx) -> Option; } -trait TokenConvertor: Sized { +trait TokenConverter: Sized { type Token: SrcToken; fn convert_doc_comment(&self, token: &Self::Token) -> Option>; @@ -454,25 +454,25 @@ trait TokenConvertor: Sized { fn id_alloc(&mut self) -> &mut TokenIdAlloc; } -impl<'a> SrcToken> for usize { - fn kind(&self, ctx: &RawConvertor<'a>) -> SyntaxKind { +impl<'a> SrcToken> for usize { + fn kind(&self, ctx: &RawConverter<'a>) -> SyntaxKind { ctx.lexed.kind(*self) } - fn to_char(&self, ctx: &RawConvertor<'a>) -> Option { + fn to_char(&self, ctx: &RawConverter<'a>) -> Option { ctx.lexed.text(*self).chars().next() } - fn to_text(&self, ctx: &RawConvertor<'_>) -> SmolStr { + fn to_text(&self, ctx: &RawConverter<'_>) -> SmolStr { ctx.lexed.text(*self).into() } - fn synthetic_id(&self, _ctx: &RawConvertor<'a>) -> Option { + fn synthetic_id(&self, _ctx: &RawConverter<'a>) -> Option { None } } -impl<'a> TokenConvertor for RawConvertor<'a> { +impl<'a> TokenConverter for RawConverter<'a> { type Token = usize; fn convert_doc_comment(&self, &token: &usize) -> Option> { @@ -504,7 +504,7 @@ impl<'a> TokenConvertor for RawConvertor<'a> { } } -struct Convertor { +struct Converter { id_alloc: TokenIdAlloc, current: Option, current_synthetic: Vec, @@ -515,7 +515,7 @@ struct Convertor { punct_offset: Option<(SyntaxToken, TextSize)>, } -impl Convertor { +impl Converter { fn new( node: &SyntaxNode, global_offset: TextSize, @@ -523,11 +523,11 @@ impl Convertor { next_id: u32, mut replace: FxHashMap>, mut append: FxHashMap>, - ) -> Convertor { + ) -> Converter { let range = node.text_range(); let mut preorder = node.preorder_with_tokens(); let (first, synthetic) = Self::next_token(&mut preorder, &mut replace, &mut append); - Convertor { + Converter { id_alloc: { TokenIdAlloc { map: existing_token_map, global_offset, next_id } }, current: first, current_synthetic: synthetic, @@ -590,15 +590,15 @@ impl SynToken { } } -impl SrcToken for SynToken { - fn kind(&self, _ctx: &Convertor) -> SyntaxKind { +impl SrcToken for SynToken { + fn kind(&self, _ctx: &Converter) -> SyntaxKind { match self { SynToken::Ordinary(token) => token.kind(), SynToken::Punch(token, _) => token.kind(), SynToken::Synthetic(token) => token.kind, } } - fn to_char(&self, _ctx: &Convertor) -> Option { + fn to_char(&self, _ctx: &Converter) -> Option { match self { SynToken::Ordinary(_) => None, SynToken::Punch(it, i) => it.text().chars().nth((*i).into()), @@ -606,7 +606,7 @@ impl SrcToken for SynToken { SynToken::Synthetic(_) => None, } } - fn to_text(&self, _ctx: &Convertor) -> SmolStr { + fn to_text(&self, _ctx: &Converter) -> SmolStr { match self { SynToken::Ordinary(token) => token.text().into(), SynToken::Punch(token, _) => token.text().into(), @@ -614,7 +614,7 @@ impl SrcToken for SynToken { } } - fn synthetic_id(&self, _ctx: &Convertor) -> Option { + fn synthetic_id(&self, _ctx: &Converter) -> Option { match self { SynToken::Synthetic(token) => Some(token.id), _ => None, @@ -622,7 +622,7 @@ impl SrcToken for SynToken { } } -impl TokenConvertor for Convertor { +impl TokenConverter for Converter { type Token = SynToken; fn convert_doc_comment(&self, token: &Self::Token) -> Option> { convert_doc_comment(token.token()?) From 41b0c54c071621b0c4fe664bfc0d3e973602d3ad Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Sat, 5 Nov 2022 19:01:26 +0900 Subject: [PATCH 10/81] Fix `tt::Punct`'s spacing calculation --- .../src/macro_expansion_tests/mbe/matching.rs | 10 +- .../src/macro_expansion_tests/proc_macros.rs | 6 +- crates/hir-expand/src/fixup.rs | 23 ++--- crates/mbe/src/syntax_bridge.rs | 47 ++++++++-- crates/mbe/src/syntax_bridge/tests.rs | 93 +++++++++++++++++++ 5 files changed, 152 insertions(+), 27 deletions(-) create mode 100644 crates/mbe/src/syntax_bridge/tests.rs diff --git a/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs b/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs index bc162d0fa2069..fc90c6e9f370f 100644 --- a/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs +++ b/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs @@ -94,11 +94,11 @@ macro_rules! m { ($($s:stmt)*) => (stringify!($($s |)*);) } stringify!(; -|; -|92|; -|let x = 92|; +| ; +|92| ; +|let x = 92| ; |loop {} -|; +| ; |); "#]], ); @@ -118,7 +118,7 @@ m!(.. .. ..); macro_rules! m { ($($p:pat)*) => (stringify!($($p |)*);) } -stringify!(.. .. ..|); +stringify!(.. .. .. |); "#]], ); } diff --git a/crates/hir-def/src/macro_expansion_tests/proc_macros.rs b/crates/hir-def/src/macro_expansion_tests/proc_macros.rs index 029821e5e87f6..118c14ed843fe 100644 --- a/crates/hir-def/src/macro_expansion_tests/proc_macros.rs +++ b/crates/hir-def/src/macro_expansion_tests/proc_macros.rs @@ -82,14 +82,14 @@ fn attribute_macro_syntax_completion_2() { #[proc_macros::identity_when_valid] fn foo() { bar.; blub } "#, - expect![[r##" + expect![[r#" #[proc_macros::identity_when_valid] fn foo() { bar.; blub } fn foo() { - bar.; + bar. ; blub -}"##]], +}"#]], ); } diff --git a/crates/hir-expand/src/fixup.rs b/crates/hir-expand/src/fixup.rs index 893e6fe4b8240..00b4cb3f96413 100644 --- a/crates/hir-expand/src/fixup.rs +++ b/crates/hir-expand/src/fixup.rs @@ -293,14 +293,10 @@ pub(crate) fn reverse_fixups( undo_info: &SyntaxFixupUndoInfo, ) { tt.token_trees.retain(|tt| match tt { - tt::TokenTree::Leaf(leaf) => { - token_map.synthetic_token_id(leaf.id()).is_none() - || token_map.synthetic_token_id(leaf.id()) != Some(EMPTY_ID) + tt::TokenTree::Leaf(leaf) => token_map.synthetic_token_id(leaf.id()) != Some(EMPTY_ID), + tt::TokenTree::Subtree(st) => { + st.delimiter.map_or(true, |d| token_map.synthetic_token_id(d.id) != Some(EMPTY_ID)) } - tt::TokenTree::Subtree(st) => st.delimiter.map_or(true, |d| { - token_map.synthetic_token_id(d.id).is_none() - || token_map.synthetic_token_id(d.id) != Some(EMPTY_ID) - }), }); tt.token_trees.iter_mut().for_each(|tt| match tt { tt::TokenTree::Subtree(tt) => reverse_fixups(tt, token_map, undo_info), @@ -339,9 +335,8 @@ mod tests { // the fixed-up tree should be syntactically valid let (parse, _) = mbe::token_tree_to_syntax_node(&tt, ::mbe::TopEntryPoint::MacroItems); - assert_eq!( - parse.errors(), - &[], + assert!( + parse.errors().is_empty(), "parse has syntax errors. parse tree:\n{:#?}", parse.syntax_node() ); @@ -468,12 +463,13 @@ fn foo() { } "#, expect![[r#" -fn foo () {a .__ra_fixup} +fn foo () {a . __ra_fixup} "#]], ) } #[test] + #[ignore] fn incomplete_field_expr_2() { check( r#" @@ -488,6 +484,7 @@ fn foo () {a .__ra_fixup ;} } #[test] + #[ignore] fn incomplete_field_expr_3() { check( r#" @@ -525,7 +522,7 @@ fn foo() { } "#, expect![[r#" -fn foo () {let x = a .__ra_fixup ;} +fn foo () {let x = a . __ra_fixup ;} "#]], ) } @@ -541,7 +538,7 @@ fn foo() { } "#, expect![[r#" -fn foo () {a .b ; bar () ;} +fn foo () {a . b ; bar () ;} "#]], ) } diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs index 1df3a6f56f07a..cf53c16726bf7 100644 --- a/crates/mbe/src/syntax_bridge.rs +++ b/crates/mbe/src/syntax_bridge.rs @@ -12,6 +12,9 @@ use tt::buffer::{Cursor, TokenBuffer}; use crate::{to_parser_input::to_parser_input, tt_iter::TtIter, TokenMap}; +#[cfg(test)] +mod tests; + /// Convert the syntax node to a `TokenTree` (what macro /// will consume). pub fn syntax_node_to_token_tree(node: &SyntaxNode) -> (tt::Subtree, TokenMap) { @@ -228,7 +231,7 @@ fn convert_tokens(conv: &mut C) -> tt::Subtree { } let spacing = match conv.peek().map(|next| next.kind(conv)) { - Some(kind) if !kind.is_trivia() => tt::Spacing::Joint, + Some(kind) if is_single_token_op(kind) => tt::Spacing::Joint, _ => tt::Spacing::Alone, }; let char = match token.to_char(conv) { @@ -307,6 +310,35 @@ fn convert_tokens(conv: &mut C) -> tt::Subtree { } } +fn is_single_token_op(kind: SyntaxKind) -> bool { + matches!( + kind, + EQ | L_ANGLE + | R_ANGLE + | BANG + | AMP + | PIPE + | TILDE + | AT + | DOT + | COMMA + | SEMICOLON + | COLON + | POUND + | DOLLAR + | QUESTION + | PLUS + | MINUS + | STAR + | SLASH + | PERCENT + | CARET + // LIFETIME_IDENT will be split into a sequence of `'` (a single quote) and an + // identifier. + | LIFETIME_IDENT + ) +} + /// Returns the textual content of a doc comment block as a quoted string /// That is, strips leading `///` (or `/**`, etc) /// and strips the ending `*/` @@ -591,10 +623,10 @@ impl SynToken { } impl SrcToken for SynToken { - fn kind(&self, _ctx: &Converter) -> SyntaxKind { + fn kind(&self, ctx: &Converter) -> SyntaxKind { match self { SynToken::Ordinary(token) => token.kind(), - SynToken::Punch(token, _) => token.kind(), + SynToken::Punch(..) => SyntaxKind::from_char(self.to_char(ctx).unwrap()).unwrap(), SynToken::Synthetic(token) => token.kind, } } @@ -651,7 +683,7 @@ impl TokenConverter for Converter { } let curr = self.current.clone()?; - if !&self.range.contains_range(curr.text_range()) { + if !self.range.contains_range(curr.text_range()) { return None; } let (new_current, new_synth) = @@ -809,12 +841,15 @@ impl<'a> TtTreeSink<'a> { let next = last.bump(); if let ( Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Punct(curr), _)), - Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Punct(_), _)), + Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Punct(next), _)), ) = (last.token_tree(), next.token_tree()) { // Note: We always assume the semi-colon would be the last token in // other parts of RA such that we don't add whitespace here. - if curr.spacing == tt::Spacing::Alone && curr.char != ';' { + // + // When `next` is a `Punct` of `'`, that's a part of a lifetime identifier so we don't + // need to add whitespace either. + if curr.spacing == tt::Spacing::Alone && curr.char != ';' && next.char != '\'' { self.inner.token(WHITESPACE, " "); self.text_pos += TextSize::of(' '); } diff --git a/crates/mbe/src/syntax_bridge/tests.rs b/crates/mbe/src/syntax_bridge/tests.rs new file mode 100644 index 0000000000000..4e04d2bc1c77b --- /dev/null +++ b/crates/mbe/src/syntax_bridge/tests.rs @@ -0,0 +1,93 @@ +use std::collections::HashMap; + +use syntax::{ast, AstNode}; +use test_utils::extract_annotations; +use tt::{ + buffer::{TokenBuffer, TokenTreeRef}, + Leaf, Punct, Spacing, +}; + +use super::syntax_node_to_token_tree; + +fn check_punct_spacing(fixture: &str) { + let source_file = ast::SourceFile::parse(fixture).ok().unwrap(); + let (subtree, token_map) = syntax_node_to_token_tree(source_file.syntax()); + let mut annotations: HashMap<_, _> = extract_annotations(fixture) + .into_iter() + .map(|(range, annotation)| { + let token = token_map.token_by_range(range).expect("no token found"); + let spacing = match annotation.as_str() { + "Alone" => Spacing::Alone, + "Joint" => Spacing::Joint, + a => panic!("unknown annotation: {}", a), + }; + (token, spacing) + }) + .collect(); + + let buf = TokenBuffer::from_subtree(&subtree); + let mut cursor = buf.begin(); + while !cursor.eof() { + while let Some(token_tree) = cursor.token_tree() { + if let TokenTreeRef::Leaf(Leaf::Punct(Punct { spacing, id, .. }), _) = token_tree { + if let Some(expected) = annotations.remove(&id) { + assert_eq!(expected, *spacing); + } + } + cursor = cursor.bump_subtree(); + } + cursor = cursor.bump(); + } + + assert!(annotations.is_empty(), "unchecked annotations: {:?}", annotations); +} + +#[test] +fn punct_spacing() { + check_punct_spacing( + r#" +fn main() { + 0+0; + //^ Alone + 0+(0); + //^ Alone + 0<=0; + //^ Joint + // ^ Alone + 0<=(0); + // ^ Alone + a=0; + //^ Alone + a=(0); + //^ Alone + a+=0; + //^ Joint + // ^ Alone + a+=(0); + // ^ Alone + a&&b; + //^ Joint + // ^ Alone + a&&(b); + // ^ Alone + foo::bar; + // ^ Joint + // ^ Alone + use foo::{bar,baz,}; + // ^ Alone + // ^ Alone + // ^ Alone + struct Struct<'a> {}; + // ^ Joint + // ^ Joint + Struct::<0>; + // ^ Alone + Struct::<{0}>; + // ^ Alone + ;; + //^ Joint + // ^ Alone +} + "#, + ); +} From 1dcc25a70afdc484081c0fc5cda1f8911d6660b8 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 5 Nov 2022 16:28:04 +0100 Subject: [PATCH 11/81] internal: Use a process group for flycheck --- Cargo.lock | 24 ++++++++++++++++++++++++ crates/flycheck/Cargo.toml | 1 + crates/flycheck/src/lib.rs | 19 +++++++++++-------- 3 files changed, 36 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8931c17bbdc16..c04906c453832 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -221,6 +221,16 @@ dependencies = [ "tracing", ] +[[package]] +name = "command-group" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7a8a86f409b4a59df3a3e4bee2de0b83f1755fdd2a25e3a9684c396fc4bed2c" +dependencies = [ + "nix", + "winapi", +] + [[package]] name = "countme" version = "3.0.1" @@ -390,6 +400,7 @@ name = "flycheck" version = "0.0.0" dependencies = [ "cargo_metadata", + "command-group", "crossbeam-channel", "jod-thread", "paths", @@ -970,6 +981,19 @@ dependencies = [ "windows-sys 0.28.0", ] +[[package]] +name = "nix" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4916f159ed8e5de0082076562152a76b7a1f64a01fd9d1e0fea002c37624faf" +dependencies = [ + "bitflags", + "cc", + "cfg-if", + "libc", + "memoffset", +] + [[package]] name = "notify" version = "5.0.0" diff --git a/crates/flycheck/Cargo.toml b/crates/flycheck/Cargo.toml index 2ad32d24837d7..6871f90015fed 100644 --- a/crates/flycheck/Cargo.toml +++ b/crates/flycheck/Cargo.toml @@ -17,6 +17,7 @@ rustc-hash = "1.1.0" serde = { version = "1.0.137", features = ["derive"] } serde_json = "1.0.86" jod-thread = "0.1.2" +command-group = "1.0.8" toolchain = { path = "../toolchain", version = "0.0.0" } stdx = { path = "../stdx", version = "0.0.0" } diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs index 8a91d6066614f..1758c9c27a24c 100644 --- a/crates/flycheck/src/lib.rs +++ b/crates/flycheck/src/lib.rs @@ -10,11 +10,12 @@ use std::{ time::Duration, }; +use command_group::{CommandGroup, GroupChild}; use crossbeam_channel::{never, select, unbounded, Receiver, Sender}; use paths::AbsPathBuf; use rustc_hash::FxHashMap; use serde::Deserialize; -use stdx::{process::streaming_output, JodChild}; +use stdx::process::streaming_output; pub use cargo_metadata::diagnostic::{ Applicability, Diagnostic, DiagnosticCode, DiagnosticLevel, DiagnosticSpan, @@ -359,6 +360,8 @@ impl FlycheckActor { } } +struct JodChild(GroupChild); + /// A handle to a cargo process used for fly-checking. struct CargoHandle { /// The handle to the actual cargo process. As we cannot cancel directly from with @@ -371,10 +374,10 @@ struct CargoHandle { impl CargoHandle { fn spawn(mut command: Command) -> std::io::Result { command.stdout(Stdio::piped()).stderr(Stdio::piped()).stdin(Stdio::null()); - let mut child = JodChild::spawn(command)?; + let mut child = command.group_spawn().map(JodChild)?; - let stdout = child.stdout.take().unwrap(); - let stderr = child.stderr.take().unwrap(); + let stdout = child.0.inner().stdout.take().unwrap(); + let stderr = child.0.inner().stderr.take().unwrap(); let (sender, receiver) = unbounded(); let actor = CargoActor::new(sender, stdout, stderr); @@ -386,13 +389,13 @@ impl CargoHandle { } fn cancel(mut self) { - let _ = self.child.kill(); - let _ = self.child.wait(); + let _ = self.child.0.kill(); + let _ = self.child.0.wait(); } fn join(mut self) -> io::Result<()> { - let _ = self.child.kill(); - let exit_status = self.child.wait()?; + let _ = self.child.0.kill(); + let exit_status = self.child.0.wait()?; let (read_at_least_one_message, error) = self.thread.join()?; if read_at_least_one_message || exit_status.success() { Ok(()) From cff7ab1308906dc45f11967be65ac752f0ea2994 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Mon, 7 Nov 2022 12:53:33 +0200 Subject: [PATCH 12/81] Fix typos --- crates/flycheck/src/lib.rs | 2 +- crates/hir-expand/src/lib.rs | 4 ++-- crates/rust-analyzer/src/config.rs | 2 +- crates/rust-analyzer/src/line_index.rs | 2 +- crates/syntax/src/tests/sourcegen_ast.rs | 2 +- docs/user/generated_config.adoc | 2 +- editors/code/package.json | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs index 1758c9c27a24c..ff507a52d550d 100644 --- a/crates/flycheck/src/lib.rs +++ b/crates/flycheck/src/lib.rs @@ -365,7 +365,7 @@ struct JodChild(GroupChild); /// A handle to a cargo process used for fly-checking. struct CargoHandle { /// The handle to the actual cargo process. As we cannot cancel directly from with - /// a read syscall dropping and therefor terminating the process is our best option. + /// a read syscall dropping and therefore terminating the process is our best option. child: JodChild, thread: jod_thread::JoinHandle>, receiver: Receiver, diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs index a5b499fe8d9d4..7352b003a491c 100644 --- a/crates/hir-expand/src/lib.rs +++ b/crates/hir-expand/src/lib.rs @@ -814,7 +814,7 @@ impl<'a> InFile<&'a SyntaxNode> { pub fn original_syntax_node(self, db: &dyn db::AstDatabase) -> Option> { // This kind of upmapping can only be achieved in attribute expanded files, - // as we don't have node inputs otherwise and therefor can't find an `N` node in the input + // as we don't have node inputs otherwise and therefore can't find an `N` node in the input if !self.file_id.is_macro() { return Some(self.map(Clone::clone)); } else if !self.file_id.is_attr_macro(db) { @@ -926,7 +926,7 @@ impl InFile { pub fn original_ast_node(self, db: &dyn db::AstDatabase) -> Option> { // This kind of upmapping can only be achieved in attribute expanded files, - // as we don't have node inputs otherwise and therefor can't find an `N` node in the input + // as we don't have node inputs otherwise and therefore can't find an `N` node in the input if !self.file_id.is_macro() { return Some(self); } else if !self.file_id.is_attr_macro(db) { diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 4072ae585dbd9..c278ba2d7c5b3 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -157,7 +157,7 @@ config_data! { checkOnSave_noDefaultFeatures: Option = "null", /// Override the command rust-analyzer uses instead of `cargo check` for /// diagnostics on save. The command is required to output json and - /// should therefor include `--message-format=json` or a similar option. + /// should therefore include `--message-format=json` or a similar option. /// /// If you're changing this because you're using some tool wrapping /// Cargo, you might also want to change diff --git a/crates/rust-analyzer/src/line_index.rs b/crates/rust-analyzer/src/line_index.rs index 7636c3da7f9af..2945dba12f255 100644 --- a/crates/rust-analyzer/src/line_index.rs +++ b/crates/rust-analyzer/src/line_index.rs @@ -42,7 +42,7 @@ impl LineEndings { loop { let idx = match find_crlf(&tail[gap_len..]) { None if crlf_seen => tail.len(), - // SAFETY: buf is unchanged and therefor still contains utf8 data + // SAFETY: buf is unchanged and therefore still contains utf8 data None => return (unsafe { String::from_utf8_unchecked(buf) }, LineEndings::Unix), Some(idx) => { crlf_seen = true; diff --git a/crates/syntax/src/tests/sourcegen_ast.rs b/crates/syntax/src/tests/sourcegen_ast.rs index 70b54843dbaab..712ef5f63b651 100644 --- a/crates/syntax/src/tests/sourcegen_ast.rs +++ b/crates/syntax/src/tests/sourcegen_ast.rs @@ -86,7 +86,7 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> String { .traits .iter() .filter(|trait_name| { - // Loops have two expressions so this might collide, therefor manual impl it + // Loops have two expressions so this might collide, therefore manual impl it node.name != "ForExpr" && node.name != "WhileExpr" || trait_name.as_str() != "HasLoopBody" }) diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index 36794efe42726..f171eb41bfd73 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc @@ -173,7 +173,7 @@ Whether to pass `--no-default-features` to Cargo. Defaults to -- Override the command rust-analyzer uses instead of `cargo check` for diagnostics on save. The command is required to output json and -should therefor include `--message-format=json` or a similar option. +should therefore include `--message-format=json` or a similar option. If you're changing this because you're using some tool wrapping Cargo, you might also want to change diff --git a/editors/code/package.json b/editors/code/package.json index 1a97a9c089375..4357dc73067fd 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -623,7 +623,7 @@ ] }, "rust-analyzer.checkOnSave.overrideCommand": { - "markdownDescription": "Override the command rust-analyzer uses instead of `cargo check` for\ndiagnostics on save. The command is required to output json and\nshould therefor include `--message-format=json` or a similar option.\n\nIf you're changing this because you're using some tool wrapping\nCargo, you might also want to change\n`#rust-analyzer.cargo.buildScripts.overrideCommand#`.\n\nIf there are multiple linked projects, this command is invoked for\neach of them, with the working directory being the project root\n(i.e., the folder containing the `Cargo.toml`).\n\nAn example command would be:\n\n```bash\ncargo check --workspace --message-format=json --all-targets\n```\n.", + "markdownDescription": "Override the command rust-analyzer uses instead of `cargo check` for\ndiagnostics on save. The command is required to output json and\nshould therefore include `--message-format=json` or a similar option.\n\nIf you're changing this because you're using some tool wrapping\nCargo, you might also want to change\n`#rust-analyzer.cargo.buildScripts.overrideCommand#`.\n\nIf there are multiple linked projects, this command is invoked for\neach of them, with the working directory being the project root\n(i.e., the folder containing the `Cargo.toml`).\n\nAn example command would be:\n\n```bash\ncargo check --workspace --message-format=json --all-targets\n```\n.", "default": null, "type": [ "null", From f24fbc20274962860e15e1160bfdaade543092bf Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 7 Nov 2022 11:58:57 +0100 Subject: [PATCH 13/81] rustfmt --- crates/ide-assists/src/handlers/extract_function.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/crates/ide-assists/src/handlers/extract_function.rs b/crates/ide-assists/src/handlers/extract_function.rs index c40fb291a32a2..f24a6aacc900a 100644 --- a/crates/ide-assists/src/handlers/extract_function.rs +++ b/crates/ide-assists/src/handlers/extract_function.rs @@ -127,10 +127,8 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op builder.replace(target_range, make_call(ctx, &fun, old_indent)); - let has_impl_wrapper = insert_after - .ancestors() - .find(|a| a.kind() == SyntaxKind::IMPL && a != &insert_after) - .is_some(); + let has_impl_wrapper = + insert_after.ancestors().any(|a| a.kind() == SyntaxKind::IMPL && a != insert_after); let fn_def = match fun.self_param_adt(ctx) { Some(adt) if anchor == Anchor::Method && !has_impl_wrapper => { @@ -1250,8 +1248,7 @@ fn node_to_insert_after(body: &FunctionBody, anchor: Anchor) -> Option { if body.extracted_from_trait_impl() && matches!(anchor, Anchor::Method) { let impl_node = find_non_trait_impl(&next_ancestor); - let target_node = impl_node.as_ref().and_then(last_impl_member); - if target_node.is_some() { + if let target_node @ Some(_) = impl_node.as_ref().and_then(last_impl_member) { return target_node; } } @@ -1281,7 +1278,8 @@ fn find_non_trait_impl(trait_impl: &SyntaxNode) -> Option { let impl_type = Some(impl_type_name(&as_impl)?); let sibblings = trait_impl.parent()?.children(); - sibblings.filter_map(ast::Impl::cast) + sibblings + .filter_map(ast::Impl::cast) .find(|s| impl_type_name(s) == impl_type && !is_trait_impl(s)) } From 8ad4a1d1187326e66a0de73133ea7197992c3837 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 7 Nov 2022 11:45:52 +0100 Subject: [PATCH 14/81] Update sysroot crates --- crates/project-model/src/sysroot.rs | 27 +++++++---- crates/project-model/src/tests.rs | 71 ++++++----------------------- 2 files changed, 31 insertions(+), 67 deletions(-) diff --git a/crates/project-model/src/sysroot.rs b/crates/project-model/src/sysroot.rs index fa8d76f3f4529..f6c09a27c9d7e 100644 --- a/crates/project-model/src/sysroot.rs +++ b/crates/project-model/src/sysroot.rs @@ -128,14 +128,18 @@ impl Sysroot { } if let Some(alloc) = sysroot.by_name("alloc") { - if let Some(core) = sysroot.by_name("core") { - sysroot.crates[alloc].deps.push(core); + for dep in ALLOC_DEPS.trim().lines() { + if let Some(dep) = sysroot.by_name(dep) { + sysroot.crates[alloc].deps.push(dep) + } } } if let Some(proc_macro) = sysroot.by_name("proc_macro") { - if let Some(std) = sysroot.by_name("std") { - sysroot.crates[proc_macro].deps.push(std); + for dep in PROC_MACRO_DEPS.trim().lines() { + if let Some(dep) = sysroot.by_name(dep) { + sysroot.crates[proc_macro].deps.push(dep) + } } } @@ -239,6 +243,7 @@ fn get_rust_src(sysroot_path: &AbsPath) -> Option { const SYSROOT_CRATES: &str = " alloc +backtrace core panic_abort panic_unwind @@ -246,17 +251,19 @@ proc_macro profiler_builtins std stdarch/crates/std_detect -term test unwind"; +const ALLOC_DEPS: &str = "core"; + const STD_DEPS: &str = " alloc -core -panic_abort panic_unwind +panic_abort +core profiler_builtins +unwind std_detect -term -test -unwind"; +test"; + +const PROC_MACRO_DEPS: &str = "std"; diff --git a/crates/project-model/src/tests.rs b/crates/project-model/src/tests.rs index e2444e24974a7..a1cb438bddc4c 100644 --- a/crates/project-model/src/tests.rs +++ b/crates/project-model/src/tests.rs @@ -1566,10 +1566,10 @@ fn rust_project_hello_world_project_model() { }, Dependency { crate_id: CrateId( - 1, + 3, ), name: CrateName( - "core", + "panic_unwind", ), prelude: true, }, @@ -1584,10 +1584,10 @@ fn rust_project_hello_world_project_model() { }, Dependency { crate_id: CrateId( - 3, + 1, ), name: CrateName( - "panic_unwind", + "core", ), prelude: true, }, @@ -1602,40 +1602,31 @@ fn rust_project_hello_world_project_model() { }, Dependency { crate_id: CrateId( - 7, + 9, ), name: CrateName( - "std_detect", + "unwind", ), prelude: true, }, Dependency { crate_id: CrateId( - 8, + 7, ), name: CrateName( - "term", + "std_detect", ), prelude: true, }, Dependency { crate_id: CrateId( - 9, + 8, ), name: CrateName( "test", ), prelude: true, }, - Dependency { - crate_id: CrateId( - 10, - ), - name: CrateName( - "unwind", - ), - prelude: true, - }, ], proc_macro: Err( "no proc macro loaded for sysroot crate", @@ -1687,40 +1678,6 @@ fn rust_project_hello_world_project_model() { ), edition: Edition2018, version: None, - display_name: Some( - CrateDisplayName { - crate_name: CrateName( - "term", - ), - canonical_name: "term", - }, - ), - cfg_options: CfgOptions( - [], - ), - potential_cfg_options: CfgOptions( - [], - ), - env: Env { - entries: {}, - }, - dependencies: [], - proc_macro: Err( - "no proc macro loaded for sysroot crate", - ), - origin: Lang( - Other, - ), - is_proc_macro: false, - }, - CrateId( - 9, - ): CrateData { - root_file_id: FileId( - 10, - ), - edition: Edition2018, - version: None, display_name: Some( CrateDisplayName { crate_name: CrateName( @@ -1748,10 +1705,10 @@ fn rust_project_hello_world_project_model() { is_proc_macro: false, }, CrateId( - 10, + 9, ): CrateData { root_file_id: FileId( - 11, + 10, ), edition: Edition2018, version: None, @@ -1782,10 +1739,10 @@ fn rust_project_hello_world_project_model() { is_proc_macro: false, }, CrateId( - 11, + 10, ): CrateData { root_file_id: FileId( - 12, + 11, ), edition: Edition2018, version: None, @@ -1836,7 +1793,7 @@ fn rust_project_hello_world_project_model() { }, Dependency { crate_id: CrateId( - 9, + 8, ), name: CrateName( "test", From 180b4cedec730d0c0127d0d41714abe4176d5365 Mon Sep 17 00:00:00 2001 From: Noritada Kobayashi Date: Mon, 7 Nov 2022 19:25:07 +0900 Subject: [PATCH 15/81] Fix the length displayed for byte string literals with escaped newlines The length of byte strings containing escaped newlines is displayed two bytes longer when the first escaped character is a newline. This is due to a small bug in handling the first escaped newline in string literals. Closes #13567 --- crates/syntax/src/ast/token_ext.rs | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs index ba72e64425b23..22ad6db9aef37 100644 --- a/crates/syntax/src/ast/token_ext.rs +++ b/crates/syntax/src/ast/token_ext.rs @@ -209,17 +209,19 @@ impl ast::String { let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()]; let mut buf = String::new(); - let mut text_iter = text.chars(); + let mut prev = 0; let mut has_error = false; unescape_literal(text, Mode::Str, &mut |char_range, unescaped_char| match ( unescaped_char, buf.capacity() == 0, ) { (Ok(c), false) => buf.push(c), - (Ok(c), true) if char_range.len() == 1 && Some(c) == text_iter.next() => (), + (Ok(_), true) if char_range.len() == 1 && char_range.start == prev => { + prev = char_range.end + } (Ok(c), true) => { buf.reserve_exact(text.len()); - buf.push_str(&text[..char_range.start]); + buf.push_str(&text[..prev]); buf.push(c); } (Err(_), _) => has_error = true, @@ -252,17 +254,19 @@ impl ast::ByteString { let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()]; let mut buf: Vec = Vec::new(); - let mut text_iter = text.chars(); + let mut prev = 0; let mut has_error = false; unescape_literal(text, Mode::ByteStr, &mut |char_range, unescaped_char| match ( unescaped_char, buf.capacity() == 0, ) { (Ok(c), false) => buf.push(c as u8), - (Ok(c), true) if char_range.len() == 1 && Some(c) == text_iter.next() => (), + (Ok(_), true) if char_range.len() == 1 && char_range.start == prev => { + prev = char_range.end + } (Ok(c), true) => { buf.reserve_exact(text.len()); - buf.extend_from_slice(text[..char_range.start].as_bytes()); + buf.extend_from_slice(text[..prev].as_bytes()); buf.push(c as u8); } (Err(_), _) => has_error = true, @@ -445,6 +449,12 @@ mod tests { check_string_value(r"\foobar", None); check_string_value(r"\nfoobar", "\nfoobar"); check_string_value(r"C:\\Windows\\System32\\", "C:\\Windows\\System32\\"); + check_string_value(r"\x61bcde", "a\x62cde"); + check_string_value( + r"a\ +bcde", "a\ +bcde", + ); } #[test] From ee2dd934caeeb2fb044ac1cacd3e65c3b033bc8b Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 7 Nov 2022 12:49:52 +0100 Subject: [PATCH 16/81] Don't trigger adjustment hints in all inlay hint tests --- crates/ide/src/inlay_hints.rs | 37 +++++++++++++++++------------------ 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 50934a27f89e3..325e609054dc8 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -861,23 +861,23 @@ fn binding_mode_hints( tooltip: Some(InlayTooltip::String("Inferred binding mode".into())), }); }); - // match pat { - // ast::Pat::IdentPat(pat) if pat.ref_token().is_none() && pat.mut_token().is_none() => { - // let bm = sema.binding_mode_of_pat(pat)?; - // let bm = match bm { - // hir::BindingMode::Move => return None, - // hir::BindingMode::Ref(Mutability::Mut) => "ref mut", - // hir::BindingMode::Ref(Mutability::Shared) => "ref", - // }; - // acc.push(InlayHint { - // range, - // kind: InlayKind::BindingModeHint, - // label: bm.to_string().into(), - // tooltip: Some(InlayTooltip::String("Inferred binding mode".into())), - // }); - // } - // _ => (), - // } + match pat { + ast::Pat::IdentPat(pat) if pat.ref_token().is_none() && pat.mut_token().is_none() => { + let bm = sema.binding_mode_of_pat(pat)?; + let bm = match bm { + hir::BindingMode::Move => return None, + hir::BindingMode::Ref(Mutability::Mut) => "ref mut", + hir::BindingMode::Ref(Mutability::Shared) => "ref", + }; + acc.push(InlayHint { + range, + kind: InlayKind::BindingModeHint, + label: bm.to_string().into(), + tooltip: Some(InlayTooltip::String("Inferred binding mode".into())), + }); + } + _ => (), + } Some(()) } @@ -1306,7 +1306,7 @@ mod tests { chaining_hints: false, lifetime_elision_hints: LifetimeElisionHints::Never, closure_return_type_hints: ClosureReturnTypeHints::Never, - adjustment_hints: AdjustmentHints::Always, + adjustment_hints: AdjustmentHints::Never, binding_mode_hints: false, hide_named_constructor_hints: false, hide_closure_initialization_hints: false, @@ -1318,7 +1318,6 @@ mod tests { type_hints: true, parameter_hints: true, chaining_hints: true, - adjustment_hints: AdjustmentHints::Always, closure_return_type_hints: ClosureReturnTypeHints::WithBlock, binding_mode_hints: true, lifetime_elision_hints: LifetimeElisionHints::Always, From ffd7bf8bf9c99d115e7e0c4e6d1cffe60ea3ff84 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 7 Nov 2022 12:59:51 +0100 Subject: [PATCH 17/81] Bump Cargo rust-version fields to latest stable --- crates/base-db/Cargo.toml | 2 +- crates/cfg/Cargo.toml | 2 +- crates/flycheck/Cargo.toml | 2 +- crates/hir-def/Cargo.toml | 2 +- crates/hir-expand/Cargo.toml | 2 +- crates/hir-ty/Cargo.toml | 2 +- crates/hir/Cargo.toml | 2 +- crates/ide-assists/Cargo.toml | 2 +- crates/ide-completion/Cargo.toml | 2 +- crates/ide-db/Cargo.toml | 2 +- crates/ide-diagnostics/Cargo.toml | 2 +- crates/ide-ssr/Cargo.toml | 2 +- crates/ide/Cargo.toml | 2 +- crates/limit/Cargo.toml | 2 +- crates/mbe/Cargo.toml | 2 +- crates/parser/Cargo.toml | 2 +- crates/paths/Cargo.toml | 2 +- crates/proc-macro-api/Cargo.toml | 2 +- crates/proc-macro-srv-cli/Cargo.toml | 2 +- crates/proc-macro-srv/Cargo.toml | 2 +- crates/proc-macro-test/Cargo.toml | 2 +- crates/proc-macro-test/imp/Cargo.toml | 2 +- crates/profile/Cargo.toml | 2 +- crates/project-model/Cargo.toml | 2 +- crates/rust-analyzer/Cargo.toml | 2 +- crates/sourcegen/Cargo.toml | 2 +- crates/stdx/Cargo.toml | 2 +- crates/syntax/Cargo.toml | 2 +- crates/syntax/fuzz/Cargo.toml | 2 +- crates/test-utils/Cargo.toml | 2 +- crates/text-edit/Cargo.toml | 2 +- crates/toolchain/Cargo.toml | 2 +- crates/tt/Cargo.toml | 2 +- crates/vfs-notify/Cargo.toml | 2 +- crates/vfs/Cargo.toml | 2 +- xtask/Cargo.toml | 2 +- 36 files changed, 36 insertions(+), 36 deletions(-) diff --git a/crates/base-db/Cargo.toml b/crates/base-db/Cargo.toml index f02a51ab6c47f..a484ecec68250 100644 --- a/crates/base-db/Cargo.toml +++ b/crates/base-db/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/cfg/Cargo.toml b/crates/cfg/Cargo.toml index ee1ad677a95f2..2857420c285a7 100644 --- a/crates/cfg/Cargo.toml +++ b/crates/cfg/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/flycheck/Cargo.toml b/crates/flycheck/Cargo.toml index 6871f90015fed..514d567fcce75 100644 --- a/crates/flycheck/Cargo.toml +++ b/crates/flycheck/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/hir-def/Cargo.toml b/crates/hir-def/Cargo.toml index 4ad8e75970b59..22f98ea7cd450 100644 --- a/crates/hir-def/Cargo.toml +++ b/crates/hir-def/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/hir-expand/Cargo.toml b/crates/hir-expand/Cargo.toml index 3359c99b3961c..77eb1fd450433 100644 --- a/crates/hir-expand/Cargo.toml +++ b/crates/hir-expand/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/hir-ty/Cargo.toml b/crates/hir-ty/Cargo.toml index ed13275bab8fe..a1d6835bfaed3 100644 --- a/crates/hir-ty/Cargo.toml +++ b/crates/hir-ty/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/hir/Cargo.toml b/crates/hir/Cargo.toml index e1418de3cdc24..f780e3f53c855 100644 --- a/crates/hir/Cargo.toml +++ b/crates/hir/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/ide-assists/Cargo.toml b/crates/ide-assists/Cargo.toml index 57a41f3d9a937..e781c0a016d5a 100644 --- a/crates/ide-assists/Cargo.toml +++ b/crates/ide-assists/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/ide-completion/Cargo.toml b/crates/ide-completion/Cargo.toml index 75835bce95da1..11310e2f1291e 100644 --- a/crates/ide-completion/Cargo.toml +++ b/crates/ide-completion/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/ide-db/Cargo.toml b/crates/ide-db/Cargo.toml index cf0bcd5c96b2a..f48cce58c6e73 100644 --- a/crates/ide-db/Cargo.toml +++ b/crates/ide-db/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/ide-diagnostics/Cargo.toml b/crates/ide-diagnostics/Cargo.toml index e1d146f4ee561..7e9a1125d751c 100644 --- a/crates/ide-diagnostics/Cargo.toml +++ b/crates/ide-diagnostics/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/ide-ssr/Cargo.toml b/crates/ide-ssr/Cargo.toml index 4baf786c45552..7be62a8d9ffe9 100644 --- a/crates/ide-ssr/Cargo.toml +++ b/crates/ide-ssr/Cargo.toml @@ -5,7 +5,7 @@ description = "Structural search and replace of Rust code" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/rust-analyzer" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/ide/Cargo.toml b/crates/ide/Cargo.toml index 712459a7ee9c6..73f202630f15b 100644 --- a/crates/ide/Cargo.toml +++ b/crates/ide/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/limit/Cargo.toml b/crates/limit/Cargo.toml index 893db436d8b73..3536f73da73e3 100644 --- a/crates/limit/Cargo.toml +++ b/crates/limit/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [features] tracking = [] diff --git a/crates/mbe/Cargo.toml b/crates/mbe/Cargo.toml index 13cd8901031d5..bce2fc9a70e82 100644 --- a/crates/mbe/Cargo.toml +++ b/crates/mbe/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/parser/Cargo.toml b/crates/parser/Cargo.toml index a286a6bcdddec..d1420de8937a0 100644 --- a/crates/parser/Cargo.toml +++ b/crates/parser/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/paths/Cargo.toml b/crates/paths/Cargo.toml index 5e83de7d994e0..d23a63d2a973d 100644 --- a/crates/paths/Cargo.toml +++ b/crates/paths/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/proc-macro-api/Cargo.toml b/crates/proc-macro-api/Cargo.toml index 54879c1870c05..f261f3def45d6 100644 --- a/crates/proc-macro-api/Cargo.toml +++ b/crates/proc-macro-api/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/proc-macro-srv-cli/Cargo.toml b/crates/proc-macro-srv-cli/Cargo.toml index 9d0da5dee9c10..7991e125ab83c 100644 --- a/crates/proc-macro-srv-cli/Cargo.toml +++ b/crates/proc-macro-srv-cli/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [dependencies] proc-macro-srv = { version = "0.0.0", path = "../proc-macro-srv" } diff --git a/crates/proc-macro-srv/Cargo.toml b/crates/proc-macro-srv/Cargo.toml index e39026ac70bfd..a136abc12b756 100644 --- a/crates/proc-macro-srv/Cargo.toml +++ b/crates/proc-macro-srv/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/proc-macro-test/Cargo.toml b/crates/proc-macro-test/Cargo.toml index 684477191b276..d2a79f91074a1 100644 --- a/crates/proc-macro-test/Cargo.toml +++ b/crates/proc-macro-test/Cargo.toml @@ -3,7 +3,7 @@ name = "proc-macro-test" version = "0.0.0" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" publish = false [lib] diff --git a/crates/proc-macro-test/imp/Cargo.toml b/crates/proc-macro-test/imp/Cargo.toml index 2d1fc3c5c7a3b..1bd14070e90da 100644 --- a/crates/proc-macro-test/imp/Cargo.toml +++ b/crates/proc-macro-test/imp/Cargo.toml @@ -3,7 +3,7 @@ name = "proc-macro-test-impl" version = "0.0.0" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" publish = false [lib] diff --git a/crates/profile/Cargo.toml b/crates/profile/Cargo.toml index 5697aea964f78..01d1735bf7843 100644 --- a/crates/profile/Cargo.toml +++ b/crates/profile/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/project-model/Cargo.toml b/crates/project-model/Cargo.toml index cf9868740cb03..39902a53214d0 100644 --- a/crates/project-model/Cargo.toml +++ b/crates/project-model/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index 7ae5324ab051a..56f14fe187490 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml @@ -8,7 +8,7 @@ documentation = "https://rust-analyzer.github.io/manual.html" license = "MIT OR Apache-2.0" autobins = false edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/sourcegen/Cargo.toml b/crates/sourcegen/Cargo.toml index e75867e2d81cf..593dc4e55b21b 100644 --- a/crates/sourcegen/Cargo.toml +++ b/crates/sourcegen/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/stdx/Cargo.toml b/crates/stdx/Cargo.toml index e0657ab0f6d1c..957d16c036fab 100644 --- a/crates/stdx/Cargo.toml +++ b/crates/stdx/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml index 1ef903371cf89..00743cca55934 100644 --- a/crates/syntax/Cargo.toml +++ b/crates/syntax/Cargo.toml @@ -5,7 +5,7 @@ description = "Comment and whitespace preserving parser for the Rust language" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/rust-analyzer" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/syntax/fuzz/Cargo.toml b/crates/syntax/fuzz/Cargo.toml index ba2f515b0bc1b..f295c40065dbd 100644 --- a/crates/syntax/fuzz/Cargo.toml +++ b/crates/syntax/fuzz/Cargo.toml @@ -4,7 +4,7 @@ name = "syntax-fuzz" version = "0.0.1" publish = false edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [package.metadata] cargo-fuzz = true diff --git a/crates/test-utils/Cargo.toml b/crates/test-utils/Cargo.toml index cceafe04e3777..1047373b1c75e 100644 --- a/crates/test-utils/Cargo.toml +++ b/crates/test-utils/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/text-edit/Cargo.toml b/crates/text-edit/Cargo.toml index 7a90d64a98ba9..8df7e1af61163 100644 --- a/crates/text-edit/Cargo.toml +++ b/crates/text-edit/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/toolchain/Cargo.toml b/crates/toolchain/Cargo.toml index 3e0f31f19c507..a6a3ae742aeb3 100644 --- a/crates/toolchain/Cargo.toml +++ b/crates/toolchain/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/tt/Cargo.toml b/crates/tt/Cargo.toml index 52dfb86080418..4f2103f3a97fc 100644 --- a/crates/tt/Cargo.toml +++ b/crates/tt/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/vfs-notify/Cargo.toml b/crates/vfs-notify/Cargo.toml index df5dc24e2cd12..061f3c157a88c 100644 --- a/crates/vfs-notify/Cargo.toml +++ b/crates/vfs-notify/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/crates/vfs/Cargo.toml b/crates/vfs/Cargo.toml index d7549a2841539..e55bf6f293c43 100644 --- a/crates/vfs/Cargo.toml +++ b/crates/vfs/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" description = "TBD" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [lib] doctest = false diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index 0be0bf920de9d..95e27beab5dc1 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" publish = false license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [dependencies] anyhow = "1.0.62" From bdf854701375c0692f9014db71a097520fddd41f Mon Sep 17 00:00:00 2001 From: Noritada Kobayashi Date: Mon, 7 Nov 2022 22:51:29 +0900 Subject: [PATCH 18/81] Clarify the intent Thanks to Lukas Wirth for a suggestion. --- crates/syntax/src/ast/token_ext.rs | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs index 22ad6db9aef37..32dd2db405c89 100644 --- a/crates/syntax/src/ast/token_ext.rs +++ b/crates/syntax/src/ast/token_ext.rs @@ -209,19 +209,19 @@ impl ast::String { let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()]; let mut buf = String::new(); - let mut prev = 0; + let mut prev_end = 0; let mut has_error = false; unescape_literal(text, Mode::Str, &mut |char_range, unescaped_char| match ( unescaped_char, buf.capacity() == 0, ) { (Ok(c), false) => buf.push(c), - (Ok(_), true) if char_range.len() == 1 && char_range.start == prev => { - prev = char_range.end + (Ok(_), true) if char_range.len() == 1 && char_range.start == prev_end => { + prev_end = char_range.end } (Ok(c), true) => { buf.reserve_exact(text.len()); - buf.push_str(&text[..prev]); + buf.push_str(&text[..prev_end]); buf.push(c); } (Err(_), _) => has_error = true, @@ -254,19 +254,19 @@ impl ast::ByteString { let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()]; let mut buf: Vec = Vec::new(); - let mut prev = 0; + let mut prev_end = 0; let mut has_error = false; unescape_literal(text, Mode::ByteStr, &mut |char_range, unescaped_char| match ( unescaped_char, buf.capacity() == 0, ) { (Ok(c), false) => buf.push(c as u8), - (Ok(_), true) if char_range.len() == 1 && char_range.start == prev => { - prev = char_range.end + (Ok(_), true) if char_range.len() == 1 && char_range.start == prev_end => { + prev_end = char_range.end } (Ok(c), true) => { buf.reserve_exact(text.len()); - buf.extend_from_slice(text[..prev].as_bytes()); + buf.extend_from_slice(text[..prev_end].as_bytes()); buf.push(c as u8); } (Err(_), _) => has_error = true, @@ -449,11 +449,10 @@ mod tests { check_string_value(r"\foobar", None); check_string_value(r"\nfoobar", "\nfoobar"); check_string_value(r"C:\\Windows\\System32\\", "C:\\Windows\\System32\\"); - check_string_value(r"\x61bcde", "a\x62cde"); + check_string_value(r"\x61bcde", "abcde"); check_string_value( r"a\ -bcde", "a\ -bcde", +bcde", "abcde", ); } From 2340d7059e3b89a5233b0c91cf3c36fa94adfe6e Mon Sep 17 00:00:00 2001 From: Noritada Kobayashi Date: Mon, 7 Nov 2022 23:39:02 +0900 Subject: [PATCH 19/81] Add test code for unescaping byte strings --- crates/syntax/src/ast/token_ext.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs index 32dd2db405c89..8990f7a7d4e8e 100644 --- a/crates/syntax/src/ast/token_ext.rs +++ b/crates/syntax/src/ast/token_ext.rs @@ -456,6 +456,31 @@ bcde", "abcde", ); } + fn check_byte_string_value<'a, const N: usize>( + lit: &str, + expected: impl Into>, + ) { + assert_eq!( + ast::ByteString { syntax: make::tokens::literal(&format!("b\"{}\"", lit)) } + .value() + .as_deref(), + expected.into().map(|value| &value[..]) + ); + } + + #[test] + fn test_byte_string_escape() { + check_byte_string_value(r"foobar", b"foobar"); + check_byte_string_value(r"\foobar", None::<&[u8; 0]>); + check_byte_string_value(r"\nfoobar", b"\nfoobar"); + check_byte_string_value(r"C:\\Windows\\System32\\", b"C:\\Windows\\System32\\"); + check_byte_string_value(r"\x61bcde", b"abcde"); + check_byte_string_value( + r"a\ +bcde", b"abcde", + ); + } + #[test] fn test_value_underscores() { check_float_value("3.141592653589793_f64", 3.141592653589793_f64); From b169e1e5decbbda7ad09a8fa07fb32ca83ec7a50 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 7 Nov 2022 15:49:26 +0100 Subject: [PATCH 20/81] Remove code duplication --- crates/ide/src/moniker.rs | 20 ++++---------------- crates/ide/src/static_index.rs | 5 +++-- 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/crates/ide/src/moniker.rs b/crates/ide/src/moniker.rs index 07d117aff10bd..fcbf6d8e58c4b 100644 --- a/crates/ide/src/moniker.rs +++ b/crates/ide/src/moniker.rs @@ -1,9 +1,9 @@ //! This module generates [moniker](https://microsoft.github.io/language-server-protocol/specifications/lsif/0.6.0/specification/#exportsImports) //! for LSIF and LSP. -use hir::{db::DefDatabase, AsAssocItem, AssocItemContainer, Crate, Name, Semantics}; +use hir::{AsAssocItem, AssocItemContainer, Crate, Name, Semantics}; use ide_db::{ - base_db::{CrateOrigin, FileId, FileLoader, FilePosition, LangCrateOrigin}, + base_db::{CrateOrigin, FilePosition, LangCrateOrigin}, defs::{Definition, IdentClass}, helpers::pick_best_token, RootDatabase, @@ -11,7 +11,7 @@ use ide_db::{ use itertools::Itertools; use syntax::{AstNode, SyntaxKind::*, T}; -use crate::{doc_links::token_as_doc_comment, RangeInfo}; +use crate::{doc_links::token_as_doc_comment, parent_module::crates_for, RangeInfo}; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum MonikerDescriptorKind { @@ -77,25 +77,13 @@ pub struct PackageInformation { pub version: Option, } -pub(crate) fn crate_for_file(db: &RootDatabase, file_id: FileId) -> Option { - for &krate in db.relevant_crates(file_id).iter() { - let crate_def_map = db.crate_def_map(krate); - for (_, data) in crate_def_map.modules() { - if data.origin.file_id() == Some(file_id) { - return Some(krate.into()); - } - } - } - None -} - pub(crate) fn moniker( db: &RootDatabase, FilePosition { file_id, offset }: FilePosition, ) -> Option>> { let sema = &Semantics::new(db); let file = sema.parse(file_id).syntax().clone(); - let current_crate = crate_for_file(db, file_id)?; + let current_crate: hir::Crate = crates_for(db, file_id).pop()?.into(); let original_token = pick_best_token(file.token_at_offset(offset), |kind| match kind { IDENT | INT_NUMBER diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs index 27ad1a948d13b..954d3b018afa9 100644 --- a/crates/ide/src/static_index.rs +++ b/crates/ide/src/static_index.rs @@ -13,7 +13,8 @@ use syntax::{AstNode, SyntaxKind::*, SyntaxToken, TextRange, T}; use crate::{ hover::hover_for_definition, - moniker::{crate_for_file, def_to_moniker, MonikerResult}, + moniker::{def_to_moniker, MonikerResult}, + parent_module::crates_for, Analysis, Fold, HoverConfig, HoverDocFormat, HoverResult, InlayHint, InlayHintsConfig, TryToNav, }; @@ -99,7 +100,7 @@ fn all_modules(db: &dyn HirDatabase) -> Vec { impl StaticIndex<'_> { fn add_file(&mut self, file_id: FileId) { - let current_crate = crate_for_file(self.db, file_id); + let current_crate = crates_for(self.db, file_id).pop().map(Into::into); let folds = self.analysis.folding_ranges(file_id).unwrap(); let inlay_hints = self .analysis From 6a06f6f724d385c61e428ef46e6bf9e13e1c37ce Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 7 Nov 2022 16:48:50 +0100 Subject: [PATCH 21/81] Deduplicate reference search results --- crates/ide/src/references.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index e942413c11057..0f758cfa2d344 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs @@ -16,6 +16,7 @@ use ide_db::{ search::{ReferenceCategory, SearchScope, UsageSearchResult}, RootDatabase, }; +use itertools::Itertools; use stdx::hash::NoHashHashMap; use syntax::{ algo::find_node_at_offset, @@ -86,6 +87,7 @@ pub(crate) fn find_all_refs( file_id, refs.into_iter() .map(|file_ref| (file_ref.range, file_ref.category)) + .unique() .collect(), ) }) From fa70b0a86ec89ea53c0855caba42d121cbcc5697 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 7 Nov 2022 17:21:37 +0100 Subject: [PATCH 22/81] internal: Use Cancellable in favor of Result for clarity --- crates/ide/src/inlay_hints.rs | 10 ++--- crates/ide/src/lib.rs | 2 +- crates/rust-analyzer/src/cargo_target_spec.rs | 10 ++--- crates/rust-analyzer/src/handlers.rs | 19 +++++----- crates/rust-analyzer/src/mem_docs.rs | 8 +++- crates/rust-analyzer/src/to_proto.rs | 38 +++++++++---------- 6 files changed, 44 insertions(+), 43 deletions(-) diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 34d8bf67a3016..8ef122528b4a8 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -180,7 +180,7 @@ impl fmt::Debug for InlayHintLabelPart { pub(crate) fn inlay_hints( db: &RootDatabase, file_id: FileId, - range_limit: Option, + range_limit: Option, config: &InlayHintsConfig, ) -> Vec { let _p = profile::span("inlay_hints"); @@ -195,7 +195,7 @@ pub(crate) fn inlay_hints( let hints = |node| hints(&mut acc, &famous_defs, config, file_id, node); match range_limit { - Some(FileRange { range, .. }) => match file.covering_element(range) { + Some(range) => match file.covering_element(range) { NodeOrToken::Token(_) => return acc, NodeOrToken::Node(n) => n .descendants() @@ -1213,7 +1213,6 @@ fn get_callable( #[cfg(test)] mod tests { use expect_test::{expect, Expect}; - use ide_db::base_db::FileRange; use itertools::Itertools; use syntax::{TextRange, TextSize}; use test_utils::extract_annotations; @@ -1838,10 +1837,7 @@ fn main() { .inlay_hints( &InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG }, file_id, - Some(FileRange { - file_id, - range: TextRange::new(TextSize::from(500), TextSize::from(600)), - }), + Some(TextRange::new(TextSize::from(500), TextSize::from(600))), ) .unwrap(); let actual = diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index 416817ca0b42c..841a5832c5417 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -367,7 +367,7 @@ impl Analysis { &self, config: &InlayHintsConfig, file_id: FileId, - range: Option, + range: Option, ) -> Cancellable> { self.with_db(|db| inlay_hints::inlay_hints(db, file_id, range, config)) } diff --git a/crates/rust-analyzer/src/cargo_target_spec.rs b/crates/rust-analyzer/src/cargo_target_spec.rs index 6ede194babc20..cf51cf15a0e1d 100644 --- a/crates/rust-analyzer/src/cargo_target_spec.rs +++ b/crates/rust-analyzer/src/cargo_target_spec.rs @@ -3,11 +3,11 @@ use std::mem; use cfg::{CfgAtom, CfgExpr}; -use ide::{FileId, RunnableKind, TestId}; +use ide::{Cancellable, FileId, RunnableKind, TestId}; use project_model::{self, CargoFeatures, ManifestPath, TargetKind}; use vfs::AbsPathBuf; -use crate::{global_state::GlobalStateSnapshot, Result}; +use crate::global_state::GlobalStateSnapshot; /// Abstract representation of Cargo target. /// @@ -29,7 +29,7 @@ impl CargoTargetSpec { spec: Option, kind: &RunnableKind, cfg: &Option, - ) -> Result<(Vec, Vec)> { + ) -> (Vec, Vec) { let mut args = Vec::new(); let mut extra_args = Vec::new(); @@ -111,13 +111,13 @@ impl CargoTargetSpec { } } } - Ok((args, extra_args)) + (args, extra_args) } pub(crate) fn for_file( global_state_snapshot: &GlobalStateSnapshot, file_id: FileId, - ) -> Result> { + ) -> Cancellable> { let crate_id = match &*global_state_snapshot.analysis.crates_for(file_id)? { &[crate_id, ..] => crate_id, _ => return Ok(None), diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index 34795a8eb40ab..d190a9f4e2ca9 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs @@ -9,9 +9,9 @@ use std::{ use anyhow::Context; use ide::{ - AnnotationConfig, AssistKind, AssistResolveStrategy, FileId, FilePosition, FileRange, - HoverAction, HoverGotoTypeData, Query, RangeInfo, ReferenceCategory, Runnable, RunnableKind, - SingleResolve, SourceChange, TextEdit, + AnnotationConfig, AssistKind, AssistResolveStrategy, Cancellable, FileId, FilePosition, + FileRange, HoverAction, HoverGotoTypeData, Query, RangeInfo, ReferenceCategory, Runnable, + RunnableKind, SingleResolve, SourceChange, TextEdit, }; use ide_db::SymbolKind; use lsp_server::ErrorCode; @@ -556,7 +556,7 @@ pub(crate) fn handle_will_rename_files( if source_change.source_file_edits.is_empty() { Ok(None) } else { - to_proto::workspace_edit(&snap, source_change).map(Some) + Ok(Some(to_proto::workspace_edit(&snap, source_change)?)) } } @@ -1313,7 +1313,7 @@ pub(crate) fn handle_ssr( position, selections, )??; - to_proto::workspace_edit(&snap, source_change) + to_proto::workspace_edit(&snap, source_change).map_err(Into::into) } pub(crate) fn publish_diagnostics( @@ -1354,13 +1354,12 @@ pub(crate) fn handle_inlay_hints( ) -> Result>> { let _p = profile::span("handle_inlay_hints"); let document_uri = ¶ms.text_document.uri; - let file_id = from_proto::file_id(&snap, document_uri)?; - let line_index = snap.file_line_index(file_id)?; - let range = from_proto::file_range( + let FileRange { file_id, range } = from_proto::file_range( &snap, TextDocumentIdentifier::new(document_uri.to_owned()), params.range, )?; + let line_index = snap.file_line_index(file_id)?; let inlay_hints_config = snap.config.inlay_hints(); Ok(Some( snap.analysis @@ -1369,7 +1368,7 @@ pub(crate) fn handle_inlay_hints( .map(|it| { to_proto::inlay_hint(&snap, &line_index, inlay_hints_config.render_colons, it) }) - .collect::>>()?, + .collect::>>()?, )) } @@ -1426,7 +1425,7 @@ pub(crate) fn handle_call_hierarchy_prepare( .into_iter() .filter(|it| it.kind == Some(SymbolKind::Function)) .map(|it| to_proto::call_hierarchy_item(&snap, it)) - .collect::>>()?; + .collect::>>()?; Ok(Some(res)) } diff --git a/crates/rust-analyzer/src/mem_docs.rs b/crates/rust-analyzer/src/mem_docs.rs index f86a0f66ad8d6..45a1dab9772fa 100644 --- a/crates/rust-analyzer/src/mem_docs.rs +++ b/crates/rust-analyzer/src/mem_docs.rs @@ -7,7 +7,7 @@ use vfs::VfsPath; /// Holds the set of in-memory documents. /// -/// For these document, there true contents is maintained by the client. It +/// For these document, their true contents is maintained by the client. It /// might be different from what's on disk. #[derive(Default, Clone)] pub(crate) struct MemDocs { @@ -19,6 +19,7 @@ impl MemDocs { pub(crate) fn contains(&self, path: &VfsPath) -> bool { self.mem_docs.contains_key(path) } + pub(crate) fn insert(&mut self, path: VfsPath, data: DocumentData) -> Result<(), ()> { self.added_or_removed = true; match self.mem_docs.insert(path, data) { @@ -26,6 +27,7 @@ impl MemDocs { None => Ok(()), } } + pub(crate) fn remove(&mut self, path: &VfsPath) -> Result<(), ()> { self.added_or_removed = true; match self.mem_docs.remove(path) { @@ -33,17 +35,21 @@ impl MemDocs { None => Err(()), } } + pub(crate) fn get(&self, path: &VfsPath) -> Option<&DocumentData> { self.mem_docs.get(path) } + pub(crate) fn get_mut(&mut self, path: &VfsPath) -> Option<&mut DocumentData> { // NB: don't set `self.added_or_removed` here, as that purposefully only // tracks changes to the key set. self.mem_docs.get_mut(path) } + pub(crate) fn iter(&self) -> impl Iterator { self.mem_docs.keys() } + pub(crate) fn take_changes(&mut self) -> bool { mem::replace(&mut self.added_or_removed, false) } diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 6c84a2069cd57..830b071b9416d 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs @@ -24,7 +24,7 @@ use crate::{ line_index::{LineEndings, LineIndex, PositionEncoding}, lsp_ext, lsp_utils::invalid_params_error, - semantic_tokens, Result, + semantic_tokens, }; pub(crate) fn position(line_index: &LineIndex, offset: TextSize) -> lsp_types::Position { @@ -429,7 +429,7 @@ pub(crate) fn inlay_hint( line_index: &LineIndex, render_colons: bool, mut inlay_hint: InlayHint, -) -> Result { +) -> Cancellable { match inlay_hint.kind { InlayKind::ParameterHint if render_colons => inlay_hint.label.append_str(":"), InlayKind::TypeHint if render_colons => inlay_hint.label.prepend_str(": "), @@ -518,7 +518,7 @@ pub(crate) fn inlay_hint( fn inlay_hint_label( snap: &GlobalStateSnapshot, label: InlayHintLabel, -) -> Result { +) -> Cancellable { Ok(match label.as_simple_str() { Some(s) => lsp_types::InlayHintLabel::String(s.into()), None => lsp_types::InlayHintLabel::LabelParts( @@ -536,7 +536,7 @@ fn inlay_hint_label( command: None, }) }) - .collect::>>()?, + .collect::>>()?, ), }) } @@ -794,7 +794,7 @@ pub(crate) fn optional_versioned_text_document_identifier( pub(crate) fn location( snap: &GlobalStateSnapshot, frange: FileRange, -) -> Result { +) -> Cancellable { let url = url(snap, frange.file_id); let line_index = snap.file_line_index(frange.file_id)?; let range = range(&line_index, frange.range); @@ -806,7 +806,7 @@ pub(crate) fn location( pub(crate) fn location_from_nav( snap: &GlobalStateSnapshot, nav: NavigationTarget, -) -> Result { +) -> Cancellable { let url = url(snap, nav.file_id); let line_index = snap.file_line_index(nav.file_id)?; let range = range(&line_index, nav.full_range); @@ -818,7 +818,7 @@ pub(crate) fn location_link( snap: &GlobalStateSnapshot, src: Option, target: NavigationTarget, -) -> Result { +) -> Cancellable { let origin_selection_range = match src { Some(src) => { let line_index = snap.file_line_index(src.file_id)?; @@ -840,7 +840,7 @@ pub(crate) fn location_link( fn location_info( snap: &GlobalStateSnapshot, target: NavigationTarget, -) -> Result<(lsp_types::Url, lsp_types::Range, lsp_types::Range)> { +) -> Cancellable<(lsp_types::Url, lsp_types::Range, lsp_types::Range)> { let line_index = snap.file_line_index(target.file_id)?; let target_uri = url(snap, target.file_id); @@ -854,12 +854,12 @@ pub(crate) fn goto_definition_response( snap: &GlobalStateSnapshot, src: Option, targets: Vec, -) -> Result { +) -> Cancellable { if snap.config.location_link() { let links = targets .into_iter() .map(|nav| location_link(snap, src, nav)) - .collect::>>()?; + .collect::>>()?; Ok(links.into()) } else { let locations = targets @@ -867,7 +867,7 @@ pub(crate) fn goto_definition_response( .map(|nav| { location(snap, FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() }) }) - .collect::>>()?; + .collect::>>()?; Ok(locations.into()) } } @@ -881,7 +881,7 @@ pub(crate) fn snippet_text_document_edit( is_snippet: bool, file_id: FileId, edit: TextEdit, -) -> Result { +) -> Cancellable { let text_document = optional_versioned_text_document_identifier(snap, file_id); let line_index = snap.file_line_index(file_id)?; let mut edits: Vec<_> = @@ -958,7 +958,7 @@ pub(crate) fn snippet_text_document_ops( pub(crate) fn snippet_workspace_edit( snap: &GlobalStateSnapshot, source_change: SourceChange, -) -> Result { +) -> Cancellable { let mut document_changes: Vec = Vec::new(); for op in source_change.file_system_edits { @@ -995,7 +995,7 @@ pub(crate) fn snippet_workspace_edit( pub(crate) fn workspace_edit( snap: &GlobalStateSnapshot, source_change: SourceChange, -) -> Result { +) -> Cancellable { assert!(!source_change.is_snippet); snippet_workspace_edit(snap, source_change).map(|it| it.into()) } @@ -1048,7 +1048,7 @@ impl From pub(crate) fn call_hierarchy_item( snap: &GlobalStateSnapshot, target: NavigationTarget, -) -> Result { +) -> Cancellable { let name = target.name.to_string(); let detail = target.description.clone(); let kind = target.kind.map(symbol_kind).unwrap_or(lsp_types::SymbolKind::FUNCTION); @@ -1080,7 +1080,7 @@ pub(crate) fn code_action( snap: &GlobalStateSnapshot, assist: Assist, resolve_data: Option<(usize, lsp_types::CodeActionParams)>, -) -> Result { +) -> Cancellable { let mut res = lsp_ext::CodeAction { title: assist.label.to_string(), group: assist.group.filter(|_| snap.config.code_action_group()).map(|gr| gr.0), @@ -1113,13 +1113,13 @@ pub(crate) fn code_action( pub(crate) fn runnable( snap: &GlobalStateSnapshot, runnable: Runnable, -) -> Result { +) -> Cancellable { let config = snap.config.runnables(); let spec = CargoTargetSpec::for_file(snap, runnable.nav.file_id)?; let workspace_root = spec.as_ref().map(|it| it.workspace_root.clone()); let target = spec.as_ref().map(|s| s.target.clone()); let (cargo_args, executable_args) = - CargoTargetSpec::runnable_args(snap, spec, &runnable.kind, &runnable.cfg)?; + CargoTargetSpec::runnable_args(snap, spec, &runnable.kind, &runnable.cfg); let label = runnable.label(target); let location = location_link(snap, None, runnable.nav)?; @@ -1142,7 +1142,7 @@ pub(crate) fn code_lens( acc: &mut Vec, snap: &GlobalStateSnapshot, annotation: Annotation, -) -> Result<()> { +) -> Cancellable<()> { let client_commands_config = snap.config.client_commands(); match annotation.kind { AnnotationKind::Runnable(run) => { From 1cb6ab89eebb76953864b3d7fae8ed068fddc5a0 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 7 Nov 2022 17:43:22 +0100 Subject: [PATCH 23/81] internal: error instead of panic on invalid file range --- crates/rust-analyzer/src/from_proto.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/rust-analyzer/src/from_proto.rs b/crates/rust-analyzer/src/from_proto.rs index 936957bab4882..dd433b0f4d31c 100644 --- a/crates/rust-analyzer/src/from_proto.rs +++ b/crates/rust-analyzer/src/from_proto.rs @@ -42,8 +42,10 @@ pub(crate) fn offset(line_index: &LineIndex, position: lsp_types::Position) -> R pub(crate) fn text_range(line_index: &LineIndex, range: lsp_types::Range) -> Result { let start = offset(line_index, range.start)?; let end = offset(line_index, range.end)?; - let text_range = TextRange::new(start, end); - Ok(text_range) + match end < start { + true => Err(format_err!("Invalid Range").into()), + false => Ok(TextRange::new(start, end)), + } } pub(crate) fn file_id(snap: &GlobalStateSnapshot, url: &lsp_types::Url) -> Result { From 90e2db81269f285cd1a0232e35cfd4519e8ce5f3 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 8 Nov 2022 08:37:45 +0100 Subject: [PATCH 24/81] fix: Fix item completions not working properly after unit structs and outline modules --- crates/ide-completion/src/context/analysis.rs | 8 +++-- crates/ide-completion/src/tests/item_list.rs | 32 +++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs index 04111ec7efaa6..c142a7305f9e9 100644 --- a/crates/ide-completion/src/context/analysis.rs +++ b/crates/ide-completion/src/context/analysis.rs @@ -681,9 +681,13 @@ fn classify_name_ref( ast::Item::ExternBlock(it) => it.extern_item_list().is_none(), ast::Item::Fn(it) => it.body().is_none(), ast::Item::Impl(it) => it.assoc_item_list().is_none(), - ast::Item::Module(it) => it.item_list().is_none(), + ast::Item::Module(it) => { + it.item_list().is_none() && it.semicolon_token().is_none() + } ast::Item::Static(it) => it.body().is_none(), - ast::Item::Struct(it) => it.field_list().is_none(), + ast::Item::Struct(it) => { + it.field_list().is_none() && it.semicolon_token().is_none() + } ast::Item::Trait(it) => it.assoc_item_list().is_none(), ast::Item::TypeAlias(it) => it.ty().is_none(), ast::Item::Union(it) => it.record_field_list().is_none(), diff --git a/crates/ide-completion/src/tests/item_list.rs b/crates/ide-completion/src/tests/item_list.rs index 5076c6e86caee..8ed6cb3cf867e 100644 --- a/crates/ide-completion/src/tests/item_list.rs +++ b/crates/ide-completion/src/tests/item_list.rs @@ -245,3 +245,35 @@ impl Test for () { "#]], ); } + +#[test] +fn after_unit_struct() { + check( + r#"struct S; f$0"#, + expect![[r#" + ma makro!(…) macro_rules! makro + md module + kw const + kw crate:: + kw enum + kw extern + kw fn + kw impl + kw mod + kw pub + kw pub(crate) + kw pub(super) + kw self:: + kw static + kw struct + kw trait + kw type + kw union + kw unsafe + kw use + sn macro_rules + sn tfn (Test function) + sn tmod (Test module) + "#]], + ); +} From 4403dde711dd947670b1cf52e39c25a91edd9f4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Tue, 8 Nov 2022 09:57:05 +0200 Subject: [PATCH 25/81] Nest Cargo.lock under Cargo.toml in Code --- editors/code/package.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/editors/code/package.json b/editors/code/package.json index 4357dc73067fd..9c9f120efa3d2 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -1276,6 +1276,11 @@ "$generated-end": {} } }, + "configurationDefaults": { + "explorer.fileNesting.patterns": { + "Cargo.toml": "Cargo.lock" + } + }, "problemPatterns": [ { "name": "rustc", From 9be0615bde83a4a67c8319bce31f5929239d2fd9 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 8 Nov 2022 18:05:07 +0100 Subject: [PATCH 26/81] Don't canonicalize self type when querying FnOnce signature --- crates/hir-ty/src/lib.rs | 48 +++++++++++++++----------------- crates/hir/src/lib.rs | 3 +- crates/ide/src/signature_help.rs | 31 +++++++++++++++++++++ 3 files changed, 54 insertions(+), 28 deletions(-) diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs index ad33053ad095f..39514fc44e6c8 100644 --- a/crates/hir-ty/src/lib.rs +++ b/crates/hir-ty/src/lib.rs @@ -523,7 +523,7 @@ where } pub fn callable_sig_from_fnonce( - self_ty: &Canonical, + self_ty: &Ty, env: Arc, db: &dyn HirDatabase, ) -> Option { @@ -531,27 +531,28 @@ pub fn callable_sig_from_fnonce( let fn_once_trait = FnTrait::FnOnce.get_id(db, krate)?; let output_assoc_type = db.trait_data(fn_once_trait).associated_type_by_name(&name![Output])?; - let mut kinds = self_ty.binders.interned().to_vec(); let b = TyBuilder::trait_ref(db, fn_once_trait); if b.remaining() != 2 { return None; } - let fn_once = b - .push(self_ty.value.clone()) - .fill_with_bound_vars(DebruijnIndex::INNERMOST, kinds.len()) - .build(); - kinds.extend(fn_once.substitution.iter(Interner).skip(1).map(|x| { - let vk = match x.data(Interner) { - chalk_ir::GenericArgData::Ty(_) => { - chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General) - } - chalk_ir::GenericArgData::Lifetime(_) => chalk_ir::VariableKind::Lifetime, - chalk_ir::GenericArgData::Const(c) => { - chalk_ir::VariableKind::Const(c.data(Interner).ty.clone()) - } - }; - chalk_ir::WithKind::new(vk, UniverseIndex::ROOT) - })); + let fn_once = b.push(self_ty.clone()).fill_with_bound_vars(DebruijnIndex::INNERMOST, 0).build(); + let kinds = fn_once + .substitution + .iter(Interner) + .skip(1) + .map(|x| { + let vk = match x.data(Interner) { + chalk_ir::GenericArgData::Ty(_) => { + chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General) + } + chalk_ir::GenericArgData::Lifetime(_) => chalk_ir::VariableKind::Lifetime, + chalk_ir::GenericArgData::Const(c) => { + chalk_ir::VariableKind::Const(c.data(Interner).ty.clone()) + } + }; + chalk_ir::WithKind::new(vk, UniverseIndex::ROOT) + }) + .collect::>(); // FIXME: chalk refuses to solve `>::Output == ^0.1`, so we first solve // `>` and then replace `^0.0` with the concrete argument tuple. @@ -563,21 +564,16 @@ pub fn callable_sig_from_fnonce( Some(Solution::Unique(vars)) => vars.value.subst, _ => return None, }; - let args = subst.at(Interner, self_ty.binders.interned().len()).ty(Interner)?; + let args = subst.at(Interner, 0).ty(Interner)?; let params = match args.kind(Interner) { chalk_ir::TyKind::Tuple(_, subst) => { subst.iter(Interner).filter_map(|arg| arg.ty(Interner).cloned()).collect::>() } _ => return None, }; - if params.iter().any(|ty| ty.is_unknown()) { - return None; - } - let fn_once = TyBuilder::trait_ref(db, fn_once_trait) - .push(self_ty.value.clone()) - .push(args.clone()) - .build(); + let fn_once = + TyBuilder::trait_ref(db, fn_once_trait).push(self_ty.clone()).push(args.clone()).build(); let projection = TyBuilder::assoc_type_projection(db, output_assoc_type, Some(fn_once.substitution.clone())) .build(); diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 9d77f343bc575..cbbcaebb42855 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -2997,8 +2997,7 @@ impl Type { TyKind::Function(_) => Callee::FnPtr, TyKind::FnDef(..) => Callee::Def(self.ty.callable_def(db)?), _ => { - let ty = hir_ty::replace_errors_with_variables(&self.ty); - let sig = hir_ty::callable_sig_from_fnonce(&ty, self.env.clone(), db)?; + let sig = hir_ty::callable_sig_from_fnonce(&self.ty, self.env.clone(), db)?; return Some(Callable { ty: self.clone(), sig, diff --git a/crates/ide/src/signature_help.rs b/crates/ide/src/signature_help.rs index 7486b20293a66..e7412d27faf44 100644 --- a/crates/ide/src/signature_help.rs +++ b/crates/ide/src/signature_help.rs @@ -1345,5 +1345,36 @@ fn f i32>(f: F) { ^^ --- "#]], ); + check( + r#" +fn f &T>(f: F) { + f($0) +} +"#, + expect![[r#" + (&T, u16) -> &T + ^^ --- + "#]], + ); + } + + #[test] + fn regression_13579() { + check( + r#" +fn f() { + take(2)($0); +} + +fn take( + count: C +) -> impl Fn() -> C { + move || count +} +"#, + expect![[r#" + () -> i32 + "#]], + ); } } From 3c35d44f55d0af18116a8403533f83c2ebb9bf6f Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 9 Nov 2022 20:50:18 +0100 Subject: [PATCH 27/81] Add proc-macro dependency to rustc_private crates --- crates/project-model/src/workspace.rs | 69 ++++++++++++++++----------- 1 file changed, 41 insertions(+), 28 deletions(-) diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index 2780c62ed118a..4a2f468de7255 100644 --- a/crates/project-model/src/workspace.rs +++ b/crates/project-model/src/workspace.rs @@ -509,14 +509,14 @@ impl ProjectWorkspace { build_scripts, toolchain: _, } => cargo_to_crate_graph( - rustc_cfg.clone(), - cfg_overrides, load_proc_macro, load, + rustc, cargo, - build_scripts, sysroot.as_ref(), - rustc, + rustc_cfg.clone(), + cfg_overrides, + build_scripts, ), ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => { detached_files_to_crate_graph(rustc_cfg.clone(), load, files, sysroot) @@ -602,7 +602,7 @@ fn project_json_to_crate_graph( for (from, krate) in project.crates() { if let Some(&from) = crates.get(&from) { if let Some((public_deps, libproc_macro)) = &sysroot_deps { - public_deps.add(from, &mut crate_graph); + public_deps.add_to_crate_graph(&mut crate_graph, from); if krate.is_proc_macro { if let Some(proc_macro) = libproc_macro { add_dep( @@ -626,14 +626,14 @@ fn project_json_to_crate_graph( } fn cargo_to_crate_graph( - rustc_cfg: Vec, - override_cfg: &CfgOverrides, load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult, load: &mut dyn FnMut(&AbsPath) -> Option, + rustc: &Option, cargo: &CargoWorkspace, - build_scripts: &WorkspaceBuildScripts, sysroot: Option<&Sysroot>, - rustc: &Option, + rustc_cfg: Vec, + override_cfg: &CfgOverrides, + build_scripts: &WorkspaceBuildScripts, ) -> CrateGraph { let _p = profile::span("cargo_to_crate_graph"); let mut crate_graph = CrateGraph::default(); @@ -642,13 +642,15 @@ fn cargo_to_crate_graph( None => (SysrootPublicDeps::default(), None), }; - let mut cfg_options = CfgOptions::default(); - cfg_options.extend(rustc_cfg); + let cfg_options = { + let mut cfg_options = CfgOptions::default(); + cfg_options.extend(rustc_cfg); + cfg_options.insert_atom("debug_assertions".into()); + cfg_options + }; let mut pkg_to_lib_crate = FxHashMap::default(); - cfg_options.insert_atom("debug_assertions".into()); - let mut pkg_crates = FxHashMap::default(); // Does any crate signal to rust-analyzer that they need the rustc_private crates? let mut has_private = false; @@ -723,7 +725,7 @@ fn cargo_to_crate_graph( // Set deps to the core, std and to the lib target of the current package for &(from, kind) in pkg_crates.get(&pkg).into_iter().flatten() { // Add sysroot deps first so that a lib target named `core` etc. can overwrite them. - public_deps.add(from, &mut crate_graph); + public_deps.add_to_crate_graph(&mut crate_graph, from); if let Some((to, name)) = lib_tgt.clone() { if to != from && kind != TargetKind::BuildScript { @@ -767,15 +769,16 @@ fn cargo_to_crate_graph( if let Some(rustc_workspace) = rustc { handle_rustc_crates( &mut crate_graph, - rustc_workspace, + &mut pkg_to_lib_crate, load, - &cfg_options, - override_cfg, load_proc_macro, - &mut pkg_to_lib_crate, - &public_deps, + rustc_workspace, cargo, + &public_deps, + libproc_macro, &pkg_crates, + &cfg_options, + override_cfg, build_scripts, ); } @@ -825,28 +828,29 @@ fn detached_files_to_crate_graph( }, ); - public_deps.add(detached_file_crate, &mut crate_graph); + public_deps.add_to_crate_graph(&mut crate_graph, detached_file_crate); } crate_graph } fn handle_rustc_crates( crate_graph: &mut CrateGraph, - rustc_workspace: &CargoWorkspace, + pkg_to_lib_crate: &mut FxHashMap, load: &mut dyn FnMut(&AbsPath) -> Option, - cfg_options: &CfgOptions, - override_cfg: &CfgOverrides, load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult, - pkg_to_lib_crate: &mut FxHashMap, - public_deps: &SysrootPublicDeps, + rustc_workspace: &CargoWorkspace, cargo: &CargoWorkspace, + public_deps: &SysrootPublicDeps, + libproc_macro: Option, pkg_crates: &FxHashMap>, + cfg_options: &CfgOptions, + override_cfg: &CfgOverrides, build_scripts: &WorkspaceBuildScripts, ) { let mut rustc_pkg_crates = FxHashMap::default(); // The root package of the rustc-dev component is rustc_driver, so we match that let root_pkg = - rustc_workspace.packages().find(|package| rustc_workspace[*package].name == "rustc_driver"); + rustc_workspace.packages().find(|&package| rustc_workspace[package].name == "rustc_driver"); // The rustc workspace might be incomplete (such as if rustc-dev is not // installed for the current toolchain) and `rustc_source` is set to discover. if let Some(root_pkg) = root_pkg { @@ -901,7 +905,16 @@ fn handle_rustc_crates( ); pkg_to_lib_crate.insert(pkg, crate_id); // Add dependencies on core / std / alloc for this crate - public_deps.add(crate_id, crate_graph); + public_deps.add_to_crate_graph(crate_graph, crate_id); + if let Some(proc_macro) = libproc_macro { + add_dep_with_prelude( + crate_graph, + crate_id, + CrateName::new("proc_macro").unwrap(), + proc_macro, + rustc_workspace[tgt].is_proc_macro, + ); + } rustc_pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id); } } @@ -1009,7 +1022,7 @@ struct SysrootPublicDeps { impl SysrootPublicDeps { /// Makes `from` depend on the public sysroot crates. - fn add(&self, from: CrateId, crate_graph: &mut CrateGraph) { + fn add_to_crate_graph(&self, crate_graph: &mut CrateGraph, from: CrateId) { for (name, krate, prelude) in &self.deps { add_dep_with_prelude(crate_graph, from, name.clone(), *krate, *prelude); } From 4f415fc3489d5a8e910a035455d7d33f15928ed7 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Thu, 10 Nov 2022 19:22:20 +0900 Subject: [PATCH 28/81] Ignore outermost non-delimited `Subtree` when reversing fixups --- crates/hir-expand/src/fixup.rs | 42 ++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/crates/hir-expand/src/fixup.rs b/crates/hir-expand/src/fixup.rs index 00b4cb3f96413..aab36f640efa6 100644 --- a/crates/hir-expand/src/fixup.rs +++ b/crates/hir-expand/src/fixup.rs @@ -4,6 +4,7 @@ use std::mem; use mbe::{SyntheticToken, SyntheticTokenId, TokenMap}; use rustc_hash::FxHashMap; +use smallvec::SmallVec; use syntax::{ ast::{self, AstNode, HasLoopBody}, match_ast, SyntaxElement, SyntaxKind, SyntaxNode, TextRange, @@ -292,21 +293,34 @@ pub(crate) fn reverse_fixups( token_map: &TokenMap, undo_info: &SyntaxFixupUndoInfo, ) { - tt.token_trees.retain(|tt| match tt { - tt::TokenTree::Leaf(leaf) => token_map.synthetic_token_id(leaf.id()) != Some(EMPTY_ID), - tt::TokenTree::Subtree(st) => { - st.delimiter.map_or(true, |d| token_map.synthetic_token_id(d.id) != Some(EMPTY_ID)) - } - }); - tt.token_trees.iter_mut().for_each(|tt| match tt { - tt::TokenTree::Subtree(tt) => reverse_fixups(tt, token_map, undo_info), - tt::TokenTree::Leaf(leaf) => { - if let Some(id) = token_map.synthetic_token_id(leaf.id()) { - let original = &undo_info.original[id.0 as usize]; - *tt = tt::TokenTree::Subtree(original.clone()); + let tts = std::mem::take(&mut tt.token_trees); + tt.token_trees = tts + .into_iter() + .filter(|tt| match tt { + tt::TokenTree::Leaf(leaf) => token_map.synthetic_token_id(leaf.id()) != Some(EMPTY_ID), + tt::TokenTree::Subtree(st) => { + st.delimiter.map_or(true, |d| token_map.synthetic_token_id(d.id) != Some(EMPTY_ID)) } - } - }); + }) + .flat_map(|tt| match tt { + tt::TokenTree::Subtree(mut tt) => { + reverse_fixups(&mut tt, token_map, undo_info); + SmallVec::from_const([tt.into()]) + } + tt::TokenTree::Leaf(leaf) => { + if let Some(id) = token_map.synthetic_token_id(leaf.id()) { + let original = undo_info.original[id.0 as usize].clone(); + if original.delimiter.is_none() { + original.token_trees.into() + } else { + SmallVec::from_const([original.into()]) + } + } else { + SmallVec::from_const([leaf.into()]) + } + } + }) + .collect(); } #[cfg(test)] From 5b070610118a98d96869af4cad79575d4edc5941 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Thu, 10 Nov 2022 19:24:01 +0900 Subject: [PATCH 29/81] Test `TokenTree`s' equality modulo `Punct`s' spacing --- crates/hir-expand/src/fixup.rs | 41 +++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/crates/hir-expand/src/fixup.rs b/crates/hir-expand/src/fixup.rs index aab36f640efa6..a4abe75626e6d 100644 --- a/crates/hir-expand/src/fixup.rs +++ b/crates/hir-expand/src/fixup.rs @@ -329,6 +329,31 @@ mod tests { use super::reverse_fixups; + // The following three functions are only meant to check partial structural equivalence of + // `TokenTree`s, see the last assertion in `check()`. + fn check_leaf_eq(a: &tt::Leaf, b: &tt::Leaf) -> bool { + match (a, b) { + (tt::Leaf::Literal(a), tt::Leaf::Literal(b)) => a.text == b.text, + (tt::Leaf::Punct(a), tt::Leaf::Punct(b)) => a.char == b.char, + (tt::Leaf::Ident(a), tt::Leaf::Ident(b)) => a.text == b.text, + _ => false, + } + } + + fn check_subtree_eq(a: &tt::Subtree, b: &tt::Subtree) -> bool { + a.delimiter.map(|it| it.kind) == b.delimiter.map(|it| it.kind) + && a.token_trees.len() == b.token_trees.len() + && a.token_trees.iter().zip(&b.token_trees).all(|(a, b)| check_tt_eq(a, b)) + } + + fn check_tt_eq(a: &tt::TokenTree, b: &tt::TokenTree) -> bool { + match (a, b) { + (tt::TokenTree::Leaf(a), tt::TokenTree::Leaf(b)) => check_leaf_eq(a, b), + (tt::TokenTree::Subtree(a), tt::TokenTree::Subtree(b)) => check_subtree_eq(a, b), + _ => false, + } + } + #[track_caller] fn check(ra_fixture: &str, mut expect: Expect) { let parsed = syntax::SourceFile::parse(ra_fixture); @@ -341,8 +366,7 @@ mod tests { fixups.append, ); - let mut actual = tt.to_string(); - actual.push('\n'); + let actual = format!("{}\n", tt); expect.indent(false); expect.assert_eq(&actual); @@ -358,9 +382,12 @@ mod tests { reverse_fixups(&mut tt, &tmap, &fixups.undo_info); // the fixed-up + reversed version should be equivalent to the original input - // (but token IDs don't matter) + // modulo token IDs and `Punct`s' spacing. let (original_as_tt, _) = mbe::syntax_node_to_token_tree(&parsed.syntax_node()); - assert_eq!(tt.to_string(), original_as_tt.to_string()); + assert!( + check_subtree_eq(&tt, &original_as_tt), + "different token tree: {tt:?}, {original_as_tt:?}" + ); } #[test] @@ -483,7 +510,6 @@ fn foo () {a . __ra_fixup} } #[test] - #[ignore] fn incomplete_field_expr_2() { check( r#" @@ -492,13 +518,12 @@ fn foo() { } "#, expect![[r#" -fn foo () {a .__ra_fixup ;} +fn foo () {a . __ra_fixup ;} "#]], ) } #[test] - #[ignore] fn incomplete_field_expr_3() { check( r#" @@ -508,7 +533,7 @@ fn foo() { } "#, expect![[r#" -fn foo () {a .__ra_fixup ; bar () ;} +fn foo () {a . __ra_fixup ; bar () ;} "#]], ) } From dea49d082644cb3dbc7755849b6e3c325a6f32d9 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Fri, 11 Nov 2022 19:50:26 +0900 Subject: [PATCH 30/81] fix: check visibility of each segment in path resolution --- crates/hir-def/src/nameres/collector.rs | 4 +++ crates/hir-def/src/nameres/path_resolution.rs | 7 +++++ crates/hir-def/src/nameres/tests/globs.rs | 30 +++++++++++++++++++ 3 files changed, 41 insertions(+) diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index 9ffc218818ca1..b0dd01f9dbea2 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -212,6 +212,7 @@ impl Import { #[derive(Debug, Eq, PartialEq)] struct ImportDirective { + /// The module this import directive is in. module_id: LocalModuleId, import: Import, status: PartialResolvedImport, @@ -963,8 +964,10 @@ impl DefCollector<'_> { fn update( &mut self, + // The module for which `resolutions` have been resolve module_id: LocalModuleId, resolutions: &[(Option, PerNs)], + // Visibility this import will have vis: Visibility, import_type: ImportType, ) { @@ -974,6 +977,7 @@ impl DefCollector<'_> { fn update_recursive( &mut self, + // The module for which `resolutions` have been resolve module_id: LocalModuleId, resolutions: &[(Option, PerNs)], // All resolutions are imported with this visibility; the visibilities in diff --git a/crates/hir-def/src/nameres/path_resolution.rs b/crates/hir-def/src/nameres/path_resolution.rs index 8dfda6df64e7c..20d39ec6cb92e 100644 --- a/crates/hir-def/src/nameres/path_resolution.rs +++ b/crates/hir-def/src/nameres/path_resolution.rs @@ -73,7 +73,10 @@ impl DefMap { pub(crate) fn resolve_visibility( &self, db: &dyn DefDatabase, + // module to import to original_module: LocalModuleId, + // pub(path) + // ^^^^ this visibility: &RawVisibility, ) -> Option { let mut vis = match visibility { @@ -115,6 +118,7 @@ impl DefMap { &self, db: &dyn DefDatabase, mode: ResolveMode, + // module to import to mut original_module: LocalModuleId, path: &ModPath, shadow: BuiltinShadowMode, @@ -361,6 +365,9 @@ impl DefMap { ); } }; + + curr_per_ns = curr_per_ns + .filter_visibility(|vis| vis.is_visible_from_def_map(db, self, original_module)); } ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None, Some(self.krate)) diff --git a/crates/hir-def/src/nameres/tests/globs.rs b/crates/hir-def/src/nameres/tests/globs.rs index b2a6a592cf38b..84d14e3b926bb 100644 --- a/crates/hir-def/src/nameres/tests/globs.rs +++ b/crates/hir-def/src/nameres/tests/globs.rs @@ -336,3 +336,33 @@ mod d { "#]], ); } + +#[test] +fn glob_name_collision_check_visibility() { + check( + r#" +mod event { + mod serenity { + pub fn Event() {} + } + use serenity::*; + + pub struct Event {} +} + +use event::Event; + "#, + expect![[r#" + crate + Event: t + event: t + + crate::event + Event: t v + serenity: t + + crate::event::serenity + Event: v + "#]], + ); +} From e75afebeb243538ac85e4cb965bd40582f4c7b59 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Fri, 11 Nov 2022 19:56:47 +0900 Subject: [PATCH 31/81] Resolve invisible defs in `fix_visibility` assist --- .../src/handlers/fix_visibility.rs | 20 +++++++++++-------- crates/ide-assists/src/tests/generated.rs | 4 ++-- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/crates/ide-assists/src/handlers/fix_visibility.rs b/crates/ide-assists/src/handlers/fix_visibility.rs index 8764543028706..d9e00435ecf5d 100644 --- a/crates/ide-assists/src/handlers/fix_visibility.rs +++ b/crates/ide-assists/src/handlers/fix_visibility.rs @@ -1,4 +1,4 @@ -use hir::{db::HirDatabase, HasSource, HasVisibility, PathResolution}; +use hir::{db::HirDatabase, HasSource, HasVisibility, ModuleDef, PathResolution, ScopeDef}; use ide_db::base_db::FileId; use syntax::{ ast::{self, HasVisibility as _}, @@ -18,7 +18,7 @@ use crate::{utils::vis_offset, AssistContext, AssistId, AssistKind, Assists}; // fn frobnicate() {} // } // fn main() { -// m::frobnicate$0() {} +// m::frobnicate$0(); // } // ``` // -> @@ -27,7 +27,7 @@ use crate::{utils::vis_offset, AssistContext, AssistId, AssistKind, Assists}; // $0pub(crate) fn frobnicate() {} // } // fn main() { -// m::frobnicate() {} +// m::frobnicate(); // } // ``` pub(crate) fn fix_visibility(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { @@ -37,11 +37,15 @@ pub(crate) fn fix_visibility(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let path: ast::Path = ctx.find_node_at_offset()?; - let path_res = ctx.sema.resolve_path(&path)?; - let def = match path_res { - PathResolution::Def(def) => def, - _ => return None, - }; + let qualifier = path.qualifier()?; + let name_ref = path.segment()?.name_ref()?; + let qualifier_res = ctx.sema.resolve_path(&qualifier)?; + let PathResolution::Def(ModuleDef::Module(module)) = qualifier_res else { return None; }; + let (_, def) = module + .scope(ctx.db(), None) + .into_iter() + .find(|(name, _)| name.to_smol_str() == name_ref.text().as_str())?; + let ScopeDef::ModuleDef(def) = def else { return None; }; let current_module = ctx.sema.scope(path.syntax())?.module(); let target_module = def.module(ctx.db())?; diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs index 029d169899bb4..c09317572acf2 100644 --- a/crates/ide-assists/src/tests/generated.rs +++ b/crates/ide-assists/src/tests/generated.rs @@ -741,7 +741,7 @@ mod m { fn frobnicate() {} } fn main() { - m::frobnicate$0() {} + m::frobnicate$0(); } "#####, r#####" @@ -749,7 +749,7 @@ mod m { $0pub(crate) fn frobnicate() {} } fn main() { - m::frobnicate() {} + m::frobnicate(); } "#####, ) From 19306c070d5deb8afa6e9da21fcf22e5b7e24a11 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Fri, 11 Nov 2022 19:59:52 +0900 Subject: [PATCH 32/81] Fix tests that depended on loose visibility restriction --- crates/hir-def/src/nameres/tests.rs | 6 +-- crates/hir-def/src/nameres/tests/globs.rs | 3 +- .../src/nameres/tests/mod_resolution.rs | 2 +- crates/hir-ty/src/tests/method_resolution.rs | 40 +++++++++---------- crates/hir-ty/src/tests/simple.rs | 18 ++++----- crates/hir-ty/src/tests/traits.rs | 36 ++++++++--------- .../src/handlers/add_missing_impl_members.rs | 28 ++++++------- .../src/handlers/generate_enum_variant.rs | 12 +++--- .../src/handlers/generate_function.rs | 4 +- .../src/handlers/no_such_field.rs | 4 +- .../src/handlers/useless_braces.rs | 20 +++++----- crates/ide/src/goto_definition.rs | 6 +-- 12 files changed, 90 insertions(+), 89 deletions(-) diff --git a/crates/hir-def/src/nameres/tests.rs b/crates/hir-def/src/nameres/tests.rs index 70dd2eb3ade69..0d90047c28f6f 100644 --- a/crates/hir-def/src/nameres/tests.rs +++ b/crates/hir-def/src/nameres/tests.rs @@ -58,9 +58,9 @@ extern { "#, expect![[r#" crate - E: t + E: _ S: t v - V: t v + V: _ foo: t crate::foo @@ -307,7 +307,7 @@ pub struct FromLib; Bar: t v crate::foo - Bar: t v + Bar: _ FromLib: t v "#]], ); diff --git a/crates/hir-def/src/nameres/tests/globs.rs b/crates/hir-def/src/nameres/tests/globs.rs index 84d14e3b926bb..88a3c76393f08 100644 --- a/crates/hir-def/src/nameres/tests/globs.rs +++ b/crates/hir-def/src/nameres/tests/globs.rs @@ -119,7 +119,7 @@ use foo::*; use foo::bar::*; //- /foo/mod.rs -mod bar; +pub mod bar; fn Foo() {}; pub struct Foo {}; @@ -132,6 +132,7 @@ pub(crate) struct PubCrateStruct; crate Foo: t PubCrateStruct: t v + bar: t foo: t crate::foo diff --git a/crates/hir-def/src/nameres/tests/mod_resolution.rs b/crates/hir-def/src/nameres/tests/mod_resolution.rs index ba3bf8b5a5cfa..c575bf7cac255 100644 --- a/crates/hir-def/src/nameres/tests/mod_resolution.rs +++ b/crates/hir-def/src/nameres/tests/mod_resolution.rs @@ -580,7 +580,7 @@ fn module_resolution_decl_inside_inline_module_in_crate_root() { //- /main.rs mod foo { #[path = "baz.rs"] - mod bar; + pub mod bar; } use self::foo::bar::Baz; diff --git a/crates/hir-ty/src/tests/method_resolution.rs b/crates/hir-ty/src/tests/method_resolution.rs index ac8edb841a580..5d76d185ffc04 100644 --- a/crates/hir-ty/src/tests/method_resolution.rs +++ b/crates/hir-ty/src/tests/method_resolution.rs @@ -164,16 +164,16 @@ fn infer_associated_method_with_modules() { check_infer( r#" mod a { - struct A; + pub struct A; impl A { pub fn thing() -> A { A {} }} } mod b { - struct B; + pub struct B; impl B { pub fn thing() -> u32 { 99 }} - mod c { - struct C; + pub mod c { + pub struct C; impl C { pub fn thing() -> C { C {} }} } } @@ -186,22 +186,22 @@ fn infer_associated_method_with_modules() { } "#, expect![[r#" - 55..63 '{ A {} }': A - 57..61 'A {}': A - 125..131 '{ 99 }': u32 - 127..129 '99': u32 - 201..209 '{ C {} }': C - 203..207 'C {}': C - 240..324 '{ ...g(); }': () - 250..251 'x': A - 254..265 'a::A::thing': fn thing() -> A - 254..267 'a::A::thing()': A - 277..278 'y': u32 - 281..292 'b::B::thing': fn thing() -> u32 - 281..294 'b::B::thing()': u32 - 304..305 'z': C - 308..319 'c::C::thing': fn thing() -> C - 308..321 'c::C::thing()': C + 59..67 '{ A {} }': A + 61..65 'A {}': A + 133..139 '{ 99 }': u32 + 135..137 '99': u32 + 217..225 '{ C {} }': C + 219..223 'C {}': C + 256..340 '{ ...g(); }': () + 266..267 'x': A + 270..281 'a::A::thing': fn thing() -> A + 270..283 'a::A::thing()': A + 293..294 'y': u32 + 297..308 'b::B::thing': fn thing() -> u32 + 297..310 'b::B::thing()': u32 + 320..321 'z': C + 324..335 'c::C::thing': fn thing() -> C + 324..337 'c::C::thing()': C "#]], ); } diff --git a/crates/hir-ty/src/tests/simple.rs b/crates/hir-ty/src/tests/simple.rs index 080e2ac1b8e1e..d7431443b83d5 100644 --- a/crates/hir-ty/src/tests/simple.rs +++ b/crates/hir-ty/src/tests/simple.rs @@ -214,7 +214,7 @@ fn infer_paths() { fn a() -> u32 { 1 } mod b { - fn c() -> u32 { 1 } + pub fn c() -> u32 { 1 } } fn test() { @@ -225,13 +225,13 @@ fn test() { expect![[r#" 14..19 '{ 1 }': u32 16..17 '1': u32 - 47..52 '{ 1 }': u32 - 49..50 '1': u32 - 66..90 '{ ...c(); }': () - 72..73 'a': fn a() -> u32 - 72..75 'a()': u32 - 81..85 'b::c': fn c() -> u32 - 81..87 'b::c()': u32 + 51..56 '{ 1 }': u32 + 53..54 '1': u32 + 70..94 '{ ...c(); }': () + 76..77 'a': fn a() -> u32 + 76..79 'a()': u32 + 85..89 'b::c': fn c() -> u32 + 85..91 'b::c()': u32 "#]], ); } @@ -1856,7 +1856,7 @@ fn not_shadowing_module_by_primitive() { check_types( r#" //- /str.rs -fn foo() -> u32 {0} +pub fn foo() -> u32 {0} //- /main.rs mod str; diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs index 7d42b8b9bc8d8..3d7194b6f4468 100644 --- a/crates/hir-ty/src/tests/traits.rs +++ b/crates/hir-ty/src/tests/traits.rs @@ -1706,7 +1706,7 @@ fn where_clause_trait_in_scope_for_method_resolution() { check_types( r#" mod foo { - trait Trait { + pub trait Trait { fn foo(&self) -> u32 { 0 } } } @@ -1723,7 +1723,7 @@ fn super_trait_method_resolution() { check_infer( r#" mod foo { - trait SuperTrait { + pub trait SuperTrait { fn foo(&self) -> u32 {} } } @@ -1735,15 +1735,15 @@ fn test(x: T, y: U) { y.foo(); }"#, expect![[r#" - 49..53 'self': &Self - 62..64 '{}': u32 - 181..182 'x': T - 187..188 'y': U - 193..222 '{ ...o(); }': () - 199..200 'x': T - 199..206 'x.foo()': u32 - 212..213 'y': U - 212..219 'y.foo()': u32 + 53..57 'self': &Self + 66..68 '{}': u32 + 185..186 'x': T + 191..192 'y': U + 197..226 '{ ...o(); }': () + 203..204 'x': T + 203..210 'x.foo()': u32 + 216..217 'y': U + 216..223 'y.foo()': u32 "#]], ); } @@ -1754,7 +1754,7 @@ fn super_trait_impl_trait_method_resolution() { r#" //- minicore: sized mod foo { - trait SuperTrait { + pub trait SuperTrait { fn foo(&self) -> u32 {} } } @@ -1764,12 +1764,12 @@ fn test(x: &impl Trait1) { x.foo(); }"#, expect![[r#" - 49..53 'self': &Self - 62..64 '{}': u32 - 115..116 'x': &impl Trait1 - 132..148 '{ ...o(); }': () - 138..139 'x': &impl Trait1 - 138..145 'x.foo()': u32 + 53..57 'self': &Self + 66..68 '{}': u32 + 119..120 'x': &impl Trait1 + 136..152 '{ ...o(); }': () + 142..143 'x': &impl Trait1 + 142..149 'x.foo()': u32 "#]], ); } diff --git a/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/crates/ide-assists/src/handlers/add_missing_impl_members.rs index 62cf5ab4f37a1..722302f991e27 100644 --- a/crates/ide-assists/src/handlers/add_missing_impl_members.rs +++ b/crates/ide-assists/src/handlers/add_missing_impl_members.rs @@ -379,14 +379,14 @@ impl Foo for S { r#" mod foo { pub struct Bar; - trait Foo { fn foo(&self, bar: Bar); } + pub trait Foo { fn foo(&self, bar: Bar); } } struct S; impl foo::Foo for S { $0 }"#, r#" mod foo { pub struct Bar; - trait Foo { fn foo(&self, bar: Bar); } + pub trait Foo { fn foo(&self, bar: Bar); } } struct S; impl foo::Foo for S { @@ -439,14 +439,14 @@ impl bar::Foo for S { r#" mod foo { pub struct Bar; - trait Foo { fn foo(&self, bar: Bar); } + pub trait Foo { fn foo(&self, bar: Bar); } } struct S; impl foo::Foo for S { $0 }"#, r#" mod foo { pub struct Bar; - trait Foo { fn foo(&self, bar: Bar); } + pub trait Foo { fn foo(&self, bar: Bar); } } struct S; impl foo::Foo for S { @@ -464,14 +464,14 @@ impl foo::Foo for S { r#" mod foo { pub struct Bar; - trait Foo { fn foo(&self, bar: Bar); } + pub trait Foo { fn foo(&self, bar: Bar); } } struct S; impl foo::Foo for S { $0 }"#, r#" mod foo { pub struct Bar; - trait Foo { fn foo(&self, bar: Bar); } + pub trait Foo { fn foo(&self, bar: Bar); } } struct S; impl foo::Foo for S { @@ -489,7 +489,7 @@ impl foo::Foo for S { add_missing_impl_members, r#" mod foo { - trait Foo { fn foo(&self, bar: T); } + pub trait Foo { fn foo(&self, bar: T); } pub struct Param; } struct Param; @@ -497,7 +497,7 @@ struct S; impl foo::Foo for S { $0 }"#, r#" mod foo { - trait Foo { fn foo(&self, bar: T); } + pub trait Foo { fn foo(&self, bar: T); } pub struct Param; } struct Param; @@ -518,7 +518,7 @@ impl foo::Foo for S { mod foo { pub struct Bar; impl Bar { type Assoc = u32; } - trait Foo { fn foo(&self, bar: Bar::Assoc); } + pub trait Foo { fn foo(&self, bar: Bar::Assoc); } } struct S; impl foo::Foo for S { $0 }"#, @@ -526,7 +526,7 @@ impl foo::Foo for S { $0 }"#, mod foo { pub struct Bar; impl Bar { type Assoc = u32; } - trait Foo { fn foo(&self, bar: Bar::Assoc); } + pub trait Foo { fn foo(&self, bar: Bar::Assoc); } } struct S; impl foo::Foo for S { @@ -545,7 +545,7 @@ impl foo::Foo for S { mod foo { pub struct Bar; pub struct Baz; - trait Foo { fn foo(&self, bar: Bar); } + pub trait Foo { fn foo(&self, bar: Bar); } } struct S; impl foo::Foo for S { $0 }"#, @@ -553,7 +553,7 @@ impl foo::Foo for S { $0 }"#, mod foo { pub struct Bar; pub struct Baz; - trait Foo { fn foo(&self, bar: Bar); } + pub trait Foo { fn foo(&self, bar: Bar); } } struct S; impl foo::Foo for S { @@ -571,14 +571,14 @@ impl foo::Foo for S { r#" mod foo { pub trait Fn { type Output; } - trait Foo { fn foo(&self, bar: dyn Fn(u32) -> i32); } + pub trait Foo { fn foo(&self, bar: dyn Fn(u32) -> i32); } } struct S; impl foo::Foo for S { $0 }"#, r#" mod foo { pub trait Fn { type Output; } - trait Foo { fn foo(&self, bar: dyn Fn(u32) -> i32); } + pub trait Foo { fn foo(&self, bar: dyn Fn(u32) -> i32); } } struct S; impl foo::Foo for S { diff --git a/crates/ide-assists/src/handlers/generate_enum_variant.rs b/crates/ide-assists/src/handlers/generate_enum_variant.rs index 35cd42908af2c..0bcb5728311b7 100644 --- a/crates/ide-assists/src/handlers/generate_enum_variant.rs +++ b/crates/ide-assists/src/handlers/generate_enum_variant.rs @@ -261,12 +261,12 @@ fn main() { } //- /foo.rs -enum Foo { +pub enum Foo { Bar, } ", r" -enum Foo { +pub enum Foo { Bar, Baz, } @@ -310,7 +310,7 @@ fn main() { generate_enum_variant, r" mod m { - enum Foo { + pub enum Foo { Bar, } } @@ -320,7 +320,7 @@ fn main() { ", r" mod m { - enum Foo { + pub enum Foo { Bar, Baz, } @@ -516,10 +516,10 @@ mod foo; use foo::Foo::Bar$0; //- /foo.rs -enum Foo {} +pub enum Foo {} ", r" -enum Foo { +pub enum Foo { Bar, } ", diff --git a/crates/ide-assists/src/handlers/generate_function.rs b/crates/ide-assists/src/handlers/generate_function.rs index c229127e48ffc..57f198748cb76 100644 --- a/crates/ide-assists/src/handlers/generate_function.rs +++ b/crates/ide-assists/src/handlers/generate_function.rs @@ -1324,7 +1324,7 @@ fn foo() { generate_function, r" mod bar { - mod baz {} + pub mod baz {} } fn foo() { @@ -1333,7 +1333,7 @@ fn foo() { ", r" mod bar { - mod baz { + pub mod baz { pub(crate) fn my_fn() { ${0:todo!()} } diff --git a/crates/ide-diagnostics/src/handlers/no_such_field.rs b/crates/ide-diagnostics/src/handlers/no_such_field.rs index a80299106bd36..d8f2a9de9818f 100644 --- a/crates/ide-diagnostics/src/handlers/no_such_field.rs +++ b/crates/ide-diagnostics/src/handlers/no_such_field.rs @@ -268,12 +268,12 @@ fn main() { foo::Foo { bar: 3, $0baz: false}; } //- /foo.rs -struct Foo { +pub struct Foo { bar: i32 } "#, r#" -struct Foo { +pub struct Foo { bar: i32, pub(crate) baz: bool } diff --git a/crates/ide-diagnostics/src/handlers/useless_braces.rs b/crates/ide-diagnostics/src/handlers/useless_braces.rs index 8b9330e040137..289ed0458c67d 100644 --- a/crates/ide-diagnostics/src/handlers/useless_braces.rs +++ b/crates/ide-diagnostics/src/handlers/useless_braces.rs @@ -71,9 +71,9 @@ use a; use a::{c, d::e}; mod a { - mod c {} - mod d { - mod e {} + pub mod c {} + pub mod d { + pub mod e {} } } "#, @@ -87,9 +87,9 @@ use a::{ }; mod a { - mod c {} - mod d { - mod e {} + pub mod c {} + pub mod d { + pub mod e {} } } "#, @@ -116,11 +116,11 @@ use b; ); check_fix( r#" -mod a { mod c {} } +mod a { pub mod c {} } use a::{c$0}; "#, r#" -mod a { mod c {} } +mod a { pub mod c {} } use a::c; "#, ); @@ -136,11 +136,11 @@ use a; ); check_fix( r#" -mod a { mod c {} mod d { mod e {} } } +mod a { pub mod c {} pub mod d { pub mod e {} } } use a::{c, d::{e$0}}; "#, r#" -mod a { mod c {} mod d { mod e {} } } +mod a { pub mod c {} pub mod d { pub mod e {} } } use a::{c, d::e}; "#, ); diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs index f97c67b144ac1..43f7a529bc297 100644 --- a/crates/ide/src/goto_definition.rs +++ b/crates/ide/src/goto_definition.rs @@ -289,10 +289,10 @@ mod b; enum E { X(Foo$0) } //- /a.rs -struct Foo; - //^^^ +pub struct Foo; + //^^^ //- /b.rs -struct Foo; +pub struct Foo; "#, ); } From e35836eb811a99872fdf63f1f0f1046ee651eeb0 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 11 Nov 2022 13:00:22 +0100 Subject: [PATCH 33/81] Send status notification if there are no found workspaces --- crates/rust-analyzer/src/reload.rs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index e1f651786dee4..407416d9f40fb 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -106,6 +106,14 @@ impl GlobalState { status.health = lsp_ext::Health::Error; status.message = Some(error) } + + if self.config.linked_projects().is_empty() + && self.config.detached_files().is_empty() + && self.config.notifications().cargo_toml_not_found + { + status.health = lsp_ext::Health::Warning; + status.message = Some("Workspace reload required".to_string()) + } status } @@ -427,9 +435,14 @@ impl GlobalState { fn fetch_workspace_error(&self) -> Result<(), String> { let mut buf = String::new(); - for ws in self.fetch_workspaces_queue.last_op_result() { - if let Err(err) = ws { - stdx::format_to!(buf, "rust-analyzer failed to load workspace: {:#}\n", err); + let last_op_result = self.fetch_workspaces_queue.last_op_result(); + if last_op_result.is_empty() { + stdx::format_to!(buf, "rust-analyzer failed to discover workspace"); + } else { + for ws in last_op_result { + if let Err(err) = ws { + stdx::format_to!(buf, "rust-analyzer failed to load workspace: {:#}\n", err); + } } } From e50712cf2c115a1c287080b351f584edce49485b Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 11 Nov 2022 13:38:07 +0100 Subject: [PATCH 34/81] fix: Fix hover in attributed items not preferring similar kinded tokens --- crates/ide/src/hover.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 3687b597fc642..838fb18c3d590 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs @@ -119,7 +119,14 @@ pub(crate) fn hover( }); } - let in_attr = matches!(original_token.parent().and_then(ast::TokenTree::cast), Some(tt) if tt.syntax().ancestors().any(|it| ast::Meta::can_cast(it.kind()))); + let in_attr = original_token + .parent_ancestors() + .filter_map(ast::Item::cast) + .any(|item| sema.is_attr_macro_call(&item)) + && !matches!( + original_token.parent().and_then(ast::TokenTree::cast), + Some(tt) if tt.syntax().ancestors().any(|it| ast::Meta::can_cast(it.kind())) + ); // prefer descending the same token kind in attribute expansions, in normal macros text // equivalency is more important let descended = if in_attr { From c6c932d3f3b57b6e5e04321398e67326ebd1ce58 Mon Sep 17 00:00:00 2001 From: "Alexis (Poliorcetics) Bourget" Date: Sun, 25 Sep 2022 01:23:20 +0200 Subject: [PATCH 35/81] chore: Align config property --- crates/rust-analyzer/src/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index d642cd9b928ed..25e341391a8f2 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -120,7 +120,7 @@ config_data! { /// Compilation target override (target triple). cargo_target: Option = "null", /// Unsets `#[cfg(test)]` for the specified crates. - cargo_unsetTest: Vec = "[\"core\"]", + cargo_unsetTest: Vec = "[\"core\"]", /// Check all targets and tests (`--all-targets`). checkOnSave_allTargets: bool = "true", From 0d4737adb68704a9db802614f6ac9ba933d81f65 Mon Sep 17 00:00:00 2001 From: "Alexis (Poliorcetics) Bourget" Date: Sun, 25 Sep 2022 01:22:27 +0200 Subject: [PATCH 36/81] feat: Support passing multiple targets to cargo (for Rust 1.64.0+) --- crates/flycheck/src/lib.rs | 6 +-- crates/project-model/src/build_scripts.rs | 2 +- crates/project-model/src/cargo_workspace.rs | 50 +++++++++++++++------ crates/rust-analyzer/src/config.rs | 35 +++++++++++---- docs/user/generated_config.adoc | 10 +++-- editors/code/package.json | 17 ++++--- 6 files changed, 86 insertions(+), 34 deletions(-) diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs index ff507a52d550d..8f93dad06e3f5 100644 --- a/crates/flycheck/src/lib.rs +++ b/crates/flycheck/src/lib.rs @@ -40,7 +40,7 @@ pub enum InvocationLocation { pub enum FlycheckConfig { CargoCommand { command: String, - target_triple: Option, + target_triples: Vec, all_targets: bool, no_default_features: bool, all_features: bool, @@ -286,7 +286,7 @@ impl FlycheckActor { let (mut cmd, args) = match &self.config { FlycheckConfig::CargoCommand { command, - target_triple, + target_triples, no_default_features, all_targets, all_features, @@ -300,7 +300,7 @@ impl FlycheckActor { cmd.args(&["--workspace", "--message-format=json", "--manifest-path"]) .arg(self.root.join("Cargo.toml").as_os_str()); - if let Some(target) = target_triple { + for target in target_triples { cmd.args(&["--target", target.as_str()]); } if *all_targets { diff --git a/crates/project-model/src/build_scripts.rs b/crates/project-model/src/build_scripts.rs index a26a7c57acfce..ae2b41f27d58e 100644 --- a/crates/project-model/src/build_scripts.rs +++ b/crates/project-model/src/build_scripts.rs @@ -69,7 +69,7 @@ impl WorkspaceBuildScripts { cmd.args(&["check", "--quiet", "--workspace", "--message-format=json"]); // --all-targets includes tests, benches and examples in addition to the - // default lib and bins. This is an independent concept from the --targets + // default lib and bins. This is an independent concept from the --target // flag below. cmd.arg("--all-targets"); diff --git a/crates/project-model/src/cargo_workspace.rs b/crates/project-model/src/cargo_workspace.rs index b4c2ba436772f..02ec7a4f6f992 100644 --- a/crates/project-model/src/cargo_workspace.rs +++ b/crates/project-model/src/cargo_workspace.rs @@ -270,11 +270,7 @@ impl CargoWorkspace { config: &CargoConfig, progress: &dyn Fn(String), ) -> Result { - let target = config - .target - .clone() - .or_else(|| cargo_config_build_target(cargo_toml, &config.extra_env)) - .or_else(|| rustc_discover_host_triple(cargo_toml, &config.extra_env)); + let targets = find_list_of_build_targets(config, cargo_toml); let mut meta = MetadataCommand::new(); meta.cargo_path(toolchain::cargo()); @@ -294,8 +290,12 @@ impl CargoWorkspace { } meta.current_dir(current_dir.as_os_str()); - if let Some(target) = target { - meta.other_options(vec![String::from("--filter-platform"), target]); + if !targets.is_empty() { + let other_options: Vec<_> = targets + .into_iter() + .flat_map(|target| ["--filter-platform".to_string(), target]) + .collect(); + meta.other_options(other_options); } // FIXME: Fetching metadata is a slow process, as it might require @@ -469,6 +469,19 @@ impl CargoWorkspace { } } +fn find_list_of_build_targets(config: &CargoConfig, cargo_toml: &ManifestPath) -> Vec { + if let Some(target) = &config.target { + return [target.into()].to_vec(); + } + + let build_targets = cargo_config_build_target(cargo_toml, &config.extra_env); + if !build_targets.is_empty() { + return build_targets; + } + + rustc_discover_host_triple(cargo_toml, &config.extra_env).into_iter().collect() +} + fn rustc_discover_host_triple( cargo_toml: &ManifestPath, extra_env: &FxHashMap, @@ -499,7 +512,7 @@ fn rustc_discover_host_triple( fn cargo_config_build_target( cargo_toml: &ManifestPath, extra_env: &FxHashMap, -) -> Option { +) -> Vec { let mut cargo_config = Command::new(toolchain::cargo()); cargo_config.envs(extra_env); cargo_config @@ -507,12 +520,21 @@ fn cargo_config_build_target( .args(&["-Z", "unstable-options", "config", "get", "build.target"]) .env("RUSTC_BOOTSTRAP", "1"); // if successful we receive `build.target = "target-triple"` + // or `build.target = ["", ..]` tracing::debug!("Discovering cargo config target by {:?}", cargo_config); - match utf8_stdout(cargo_config) { - Ok(stdout) => stdout - .strip_prefix("build.target = \"") - .and_then(|stdout| stdout.strip_suffix('"')) - .map(ToOwned::to_owned), - Err(_) => None, + utf8_stdout(cargo_config).map(parse_output_cargo_config_build_target).unwrap_or_default() +} + +fn parse_output_cargo_config_build_target(stdout: String) -> Vec { + let trimmed = stdout.trim_start_matches("build.target = ").trim_matches('"'); + + if !trimmed.starts_with('[') { + return [trimmed.to_string()].to_vec(); + } + + let res = serde_json::from_str(trimmed); + if let Err(e) = &res { + tracing::warn!("Failed to parse `build.target` as an array of target: {}`", e); } + res.unwrap_or_default() } diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 25e341391a8f2..6b2f22faa7178 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -118,6 +118,8 @@ config_data! { /// This option does not take effect until rust-analyzer is restarted. cargo_sysroot: Option = "\"discover\"", /// Compilation target override (target triple). + // FIXME(@poliorcetics): move to multiple targets here too, but this will need more work + // than `checkOnSave_target` cargo_target: Option = "null", /// Unsets `#[cfg(test)]` for the specified crates. cargo_unsetTest: Vec = "[\"core\"]", @@ -174,9 +176,13 @@ config_data! { /// ``` /// . checkOnSave_overrideCommand: Option> = "null", - /// Check for a specific target. Defaults to - /// `#rust-analyzer.cargo.target#`. - checkOnSave_target: Option = "null", + /// Check for specific targets. Defaults to `#rust-analyzer.cargo.target#` if empty. + /// + /// Can be a single target, e.g. `"x86_64-unknown-linux-gnu"` or a list of targets, e.g. + /// `["aarch64-apple-darwin", "x86_64-apple-darwin"]`. + /// + /// Aliased as `"checkOnSave.targets"`. + checkOnSave_target | checkOnSave_targets: CheckOnSaveTargets = "[]", /// Toggles the additional completions that automatically add imports when completed. /// Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled. @@ -1147,11 +1153,10 @@ impl Config { } Some(_) | None => FlycheckConfig::CargoCommand { command: self.data.checkOnSave_command.clone(), - target_triple: self - .data - .checkOnSave_target - .clone() - .or_else(|| self.data.cargo_target.clone()), + target_triples: match &self.data.checkOnSave_target.0[..] { + [] => self.data.cargo_target.clone().into_iter().collect(), + targets => targets.into(), + }, all_targets: self.data.checkOnSave_allTargets, no_default_features: self .data @@ -1657,6 +1662,9 @@ enum InvocationStrategy { PerWorkspace, } +#[derive(Deserialize, Debug, Clone)] +struct CheckOnSaveTargets(#[serde(deserialize_with = "single_or_array")] Vec); + #[derive(Deserialize, Debug, Clone)] #[serde(rename_all = "snake_case")] enum InvocationLocation { @@ -2118,6 +2126,17 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json "The command will be executed in the project root." ], }, + "CheckOnSaveTargets" => set! { + "anyOf": [ + { + "type": "string", + }, + { + "type": "array", + "items": { "type": "string" } + }, + ], + }, _ => panic!("missing entry for {}: {}", ty, default), } diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index da8e62980789e..57f950034cbb7 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc @@ -190,11 +190,15 @@ cargo check --workspace --message-format=json --all-targets ``` . -- -[[rust-analyzer.checkOnSave.target]]rust-analyzer.checkOnSave.target (default: `null`):: +[[rust-analyzer.checkOnSave.target]]rust-analyzer.checkOnSave.target (default: `[]`):: + -- -Check for a specific target. Defaults to -`#rust-analyzer.cargo.target#`. +Check for specific targets. Defaults to `#rust-analyzer.cargo.target#` if empty. + +Can be a single target, e.g. `"x86_64-unknown-linux-gnu"` or a list of targets, e.g. +`["aarch64-apple-darwin", "x86_64-apple-darwin"]`. + +Aliased as `"checkOnSave.targets"`. -- [[rust-analyzer.completion.autoimport.enable]]rust-analyzer.completion.autoimport.enable (default: `true`):: + diff --git a/editors/code/package.json b/editors/code/package.json index 0c78165960423..762726842f957 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -634,11 +634,18 @@ } }, "rust-analyzer.checkOnSave.target": { - "markdownDescription": "Check for a specific target. Defaults to\n`#rust-analyzer.cargo.target#`.", - "default": null, - "type": [ - "null", - "string" + "markdownDescription": "Check for specific targets. Defaults to `#rust-analyzer.cargo.target#` if empty.\n\nCan be a single target, e.g. `\"x86_64-unknown-linux-gnu\"` or a list of targets, e.g.\n`[\"aarch64-apple-darwin\", \"x86_64-apple-darwin\"]`.\n\nAliased as `\"checkOnSave.targets\"`.", + "default": [], + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } ] }, "rust-analyzer.completion.autoimport.enable": { From a143ff0248320bfd234aad0d93f2a59baf78216f Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 11 Nov 2022 14:36:27 +0100 Subject: [PATCH 37/81] fix: Fix r-a eagerly showing no discovered workspace errors --- crates/rust-analyzer/src/global_state.rs | 2 +- crates/rust-analyzer/src/main_loop.rs | 2 +- crates/rust-analyzer/src/reload.rs | 11 ++++------- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index 74277ff2e576e..4e8bc8d6462ce 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -100,7 +100,7 @@ pub(crate) struct GlobalState { /// the user just adds comments or whitespace to Cargo.toml, we do not want /// to invalidate any salsa caches. pub(crate) workspaces: Arc>, - pub(crate) fetch_workspaces_queue: OpQueue>>, + pub(crate) fetch_workspaces_queue: OpQueue>>>, pub(crate) fetch_build_data_queue: OpQueue<(Arc>, Vec>)>, diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 6e5da58fe372a..274588ce0e076 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -451,7 +451,7 @@ impl GlobalState { ProjectWorkspaceProgress::Begin => (Progress::Begin, None), ProjectWorkspaceProgress::Report(msg) => (Progress::Report, Some(msg)), ProjectWorkspaceProgress::End(workspaces) => { - self.fetch_workspaces_queue.op_completed(workspaces); + self.fetch_workspaces_queue.op_completed(Some(workspaces)); let old = Arc::clone(&self.workspaces); self.switch_workspaces("fetched workspace".to_string()); diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 407416d9f40fb..aa0510a4ea6a0 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -206,12 +206,9 @@ impl GlobalState { self.show_and_log_error("failed to run build scripts".to_string(), Some(error)); } - let workspaces = self - .fetch_workspaces_queue - .last_op_result() - .iter() - .filter_map(|res| res.as_ref().ok().cloned()) - .collect::>(); + let Some(workspaces) = self.fetch_workspaces_queue.last_op_result() else { return; }; + let workspaces = + workspaces.iter().filter_map(|res| res.as_ref().ok().cloned()).collect::>(); fn eq_ignore_build_data<'a>( left: &'a ProjectWorkspace, @@ -435,7 +432,7 @@ impl GlobalState { fn fetch_workspace_error(&self) -> Result<(), String> { let mut buf = String::new(); - let last_op_result = self.fetch_workspaces_queue.last_op_result(); + let Some(last_op_result) = self.fetch_workspaces_queue.last_op_result() else { return Ok(()) }; if last_op_result.is_empty() { stdx::format_to!(buf, "rust-analyzer failed to discover workspace"); } else { From 6674bd898ed0e85fd61dba2b018144477ef6347c Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 11 Nov 2022 15:25:15 +0100 Subject: [PATCH 38/81] fix: Add trait alias grammar to rust.ungram --- crates/hir-def/src/data.rs | 18 +++++++++++++----- crates/hir-def/src/item_tree.rs | 3 ++- crates/hir-def/src/item_tree/lower.rs | 10 +--------- crates/hir-def/src/item_tree/pretty.rs | 19 ++++++++++++++----- crates/syntax/rust.ungram | 7 +++++-- crates/syntax/src/ast/generated/nodes.rs | 2 ++ 6 files changed, 37 insertions(+), 22 deletions(-) diff --git a/crates/hir-def/src/data.rs b/crates/hir-def/src/data.rs index 2dc69b00ace00..9c76969086485 100644 --- a/crates/hir-def/src/data.rs +++ b/crates/hir-def/src/data.rs @@ -236,11 +236,19 @@ impl TraitData { .by_key("rustc_skip_array_during_method_dispatch") .exists(); - let mut collector = - AssocItemCollector::new(db, module_id, tree_id.file_id(), ItemContainerId::TraitId(tr)); - collector.collect(&item_tree, tree_id.tree_id(), &tr_def.items); - let (items, attribute_calls, diagnostics) = collector.finish(); - + let (items, attribute_calls, diagnostics) = match &tr_def.items { + Some(items) => { + let mut collector = AssocItemCollector::new( + db, + module_id, + tree_id.file_id(), + ItemContainerId::TraitId(tr), + ); + collector.collect(&item_tree, tree_id.tree_id(), items); + collector.finish() + } + None => Default::default(), + }; ( Arc::new(TraitData { name, diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs index 570344596def8..0aa531eff71f6 100644 --- a/crates/hir-def/src/item_tree.rs +++ b/crates/hir-def/src/item_tree.rs @@ -666,7 +666,8 @@ pub struct Trait { pub generic_params: Interned, pub is_auto: bool, pub is_unsafe: bool, - pub items: Box<[AssocItem]>, + /// This is [`None`] if this Trait is a trait alias. + pub items: Option>, pub ast_id: FileAstId, } diff --git a/crates/hir-def/src/item_tree/lower.rs b/crates/hir-def/src/item_tree/lower.rs index 79249757d9e9b..b25274bccc9a4 100644 --- a/crates/hir-def/src/item_tree/lower.rs +++ b/crates/hir-def/src/item_tree/lower.rs @@ -451,15 +451,7 @@ impl<'a> Ctx<'a> { .collect() }); let ast_id = self.source_ast_id_map.ast_id(trait_def); - let res = Trait { - name, - visibility, - generic_params, - is_auto, - is_unsafe, - items: items.unwrap_or_default(), - ast_id, - }; + let res = Trait { name, visibility, generic_params, is_auto, is_unsafe, items, ast_id }; Some(id(self.data().traits.alloc(res))) } diff --git a/crates/hir-def/src/item_tree/pretty.rs b/crates/hir-def/src/item_tree/pretty.rs index da1643152c2fe..48c40df22ff5f 100644 --- a/crates/hir-def/src/item_tree/pretty.rs +++ b/crates/hir-def/src/item_tree/pretty.rs @@ -375,12 +375,21 @@ impl<'a> Printer<'a> { } w!(self, "trait {}", name); self.print_generic_params(generic_params); - self.print_where_clause_and_opening_brace(generic_params); - self.indented(|this| { - for item in &**items { - this.print_mod_item((*item).into()); + match items { + Some(items) => { + self.print_where_clause_and_opening_brace(generic_params); + self.indented(|this| { + for item in &**items { + this.print_mod_item((*item).into()); + } + }); } - }); + None => { + w!(self, " = "); + // FIXME: Print the aliased traits + self.print_where_clause_and_opening_brace(generic_params); + } + } wln!(self, "}}"); } ModItem::Impl(it) => { diff --git a/crates/syntax/rust.ungram b/crates/syntax/rust.ungram index 5379732ac6c37..0a0cb0290d6cb 100644 --- a/crates/syntax/rust.ungram +++ b/crates/syntax/rust.ungram @@ -239,8 +239,11 @@ Static = Trait = Attr* Visibility? 'unsafe'? 'auto'? - 'trait' Name GenericParamList? (':' TypeBoundList?)? WhereClause? - AssocItemList + 'trait' Name GenericParamList? + ( + (':' TypeBoundList?)? WhereClause? AssocItemList + | '=' TypeBoundList? WhereClause? ';' + ) AssocItemList = '{' Attr* AssocItem* '}' diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs index 6cfb98d92fcf2..2ea715f47fb23 100644 --- a/crates/syntax/src/ast/generated/nodes.rs +++ b/crates/syntax/src/ast/generated/nodes.rs @@ -407,6 +407,8 @@ impl Trait { pub fn auto_token(&self) -> Option { support::token(&self.syntax, T![auto]) } pub fn trait_token(&self) -> Option { support::token(&self.syntax, T![trait]) } pub fn assoc_item_list(&self) -> Option { support::child(&self.syntax) } + pub fn eq_token(&self) -> Option { support::token(&self.syntax, T![=]) } + pub fn semicolon_token(&self) -> Option { support::token(&self.syntax, T![;]) } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] From 6b4b7d81e461b758a5785e2f8ac6eea0ed71e6f2 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 11 Nov 2022 16:57:05 +0100 Subject: [PATCH 39/81] internal: Add version info to unsupported proc macro abi error --- crates/proc-macro-srv/src/abis/mod.rs | 2 +- crates/proc-macro-srv/src/dylib.rs | 4 ++-- crates/proc-macro-srv/src/lib.rs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/proc-macro-srv/src/abis/mod.rs b/crates/proc-macro-srv/src/abis/mod.rs index 2f854bc159548..0ce099ae0bab3 100644 --- a/crates/proc-macro-srv/src/abis/mod.rs +++ b/crates/proc-macro-srv/src/abis/mod.rs @@ -117,7 +117,7 @@ impl Abi { let inner = unsafe { Abi_1_63::from_lib(lib, symbol_name) }?; Ok(Abi::Abi1_63(inner)) } - _ => Err(LoadProcMacroDylibError::UnsupportedABI), + _ => Err(LoadProcMacroDylibError::UnsupportedABI(info.version_string.clone())), } } diff --git a/crates/proc-macro-srv/src/dylib.rs b/crates/proc-macro-srv/src/dylib.rs index 7aba74e5396de..0722cd89d7297 100644 --- a/crates/proc-macro-srv/src/dylib.rs +++ b/crates/proc-macro-srv/src/dylib.rs @@ -80,14 +80,14 @@ fn load_library(file: &Path) -> Result { pub enum LoadProcMacroDylibError { Io(io::Error), LibLoading(libloading::Error), - UnsupportedABI, + UnsupportedABI(String), } impl fmt::Display for LoadProcMacroDylibError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Io(e) => e.fmt(f), - Self::UnsupportedABI => write!(f, "unsupported ABI version"), + Self::UnsupportedABI(v) => write!(f, "unsupported ABI `{v}`"), Self::LibLoading(e) => e.fmt(f), } } diff --git a/crates/proc-macro-srv/src/lib.rs b/crates/proc-macro-srv/src/lib.rs index 72a2dfe72d374..b4f5ebd157f33 100644 --- a/crates/proc-macro-srv/src/lib.rs +++ b/crates/proc-macro-srv/src/lib.rs @@ -113,12 +113,12 @@ impl ProcMacroSrv { fn expander(&mut self, path: &Path) -> Result<&dylib::Expander, String> { let time = fs::metadata(path).and_then(|it| it.modified()).map_err(|err| { - format!("Failed to get file metadata for {}: {:?}", path.display(), err) + format!("Failed to get file metadata for {}: {}", path.display(), err) })?; Ok(match self.expanders.entry((path.to_path_buf(), time)) { Entry::Vacant(v) => v.insert(dylib::Expander::new(path).map_err(|err| { - format!("Cannot create expander for {}: {:?}", path.display(), err) + format!("Cannot create expander for {}: {}", path.display(), err) })?), Entry::Occupied(e) => e.into_mut(), }) From 46417add8ddc623f8abb8e96861dba721044f656 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Sun, 13 Nov 2022 22:23:56 +0100 Subject: [PATCH 40/81] Update several crates to bring support for the new Tier 3 Windows targets --- Cargo.lock | 92 ++++++++++++++++++++++++------------------ crates/stdx/Cargo.toml | 2 +- 2 files changed, 54 insertions(+), 40 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c04906c453832..41c5d36671de0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -310,7 +310,7 @@ dependencies = [ "hashbrown", "lock_api", "once_cell", - "parking_lot_core 0.9.3", + "parking_lot_core 0.9.4", ] [[package]] @@ -369,14 +369,14 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.17" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94a7bbaa59354bc20dd75b67f23e2797b4490e9d6928203fb105c79e448c86c" +checksum = "4b9663d381d07ae25dc88dbdf27df458faa83a9b25336bcac83d5e452b5fc9d3" dependencies = [ "cfg-if", "libc", "redox_syscall", - "windows-sys 0.36.1", + "windows-sys 0.42.0", ] [[package]] @@ -974,11 +974,11 @@ dependencies = [ [[package]] name = "miow" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7377f7792b3afb6a3cba68daa54ca23c032137010460d667fda53a8d66be00e" +checksum = "52ffbca2f655e33c08be35d87278e5b18b89550a37dbd598c20db92f6a471123" dependencies = [ - "windows-sys 0.28.0", + "windows-sys 0.42.0", ] [[package]] @@ -1061,7 +1061,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.3", + "parking_lot_core 0.9.4", ] [[package]] @@ -1080,15 +1080,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-sys 0.36.1", + "windows-sys 0.42.0", ] [[package]] @@ -2003,19 +2003,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-sys" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82ca39602d5cbfa692c4b67e3bcbb2751477355141c1ed434c94da4186836ff6" -dependencies = [ - "windows_aarch64_msvc 0.28.0", - "windows_i686_gnu 0.28.0", - "windows_i686_msvc 0.28.0", - "windows_x86_64_gnu 0.28.0", - "windows_x86_64_msvc 0.28.0", -] - [[package]] name = "windows-sys" version = "0.36.1" @@ -2030,10 +2017,25 @@ dependencies = [ ] [[package]] -name = "windows_aarch64_msvc" -version = "0.28.0" +name = "windows-sys" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52695a41e536859d5308cc613b4a022261a274390b25bd29dfff4bf08505f3c2" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc 0.42.0", + "windows_i686_gnu 0.42.0", + "windows_i686_msvc 0.42.0", + "windows_x86_64_gnu 0.42.0", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc 0.42.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" [[package]] name = "windows_aarch64_msvc" @@ -2042,10 +2044,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" [[package]] -name = "windows_i686_gnu" -version = "0.28.0" +name = "windows_aarch64_msvc" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f54725ac23affef038fecb177de6c9bf065787c2f432f79e3c373da92f3e1d8a" +checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" [[package]] name = "windows_i686_gnu" @@ -2054,10 +2056,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" [[package]] -name = "windows_i686_msvc" -version = "0.28.0" +name = "windows_i686_gnu" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d5158a43cc43623c0729d1ad6647e62fa384a3d135fd15108d37c683461f64" +checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" [[package]] name = "windows_i686_msvc" @@ -2066,10 +2068,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" [[package]] -name = "windows_x86_64_gnu" -version = "0.28.0" +name = "windows_i686_msvc" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc31f409f565611535130cfe7ee8e6655d3fa99c1c61013981e491921b5ce954" +checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" [[package]] name = "windows_x86_64_gnu" @@ -2078,10 +2080,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" [[package]] -name = "windows_x86_64_msvc" -version = "0.28.0" +name = "windows_x86_64_gnu" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f2b8c7cbd3bfdddd9ab98769f9746a7fad1bca236554cd032b78d768bc0e89f" +checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" [[package]] name = "windows_x86_64_msvc" @@ -2089,6 +2097,12 @@ version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" + [[package]] name = "write-json" version = "0.1.2" diff --git a/crates/stdx/Cargo.toml b/crates/stdx/Cargo.toml index 957d16c036fab..f7b7d09640ff7 100644 --- a/crates/stdx/Cargo.toml +++ b/crates/stdx/Cargo.toml @@ -16,7 +16,7 @@ always-assert = { version = "0.1.2", features = ["log"] } # Think twice before adding anything here [target.'cfg(windows)'.dependencies] -miow = "0.4.0" +miow = "0.5.0" winapi = { version = "0.3.9", features = ["winerror"] } [features] From 15dfeabb96b370e9fab1ddbb8b39a9dcefc3764b Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 15 Nov 2022 12:05:11 +0100 Subject: [PATCH 41/81] Fix GAT completion not including generic parameters --- .../src/completions/item_list/trait_impl.rs | 77 +++++++++++++++---- 1 file changed, 63 insertions(+), 14 deletions(-) diff --git a/crates/ide-completion/src/completions/item_list/trait_impl.rs b/crates/ide-completion/src/completions/item_list/trait_impl.rs index e82cbfdcb8402..b612cdc4a1741 100644 --- a/crates/ide-completion/src/completions/item_list/trait_impl.rs +++ b/crates/ide-completion/src/completions/item_list/trait_impl.rs @@ -157,7 +157,7 @@ fn complete_trait_impl( add_function_impl(acc, ctx, replacement_range, func, hir_impl) } (hir::AssocItem::TypeAlias(type_alias), All | TypeAlias) => { - add_type_alias_impl(acc, ctx, replacement_range, type_alias) + add_type_alias_impl(acc, ctx, replacement_range, type_alias, hir_impl) } (hir::AssocItem::Const(const_), All | Const) => { add_const_impl(acc, ctx, replacement_range, const_, hir_impl) @@ -247,24 +247,50 @@ fn add_type_alias_impl( ctx: &CompletionContext<'_>, replacement_range: TextRange, type_alias: hir::TypeAlias, + impl_def: hir::Impl, ) { - let alias_name = type_alias.name(ctx.db); - let (alias_name, escaped_name) = - (alias_name.unescaped().to_smol_str(), alias_name.to_smol_str()); + let alias_name = type_alias.name(ctx.db).unescaped().to_smol_str(); let label = format!("type {} =", alias_name); - let replacement = format!("type {} = ", escaped_name); let mut item = CompletionItem::new(SymbolKind::TypeAlias, replacement_range, label); item.lookup_by(format!("type {}", alias_name)) .set_documentation(type_alias.docs(ctx.db)) .set_relevance(CompletionRelevance { is_item_from_trait: true, ..Default::default() }); - match ctx.config.snippet_cap { - Some(cap) => item - .snippet_edit(cap, TextEdit::replace(replacement_range, format!("{}$0;", replacement))), - None => item.text_edit(TextEdit::replace(replacement_range, replacement)), - }; - item.add_to(acc); + + if let Some(source) = ctx.sema.source(type_alias) { + let assoc_item = ast::AssocItem::TypeAlias(source.value); + if let Some(transformed_item) = get_transformed_assoc_item(ctx, assoc_item, impl_def) { + let transformed_ty = match transformed_item { + ast::AssocItem::TypeAlias(ty) => ty, + _ => unreachable!(), + }; + + let start = transformed_ty.syntax().text_range().start(); + let Some(end) = transformed_ty + .eq_token() + .map(|tok| tok.text_range().start()) + .or(transformed_ty.semicolon_token().map(|tok| tok.text_range().start())) else { return }; + + let len = end - start; + let mut decl = transformed_ty.syntax().text().slice(..len).to_string(); + if !decl.ends_with(' ') { + decl.push(' '); + } + decl.push_str("= "); + + match ctx.config.snippet_cap { + Some(cap) => { + let snippet = format!("{}$0;", decl); + item.snippet_edit(cap, TextEdit::replace(replacement_range, snippet)); + } + None => { + item.text_edit(TextEdit::replace(replacement_range, decl)); + } + }; + item.add_to(acc); + } + } } fn add_const_impl( @@ -350,9 +376,7 @@ fn function_declaration(node: &ast::Fn, needs_whitespace: bool) -> String { .map_or(end, |f| f.text_range().start()); let len = end - start; - let range = TextRange::new(0.into(), len); - - let syntax = node.text().slice(range).to_string(); + let syntax = node.text().slice(..len).to_string(); syntax.trim_end().to_owned() } @@ -1160,6 +1184,31 @@ impl Foo for Test { $0 } } +"#, + ); + } + + #[test] + fn includes_gat_generics() { + check_edit( + "type Ty", + r#" +trait Tr<'b> { + type Ty<'a: 'b, T: Copy, const C: usize>; +} + +impl<'b> Tr<'b> for () { + $0 +} +"#, + r#" +trait Tr<'b> { + type Ty<'a: 'b, T: Copy, const C: usize>; +} + +impl<'b> Tr<'b> for () { + type Ty<'a: 'b, T: Copy, const C: usize> = $0; +} "#, ); } From 6ed649fc8f606df25bde8e79dc3b17aa3d140c9b Mon Sep 17 00:00:00 2001 From: TheOddGarlic Date: Sat, 20 Aug 2022 14:28:43 +0300 Subject: [PATCH 42/81] Migrate "function cannot return without recursing" diagnostic --- Cargo.lock | 1 + .../locales/en-US/mir_build.ftl | 5 +++++ compiler/rustc_error_messages/src/lib.rs | 1 + compiler/rustc_mir_build/Cargo.toml | 1 + compiler/rustc_mir_build/src/errors.rs | 13 +++++++++++++ compiler/rustc_mir_build/src/lib.rs | 1 + compiler/rustc_mir_build/src/lints.rs | 19 +++++-------------- 7 files changed, 27 insertions(+), 14 deletions(-) create mode 100644 compiler/rustc_error_messages/locales/en-US/mir_build.ftl create mode 100644 compiler/rustc_mir_build/src/errors.rs diff --git a/Cargo.lock b/Cargo.lock index 9f64aa44314db..62ebc62f6f02b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3831,6 +3831,7 @@ dependencies = [ "rustc_hir", "rustc_index", "rustc_infer", + "rustc_macros", "rustc_middle", "rustc_serialize", "rustc_session", diff --git a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl new file mode 100644 index 0000000000000..b5bd2eb21a8ad --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl @@ -0,0 +1,5 @@ +mir_build_unconditional_recursion = function cannot return without recursing + .label = cannot return without recursing + .help = a `loop` may express intention better if this is on purpose + +mir_build_unconditional_recursion_call_site_label = recursive call site diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 0b1b75471a661..25aee6f681b58 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -57,6 +57,7 @@ fluent_messages! { metadata => "../locales/en-US/metadata.ftl", middle => "../locales/en-US/middle.ftl", mir_dataflow => "../locales/en-US/mir_dataflow.ftl", + mir_build => "../locales/en-US/mir_build.ftl", monomorphize => "../locales/en-US/monomorphize.ftl", parser => "../locales/en-US/parser.ftl", passes => "../locales/en-US/passes.ftl", diff --git a/compiler/rustc_mir_build/Cargo.toml b/compiler/rustc_mir_build/Cargo.toml index c726fa3a33fff..2322400526d55 100644 --- a/compiler/rustc_mir_build/Cargo.toml +++ b/compiler/rustc_mir_build/Cargo.toml @@ -16,6 +16,7 @@ rustc_index = { path = "../rustc_index" } rustc_errors = { path = "../rustc_errors" } rustc_hir = { path = "../rustc_hir" } rustc_infer = { path = "../rustc_infer" } +rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs new file mode 100644 index 0000000000000..1d44db7eb3a7d --- /dev/null +++ b/compiler/rustc_mir_build/src/errors.rs @@ -0,0 +1,13 @@ +use rustc_macros::LintDiagnostic; +use rustc_span::Span; + +#[derive(LintDiagnostic)] +#[lint(mir_build::unconditional_recursion)] +#[help] +pub struct UnconditionalRecursion { + #[primary_span] + #[label] + pub span: Span, + #[label(mir_build::unconditional_recursion_call_site_label)] + pub call_sites: Vec, +} diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index b53bd3d0710a6..364dd137cd6a7 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -18,6 +18,7 @@ extern crate rustc_middle; mod build; mod check_unsafety; +mod errors; mod lints; pub mod thir; diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs index b21f30efce807..383598fb094b6 100644 --- a/compiler/rustc_mir_build/src/lints.rs +++ b/compiler/rustc_mir_build/src/lints.rs @@ -1,3 +1,4 @@ +use crate::errors::UnconditionalRecursion; use rustc_data_structures::graph::iterate::{ NodeStatus, TriColorDepthFirstSearch, TriColorVisitor, }; @@ -36,20 +37,10 @@ pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { let sp = tcx.def_span(def_id); let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - tcx.struct_span_lint_hir( - UNCONDITIONAL_RECURSION, - hir_id, - sp, - "function cannot return without recursing", - |lint| { - lint.span_label(sp, "cannot return without recursing"); - // offer some help to the programmer. - for call_span in vis.reachable_recursive_calls { - lint.span_label(call_span, "recursive call site"); - } - lint.help("a `loop` may express intention better if this is on purpose") - }, - ); + tcx.emit_spanned_lint(UNCONDITIONAL_RECURSION, hir_id, sp, UnconditionalRecursion { + span: sp, + call_sites: vis.reachable_recursive_calls, + }); } } From 65f453357ecb1ec41518a165b40d2aeece176979 Mon Sep 17 00:00:00 2001 From: TheOddGarlic Date: Sat, 20 Aug 2022 23:54:58 +0300 Subject: [PATCH 43/81] Migrate "unsafe_op_in_unsafe_fn" lints --- .../locales/en-US/mir_build.ftl | 56 +++++++++++ .../rustc_mir_build/src/check_unsafety.rs | 92 +++++++++++++++++-- compiler/rustc_mir_build/src/errors.rs | 92 ++++++++++++++++++- compiler/rustc_mir_build/src/lints.rs | 10 +- 4 files changed, 236 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl index b5bd2eb21a8ad..2dfc4984786b9 100644 --- a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl +++ b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl @@ -3,3 +3,59 @@ mir_build_unconditional_recursion = function cannot return without recursing .help = a `loop` may express intention better if this is on purpose mir_build_unconditional_recursion_call_site_label = recursive call site + +mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe = + call to unsafe function `{$function}` is unsafe and requires unsafe block (error E0133) + .note = consult the function's documentation for information on how to avoid undefined behavior + .label = call to unsafe function + +mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe_nameless = + call to unsafe function is unsafe and requires unsafe block (error E0133) + .note = consult the function's documentation for information on how to avoid undefined behavior + .label = call to unsafe function + +mir_build_unsafe_op_in_unsafe_fn_inline_assembly_requires_unsafe = + use of inline assembly is unsafe and requires unsafe block (error E0133) + .note = inline assembly is entirely unchecked and can cause undefined behavior + .label = use of inline assembly + +mir_build_unsafe_op_in_unsafe_fn_initializing_type_with_requires_unsafe = + initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe + block (error E0133) + .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior + .label = initializing type with `rustc_layout_scalar_valid_range` attr + +mir_build_unsafe_op_in_unsafe_fn_mutable_static_requires_unsafe = + use of mutable static is unsafe and requires unsafe block (error E0133) + .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + .label = use of mutable static + +mir_build_unsafe_op_in_unsafe_fn_extern_static_requires_unsafe = + use of extern static is unsafe and requires unsafe block (error E0133) + .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior + .label = use of extern static + +mir_build_unsafe_op_in_unsafe_fn_deref_raw_pointer_requires_unsafe = + dereference of raw pointer is unsafe and requires unsafe block (error E0133) + .note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior + .label = dereference of raw pointer + +mir_build_unsafe_op_in_unsafe_fn_union_field_requires_unsafe = + access to union field is unsafe and requires unsafe block (error E0133) + .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior + .label = access to union field + +mir_build_unsafe_op_in_unsafe_fn_mutation_of_layout_constrained_field_requires_unsafe = + mutation of layout constrained field is unsafe and requires unsafe block (error E0133) + .note = mutating layout constrained fields cannot statically be checked for valid values + .label = mutation of layout constrained field + +mir_build_unsafe_op_in_unsafe_fn_borrow_of_layout_constrained_field_requires_unsafe = + borrow of layout constrained field with interior mutability is unsafe and requires unsafe block (error E0133) + .note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values + .label = borrow of layout constrained field with interior mutability + +mir_build_unsafe_op_in_unsafe_fn_call_to_fn_with_requires_unsafe = + call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block (error E0133) + .note = can only be called if the required target features are available + .label = call to function with `#[target_feature]` diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index fb1ea9ed300ad..a7993e7dfe4da 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -1,4 +1,5 @@ use crate::build::ExprCategory; +use crate::errors::*; use rustc_middle::thir::visit::{self, Visitor}; use rustc_errors::struct_span_err; @@ -83,15 +84,8 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> { } SafetyContext::UnsafeFn if unsafe_op_in_unsafe_fn_allowed => {} SafetyContext::UnsafeFn => { - let (description, note) = kind.description_and_note(self.tcx); // unsafe_op_in_unsafe_fn is disallowed - self.tcx.struct_span_lint_hir( - UNSAFE_OP_IN_UNSAFE_FN, - self.hir_context, - span, - format!("{} is unsafe and requires unsafe block (error E0133)", description,), - |lint| lint.span_label(span, kind.simple_description()).note(note), - ) + kind.emit_unsafe_op_in_unsafe_fn_lint(self.tcx, self.hir_context, span); } SafetyContext::Safe => { let (description, note) = kind.description_and_note(self.tcx); @@ -529,6 +523,88 @@ enum UnsafeOpKind { use UnsafeOpKind::*; impl UnsafeOpKind { + pub fn emit_unsafe_op_in_unsafe_fn_lint( + &self, + tcx: TyCtxt<'_>, + hir_id: hir::HirId, + span: Span, + ) { + match self { + CallToUnsafeFunction(did) if did.is_some() => tcx.emit_spanned_lint( + UNSAFE_OP_IN_UNSAFE_FN, + hir_id, + span, + UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafe { + span, + function: &tcx.def_path_str(did.unwrap()), + }, + ), + CallToUnsafeFunction(..) => tcx.emit_spanned_lint( + UNSAFE_OP_IN_UNSAFE_FN, + hir_id, + span, + UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafeNameless { span }, + ), + UseOfInlineAssembly => tcx.emit_spanned_lint( + UNSAFE_OP_IN_UNSAFE_FN, + hir_id, + span, + UnsafeOpInUnsafeUseOfInlineAssemblyRequiresUnsafe { span }, + ), + InitializingTypeWith => tcx.emit_spanned_lint( + UNSAFE_OP_IN_UNSAFE_FN, + hir_id, + span, + UnsafeOpInUnsafeInitializingTypeWithRequiresUnsafe { span }, + ), + UseOfMutableStatic => tcx.emit_spanned_lint( + UNSAFE_OP_IN_UNSAFE_FN, + hir_id, + span, + UnsafeOpInUnsafeUseOfMutableStaticRequiresUnsafe { span }, + ), + UseOfExternStatic => tcx.emit_spanned_lint( + UNSAFE_OP_IN_UNSAFE_FN, + hir_id, + span, + UnsafeOpInUnsafeUseOfExternStaticRequiresUnsafe { span }, + ), + DerefOfRawPointer => tcx.emit_spanned_lint( + UNSAFE_OP_IN_UNSAFE_FN, + hir_id, + span, + UnsafeOpInUnsafeDerefOfRawPointerRequiresUnsafe { span }, + ), + AccessToUnionField => tcx.emit_spanned_lint( + UNSAFE_OP_IN_UNSAFE_FN, + hir_id, + span, + UnsafeOpInUnsafeAccessToUnionFieldRequiresUnsafe { span }, + ), + MutationOfLayoutConstrainedField => tcx.emit_spanned_lint( + UNSAFE_OP_IN_UNSAFE_FN, + hir_id, + span, + UnsafeOpInUnsafeMutationOfLayoutConstrainedFieldRequiresUnsafe { span }, + ), + BorrowOfLayoutConstrainedField => tcx.emit_spanned_lint( + UNSAFE_OP_IN_UNSAFE_FN, + hir_id, + span, + UnsafeOpInUnsafeBorrowOfLayoutConstrainedFieldRequiresUnsafe { span }, + ), + CallToFunctionWith(did) => tcx.emit_spanned_lint( + UNSAFE_OP_IN_UNSAFE_FN, + hir_id, + span, + UnsafeOpInUnsafeCallToFunctionWithRequiresUnsafe { + span, + function: &tcx.def_path_str(*did), + }, + ), + } + } + pub fn simple_description(&self) -> &'static str { match self { CallToUnsafeFunction(..) => "call to unsafe function", diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 1d44db7eb3a7d..61131c0d733cd 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -2,12 +2,100 @@ use rustc_macros::LintDiagnostic; use rustc_span::Span; #[derive(LintDiagnostic)] -#[lint(mir_build::unconditional_recursion)] +#[diag(mir_build::unconditional_recursion)] #[help] pub struct UnconditionalRecursion { - #[primary_span] #[label] pub span: Span, #[label(mir_build::unconditional_recursion_call_site_label)] pub call_sites: Vec, } + +#[derive(LintDiagnostic)] +#[diag(mir_build::unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe)] +#[note] +pub struct UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafe<'a> { + #[label] + pub span: Span, + pub function: &'a str, +} + +#[derive(LintDiagnostic)] +#[diag(mir_build::unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe_nameless)] +#[note] +pub struct UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafeNameless { + #[label] + pub span: Span, +} + +#[derive(LintDiagnostic)] +#[diag(mir_build::unsafe_op_in_unsafe_fn_inline_assembly_requires_unsafe)] +#[note] +pub struct UnsafeOpInUnsafeFnUseOfInlineAssemblyRequiresUnsafe { + #[label] + pub span: Span, +} + +#[derive(LintDiagnostic)] +#[diag(mir_build::unsafe_op_in_unsafe_fn_initializing_type_with_requires_unsafe)] +#[note] +pub struct UnsafeOpInUnsafeFnInitializingTypeWithRequiresUnsafe { + #[label] + pub span: Span, +} + +#[derive(LintDiagnostic)] +#[diag(mir_build::unsafe_op_in_unsafe_fn_mutable_static_requires_unsafe)] +#[note] +pub struct UnsafeOpInUnsafeFnUseOfMutableStaticRequiresUnsafe { + #[label] + pub span: Span, +} + +#[derive(LintDiagnostic)] +#[diag(mir_build::unsafe_op_in_unsafe_fn_extern_static_requires_unsafe)] +#[note] +pub struct UnsafeOpInUnsafeFnUseOfExternStaticRequiresUnsafe { + #[label] + pub span: Span, +} + +#[derive(LintDiagnostic)] +#[diag(mir_build::unsafe_op_in_unsafe_fn_deref_raw_pointer_requires_unsafe)] +#[note] +pub struct UnsafeOpInUnsafeFnDerefOfRawPointerRequiresUnsafe { + #[label] + pub span: Span, +} + +#[derive(LintDiagnostic)] +#[diag(mir_build::unsafe_op_in_unsafe_fn_union_field_requires_unsafe)] +#[note] +pub struct UnsafeOpInUnsafeFnAccessToUnionFieldRequiresUnsafe { + #[label] + pub span: Span, +} + +#[derive(LintDiagnostic)] +#[diag(mir_build::unsafe_op_in_unsafe_fn_mutation_of_layout_constrained_field_requires_unsafe)] +#[note] +pub struct UnsafeOpInUnsafeFnMutationOfLayoutConstrainedFieldRequiresUnsafe { + #[label] + pub span: Span, +} + +#[derive(LintDiagnostic)] +#[diag(mir_build::unsafe_op_in_unsafe_fn_borrow_of_layout_constrained_field_requires_unsafe)] +pub struct UnsafeOpInUnsafeFnBorrowOfLayoutConstrainedFieldRequiresUnsafe { + #[label] + pub span: Span, +} + +#[derive(LintDiagnostic)] +#[diag(mir_build::unsafe_op_in_unsafe_fn_call_to_fn_with_requires_unsafe)] +#[note] +pub struct UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe<'a> { + #[label] + pub span: Span, + pub function: &'a str, +} diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs index 383598fb094b6..8529c64cd5cca 100644 --- a/compiler/rustc_mir_build/src/lints.rs +++ b/compiler/rustc_mir_build/src/lints.rs @@ -37,10 +37,12 @@ pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { let sp = tcx.def_span(def_id); let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - tcx.emit_spanned_lint(UNCONDITIONAL_RECURSION, hir_id, sp, UnconditionalRecursion { - span: sp, - call_sites: vis.reachable_recursive_calls, - }); + tcx.emit_spanned_lint( + UNCONDITIONAL_RECURSION, + hir_id, + sp, + UnconditionalRecursion { span: sp, call_sites: vis.reachable_recursive_calls }, + ); } } From 9c3f8d1f0cd03ee4e8926d170cbfb0aa4f8f440c Mon Sep 17 00:00:00 2001 From: TheOddGarlic Date: Wed, 24 Aug 2022 11:01:53 +0300 Subject: [PATCH 44/81] Migrate "requires unsafe" diagnostics --- .../locales/en-US/mir_build.ftl | 110 +++++++++ .../rustc_mir_build/src/check_unsafety.rs | 200 ++++++++-------- compiler/rustc_mir_build/src/errors.rs | 216 +++++++++++++++++- 3 files changed, 431 insertions(+), 95 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl index 2dfc4984786b9..fd42cc6cb0876 100644 --- a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl +++ b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl @@ -59,3 +59,113 @@ mir_build_unsafe_op_in_unsafe_fn_call_to_fn_with_requires_unsafe = call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block (error E0133) .note = can only be called if the required target features are available .label = call to function with `#[target_feature]` + +mir_build_call_to_unsafe_fn_requires_unsafe = + call to unsafe function `{$function}` is unsafe and requires unsafe block + .note = consult the function's documentation for information on how to avoid undefined behavior + .label = call to unsafe function + +mir_build_call_to_unsafe_fn_requires_unsafe_nameless = + call to unsafe function is unsafe and requires unsafe block + .note = consult the function's documentation for information on how to avoid undefined behavior + .label = call to unsafe function + +mir_build_call_to_unsafe_fn_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = + call to unsafe function `{$function}` is unsafe and requires unsafe function or block + .note = consult the function's documentation for information on how to avoid undefined behavior + .label = call to unsafe function + +mir_build_call_to_unsafe_fn_requires_unsafe_nameless_unsafe_op_in_unsafe_fn_allowed = + call to unsafe function is unsafe and requires unsafe function or block + .note = consult the function's documentation for information on how to avoid undefined behavior + .label = call to unsafe function + +mir_build_inline_assembly_requires_unsafe = + use of inline assembly is unsafe and requires unsafe block + .note = inline assembly is entirely unchecked and can cause undefined behavior + .label = use of inline assembly + +mir_build_inline_assembly_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = + use of inline assembly is unsafe and requires unsafe function or block + .note = inline assembly is entirely unchecked and can cause undefined behavior + .label = use of inline assembly + +mir_build_initializing_type_with_requires_unsafe = + initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe block + .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior + .label = initializing type with `rustc_layout_scalar_valid_range` attr + +mir_build_initializing_type_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = + initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe function or block + .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior + .label = initializing type with `rustc_layout_scalar_valid_range` attr + +mir_build_mutable_static_requires_unsafe = + use of mutable static is unsafe and requires unsafe block + .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + .label = use of mutable static + +mir_build_mutable_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = + use of mutable static is unsafe and requires unsafe function or block + .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + .label = use of mutable static + +mir_build_extern_static_requires_unsafe = + use of extern static is unsafe and requires unsafe block + .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior + .label = use of extern static + +mir_build_extern_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = + use of extern static is unsafe and requires unsafe function or block + .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior + .label = use of extern static + +mir_build_deref_raw_pointer_requires_unsafe = + dereference of raw pointer is unsafe and requires unsafe block + .note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior + .label = dereference of raw pointer + +mir_build_deref_raw_pointer_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = + dereference of raw pointer is unsafe and requires unsafe function or block + .note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior + .label = dereference of raw pointer + +mir_build_union_field_requires_unsafe = + access to union field is unsafe and requires unsafe block + .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior + .label = access to union field + +mir_build_union_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = + access to union field is unsafe and requires unsafe function or block + .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior + .label = access to union field + +mir_build_mutation_of_layout_constrained_field_requires_unsafe = + mutation of layout constrained field is unsafe and requires unsafe block + .note = mutating layout constrained fields cannot statically be checked for valid values + .label = mutation of layout constrained field + +mir_build_mutation_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = + mutation of layout constrained field is unsafe and requires unsafe function or block + .note = mutating layout constrained fields cannot statically be checked for valid values + .label = mutation of layout constrained field + +mir_build_borrow_of_layout_constrained_field_requires_unsafe = + borrow of layout constrained field with interior mutability is unsafe and requires unsafe block + .note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values + .label = borrow of layout constrained field with interior mutability + +mir_build_borrow_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = + borrow of layout constrained field with interior mutability is unsafe and requires unsafe function or block + .note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values + .label = borrow of layout constrained field with interior mutability + +mir_build_call_to_fn_with_requires_unsafe = + call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block + .note = can only be called if the required target features are available + .label = call to function with `#[target_feature]` + +mir_build_call_to_fn_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = + call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe function or block + .note = can only be called if the required target features are available + .label = call to function with `#[target_feature]` diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index a7993e7dfe4da..b68241bc96b8e 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -2,7 +2,6 @@ use crate::build::ExprCategory; use crate::errors::*; use rustc_middle::thir::visit::{self, Visitor}; -use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_middle::mir::BorrowKind; use rustc_middle::thir::*; @@ -13,7 +12,6 @@ use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::symbol::Symbol; use rustc_span::Span; -use std::borrow::Cow; use std::ops::Bound; struct UnsafetyVisitor<'a, 'tcx> { @@ -88,19 +86,7 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> { kind.emit_unsafe_op_in_unsafe_fn_lint(self.tcx, self.hir_context, span); } SafetyContext::Safe => { - let (description, note) = kind.description_and_note(self.tcx); - let fn_sugg = if unsafe_op_in_unsafe_fn_allowed { " function or" } else { "" }; - struct_span_err!( - self.tcx.sess, - span, - E0133, - "{} is unsafe and requires unsafe{} block", - description, - fn_sugg, - ) - .span_label(span, kind.simple_description()) - .note(note) - .emit(); + kind.emit_requires_unsafe_err(self.tcx, span, unsafe_op_in_unsafe_fn_allowed); } } } @@ -549,55 +535,55 @@ impl UnsafeOpKind { UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, - UnsafeOpInUnsafeUseOfInlineAssemblyRequiresUnsafe { span }, + UnsafeOpInUnsafeFnUseOfInlineAssemblyRequiresUnsafe { span }, ), InitializingTypeWith => tcx.emit_spanned_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, - UnsafeOpInUnsafeInitializingTypeWithRequiresUnsafe { span }, + UnsafeOpInUnsafeFnInitializingTypeWithRequiresUnsafe { span }, ), UseOfMutableStatic => tcx.emit_spanned_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, - UnsafeOpInUnsafeUseOfMutableStaticRequiresUnsafe { span }, + UnsafeOpInUnsafeFnUseOfMutableStaticRequiresUnsafe { span }, ), UseOfExternStatic => tcx.emit_spanned_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, - UnsafeOpInUnsafeUseOfExternStaticRequiresUnsafe { span }, + UnsafeOpInUnsafeFnUseOfExternStaticRequiresUnsafe { span }, ), DerefOfRawPointer => tcx.emit_spanned_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, - UnsafeOpInUnsafeDerefOfRawPointerRequiresUnsafe { span }, + UnsafeOpInUnsafeFnDerefOfRawPointerRequiresUnsafe { span }, ), AccessToUnionField => tcx.emit_spanned_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, - UnsafeOpInUnsafeAccessToUnionFieldRequiresUnsafe { span }, + UnsafeOpInUnsafeFnAccessToUnionFieldRequiresUnsafe { span }, ), MutationOfLayoutConstrainedField => tcx.emit_spanned_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, - UnsafeOpInUnsafeMutationOfLayoutConstrainedFieldRequiresUnsafe { span }, + UnsafeOpInUnsafeFnMutationOfLayoutConstrainedFieldRequiresUnsafe { span }, ), BorrowOfLayoutConstrainedField => tcx.emit_spanned_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, - UnsafeOpInUnsafeBorrowOfLayoutConstrainedFieldRequiresUnsafe { span }, + UnsafeOpInUnsafeFnBorrowOfLayoutConstrainedFieldRequiresUnsafe { span }, ), CallToFunctionWith(did) => tcx.emit_spanned_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, - UnsafeOpInUnsafeCallToFunctionWithRequiresUnsafe { + UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe { span, function: &tcx.def_path_str(*did), }, @@ -605,79 +591,105 @@ impl UnsafeOpKind { } } - pub fn simple_description(&self) -> &'static str { + pub fn emit_requires_unsafe_err( + &self, + tcx: TyCtxt<'_>, + span: Span, + unsafe_op_in_unsafe_fn_allowed: bool, + ) { match self { - CallToUnsafeFunction(..) => "call to unsafe function", - UseOfInlineAssembly => "use of inline assembly", - InitializingTypeWith => "initializing type with `rustc_layout_scalar_valid_range` attr", - UseOfMutableStatic => "use of mutable static", - UseOfExternStatic => "use of extern static", - DerefOfRawPointer => "dereference of raw pointer", - AccessToUnionField => "access to union field", - MutationOfLayoutConstrainedField => "mutation of layout constrained field", + CallToUnsafeFunction(did) if did.is_some() && unsafe_op_in_unsafe_fn_allowed => { + tcx.sess.emit_err(CallToUnsafeFunctionRequiresUnsafeUnsafeOpInUnsafeFnAllowed { + span, + function: &tcx.def_path_str(did.unwrap()), + }); + } + CallToUnsafeFunction(did) if did.is_some() => { + tcx.sess.emit_err(CallToUnsafeFunctionRequiresUnsafe { + span, + function: &tcx.def_path_str(did.unwrap()), + }); + } + CallToUnsafeFunction(..) if unsafe_op_in_unsafe_fn_allowed => { + tcx.sess.emit_err( + CallToUnsafeFunctionRequiresUnsafeNamelessUnsafeOpInUnsafeFnAllowed { span }, + ); + } + CallToUnsafeFunction(..) => { + tcx.sess.emit_err(CallToUnsafeFunctionRequiresUnsafeNameless { span }); + } + UseOfInlineAssembly if unsafe_op_in_unsafe_fn_allowed => { + tcx.sess + .emit_err(UseOfInlineAssemblyRequiresUnsafeUnsafeOpInUnsafeFnAllowed { span }); + } + UseOfInlineAssembly => { + tcx.sess.emit_err(UseOfInlineAssemblyRequiresUnsafe { span }); + } + InitializingTypeWith if unsafe_op_in_unsafe_fn_allowed => { + tcx.sess + .emit_err(InitializingTypeWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed { span }); + } + InitializingTypeWith => { + tcx.sess.emit_err(InitializingTypeWithRequiresUnsafe { span }); + } + UseOfMutableStatic if unsafe_op_in_unsafe_fn_allowed => { + tcx.sess + .emit_err(UseOfMutableStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed { span }); + } + UseOfMutableStatic => { + tcx.sess.emit_err(UseOfMutableStaticRequiresUnsafe { span }); + } + UseOfExternStatic if unsafe_op_in_unsafe_fn_allowed => { + tcx.sess + .emit_err(UseOfExternStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed { span }); + } + UseOfExternStatic => { + tcx.sess.emit_err(UseOfExternStaticRequiresUnsafe { span }); + } + DerefOfRawPointer if unsafe_op_in_unsafe_fn_allowed => { + tcx.sess + .emit_err(DerefOfRawPointerRequiresUnsafeUnsafeOpInUnsafeFnAllowed { span }); + } + DerefOfRawPointer => { + tcx.sess.emit_err(DerefOfRawPointerRequiresUnsafe { span }); + } + AccessToUnionField if unsafe_op_in_unsafe_fn_allowed => { + tcx.sess + .emit_err(AccessToUnionFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed { span }); + } + AccessToUnionField => { + tcx.sess.emit_err(AccessToUnionFieldRequiresUnsafe { span }); + } + MutationOfLayoutConstrainedField if unsafe_op_in_unsafe_fn_allowed => { + tcx.sess.emit_err( + MutationOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed { + span, + }, + ); + } + MutationOfLayoutConstrainedField => { + tcx.sess.emit_err(MutationOfLayoutConstrainedFieldRequiresUnsafe { span }); + } + BorrowOfLayoutConstrainedField if unsafe_op_in_unsafe_fn_allowed => { + tcx.sess.emit_err( + BorrowOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed { span }, + ); + } BorrowOfLayoutConstrainedField => { - "borrow of layout constrained field with interior mutability" + tcx.sess.emit_err(BorrowOfLayoutConstrainedFieldRequiresUnsafe { span }); + } + CallToFunctionWith(did) if unsafe_op_in_unsafe_fn_allowed => { + tcx.sess.emit_err(CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed { + span, + function: &tcx.def_path_str(*did), + }); + } + CallToFunctionWith(did) => { + tcx.sess.emit_err(CallToFunctionWithRequiresUnsafe { + span, + function: &tcx.def_path_str(*did), + }); } - CallToFunctionWith(..) => "call to function with `#[target_feature]`", - } - } - - pub fn description_and_note(&self, tcx: TyCtxt<'_>) -> (Cow<'static, str>, &'static str) { - match self { - CallToUnsafeFunction(did) => ( - if let Some(did) = did { - Cow::from(format!("call to unsafe function `{}`", tcx.def_path_str(*did))) - } else { - Cow::Borrowed(self.simple_description()) - }, - "consult the function's documentation for information on how to avoid undefined \ - behavior", - ), - UseOfInlineAssembly => ( - Cow::Borrowed(self.simple_description()), - "inline assembly is entirely unchecked and can cause undefined behavior", - ), - InitializingTypeWith => ( - Cow::Borrowed(self.simple_description()), - "initializing a layout restricted type's field with a value outside the valid \ - range is undefined behavior", - ), - UseOfMutableStatic => ( - Cow::Borrowed(self.simple_description()), - "mutable statics can be mutated by multiple threads: aliasing violations or data \ - races will cause undefined behavior", - ), - UseOfExternStatic => ( - Cow::Borrowed(self.simple_description()), - "extern statics are not controlled by the Rust type system: invalid data, \ - aliasing violations or data races will cause undefined behavior", - ), - DerefOfRawPointer => ( - Cow::Borrowed(self.simple_description()), - "raw pointers may be null, dangling or unaligned; they can violate aliasing rules \ - and cause data races: all of these are undefined behavior", - ), - AccessToUnionField => ( - Cow::Borrowed(self.simple_description()), - "the field may not be properly initialized: using uninitialized data will cause \ - undefined behavior", - ), - MutationOfLayoutConstrainedField => ( - Cow::Borrowed(self.simple_description()), - "mutating layout constrained fields cannot statically be checked for valid values", - ), - BorrowOfLayoutConstrainedField => ( - Cow::Borrowed(self.simple_description()), - "references to fields of layout constrained fields lose the constraints. Coupled \ - with interior mutability, the field can be changed to invalid values", - ), - CallToFunctionWith(did) => ( - Cow::from(format!( - "call to function `{}` with `#[target_feature]`", - tcx.def_path_str(*did) - )), - "can only be called if the required target features are available", - ), } } } diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 61131c0d733cd..260a9f6375bb9 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -1,4 +1,4 @@ -use rustc_macros::LintDiagnostic; +use rustc_macros::{LintDiagnostic, SessionDiagnostic}; use rustc_span::Span; #[derive(LintDiagnostic)] @@ -99,3 +99,217 @@ pub struct UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe<'a> { pub span: Span, pub function: &'a str, } + +#[derive(SessionDiagnostic)] +#[diag(mir_build::call_to_unsafe_fn_requires_unsafe, code = "E0133")] +#[note] +pub struct CallToUnsafeFunctionRequiresUnsafe<'a> { + #[primary_span] + #[label] + pub span: Span, + pub function: &'a str, +} + +#[derive(SessionDiagnostic)] +#[diag(mir_build::call_to_unsafe_fn_requires_unsafe_nameless, code = "E0133")] +#[note] +pub struct CallToUnsafeFunctionRequiresUnsafeNameless { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(mir_build::call_to_unsafe_fn_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")] +#[note] +pub struct CallToUnsafeFunctionRequiresUnsafeUnsafeOpInUnsafeFnAllowed<'a> { + #[primary_span] + #[label] + pub span: Span, + pub function: &'a str, +} + +#[derive(SessionDiagnostic)] +#[diag( + mir_build::call_to_unsafe_fn_requires_unsafe_nameless_unsafe_op_in_unsafe_fn_allowed, + code = "E0133" +)] +#[note] +pub struct CallToUnsafeFunctionRequiresUnsafeNamelessUnsafeOpInUnsafeFnAllowed { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(mir_build::inline_assembly_requires_unsafe, code = "E0133")] +#[note] +pub struct UseOfInlineAssemblyRequiresUnsafe { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(mir_build::inline_assembly_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")] +#[note] +pub struct UseOfInlineAssemblyRequiresUnsafeUnsafeOpInUnsafeFnAllowed { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(mir_build::initializing_type_with_requires_unsafe, code = "E0133")] +#[note] +pub struct InitializingTypeWithRequiresUnsafe { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag( + mir_build::initializing_type_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, + code = "E0133" +)] +#[note] +pub struct InitializingTypeWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(mir_build::mutable_static_requires_unsafe, code = "E0133")] +#[note] +pub struct UseOfMutableStaticRequiresUnsafe { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(mir_build::mutable_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")] +#[note] +pub struct UseOfMutableStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(mir_build::extern_static_requires_unsafe, code = "E0133")] +#[note] +pub struct UseOfExternStaticRequiresUnsafe { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(mir_build::extern_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")] +#[note] +pub struct UseOfExternStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(mir_build::deref_raw_pointer_requires_unsafe, code = "E0133")] +#[note] +pub struct DerefOfRawPointerRequiresUnsafe { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(mir_build::deref_raw_pointer_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")] +#[note] +pub struct DerefOfRawPointerRequiresUnsafeUnsafeOpInUnsafeFnAllowed { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(mir_build::union_field_requires_unsafe, code = "E0133")] +#[note] +pub struct AccessToUnionFieldRequiresUnsafe { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(mir_build::union_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")] +#[note] +pub struct AccessToUnionFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(mir_build::mutation_of_layout_constrained_field_requires_unsafe, code = "E0133")] +#[note] +pub struct MutationOfLayoutConstrainedFieldRequiresUnsafe { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag( + mir_build::mutation_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, + code = "E0133" +)] +#[note] +pub struct MutationOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(mir_build::borrow_of_layout_constrained_field_requires_unsafe, code = "E0133")] +#[note] +pub struct BorrowOfLayoutConstrainedFieldRequiresUnsafe { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag( + mir_build::borrow_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, + code = "E0133" +)] +#[note] +pub struct BorrowOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(mir_build::call_to_fn_with_requires_unsafe, code = "E0133")] +#[note] +pub struct CallToFunctionWithRequiresUnsafe<'a> { + #[primary_span] + #[label] + pub span: Span, + pub function: &'a str, +} + +#[derive(SessionDiagnostic)] +#[diag(mir_build::call_to_fn_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")] +#[note] +pub struct CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed<'a> { + #[primary_span] + #[label] + pub span: Span, + pub function: &'a str, +} From 1696fb2a94696ec21d86a10df777c7c02cfea9b1 Mon Sep 17 00:00:00 2001 From: TheOddGarlic Date: Wed, 24 Aug 2022 20:16:50 +0300 Subject: [PATCH 45/81] Migrate "unused unsafe" lint --- .../locales/en-US/mir_build.ftl | 6 +++++ .../rustc_mir_build/src/check_unsafety.rs | 24 ++++++++++-------- compiler/rustc_mir_build/src/errors.rs | 25 ++++++++++++++++++- 3 files changed, 43 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl index fd42cc6cb0876..9dab6f8e88320 100644 --- a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl +++ b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl @@ -169,3 +169,9 @@ mir_build_call_to_fn_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe function or block .note = can only be called if the required target features are available .label = call to function with `#[target_feature]` + +mir_build_unused_unsafe = unnecessary `unsafe` block + .label = unnecessary `unsafe` block + +mir_build_unused_unsafe_enclosing_block_label = because it's nested under this `unsafe` block +mir_build_unused_unsafe_enclosing_fn_label = because it's nested under this `unsafe` fn diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index b68241bc96b8e..3f0f05711edd3 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -45,7 +45,9 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> { self.warn_unused_unsafe( hir_id, block_span, - Some((self.tcx.sess.source_map().guess_head_span(enclosing_span), "block")), + Some(UnusedUnsafeEnclosing::Block { + span: self.tcx.sess.source_map().guess_head_span(enclosing_span), + }), ); f(self); } else { @@ -59,7 +61,9 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> { hir_id, span, if self.unsafe_op_in_unsafe_fn_allowed() { - self.body_unsafety.unsafe_fn_sig_span().map(|span| (span, "fn")) + self.body_unsafety + .unsafe_fn_sig_span() + .map(|span| UnusedUnsafeEnclosing::Function { span }) } else { None }, @@ -95,17 +99,15 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> { &self, hir_id: hir::HirId, block_span: Span, - enclosing_unsafe: Option<(Span, &'static str)>, + enclosing_unsafe: Option, ) { let block_span = self.tcx.sess.source_map().guess_head_span(block_span); - let msg = "unnecessary `unsafe` block"; - self.tcx.struct_span_lint_hir(UNUSED_UNSAFE, hir_id, block_span, msg, |lint| { - lint.span_label(block_span, msg); - if let Some((span, kind)) = enclosing_unsafe { - lint.span_label(span, format!("because it's nested under this `unsafe` {}", kind)); - } - lint - }); + self.tcx.emit_spanned_lint( + UNUSED_UNSAFE, + hir_id, + block_span, + UnusedUnsafe { span: block_span, enclosing: enclosing_unsafe }, + ); } /// Whether the `unsafe_op_in_unsafe_fn` lint is `allow`ed at the current HIR node. diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 260a9f6375bb9..a3e8715122667 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -1,4 +1,4 @@ -use rustc_macros::{LintDiagnostic, SessionDiagnostic}; +use rustc_macros::{LintDiagnostic, SessionDiagnostic, SessionSubdiagnostic}; use rustc_span::Span; #[derive(LintDiagnostic)] @@ -313,3 +313,26 @@ pub struct CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed<'a> { pub span: Span, pub function: &'a str, } + +#[derive(LintDiagnostic)] +#[diag(mir_build::unused_unsafe)] +pub struct UnusedUnsafe { + #[label] + pub span: Span, + #[subdiagnostic] + pub enclosing: Option, +} + +#[derive(SessionSubdiagnostic)] +pub enum UnusedUnsafeEnclosing { + #[label(mir_build::unused_unsafe_enclosing_block_label)] + Block { + #[primary_span] + span: Span, + }, + #[label(mir_build::unused_unsafe_enclosing_fn_label)] + Function { + #[primary_span] + span: Span, + }, +} From c9dc023b37d4fdfb9bd4f6458786f0a67ca6e3a8 Mon Sep 17 00:00:00 2001 From: TheOddGarlic Date: Fri, 26 Aug 2022 16:38:21 +0300 Subject: [PATCH 46/81] Migrate "non-exhaustive patterns: type is non-empty" diagnostic --- .../locales/en-US/mir_build.ftl | 8 ++ compiler/rustc_mir_build/src/errors.rs | 93 +++++++++++++++++++ .../src/thir/pattern/check_match.rs | 18 ++-- .../rustc_mir_build/src/thir/pattern/mod.rs | 1 + 4 files changed, 113 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl index 9dab6f8e88320..5fb89dcccaeeb 100644 --- a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl +++ b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl @@ -175,3 +175,11 @@ mir_build_unused_unsafe = unnecessary `unsafe` block mir_build_unused_unsafe_enclosing_block_label = because it's nested under this `unsafe` block mir_build_unused_unsafe_enclosing_fn_label = because it's nested under this `unsafe` fn + +mir_build_non_exhaustive_patterns_type_not_empty = non-exhaustive patterns: type `{$ty}` is non-empty + .def_note = `{$peeled_ty}` defined here + .type_note = the matched value is of type `{$ty}` + .non_exhaustive_type_note = the matched value is of type `{$ty}`, which is marked as non-exhaustive + .reference_note = references are always considered inhabited + .suggestion = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + .help = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index a3e8715122667..9e63141d7160c 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -1,4 +1,8 @@ +use crate::thir::pattern::MatchCheckCtxt; +use rustc_errors::{error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, MultiSpan}; use rustc_macros::{LintDiagnostic, SessionDiagnostic, SessionSubdiagnostic}; +use rustc_middle::ty::{self, Ty}; +use rustc_session::{parse::ParseSess, SessionDiagnostic}; use rustc_span::Span; #[derive(LintDiagnostic)] @@ -336,3 +340,92 @@ pub enum UnusedUnsafeEnclosing { span: Span, }, } + +pub(crate) struct NonExhaustivePatternsTypeNotEmpty<'p, 'tcx, 'm> { + pub cx: &'m MatchCheckCtxt<'p, 'tcx>, + pub expr_span: Span, + pub span: Span, + pub ty: Ty<'tcx>, +} + +impl<'a> SessionDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> { + fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'_, ErrorGuaranteed> { + let mut diag = sess.span_diagnostic.struct_span_err_with_code( + self.span, + rustc_errors::fluent::mir_build::non_exhaustive_patterns_type_not_empty, + error_code!(E0004), + ); + + let peeled_ty = self.ty.peel_refs(); + diag.set_arg("ty", self.ty); + diag.set_arg("peeled_ty", peeled_ty); + + if let ty::Adt(def, _) = peeled_ty.kind() { + let def_span = self + .cx + .tcx + .hir() + .get_if_local(def.did()) + .and_then(|node| node.ident()) + .map(|ident| ident.span) + .unwrap_or_else(|| self.cx.tcx.def_span(def.did())); + + // workaround to make test pass + let mut span: MultiSpan = def_span.into(); + span.push_span_label(def_span, ""); + + diag.span_note(span, rustc_errors::fluent::mir_build::def_note); + } + + let is_variant_list_non_exhaustive = match self.ty.kind() { + ty::Adt(def, _) if def.is_variant_list_non_exhaustive() && !def.did().is_local() => { + true + } + _ => false, + }; + + if is_variant_list_non_exhaustive { + diag.note(rustc_errors::fluent::mir_build::non_exhaustive_type_note); + } else { + diag.note(rustc_errors::fluent::mir_build::type_note); + } + + if let ty::Ref(_, sub_ty, _) = self.ty.kind() { + if self.cx.tcx.is_ty_uninhabited_from(self.cx.module, *sub_ty, self.cx.param_env) { + diag.note(rustc_errors::fluent::mir_build::reference_note); + } + } + + let mut suggestion = None; + let sm = self.cx.tcx.sess.source_map(); + if self.span.eq_ctxt(self.expr_span) { + // Get the span for the empty match body `{}`. + let (indentation, more) = if let Some(snippet) = sm.indentation_before(self.span) { + (format!("\n{}", snippet), " ") + } else { + (" ".to_string(), "") + }; + suggestion = Some(( + self.span.shrink_to_hi().with_hi(self.expr_span.hi()), + format!( + " {{{indentation}{more}_ => todo!(),{indentation}}}", + indentation = indentation, + more = more, + ), + )); + } + + if let Some((span, sugg)) = suggestion { + diag.span_suggestion_verbose( + span, + rustc_errors::fluent::mir_build::suggestion, + sugg, + Applicability::HasPlaceholders, + ); + } else { + diag.help(rustc_errors::fluent::mir_build::help); + } + + diag + } +} 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 93a3dd8962a9e..d906666b96a35 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -4,6 +4,8 @@ use super::usefulness::{ }; use super::{PatCtxt, PatternError}; +use crate::errors::NonExhaustivePatternsTypeNotEmpty; + use rustc_arena::TypedArena; use rustc_ast::Mutability; use rustc_errors::{ @@ -760,15 +762,17 @@ fn non_exhaustive_match<'p, 'tcx>( // informative. let mut err; let pattern; - let mut patterns_len = 0; + let patterns_len; if is_empty_match && !non_empty_enum { - err = create_e0004( - cx.tcx.sess, - sp, - format!("non-exhaustive patterns: type `{}` is non-empty", scrut_ty), - ); - pattern = "_".to_string(); + cx.tcx.sess.emit_err(NonExhaustivePatternsTypeNotEmpty { + cx, + expr_span, + span: sp, + ty: scrut_ty, + }); + return; } else { + // FIXME: migration of this diagnostic will require list support let joined_patterns = joined_uncovered_patterns(cx, &witnesses); err = create_e0004( cx.tcx.sess, diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 80b532aec6c1a..2683919bb1b51 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -6,6 +6,7 @@ mod deconstruct_pat; mod usefulness; pub(crate) use self::check_match::check_match; +pub(crate) use self::usefulness::MatchCheckCtxt; use crate::thir::util::UserAnnotatedTyHelpers; From fb90cb3c1f19f2bb111497ba72c00ecb3850a6af Mon Sep 17 00:00:00 2001 From: TheOddGarlic Date: Fri, 26 Aug 2022 19:30:33 +0300 Subject: [PATCH 47/81] Migrate pattern inlining error diagnostics --- .../locales/en-US/mir_build.ftl | 8 ++++++ compiler/rustc_mir_build/src/errors.rs | 28 +++++++++++++++++++ .../src/thir/pattern/check_match.rs | 18 ++++-------- 3 files changed, 41 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl index 5fb89dcccaeeb..610e16ab7d8e7 100644 --- a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl +++ b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl @@ -183,3 +183,11 @@ mir_build_non_exhaustive_patterns_type_not_empty = non-exhaustive patterns: type .reference_note = references are always considered inhabited .suggestion = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown .help = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern + +mir_build_static_in_pattern = statics cannot be referenced in patterns + +mir_build_assoc_const_in_pattern = associated consts cannot be referenced in patterns + +mir_build_const_param_in_pattern = const parameters cannot be referenced in patterns + +mir_build_non_const_path = runtime values cannot be referenced in patterns diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 9e63141d7160c..ceaf057bb465b 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -429,3 +429,31 @@ impl<'a> SessionDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> diag } } + +#[derive(SessionDiagnostic)] +#[diag(mir_build::static_in_pattern, code = "E0158")] +pub struct StaticInPattern { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(mir_build::assoc_const_in_pattern, code = "E0158")] +pub struct AssocConstInPattern { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(mir_build::const_param_in_pattern, code = "E0158")] +pub struct ConstParamInPattern { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(mir_build::non_const_path, code = "E0080")] +pub struct NonConstPath { + #[primary_span] + pub span: Span, +} 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 d906666b96a35..f72dc764eeb33 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -4,7 +4,7 @@ use super::usefulness::{ }; use super::{PatCtxt, PatternError}; -use crate::errors::NonExhaustivePatternsTypeNotEmpty; +use crate::errors::*; use rustc_arena::TypedArena; use rustc_ast::Mutability; @@ -109,28 +109,20 @@ impl PatCtxt<'_, '_> { for error in &self.errors { match *error { PatternError::StaticInPattern(span) => { - self.span_e0158(span, "statics cannot be referenced in patterns") + self.tcx.sess.emit_err(StaticInPattern { span }); } PatternError::AssocConstInPattern(span) => { - self.span_e0158(span, "associated consts cannot be referenced in patterns") + self.tcx.sess.emit_err(AssocConstInPattern { span }); } PatternError::ConstParamInPattern(span) => { - self.span_e0158(span, "const parameters cannot be referenced in patterns") + self.tcx.sess.emit_err(ConstParamInPattern { span }); } PatternError::NonConstPath(span) => { - rustc_middle::mir::interpret::struct_error( - self.tcx.at(span), - "runtime values cannot be referenced in patterns", - ) - .emit(); + self.tcx.sess.emit_err(NonConstPath { span }); } } } } - - fn span_e0158(&self, span: Span, text: &str) { - struct_span_err!(self.tcx.sess, span, E0158, "{}", text).emit(); - } } impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { From d3bc82b489380ebd6205d533bb355ec4dc0b2a2e Mon Sep 17 00:00:00 2001 From: TheOddGarlic Date: Sat, 27 Aug 2022 22:06:06 +0300 Subject: [PATCH 48/81] Migrate unreachable pattern diagnostic --- .../locales/en-US/mir_build.ftl | 4 ++++ compiler/rustc_mir_build/src/errors.rs | 9 +++++++++ .../src/thir/pattern/check_match.rs | 14 ++++++-------- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl index 610e16ab7d8e7..8ff5c9b3fdebb 100644 --- a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl +++ b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl @@ -191,3 +191,7 @@ mir_build_assoc_const_in_pattern = associated consts cannot be referenced in pat mir_build_const_param_in_pattern = const parameters cannot be referenced in patterns mir_build_non_const_path = runtime values cannot be referenced in patterns + +mir_build_unreachable_pattern = unreachable pattern + .label = unreachable pattern + .catchall_label = matches any value diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index ceaf057bb465b..3049ebc5b037b 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -457,3 +457,12 @@ pub struct NonConstPath { #[primary_span] pub span: Span, } + +#[derive(LintDiagnostic)] +#[diag(mir_build::unreachable_pattern)] +pub struct UnreachablePattern { + #[label] + pub span: Option, + #[label(mir_build::catchall_label)] + pub catchall: Option, +} 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 f72dc764eeb33..ab7b82c29c296 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -605,14 +605,12 @@ fn pat_is_catchall(pat: &DeconstructedPat<'_, '_>) -> bool { } fn unreachable_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, catchall: Option) { - tcx.struct_span_lint_hir(UNREACHABLE_PATTERNS, id, span, "unreachable pattern", |lint| { - if let Some(catchall) = catchall { - // We had a catchall pattern, hint at that. - lint.span_label(span, "unreachable pattern"); - lint.span_label(catchall, "matches any value"); - } - lint - }); + tcx.emit_spanned_lint( + UNREACHABLE_PATTERNS, + id, + span, + UnreachablePattern { span: if catchall.is_some() { Some(span) } else { None }, catchall }, + ); } fn irrefutable_let_pattern(tcx: TyCtxt<'_>, id: HirId, span: Span) { From e26482bd27347cd3a4818757f312a633a6ca5683 Mon Sep 17 00:00:00 2001 From: TheOddGarlic Date: Sat, 27 Aug 2022 22:17:10 +0300 Subject: [PATCH 49/81] Migrate "constant pattern depends on generic parameter" diagnostic --- compiler/rustc_error_messages/locales/en-US/mir_build.ftl | 3 +++ compiler/rustc_mir_build/src/errors.rs | 7 +++++++ compiler/rustc_mir_build/src/thir/pattern/mod.rs | 7 ++++--- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl index 8ff5c9b3fdebb..4504d557da3f0 100644 --- a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl +++ b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl @@ -195,3 +195,6 @@ mir_build_non_const_path = runtime values cannot be referenced in patterns mir_build_unreachable_pattern = unreachable pattern .label = unreachable pattern .catchall_label = matches any value + +mir_build_const_pattern_depends_on_generic_parameter = + constant pattern depends on a generic parameter diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 3049ebc5b037b..e6ed824b8bb91 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -466,3 +466,10 @@ pub struct UnreachablePattern { #[label(mir_build::catchall_label)] pub catchall: Option, } + +#[derive(SessionDiagnostic)] +#[diag(mir_build::const_pattern_depends_on_generic_parameter)] +pub struct ConstPatternDependsOnGenericParameter { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 2683919bb1b51..52945066ae5df 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -8,6 +8,7 @@ mod usefulness; pub(crate) use self::check_match::check_match; pub(crate) use self::usefulness::MatchCheckCtxt; +use crate::errors::ConstPatternDependsOnGenericParameter; use crate::thir::util::UserAnnotatedTyHelpers; use rustc_errors::struct_span_err; @@ -549,7 +550,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { Err(ErrorHandled::TooGeneric) => { // While `Reported | Linted` cases will have diagnostics emitted already // it is not true for TooGeneric case, so we need to give user more information. - self.tcx.sess.span_err(span, "constant pattern depends on a generic parameter"); + self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span }); pat_from_kind(PatKind::Wild) } Err(_) => { @@ -584,9 +585,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { _ => bug!("Expected ConstKind::Param"), }, mir::ConstantKind::Val(_, _) => self.const_to_pat(value, id, span, false).kind, - mir::ConstantKind::Unevaluated(..) => { + mir::ConstKind::Unevaluated(_) => { // If we land here it means the const can't be evaluated because it's `TooGeneric`. - self.tcx.sess.span_err(span, "constant pattern depends on a generic parameter"); + self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span }); return PatKind::Wild; } } From 5b581f0d3068087de27546a1b35d9d44422a5ab7 Mon Sep 17 00:00:00 2001 From: TheOddGarlic Date: Sat, 27 Aug 2022 22:25:09 +0300 Subject: [PATCH 50/81] Migrate "could not evaluate const pattern" diagnostic --- compiler/rustc_error_messages/locales/en-US/mir_build.ftl | 2 ++ compiler/rustc_mir_build/src/errors.rs | 7 +++++++ compiler/rustc_mir_build/src/thir/pattern/mod.rs | 6 +++--- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl index 4504d557da3f0..87e7f348ee080 100644 --- a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl +++ b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl @@ -198,3 +198,5 @@ mir_build_unreachable_pattern = unreachable pattern mir_build_const_pattern_depends_on_generic_parameter = constant pattern depends on a generic parameter + +mir_build_could_not_eval_const_pattern = could not evaluate constant pattern diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index e6ed824b8bb91..0d7e62e616f3c 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -473,3 +473,10 @@ pub struct ConstPatternDependsOnGenericParameter { #[primary_span] pub span: Span, } + +#[derive(SessionDiagnostic)] +#[diag(mir_build::could_not_eval_const_pattern)] +pub struct CouldNotEvalConstPattern { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 52945066ae5df..c57df1aef1eaf 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -8,7 +8,7 @@ mod usefulness; pub(crate) use self::check_match::check_match; pub(crate) use self::usefulness::MatchCheckCtxt; -use crate::errors::ConstPatternDependsOnGenericParameter; +use crate::errors::*; use crate::thir::util::UserAnnotatedTyHelpers; use rustc_errors::struct_span_err; @@ -503,7 +503,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { } Err(_) => { - self.tcx.sess.span_err(span, "could not evaluate constant pattern"); + self.tcx.sess.emit_err(CouldNotEvalConstPattern { span }); return pat_from_kind(PatKind::Wild); } }; @@ -554,7 +554,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { pat_from_kind(PatKind::Wild) } Err(_) => { - self.tcx.sess.span_err(span, "could not evaluate constant pattern"); + self.tcx.sess.emit_err(CouldNotEvalConstPattern { span }); pat_from_kind(PatKind::Wild) } } From 058b55e0dd7f585fe7362514cbd0d393cf283e11 Mon Sep 17 00:00:00 2001 From: TheOddGarlic Date: Sat, 27 Aug 2022 22:48:18 +0300 Subject: [PATCH 51/81] Migrate lower range bound diagnostics --- .../locales/en-US/mir_build.ftl | 7 +++++ compiler/rustc_mir_build/src/errors.rs | 17 +++++++++++ .../rustc_mir_build/src/thir/pattern/mod.rs | 29 ++++--------------- 3 files changed, 29 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl index 87e7f348ee080..6bfab0774feae 100644 --- a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl +++ b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl @@ -200,3 +200,10 @@ mir_build_const_pattern_depends_on_generic_parameter = constant pattern depends on a generic parameter mir_build_could_not_eval_const_pattern = could not evaluate constant pattern + +mir_build_lower_range_bound_must_be_less_than_or_equal_to_upper = + lower range bound must be less than or equal to upper + .label = lower bound larger than upper bound + .teach_note = When matching against a range, the compiler verifies that the range is non-empty. Range patterns include both end-points, so this is equivalent to requiring the start of the range to be less than or equal to the end of the range. + +mir_build_lower_range_bound_must_be_less_than_upper = lower range bound must be less than upper diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 0d7e62e616f3c..96728970c5be0 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -480,3 +480,20 @@ pub struct CouldNotEvalConstPattern { #[primary_span] pub span: Span, } + +#[derive(SessionDiagnostic)] +#[diag(mir_build::lower_range_bound_must_be_less_than_or_equal_to_upper, code = "E0030")] +pub struct LowerRangeBoundMustBeLessThanOrEqualToUpper { + #[primary_span] + #[label] + pub span: Span, + #[note(mir_build::teach_note)] + pub teach: Option<()>, +} + +#[derive(SessionDiagnostic)] +#[diag(mir_build::lower_range_bound_must_be_less_than_upper, code = "E0579")] +pub struct LowerRangeBoundMustBeLessThanUpper { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index c57df1aef1eaf..90f224f5eff1f 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -11,7 +11,7 @@ pub(crate) use self::usefulness::MatchCheckCtxt; use crate::errors::*; use crate::thir::util::UserAnnotatedTyHelpers; -use rustc_errors::struct_span_err; +use rustc_errors::error_code; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::pat_util::EnumerateAndAdjustIterator; @@ -141,13 +141,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { } // `x..y` where `x >= y`. The range is empty => error. (RangeEnd::Excluded, _) => { - struct_span_err!( - self.tcx.sess, - span, - E0579, - "lower range bound must be less than upper" - ) - .emit(); + self.tcx.sess.emit_err(LowerRangeBoundMustBeLessThanUpper { span }); PatKind::Wild } // `x..=y` where `x == y`. @@ -158,23 +152,10 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { } // `x..=y` where `x > y` hence the range is empty => error. (RangeEnd::Included, _) => { - let mut err = struct_span_err!( - self.tcx.sess, + self.tcx.sess.emit_err(LowerRangeBoundMustBeLessThanOrEqualToUpper { span, - E0030, - "lower range bound must be less than or equal to upper" - ); - err.span_label(span, "lower bound larger than upper bound"); - if self.tcx.sess.teach(&err.get_code().unwrap()) { - err.note( - "When matching against a range, the compiler \ - verifies that the range is non-empty. Range \ - patterns include both end-points, so this is \ - equivalent to requiring the start of the range \ - to be less than or equal to the end of the range.", - ); - } - err.emit(); + teach: if self.tcx.sess.teach(&error_code!(E0030)) { Some(()) } else { None }, + }); PatKind::Wild } } From 9137e6d7b7bd5e38eb15ffaccb258fd8960bd88e Mon Sep 17 00:00:00 2001 From: TheOddGarlic Date: Sun, 28 Aug 2022 21:48:09 +0300 Subject: [PATCH 52/81] Migrate leading/trailing irrefutable let pattern diagnostics --- .../locales/en-US/mir_build.ftl | 26 ++++++++++++++ compiler/rustc_mir_build/src/errors.rs | 16 +++++++++ .../src/thir/pattern/check_match.rs | 35 ++++++------------- 3 files changed, 52 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl index 6bfab0774feae..280b82b4ea400 100644 --- a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl +++ b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl @@ -207,3 +207,29 @@ mir_build_lower_range_bound_must_be_less_than_or_equal_to_upper = .teach_note = When matching against a range, the compiler verifies that the range is non-empty. Range patterns include both end-points, so this is equivalent to requiring the start of the range to be less than or equal to the end of the range. mir_build_lower_range_bound_must_be_less_than_upper = lower range bound must be less than upper + +mir_build_leading_irrefutable_let_patterns = leading irrefutable {$count -> + [one] pattern + *[other] patterns + } in let chain + .note = {$count -> + [one] this pattern + *[other] these patterns + } will always match + .help = consider moving {$count -> + [one] it + *[other] them + } outside of the construct + +mir_build_trailing_irrefutable_let_patterns = trailing irrefutable {$count -> + [one] pattern + *[other] patterns + } in let chain + .note = {$count -> + [one] this pattern + *[other] these patterns + } will always match + .help = consider moving {$count -> + [one] it + *[other] them + } into the body diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 96728970c5be0..3331e785b95f2 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -497,3 +497,19 @@ pub struct LowerRangeBoundMustBeLessThanUpper { #[primary_span] pub span: Span, } + +#[derive(LintDiagnostic)] +#[diag(mir_build::leading_irrefutable_let_patterns)] +#[note] +#[help] +pub struct LeadingIrrefutableLetPatterns { + pub count: usize, +} + +#[derive(LintDiagnostic)] +#[diag(mir_build::trailing_irrefutable_let_patterns)] +#[note] +#[help] +pub struct TrailingIrrefutableLetPatterns { + pub count: usize, +} 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 ab7b82c29c296..9ccbe08a3aca9 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -339,29 +339,6 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { ); return true; } - let lint_affix = |affix: &[Option<(Span, bool)>], kind, suggestion| { - let span_start = affix[0].unwrap().0; - let span_end = affix.last().unwrap().unwrap().0; - let span = span_start.to(span_end); - let cnt = affix.len(); - let s = pluralize!(cnt); - cx.tcx.struct_span_lint_hir( - IRREFUTABLE_LET_PATTERNS, - top, - span, - format!("{kind} irrefutable pattern{s} in let chain"), - |lint| { - lint.note(format!( - "{these} pattern{s} will always match", - these = pluralize!("this", cnt), - )) - .help(format!( - "consider moving {} {suggestion}", - if cnt > 1 { "them" } else { "it" } - )) - }, - ); - }; if let Some(until) = chain_refutabilities.iter().position(|r| !matches!(*r, Some((_, false)))) && until > 0 { // The chain has a non-zero prefix of irrefutable `let` statements. @@ -375,13 +352,21 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { if !matches!(let_source, LetSource::WhileLet | LetSource::IfLetGuard) { // Emit the lint let prefix = &chain_refutabilities[..until]; - lint_affix(prefix, "leading", "outside of the construct"); + let span_start = prefix[0].unwrap().0; + let span_end = prefix.last().unwrap().unwrap().0; + let span = span_start.to(span_end); + let count = prefix.len(); + cx.tcx.emit_spanned_lint(IRREFUTABLE_LET_PATTERNS, top, span, LeadingIrrefutableLetPatterns { count }); } } if let Some(from) = chain_refutabilities.iter().rposition(|r| !matches!(*r, Some((_, false)))) && from != (chain_refutabilities.len() - 1) { // The chain has a non-empty suffix of irrefutable `let` statements let suffix = &chain_refutabilities[from + 1..]; - lint_affix(suffix, "trailing", "into the body"); + let span_start = suffix[0].unwrap().0; + let span_end = suffix.last().unwrap().unwrap().0; + let span = span_start.to(span_end); + let count = suffix.len(); + cx.tcx.emit_spanned_lint(IRREFUTABLE_LET_PATTERNS, top, span, TrailingIrrefutableLetPatterns { count }); } true } From 4ab083139164d5301d5f9d5772d16a56324297ae Mon Sep 17 00:00:00 2001 From: TheOddGarlic Date: Mon, 29 Aug 2022 10:06:50 +0300 Subject: [PATCH 53/81] Migrate pattern bindings with variant name lint --- .../locales/en-US/mir_build.ftl | 4 +++ compiler/rustc_mir_build/src/errors.rs | 11 ++++++- .../src/thir/pattern/check_match.rs | 32 ++++++------------- 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl index 280b82b4ea400..539794086ee26 100644 --- a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl +++ b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl @@ -233,3 +233,7 @@ mir_build_trailing_irrefutable_let_patterns = trailing irrefutable {$count -> [one] it *[other] them } into the body + +mir_build_bindings_with_variant_name = + pattern binding `{$ident}` is named the same as one of the variants of the type `{$ty_path}` + .suggestion = to match on the variant, qualify the path diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 3331e785b95f2..085511a9d7c0a 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -3,7 +3,7 @@ use rustc_errors::{error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed use rustc_macros::{LintDiagnostic, SessionDiagnostic, SessionSubdiagnostic}; use rustc_middle::ty::{self, Ty}; use rustc_session::{parse::ParseSess, SessionDiagnostic}; -use rustc_span::Span; +use rustc_span::{symbol::Ident, Span}; #[derive(LintDiagnostic)] #[diag(mir_build::unconditional_recursion)] @@ -513,3 +513,12 @@ pub struct LeadingIrrefutableLetPatterns { pub struct TrailingIrrefutableLetPatterns { pub count: usize, } + +#[derive(LintDiagnostic)] +#[diag(mir_build::bindings_with_variant_name, code = "E0170")] +pub struct BindingsWithVariantName { + #[suggestion(code = "{ty_path}::{ident}", applicability = "machine-applicable")] + pub suggestion: Option, + pub ty_path: String, + pub ident: Ident, +} 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 9ccbe08a3aca9..66f2c6f0f99bb 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -9,8 +9,8 @@ use crate::errors::*; use rustc_arena::TypedArena; use rustc_ast::Mutability; use rustc_errors::{ - error_code, pluralize, struct_span_err, Applicability, DelayDm, Diagnostic, DiagnosticBuilder, - ErrorGuaranteed, MultiSpan, + pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, + MultiSpan, }; use rustc_hir as hir; use rustc_hir::def::*; @@ -547,32 +547,20 @@ fn check_for_bindings_named_same_as_variants( }) { let variant_count = edef.variants().len(); - cx.tcx.struct_span_lint_hir( + let ty_path = cx.tcx.def_path_str(edef.did()); + cx.tcx.emit_spanned_lint( BINDINGS_WITH_VARIANT_NAME, p.hir_id, p.span, - DelayDm(|| format!( - "pattern binding `{}` is named the same as one \ - of the variants of the type `{}`", - ident, cx.tcx.def_path_str(edef.did()) - )), - |lint| { - let ty_path = cx.tcx.def_path_str(edef.did()); - lint.code(error_code!(E0170)); - + BindingsWithVariantName { // If this is an irrefutable pattern, and there's > 1 variant, // then we can't actually match on this. Applying the below // suggestion would produce code that breaks on `check_irrefutable`. - if rf == Refutable || variant_count == 1 { - lint.span_suggestion( - p.span, - "to match on the variant, qualify the path", - format!("{}::{}", ty_path, ident), - Applicability::MachineApplicable, - ); - } - - lint + suggestion: if rf == Refutable || variant_count == 1 { + Some(p.span) + } else { None }, + ty_path, + ident, }, ) } From afc922862da045b2a861b8b6f0549d35c67803df Mon Sep 17 00:00:00 2001 From: TheOddGarlic Date: Mon, 29 Aug 2022 11:21:25 +0300 Subject: [PATCH 54/81] Migrate irrefutable let pattern diagnostics --- .../locales/en-US/mir_build.ftl | 50 +++++++++++++ compiler/rustc_mir_build/src/errors.rs | 40 +++++++++++ .../src/thir/pattern/check_match.rs | 70 ++++--------------- 3 files changed, 103 insertions(+), 57 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl index 539794086ee26..7555bd608498d 100644 --- a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl +++ b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl @@ -237,3 +237,53 @@ mir_build_trailing_irrefutable_let_patterns = trailing irrefutable {$count -> mir_build_bindings_with_variant_name = pattern binding `{$ident}` is named the same as one of the variants of the type `{$ty_path}` .suggestion = to match on the variant, qualify the path + +mir_build_irrefutable_let_patterns_generic_let = irrefutable `let` {$count -> + [one] pattern + *[other] patterns + } + .note = {$count -> + [one] this pattern + *[other] these patterns + } will always match, so the `let` is useless + .help = consider removing `let` + +mir_build_irrefutable_let_patterns_if_let = irrefutable `if let` {$count -> + [one] pattern + *[other] patterns + } + .note = {$count -> + [one] this pattern + *[other] these patterns + } will always match, so the `if let` is useless + .help = consider replacing the `if let` with a `let` + +mir_build_irrefutable_let_patterns_if_let_guard = irrefutable `if let` guard {$count -> + [one] pattern + *[other] patterns + } + .note = {$count -> + [one] this pattern + *[other] these patterns + } will always match, so the guard is useless + .help = consider removing the guard and adding a `let` inside the match arm + +mir_build_irrefutable_let_patterns_let_else = irrefutable `let...else` {$count -> + [one] pattern + *[other] patterns + } + .note = {$count -> + [one] this pattern + *[other] these patterns + } will always match, so the `else` clause is useless + .help = consider removing the `else` clause + +mir_build_irrefutable_let_patterns_while_let = irrefutable `while let` {$count -> + [one] pattern + *[other] patterns + } + .note = {$count -> + [one] this pattern + *[other] these patterns + } will always match, so the loop will never exit + .help = consider instead using a `loop {"{"} ... {"}"}` with a `let` inside it diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 085511a9d7c0a..eecef26b94cb6 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -522,3 +522,43 @@ pub struct BindingsWithVariantName { pub ty_path: String, pub ident: Ident, } + +#[derive(LintDiagnostic)] +#[diag(mir_build::irrefutable_let_patterns_generic_let)] +#[note] +#[help] +pub struct IrrefutableLetPatternsGenericLet { + pub count: usize, +} + +#[derive(LintDiagnostic)] +#[diag(mir_build::irrefutable_let_patterns_if_let)] +#[note] +#[help] +pub struct IrrefutableLetPatternsIfLet { + pub count: usize, +} + +#[derive(LintDiagnostic)] +#[diag(mir_build::irrefutable_let_patterns_if_let_guard)] +#[note] +#[help] +pub struct IrrefutableLetPatternsIfLetGuard { + pub count: usize, +} + +#[derive(LintDiagnostic)] +#[diag(mir_build::irrefutable_let_patterns_let_else)] +#[note] +#[help] +pub struct IrrefutableLetPatternsLetElse { + pub count: usize, +} + +#[derive(LintDiagnostic)] +#[diag(mir_build::irrefutable_let_patterns_while_let)] +#[note] +#[help] +pub struct IrrefutableLetPatternsWhileLet { + pub count: usize, +} 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 66f2c6f0f99bb..8c5a586e8e5f9 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -598,68 +598,24 @@ fn irrefutable_let_patterns( count: usize, span: Span, ) { + let span = match source { + LetSource::LetElse(span) => span, + _ => span, + }; + macro_rules! emit_diag { - ( - $lint:expr, - $source_name:expr, - $note_sufix:expr, - $help_sufix:expr - ) => {{ - let s = pluralize!(count); - let these = pluralize!("this", count); - tcx.struct_span_lint_hir( - IRREFUTABLE_LET_PATTERNS, - id, - span, - format!("irrefutable {} pattern{s}", $source_name), - |lint| { - lint.note(&format!( - "{these} pattern{s} will always match, so the {}", - $note_sufix - )) - .help(concat!("consider ", $help_sufix)) - }, - ) + ($lint:tt) => {{ + tcx.emit_spanned_lint(IRREFUTABLE_LET_PATTERNS, id, span, $lint { count }); }}; } match source { - LetSource::GenericLet => { - emit_diag!(lint, "`let`", "`let` is useless", "removing `let`"); - } - LetSource::IfLet => { - emit_diag!( - lint, - "`if let`", - "`if let` is useless", - "replacing the `if let` with a `let`" - ); - } - LetSource::IfLetGuard => { - emit_diag!( - lint, - "`if let` guard", - "guard is useless", - "removing the guard and adding a `let` inside the match arm" - ); - } - LetSource::LetElse => { - emit_diag!( - lint, - "`let...else`", - "`else` clause is useless", - "removing the `else` clause" - ); - } - LetSource::WhileLet => { - emit_diag!( - lint, - "`while let`", - "loop will never exit", - "instead using a `loop { ... }` with a `let` inside it" - ); - } - }; + LetSource::GenericLet => emit_diag!(IrrefutableLetPatternsGenericLet), + LetSource::IfLet => emit_diag!(IrrefutableLetPatternsIfLet), + LetSource::IfLetGuard => emit_diag!(IrrefutableLetPatternsIfLetGuard), + LetSource::LetElse(..) => emit_diag!(IrrefutableLetPatternsLetElse), + LetSource::WhileLet => emit_diag!(IrrefutableLetPatternsWhileLet), + } } fn is_let_irrefutable<'p, 'tcx>( From 551daa682631424a5a902f43d1fd8a7f83dd0430 Mon Sep 17 00:00:00 2001 From: TheOddGarlic Date: Tue, 30 Aug 2022 20:01:28 +0300 Subject: [PATCH 55/81] Migrate borrow of moved value diagnostic --- .../locales/en-US/mir_build.ftl | 5 +++++ compiler/rustc_mir_build/src/errors.rs | 14 ++++++++++++++ .../src/thir/pattern/check_match.rs | 15 ++++++--------- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl index 7555bd608498d..bdef14755c872 100644 --- a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl +++ b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl @@ -287,3 +287,8 @@ mir_build_irrefutable_let_patterns_while_let = irrefutable `while let` {$count - *[other] these patterns } will always match, so the loop will never exit .help = consider instead using a `loop {"{"} ... {"}"}` with a `let` inside it + +mir_build_borrow_of_moved_value = borrow of moved value + .label = value moved into `{$name}` here + .occurs_because_label = move occurs because `{$name}` has type `{$ty}` which does not implement the `Copy` trait + .value_borrowed_label = value borrowed here after move diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index eecef26b94cb6..e78035a64c3b3 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -562,3 +562,17 @@ pub struct IrrefutableLetPatternsLetElse { pub struct IrrefutableLetPatternsWhileLet { pub count: usize, } + +#[derive(SessionDiagnostic)] +#[diag(mir_build::borrow_of_moved_value)] +pub struct BorrowOfMovedValue<'tcx> { + #[primary_span] + pub span: Span, + #[label] + #[label(mir_build::occurs_because_label)] + pub binding_span: Span, + #[label(mir_build::value_borrowed_label)] + pub conflicts_ref: Vec, + pub name: Ident, + pub ty: Ty<'tcx>, +} 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 8c5a586e8e5f9..7be39b9a52aba 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -962,16 +962,13 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa } }); if !conflicts_ref.is_empty() { - let occurs_because = format!( - "move occurs because `{}` has type `{}` which does not implement the `Copy` trait", + sess.emit_err(BorrowOfMovedValue { + span: pat.span, + binding_span, + conflicts_ref, name, - typeck_results.node_type(pat.hir_id), - ); - sess.struct_span_err(pat.span, "borrow of moved value") - .span_label(binding_span, format!("value moved into `{}` here", name)) - .span_label(binding_span, occurs_because) - .span_labels(conflicts_ref, "value borrowed here after move") - .emit(); + ty: typeck_results.node_type(pat.hir_id), + }); } return; } From 018be9e3f37cebeddcfddd97ec38f575bf2846cc Mon Sep 17 00:00:00 2001 From: TheOddGarlic Date: Tue, 30 Aug 2022 20:38:10 +0300 Subject: [PATCH 56/81] Migrate multiple mut borrows diagnostic --- .../locales/en-US/mir_build.ftl | 6 ++++ compiler/rustc_mir_build/src/errors.rs | 34 +++++++++++++++++++ .../src/thir/pattern/check_match.rs | 14 ++++---- 3 files changed, 47 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl index bdef14755c872..c6b26dd09247d 100644 --- a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl +++ b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl @@ -292,3 +292,9 @@ mir_build_borrow_of_moved_value = borrow of moved value .label = value moved into `{$name}` here .occurs_because_label = move occurs because `{$name}` has type `{$ty}` which does not implement the `Copy` trait .value_borrowed_label = value borrowed here after move + +mir_build_multiple_mut_borrows = cannot borrow value as mutable more than once at a time + .label = first mutable borrow, by `{$name}`, occurs here + .mutable_borrow = another mutable borrow, by `{$name_mut}`, occurs here + .immutable_borrow = also borrowed as immutable, by `{$name_immut}`, here + .moved = also moved into `{$name_moved}` here diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index e78035a64c3b3..ebe3e4042e9dd 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -576,3 +576,37 @@ pub struct BorrowOfMovedValue<'tcx> { pub name: Ident, pub ty: Ty<'tcx>, } + +#[derive(SessionDiagnostic)] +#[diag(mir_build::multiple_mut_borrows)] +pub struct MultipleMutBorrows { + #[primary_span] + pub span: Span, + #[label] + pub binding_span: Span, + #[subdiagnostic] + pub occurences: Vec, + pub name: Ident, +} + +#[derive(SessionSubdiagnostic)] +pub enum MultipleMutBorrowOccurence { + #[label(mir_build::mutable_borrow)] + Mutable { + #[primary_span] + span: Span, + name_mut: Ident, + }, + #[label(mir_build::immutable_borrow)] + Immutable { + #[primary_span] + span: Span, + name_immut: Ident, + }, + #[label(mir_build::moved)] + Moved { + #[primary_span] + span: Span, + name_moved: Ident, + }, +} 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 7be39b9a52aba..8b586574656b5 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -998,19 +998,19 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa // Report errors if any. if !conflicts_mut_mut.is_empty() { // Report mutability conflicts for e.g. `ref mut x @ Some(ref mut y)`. - let mut err = sess - .struct_span_err(pat.span, "cannot borrow value as mutable more than once at a time"); - err.span_label(binding_span, format!("first mutable borrow, by `{}`, occurs here", name)); + let mut occurences = vec![]; + for (span, name) in conflicts_mut_mut { - err.span_label(span, format!("another mutable borrow, by `{}`, occurs here", name)); + occurences.push(MultipleMutBorrowOccurence::Mutable { span, name_mut: name }); } for (span, name) in conflicts_mut_ref { - err.span_label(span, format!("also borrowed as immutable, by `{}`, here", name)); + occurences.push(MultipleMutBorrowOccurence::Immutable { span, name_immut: name }); } for (span, name) in conflicts_move { - err.span_label(span, format!("also moved into `{}` here", name)); + occurences.push(MultipleMutBorrowOccurence::Moved { span, name_moved: name }); } - err.emit(); + + sess.emit_err(MultipleMutBorrows { span: pat.span, binding_span, occurences, name }); } else if !conflicts_mut_ref.is_empty() { // Report mutability conflicts for e.g. `ref x @ Some(ref mut y)` or the converse. let (primary, also) = match mut_outer { From e9425a55e0c41bd023a452c938d834eeed176fd7 Mon Sep 17 00:00:00 2001 From: mejrs <> Date: Mon, 14 Nov 2022 19:00:14 +0100 Subject: [PATCH 57/81] Fix compile errors --- compiler/rustc_mir_build/src/errors.rs | 224 +++++++++--------- .../src/thir/pattern/check_match.rs | 20 +- .../borrowck-pat-ref-mut-twice.stderr | 8 +- .../hir-ty/src/diagnostics/match_check.rs | 4 +- 4 files changed, 126 insertions(+), 130 deletions(-) diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index ebe3e4042e9dd..f26f6bb25ff59 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -1,22 +1,24 @@ use crate::thir::pattern::MatchCheckCtxt; -use rustc_errors::{error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, MultiSpan}; -use rustc_macros::{LintDiagnostic, SessionDiagnostic, SessionSubdiagnostic}; +use rustc_errors::Handler; +use rustc_errors::{ + error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, MultiSpan, +}; +use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::{self, Ty}; -use rustc_session::{parse::ParseSess, SessionDiagnostic}; use rustc_span::{symbol::Ident, Span}; #[derive(LintDiagnostic)] -#[diag(mir_build::unconditional_recursion)] +#[diag(mir_build_unconditional_recursion)] #[help] pub struct UnconditionalRecursion { #[label] pub span: Span, - #[label(mir_build::unconditional_recursion_call_site_label)] + #[label(mir_build_unconditional_recursion_call_site_label)] pub call_sites: Vec, } #[derive(LintDiagnostic)] -#[diag(mir_build::unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe)] +#[diag(mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe)] #[note] pub struct UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafe<'a> { #[label] @@ -25,7 +27,7 @@ pub struct UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafe<'a> { } #[derive(LintDiagnostic)] -#[diag(mir_build::unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe_nameless)] +#[diag(mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe_nameless)] #[note] pub struct UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafeNameless { #[label] @@ -33,7 +35,7 @@ pub struct UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafeNameless { } #[derive(LintDiagnostic)] -#[diag(mir_build::unsafe_op_in_unsafe_fn_inline_assembly_requires_unsafe)] +#[diag(mir_build_unsafe_op_in_unsafe_fn_inline_assembly_requires_unsafe)] #[note] pub struct UnsafeOpInUnsafeFnUseOfInlineAssemblyRequiresUnsafe { #[label] @@ -41,7 +43,7 @@ pub struct UnsafeOpInUnsafeFnUseOfInlineAssemblyRequiresUnsafe { } #[derive(LintDiagnostic)] -#[diag(mir_build::unsafe_op_in_unsafe_fn_initializing_type_with_requires_unsafe)] +#[diag(mir_build_unsafe_op_in_unsafe_fn_initializing_type_with_requires_unsafe)] #[note] pub struct UnsafeOpInUnsafeFnInitializingTypeWithRequiresUnsafe { #[label] @@ -49,7 +51,7 @@ pub struct UnsafeOpInUnsafeFnInitializingTypeWithRequiresUnsafe { } #[derive(LintDiagnostic)] -#[diag(mir_build::unsafe_op_in_unsafe_fn_mutable_static_requires_unsafe)] +#[diag(mir_build_unsafe_op_in_unsafe_fn_mutable_static_requires_unsafe)] #[note] pub struct UnsafeOpInUnsafeFnUseOfMutableStaticRequiresUnsafe { #[label] @@ -57,7 +59,7 @@ pub struct UnsafeOpInUnsafeFnUseOfMutableStaticRequiresUnsafe { } #[derive(LintDiagnostic)] -#[diag(mir_build::unsafe_op_in_unsafe_fn_extern_static_requires_unsafe)] +#[diag(mir_build_unsafe_op_in_unsafe_fn_extern_static_requires_unsafe)] #[note] pub struct UnsafeOpInUnsafeFnUseOfExternStaticRequiresUnsafe { #[label] @@ -65,7 +67,7 @@ pub struct UnsafeOpInUnsafeFnUseOfExternStaticRequiresUnsafe { } #[derive(LintDiagnostic)] -#[diag(mir_build::unsafe_op_in_unsafe_fn_deref_raw_pointer_requires_unsafe)] +#[diag(mir_build_unsafe_op_in_unsafe_fn_deref_raw_pointer_requires_unsafe)] #[note] pub struct UnsafeOpInUnsafeFnDerefOfRawPointerRequiresUnsafe { #[label] @@ -73,7 +75,7 @@ pub struct UnsafeOpInUnsafeFnDerefOfRawPointerRequiresUnsafe { } #[derive(LintDiagnostic)] -#[diag(mir_build::unsafe_op_in_unsafe_fn_union_field_requires_unsafe)] +#[diag(mir_build_unsafe_op_in_unsafe_fn_union_field_requires_unsafe)] #[note] pub struct UnsafeOpInUnsafeFnAccessToUnionFieldRequiresUnsafe { #[label] @@ -81,7 +83,7 @@ pub struct UnsafeOpInUnsafeFnAccessToUnionFieldRequiresUnsafe { } #[derive(LintDiagnostic)] -#[diag(mir_build::unsafe_op_in_unsafe_fn_mutation_of_layout_constrained_field_requires_unsafe)] +#[diag(mir_build_unsafe_op_in_unsafe_fn_mutation_of_layout_constrained_field_requires_unsafe)] #[note] pub struct UnsafeOpInUnsafeFnMutationOfLayoutConstrainedFieldRequiresUnsafe { #[label] @@ -89,14 +91,14 @@ pub struct UnsafeOpInUnsafeFnMutationOfLayoutConstrainedFieldRequiresUnsafe { } #[derive(LintDiagnostic)] -#[diag(mir_build::unsafe_op_in_unsafe_fn_borrow_of_layout_constrained_field_requires_unsafe)] +#[diag(mir_build_unsafe_op_in_unsafe_fn_borrow_of_layout_constrained_field_requires_unsafe)] pub struct UnsafeOpInUnsafeFnBorrowOfLayoutConstrainedFieldRequiresUnsafe { #[label] pub span: Span, } #[derive(LintDiagnostic)] -#[diag(mir_build::unsafe_op_in_unsafe_fn_call_to_fn_with_requires_unsafe)] +#[diag(mir_build_unsafe_op_in_unsafe_fn_call_to_fn_with_requires_unsafe)] #[note] pub struct UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe<'a> { #[label] @@ -104,8 +106,8 @@ pub struct UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe<'a> { pub function: &'a str, } -#[derive(SessionDiagnostic)] -#[diag(mir_build::call_to_unsafe_fn_requires_unsafe, code = "E0133")] +#[derive(Diagnostic)] +#[diag(mir_build_call_to_unsafe_fn_requires_unsafe, code = "E0133")] #[note] pub struct CallToUnsafeFunctionRequiresUnsafe<'a> { #[primary_span] @@ -114,8 +116,8 @@ pub struct CallToUnsafeFunctionRequiresUnsafe<'a> { pub function: &'a str, } -#[derive(SessionDiagnostic)] -#[diag(mir_build::call_to_unsafe_fn_requires_unsafe_nameless, code = "E0133")] +#[derive(Diagnostic)] +#[diag(mir_build_call_to_unsafe_fn_requires_unsafe_nameless, code = "E0133")] #[note] pub struct CallToUnsafeFunctionRequiresUnsafeNameless { #[primary_span] @@ -123,8 +125,8 @@ pub struct CallToUnsafeFunctionRequiresUnsafeNameless { pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(mir_build::call_to_unsafe_fn_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")] +#[derive(Diagnostic)] +#[diag(mir_build_call_to_unsafe_fn_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")] #[note] pub struct CallToUnsafeFunctionRequiresUnsafeUnsafeOpInUnsafeFnAllowed<'a> { #[primary_span] @@ -133,9 +135,9 @@ pub struct CallToUnsafeFunctionRequiresUnsafeUnsafeOpInUnsafeFnAllowed<'a> { pub function: &'a str, } -#[derive(SessionDiagnostic)] +#[derive(Diagnostic)] #[diag( - mir_build::call_to_unsafe_fn_requires_unsafe_nameless_unsafe_op_in_unsafe_fn_allowed, + mir_build_call_to_unsafe_fn_requires_unsafe_nameless_unsafe_op_in_unsafe_fn_allowed, code = "E0133" )] #[note] @@ -145,8 +147,8 @@ pub struct CallToUnsafeFunctionRequiresUnsafeNamelessUnsafeOpInUnsafeFnAllowed { pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(mir_build::inline_assembly_requires_unsafe, code = "E0133")] +#[derive(Diagnostic)] +#[diag(mir_build_inline_assembly_requires_unsafe, code = "E0133")] #[note] pub struct UseOfInlineAssemblyRequiresUnsafe { #[primary_span] @@ -154,8 +156,8 @@ pub struct UseOfInlineAssemblyRequiresUnsafe { pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(mir_build::inline_assembly_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")] +#[derive(Diagnostic)] +#[diag(mir_build_inline_assembly_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")] #[note] pub struct UseOfInlineAssemblyRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[primary_span] @@ -163,8 +165,8 @@ pub struct UseOfInlineAssemblyRequiresUnsafeUnsafeOpInUnsafeFnAllowed { pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(mir_build::initializing_type_with_requires_unsafe, code = "E0133")] +#[derive(Diagnostic)] +#[diag(mir_build_initializing_type_with_requires_unsafe, code = "E0133")] #[note] pub struct InitializingTypeWithRequiresUnsafe { #[primary_span] @@ -172,9 +174,9 @@ pub struct InitializingTypeWithRequiresUnsafe { pub span: Span, } -#[derive(SessionDiagnostic)] +#[derive(Diagnostic)] #[diag( - mir_build::initializing_type_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, + mir_build_initializing_type_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133" )] #[note] @@ -184,8 +186,8 @@ pub struct InitializingTypeWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed { pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(mir_build::mutable_static_requires_unsafe, code = "E0133")] +#[derive(Diagnostic)] +#[diag(mir_build_mutable_static_requires_unsafe, code = "E0133")] #[note] pub struct UseOfMutableStaticRequiresUnsafe { #[primary_span] @@ -193,8 +195,8 @@ pub struct UseOfMutableStaticRequiresUnsafe { pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(mir_build::mutable_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")] +#[derive(Diagnostic)] +#[diag(mir_build_mutable_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")] #[note] pub struct UseOfMutableStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[primary_span] @@ -202,8 +204,8 @@ pub struct UseOfMutableStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed { pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(mir_build::extern_static_requires_unsafe, code = "E0133")] +#[derive(Diagnostic)] +#[diag(mir_build_extern_static_requires_unsafe, code = "E0133")] #[note] pub struct UseOfExternStaticRequiresUnsafe { #[primary_span] @@ -211,8 +213,8 @@ pub struct UseOfExternStaticRequiresUnsafe { pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(mir_build::extern_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")] +#[derive(Diagnostic)] +#[diag(mir_build_extern_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")] #[note] pub struct UseOfExternStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[primary_span] @@ -220,8 +222,8 @@ pub struct UseOfExternStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed { pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(mir_build::deref_raw_pointer_requires_unsafe, code = "E0133")] +#[derive(Diagnostic)] +#[diag(mir_build_deref_raw_pointer_requires_unsafe, code = "E0133")] #[note] pub struct DerefOfRawPointerRequiresUnsafe { #[primary_span] @@ -229,8 +231,8 @@ pub struct DerefOfRawPointerRequiresUnsafe { pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(mir_build::deref_raw_pointer_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")] +#[derive(Diagnostic)] +#[diag(mir_build_deref_raw_pointer_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")] #[note] pub struct DerefOfRawPointerRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[primary_span] @@ -238,8 +240,8 @@ pub struct DerefOfRawPointerRequiresUnsafeUnsafeOpInUnsafeFnAllowed { pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(mir_build::union_field_requires_unsafe, code = "E0133")] +#[derive(Diagnostic)] +#[diag(mir_build_union_field_requires_unsafe, code = "E0133")] #[note] pub struct AccessToUnionFieldRequiresUnsafe { #[primary_span] @@ -247,8 +249,8 @@ pub struct AccessToUnionFieldRequiresUnsafe { pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(mir_build::union_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")] +#[derive(Diagnostic)] +#[diag(mir_build_union_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")] #[note] pub struct AccessToUnionFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[primary_span] @@ -256,8 +258,8 @@ pub struct AccessToUnionFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed { pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(mir_build::mutation_of_layout_constrained_field_requires_unsafe, code = "E0133")] +#[derive(Diagnostic)] +#[diag(mir_build_mutation_of_layout_constrained_field_requires_unsafe, code = "E0133")] #[note] pub struct MutationOfLayoutConstrainedFieldRequiresUnsafe { #[primary_span] @@ -265,9 +267,9 @@ pub struct MutationOfLayoutConstrainedFieldRequiresUnsafe { pub span: Span, } -#[derive(SessionDiagnostic)] +#[derive(Diagnostic)] #[diag( - mir_build::mutation_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, + mir_build_mutation_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133" )] #[note] @@ -277,8 +279,8 @@ pub struct MutationOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllow pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(mir_build::borrow_of_layout_constrained_field_requires_unsafe, code = "E0133")] +#[derive(Diagnostic)] +#[diag(mir_build_borrow_of_layout_constrained_field_requires_unsafe, code = "E0133")] #[note] pub struct BorrowOfLayoutConstrainedFieldRequiresUnsafe { #[primary_span] @@ -286,9 +288,9 @@ pub struct BorrowOfLayoutConstrainedFieldRequiresUnsafe { pub span: Span, } -#[derive(SessionDiagnostic)] +#[derive(Diagnostic)] #[diag( - mir_build::borrow_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, + mir_build_borrow_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133" )] #[note] @@ -298,8 +300,8 @@ pub struct BorrowOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(mir_build::call_to_fn_with_requires_unsafe, code = "E0133")] +#[derive(Diagnostic)] +#[diag(mir_build_call_to_fn_with_requires_unsafe, code = "E0133")] #[note] pub struct CallToFunctionWithRequiresUnsafe<'a> { #[primary_span] @@ -308,8 +310,8 @@ pub struct CallToFunctionWithRequiresUnsafe<'a> { pub function: &'a str, } -#[derive(SessionDiagnostic)] -#[diag(mir_build::call_to_fn_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")] +#[derive(Diagnostic)] +#[diag(mir_build_call_to_fn_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")] #[note] pub struct CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed<'a> { #[primary_span] @@ -319,7 +321,7 @@ pub struct CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed<'a> { } #[derive(LintDiagnostic)] -#[diag(mir_build::unused_unsafe)] +#[diag(mir_build_unused_unsafe)] pub struct UnusedUnsafe { #[label] pub span: Span, @@ -327,14 +329,14 @@ pub struct UnusedUnsafe { pub enclosing: Option, } -#[derive(SessionSubdiagnostic)] +#[derive(Subdiagnostic)] pub enum UnusedUnsafeEnclosing { - #[label(mir_build::unused_unsafe_enclosing_block_label)] + #[label(mir_build_unused_unsafe_enclosing_block_label)] Block { #[primary_span] span: Span, }, - #[label(mir_build::unused_unsafe_enclosing_fn_label)] + #[label(mir_build_unused_unsafe_enclosing_fn_label)] Function { #[primary_span] span: Span, @@ -348,11 +350,11 @@ pub(crate) struct NonExhaustivePatternsTypeNotEmpty<'p, 'tcx, 'm> { pub ty: Ty<'tcx>, } -impl<'a> SessionDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> { - fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'_, ErrorGuaranteed> { - let mut diag = sess.span_diagnostic.struct_span_err_with_code( +impl<'a> IntoDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> { + fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> { + let mut diag = handler.struct_span_err_with_code( self.span, - rustc_errors::fluent::mir_build::non_exhaustive_patterns_type_not_empty, + rustc_errors::fluent::mir_build_non_exhaustive_patterns_type_not_empty, error_code!(E0004), ); @@ -374,7 +376,7 @@ impl<'a> SessionDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> let mut span: MultiSpan = def_span.into(); span.push_span_label(def_span, ""); - diag.span_note(span, rustc_errors::fluent::mir_build::def_note); + diag.span_note(span, rustc_errors::fluent::def_note); } let is_variant_list_non_exhaustive = match self.ty.kind() { @@ -385,14 +387,14 @@ impl<'a> SessionDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> }; if is_variant_list_non_exhaustive { - diag.note(rustc_errors::fluent::mir_build::non_exhaustive_type_note); + diag.note(rustc_errors::fluent::non_exhaustive_type_note); } else { - diag.note(rustc_errors::fluent::mir_build::type_note); + diag.note(rustc_errors::fluent::type_note); } if let ty::Ref(_, sub_ty, _) = self.ty.kind() { if self.cx.tcx.is_ty_uninhabited_from(self.cx.module, *sub_ty, self.cx.param_env) { - diag.note(rustc_errors::fluent::mir_build::reference_note); + diag.note(rustc_errors::fluent::reference_note); } } @@ -418,88 +420,88 @@ impl<'a> SessionDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> if let Some((span, sugg)) = suggestion { diag.span_suggestion_verbose( span, - rustc_errors::fluent::mir_build::suggestion, + rustc_errors::fluent::suggestion, sugg, Applicability::HasPlaceholders, ); } else { - diag.help(rustc_errors::fluent::mir_build::help); + diag.help(rustc_errors::fluent::help); } diag } } -#[derive(SessionDiagnostic)] -#[diag(mir_build::static_in_pattern, code = "E0158")] +#[derive(Diagnostic)] +#[diag(mir_build_static_in_pattern, code = "E0158")] pub struct StaticInPattern { #[primary_span] pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(mir_build::assoc_const_in_pattern, code = "E0158")] +#[derive(Diagnostic)] +#[diag(mir_build_assoc_const_in_pattern, code = "E0158")] pub struct AssocConstInPattern { #[primary_span] pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(mir_build::const_param_in_pattern, code = "E0158")] +#[derive(Diagnostic)] +#[diag(mir_build_const_param_in_pattern, code = "E0158")] pub struct ConstParamInPattern { #[primary_span] pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(mir_build::non_const_path, code = "E0080")] +#[derive(Diagnostic)] +#[diag(mir_build_non_const_path, code = "E0080")] pub struct NonConstPath { #[primary_span] pub span: Span, } #[derive(LintDiagnostic)] -#[diag(mir_build::unreachable_pattern)] +#[diag(mir_build_unreachable_pattern)] pub struct UnreachablePattern { #[label] pub span: Option, - #[label(mir_build::catchall_label)] + #[label(catchall_label)] pub catchall: Option, } -#[derive(SessionDiagnostic)] -#[diag(mir_build::const_pattern_depends_on_generic_parameter)] +#[derive(Diagnostic)] +#[diag(mir_build_const_pattern_depends_on_generic_parameter)] pub struct ConstPatternDependsOnGenericParameter { #[primary_span] pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(mir_build::could_not_eval_const_pattern)] +#[derive(Diagnostic)] +#[diag(mir_build_could_not_eval_const_pattern)] pub struct CouldNotEvalConstPattern { #[primary_span] pub span: Span, } -#[derive(SessionDiagnostic)] -#[diag(mir_build::lower_range_bound_must_be_less_than_or_equal_to_upper, code = "E0030")] +#[derive(Diagnostic)] +#[diag(mir_build_lower_range_bound_must_be_less_than_or_equal_to_upper, code = "E0030")] pub struct LowerRangeBoundMustBeLessThanOrEqualToUpper { #[primary_span] #[label] pub span: Span, - #[note(mir_build::teach_note)] + #[note(teach_note)] pub teach: Option<()>, } -#[derive(SessionDiagnostic)] -#[diag(mir_build::lower_range_bound_must_be_less_than_upper, code = "E0579")] +#[derive(Diagnostic)] +#[diag(mir_build_lower_range_bound_must_be_less_than_upper, code = "E0579")] pub struct LowerRangeBoundMustBeLessThanUpper { #[primary_span] pub span: Span, } #[derive(LintDiagnostic)] -#[diag(mir_build::leading_irrefutable_let_patterns)] +#[diag(mir_build_leading_irrefutable_let_patterns)] #[note] #[help] pub struct LeadingIrrefutableLetPatterns { @@ -507,7 +509,7 @@ pub struct LeadingIrrefutableLetPatterns { } #[derive(LintDiagnostic)] -#[diag(mir_build::trailing_irrefutable_let_patterns)] +#[diag(mir_build_trailing_irrefutable_let_patterns)] #[note] #[help] pub struct TrailingIrrefutableLetPatterns { @@ -515,7 +517,7 @@ pub struct TrailingIrrefutableLetPatterns { } #[derive(LintDiagnostic)] -#[diag(mir_build::bindings_with_variant_name, code = "E0170")] +#[diag(mir_build_bindings_with_variant_name, code = "E0170")] pub struct BindingsWithVariantName { #[suggestion(code = "{ty_path}::{ident}", applicability = "machine-applicable")] pub suggestion: Option, @@ -524,7 +526,7 @@ pub struct BindingsWithVariantName { } #[derive(LintDiagnostic)] -#[diag(mir_build::irrefutable_let_patterns_generic_let)] +#[diag(mir_build_irrefutable_let_patterns_generic_let)] #[note] #[help] pub struct IrrefutableLetPatternsGenericLet { @@ -532,7 +534,7 @@ pub struct IrrefutableLetPatternsGenericLet { } #[derive(LintDiagnostic)] -#[diag(mir_build::irrefutable_let_patterns_if_let)] +#[diag(mir_build_irrefutable_let_patterns_if_let)] #[note] #[help] pub struct IrrefutableLetPatternsIfLet { @@ -540,7 +542,7 @@ pub struct IrrefutableLetPatternsIfLet { } #[derive(LintDiagnostic)] -#[diag(mir_build::irrefutable_let_patterns_if_let_guard)] +#[diag(mir_build_irrefutable_let_patterns_if_let_guard)] #[note] #[help] pub struct IrrefutableLetPatternsIfLetGuard { @@ -548,7 +550,7 @@ pub struct IrrefutableLetPatternsIfLetGuard { } #[derive(LintDiagnostic)] -#[diag(mir_build::irrefutable_let_patterns_let_else)] +#[diag(mir_build_irrefutable_let_patterns_let_else)] #[note] #[help] pub struct IrrefutableLetPatternsLetElse { @@ -556,29 +558,29 @@ pub struct IrrefutableLetPatternsLetElse { } #[derive(LintDiagnostic)] -#[diag(mir_build::irrefutable_let_patterns_while_let)] +#[diag(mir_build_irrefutable_let_patterns_while_let)] #[note] #[help] pub struct IrrefutableLetPatternsWhileLet { pub count: usize, } -#[derive(SessionDiagnostic)] -#[diag(mir_build::borrow_of_moved_value)] +#[derive(Diagnostic)] +#[diag(mir_build_borrow_of_moved_value)] pub struct BorrowOfMovedValue<'tcx> { #[primary_span] pub span: Span, #[label] - #[label(mir_build::occurs_because_label)] + #[label(occurs_because_label)] pub binding_span: Span, - #[label(mir_build::value_borrowed_label)] + #[label(value_borrowed_label)] pub conflicts_ref: Vec, pub name: Ident, pub ty: Ty<'tcx>, } -#[derive(SessionDiagnostic)] -#[diag(mir_build::multiple_mut_borrows)] +#[derive(Diagnostic)] +#[diag(mir_build_multiple_mut_borrows)] pub struct MultipleMutBorrows { #[primary_span] pub span: Span, @@ -589,21 +591,21 @@ pub struct MultipleMutBorrows { pub name: Ident, } -#[derive(SessionSubdiagnostic)] +#[derive(Subdiagnostic)] pub enum MultipleMutBorrowOccurence { - #[label(mir_build::mutable_borrow)] + #[label(mutable_borrow)] Mutable { #[primary_span] span: Span, name_mut: Ident, }, - #[label(mir_build::immutable_borrow)] + #[label(immutable_borrow)] Immutable { #[primary_span] span: Span, name_immut: Ident, }, - #[label(mir_build::moved)] + #[label(moved)] Moved { #[primary_span] span: Span, 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 8b586574656b5..017220bf5c701 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -598,11 +598,6 @@ fn irrefutable_let_patterns( count: usize, span: Span, ) { - let span = match source { - LetSource::LetElse(span) => span, - _ => span, - }; - macro_rules! emit_diag { ($lint:tt) => {{ tcx.emit_spanned_lint(IRREFUTABLE_LET_PATTERNS, id, span, $lint { count }); @@ -613,7 +608,7 @@ fn irrefutable_let_patterns( LetSource::GenericLet => emit_diag!(IrrefutableLetPatternsGenericLet), LetSource::IfLet => emit_diag!(IrrefutableLetPatternsIfLet), LetSource::IfLetGuard => emit_diag!(IrrefutableLetPatternsIfLetGuard), - LetSource::LetElse(..) => emit_diag!(IrrefutableLetPatternsLetElse), + LetSource::LetElse => emit_diag!(IrrefutableLetPatternsLetElse), LetSource::WhileLet => emit_diag!(IrrefutableLetPatternsWhileLet), } } @@ -1000,16 +995,15 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa // Report mutability conflicts for e.g. `ref mut x @ Some(ref mut y)`. let mut occurences = vec![]; - for (span, name) in conflicts_mut_mut { - occurences.push(MultipleMutBorrowOccurence::Mutable { span, name_mut: name }); + for (span, name_mut) in conflicts_mut_mut { + occurences.push(MultipleMutBorrowOccurence::Mutable { span, name_mut }); } - for (span, name) in conflicts_mut_ref { - occurences.push(MultipleMutBorrowOccurence::Immutable { span, name_immut: name }); + for (span, name_immut) in conflicts_mut_ref { + occurences.push(MultipleMutBorrowOccurence::Immutable { span, name_immut }); } - for (span, name) in conflicts_move { - occurences.push(MultipleMutBorrowOccurence::Moved { span, name_moved: name }); + for (span, name_moved) in conflicts_move { + occurences.push(MultipleMutBorrowOccurence::Moved { span, name_moved }); } - sess.emit_err(MultipleMutBorrows { span: pat.span, binding_span, occurences, name }); } else if !conflicts_mut_ref.is_empty() { // Report mutability conflicts for e.g. `ref x @ Some(ref mut y)` or the converse. diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr index 384a57b2ee092..318a643573f2f 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr @@ -53,10 +53,10 @@ LL | let ref mut a @ ( | | LL | | LL | | ref mut b, - | | --------- another mutable borrow, by `b`, occurs here + | | --------- another mutable borrow, by `d`, occurs here LL | | [ LL | | ref mut c, - | | --------- another mutable borrow, by `c`, occurs here + | | --------- another mutable borrow, by `d`, occurs here LL | | ref mut d, | | --------- another mutable borrow, by `d`, occurs here LL | | ref e, @@ -75,10 +75,10 @@ LL | let ref mut a @ ( | | LL | | LL | | ref mut b, - | | --------- another mutable borrow, by `b`, occurs here + | | --------- another mutable borrow, by `d`, occurs here LL | | [ LL | | ref mut c, - | | --------- another mutable borrow, by `c`, occurs here + | | --------- another mutable borrow, by `d`, occurs here LL | | ref mut d, | | --------- another mutable borrow, by `d`, occurs here LL | | ref e, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs index d51ad72bd27b1..c85e1469bf256 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs @@ -3,7 +3,7 @@ //! This module provides lowering from [hir_def::expr::Pat] to [self::Pat] and match //! checking algorithm. //! -//! It is modeled on the rustc module `rustc_mir_build::thir::pattern`. +//! It is modeled on the rustc module `rustc_mir_build_thir::pattern`. mod pat_util; @@ -50,7 +50,7 @@ pub(crate) struct Pat { pub(crate) kind: Box, } -/// Close relative to `rustc_mir_build::thir::pattern::PatKind` +/// Close relative to `rustc_mir_build_thir::pattern::PatKind` #[derive(Clone, Debug, PartialEq)] pub(crate) enum PatKind { Wild, From 09ea5130aa25c5db87c80ad43c14f14d0cbf580c Mon Sep 17 00:00:00 2001 From: mejrs <> Date: Mon, 14 Nov 2022 19:08:32 +0100 Subject: [PATCH 58/81] tidy --- compiler/rustc_error_messages/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 25aee6f681b58..c8d9c2eeaaf09 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -56,8 +56,8 @@ fluent_messages! { lint => "../locales/en-US/lint.ftl", metadata => "../locales/en-US/metadata.ftl", middle => "../locales/en-US/middle.ftl", - mir_dataflow => "../locales/en-US/mir_dataflow.ftl", mir_build => "../locales/en-US/mir_build.ftl", + mir_dataflow => "../locales/en-US/mir_dataflow.ftl", monomorphize => "../locales/en-US/monomorphize.ftl", parser => "../locales/en-US/parser.ftl", passes => "../locales/en-US/passes.ftl", From a14aafafd352ed4799df5a920d601a4c03e3de62 Mon Sep 17 00:00:00 2001 From: mejrs <> Date: Tue, 15 Nov 2022 12:20:50 +0100 Subject: [PATCH 59/81] Fix "mir_build_multiple_mut_borrows" --- compiler/rustc_mir_build/src/errors.rs | 2 +- .../bindings-after-at/borrowck-pat-ref-mut-twice.stderr | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index f26f6bb25ff59..01c0b856072b0 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -586,7 +586,7 @@ pub struct MultipleMutBorrows { pub span: Span, #[label] pub binding_span: Span, - #[subdiagnostic] + #[subdiagnostic(eager)] pub occurences: Vec, pub name: Ident, } diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr index 318a643573f2f..384a57b2ee092 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr @@ -53,10 +53,10 @@ LL | let ref mut a @ ( | | LL | | LL | | ref mut b, - | | --------- another mutable borrow, by `d`, occurs here + | | --------- another mutable borrow, by `b`, occurs here LL | | [ LL | | ref mut c, - | | --------- another mutable borrow, by `d`, occurs here + | | --------- another mutable borrow, by `c`, occurs here LL | | ref mut d, | | --------- another mutable borrow, by `d`, occurs here LL | | ref e, @@ -75,10 +75,10 @@ LL | let ref mut a @ ( | | LL | | LL | | ref mut b, - | | --------- another mutable borrow, by `d`, occurs here + | | --------- another mutable borrow, by `b`, occurs here LL | | [ LL | | ref mut c, - | | --------- another mutable borrow, by `d`, occurs here + | | --------- another mutable borrow, by `c`, occurs here LL | | ref mut d, | | --------- another mutable borrow, by `d`, occurs here LL | | ref e, From 139bc67ef0864bc0a75a2a4105afb3c8b70cfd4b Mon Sep 17 00:00:00 2001 From: mejrs <> Date: Tue, 15 Nov 2022 12:21:03 +0100 Subject: [PATCH 60/81] Fix bad replacement --- .../crates/hir-ty/src/diagnostics/match_check.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs index c85e1469bf256..d51ad72bd27b1 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs @@ -3,7 +3,7 @@ //! This module provides lowering from [hir_def::expr::Pat] to [self::Pat] and match //! checking algorithm. //! -//! It is modeled on the rustc module `rustc_mir_build_thir::pattern`. +//! It is modeled on the rustc module `rustc_mir_build::thir::pattern`. mod pat_util; @@ -50,7 +50,7 @@ pub(crate) struct Pat { pub(crate) kind: Box, } -/// Close relative to `rustc_mir_build_thir::pattern::PatKind` +/// Close relative to `rustc_mir_build::thir::pattern::PatKind` #[derive(Clone, Debug, PartialEq)] pub(crate) enum PatKind { Wild, From 7e77d4e310fa36c9ede7905be5971776a075be16 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 15 Nov 2022 12:41:39 +0100 Subject: [PATCH 61/81] Strip comments and attributes off of all trait item completions --- .../src/completions/item_list/trait_impl.rs | 82 +++++++++++++++++-- 1 file changed, 76 insertions(+), 6 deletions(-) diff --git a/crates/ide-completion/src/completions/item_list/trait_impl.rs b/crates/ide-completion/src/completions/item_list/trait_impl.rs index b612cdc4a1741..7384a3f2d80b4 100644 --- a/crates/ide-completion/src/completions/item_list/trait_impl.rs +++ b/crates/ide-completion/src/completions/item_list/trait_impl.rs @@ -236,9 +236,7 @@ fn get_transformed_assoc_item( ); transform.apply(assoc_item.syntax()); - if let ast::AssocItem::Fn(func) = &assoc_item { - func.remove_attrs_and_docs(); - } + assoc_item.remove_attrs_and_docs(); Some(assoc_item) } @@ -335,7 +333,6 @@ fn add_const_impl( } fn make_const_compl_syntax(const_: &ast::Const, needs_whitespace: bool) -> String { - const_.remove_attrs_and_docs(); let const_ = if needs_whitespace { insert_whitespace_into_node::insert_ws_into(const_.syntax().clone()) } else { @@ -359,8 +356,6 @@ fn make_const_compl_syntax(const_: &ast::Const, needs_whitespace: bool) -> Strin } fn function_declaration(node: &ast::Fn, needs_whitespace: bool) -> String { - node.remove_attrs_and_docs(); - let node = if needs_whitespace { insert_whitespace_into_node::insert_ws_into(node.syntax().clone()) } else { @@ -1209,6 +1204,81 @@ trait Tr<'b> { impl<'b> Tr<'b> for () { type Ty<'a: 'b, T: Copy, const C: usize> = $0; } +"#, + ); + } + + #[test] + fn strips_comments() { + check_edit( + "fn func", + r#" +trait Tr { + /// docs + #[attr] + fn func(); +} +impl Tr for () { + $0 +} +"#, + r#" +trait Tr { + /// docs + #[attr] + fn func(); +} +impl Tr for () { + fn func() { + $0 +} +} +"#, + ); + check_edit( + "const C", + r#" +trait Tr { + /// docs + #[attr] + const C: usize; +} +impl Tr for () { + $0 +} +"#, + r#" +trait Tr { + /// docs + #[attr] + const C: usize; +} +impl Tr for () { + const C: usize = $0; +} +"#, + ); + check_edit( + "type Item", + r#" +trait Tr { + /// docs + #[attr] + type Item; +} +impl Tr for () { + $0 +} +"#, + r#" +trait Tr { + /// docs + #[attr] + type Item; +} +impl Tr for () { + type Item = $0; +} "#, ); } From 23546977081c6f3e3fc35afdc60f4c5a6b32e233 Mon Sep 17 00:00:00 2001 From: mejrs <> Date: Tue, 15 Nov 2022 12:47:55 +0100 Subject: [PATCH 62/81] Fix rebase :( --- compiler/rustc_mir_build/src/thir/pattern/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 90f224f5eff1f..608ba6b007b73 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -566,7 +566,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { _ => bug!("Expected ConstKind::Param"), }, mir::ConstantKind::Val(_, _) => self.const_to_pat(value, id, span, false).kind, - mir::ConstKind::Unevaluated(_) => { + mir::ConstantKind::Unevaluated(..) => { // If we land here it means the const can't be evaluated because it's `TooGeneric`. self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span }); return PatKind::Wild; From 1ad11b53661979624ba1bfcf4520d5e2b9edbc01 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Wed, 16 Nov 2022 19:54:07 +0900 Subject: [PATCH 63/81] fix: resolve inference variable before applying adjustments --- crates/hir-ty/src/method_resolution.rs | 2 +- crates/hir-ty/src/tests/regression.rs | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index b1178ba0d2af7..20bed7bf3cc47 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -541,7 +541,7 @@ pub struct ReceiverAdjustments { impl ReceiverAdjustments { pub(crate) fn apply(&self, table: &mut InferenceTable<'_>, ty: Ty) -> (Ty, Vec) { - let mut ty = ty; + let mut ty = table.resolve_ty_shallow(&ty); let mut adjust = Vec::new(); for _ in 0..self.autoderefs { match autoderef::autoderef_step(table, ty.clone()) { diff --git a/crates/hir-ty/src/tests/regression.rs b/crates/hir-ty/src/tests/regression.rs index a155adcec6c33..4e46397459d5d 100644 --- a/crates/hir-ty/src/tests/regression.rs +++ b/crates/hir-ty/src/tests/regression.rs @@ -1707,3 +1707,19 @@ impl Trait for [T; N] { "#, ); } + +#[test] +fn unsize_array_with_inference_variable() { + check_types( + r#" +//- minicore: try, slice +use core::ops::ControlFlow; +fn foo() -> ControlFlow<(), [usize; 1]> { loop {} } +fn bar() -> ControlFlow<(), ()> { + let a = foo()?.len(); + //^ usize + ControlFlow::Continue(()) +} +"#, + ); +} From 7577c44c65321b20b165445e417329619a9bc506 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Thu, 17 Nov 2022 01:42:56 +0900 Subject: [PATCH 64/81] Update proc-macro-srv tests --- crates/proc-macro-srv/src/tests/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/proc-macro-srv/src/tests/mod.rs b/crates/proc-macro-srv/src/tests/mod.rs index b46cdddcf6b10..cc0fc91fe989e 100644 --- a/crates/proc-macro-srv/src/tests/mod.rs +++ b/crates/proc-macro-srv/src/tests/mod.rs @@ -19,7 +19,7 @@ fn test_derive_error() { expect![[r##" SUBTREE $ IDENT compile_error 4294967295 - PUNCH ! [joint] 4294967295 + PUNCH ! [alone] 4294967295 SUBTREE () 4294967295 LITERAL "#[derive(DeriveError)] struct S ;" 4294967295 PUNCH ; [alone] 4294967295"##]], @@ -109,7 +109,7 @@ fn test_fn_like_macro_clone_literals() { PUNCH , [alone] 4294967295 LITERAL 2_u32 4294967295 PUNCH , [alone] 4294967295 - PUNCH - [joint] 4294967295 + PUNCH - [alone] 4294967295 LITERAL 4i64 4294967295 PUNCH , [alone] 4294967295 LITERAL 3.14f32 4294967295 @@ -130,7 +130,7 @@ fn test_attr_macro() { expect![[r##" SUBTREE $ IDENT compile_error 4294967295 - PUNCH ! [joint] 4294967295 + PUNCH ! [alone] 4294967295 SUBTREE () 4294967295 LITERAL "#[attr_error(some arguments)] mod m {}" 4294967295 PUNCH ; [alone] 4294967295"##]], From cd6459e7b389f1127200e83f99da45fc96b01589 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Thu, 17 Nov 2022 17:39:31 +0100 Subject: [PATCH 65/81] Make "Remove dbg!()" assist work on selections --- crates/ide-assists/src/handlers/remove_dbg.rs | 63 ++++++++++++++++--- 1 file changed, 56 insertions(+), 7 deletions(-) diff --git a/crates/ide-assists/src/handlers/remove_dbg.rs b/crates/ide-assists/src/handlers/remove_dbg.rs index 3d9cbff177ba9..99ae60e07bcfa 100644 --- a/crates/ide-assists/src/handlers/remove_dbg.rs +++ b/crates/ide-assists/src/handlers/remove_dbg.rs @@ -1,7 +1,7 @@ use itertools::Itertools; use syntax::{ ast::{self, AstNode, AstToken}, - match_ast, NodeOrToken, SyntaxElement, TextSize, T, + match_ast, NodeOrToken, SyntaxElement, TextRange, TextSize, T, }; use crate::{AssistContext, AssistId, AssistKind, Assists}; @@ -22,7 +22,36 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; // } // ``` pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { - let macro_call = ctx.find_node_at_offset::()?; + let macro_calls = if ctx.has_empty_selection() { + vec![ctx.find_node_at_offset::()?] + } else { + ctx.covering_element() + .as_node()? + .descendants() + .filter(|node| ctx.selection_trimmed().contains_range(node.text_range())) + .filter_map(ast::MacroCall::cast) + .collect() + }; + + let replacements = + macro_calls.into_iter().filter_map(compute_dbg_replacement).collect::>(); + if replacements.is_empty() { + return None; + } + + acc.add( + AssistId("remove_dbg", AssistKind::Refactor), + "Remove dbg!()", + ctx.selection_trimmed(), + |builder| { + for (range, text) in replacements { + builder.replace(range, text); + } + }, + ) +} + +fn compute_dbg_replacement(macro_call: ast::MacroCall) -> Option<(TextRange, String)> { let tt = macro_call.token_tree()?; let r_delim = NodeOrToken::Token(tt.right_delimiter_token()?); if macro_call.path()?.segment()?.name_ref()?.text() != "dbg" @@ -41,7 +70,7 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<( let macro_expr = ast::MacroExpr::cast(macro_call.syntax().parent()?)?; let parent = macro_expr.syntax().parent()?; - let (range, text) = match &*input_expressions { + Some(match &*input_expressions { // dbg!() [] => { match_ast! { @@ -107,10 +136,6 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<( } // dbg!(expr0, expr1, ...) exprs => (macro_call.syntax().text_range(), format!("({})", exprs.iter().format(", "))), - }; - - acc.add(AssistId("remove_dbg", AssistKind::Refactor), "Remove dbg!()", range, |builder| { - builder.replace(range, text); }) } @@ -238,4 +263,28 @@ fn foo() { check(r#"$0dbg!(0, 1)"#, r#"(0, 1)"#); check(r#"$0dbg!(0, (1, 2))"#, r#"(0, (1, 2))"#); } + + #[test] + fn test_range() { + check( + r#" +fn f() { + dbg!(0) + $0dbg!(1); + dbg!(())$0 +} +"#, + r#" +fn f() { + dbg!(0) + 1; + () +} +"#, + ); + } + + #[test] + fn test_range_partial() { + check_assist_not_applicable(remove_dbg, r#"$0dbg$0!(0)"#); + check_assist_not_applicable(remove_dbg, r#"$0dbg!(0$0)"#); + } } From 656d886ca8a37ac4b0df60f48d699584d3abca46 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 18 Nov 2022 11:31:12 +0100 Subject: [PATCH 66/81] Make it more obvious which SCIP features we do not yet emit in code --- crates/rust-analyzer/src/cli/scip.rs | 115 ++++++++++++++++----------- 1 file changed, 68 insertions(+), 47 deletions(-) diff --git a/crates/rust-analyzer/src/cli/scip.rs b/crates/rust-analyzer/src/cli/scip.rs index ca7ba896b67cf..9edd045ab0716 100644 --- a/crates/rust-analyzer/src/cli/scip.rs +++ b/crates/rust-analyzer/src/cli/scip.rs @@ -47,30 +47,27 @@ impl flags::Scip { let si = StaticIndex::compute(&analysis); - let mut index = scip_types::Index { - metadata: Some(scip_types::Metadata { - version: scip_types::ProtocolVersion::UnspecifiedProtocolVersion.into(), - tool_info: Some(scip_types::ToolInfo { - name: "rust-analyzer".to_owned(), - version: "0.1".to_owned(), - arguments: vec![], - ..Default::default() - }) - .into(), - project_root: format!( - "file://{}", - path.normalize() - .as_os_str() - .to_str() - .ok_or(anyhow::anyhow!("Unable to normalize project_root path"))? - .to_string() - ), - text_document_encoding: scip_types::TextEncoding::UTF8.into(), - ..Default::default() + let metadata = scip_types::Metadata { + version: scip_types::ProtocolVersion::UnspecifiedProtocolVersion.into(), + tool_info: Some(scip_types::ToolInfo { + name: "rust-analyzer".to_owned(), + version: "0.1".to_owned(), + arguments: vec![], + special_fields: Default::default(), }) .into(), - ..Default::default() + project_root: format!( + "file://{}", + path.normalize() + .as_os_str() + .to_str() + .ok_or(anyhow::anyhow!("Unable to normalize project_root path"))? + .to_string() + ), + text_document_encoding: scip_types::TextEncoding::UTF8.into(), + special_fields: Default::default(), }; + let mut documents = Vec::new(); let mut symbols_emitted: HashSet = HashSet::default(); let mut tokens_to_symbol: HashMap = HashMap::new(); @@ -95,18 +92,14 @@ impl flags::Scip { endings: LineEndings::Unix, }; - let mut doc = scip_types::Document { - relative_path, - language: "rust".to_string(), - ..Default::default() - }; + let mut occurrences = Vec::new(); + let mut symbols = Vec::new(); - tokens.into_iter().for_each(|(range, id)| { + tokens.into_iter().for_each(|(text_range, id)| { let token = si.tokens.get(id).unwrap(); - let mut occurrence = scip_types::Occurrence::default(); - occurrence.range = text_range_to_scip_range(&line_index, range); - occurrence.symbol = tokens_to_symbol + let range = text_range_to_scip_range(&line_index, text_range); + let symbol = tokens_to_symbol .entry(id) .or_insert_with(|| { let symbol = token_to_symbol(&token).unwrap_or_else(&mut new_local_symbol); @@ -114,34 +107,62 @@ impl flags::Scip { }) .clone(); + let mut symbol_roles = Default::default(); + if let Some(def) = token.definition { - if def.range == range { - occurrence.symbol_roles |= scip_types::SymbolRole::Definition as i32; + if def.range == text_range { + symbol_roles |= scip_types::SymbolRole::Definition as i32; } if symbols_emitted.insert(id) { - let mut symbol_info = scip_types::SymbolInformation::default(); - symbol_info.symbol = occurrence.symbol.clone(); - if let Some(hover) = &token.hover { - if !hover.markup.as_str().is_empty() { - symbol_info.documentation = vec![hover.markup.as_str().to_string()]; - } - } - - doc.symbols.push(symbol_info) + let documentation = token + .hover + .as_ref() + .map(|hover| hover.markup.as_str()) + .filter(|it| !it.is_empty()) + .map(|it| vec![it.to_owned()]); + let symbol_info = scip_types::SymbolInformation { + symbol: symbol.clone(), + documentation: documentation.unwrap_or_default(), + relationships: Vec::new(), + special_fields: Default::default(), + }; + + symbols.push(symbol_info) } } - doc.occurrences.push(occurrence); + occurrences.push(scip_types::Occurrence { + range, + symbol, + symbol_roles, + override_documentation: Vec::new(), + syntax_kind: Default::default(), + diagnostics: Vec::new(), + special_fields: Default::default(), + }); }); - if doc.occurrences.is_empty() { + if occurrences.is_empty() { continue; } - index.documents.push(doc); + documents.push(scip_types::Document { + relative_path, + language: "rust".to_string(), + occurrences, + symbols, + special_fields: Default::default(), + }); } + let index = scip_types::Index { + metadata: Some(metadata).into(), + documents, + external_symbols: Vec::new(), + special_fields: Default::default(), + }; + scip::write_message_to_file("index.scip", index) .map_err(|err| anyhow::anyhow!("Failed to write scip to file: {}", err))?; @@ -181,7 +202,7 @@ fn new_descriptor_str( name: name.to_string(), disambiguator: "".to_string(), suffix: suffix.into(), - ..Default::default() + special_fields: Default::default(), } } @@ -232,11 +253,11 @@ fn token_to_symbol(token: &TokenStaticData) -> Option { manager: "cargo".to_string(), name: package_name, version: version.unwrap_or_else(|| ".".to_string()), - ..Default::default() + special_fields: Default::default(), }) .into(), descriptors, - ..Default::default() + special_fields: Default::default(), }) } From 073a63b93ec39b51cb412119c38716c1af5db871 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 18 Nov 2022 19:47:45 +0100 Subject: [PATCH 67/81] feat: Allow viewing the full compiler diagnostic in a readonly textview --- .../rust-analyzer/src/diagnostics/to_proto.rs | 19 +++++---- editors/code/package.json | 5 +++ editors/code/src/client.ts | 42 ++++++++++++++++++- editors/code/src/config.ts | 3 ++ editors/code/src/ctx.ts | 3 +- editors/code/src/main.ts | 24 +++++++++++ 6 files changed, 84 insertions(+), 12 deletions(-) diff --git a/crates/rust-analyzer/src/diagnostics/to_proto.rs b/crates/rust-analyzer/src/diagnostics/to_proto.rs index 189ac2fbf5339..35f37c740b802 100644 --- a/crates/rust-analyzer/src/diagnostics/to_proto.rs +++ b/crates/rust-analyzer/src/diagnostics/to_proto.rs @@ -359,14 +359,15 @@ pub(crate) fn map_rust_diagnostic_to_lsp( .iter() .flat_map(|primary_span| { let primary_location = primary_location(config, workspace_root, primary_span, snap); - - let mut message = message.clone(); - if needs_primary_span_label { - if let Some(primary_span_label) = &primary_span.label { - format_to!(message, "\n{}", primary_span_label); + let message = { + let mut message = message.clone(); + if needs_primary_span_label { + if let Some(primary_span_label) = &primary_span.label { + format_to!(message, "\n{}", primary_span_label); + } } - } - + message + }; // Each primary diagnostic span may result in multiple LSP diagnostics. let mut diagnostics = Vec::new(); @@ -417,7 +418,7 @@ pub(crate) fn map_rust_diagnostic_to_lsp( message: message.clone(), related_information: Some(information_for_additional_diagnostic), tags: if tags.is_empty() { None } else { Some(tags.clone()) }, - data: None, + data: Some(serde_json::json!({ "rendered": rd.rendered })), }; diagnostics.push(MappedRustDiagnostic { url: secondary_location.uri, @@ -449,7 +450,7 @@ pub(crate) fn map_rust_diagnostic_to_lsp( } }, tags: if tags.is_empty() { None } else { Some(tags.clone()) }, - data: None, + data: Some(serde_json::json!({ "rendered": rd.rendered })), }, fix: None, }); diff --git a/editors/code/package.json b/editors/code/package.json index 0c78165960423..b1c3473b825df 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -396,6 +396,11 @@ "default": true, "type": "boolean" }, + "rust-analyzer.diagnostics.previewRustcOutput": { + "markdownDescription": "Whether to show the main part of the rendered rustc output of a diagnostic message.", + "default": false, + "type": "boolean" + }, "$generated-start": {}, "rust-analyzer.assist.emitMustUse": { "markdownDescription": "Whether to insert #[must_use] when generating `as_` methods\nfor enum variants.", diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index fb667619c86be..23e039722ee33 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts @@ -4,7 +4,7 @@ import * as ra from "../src/lsp_ext"; import * as Is from "vscode-languageclient/lib/common/utils/is"; import { assert } from "./util"; import { WorkspaceEdit } from "vscode"; -import { substituteVSCodeVariables } from "./config"; +import { Config, substituteVSCodeVariables } from "./config"; import { randomUUID } from "crypto"; export interface Env { @@ -66,7 +66,8 @@ export async function createClient( traceOutputChannel: vscode.OutputChannel, outputChannel: vscode.OutputChannel, initializationOptions: vscode.WorkspaceConfiguration, - serverOptions: lc.ServerOptions + serverOptions: lc.ServerOptions, + config: Config ): Promise { const clientOptions: lc.LanguageClientOptions = { documentSelector: [{ scheme: "file", language: "rust" }], @@ -99,6 +100,43 @@ export async function createClient( } }, }, + async handleDiagnostics( + uri: vscode.Uri, + diagnostics: vscode.Diagnostic[], + next: lc.HandleDiagnosticsSignature + ) { + const preview = config.previewRustcOutput; + diagnostics.forEach((diag, idx) => { + // Abuse the fact that VSCode leaks the LSP diagnostics data field through the + // Diagnostic class, if they ever break this we are out of luck and have to go + // back to the worst diagnostics experience ever:) + + // We encode the rendered output of a rustc diagnostic in the rendered field of + // the data payload of the lsp diagnostic. If that field exists, overwrite the + // diagnostic code such that clicking it opens the diagnostic in a readonly + // text editor for easy inspection + const rendered = (diag as unknown as { data?: { rendered?: string } }).data + ?.rendered; + if (rendered) { + if (preview) { + const index = rendered.match(/^(note|help):/m)?.index || 0; + diag.message = rendered + .substring(0, index) + .replace(/^ -->[^\n]+\n/m, ""); + } + diag.code = { + target: vscode.Uri.from({ + scheme: "rust-analyzer-diagnostics-view", + path: "/diagnostic message", + fragment: uri.toString(), + query: idx.toString(), + }), + value: "Click for full compiler diagnostic", + }; + } + }); + return next(uri, diagnostics); + }, async provideHover( document: vscode.TextDocument, position: vscode.Position, diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index 632a7d86faa36..d8dbd1df16dfb 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts @@ -238,6 +238,9 @@ export class Config { gotoTypeDef: this.get("hover.actions.gotoTypeDef.enable"), }; } + get previewRustcOutput() { + return this.get("diagnostics.previewRustcOutput"); + } } const VarRegex = new RegExp(/\$\{(.+?)\}/g); diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts index 3e366525ee295..d6cee5c8fc610 100644 --- a/editors/code/src/ctx.ts +++ b/editors/code/src/ctx.ts @@ -179,7 +179,8 @@ export class Ctx { this.traceOutputChannel, this.outputChannel, initializationOptions, - serverOptions + serverOptions, + this.config ); this.pushClientCleanup( this._client.onNotification(ra.serverStatus, (params) => diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index e76b657c1bfb5..25f1e83d109cb 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts @@ -48,6 +48,30 @@ async function activateServer(ctx: Ctx): Promise { ctx.pushExtCleanup(activateTaskProvider(ctx.config)); } + ctx.pushExtCleanup( + vscode.workspace.registerTextDocumentContentProvider( + "rust-analyzer-diagnostics-view", + new (class implements vscode.TextDocumentContentProvider { + async provideTextDocumentContent(uri: vscode.Uri): Promise { + const diags = ctx.client?.diagnostics?.get( + vscode.Uri.parse(uri.fragment, true) + ); + if (!diags) { + return "Unable to find original rustc diagnostic"; + } + + const diag = diags[parseInt(uri.query)]; + if (!diag) { + return "Unable to find original rustc diagnostic"; + } + const rendered = (diag as unknown as { data?: { rendered?: string } }).data + ?.rendered; + return rendered ?? "Unable to find original rustc diagnostic"; + } + })() + ) + ); + vscode.workspace.onDidChangeWorkspaceFolders( async (_) => ctx.onWorkspaceFolderChanges(), null, From 8452844c2674584064d8d459e41a3a809648a62f Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 18 Nov 2022 20:11:48 +0100 Subject: [PATCH 68/81] Fix tests checking the data value --- crates/rust-analyzer/src/diagnostics/to_proto.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/rust-analyzer/src/diagnostics/to_proto.rs b/crates/rust-analyzer/src/diagnostics/to_proto.rs index 35f37c740b802..beb23c54c9f0f 100644 --- a/crates/rust-analyzer/src/diagnostics/to_proto.rs +++ b/crates/rust-analyzer/src/diagnostics/to_proto.rs @@ -535,7 +535,8 @@ mod tests { Config::new(workspace_root.to_path_buf(), ClientCapabilities::default()), ); let snap = state.snapshot(); - let actual = map_rust_diagnostic_to_lsp(&config, &diagnostic, workspace_root, &snap); + let mut actual = map_rust_diagnostic_to_lsp(&config, &diagnostic, workspace_root, &snap); + actual.iter_mut().for_each(|diag| diag.diagnostic.data = None); expect.assert_debug_eq(&actual) } From 52bc15fc1fe763f5e7a91cb70c71a00997bb52ab Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 18 Nov 2022 23:32:26 +0100 Subject: [PATCH 69/81] fix: Fix proc-macro-srv search paths for Arch Linux --- crates/project-model/src/workspace.rs | 15 +++++++++ crates/rust-analyzer/src/cli/load_cargo.rs | 22 +++---------- crates/rust-analyzer/src/reload.rs | 36 +++------------------- 3 files changed, 25 insertions(+), 48 deletions(-) diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index 4a2f468de7255..3d199ed24afe7 100644 --- a/crates/project-model/src/workspace.rs +++ b/crates/project-model/src/workspace.rs @@ -377,6 +377,21 @@ impl ProjectWorkspace { } } + pub fn find_sysroot_proc_macro_srv(&self) -> Option { + match self { + ProjectWorkspace::Cargo { sysroot: Some(sysroot), .. } + | ProjectWorkspace::Json { sysroot: Some(sysroot), .. } => { + let standalone_server_name = + format!("rust-analyzer-proc-macro-srv{}", std::env::consts::EXE_SUFFIX); + ["libexec", "lib"] + .into_iter() + .map(|segment| sysroot.root().join(segment).join(&standalone_server_name)) + .find(|server_path| std::fs::metadata(&server_path).is_ok()) + } + _ => None, + } + } + /// Returns the roots for the current `ProjectWorkspace` /// The return type contains the path and whether or not /// the root is a member of the current workspace diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs index 5dba545b87184..762d7d3a18e8b 100644 --- a/crates/rust-analyzer/src/cli/load_cargo.rs +++ b/crates/rust-analyzer/src/cli/load_cargo.rs @@ -60,24 +60,12 @@ pub fn load_workspace( }; let proc_macro_client = if load_config.with_proc_macro { - let mut path = AbsPathBuf::assert(std::env::current_exe()?); - let mut args = vec!["proc-macro"]; - - if let ProjectWorkspace::Cargo { sysroot, .. } | ProjectWorkspace::Json { sysroot, .. } = - &ws - { - if let Some(sysroot) = sysroot.as_ref() { - let standalone_server_name = - format!("rust-analyzer-proc-macro-srv{}", std::env::consts::EXE_SUFFIX); - let server_path = sysroot.root().join("libexec").join(&standalone_server_name); - if std::fs::metadata(&server_path).is_ok() { - path = server_path; - args = vec![]; - } - } - } + let (server_path, args): (_, &[_]) = match ws.find_sysroot_proc_macro_srv() { + Some(server_path) => (server_path, &[]), + None => (AbsPathBuf::assert(std::env::current_exe()?), &["proc-macro"]), + }; - ProcMacroServer::spawn(path.clone(), args.clone()).map_err(|e| e.to_string()) + ProcMacroServer::spawn(server_path, args).map_err(|e| e.to_string()) } else { Err("proc macro server disabled".to_owned()) }; diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index aa0510a4ea6a0..fcfe4be0b8cec 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -305,9 +305,6 @@ impl GlobalState { let files_config = self.config.files(); let project_folders = ProjectFolders::new(&self.workspaces, &files_config.exclude); - let standalone_server_name = - format!("rust-analyzer-proc-macro-srv{}", std::env::consts::EXE_SUFFIX); - if self.proc_macro_clients.is_empty() { if let Some((path, path_manually_set)) = self.config.proc_macro_srv() { tracing::info!("Spawning proc-macro servers"); @@ -315,40 +312,17 @@ impl GlobalState { .workspaces .iter() .map(|ws| { - let (path, args) = if path_manually_set { + let (path, args): (_, &[_]) = if path_manually_set { tracing::debug!( "Pro-macro server path explicitly set: {}", path.display() ); - (path.clone(), vec![]) + (path.clone(), &[]) } else { - let mut sysroot_server = None; - if let ProjectWorkspace::Cargo { sysroot, .. } - | ProjectWorkspace::Json { sysroot, .. } = ws - { - if let Some(sysroot) = sysroot.as_ref() { - let server_path = sysroot - .root() - .join("libexec") - .join(&standalone_server_name); - if std::fs::metadata(&server_path).is_ok() { - tracing::debug!( - "Sysroot proc-macro server exists at {}", - server_path.display() - ); - sysroot_server = Some(server_path); - } else { - tracing::debug!( - "Sysroot proc-macro server does not exist at {}", - server_path.display() - ); - } - } + match ws.find_sysroot_proc_macro_srv() { + Some(server_path) => (server_path, &[]), + None => (path.clone(), &["proc-macro"]), } - sysroot_server.map_or_else( - || (path.clone(), vec!["proc-macro".to_owned()]), - |path| (path, vec![]), - ) }; tracing::info!(?args, "Using proc-macro server at {}", path.display(),); From a3f8fd71df0e09b6cd161a7e7df78c67bb47d329 Mon Sep 17 00:00:00 2001 From: Kartavya Vashishtha Date: Sat, 19 Nov 2022 15:00:25 +0530 Subject: [PATCH 70/81] fix: format expression parsing edge-cases handle positional arg with formatting handle indexed positional args --- .../src/handlers/move_format_string_arg.rs | 6 +- .../src/syntax_helpers/format_string_exprs.rs | 62 +++++++++---------- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/crates/ide-assists/src/handlers/move_format_string_arg.rs b/crates/ide-assists/src/handlers/move_format_string_arg.rs index aa710d2ce6513..11db6ae7f7b81 100644 --- a/crates/ide-assists/src/handlers/move_format_string_arg.rs +++ b/crates/ide-assists/src/handlers/move_format_string_arg.rs @@ -92,7 +92,7 @@ pub(crate) fn move_format_string_arg(acc: &mut Assists, ctx: &AssistContext<'_>) NodeOrToken::Node(n) => { format_to!(current_arg, "{n}"); }, - NodeOrToken::Token(t) if t.kind() == COMMA=> { + NodeOrToken::Token(t) if t.kind() == COMMA => { existing_args.push(current_arg.trim().into()); current_arg.clear(); }, @@ -238,14 +238,14 @@ fn main() { &add_macro_decl( r#" fn main() { - print!("{} {x + 1:b} {Struct(1, 2)}$0", 1); + print!("{:b} {x + 1:b} {Struct(1, 2)}$0", 1); } "#, ), &add_macro_decl( r#" fn main() { - print!("{} {:b} {}"$0, 1, x + 1, Struct(1, 2)); + print!("{:b} {:b} {}"$0, 1, x + 1, Struct(1, 2)); } "#, ), diff --git a/crates/ide-db/src/syntax_helpers/format_string_exprs.rs b/crates/ide-db/src/syntax_helpers/format_string_exprs.rs index ac6c6e8feeea0..c3b7bb27d88bb 100644 --- a/crates/ide-db/src/syntax_helpers/format_string_exprs.rs +++ b/crates/ide-db/src/syntax_helpers/format_string_exprs.rs @@ -103,7 +103,12 @@ pub fn parse_format_exprs(input: &str) -> Result<(String, Vec), ()> { output.push(chr); extracted_expressions.push(Arg::Placeholder); state = State::NotArg; - } + }, + (State::MaybeArg, ':') => { + output.push(chr); + extracted_expressions.push(Arg::Placeholder); + state = State::FormatOpts; + }, (State::MaybeArg, _) => { if matches!(chr, '\\' | '$') { current_expr.push('\\'); @@ -117,49 +122,40 @@ pub fn parse_format_exprs(input: &str) -> Result<(String, Vec), ()> { } else { state = State::Expr; } - } - (State::Ident | State::Expr, '}') => { - if inexpr_open_count == 0 { - output.push(chr); - - if matches!(state, State::Expr) { - extracted_expressions.push(Arg::Expr(current_expr.trim().into())); - } else { - extracted_expressions.push(Arg::Ident(current_expr.trim().into())); - } - - current_expr = String::new(); - state = State::NotArg; - } else { - // We're closing one brace met before inside of the expression. - current_expr.push(chr); - inexpr_open_count -= 1; - } - } + }, (State::Ident | State::Expr, ':') if matches!(chars.peek(), Some(':')) => { // path separator state = State::Expr; current_expr.push_str("::"); chars.next(); - } - (State::Ident | State::Expr, ':') => { + }, + (State::Ident | State::Expr, ':' | '}') => { if inexpr_open_count == 0 { - // We're outside of braces, thus assume that it's a specifier, like "{Some(value):?}" - output.push(chr); + let trimmed = current_expr.trim(); - if matches!(state, State::Expr) { - extracted_expressions.push(Arg::Expr(current_expr.trim().into())); + // if the expression consists of a single number, like "0" or "12", it can refer to + // format args in the order they are specified. + // see: https://doc.rust-lang.org/std/fmt/#positional-parameters + if trimmed.chars().fold(true, |only_num, c| c.is_ascii_digit() && only_num) { + output.push_str(trimmed); + } else if matches!(state, State::Expr) { + extracted_expressions.push(Arg::Expr(trimmed.into())); } else { - extracted_expressions.push(Arg::Ident(current_expr.trim().into())); + extracted_expressions.push(Arg::Ident(trimmed.into())); } - current_expr = String::new(); - state = State::FormatOpts; - } else { + output.push(chr); + current_expr.clear(); + state = if chr == ':' {State::FormatOpts} else if chr == '}' {State::NotArg} else {unreachable!()}; + } else if chr == '}' { + // We're closing one brace met before inside of the expression. + current_expr.push(chr); + inexpr_open_count -= 1; + } else if chr == ':' { // We're inside of braced expression, assume that it's a struct field name/value delimiter. current_expr.push(chr); } - } + }, (State::Ident | State::Expr, '{') => { state = State::Expr; current_expr.push(chr); @@ -219,6 +215,10 @@ mod tests { ("{expr} is {2 + 2}", expect![["{} is {}; expr, 2 + 2"]]), ("{expr:?}", expect![["{:?}; expr"]]), ("{expr:1$}", expect![[r"{:1\$}; expr"]]), + ("{:1$}", expect![[r"{:1\$}; $1"]]), + ("{:>padding$}", expect![[r"{:>padding\$}; $1"]]), + ("{}, {}, {0}", expect![[r"{}, {}, {0}; $1, $2"]]), + ("{}, {}, {0:b}", expect![[r"{}, {}, {0:b}; $1, $2"]]), ("{$0}", expect![[r"{}; \$0"]]), ("{malformed", expect![["-"]]), ("malformed}", expect![["-"]]), From dc8254c6abdfcd273cb49475e798048558dcf4db Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 19 Nov 2022 10:32:32 +0100 Subject: [PATCH 71/81] fix: Fix nested macro diagnostics pointing at macro expansion files --- .../src/handlers/macro_error.rs | 5 +---- .../src/handlers/unresolved_macro_call.rs | 5 +---- .../src/handlers/unresolved_proc_macro.rs | 12 +--------- crates/ide-diagnostics/src/lib.rs | 22 +++++++++++++++++++ 4 files changed, 25 insertions(+), 19 deletions(-) diff --git a/crates/ide-diagnostics/src/handlers/macro_error.rs b/crates/ide-diagnostics/src/handlers/macro_error.rs index 43ff4ed5a6c86..870c78d1f1eb7 100644 --- a/crates/ide-diagnostics/src/handlers/macro_error.rs +++ b/crates/ide-diagnostics/src/handlers/macro_error.rs @@ -5,10 +5,7 @@ use crate::{Diagnostic, DiagnosticsContext}; // This diagnostic is shown for macro expansion errors. pub(crate) fn macro_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroError) -> Diagnostic { // Use more accurate position if available. - let display_range = d - .precise_location - .unwrap_or_else(|| ctx.sema.diagnostics_display_range(d.node.clone()).range); - + let display_range = ctx.resolve_precise_location(&d.node, d.precise_location); Diagnostic::new("macro-error", d.message.clone(), display_range).experimental() } diff --git a/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs b/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs index 4b43124757f06..87531f4acfb75 100644 --- a/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs +++ b/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs @@ -9,10 +9,7 @@ pub(crate) fn unresolved_macro_call( d: &hir::UnresolvedMacroCall, ) -> Diagnostic { // Use more accurate position if available. - let display_range = d - .precise_location - .unwrap_or_else(|| ctx.sema.diagnostics_display_range(d.macro_call.clone()).range); - + let display_range = ctx.resolve_precise_location(&d.macro_call, d.precise_location); let bang = if d.is_bang { "!" } else { "" }; Diagnostic::new( "unresolved-macro-call", diff --git a/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs b/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs index 760f51f90498c..23818d883f731 100644 --- a/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs +++ b/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs @@ -1,5 +1,4 @@ use hir::db::DefDatabase; -use syntax::NodeOrToken; use crate::{Diagnostic, DiagnosticsContext, Severity}; @@ -19,16 +18,7 @@ pub(crate) fn unresolved_proc_macro( proc_attr_macros_enabled: bool, ) -> Diagnostic { // Use more accurate position if available. - let display_range = (|| { - let precise_location = d.precise_location?; - let root = ctx.sema.parse_or_expand(d.node.file_id)?; - match root.covering_element(precise_location) { - NodeOrToken::Node(it) => Some(ctx.sema.original_range(&it)), - NodeOrToken::Token(it) => d.node.with_value(it).original_file_range_opt(ctx.sema.db), - } - })() - .unwrap_or_else(|| ctx.sema.diagnostics_display_range(d.node.clone())) - .range; + let display_range = ctx.resolve_precise_location(&d.node, d.precise_location); let config_enabled = match d.kind { hir::MacroKind::Attr => proc_macros_enabled && proc_attr_macros_enabled, diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs index ae299f0584148..d81e36a1f8632 100644 --- a/crates/ide-diagnostics/src/lib.rs +++ b/crates/ide-diagnostics/src/lib.rs @@ -182,6 +182,28 @@ struct DiagnosticsContext<'a> { resolve: &'a AssistResolveStrategy, } +impl<'a> DiagnosticsContext<'a> { + fn resolve_precise_location( + &self, + node: &InFile, + precise_location: Option, + ) -> TextRange { + let sema = &self.sema; + (|| { + let precise_location = precise_location?; + let root = sema.parse_or_expand(node.file_id)?; + match root.covering_element(precise_location) { + syntax::NodeOrToken::Node(it) => Some(sema.original_range(&it)), + syntax::NodeOrToken::Token(it) => { + node.with_value(it).original_file_range_opt(sema.db) + } + } + })() + .unwrap_or_else(|| sema.diagnostics_display_range(node.clone())) + .range + } +} + pub fn diagnostics( db: &RootDatabase, config: &DiagnosticsConfig, From 6d4b2b4b17841cdb29e99bf7e7e71b57dbaa2dc1 Mon Sep 17 00:00:00 2001 From: Kartavya Vashishtha Date: Sat, 19 Nov 2022 15:08:32 +0530 Subject: [PATCH 72/81] run cargo fmt --- .../src/syntax_helpers/format_string_exprs.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/crates/ide-db/src/syntax_helpers/format_string_exprs.rs b/crates/ide-db/src/syntax_helpers/format_string_exprs.rs index c3b7bb27d88bb..313346ee13153 100644 --- a/crates/ide-db/src/syntax_helpers/format_string_exprs.rs +++ b/crates/ide-db/src/syntax_helpers/format_string_exprs.rs @@ -103,12 +103,12 @@ pub fn parse_format_exprs(input: &str) -> Result<(String, Vec), ()> { output.push(chr); extracted_expressions.push(Arg::Placeholder); state = State::NotArg; - }, + } (State::MaybeArg, ':') => { output.push(chr); extracted_expressions.push(Arg::Placeholder); state = State::FormatOpts; - }, + } (State::MaybeArg, _) => { if matches!(chr, '\\' | '$') { current_expr.push('\\'); @@ -122,13 +122,13 @@ pub fn parse_format_exprs(input: &str) -> Result<(String, Vec), ()> { } else { state = State::Expr; } - }, + } (State::Ident | State::Expr, ':') if matches!(chars.peek(), Some(':')) => { // path separator state = State::Expr; current_expr.push_str("::"); chars.next(); - }, + } (State::Ident | State::Expr, ':' | '}') => { if inexpr_open_count == 0 { let trimmed = current_expr.trim(); @@ -146,7 +146,13 @@ pub fn parse_format_exprs(input: &str) -> Result<(String, Vec), ()> { output.push(chr); current_expr.clear(); - state = if chr == ':' {State::FormatOpts} else if chr == '}' {State::NotArg} else {unreachable!()}; + state = if chr == ':' { + State::FormatOpts + } else if chr == '}' { + State::NotArg + } else { + unreachable!() + }; } else if chr == '}' { // We're closing one brace met before inside of the expression. current_expr.push(chr); @@ -155,7 +161,7 @@ pub fn parse_format_exprs(input: &str) -> Result<(String, Vec), ()> { // We're inside of braced expression, assume that it's a struct field name/value delimiter. current_expr.push(chr); } - }, + } (State::Ident | State::Expr, '{') => { state = State::Expr; current_expr.push(chr); From a4f071afd5ebe8a1fc537136f9e823349cdee526 Mon Sep 17 00:00:00 2001 From: bvanjoi Date: Sat, 19 Nov 2022 19:38:53 +0800 Subject: [PATCH 73/81] fix(assists): remove `item_const` which had default value when implement missing members` --- .../src/handlers/add_missing_impl_members.rs | 10 ++++++++-- .../src/handlers/replace_derive_with_manual_impl.rs | 2 -- crates/ide-assists/src/utils.rs | 4 ++++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/crates/ide-assists/src/handlers/add_missing_impl_members.rs index 722302f991e27..2b3793659cf7d 100644 --- a/crates/ide-assists/src/handlers/add_missing_impl_members.rs +++ b/crates/ide-assists/src/handlers/add_missing_impl_members.rs @@ -196,6 +196,7 @@ trait Foo { type Output; const CONST: usize = 42; + const CONST_2: i32; fn foo(&self); fn bar(&self); @@ -213,6 +214,7 @@ trait Foo { type Output; const CONST: usize = 42; + const CONST_2: i32; fn foo(&self); fn bar(&self); @@ -226,7 +228,7 @@ impl Foo for S { $0type Output; - const CONST: usize = 42; + const CONST_2: i32; fn foo(&self) { todo!() @@ -658,6 +660,7 @@ trait Foo { type Output; const CONST: usize = 42; + const CONST_2: i32; fn valid(some: u32) -> bool { false } fn foo(some: u32) -> bool; @@ -669,13 +672,16 @@ trait Foo { type Output; const CONST: usize = 42; + const CONST_2: i32; fn valid(some: u32) -> bool { false } fn foo(some: u32) -> bool; } struct S; impl Foo for S { - $0fn valid(some: u32) -> bool { false } + $0const CONST: usize = 42; + + fn valid(some: u32) -> bool { false } }"#, ) } diff --git a/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs index f9ba289ee175f..6fa15b28e4efc 100644 --- a/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs +++ b/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs @@ -1019,8 +1019,6 @@ struct Foo { impl foo::Bar for Foo { $0type Qux; - const Baz: usize = 42; - const Fez: usize; fn foo() { diff --git a/crates/ide-assists/src/utils.rs b/crates/ide-assists/src/utils.rs index 307e67927056b..68c31b4f8e922 100644 --- a/crates/ide-assists/src/utils.rs +++ b/crates/ide-assists/src/utils.rs @@ -119,6 +119,10 @@ pub fn filter_assoc_items( (default_methods, def.body()), (DefaultMethods::Only, Some(_)) | (DefaultMethods::No, None) ), + ast::AssocItem::Const(def) => matches!( + (default_methods, def.body()), + (DefaultMethods::Only, Some(_)) | (DefaultMethods::No, None) + ), _ => default_methods == DefaultMethods::No, }) .collect::>() From e39d90a8e6723cbd9937aca273d1f58a9beee2c9 Mon Sep 17 00:00:00 2001 From: ZZzzaaKK <66885975+ZZzzaaKK@users.noreply.github.com> Date: Sun, 20 Nov 2022 01:58:16 +0100 Subject: [PATCH 74/81] Improve grammar of architecture.md --- docs/dev/architecture.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/dev/architecture.md b/docs/dev/architecture.md index e3a4fdfda90c2..a07cf036e0604 100644 --- a/docs/dev/architecture.md +++ b/docs/dev/architecture.md @@ -481,7 +481,7 @@ It is not cheap enough to enable in prod, and this is a bug which should be fixe rust-analyzer strives to be as configurable as possible while offering reasonable defaults where no configuration exists yet. The rule of thumb is to enable most features by default unless they are buggy or degrade performance too much. There will always be features that some people find more annoying than helpful, so giving the users the ability to tweak or disable these is a big part of offering a good user experience. -Enabling them by default is a matter of discoverability, as many users end up don't know about some features even though they are presented in the manual. +Enabling them by default is a matter of discoverability, as many users don't know about some features even though they are presented in the manual. Mind the code--architecture gap: at the moment, we are using fewer feature flags than we really should. ### Serialization @@ -492,8 +492,8 @@ If a type is serializable, then it is a part of some IPC boundary. You often don't control the other side of this boundary, so changing serializable types is hard. For this reason, the types in `ide`, `base_db` and below are not serializable by design. -If such types need to cross an IPC boundary, then the client of rust-analyzer needs to provide custom, client-specific serialization format. +If such types need to cross an IPC boundary, then the client of rust-analyzer needs to provide a custom, client-specific serialization format. This isolates backwards compatibility and migration concerns to a specific client. -For example, `rust-project.json` is it's own format -- it doesn't include `CrateGraph` as is. +For example, `rust-project.json` is its own format -- it doesn't include `CrateGraph` as is. Instead, it creates a `CrateGraph` by calling appropriate constructing functions. From ebbc5492f586601a9a369ace53397864bc39b71a Mon Sep 17 00:00:00 2001 From: Max Gautier Date: Sun, 20 Nov 2022 12:47:28 +0100 Subject: [PATCH 75/81] Fix typo on 'configuration' anchor https://rust-analyzer.github.io/manual.html#_configuration lands you at the start of the page, while https://rust-analyzer.github.io/manual.html#configuration correctly puts you at the correct anchor --- docs/user/manual.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc index 49500e390a502..1a4c70575b033 100644 --- a/docs/user/manual.adoc +++ b/docs/user/manual.adoc @@ -367,7 +367,7 @@ if executable('rust-analyzer') endif ---- -There is no dedicated UI for the server configuration, so you would need to send any options as a value of the `initialization_options` field, as described in the <<_configuration,Configuration>> section. +There is no dedicated UI for the server configuration, so you would need to send any options as a value of the `initialization_options` field, as described in the <> section. Here is an example of how to enable the proc-macro support: [source,vim] From a2da749d905e64b78784278dcc2250f9587cab56 Mon Sep 17 00:00:00 2001 From: David Rheinsberg Date: Mon, 21 Nov 2022 16:47:02 +0100 Subject: [PATCH 76/81] codegen-llvm: never combine DSOLocal and DllImport Prevent DllImport from being attached to DSOLocal definitions in the LLVM IR. The combination makes no sense, since definitions local to the compilation unit will never be imported from external objects. Additionally, LLVM will refuse the IR if it encounters the combination (introduced in [1]): if (GV.hasDLLImportStorageClass()) Assert(!GV.isDSOLocal(), "GlobalValue with DLLImport Storage is dso_local!", &GV); Right now, codegen-llvm will only apply DllImport to constants and rely on call-stubs for functions. Hence, we simply extend the codegen of constants to skip DllImport for any local definitions. This was discovered when switching the EFI targets to the static relocation model [2]. With this fixed, we can start another attempt at this. [1] https://smlnj-gitlab.cs.uchicago.edu/manticore/llvm/commit/509132b368efed10bbdad825403f45e9cf1d6e38 [2] https://github.com/rust-lang/rust/issues/101656 --- compiler/rustc_codegen_llvm/src/consts.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 69434280b2144..3c324359565c1 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -295,8 +295,18 @@ impl<'ll> CodegenCx<'ll, '_> { llvm::set_thread_local_mode(g, self.tls_model); } + let dso_local = unsafe { self.should_assume_dso_local(g, true) }; + if dso_local { + unsafe { + llvm::LLVMRustSetDSOLocal(g, true); + } + } + if !def_id.is_local() { let needs_dll_storage_attr = self.use_dll_storage_attrs && !self.tcx.is_foreign_item(def_id) && + // Local definitions can never be imported, so we must not apply + // the DLLImport annotation. + !dso_local && // ThinLTO can't handle this workaround in all cases, so we don't // emit the attrs. Instead we make them unnecessary by disallowing // dynamic linking when linker plugin based LTO is enabled. @@ -340,12 +350,6 @@ impl<'ll> CodegenCx<'ll, '_> { } } - unsafe { - if self.should_assume_dso_local(g, true) { - llvm::LLVMRustSetDSOLocal(g, true); - } - } - self.instances.borrow_mut().insert(instance, g); g } From 46e0b025dc8a83d85fc2baef48079e9b7d5c45d2 Mon Sep 17 00:00:00 2001 From: David Rheinsberg Date: Tue, 22 Nov 2022 11:12:26 +0100 Subject: [PATCH 77/81] test/codegen: test inter-crate linkage with static relocation Add a codegen-test that verifies inter-crate linkage with the static relocation model. We expect all symbols that are part of a rust compilation to end up in the same DSO, thus we expect `dso_local` annotations. --- src/test/codegen/auxiliary/extern_decl.rs | 11 +++++++++ src/test/codegen/static-relocation-model.rs | 25 +++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 src/test/codegen/auxiliary/extern_decl.rs create mode 100644 src/test/codegen/static-relocation-model.rs diff --git a/src/test/codegen/auxiliary/extern_decl.rs b/src/test/codegen/auxiliary/extern_decl.rs new file mode 100644 index 0000000000000..edc48351869a6 --- /dev/null +++ b/src/test/codegen/auxiliary/extern_decl.rs @@ -0,0 +1,11 @@ +// Auxiliary crate that exports a function and static. Both always +// evaluate to `71`. We force mutability on the static to prevent +// it from being inlined as constant. + +#![crate_type = "lib"] + +#[no_mangle] +pub fn extern_fn() -> u8 { unsafe { extern_static } } + +#[no_mangle] +pub static mut extern_static: u8 = 71; diff --git a/src/test/codegen/static-relocation-model.rs b/src/test/codegen/static-relocation-model.rs new file mode 100644 index 0000000000000..12a7657fa7de1 --- /dev/null +++ b/src/test/codegen/static-relocation-model.rs @@ -0,0 +1,25 @@ +// Verify linkage of external symbols in the static relocation model. +// +// compile-flags: -O -C relocation-model=static +// aux-build: extern_decl.rs + +#![crate_type = "rlib"] + +extern crate extern_decl; + +// The `extern_decl` definitions are imported from a statically linked rust +// crate, thus they are expected to be marked `dso_local` without `dllimport`. +// +// The `access_extern()` symbol is from this compilation unit, thus we expect +// it to be marked `dso_local` as well, given the static relocation model. +// +// CHECK: @extern_static = external dso_local local_unnamed_addr global i8 +// CHECK: define dso_local i8 @access_extern() {{.*}} +// CHECK: declare dso_local i8 @extern_fn() {{.*}} + +#[no_mangle] +pub fn access_extern() -> u8 { + unsafe { + extern_decl::extern_fn() + extern_decl::extern_static + } +} From 0a756cc8f1e9bc1c1fee715c75837371f3864fc1 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 18 Nov 2022 14:10:36 +0000 Subject: [PATCH 78/81] get rid of to_poly_trait_predicate --- compiler/rustc_hir_typeck/src/coercion.rs | 3 +-- .../src/fn_ctxt/suggestions.rs | 3 +-- compiler/rustc_hir_typeck/src/method/probe.rs | 2 +- compiler/rustc_middle/src/ty/mod.rs | 19 +++++++++++++++++++ compiler/rustc_middle/src/ty/sty.rs | 17 ----------------- .../src/traits/auto_trait.rs | 19 +++++++++++-------- .../src/traits/codegen.rs | 3 +-- .../src/traits/error_reporting/mod.rs | 2 +- .../rustc_trait_selection/src/traits/mod.rs | 2 +- .../src/traits/project.rs | 5 ++--- .../src/traits/select/confirmation.rs | 7 +------ src/librustdoc/clean/blanket_impl.rs | 7 +------ 12 files changed, 40 insertions(+), 49 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 43c7127b0d4c5..2c82c26c91abf 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -806,8 +806,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { self.param_env, ty::Binder::dummy( self.tcx.at(self.cause.span).mk_trait_ref(hir::LangItem::PointerSized, [a]), - ) - .to_poly_trait_predicate(), + ), )); } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index b5aa8cd6e7c5b..625cd18422370 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1096,8 +1096,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Binder::dummy(self.tcx.mk_trait_ref( into_def_id, [expr_ty, expected_ty] - )) - .to_poly_trait_predicate(), + )), )) { let sugg = if expr.precedence().order() >= PREC_POSTFIX { diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 9d75ccad133dd..0d9f980a00f20 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -1429,7 +1429,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { trait_ref: ty::TraitRef<'tcx>, ) -> traits::SelectionResult<'tcx, traits::Selection<'tcx>> { let cause = traits::ObligationCause::misc(self.span, self.body_id); - let predicate = ty::Binder::dummy(trait_ref).to_poly_trait_predicate(); + let predicate = ty::Binder::dummy(trait_ref); let obligation = traits::Obligation::new(self.tcx, cause, self.param_env, predicate); traits::SelectionContext::new(self).select(&obligation) } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 3f26d337d4575..ce7278140205c 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1147,6 +1147,25 @@ impl<'tcx> ToPredicate<'tcx, Predicate<'tcx>> for Binder<'tcx, PredicateKind<'tc } } +impl<'tcx> ToPredicate<'tcx, Predicate<'tcx>> for Binder<'tcx, TraitRef<'tcx>> { + #[inline(always)] + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + let pred: PolyTraitPredicate<'tcx> = self.to_predicate(tcx); + pred.to_predicate(tcx) + } +} + +impl<'tcx> ToPredicate<'tcx, PolyTraitPredicate<'tcx>> for Binder<'tcx, TraitRef<'tcx>> { + #[inline(always)] + fn to_predicate(self, _: TyCtxt<'tcx>) -> PolyTraitPredicate<'tcx> { + self.map_bound(|trait_ref| TraitPredicate { + trait_ref, + constness: ty::BoundConstness::NotConst, + polarity: ty::ImplPolarity::Positive, + }) + } +} + impl<'tcx> ToPredicate<'tcx, Predicate<'tcx>> for PolyTraitPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { self.map_bound(PredicateKind::Trait).to_predicate(tcx) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index e7a751fa0afca..a53b275fb02cd 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -853,23 +853,6 @@ impl<'tcx> PolyTraitRef<'tcx> { pub fn def_id(&self) -> DefId { self.skip_binder().def_id } - - pub fn to_poly_trait_predicate(&self) -> ty::PolyTraitPredicate<'tcx> { - self.map_bound(|trait_ref| ty::TraitPredicate { - trait_ref, - constness: ty::BoundConstness::NotConst, - polarity: ty::ImplPolarity::Positive, - }) - } - - /// Same as [`PolyTraitRef::to_poly_trait_predicate`] but sets a negative polarity instead. - pub fn to_poly_trait_predicate_negative_polarity(&self) -> ty::PolyTraitPredicate<'tcx> { - self.map_bound(|trait_ref| ty::TraitPredicate { - trait_ref, - constness: ty::BoundConstness::NotConst, - polarity: ty::ImplPolarity::Negative, - }) - } } impl rustc_errors::IntoDiagnosticArg for PolyTraitRef<'_> { diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index a057e45ad6af4..27e72ba4382d2 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -10,7 +10,7 @@ use crate::traits::project::ProjectAndUnifyResult; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::visit::TypeVisitable; -use rustc_middle::ty::{PolyTraitRef, Region, RegionVid}; +use rustc_middle::ty::{ImplPolarity, Region, RegionVid}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; @@ -88,19 +88,22 @@ impl<'tcx> AutoTraitFinder<'tcx> { let trait_ref = tcx.mk_trait_ref(trait_did, [ty]); - let trait_pred = ty::Binder::dummy(trait_ref); - let infcx = tcx.infer_ctxt().build(); let mut selcx = SelectionContext::new(&infcx); - for f in [ - PolyTraitRef::to_poly_trait_predicate, - PolyTraitRef::to_poly_trait_predicate_negative_polarity, - ] { + for polarity in [true, false] { let result = selcx.select(&Obligation::new( tcx, ObligationCause::dummy(), orig_env, - f(&trait_pred), + ty::Binder::dummy(ty::TraitPredicate { + trait_ref, + constness: ty::BoundConstness::NotConst, + polarity: if polarity { + ImplPolarity::Positive + } else { + ImplPolarity::Negative + }, + }), )); if let Ok(Some(ImplSource::UserDefined(_))) = result { debug!( diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs index ca4299f7db394..61743d78e9e80 100644 --- a/compiler/rustc_trait_selection/src/traits/codegen.rs +++ b/compiler/rustc_trait_selection/src/traits/codegen.rs @@ -39,8 +39,7 @@ pub fn codegen_select_candidate<'tcx>( let mut selcx = SelectionContext::new(&infcx); let obligation_cause = ObligationCause::dummy(); - let obligation = - Obligation::new(tcx, obligation_cause, param_env, trait_ref.to_poly_trait_predicate()); + let obligation = Obligation::new(tcx, obligation_cause, param_env, trait_ref); let selection = match selcx.select(&obligation) { Ok(Some(selection)) => selection, 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 946e6e77a3da0..937fc9c8d300d 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -2111,7 +2111,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ) }; - let obligation = obligation.with(self.tcx, trait_ref.to_poly_trait_predicate()); + let obligation = obligation.with(self.tcx, trait_ref); let mut selcx = SelectionContext::with_query_mode( &self, crate::traits::TraitQueryMode::Standard, diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index ff18aa1f9e909..88ba0e8049e94 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -473,7 +473,7 @@ fn subst_and_check_impossible_predicates<'tcx>( // associated items. if let Some(trait_def_id) = tcx.trait_of_item(key.0) { let trait_ref = ty::TraitRef::from_method(tcx, trait_def_id, key.1); - predicates.push(ty::Binder::dummy(trait_ref).to_poly_trait_predicate().to_predicate(tcx)); + predicates.push(ty::Binder::dummy(trait_ref).to_predicate(tcx)); } predicates.retain(|predicate| !predicate.needs_subst()); diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 9f19b0092c00f..5441a348685e1 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1343,8 +1343,7 @@ fn assemble_candidate_for_impl_trait_in_trait<'cx, 'tcx>( obligation.predicate.substs.truncate_to(tcx, tcx.generics_of(trait_def_id)); // FIXME(named-returns): Binders let trait_predicate = - ty::Binder::dummy(ty::TraitRef { def_id: trait_def_id, substs: trait_substs }) - .to_poly_trait_predicate(); + ty::Binder::dummy(ty::TraitRef { def_id: trait_def_id, substs: trait_substs }); let _ = selcx.infcx().commit_if_ok(|_| { match selcx.select(&obligation.with(tcx, trait_predicate)) { @@ -1542,7 +1541,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // If we are resolving `>::Item == Type`, // start out by selecting the predicate `T as TraitRef<...>`: let poly_trait_ref = ty::Binder::dummy(obligation.predicate.trait_ref(selcx.tcx())); - let trait_obligation = obligation.with(selcx.tcx(), poly_trait_ref.to_poly_trait_predicate()); + let trait_obligation = obligation.with(selcx.tcx(), poly_trait_ref); let _ = selcx.infcx().commit_if_ok(|_| { let impl_source = match selcx.select(&trait_obligation) { Ok(Some(impl_source)) => impl_source, diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 2ec5d925b6900..d503d4d8563a9 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -634,12 +634,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ); let tr = ty::Binder::dummy(self.tcx().at(cause.span).mk_trait_ref(LangItem::Sized, [output_ty])); - nested.push(Obligation::new( - self.infcx.tcx, - cause, - obligation.param_env, - tr.to_poly_trait_predicate(), - )); + nested.push(Obligation::new(self.infcx.tcx, cause, obligation.param_env, tr)); Ok(ImplSourceFnPointerData { fn_ty: self_ty, nested }) } diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index cb0b8d4a9bc19..a1145b90d6580 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -67,12 +67,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { .instantiate(cx.tcx, impl_substs) .predicates .into_iter() - .chain(Some( - ty::Binder::dummy(impl_trait_ref) - .to_poly_trait_predicate() - .map_bound(ty::PredicateKind::Trait) - .to_predicate(infcx.tcx), - )); + .chain(Some(ty::Binder::dummy(impl_trait_ref).to_predicate(infcx.tcx))); for predicate in predicates { debug!("testing predicate {:?}", predicate); let obligation = traits::Obligation::new( From b19cf140ace6d0cc48f618d6a796890e7be4e7a0 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 18 Nov 2022 21:29:26 +0000 Subject: [PATCH 79/81] Simplify a bunch of trait ref obligation creations --- .../src/transform/check_consts/check.rs | 13 ++++--------- .../src/transform/check_consts/ops.rs | 11 +++-------- .../src/transform/check_consts/qualifs.rs | 7 ++----- compiler/rustc_hir_analysis/src/check/wfcheck.rs | 2 +- compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs | 6 +----- compiler/rustc_hir_typeck/src/method/mod.rs | 2 +- compiler/rustc_trait_selection/src/autoderef.rs | 2 +- .../src/traits/object_safety.rs | 3 +-- .../src/traits/select/candidate_assembly.rs | 8 ++------ src/tools/clippy/clippy_lints/src/ptr.rs | 3 +-- 10 files changed, 17 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 36956f5dd6d96..078beadf3fc12 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -10,7 +10,7 @@ use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceC use rustc_middle::mir::*; use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts}; use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt}; -use rustc_middle::ty::{Binder, TraitPredicate, TraitRef, TypeVisitable}; +use rustc_middle::ty::{Binder, TraitRef, TypeVisitable}; use rustc_mir_dataflow::{self, Analysis}; use rustc_span::{sym, Span, Symbol}; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; @@ -726,11 +726,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } let trait_ref = TraitRef::from_method(tcx, trait_id, substs); - let poly_trait_pred = Binder::dummy(TraitPredicate { - trait_ref, - constness: ty::BoundConstness::ConstIfConst, - polarity: ty::ImplPolarity::Positive, - }); + let poly_trait_pred = + Binder::dummy(trait_ref).with_constness(ty::BoundConstness::ConstIfConst); let obligation = Obligation::new(tcx, ObligationCause::dummy(), param_env, poly_trait_pred); @@ -819,9 +816,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { tcx, ObligationCause::dummy_with_span(*fn_span), param_env, - tcx.mk_predicate( - poly_trait_pred.map_bound(ty::PredicateKind::Trait), - ), + poly_trait_pred, ); // improve diagnostics by showing what failed. Our requirements are stricter this time diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index c62c665158779..bfc950eff5c06 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -13,10 +13,9 @@ use rustc_middle::mir; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; use rustc_middle::ty::{ - suggest_constraining_type_param, Adt, Closure, DefIdTree, FnDef, FnPtr, Param, TraitPredicate, - Ty, + suggest_constraining_type_param, Adt, Closure, DefIdTree, FnDef, FnPtr, Param, Ty, }; -use rustc_middle::ty::{Binder, BoundConstness, ImplPolarity, TraitRef}; +use rustc_middle::ty::{Binder, TraitRef}; use rustc_session::parse::feature_err; use rustc_span::symbol::sym; use rustc_span::{BytePos, Pos, Span, Symbol}; @@ -150,11 +149,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { tcx, ObligationCause::dummy(), param_env, - Binder::dummy(TraitPredicate { - trait_ref, - constness: BoundConstness::NotConst, - polarity: ImplPolarity::Positive, - }), + Binder::dummy(trait_ref), ); let infcx = tcx.infer_ctxt().build(); diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index e7b3df9b7288b..8ca3fdf400eb3 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -157,11 +157,8 @@ impl Qualif for NeedsNonConstDrop { cx.tcx, ObligationCause::dummy_with_span(cx.body.span), cx.param_env, - ty::Binder::dummy(ty::TraitPredicate { - trait_ref: cx.tcx.at(cx.body.span).mk_trait_ref(LangItem::Destruct, [ty]), - constness: ty::BoundConstness::ConstIfConst, - polarity: ty::ImplPolarity::Positive, - }), + ty::Binder::dummy(cx.tcx.at(cx.body.span).mk_trait_ref(LangItem::Destruct, [ty])) + .with_constness(ty::BoundConstness::ConstIfConst), ); let infcx = cx.tcx.infer_ctxt().build(); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 7119f3a238697..d23c41ed69014 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1784,7 +1784,7 @@ fn receiver_is_implemented<'tcx>( let tcx = wfcx.tcx(); let trait_ref = ty::Binder::dummy(tcx.mk_trait_ref(receiver_trait_def_id, [receiver_ty])); - let obligation = traits::Obligation::new(tcx, cause, wfcx.param_env, trait_ref.without_const()); + let obligation = traits::Obligation::new(tcx, cause, wfcx.param_env, trait_ref); if wfcx.infcx.predicate_must_hold_modulo_regions(&obligation) { true diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index a31ab9c8b23b8..e2cdb2ab3a712 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -2157,11 +2157,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx, traits::ObligationCause::dummy(), self.param_env, - ty::Binder::dummy(ty::TraitPredicate { - trait_ref, - constness: ty::BoundConstness::NotConst, - polarity: ty::ImplPolarity::Positive, - }), + ty::Binder::dummy(trait_ref), ); match SelectionContext::new(&self).select(&obligation) { Ok(Some(traits::ImplSource::UserDefined(impl_source))) => { diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index 9b1f0cff074a6..9c2de1763b080 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -348,7 +348,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, ), self.param_env, - poly_trait_ref.without_const(), + poly_trait_ref, ), substs, ) diff --git a/compiler/rustc_trait_selection/src/autoderef.rs b/compiler/rustc_trait_selection/src/autoderef.rs index 9b39a9401149a..f5d276d3fc5d3 100644 --- a/compiler/rustc_trait_selection/src/autoderef.rs +++ b/compiler/rustc_trait_selection/src/autoderef.rs @@ -130,7 +130,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { tcx, cause.clone(), self.param_env, - ty::Binder::dummy(trait_ref).without_const(), + ty::Binder::dummy(trait_ref), ); if !self.infcx.predicate_may_hold(&obligation) { debug!("overloaded_deref_ty: cannot match obligation"); diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 90f48658113af..6c51e5d4baaae 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -721,8 +721,7 @@ fn receiver_is_dispatchable<'tcx>( let obligation = { let predicate = ty::Binder::dummy( tcx.mk_trait_ref(dispatch_from_dyn_did, [receiver_ty, unsized_receiver_ty]), - ) - .without_const(); + ); Obligation::new(tcx, ObligationCause::dummy(), param_env, predicate) }; diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 3b107d9570f14..8bb4599544454 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -715,12 +715,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // let trait_ref = tcx.mk_trait_ref(tcx.lang_items().deref_trait()?, [ty]); - let obligation = traits::Obligation::new( - tcx, - cause.clone(), - param_env, - ty::Binder::dummy(trait_ref).without_const(), - ); + let obligation = + traits::Obligation::new(tcx, cause.clone(), param_env, ty::Binder::dummy(trait_ref)); if !self.infcx.predicate_may_hold(&obligation) { return None; } diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index 5420a0e782ea8..8c4cff66f554b 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -698,9 +698,8 @@ fn matches_preds<'tcx>( cx.tcx, ObligationCause::dummy(), cx.param_env, - cx.tcx.mk_predicate(Binder::bind_with_vars( + cx.tcx.mk_predicate(Binder::dummy( PredicateKind::Projection(p.with_self_ty(cx.tcx, ty)), - List::empty(), )), )), ExistentialPredicate::AutoTrait(p) => infcx From 409203a3151dd7d45b05145f267a83f81be52c5e Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 23 Nov 2022 11:27:07 -0300 Subject: [PATCH 80/81] Use ObligationCtxt::normalize --- .../src/check/compare_method.rs | 21 ++++--------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/compare_method.rs b/compiler/rustc_hir_analysis/src/check/compare_method.rs index bf4e5126bfa10..de386e2d13556 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_method.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_method.rs @@ -218,14 +218,11 @@ fn compare_predicate_entailment<'tcx>( debug!("compare_impl_method: caller_bounds={:?}", param_env.caller_bounds()); - let mut selcx = traits::SelectionContext::new(&infcx); let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_placeholder_substs); for (predicate, span) in iter::zip(impl_m_own_bounds.predicates, impl_m_own_bounds.spans) { let normalize_cause = traits::ObligationCause::misc(span, impl_m_hir_id); - let traits::Normalized { value: predicate, obligations } = - traits::normalize(&mut selcx, param_env, normalize_cause, predicate); + let predicate = ocx.normalize(normalize_cause, param_env, predicate); - ocx.register_obligations(obligations); let cause = ObligationCause::new( span, impl_m_hir_id, @@ -1555,14 +1552,11 @@ fn compare_type_predicate_entailment<'tcx>( debug!("compare_type_predicate_entailment: caller_bounds={:?}", param_env.caller_bounds()); - let mut selcx = traits::SelectionContext::new(&infcx); - assert_eq!(impl_ty_own_bounds.predicates.len(), impl_ty_own_bounds.spans.len()); for (span, predicate) in std::iter::zip(impl_ty_own_bounds.spans, impl_ty_own_bounds.predicates) { let cause = ObligationCause::misc(span, impl_ty_hir_id); - let traits::Normalized { value: predicate, obligations } = - traits::normalize(&mut selcx, param_env, cause, predicate); + let predicate = ocx.normalize(cause, param_env, predicate); let cause = ObligationCause::new( span, @@ -1573,7 +1567,6 @@ fn compare_type_predicate_entailment<'tcx>( kind: impl_ty.kind, }, ); - ocx.register_obligations(obligations); ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate)); } @@ -1756,7 +1749,6 @@ pub fn check_type_bounds<'tcx>( let assumed_wf_types = ocx.assumed_wf_types(param_env, impl_ty_span, impl_ty.def_id.expect_local()); - let mut selcx = traits::SelectionContext::new(&infcx); let normalize_cause = ObligationCause::new( impl_ty_span, impl_ty_hir_id, @@ -1785,16 +1777,11 @@ pub fn check_type_bounds<'tcx>( debug!("check_type_bounds: item_bounds={:?}", obligations); for mut obligation in util::elaborate_obligations(tcx, obligations) { - let traits::Normalized { value: normalized_predicate, obligations } = traits::normalize( - &mut selcx, - normalize_param_env, - normalize_cause.clone(), - obligation.predicate, - ); + let normalized_predicate = + ocx.normalize(normalize_cause.clone(), normalize_param_env, obligation.predicate); debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate); obligation.predicate = normalized_predicate; - ocx.register_obligations(obligations); ocx.register_obligation(obligation); } // Check that all obligations are satisfied by the implementation's From 54a6d4edbc56d99ecf6a461975acceb219b8a2d8 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Sun, 20 Nov 2022 14:19:12 -0800 Subject: [PATCH 81/81] Add `#![deny(unsafe_op_in_unsafe_fn)]` in liballoc tests --- library/alloc/tests/boxed.rs | 41 ++++++++++++++++++++++++++++++------ library/alloc/tests/lib.rs | 1 + library/alloc/tests/vec.rs | 3 ++- 3 files changed, 38 insertions(+), 7 deletions(-) diff --git a/library/alloc/tests/boxed.rs b/library/alloc/tests/boxed.rs index 9e5123be98990..af49826ff30a3 100644 --- a/library/alloc/tests/boxed.rs +++ b/library/alloc/tests/boxed.rs @@ -102,8 +102,18 @@ unsafe impl const Allocator for ConstAllocator { let new_ptr = self.allocate(new_layout)?; if new_layout.size() > 0 { - new_ptr.as_mut_ptr().copy_from_nonoverlapping(ptr.as_ptr(), old_layout.size()); - self.deallocate(ptr, old_layout); + // Safety: `new_ptr` is valid for writes and `ptr` for reads of + // `old_layout.size()`, because `new_layout.size() >= + // old_layout.size()` (which is an invariant that must be upheld by + // callers). + unsafe { + new_ptr.as_mut_ptr().copy_from_nonoverlapping(ptr.as_ptr(), old_layout.size()); + } + // Safety: `ptr` is never used again is also an invariant which must + // be upheld by callers. + unsafe { + self.deallocate(ptr, old_layout); + } } Ok(new_ptr) } @@ -114,12 +124,21 @@ unsafe impl const Allocator for ConstAllocator { old_layout: Layout, new_layout: Layout, ) -> Result, AllocError> { - let new_ptr = self.grow(ptr, old_layout, new_layout)?; + // Safety: Invariants of `grow_zeroed` and `grow` are the same, and must + // be enforced by callers. + let new_ptr = unsafe { self.grow(ptr, old_layout, new_layout)? }; if new_layout.size() > 0 { let old_size = old_layout.size(); let new_size = new_layout.size(); let raw_ptr = new_ptr.as_mut_ptr(); - raw_ptr.add(old_size).write_bytes(0, new_size - old_size); + // Safety: + // - `grow` returned Ok, so the returned pointer must be valid for + // `new_size` bytes + // - `new_size` must be larger than `old_size`, which is an + // invariant which must be upheld by callers. + unsafe { + raw_ptr.add(old_size).write_bytes(0, new_size - old_size); + } } Ok(new_ptr) } @@ -137,8 +156,18 @@ unsafe impl const Allocator for ConstAllocator { let new_ptr = self.allocate(new_layout)?; if new_layout.size() > 0 { - new_ptr.as_mut_ptr().copy_from_nonoverlapping(ptr.as_ptr(), new_layout.size()); - self.deallocate(ptr, old_layout); + // Safety: `new_ptr` and `ptr` are valid for reads/writes of + // `new_layout.size()` because of the invariants of shrink, which + // include `new_layout.size()` being smaller than (or equal to) + // `old_layout.size()`. + unsafe { + new_ptr.as_mut_ptr().copy_from_nonoverlapping(ptr.as_ptr(), new_layout.size()); + } + // Safety: `ptr` is never used again is also an invariant which must + // be upheld by callers. + unsafe { + self.deallocate(ptr, old_layout); + } } Ok(new_ptr) } diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index d066ec03ee57e..d6d2b055b2395 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -48,6 +48,7 @@ #![feature(once_cell)] #![feature(drain_keep_rest)] #![deny(fuzzy_provenance_casts)] +#![deny(unsafe_op_in_unsafe_fn)] use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index e027118704478..7ebed0d5ca699 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -1089,7 +1089,8 @@ fn test_into_iter_drop_allocator() { } unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { - System.deallocate(ptr, layout) + // Safety: Invariants passed to caller. + unsafe { System.deallocate(ptr, layout) } } }