Repository: rust-analyzer/rust-analyzer
Pull request #8830 (2021-05-13 22:44:20)

feat: Implement bulitin macro `concat_idents`
cc  #8828

bors r+


Patch:
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs
index 98b485b602..8360426f13 100644
--- a/crates/hir_def/src/body.rs
+++ b/crates/hir_def/src/body.rs
@@ -21,6 +21,8 @@ use profile::Count;
 use rustc_hash::FxHashMap;
 use syntax::{ast, AstNode, AstPtr};
 
+pub use lower::LowerCtx;
+
 use crate::{
     attr::{Attrs, RawAttrs},
     db::DefDatabase,
@@ -33,8 +35,6 @@ use crate::{
     UnresolvedMacro,
 };
 
-pub use lower::LowerCtx;
-
 /// A subset of Expander that only deals with cfg attributes. We only need it to
 /// avoid cyclic queries in crate def map during enum processing.
 #[derive(Debug)]
diff --git a/crates/hir_def/src/find_path.rs b/crates/hir_def/src/find_path.rs
index ee52794aa8..858e880381 100644
--- a/crates/hir_def/src/find_path.rs
+++ b/crates/hir_def/src/find_path.rs
@@ -5,10 +5,10 @@ use std::iter;
 use hir_expand::name::{known, AsName, Name};
 use rustc_hash::FxHashSet;
 
+use crate::nameres::DefMap;
 use crate::{
     db::DefDatabase,
     item_scope::ItemInNs,
-    nameres::DefMap,
     path::{ModPath, PathKind},
     visibility::Visibility,
     ModuleDefId, ModuleId,
@@ -134,16 +134,7 @@ fn find_path_inner(
     for (name, def_id) in root_def_map.extern_prelude() {
         if item == ItemInNs::Types(*def_id) {
             let name = scope_name.unwrap_or_else(|| name.clone());
-
-            let name_already_occupied_in_type_ns = def_map
-                .with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| {
-                    def_map[local_id].scope.get(&name).take_types().filter(|&id| id != *def_id)
-                })
-                .is_some();
-            return Some(ModPath::from_segments(
-                if name_already_occupied_in_type_ns { PathKind::Abs } else { PathKind::Plain },
-                vec![name],
-            ));
+            return Some(ModPath::from_segments(PathKind::Plain, vec![name]));
         }
     }
 
diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs
index af98021441..280c25f111 100644
--- a/crates/hir_expand/src/builtin_macro.rs
+++ b/crates/hir_expand/src/builtin_macro.rs
@@ -118,6 +118,7 @@ register_builtin! {
     EAGER:
     (compile_error, CompileError) => compile_error_expand,
     (concat, Concat) => concat_expand,
+    (concat_idents, ConcatIdents) => concat_idents_expand,
     (include, Include) => include_expand,
     (include_bytes, IncludeBytes) => include_bytes_expand,
     (include_str, IncludeStr) => include_str_expand,
@@ -373,6 +374,28 @@ fn concat_expand(
     ExpandResult { value: Some(ExpandedEager::new(quote!(#text), FragmentKind::Expr)), err }
 }
 
+fn concat_idents_expand(
+    _db: &dyn AstDatabase,
+    _arg_id: EagerMacroId,
+    tt: &tt::Subtree,
+) -> ExpandResult<Option<ExpandedEager>> {
+    let mut err = None;
+    let mut ident = String::new();
+    for (i, t) in tt.token_trees.iter().enumerate() {
+        match t {
+            tt::TokenTree::Leaf(tt::Leaf::Ident(id)) => {
+                ident.push_str(id.text.as_str());
+            }
+            tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if i % 2 == 1 && punct.char == ',' => (),
+            _ => {
+                err.get_or_insert(mbe::ExpandError::UnexpectedToken);
+            }
+        }
+    }
+    let ident = tt::Ident { text: ident.into(), id: tt::TokenId::unspecified() };
+    ExpandResult { value: Some(ExpandedEager::new(quote!(#ident), FragmentKind::Expr)), err }
+}
+
 fn relative_file(
     db: &dyn AstDatabase,
     call_id: MacroCallId,
@@ -794,4 +817,16 @@ mod tests {
             expect![[r#""foor0bar\nfalse""#]],
         );
     }
+
+    #[test]
+    fn test_concat_idents_expand() {
+        check_expansion(
+            r##"
+            #[rustc_builtin_macro]
+            macro_rules! concat_idents {}
+            concat_idents!(foo, bar);
+            "##,
+            expect![[r#"foobar"#]],
+        );
+    }
 }
diff --git a/crates/hir_expand/src/name.rs b/crates/hir_expand/src/name.rs
index bcfd3e5242..5a5dc9afdb 100644
--- a/crates/hir_expand/src/name.rs
+++ b/crates/hir_expand/src/name.rs
@@ -212,6 +212,7 @@ pub mod known {
         std_panic,
         stringify,
         concat,
+        concat_idents,
         include,
         include_bytes,
         include_str,
diff --git a/crates/hir_ty/src/consts.rs b/crates/hir_ty/src/consts.rs
deleted file mode 100644
index 0044b1cffc..0000000000
--- a/crates/hir_ty/src/consts.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-//! Handling of concrete const values
-
-/// A concrete constant value
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub enum ConstScalar {
-    // for now, we only support the trivial case of constant evaluating the length of an array
-    // Note that this is u64 because the target usize may be bigger than our usize
-    Usize(u64),
-
-    /// Case of an unknown value that rustc might know but we don't
-    Unknown,
-}
-
-impl std::fmt::Display for ConstScalar {
-    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
-        match self {
-            ConstScalar::Usize(us) => write!(fmt, "{}", us),
-            ConstScalar::Unknown => write!(fmt, "_"),
-        }
-    }
-}
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs
index 8a42966973..1f6edf7a28 100644
--- a/crates/hir_ty/src/display.rs
+++ b/crates/hir_ty/src/display.rs
@@ -308,7 +308,7 @@ impl HirDisplay for Const {
                 let param_data = &generics.params.consts[id.local_id];
                 write!(f, "{}", param_data.name)
             }
-            ConstValue::Concrete(c) => write!(f, "{}", c.interned),
+            ConstValue::Concrete(_) => write!(f, "_"),
         }
     }
 }
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index 2178ffd077..9476e6297e 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -3,7 +3,7 @@
 use std::iter::{repeat, repeat_with};
 use std::{mem, sync::Arc};
 
-use chalk_ir::{cast::Cast, fold::Shift, ConstData, Mutability, TyVariableKind};
+use chalk_ir::{cast::Cast, fold::Shift, Mutability, TyVariableKind};
 use hir_def::{
     expr::{Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp},
     path::{GenericArg, GenericArgs},
@@ -15,9 +15,7 @@ use stdx::always;
 use syntax::ast::RangeOp;
 
 use crate::{
-    autoderef,
-    consts::ConstScalar,
-    dummy_usize_const,
+    autoderef, dummy_usize_const,
     lower::lower_to_chalk_mutability,
     mapping::from_chalk,
     method_resolution, op,
@@ -25,7 +23,7 @@ use crate::{
     static_lifetime, to_chalk_trait_id,
     traits::FnTrait,
     utils::{generics, Generics},
-    AdtId, Binders, CallableDefId, ConstValue, FnPointer, FnSig, FnSubst, InEnvironment, Interner,
+    AdtId, Binders, CallableDefId, FnPointer, FnSig, FnSubst, InEnvironment, Interner,
     ProjectionTyExt, Rawness, Scalar, Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind,
 };
 
@@ -719,12 +717,11 @@ impl<'a> InferenceContext<'a> {
                     _ => self.table.new_type_var(),
                 };
 
-                let len = match array {
+                match array {
                     Array::ElementList(items) => {
                         for expr in items.iter() {
                             self.infer_expr_coerce(*expr, &Expectation::has_type(elem_ty.clone()));
                         }
-                        Some(items.len())
                     }
                     Array::Repeat { initializer, repeat } => {
                         self.infer_expr_coerce(
@@ -737,20 +734,10 @@ impl<'a> InferenceContext<'a> {
                                 TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(&Interner),
                             ),
                         );
-                        // FIXME: support length for Repeat array expressions
-                        None
                     }
-                };
+                }
 
-                let cd = ConstData {
-                    ty: TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(&Interner),
-                    value: ConstValue::Concrete(chalk_ir::ConcreteConst {
-                        interned: len
-                            .map(|len| ConstScalar::Usize(len as u64))
-                            .unwrap_or(ConstScalar::Unknown),
-                    }),
-                };
-                TyKind::Array(elem_ty, cd.intern(&Interner)).intern(&Interner)
+                TyKind::Array(elem_ty, dummy_usize_const()).intern(&Interner)
             }
             Expr::Literal(lit) => match lit {
                 Literal::Bool(..) => TyKind::Scalar(Scalar::Bool).intern(&Interner),
@@ -760,7 +747,6 @@ impl<'a> InferenceContext<'a> {
                 }
                 Literal::ByteString(..) => {
                     let byte_type = TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(&Interner);
-
                     let array_type =
                         TyKind::Array(byte_type, dummy_usize_const()).intern(&Interner);
                     TyKind::Ref(Mutability::Not, static_lifetime(), array_type).intern(&Interner)
diff --git a/crates/hir_ty/src/interner.rs b/crates/hir_ty/src/interner.rs
index 4cbc9cd4fa..a1656115d6 100644
--- a/crates/hir_ty/src/interner.rs
+++ b/crates/hir_ty/src/interner.rs
@@ -1,7 +1,7 @@
 //! Implementation of the Chalk `Interner` trait, which allows customizing the
 //! representation of the various objects Chalk deals with (types, goals etc.).
 
-use crate::{chalk_db, consts::ConstScalar, tls, GenericArg};
+use crate::{chalk_db, tls, GenericArg};
 use base_db::salsa::InternId;
 use chalk_ir::{Goal, GoalData};
 use hir_def::{
@@ -31,7 +31,6 @@ impl_internable!(
     InternedWrapper<chalk_ir::TyData<Interner>>,
     InternedWrapper<chalk_ir::LifetimeData<Interner>>,
     InternedWrapper<chalk_ir::ConstData<Interner>>,
-    InternedWrapper<ConstScalar>,
     InternedWrapper<Vec<chalk_ir::CanonicalVarKind<Interner>>>,
     InternedWrapper<Vec<chalk_ir::ProgramClause<Interner>>>,
     InternedWrapper<Vec<chalk_ir::QuantifiedWhereClause<Interner>>>,
@@ -42,7 +41,7 @@ impl chalk_ir::interner::Interner for Interner {
     type InternedType = Interned<InternedWrapper<chalk_ir::TyData<Interner>>>;
     type InternedLifetime = Interned<InternedWrapper<chalk_ir::LifetimeData<Self>>>;
     type InternedConst = Interned<InternedWrapper<chalk_ir::ConstData<Self>>>;
-    type InternedConcreteConst = ConstScalar;
+    type InternedConcreteConst = ();
     type InternedGenericArg = chalk_ir::GenericArgData<Self>;
     type InternedGoal = Arc<GoalData<Self>>;
     type InternedGoals = Vec<Goal<Self>>;
@@ -246,15 +245,10 @@ impl chalk_ir::interner::Interner for Interner {
     fn const_eq(
         &self,
         _ty: &Self::InternedType,
-        c1: &Self::InternedConcreteConst,
-        c2: &Self::InternedConcreteConst,
+        _c1: &Self::InternedConcreteConst,
+        _c2: &Self::InternedConcreteConst,
     ) -> bool {
-        match (c1, c2) {
-            (&ConstScalar::Usize(a), &ConstScalar::Usize(b)) => a == b,
-            // we were previously assuming this to be true, I'm not whether true or false on
-            // unknown values is safer.
-            (_, _) => true,
-        }
+        true
     }
 
     fn intern_generic_arg(
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs
index d23eff513b..0505fa4aea 100644
--- a/crates/hir_ty/src/lib.rs
+++ b/crates/hir_ty/src/lib.rs
@@ -12,7 +12,6 @@ mod chalk_db;
 mod chalk_ext;
 mod infer;
 mod interner;
-mod consts;
 mod lower;
 mod mapping;
 mod op;
@@ -40,7 +39,7 @@ use chalk_ir::{
 };
 use hir_def::{expr::ExprId, type_ref::Rawness, TypeParamId};
 
-use crate::{consts::ConstScalar, db::HirDatabase, display::HirDisplay, utils::generics};
+use crate::{db::HirDatabase, display::HirDisplay, utils::generics};
 
 pub use autoderef::autoderef;
 pub use builder::TyBuilder;
@@ -251,9 +250,7 @@ pub fn dummy_usize_const() -> Const {
     let usize_ty = chalk_ir::TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(&Interner);
     chalk_ir::ConstData {
         ty: usize_ty,
-        value: chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst {
-            interned: ConstScalar::Unknown,
-        }),
+        value: chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst { interned: () }),
     }
     .intern(&Interner)
 }
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index 9751b45e46..c99dd8d0a4 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -174,8 +174,6 @@ impl<'a> TyLoweringContext<'a> {
             }
             TypeRef::Array(inner) => {
                 let inner_ty = self.lower_ty(inner);
-                // FIXME: we don't have length info here because we don't store an expression for
-                // the length
                 TyKind::Array(inner_ty, dummy_usize_const()).intern(&Interner)
             }
             TypeRef::Slice(inner) => {
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs
index 320694a17a..cb5a8e19a9 100644
--- a/crates/ide/src/doc_links.rs
+++ b/crates/ide/src/doc_links.rs
@@ -29,8 +29,7 @@ pub(crate) type DocumentationLink = String;
 /// Rewrite documentation links in markdown to point to an online host (e.g. docs.rs)
 pub(crate) fn rewrite_links(db: &RootDatabase, markdown: &str, definition: &Definition) -> String {
     let mut cb = broken_link_clone_cb;
-    let doc =
-        Parser::new_with_broken_link_callback(markdown, Options::ENABLE_TASKLISTS, Some(&mut cb));
+    let doc = Parser::new_with_broken_link_callback(markdown, Options::empty(), Some(&mut cb));
 
     let doc = map_links(doc, |target, title: &str| {
         // This check is imperfect, there's some overlap between valid intra-doc links
@@ -65,7 +64,8 @@ pub(crate) fn rewrite_links(db: &RootDatabase, markdown: &str, definition: &Defi
 pub(crate) fn remove_links(markdown: &str) -> String {
     let mut drop_link = false;
 
-    let opts = Options::ENABLE_TASKLISTS | Options::ENABLE_FOOTNOTES;
+    let mut opts = Options::empty();
+    opts.insert(Options::ENABLE_FOOTNOTES);
 
     let mut cb = |_: BrokenLink| {
         let empty = InlineStr::try_from("").unwrap();
@@ -123,7 +123,7 @@ pub(crate) fn extract_definitions_from_markdown(
 ) -> Vec<(TextRange, String, Option<hir::Namespace>)> {
     Parser::new_with_broken_link_callback(
         markdown,
-        Options::ENABLE_TASKLISTS,
+        Options::empty(),
         Some(&mut broken_link_clone_cb),
     )
     .into_offset_iter()
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index 960d169f48..e0bf660c40 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -1126,7 +1126,7 @@ fn main() {
             r#"
 fn main() {
     let data = &[1i32, 2, 3];
-      //^^^^ &[i32; 3]
+      //^^^^ &[i32; _]
     for i
 }"#,
         );
diff --git a/crates/ide_assists/src/handlers/auto_import.rs b/crates/ide_assists/src/handlers/auto_import.rs
index 506cc292c4..a454a2af32 100644
--- a/crates/ide_assists/src/handlers/auto_import.rs
+++ b/crates/ide_assists/src/handlers/auto_import.rs
@@ -966,32 +966,6 @@ mod bar {
         println!("Hallo");
     }
 }
-"#,
-        );
-    }
-
-    #[test]
-    fn uses_abs_path_with_extern_crate_clash() {
-        check_assist(
-            auto_import,
-            r#"
-//- /main.rs crate:main deps:foo
-mod foo {}
-
-const _: () = {
-    Foo$0
-};
-//- /foo.rs crate:foo
-pub struct Foo
-"#,
-            r#"
-use ::foo::Foo;
-
-mod foo {}
-
-const _: () = {
-    Foo
-};
 "#,
         );
     }
diff --git a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
index 8e21783919..66f274fa78 100644
--- a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -151,37 +151,20 @@ fn create_struct_def(
     field_list: &Either<ast::RecordFieldList, ast::TupleFieldList>,
     visibility: Option<ast::Visibility>,
 ) -> ast::Struct {
-    let pub_vis = make::visibility_pub();
-
-    let insert_pub = |node: &'_ SyntaxNode| {
-        let pub_vis = pub_vis.clone_for_update();
-        ted::insert(ted::Position::before(node), pub_vis.syntax());
-    };
-
-    // for fields without any existing visibility, use pub visibility
+    let pub_vis = Some(make::visibility_pub());
     let field_list = match field_list {
         Either::Left(field_list) => {
-            let field_list = field_list.clone_for_update();
-
-            field_list
-                .fields()
-                .filter(|field| field.visibility().is_none())
-                .filter_map(|field| field.name())
-                .for_each(|it| insert_pub(it.syntax()));
-
-            field_list.into()
+            make::record_field_list(field_list.fields().flat_map(|field| {
+                Some(make::record_field(pub_vis.clone(), field.name()?, field.ty()?))
+            }))
+            .into()
         }
-        Either::Right(field_list) => {
-            let field_list = field_list.clone_for_update();
-
+        Either::Right(field_list) => make::tuple_field_list(
             field_list
                 .fields()
-                .filter(|field| field.visibility().is_none())
-                .filter_map(|field| field.ty())
-                .for_each(|it| insert_pub(it.syntax()));
-
-            field_list.into()
-        }
+                .flat_map(|field| Some(make::tuple_field(pub_vis.clone(), field.ty()?))),
+        )
+        .into(),
     };
 
     make::struct_(visibility, variant_name, None, field_list).clone_for_update()
@@ -307,106 +290,6 @@ enum A { One(One) }"#,
             "enum A { $0One { foo: u32 } }",
             r#"struct One{ pub foo: u32 }
 
-enum A { One(One) }"#,
-        );
-    }
-
-    #[test]
-    fn test_extract_struct_keep_comments_and_attrs_one_field_named() {
-        check_assist(
-            extract_struct_from_enum_variant,
-            r#"
-enum A {
-    $0One {
-        // leading comment
-        /// doc comment
-        #[an_attr]
-        foo: u32
-        // trailing comment
-    }
-}"#,
-            r#"
-struct One{
-        // leading comment
-        /// doc comment
-        #[an_attr]
-        pub foo: u32
-        // trailing comment
-    }
-
-enum A {
-    One(One)
-}"#,
-        );
-    }
-
-    #[test]
-    fn test_extract_struct_keep_comments_and_attrs_several_fields_named() {
-        check_assist(
-            extract_struct_from_enum_variant,
-            r#"
-enum A {
-    $0One {
-        // comment
-        /// doc
-        #[attr]
-        foo: u32,
-        // comment
-        #[attr]
-        /// doc
-        bar: u32
-    }
-}"#,
-            r#"
-struct One{
-        // comment
-        /// doc
-        #[attr]
-        pub foo: u32,
-        // comment
-        #[attr]
-        /// doc
-        pub bar: u32
-    }
-
-enum A {
-    One(One)
-}"#,
-        );
-    }
-
-    #[test]
-    fn test_extract_struct_keep_comments_and_attrs_several_fields_tuple() {
-        check_assist(
-            extract_struct_from_enum_variant,
-            "enum A { $0One(/* comment */ #[attr] u32, /* another */ u32 /* tail */) }",
-            r#"
-struct One(/* comment */ #[attr] pub u32, /* another */ pub u32 /* tail */);
-
-enum A { One(One) }"#,
-        );
-    }
-
-    #[test]
-    fn test_extract_struct_keep_existing_visibility_named() {
-        check_assist(
-            extract_struct_from_enum_variant,
-            "enum A { $0One{ pub a: u32, pub(crate) b: u32, pub(super) c: u32, d: u32 } }",
-            r#"
-struct One{ pub a: u32, pub(crate) b: u32, pub(super) c: u32, pub d: u32 }
-
-enum A { One(One) }"#,
-        );
-    }
-
-    #[test]
-    fn test_extract_struct_keep_existing_visibility_tuple() {
-        check_assist(
-            extract_struct_from_enum_variant,
-            "enum A { $0One(pub u32, pub(crate) u32, pub(super) u32, u32) }",
-            r#"
-struct One(pub u32, pub(crate) u32, pub(super) u32, pub u32);
-
 enum A { One(One) }"#,
         );
     }
diff --git a/crates/ide_assists/src/handlers/move_module_to_file.rs b/crates/ide_assists/src/handlers/move_module_to_file.rs
index 93f702c556..6e685b4b29 100644
--- a/crates/ide_assists/src/handlers/move_module_to_file.rs
+++ b/crates/ide_assists/src/handlers/move_module_to_file.rs
@@ -1,4 +1,4 @@
-use ast::edit::IndentLevel;
+use ast::{edit::IndentLevel, VisibilityOwner};
 use ide_db::base_db::AnchoredPathBuf;
 use stdx::format_to;
 use syntax::{
@@ -60,18 +60,12 @@ pub(crate) fn move_module_to_file(acc: &mut Assists, ctx: &AssistContext) -> Opt
             };
 
             let mut buf = String::new();
+            if let Some(v) = module_ast.visibility() {
+                format_to!(buf, "{} ", v);
+            }
             format_to!(buf, "mod {};", module_name);
 
-            let replacement_start = if let Some(mod_token) = module_ast.mod_token() {
-                mod_token.text_range().start()
-            } else {
-                module_ast.syntax().text_range().start()
-            };
-
-            builder.replace(
-                TextRange::new(replacement_start, module_ast.syntax().text_range().end()),
-                buf,
-            );
+            builder.replace(module_ast.syntax().text_range(), buf);
 
             let dst = AnchoredPathBuf { anchor: ctx.frange.file_id, path };
             builder.create_file(dst, contents);
@@ -190,26 +184,4 @@ pub(crate) mod tests;
         cov_mark::check!(available_before_curly);
         check_assist_not_applicable(move_module_to_file, r#"mod m { $0 }"#);
     }
-
-    #[test]
-    fn keep_outer_comments_and_attributes() {
-        check_assist(
-            move_module_to_file,
-            r#"
-/// doc comment
-#[attribute]
-mod $0tests {
-    #[test] fn t() {}
-}
-"#,
-            r#"
-//- /main.rs
-/// doc comment
-#[attribute]
-mod tests;
-//- /tests.rs
-#[test] fn t() {}
-"#,
-        );
-    }
 }
diff --git a/crates/ide_assists/src/handlers/replace_unwrap_with_match.rs b/crates/ide_assists/src/handlers/replace_unwrap_with_match.rs
index a3bfa221c2..0fec961b43 100644
--- a/crates/ide_assists/src/handlers/replace_unwrap_with_match.rs
+++ b/crates/ide_assists/src/handlers/replace_unwrap_with_match.rs
@@ -17,7 +17,7 @@ use ide_db::ty_filter::TryEnum;
 
 // Assist: replace_unwrap_with_match
 //
-// Replaces `unwrap` with a `match` expression. Works for Result and Option.
+// Replaces `unwrap` a `match` expression. Works for Result and Option.
 //
 // ```
 // enum Result<T, E> { Ok(T), Err(E) }
diff --git a/crates/project_model/src/cargo_workspace.rs b/crates/project_model/src/cargo_workspace.rs
index 4a4996cf4d..b18699b771 100644
--- a/crates/project_model/src/cargo_workspace.rs
+++ b/crates/project_model/src/cargo_workspace.rs
@@ -119,32 +119,6 @@ pub struct RustAnalyzerPackageMetaData {
 pub struct PackageDependency {
     pub pkg: Package,
     pub name: String,
-    pub kind: DepKind,
-}
-
-#[derive(Debug, Clone, Eq, PartialEq)]
-pub enum DepKind {
-    /// Available to the library, binary, and dev targets in the package (but not the build script).
-    Normal,
-    /// Available only to test and bench targets (and the library target, when built with `cfg(test)`).
-    Dev,
-    /// Available only to the build script target.
-    Build,
-}
-
-impl DepKind {
-    fn new(list: &[cargo_metadata::DepKindInfo]) -> Self {
-        for info in list {
-            match info.kind {
-                cargo_metadata::DependencyKind::Normal => return Self::Normal,
-                cargo_metadata::DependencyKind::Development => return Self::Dev,
-                cargo_metadata::DependencyKind::Build => return Self::Build,
-                cargo_metadata::DependencyKind::Unknown => continue,
-            }
-        }
-
-        Self::Normal
-    }
 }
 
 /// Information associated with a package's target
@@ -170,7 +144,6 @@ pub enum TargetKind {
     Example,
     Test,
     Bench,
-    BuildScript,
     Other,
 }
 
@@ -182,7 +155,6 @@ impl TargetKind {
                 "test" => TargetKind::Test,
                 "bench" => TargetKind::Bench,
                 "example" => TargetKind::Example,
-                "custom-build" => TargetKind::BuildScript,
                 "proc-macro" => TargetKind::Lib,
                 _ if kind.contains("lib") => TargetKind::Lib,
                 _ => continue,
@@ -329,11 +301,7 @@ impl CargoWorkspace {
                         continue;
                     }
                 };
-                let dep = PackageDependency {
-                    name: dep_node.name,
-                    pkg,
-                    kind: DepKind::new(&dep_node.dep_kinds),
-                };
+                let dep = PackageDependency { name: dep_node.name, pkg };
                 packages[source].dependencies.push(dep);
             }
             packages[source].active_features.extend(node.features);
diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs
index 607e62ea59..761fbb3ab5 100644
--- a/crates/project_model/src/workspace.rs
+++ b/crates/project_model/src/workspace.rs
@@ -6,7 +6,6 @@ use std::{collections::VecDeque, fmt, fs, path::Path, process::Command};
 
 use anyhow::{Context, Result};
 use base_db::{CrateDisplayName, CrateGraph, CrateId, CrateName, Edition, Env, FileId, ProcMacro};
-use cargo_workspace::DepKind;
 use cfg::CfgOptions;
 use paths::{AbsPath, AbsPathBuf};
 use proc_macro_api::ProcMacroClient;
@@ -408,25 +407,23 @@ fn cargo_to_crate_graph(
                     }
                 }
 
-                pkg_crates.entry(pkg).or_insert_with(Vec::new).push((crate_id, cargo[tgt].kind));
+                pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id);
             }
         }
 
         // 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() {
+        for &from in pkg_crates.get(&pkg).into_iter().flatten() {
             if let Some((to, name)) = lib_tgt.clone() {
-                if to != *from && *kind != TargetKind::BuildScript {
-                    // (build script can not depend on its library target)
-
+                if to != from {
                     // For root projects with dashes in their name,
                     // cargo metadata does not do any normalization,
                     // so we do it ourselves currently
                     let name = CrateName::normalize_dashes(&name);
-                    add_dep(&mut crate_graph, *from, name, to);
+                    add_dep(&mut crate_graph, from, name, to);
                 }
             }
             for (name, krate) in public_deps.iter() {
-                add_dep(&mut crate_graph, *from, name.clone(), *krate);
+                add_dep(&mut crate_graph, from, name.clone(), *krate);
             }
         }
     }
@@ -437,17 +434,8 @@ fn cargo_to_crate_graph(
         for dep in cargo[pkg].dependencies.iter() {
             let name = CrateName::new(&dep.name).unwrap();
             if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) {
-                for (from, kind) in pkg_crates.get(&pkg).into_iter().flatten() {
-                    if dep.kind == DepKind::Build && *kind != TargetKind::BuildScript {
-                        // Only build scripts may depend on build dependencies.
-                        continue;
-                    }
-                    if dep.kind != DepKind::Build && *kind == TargetKind::BuildScript {
-                        // Build scripts may only depend on build dependencies.
-                        continue;
-                    }
-
-                    add_dep(&mut crate_graph, *from, name.clone(), to)
+                for &from in pkg_crates.get(&pkg).into_iter().flatten() {
+                    add_dep(&mut crate_graph, from, name.clone(), to)
                 }
             }
         }
@@ -484,7 +472,7 @@ fn handle_rustc_crates(
     pkg_to_lib_crate: &mut FxHashMap<la_arena::Idx<crate::PackageData>, CrateId>,
     public_deps: &[(CrateName, CrateId)],
     cargo: &CargoWorkspace,
-    pkg_crates: &FxHashMap<la_arena::Idx<crate::PackageData>, Vec<(CrateId, TargetKind)>>,
+    pkg_crates: &FxHashMap<la_arena::Idx<crate::PackageData>, Vec<CrateId>>,
 ) {
     let mut rustc_pkg_crates = FxHashMap::default();
     // The root package of the rustc-dev component is rustc_driver, so we match that
@@ -553,13 +541,13 @@ fn handle_rustc_crates(
                 if !package.metadata.rustc_private {
                     continue;
                 }
-                for (from, _) in pkg_crates.get(&pkg).into_iter().flatten() {
+                for &from in pkg_crates.get(&pkg).into_iter().flatten() {
                     // Avoid creating duplicate dependencies
                     // This avoids the situation where `from` depends on e.g. `arrayvec`, but
                     // `rust_analyzer` thinks that it should use the one from the `rustcSource`
                     // instead of the one from `crates.io`
-                    if !crate_graph[*from].dependencies.iter().any(|d| d.name == name) {
-                        add_dep(crate_graph, *from, name.clone(), to);
+                    if !crate_graph[from].dependencies.iter().any(|d| d.name == name) {
+                        add_dep(crate_graph, from, name.clone(), to);
                     }
                 }
             }
diff --git a/crates/rust-analyzer/src/cargo_target_spec.rs b/crates/rust-analyzer/src/cargo_target_spec.rs
index f4cd43448d..909c215322 100644
--- a/crates/rust-analyzer/src/cargo_target_spec.rs
+++ b/crates/rust-analyzer/src/cargo_target_spec.rs
@@ -159,7 +159,7 @@ impl CargoTargetSpec {
             TargetKind::Lib => {
                 buf.push("--lib".to_string());
             }
-            TargetKind::Other | TargetKind::BuildScript => (),
+            TargetKind::Other => (),
         }
     }
 }
diff --git a/crates/syntax/src/parsing.rs b/crates/syntax/src/parsing.rs
index 431ed06999..333bde54ab 100644
--- a/crates/syntax/src/parsing.rs
+++ b/crates/syntax/src/parsing.rs
@@ -6,13 +6,14 @@ mod text_token_source;
 mod text_tree_sink;
 mod reparsing;
 
-use parser::SyntaxKind;
+use crate::{syntax_node::GreenNode, AstNode, SyntaxError, SyntaxNode};
 use text_token_source::TextTokenSource;
 use text_tree_sink::TextTreeSink;
 
-use crate::{syntax_node::GreenNode, AstNode, SyntaxError, SyntaxNode};
+pub(crate) use lexer::*;
 
-pub(crate) use crate::parsing::{lexer::*, reparsing::incremental_reparse};
+pub(crate) use self::reparsing::incremental_reparse;
+use parser::SyntaxKind;
 
 pub(crate) fn parse_text(text: &str) -> (GreenNode, Vec<SyntaxError>) {
     let (tokens, lexer_errors) = tokenize(&text);
diff --git a/docs/dev/style.md b/docs/dev/style.md
index 9b0ddec662..d24a5952ed 100644
--- a/docs/dev/style.md
+++ b/docs/dev/style.md
@@ -636,10 +636,6 @@ use crate::{}
 
 // Finally, parent and child modules, but prefer `use crate::`.
 use super::{}
-
-// Re-exports are treated as item definitions rather than imports, so they go
-// after imports and modules. Use them sparingly.
-pub use crate::x::Z;
 ```
 
 **Rationale:** consistency.
@@ -698,9 +694,6 @@ Avoid local `use MyEnum::*` imports.
 Prefer `use crate::foo::bar` to `use super::bar` or `use self::bar::baz`.
 **Rationale:** consistency, this is the style which works in all cases.
 
-By default, avoid re-exports.
-**Rationale:** for non-library code, re-exports introduce two ways to use something and allow for inconsistency.
-
 ## Order of Items
 
 Optimize for the reader who sees the file for the first time, and wants to get a general idea about what's going on.


Test patch:
diff --git a/crates/hir_ty/src/tests/coercion.rs b/crates/hir_ty/src/tests/coercion.rs
index aad3d610e2..63d9d4e0b7 100644
--- a/crates/hir_ty/src/tests/coercion.rs
+++ b/crates/hir_ty/src/tests/coercion.rs
@@ -55,7 +55,7 @@ fn coerce_places() {
         impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
         impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
         "#,
-        expect![[r#"
+        expect![[r"
             30..31 '_': &[T]
             44..55 '{ loop {} }': T
             46..53 'loop {}': !
@@ -72,8 +72,8 @@ fn coerce_places() {
             165..170 'gen()': *mut [U; _]
             185..419 '{     ...rr); }': ()
             195..198 'arr': &[u8; _]
-            211..215 '&[1]': &[u8; 1]
-            212..215 '[1]': [u8; 1]
+            211..215 '&[1]': &[u8; _]
+            212..215 '[1]': [u8; _]
             213..214 '1': u8
             226..227 'a': &[u8]
             236..239 'arr': &[u8; _]
@@ -90,7 +90,7 @@ fn coerce_places() {
             302..314 'S { a: arr }': S<&[u8]>
             309..312 'arr': &[u8; _]
             325..326 'e': [&[u8]; _]
-            340..345 '[arr]': [&[u8]; 1]
+            340..345 '[arr]': [&[u8]; _]
             341..344 'arr': &[u8; _]
             355..356 'f': [&[u8]; _]
             370..378 '[arr; 2]': [&[u8]; _]
@@ -100,7 +100,7 @@ fn coerce_places() {
             406..416 '(arr, arr)': (&[u8], &[u8])
             407..410 'arr': &[u8; _]
             412..415 'arr': &[u8; _]
-        "#]],
+        "]],
     );
 }
 
@@ -113,17 +113,17 @@ fn infer_let_stmt_coerce() {
             let x: *const [isize] = &[1];
         }
         ",
-        expect![[r#"
+        expect![[r"
             10..75 '{     ...[1]; }': ()
             20..21 'x': &[isize]
-            34..38 '&[1]': &[isize; 1]
-            35..38 '[1]': [isize; 1]
+            34..38 '&[1]': &[isize; _]
+            35..38 '[1]': [isize; _]
             36..37 '1': isize
             48..49 'x': *const [isize]
-            68..72 '&[1]': &[isize; 1]
-            69..72 '[1]': [isize; 1]
+            68..72 '&[1]': &[isize; _]
+            69..72 '[1]': [isize; _]
             70..71 '1': isize
-        "#]],
+        "]],
     );
 }
 
@@ -208,7 +208,7 @@ fn infer_if_coerce() {
         #[lang = "unsize"]
         pub trait Unsize<T: ?Sized> {}
         "#,
-        expect![[r#"
+        expect![[r"
             10..11 'x': &[T]
             27..38 '{ loop {} }': &[T]
             29..36 'loop {}': !
@@ -220,14 +220,14 @@ fn infer_if_coerce() {
             71..96 '{     ...     }': &[i32]
             81..84 'foo': fn foo<i32>(&[i32]) -> &[i32]
             81..90 'foo(&[1])': &[i32]
-            85..89 '&[1]': &[i32; 1]
-            86..89 '[1]': [i32; 1]
+            85..89 '&[1]': &[i32; _]
+            86..89 '[1]': [i32; _]
             87..88 '1': i32
-            102..122 '{     ...     }': &[i32; 1]
-            112..116 '&[1]': &[i32; 1]
-            113..116 '[1]': [i32; 1]
+            102..122 '{     ...     }': &[i32; _]
+            112..116 '&[1]': &[i32; _]
+            113..116 '[1]': [i32; _]
             114..115 '1': i32
-        "#]],
+        "]],
     );
 }
 
@@ -254,7 +254,7 @@ fn infer_if_else_coerce() {
         impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
         impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
         "#,
-        expect![[r#"
+        expect![[r"
             10..11 'x': &[T]
             27..38 '{ loop {} }': &[T]
             29..36 'loop {}': !
@@ -263,17 +263,17 @@ fn infer_if_else_coerce() {
             59..60 'x': &[i32]
             63..122 'if tru...     }': &[i32]
             66..70 'true': bool
-            71..91 '{     ...     }': &[i32; 1]
-            81..85 '&[1]': &[i32; 1]
-            82..85 '[1]': [i32; 1]
+            71..91 '{     ...     }': &[i32; _]
+            81..85 '&[1]': &[i32; _]
+            82..85 '[1]': [i32; _]
             83..84 '1': i32
             97..122 '{     ...     }': &[i32]
             107..110 'foo': fn foo<i32>(&[i32]) -> &[i32]
             107..116 'foo(&[1])': &[i32]
-            111..115 '&[1]': &[i32; 1]
-            112..115 '[1]': [i32; 1]
+            111..115 '&[1]': &[i32; _]
+            112..115 '[1]': [i32; _]
             113..114 '1': i32
-        "#]],
+        "]],
     )
 }
 
@@ -295,7 +295,7 @@ fn infer_match_first_coerce() {
         #[lang = "unsize"]
         pub trait Unsize<T: ?Sized> {}
         "#,
-        expect![[r#"
+        expect![[r"
             10..11 'x': &[T]
             27..38 '{ loop {} }': &[T]
             29..36 'loop {}': !
@@ -309,19 +309,19 @@ fn infer_match_first_coerce() {
             87..88 '2': i32
             92..95 'foo': fn foo<i32>(&[i32]) -> &[i32]
             92..101 'foo(&[2])': &[i32]
-            96..100 '&[2]': &[i32; 1]
-            97..100 '[2]': [i32; 1]
+            96..100 '&[2]': &[i32; _]
+            97..100 '[2]': [i32; _]
             98..99 '2': i32
             111..112 '1': i32
             111..112 '1': i32
-            116..120 '&[1]': &[i32; 1]
-            117..120 '[1]': [i32; 1]
+            116..120 '&[1]': &[i32; _]
+            117..120 '[1]': [i32; _]
             118..119 '1': i32
             130..131 '_': i32
-            135..139 '&[3]': &[i32; 1]
-            136..139 '[3]': [i32; 1]
+            135..139 '&[3]': &[i32; _]
+            136..139 '[3]': [i32; _]
             137..138 '3': i32
-        "#]],
+    "]],
     );
 }
 
@@ -348,7 +348,7 @@ fn infer_match_second_coerce() {
         impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
         impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
         "#,
-        expect![[r#"
+        expect![[r"
             10..11 'x': &[T]
             27..38 '{ loop {} }': &[T]
             29..36 'loop {}': !
@@ -360,21 +360,21 @@ fn infer_match_second_coerce() {
             75..76 'i': i32
             87..88 '1': i32
             87..88 '1': i32
-            92..96 '&[1]': &[i32; 1]
-            93..96 '[1]': [i32; 1]
+            92..96 '&[1]': &[i32; _]
+            93..96 '[1]': [i32; _]
             94..95 '1': i32
             106..107 '2': i32
             106..107 '2': i32
             111..114 'foo': fn foo<i32>(&[i32]) -> &[i32]
             111..120 'foo(&[2])': &[i32]
-            115..119 '&[2]': &[i32; 1]
-            116..119 '[2]': [i32; 1]
+            115..119 '&[2]': &[i32; _]
+            116..119 '[2]': [i32; _]
             117..118 '2': i32
             130..131 '_': i32
-            135..139 '&[3]': &[i32; 1]
-            136..139 '[3]': [i32; 1]
+            135..139 '&[3]': &[i32; _]
+            136..139 '[3]': [i32; _]
             137..138 '3': i32
-        "#]],
+    "]],
     );
 }
 
@@ -685,15 +685,15 @@ fn coerce_unsize_array() {
             let f: &[usize] = &[1, 2, 3];
         }
         "#,
-        expect![[r#"
+        expect![[r"
             161..198 '{     ... 3]; }': ()
             171..172 'f': &[usize]
-            185..195 '&[1, 2, 3]': &[usize; 3]
-            186..195 '[1, 2, 3]': [usize; 3]
+            185..195 '&[1, 2, 3]': &[usize; _]
+            186..195 '[1, 2, 3]': [usize; _]
             187..188 '1': usize
             190..191 '2': usize
             193..194 '3': usize
-        "#]],
+        "]],
     );
 }
 
diff --git a/crates/hir_ty/src/tests/patterns.rs b/crates/hir_ty/src/tests/patterns.rs
index 33305f208f..f514b3efe6 100644
--- a/crates/hir_ty/src/tests/patterns.rs
+++ b/crates/hir_ty/src/tests/patterns.rs
@@ -243,8 +243,8 @@ fn infer_pattern_match_slice() {
         expect![[r#"
             10..209 '{     ...   } }': ()
             20..25 'slice': &[f64]
-            36..42 '&[0.0]': &[f64; 1]
-            37..42 '[0.0]': [f64; 1]
+            36..42 '&[0.0]': &[f64; _]
+            37..42 '[0.0]': [f64; _]
             38..41 '0.0': f64
             48..207 'match ...     }': ()
             54..59 'slice': &[f64]
@@ -346,7 +346,7 @@ fn infer_pattern_match_arr() {
         expect![[r#"
             10..179 '{     ...   } }': ()
             20..23 'arr': [f64; _]
-            36..46 '[0.0, 1.0]': [f64; 2]
+            36..46 '[0.0, 1.0]': [f64; _]
             37..40 '0.0': f64
             42..45 '1.0': f64
             52..177 'match ...     }': ()
diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs
index 4318617124..e23bd4da92 100644
--- a/crates/hir_ty/src/tests/regression.rs
+++ b/crates/hir_ty/src/tests/regression.rs
@@ -99,7 +99,7 @@ fn recursive_vars() {
             10..47 '{     ...&y]; }': ()
             20..21 'y': &{unknown}
             24..31 'unknown': &{unknown}
-            37..44 '[y, &y]': [&&{unknown}; 2]
+            37..44 '[y, &y]': [&&{unknown}; _]
             38..39 'y': &{unknown}
             41..43 '&y': &&{unknown}
             42..43 'y': &{unknown}
@@ -123,7 +123,7 @@ fn recursive_vars_2() {
             24..31 'unknown': &&{unknown}
             41..42 'y': &&{unknown}
             45..52 'unknown': &&{unknown}
-            58..76 '[(x, y..., &x)]': [(&&&{unknown}, &&&{unknown}); 2]
+            58..76 '[(x, y..., &x)]': [(&&&{unknown}, &&&{unknown}); _]
             59..65 '(x, y)': (&&&{unknown}, &&&{unknown})
             60..61 'x': &&{unknown}
             63..64 'y': &&{unknown}
@@ -175,8 +175,8 @@ fn infer_std_crash_2() {
         "#,
         expect![[r#"
             22..52 '{     ...n']; }': ()
-            28..49 '&[0, b...b'\n']': &[u8; 4]
-            29..49 '[0, b'...b'\n']': [u8; 4]
+            28..49 '&[0, b...b'\n']': &[u8; _]
+            29..49 '[0, b'...b'\n']': [u8; _]
             30..31 '0': u8
             33..38 'b'\n'': u8
             40..41 '1': u8
@@ -336,8 +336,8 @@ fn infer_array_macro_call() {
         expect![[r#"
             !0..4 '0u32': u32
             44..69 '{     ...()]; }': ()
-            54..55 'a': [u32; 1]
-            58..66 '[bar!()]': [u32; 1]
+            54..55 'a': [u32; _]
+            58..66 '[bar!()]': [u32; _]
         "#]],
     );
 }
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs
index 8b09f2e4a0..0eefd70f22 100644
--- a/crates/hir_ty/src/tests/simple.rs
+++ b/crates/hir_ty/src/tests/simple.rs
@@ -11,7 +11,7 @@ fn test() {
     let x = box 1;
     let t = (x, box x, box &1, box [1]);
     t;
-} //^ (Box<i32>, Box<Box<i32>>, Box<&i32>, Box<[i32; 1]>)
+} //^ (Box<i32>, Box<Box<i32>>, Box<&i32>, Box<[i32; _]>)
 
 //- /std.rs crate:std
 #[prelude_import] use prelude::*;
@@ -36,7 +36,7 @@ fn test() {
     let x = box 1;
     let t = (x, box x, box &1, box [1]);
     t;
-} //^ (Box<i32, {unknown}>, Box<Box<i32, {unknown}>, {unknown}>, Box<&i32, {unknown}>, Box<[i32; 1], {unknown}>)
+} //^ (Box<i32, {unknown}>, Box<Box<i32, {unknown}>, {unknown}>, Box<&i32, {unknown}>, Box<[i32; _], {unknown}>)
 
 //- /std.rs crate:std
 #[prelude_import] use prelude::*;
@@ -1266,55 +1266,55 @@ fn infer_array() {
             8..9 'x': &str
             17..18 'y': isize
             27..292 '{     ... []; }': ()
-            37..38 'a': [&str; 1]
-            41..44 '[x]': [&str; 1]
+            37..38 'a': [&str; _]
+            41..44 '[x]': [&str; _]
             42..43 'x': &str
-            54..55 'b': [[&str; 1]; 2]
-            58..64 '[a, a]': [[&str; 1]; 2]
-            59..60 'a': [&str; 1]
-            62..63 'a': [&str; 1]
-            74..75 'c': [[[&str; 1]; 2]; 2]
-            78..84 '[b, b]': [[[&str; 1]; 2]; 2]
-            79..80 'b': [[&str; 1]; 2]
-            82..83 'b': [[&str; 1]; 2]
-            95..96 'd': [isize; 4]
-            99..111 '[y, 1, 2, 3]': [isize; 4]
+            54..55 'b': [[&str; _]; _]
+            58..64 '[a, a]': [[&str; _]; _]
+            59..60 'a': [&str; _]
+            62..63 'a': [&str; _]
+            74..75 'c': [[[&str; _]; _]; _]
+            78..84 '[b, b]': [[[&str; _]; _]; _]
+            79..80 'b': [[&str; _]; _]
+            82..83 'b': [[&str; _]; _]
+            95..96 'd': [isize; _]
+            99..111 '[y, 1, 2, 3]': [isize; _]
             100..101 'y': isize
             103..104 '1': isize
             106..107 '2': isize
             109..110 '3': isize
-            121..122 'd': [isize; 4]
-            125..137 '[1, y, 2, 3]': [isize; 4]
+            121..122 'd': [isize; _]
+            125..137 '[1, y, 2, 3]': [isize; _]
             126..127 '1': isize
             129..130 'y': isize
             132..133 '2': isize
             135..136 '3': isize
-            147..148 'e': [isize; 1]
-            151..154 '[y]': [isize; 1]
+            147..148 'e': [isize; _]
+            151..154 '[y]': [isize; _]
             152..153 'y': isize
-            164..165 'f': [[isize; 4]; 2]
-            168..174 '[d, d]': [[isize; 4]; 2]
-            169..170 'd': [isize; 4]
-            172..173 'd': [isize; 4]
-            184..185 'g': [[isize; 1]; 2]
-            188..194 '[e, e]': [[isize; 1]; 2]
-            189..190 'e': [isize; 1]
-            192..193 'e': [isize; 1]
-            205..206 'h': [i32; 2]
-            209..215 '[1, 2]': [i32; 2]
+            164..165 'f': [[isize; _]; _]
+            168..174 '[d, d]': [[isize; _]; _]
+            169..170 'd': [isize; _]
+            172..173 'd': [isize; _]
+            184..185 'g': [[isize; _]; _]
+            188..194 '[e, e]': [[isize; _]; _]
+            189..190 'e': [isize; _]
+            192..193 'e': [isize; _]
+            205..206 'h': [i32; _]
+            209..215 '[1, 2]': [i32; _]
             210..211 '1': i32
             213..214 '2': i32
-            225..226 'i': [&str; 2]
-            229..239 '["a", "b"]': [&str; 2]
+            225..226 'i': [&str; _]
+            229..239 '["a", "b"]': [&str; _]
             230..233 '"a"': &str
             235..238 '"b"': &str
-            250..251 'b': [[&str; 1]; 2]
-            254..264 '[a, ["b"]]': [[&str; 1]; 2]
-            255..256 'a': [&str; 1]
-            258..263 '["b"]': [&str; 1]
+            250..251 'b': [[&str; _]; _]
+            254..264 '[a, ["b"]]': [[&str; _]; _]
+            255..256 'a': [&str; _]
+            258..263 '["b"]': [&str; _]
             259..262 '"b"': &str
             274..275 'x': [u8; _]
-            287..289 '[]': [u8; 0]
+            287..289 '[]': [u8; _]
         "#]],
     );
 }
@@ -2429,20 +2429,20 @@ fn infer_operator_overload() {
             394..395 '1': i32
             406..408 'V2': V2([f32; _]) -> V2
             406..416 'V2([x, y])': V2
-            409..415 '[x, y]': [f32; 2]
+            409..415 '[x, y]': [f32; _]
             410..411 'x': f32
             413..414 'y': f32
             436..519 '{     ... vb; }': ()
             446..448 'va': V2
             451..453 'V2': V2([f32; _]) -> V2
             451..465 'V2([0.0, 1.0])': V2
-            454..464 '[0.0, 1.0]': [f32; 2]
+            454..464 '[0.0, 1.0]': [f32; _]
             455..458 '0.0': f32
             460..463 '1.0': f32
             475..477 'vb': V2
             480..482 'V2': V2([f32; _]) -> V2
             480..494 'V2([0.0, 1.0])': V2
-            483..493 '[0.0, 1.0]': [f32; 2]
+            483..493 '[0.0, 1.0]': [f32; _]
             484..487 '0.0': f32
             489..492 '1.0': f32
             505..506 'r': V2
@@ -2593,8 +2593,8 @@ fn test() {
             658..661 'vec': Vec<i32, Global>
             664..679 '<[_]>::into_vec': fn into_vec<i32, Global>(Box<[i32], Global>) -> Vec<i32, Global>
             664..691 '<[_]>:...1i32])': Vec<i32, Global>
-            680..690 'box [1i32]': Box<[i32; 1], Global>
-            684..690 '[1i32]': [i32; 1]
+            680..690 'box [1i32]': Box<[i32; _], Global>
+            684..690 '[1i32]': [i32; _]
             685..689 '1i32': i32
         "#]],
     )
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs
index 47a1455fd0..ffc7c8ef4d 100644
--- a/crates/hir_ty/src/tests/traits.rs
+++ b/crates/hir_ty/src/tests/traits.rs
@@ -531,7 +531,7 @@ fn indexing_arrays() {
         expect![[r#"
             10..26 '{ &mut...[2]; }': ()
             12..23 '&mut [9][2]': &mut {unknown}
-            17..20 '[9]': [i32; 1]
+            17..20 '[9]': [i32; _]
             17..23 '[9][2]': {unknown}
             18..19 '9': i32
             21..22 '2': i32