aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/hir_def/src/find_path.rs13
-rw-r--r--crates/hir_ty/src/consts.rs21
-rw-r--r--crates/hir_ty/src/display.rs2
-rw-r--r--crates/hir_ty/src/infer/expr.rs26
-rw-r--r--crates/hir_ty/src/interner.rs16
-rw-r--r--crates/hir_ty/src/lib.rs7
-rw-r--r--crates/hir_ty/src/lower.rs2
-rw-r--r--crates/hir_ty/src/tests/coercion.rs90
-rw-r--r--crates/hir_ty/src/tests/patterns.rs6
-rw-r--r--crates/hir_ty/src/tests/regression.rs12
-rw-r--r--crates/hir_ty/src/tests/simple.rs80
-rw-r--r--crates/hir_ty/src/tests/traits.rs2
-rw-r--r--crates/ide/src/doc_links.rs8
-rw-r--r--crates/ide/src/inlay_hints.rs2
-rw-r--r--crates/ide_assists/src/handlers/auto_import.rs26
-rw-r--r--crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs135
-rw-r--r--crates/ide_assists/src/handlers/move_module_to_file.rs38
-rw-r--r--crates/ide_assists/src/handlers/replace_unwrap_with_match.rs2
18 files changed, 357 insertions, 131 deletions
diff --git a/crates/hir_def/src/find_path.rs b/crates/hir_def/src/find_path.rs
index 858e88038..ee52794aa 100644
--- a/crates/hir_def/src/find_path.rs
+++ b/crates/hir_def/src/find_path.rs
@@ -5,10 +5,10 @@ use std::iter;
5use hir_expand::name::{known, AsName, Name}; 5use hir_expand::name::{known, AsName, Name};
6use rustc_hash::FxHashSet; 6use rustc_hash::FxHashSet;
7 7
8use crate::nameres::DefMap;
9use crate::{ 8use crate::{
10 db::DefDatabase, 9 db::DefDatabase,
11 item_scope::ItemInNs, 10 item_scope::ItemInNs,
11 nameres::DefMap,
12 path::{ModPath, PathKind}, 12 path::{ModPath, PathKind},
13 visibility::Visibility, 13 visibility::Visibility,
14 ModuleDefId, ModuleId, 14 ModuleDefId, ModuleId,
@@ -134,7 +134,16 @@ fn find_path_inner(
134 for (name, def_id) in root_def_map.extern_prelude() { 134 for (name, def_id) in root_def_map.extern_prelude() {
135 if item == ItemInNs::Types(*def_id) { 135 if item == ItemInNs::Types(*def_id) {
136 let name = scope_name.unwrap_or_else(|| name.clone()); 136 let name = scope_name.unwrap_or_else(|| name.clone());
137 return Some(ModPath::from_segments(PathKind::Plain, vec![name])); 137
138 let name_already_occupied_in_type_ns = def_map
139 .with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| {
140 def_map[local_id].scope.get(&name).take_types().filter(|&id| id != *def_id)
141 })
142 .is_some();
143 return Some(ModPath::from_segments(
144 if name_already_occupied_in_type_ns { PathKind::Abs } else { PathKind::Plain },
145 vec![name],
146 ));
138 } 147 }
139 } 148 }
140 149
diff --git a/crates/hir_ty/src/consts.rs b/crates/hir_ty/src/consts.rs
new file mode 100644
index 000000000..0044b1cff
--- /dev/null
+++ b/crates/hir_ty/src/consts.rs
@@ -0,0 +1,21 @@
1//! Handling of concrete const values
2
3/// A concrete constant value
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
5pub enum ConstScalar {
6 // for now, we only support the trivial case of constant evaluating the length of an array
7 // Note that this is u64 because the target usize may be bigger than our usize
8 Usize(u64),
9
10 /// Case of an unknown value that rustc might know but we don't
11 Unknown,
12}
13
14impl std::fmt::Display for ConstScalar {
15 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
16 match self {
17 ConstScalar::Usize(us) => write!(fmt, "{}", us),
18 ConstScalar::Unknown => write!(fmt, "_"),
19 }
20 }
21}
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs
index 1f6edf7a2..8a4296697 100644
--- a/crates/hir_ty/src/display.rs
+++ b/crates/hir_ty/src/display.rs
@@ -308,7 +308,7 @@ impl HirDisplay for Const {
308 let param_data = &generics.params.consts[id.local_id]; 308 let param_data = &generics.params.consts[id.local_id];
309 write!(f, "{}", param_data.name) 309 write!(f, "{}", param_data.name)
310 } 310 }
311 ConstValue::Concrete(_) => write!(f, "_"), 311 ConstValue::Concrete(c) => write!(f, "{}", c.interned),
312 } 312 }
313 } 313 }
314} 314}
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index 9476e6297..2178ffd07 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -3,7 +3,7 @@
3use std::iter::{repeat, repeat_with}; 3use std::iter::{repeat, repeat_with};
4use std::{mem, sync::Arc}; 4use std::{mem, sync::Arc};
5 5
6use chalk_ir::{cast::Cast, fold::Shift, Mutability, TyVariableKind}; 6use chalk_ir::{cast::Cast, fold::Shift, ConstData, Mutability, TyVariableKind};
7use hir_def::{ 7use hir_def::{
8 expr::{Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp}, 8 expr::{Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp},
9 path::{GenericArg, GenericArgs}, 9 path::{GenericArg, GenericArgs},
@@ -15,7 +15,9 @@ use stdx::always;
15use syntax::ast::RangeOp; 15use syntax::ast::RangeOp;
16 16
17use crate::{ 17use crate::{
18 autoderef, dummy_usize_const, 18 autoderef,
19 consts::ConstScalar,
20 dummy_usize_const,
19 lower::lower_to_chalk_mutability, 21 lower::lower_to_chalk_mutability,
20 mapping::from_chalk, 22 mapping::from_chalk,
21 method_resolution, op, 23 method_resolution, op,
@@ -23,7 +25,7 @@ use crate::{
23 static_lifetime, to_chalk_trait_id, 25 static_lifetime, to_chalk_trait_id,
24 traits::FnTrait, 26 traits::FnTrait,
25 utils::{generics, Generics}, 27 utils::{generics, Generics},
26 AdtId, Binders, CallableDefId, FnPointer, FnSig, FnSubst, InEnvironment, Interner, 28 AdtId, Binders, CallableDefId, ConstValue, FnPointer, FnSig, FnSubst, InEnvironment, Interner,
27 ProjectionTyExt, Rawness, Scalar, Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind, 29 ProjectionTyExt, Rawness, Scalar, Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind,
28}; 30};
29 31
@@ -717,11 +719,12 @@ impl<'a> InferenceContext<'a> {
717 _ => self.table.new_type_var(), 719 _ => self.table.new_type_var(),
718 }; 720 };
719 721
720 match array { 722 let len = match array {
721 Array::ElementList(items) => { 723 Array::ElementList(items) => {
722 for expr in items.iter() { 724 for expr in items.iter() {
723 self.infer_expr_coerce(*expr, &Expectation::has_type(elem_ty.clone())); 725 self.infer_expr_coerce(*expr, &Expectation::has_type(elem_ty.clone()));
724 } 726 }
727 Some(items.len())
725 } 728 }
726 Array::Repeat { initializer, repeat } => { 729 Array::Repeat { initializer, repeat } => {
727 self.infer_expr_coerce( 730 self.infer_expr_coerce(
@@ -734,10 +737,20 @@ impl<'a> InferenceContext<'a> {
734 TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(&Interner), 737 TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(&Interner),
735 ), 738 ),
736 ); 739 );
740 // FIXME: support length for Repeat array expressions
741 None
737 } 742 }
738 } 743 };
739 744
740 TyKind::Array(elem_ty, dummy_usize_const()).intern(&Interner) 745 let cd = ConstData {
746 ty: TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(&Interner),
747 value: ConstValue::Concrete(chalk_ir::ConcreteConst {
748 interned: len
749 .map(|len| ConstScalar::Usize(len as u64))
750 .unwrap_or(ConstScalar::Unknown),
751 }),
752 };
753 TyKind::Array(elem_ty, cd.intern(&Interner)).intern(&Interner)
741 } 754 }
742 Expr::Literal(lit) => match lit { 755 Expr::Literal(lit) => match lit {
743 Literal::Bool(..) => TyKind::Scalar(Scalar::Bool).intern(&Interner), 756 Literal::Bool(..) => TyKind::Scalar(Scalar::Bool).intern(&Interner),
@@ -747,6 +760,7 @@ impl<'a> InferenceContext<'a> {
747 } 760 }
748 Literal::ByteString(..) => { 761 Literal::ByteString(..) => {
749 let byte_type = TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(&Interner); 762 let byte_type = TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(&Interner);
763
750 let array_type = 764 let array_type =
751 TyKind::Array(byte_type, dummy_usize_const()).intern(&Interner); 765 TyKind::Array(byte_type, dummy_usize_const()).intern(&Interner);
752 TyKind::Ref(Mutability::Not, static_lifetime(), array_type).intern(&Interner) 766 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 a1656115d..4cbc9cd4f 100644
--- a/crates/hir_ty/src/interner.rs
+++ b/crates/hir_ty/src/interner.rs
@@ -1,7 +1,7 @@
1//! Implementation of the Chalk `Interner` trait, which allows customizing the 1//! Implementation of the Chalk `Interner` trait, which allows customizing the
2//! representation of the various objects Chalk deals with (types, goals etc.). 2//! representation of the various objects Chalk deals with (types, goals etc.).
3 3
4use crate::{chalk_db, tls, GenericArg}; 4use crate::{chalk_db, consts::ConstScalar, tls, GenericArg};
5use base_db::salsa::InternId; 5use base_db::salsa::InternId;
6use chalk_ir::{Goal, GoalData}; 6use chalk_ir::{Goal, GoalData};
7use hir_def::{ 7use hir_def::{
@@ -31,6 +31,7 @@ impl_internable!(
31 InternedWrapper<chalk_ir::TyData<Interner>>, 31 InternedWrapper<chalk_ir::TyData<Interner>>,
32 InternedWrapper<chalk_ir::LifetimeData<Interner>>, 32 InternedWrapper<chalk_ir::LifetimeData<Interner>>,
33 InternedWrapper<chalk_ir::ConstData<Interner>>, 33 InternedWrapper<chalk_ir::ConstData<Interner>>,
34 InternedWrapper<ConstScalar>,
34 InternedWrapper<Vec<chalk_ir::CanonicalVarKind<Interner>>>, 35 InternedWrapper<Vec<chalk_ir::CanonicalVarKind<Interner>>>,
35 InternedWrapper<Vec<chalk_ir::ProgramClause<Interner>>>, 36 InternedWrapper<Vec<chalk_ir::ProgramClause<Interner>>>,
36 InternedWrapper<Vec<chalk_ir::QuantifiedWhereClause<Interner>>>, 37 InternedWrapper<Vec<chalk_ir::QuantifiedWhereClause<Interner>>>,
@@ -41,7 +42,7 @@ impl chalk_ir::interner::Interner for Interner {
41 type InternedType = Interned<InternedWrapper<chalk_ir::TyData<Interner>>>; 42 type InternedType = Interned<InternedWrapper<chalk_ir::TyData<Interner>>>;
42 type InternedLifetime = Interned<InternedWrapper<chalk_ir::LifetimeData<Self>>>; 43 type InternedLifetime = Interned<InternedWrapper<chalk_ir::LifetimeData<Self>>>;
43 type InternedConst = Interned<InternedWrapper<chalk_ir::ConstData<Self>>>; 44 type InternedConst = Interned<InternedWrapper<chalk_ir::ConstData<Self>>>;
44 type InternedConcreteConst = (); 45 type InternedConcreteConst = ConstScalar;
45 type InternedGenericArg = chalk_ir::GenericArgData<Self>; 46 type InternedGenericArg = chalk_ir::GenericArgData<Self>;
46 type InternedGoal = Arc<GoalData<Self>>; 47 type InternedGoal = Arc<GoalData<Self>>;
47 type InternedGoals = Vec<Goal<Self>>; 48 type InternedGoals = Vec<Goal<Self>>;
@@ -245,10 +246,15 @@ impl chalk_ir::interner::Interner for Interner {
245 fn const_eq( 246 fn const_eq(
246 &self, 247 &self,
247 _ty: &Self::InternedType, 248 _ty: &Self::InternedType,
248 _c1: &Self::InternedConcreteConst, 249 c1: &Self::InternedConcreteConst,
249 _c2: &Self::InternedConcreteConst, 250 c2: &Self::InternedConcreteConst,
250 ) -> bool { 251 ) -> bool {
251 true 252 match (c1, c2) {
253 (&ConstScalar::Usize(a), &ConstScalar::Usize(b)) => a == b,
254 // we were previously assuming this to be true, I'm not whether true or false on
255 // unknown values is safer.
256 (_, _) => true,
257 }
252 } 258 }
253 259
254 fn intern_generic_arg( 260 fn intern_generic_arg(
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs
index 0505fa4ae..d23eff513 100644
--- a/crates/hir_ty/src/lib.rs
+++ b/crates/hir_ty/src/lib.rs
@@ -12,6 +12,7 @@ mod chalk_db;
12mod chalk_ext; 12mod chalk_ext;
13mod infer; 13mod infer;
14mod interner; 14mod interner;
15mod consts;
15mod lower; 16mod lower;
16mod mapping; 17mod mapping;
17mod op; 18mod op;
@@ -39,7 +40,7 @@ use chalk_ir::{
39}; 40};
40use hir_def::{expr::ExprId, type_ref::Rawness, TypeParamId}; 41use hir_def::{expr::ExprId, type_ref::Rawness, TypeParamId};
41 42
42use crate::{db::HirDatabase, display::HirDisplay, utils::generics}; 43use crate::{consts::ConstScalar, db::HirDatabase, display::HirDisplay, utils::generics};
43 44
44pub use autoderef::autoderef; 45pub use autoderef::autoderef;
45pub use builder::TyBuilder; 46pub use builder::TyBuilder;
@@ -250,7 +251,9 @@ pub fn dummy_usize_const() -> Const {
250 let usize_ty = chalk_ir::TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(&Interner); 251 let usize_ty = chalk_ir::TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(&Interner);
251 chalk_ir::ConstData { 252 chalk_ir::ConstData {
252 ty: usize_ty, 253 ty: usize_ty,
253 value: chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst { interned: () }), 254 value: chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst {
255 interned: ConstScalar::Unknown,
256 }),
254 } 257 }
255 .intern(&Interner) 258 .intern(&Interner)
256} 259}
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index c99dd8d0a..9751b45e4 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -174,6 +174,8 @@ impl<'a> TyLoweringContext<'a> {
174 } 174 }
175 TypeRef::Array(inner) => { 175 TypeRef::Array(inner) => {
176 let inner_ty = self.lower_ty(inner); 176 let inner_ty = self.lower_ty(inner);
177 // FIXME: we don't have length info here because we don't store an expression for
178 // the length
177 TyKind::Array(inner_ty, dummy_usize_const()).intern(&Interner) 179 TyKind::Array(inner_ty, dummy_usize_const()).intern(&Interner)
178 } 180 }
179 TypeRef::Slice(inner) => { 181 TypeRef::Slice(inner) => {
diff --git a/crates/hir_ty/src/tests/coercion.rs b/crates/hir_ty/src/tests/coercion.rs
index 63d9d4e0b..aad3d610e 100644
--- a/crates/hir_ty/src/tests/coercion.rs
+++ b/crates/hir_ty/src/tests/coercion.rs
@@ -55,7 +55,7 @@ fn coerce_places() {
55 impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} 55 impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
56 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} 56 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
57 "#, 57 "#,
58 expect![[r" 58 expect![[r#"
59 30..31 '_': &[T] 59 30..31 '_': &[T]
60 44..55 '{ loop {} }': T 60 44..55 '{ loop {} }': T
61 46..53 'loop {}': ! 61 46..53 'loop {}': !
@@ -72,8 +72,8 @@ fn coerce_places() {
72 165..170 'gen()': *mut [U; _] 72 165..170 'gen()': *mut [U; _]
73 185..419 '{ ...rr); }': () 73 185..419 '{ ...rr); }': ()
74 195..198 'arr': &[u8; _] 74 195..198 'arr': &[u8; _]
75 211..215 '&[1]': &[u8; _] 75 211..215 '&[1]': &[u8; 1]
76 212..215 '[1]': [u8; _] 76 212..215 '[1]': [u8; 1]
77 213..214 '1': u8 77 213..214 '1': u8
78 226..227 'a': &[u8] 78 226..227 'a': &[u8]
79 236..239 'arr': &[u8; _] 79 236..239 'arr': &[u8; _]
@@ -90,7 +90,7 @@ fn coerce_places() {
90 302..314 'S { a: arr }': S<&[u8]> 90 302..314 'S { a: arr }': S<&[u8]>
91 309..312 'arr': &[u8; _] 91 309..312 'arr': &[u8; _]
92 325..326 'e': [&[u8]; _] 92 325..326 'e': [&[u8]; _]
93 340..345 '[arr]': [&[u8]; _] 93 340..345 '[arr]': [&[u8]; 1]
94 341..344 'arr': &[u8; _] 94 341..344 'arr': &[u8; _]
95 355..356 'f': [&[u8]; _] 95 355..356 'f': [&[u8]; _]
96 370..378 '[arr; 2]': [&[u8]; _] 96 370..378 '[arr; 2]': [&[u8]; _]
@@ -100,7 +100,7 @@ fn coerce_places() {
100 406..416 '(arr, arr)': (&[u8], &[u8]) 100 406..416 '(arr, arr)': (&[u8], &[u8])
101 407..410 'arr': &[u8; _] 101 407..410 'arr': &[u8; _]
102 412..415 'arr': &[u8; _] 102 412..415 'arr': &[u8; _]
103 "]], 103 "#]],
104 ); 104 );
105} 105}
106 106
@@ -113,17 +113,17 @@ fn infer_let_stmt_coerce() {
113 let x: *const [isize] = &[1]; 113 let x: *const [isize] = &[1];
114 } 114 }
115 ", 115 ",
116 expect![[r" 116 expect![[r#"
117 10..75 '{ ...[1]; }': () 117 10..75 '{ ...[1]; }': ()
118 20..21 'x': &[isize] 118 20..21 'x': &[isize]
119 34..38 '&[1]': &[isize; _] 119 34..38 '&[1]': &[isize; 1]
120 35..38 '[1]': [isize; _] 120 35..38 '[1]': [isize; 1]
121 36..37 '1': isize 121 36..37 '1': isize
122 48..49 'x': *const [isize] 122 48..49 'x': *const [isize]
123 68..72 '&[1]': &[isize; _] 123 68..72 '&[1]': &[isize; 1]
124 69..72 '[1]': [isize; _] 124 69..72 '[1]': [isize; 1]
125 70..71 '1': isize 125 70..71 '1': isize
126 "]], 126 "#]],
127 ); 127 );
128} 128}
129 129
@@ -208,7 +208,7 @@ fn infer_if_coerce() {
208 #[lang = "unsize"] 208 #[lang = "unsize"]
209 pub trait Unsize<T: ?Sized> {} 209 pub trait Unsize<T: ?Sized> {}
210 "#, 210 "#,
211 expect![[r" 211 expect![[r#"
212 10..11 'x': &[T] 212 10..11 'x': &[T]
213 27..38 '{ loop {} }': &[T] 213 27..38 '{ loop {} }': &[T]
214 29..36 'loop {}': ! 214 29..36 'loop {}': !
@@ -220,14 +220,14 @@ fn infer_if_coerce() {
220 71..96 '{ ... }': &[i32] 220 71..96 '{ ... }': &[i32]
221 81..84 'foo': fn foo<i32>(&[i32]) -> &[i32] 221 81..84 'foo': fn foo<i32>(&[i32]) -> &[i32]
222 81..90 'foo(&[1])': &[i32] 222 81..90 'foo(&[1])': &[i32]
223 85..89 '&[1]': &[i32; _] 223 85..89 '&[1]': &[i32; 1]
224 86..89 '[1]': [i32; _] 224 86..89 '[1]': [i32; 1]
225 87..88 '1': i32 225 87..88 '1': i32
226 102..122 '{ ... }': &[i32; _] 226 102..122 '{ ... }': &[i32; 1]
227 112..116 '&[1]': &[i32; _] 227 112..116 '&[1]': &[i32; 1]
228 113..116 '[1]': [i32; _] 228 113..116 '[1]': [i32; 1]
229 114..115 '1': i32 229 114..115 '1': i32
230 "]], 230 "#]],
231 ); 231 );
232} 232}
233 233
@@ -254,7 +254,7 @@ fn infer_if_else_coerce() {
254 impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} 254 impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
255 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} 255 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
256 "#, 256 "#,
257 expect![[r" 257 expect![[r#"
258 10..11 'x': &[T] 258 10..11 'x': &[T]
259 27..38 '{ loop {} }': &[T] 259 27..38 '{ loop {} }': &[T]
260 29..36 'loop {}': ! 260 29..36 'loop {}': !
@@ -263,17 +263,17 @@ fn infer_if_else_coerce() {
263 59..60 'x': &[i32] 263 59..60 'x': &[i32]
264 63..122 'if tru... }': &[i32] 264 63..122 'if tru... }': &[i32]
265 66..70 'true': bool 265 66..70 'true': bool
266 71..91 '{ ... }': &[i32; _] 266 71..91 '{ ... }': &[i32; 1]
267 81..85 '&[1]': &[i32; _] 267 81..85 '&[1]': &[i32; 1]
268 82..85 '[1]': [i32; _] 268 82..85 '[1]': [i32; 1]
269 83..84 '1': i32 269 83..84 '1': i32
270 97..122 '{ ... }': &[i32] 270 97..122 '{ ... }': &[i32]
271 107..110 'foo': fn foo<i32>(&[i32]) -> &[i32] 271 107..110 'foo': fn foo<i32>(&[i32]) -> &[i32]
272 107..116 'foo(&[1])': &[i32] 272 107..116 'foo(&[1])': &[i32]
273 111..115 '&[1]': &[i32; _] 273 111..115 '&[1]': &[i32; 1]
274 112..115 '[1]': [i32; _] 274 112..115 '[1]': [i32; 1]
275 113..114 '1': i32 275 113..114 '1': i32
276 "]], 276 "#]],
277 ) 277 )
278} 278}
279 279
@@ -295,7 +295,7 @@ fn infer_match_first_coerce() {
295 #[lang = "unsize"] 295 #[lang = "unsize"]
296 pub trait Unsize<T: ?Sized> {} 296 pub trait Unsize<T: ?Sized> {}
297 "#, 297 "#,
298 expect![[r" 298 expect![[r#"
299 10..11 'x': &[T] 299 10..11 'x': &[T]
300 27..38 '{ loop {} }': &[T] 300 27..38 '{ loop {} }': &[T]
301 29..36 'loop {}': ! 301 29..36 'loop {}': !
@@ -309,19 +309,19 @@ fn infer_match_first_coerce() {
309 87..88 '2': i32 309 87..88 '2': i32
310 92..95 'foo': fn foo<i32>(&[i32]) -> &[i32] 310 92..95 'foo': fn foo<i32>(&[i32]) -> &[i32]
311 92..101 'foo(&[2])': &[i32] 311 92..101 'foo(&[2])': &[i32]
312 96..100 '&[2]': &[i32; _] 312 96..100 '&[2]': &[i32; 1]
313 97..100 '[2]': [i32; _] 313 97..100 '[2]': [i32; 1]
314 98..99 '2': i32 314 98..99 '2': i32
315 111..112 '1': i32 315 111..112 '1': i32
316 111..112 '1': i32 316 111..112 '1': i32
317 116..120 '&[1]': &[i32; _] 317 116..120 '&[1]': &[i32; 1]
318 117..120 '[1]': [i32; _] 318 117..120 '[1]': [i32; 1]
319 118..119 '1': i32 319 118..119 '1': i32
320 130..131 '_': i32 320 130..131 '_': i32
321 135..139 '&[3]': &[i32; _] 321 135..139 '&[3]': &[i32; 1]
322 136..139 '[3]': [i32; _] 322 136..139 '[3]': [i32; 1]
323 137..138 '3': i32 323 137..138 '3': i32
324 "]], 324 "#]],
325 ); 325 );
326} 326}
327 327
@@ -348,7 +348,7 @@ fn infer_match_second_coerce() {
348 impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} 348 impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
349 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} 349 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
350 "#, 350 "#,
351 expect![[r" 351 expect![[r#"
352 10..11 'x': &[T] 352 10..11 'x': &[T]
353 27..38 '{ loop {} }': &[T] 353 27..38 '{ loop {} }': &[T]
354 29..36 'loop {}': ! 354 29..36 'loop {}': !
@@ -360,21 +360,21 @@ fn infer_match_second_coerce() {
360 75..76 'i': i32 360 75..76 'i': i32
361 87..88 '1': i32 361 87..88 '1': i32
362 87..88 '1': i32 362 87..88 '1': i32
363 92..96 '&[1]': &[i32; _] 363 92..96 '&[1]': &[i32; 1]
364 93..96 '[1]': [i32; _] 364 93..96 '[1]': [i32; 1]
365 94..95 '1': i32 365 94..95 '1': i32
366 106..107 '2': i32 366 106..107 '2': i32
367 106..107 '2': i32 367 106..107 '2': i32
368 111..114 'foo': fn foo<i32>(&[i32]) -> &[i32] 368 111..114 'foo': fn foo<i32>(&[i32]) -> &[i32]
369 111..120 'foo(&[2])': &[i32] 369 111..120 'foo(&[2])': &[i32]
370 115..119 '&[2]': &[i32; _] 370 115..119 '&[2]': &[i32; 1]
371 116..119 '[2]': [i32; _] 371 116..119 '[2]': [i32; 1]
372 117..118 '2': i32 372 117..118 '2': i32
373 130..131 '_': i32 373 130..131 '_': i32
374 135..139 '&[3]': &[i32; _] 374 135..139 '&[3]': &[i32; 1]
375 136..139 '[3]': [i32; _] 375 136..139 '[3]': [i32; 1]
376 137..138 '3': i32 376 137..138 '3': i32
377 "]], 377 "#]],
378 ); 378 );
379} 379}
380 380
@@ -685,15 +685,15 @@ fn coerce_unsize_array() {
685 let f: &[usize] = &[1, 2, 3]; 685 let f: &[usize] = &[1, 2, 3];
686 } 686 }
687 "#, 687 "#,
688 expect![[r" 688 expect![[r#"
689 161..198 '{ ... 3]; }': () 689 161..198 '{ ... 3]; }': ()
690 171..172 'f': &[usize] 690 171..172 'f': &[usize]
691 185..195 '&[1, 2, 3]': &[usize; _] 691 185..195 '&[1, 2, 3]': &[usize; 3]
692 186..195 '[1, 2, 3]': [usize; _] 692 186..195 '[1, 2, 3]': [usize; 3]
693 187..188 '1': usize 693 187..188 '1': usize
694 190..191 '2': usize 694 190..191 '2': usize
695 193..194 '3': usize 695 193..194 '3': usize
696 "]], 696 "#]],
697 ); 697 );
698} 698}
699 699
diff --git a/crates/hir_ty/src/tests/patterns.rs b/crates/hir_ty/src/tests/patterns.rs
index f514b3efe..33305f208 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() {
243 expect![[r#" 243 expect![[r#"
244 10..209 '{ ... } }': () 244 10..209 '{ ... } }': ()
245 20..25 'slice': &[f64] 245 20..25 'slice': &[f64]
246 36..42 '&[0.0]': &[f64; _] 246 36..42 '&[0.0]': &[f64; 1]
247 37..42 '[0.0]': [f64; _] 247 37..42 '[0.0]': [f64; 1]
248 38..41 '0.0': f64 248 38..41 '0.0': f64
249 48..207 'match ... }': () 249 48..207 'match ... }': ()
250 54..59 'slice': &[f64] 250 54..59 'slice': &[f64]
@@ -346,7 +346,7 @@ fn infer_pattern_match_arr() {
346 expect![[r#" 346 expect![[r#"
347 10..179 '{ ... } }': () 347 10..179 '{ ... } }': ()
348 20..23 'arr': [f64; _] 348 20..23 'arr': [f64; _]
349 36..46 '[0.0, 1.0]': [f64; _] 349 36..46 '[0.0, 1.0]': [f64; 2]
350 37..40 '0.0': f64 350 37..40 '0.0': f64
351 42..45 '1.0': f64 351 42..45 '1.0': f64
352 52..177 'match ... }': () 352 52..177 'match ... }': ()
diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs
index e23bd4da9..431861712 100644
--- a/crates/hir_ty/src/tests/regression.rs
+++ b/crates/hir_ty/src/tests/regression.rs
@@ -99,7 +99,7 @@ fn recursive_vars() {
99 10..47 '{ ...&y]; }': () 99 10..47 '{ ...&y]; }': ()
100 20..21 'y': &{unknown} 100 20..21 'y': &{unknown}
101 24..31 'unknown': &{unknown} 101 24..31 'unknown': &{unknown}
102 37..44 '[y, &y]': [&&{unknown}; _] 102 37..44 '[y, &y]': [&&{unknown}; 2]
103 38..39 'y': &{unknown} 103 38..39 'y': &{unknown}
104 41..43 '&y': &&{unknown} 104 41..43 '&y': &&{unknown}
105 42..43 'y': &{unknown} 105 42..43 'y': &{unknown}
@@ -123,7 +123,7 @@ fn recursive_vars_2() {
123 24..31 'unknown': &&{unknown} 123 24..31 'unknown': &&{unknown}
124 41..42 'y': &&{unknown} 124 41..42 'y': &&{unknown}
125 45..52 'unknown': &&{unknown} 125 45..52 'unknown': &&{unknown}
126 58..76 '[(x, y..., &x)]': [(&&&{unknown}, &&&{unknown}); _] 126 58..76 '[(x, y..., &x)]': [(&&&{unknown}, &&&{unknown}); 2]
127 59..65 '(x, y)': (&&&{unknown}, &&&{unknown}) 127 59..65 '(x, y)': (&&&{unknown}, &&&{unknown})
128 60..61 'x': &&{unknown} 128 60..61 'x': &&{unknown}
129 63..64 'y': &&{unknown} 129 63..64 'y': &&{unknown}
@@ -175,8 +175,8 @@ fn infer_std_crash_2() {
175 "#, 175 "#,
176 expect![[r#" 176 expect![[r#"
177 22..52 '{ ...n']; }': () 177 22..52 '{ ...n']; }': ()
178 28..49 '&[0, b...b'\n']': &[u8; _] 178 28..49 '&[0, b...b'\n']': &[u8; 4]
179 29..49 '[0, b'...b'\n']': [u8; _] 179 29..49 '[0, b'...b'\n']': [u8; 4]
180 30..31 '0': u8 180 30..31 '0': u8
181 33..38 'b'\n'': u8 181 33..38 'b'\n'': u8
182 40..41 '1': u8 182 40..41 '1': u8
@@ -336,8 +336,8 @@ fn infer_array_macro_call() {
336 expect![[r#" 336 expect![[r#"
337 !0..4 '0u32': u32 337 !0..4 '0u32': u32
338 44..69 '{ ...()]; }': () 338 44..69 '{ ...()]; }': ()
339 54..55 'a': [u32; _] 339 54..55 'a': [u32; 1]
340 58..66 '[bar!()]': [u32; _] 340 58..66 '[bar!()]': [u32; 1]
341 "#]], 341 "#]],
342 ); 342 );
343} 343}
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs
index 0eefd70f2..8b09f2e4a 100644
--- a/crates/hir_ty/src/tests/simple.rs
+++ b/crates/hir_ty/src/tests/simple.rs
@@ -11,7 +11,7 @@ fn test() {
11 let x = box 1; 11 let x = box 1;
12 let t = (x, box x, box &1, box [1]); 12 let t = (x, box x, box &1, box [1]);
13 t; 13 t;
14} //^ (Box<i32>, Box<Box<i32>>, Box<&i32>, Box<[i32; _]>) 14} //^ (Box<i32>, Box<Box<i32>>, Box<&i32>, Box<[i32; 1]>)
15 15
16//- /std.rs crate:std 16//- /std.rs crate:std
17#[prelude_import] use prelude::*; 17#[prelude_import] use prelude::*;
@@ -36,7 +36,7 @@ fn test() {
36 let x = box 1; 36 let x = box 1;
37 let t = (x, box x, box &1, box [1]); 37 let t = (x, box x, box &1, box [1]);
38 t; 38 t;
39} //^ (Box<i32, {unknown}>, Box<Box<i32, {unknown}>, {unknown}>, Box<&i32, {unknown}>, Box<[i32; _], {unknown}>) 39} //^ (Box<i32, {unknown}>, Box<Box<i32, {unknown}>, {unknown}>, Box<&i32, {unknown}>, Box<[i32; 1], {unknown}>)
40 40
41//- /std.rs crate:std 41//- /std.rs crate:std
42#[prelude_import] use prelude::*; 42#[prelude_import] use prelude::*;
@@ -1266,55 +1266,55 @@ fn infer_array() {
1266 8..9 'x': &str 1266 8..9 'x': &str
1267 17..18 'y': isize 1267 17..18 'y': isize
1268 27..292 '{ ... []; }': () 1268 27..292 '{ ... []; }': ()
1269 37..38 'a': [&str; _] 1269 37..38 'a': [&str; 1]
1270 41..44 '[x]': [&str; _] 1270 41..44 '[x]': [&str; 1]
1271 42..43 'x': &str 1271 42..43 'x': &str
1272 54..55 'b': [[&str; _]; _] 1272 54..55 'b': [[&str; 1]; 2]
1273 58..64 '[a, a]': [[&str; _]; _] 1273 58..64 '[a, a]': [[&str; 1]; 2]
1274 59..60 'a': [&str; _] 1274 59..60 'a': [&str; 1]
1275 62..63 'a': [&str; _] 1275 62..63 'a': [&str; 1]
1276 74..75 'c': [[[&str; _]; _]; _] 1276 74..75 'c': [[[&str; 1]; 2]; 2]
1277 78..84 '[b, b]': [[[&str; _]; _]; _] 1277 78..84 '[b, b]': [[[&str; 1]; 2]; 2]
1278 79..80 'b': [[&str; _]; _] 1278 79..80 'b': [[&str; 1]; 2]
1279 82..83 'b': [[&str; _]; _] 1279 82..83 'b': [[&str; 1]; 2]
1280 95..96 'd': [isize; _] 1280 95..96 'd': [isize; 4]
1281 99..111 '[y, 1, 2, 3]': [isize; _] 1281 99..111 '[y, 1, 2, 3]': [isize; 4]
1282 100..101 'y': isize 1282 100..101 'y': isize
1283 103..104 '1': isize 1283 103..104 '1': isize
1284 106..107 '2': isize 1284 106..107 '2': isize
1285 109..110 '3': isize 1285 109..110 '3': isize
1286 121..122 'd': [isize; _] 1286 121..122 'd': [isize; 4]
1287 125..137 '[1, y, 2, 3]': [isize; _] 1287 125..137 '[1, y, 2, 3]': [isize; 4]
1288 126..127 '1': isize 1288 126..127 '1': isize
1289 129..130 'y': isize 1289 129..130 'y': isize
1290 132..133 '2': isize 1290 132..133 '2': isize
1291 135..136 '3': isize 1291 135..136 '3': isize
1292 147..148 'e': [isize; _] 1292 147..148 'e': [isize; 1]
1293 151..154 '[y]': [isize; _] 1293 151..154 '[y]': [isize; 1]
1294 152..153 'y': isize 1294 152..153 'y': isize
1295 164..165 'f': [[isize; _]; _] 1295 164..165 'f': [[isize; 4]; 2]
1296 168..174 '[d, d]': [[isize; _]; _] 1296 168..174 '[d, d]': [[isize; 4]; 2]
1297 169..170 'd': [isize; _] 1297 169..170 'd': [isize; 4]
1298 172..173 'd': [isize; _] 1298 172..173 'd': [isize; 4]
1299 184..185 'g': [[isize; _]; _] 1299 184..185 'g': [[isize; 1]; 2]
1300 188..194 '[e, e]': [[isize; _]; _] 1300 188..194 '[e, e]': [[isize; 1]; 2]
1301 189..190 'e': [isize; _] 1301 189..190 'e': [isize; 1]
1302 192..193 'e': [isize; _] 1302 192..193 'e': [isize; 1]
1303 205..206 'h': [i32; _] 1303 205..206 'h': [i32; 2]
1304 209..215 '[1, 2]': [i32; _] 1304 209..215 '[1, 2]': [i32; 2]
1305 210..211 '1': i32 1305 210..211 '1': i32
1306 213..214 '2': i32 1306 213..214 '2': i32
1307 225..226 'i': [&str; _] 1307 225..226 'i': [&str; 2]
1308 229..239 '["a", "b"]': [&str; _] 1308 229..239 '["a", "b"]': [&str; 2]
1309 230..233 '"a"': &str 1309 230..233 '"a"': &str
1310 235..238 '"b"': &str 1310 235..238 '"b"': &str
1311 250..251 'b': [[&str; _]; _] 1311 250..251 'b': [[&str; 1]; 2]
1312 254..264 '[a, ["b"]]': [[&str; _]; _] 1312 254..264 '[a, ["b"]]': [[&str; 1]; 2]
1313 255..256 'a': [&str; _] 1313 255..256 'a': [&str; 1]
1314 258..263 '["b"]': [&str; _] 1314 258..263 '["b"]': [&str; 1]
1315 259..262 '"b"': &str 1315 259..262 '"b"': &str
1316 274..275 'x': [u8; _] 1316 274..275 'x': [u8; _]
1317 287..289 '[]': [u8; _] 1317 287..289 '[]': [u8; 0]
1318 "#]], 1318 "#]],
1319 ); 1319 );
1320} 1320}
@@ -2429,20 +2429,20 @@ fn infer_operator_overload() {
2429 394..395 '1': i32 2429 394..395 '1': i32
2430 406..408 'V2': V2([f32; _]) -> V2 2430 406..408 'V2': V2([f32; _]) -> V2
2431 406..416 'V2([x, y])': V2 2431 406..416 'V2([x, y])': V2
2432 409..415 '[x, y]': [f32; _] 2432 409..415 '[x, y]': [f32; 2]
2433 410..411 'x': f32 2433 410..411 'x': f32
2434 413..414 'y': f32 2434 413..414 'y': f32
2435 436..519 '{ ... vb; }': () 2435 436..519 '{ ... vb; }': ()
2436 446..448 'va': V2 2436 446..448 'va': V2
2437 451..453 'V2': V2([f32; _]) -> V2 2437 451..453 'V2': V2([f32; _]) -> V2
2438 451..465 'V2([0.0, 1.0])': V2 2438 451..465 'V2([0.0, 1.0])': V2
2439 454..464 '[0.0, 1.0]': [f32; _] 2439 454..464 '[0.0, 1.0]': [f32; 2]
2440 455..458 '0.0': f32 2440 455..458 '0.0': f32
2441 460..463 '1.0': f32 2441 460..463 '1.0': f32
2442 475..477 'vb': V2 2442 475..477 'vb': V2
2443 480..482 'V2': V2([f32; _]) -> V2 2443 480..482 'V2': V2([f32; _]) -> V2
2444 480..494 'V2([0.0, 1.0])': V2 2444 480..494 'V2([0.0, 1.0])': V2
2445 483..493 '[0.0, 1.0]': [f32; _] 2445 483..493 '[0.0, 1.0]': [f32; 2]
2446 484..487 '0.0': f32 2446 484..487 '0.0': f32
2447 489..492 '1.0': f32 2447 489..492 '1.0': f32
2448 505..506 'r': V2 2448 505..506 'r': V2
@@ -2593,8 +2593,8 @@ fn test() {
2593 658..661 'vec': Vec<i32, Global> 2593 658..661 'vec': Vec<i32, Global>
2594 664..679 '<[_]>::into_vec': fn into_vec<i32, Global>(Box<[i32], Global>) -> Vec<i32, Global> 2594 664..679 '<[_]>::into_vec': fn into_vec<i32, Global>(Box<[i32], Global>) -> Vec<i32, Global>
2595 664..691 '<[_]>:...1i32])': Vec<i32, Global> 2595 664..691 '<[_]>:...1i32])': Vec<i32, Global>
2596 680..690 'box [1i32]': Box<[i32; _], Global> 2596 680..690 'box [1i32]': Box<[i32; 1], Global>
2597 684..690 '[1i32]': [i32; _] 2597 684..690 '[1i32]': [i32; 1]
2598 685..689 '1i32': i32 2598 685..689 '1i32': i32
2599 "#]], 2599 "#]],
2600 ) 2600 )
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs
index ffc7c8ef4..47a1455fd 100644
--- a/crates/hir_ty/src/tests/traits.rs
+++ b/crates/hir_ty/src/tests/traits.rs
@@ -531,7 +531,7 @@ fn indexing_arrays() {
531 expect![[r#" 531 expect![[r#"
532 10..26 '{ &mut...[2]; }': () 532 10..26 '{ &mut...[2]; }': ()
533 12..23 '&mut [9][2]': &mut {unknown} 533 12..23 '&mut [9][2]': &mut {unknown}
534 17..20 '[9]': [i32; _] 534 17..20 '[9]': [i32; 1]
535 17..23 '[9][2]': {unknown} 535 17..23 '[9][2]': {unknown}
536 18..19 '9': i32 536 18..19 '9': i32
537 21..22 '2': i32 537 21..22 '2': i32
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs
index cb5a8e19a..320694a17 100644
--- a/crates/ide/src/doc_links.rs
+++ b/crates/ide/src/doc_links.rs
@@ -29,7 +29,8 @@ pub(crate) type DocumentationLink = String;
29/// Rewrite documentation links in markdown to point to an online host (e.g. docs.rs) 29/// Rewrite documentation links in markdown to point to an online host (e.g. docs.rs)
30pub(crate) fn rewrite_links(db: &RootDatabase, markdown: &str, definition: &Definition) -> String { 30pub(crate) fn rewrite_links(db: &RootDatabase, markdown: &str, definition: &Definition) -> String {
31 let mut cb = broken_link_clone_cb; 31 let mut cb = broken_link_clone_cb;
32 let doc = Parser::new_with_broken_link_callback(markdown, Options::empty(), Some(&mut cb)); 32 let doc =
33 Parser::new_with_broken_link_callback(markdown, Options::ENABLE_TASKLISTS, Some(&mut cb));
33 34
34 let doc = map_links(doc, |target, title: &str| { 35 let doc = map_links(doc, |target, title: &str| {
35 // This check is imperfect, there's some overlap between valid intra-doc links 36 // This check is imperfect, there's some overlap between valid intra-doc links
@@ -64,8 +65,7 @@ pub(crate) fn rewrite_links(db: &RootDatabase, markdown: &str, definition: &Defi
64pub(crate) fn remove_links(markdown: &str) -> String { 65pub(crate) fn remove_links(markdown: &str) -> String {
65 let mut drop_link = false; 66 let mut drop_link = false;
66 67
67 let mut opts = Options::empty(); 68 let opts = Options::ENABLE_TASKLISTS | Options::ENABLE_FOOTNOTES;
68 opts.insert(Options::ENABLE_FOOTNOTES);
69 69
70 let mut cb = |_: BrokenLink| { 70 let mut cb = |_: BrokenLink| {
71 let empty = InlineStr::try_from("").unwrap(); 71 let empty = InlineStr::try_from("").unwrap();
@@ -123,7 +123,7 @@ pub(crate) fn extract_definitions_from_markdown(
123) -> Vec<(TextRange, String, Option<hir::Namespace>)> { 123) -> Vec<(TextRange, String, Option<hir::Namespace>)> {
124 Parser::new_with_broken_link_callback( 124 Parser::new_with_broken_link_callback(
125 markdown, 125 markdown,
126 Options::empty(), 126 Options::ENABLE_TASKLISTS,
127 Some(&mut broken_link_clone_cb), 127 Some(&mut broken_link_clone_cb),
128 ) 128 )
129 .into_offset_iter() 129 .into_offset_iter()
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index e0bf660c4..960d169f4 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -1126,7 +1126,7 @@ fn main() {
1126 r#" 1126 r#"
1127fn main() { 1127fn main() {
1128 let data = &[1i32, 2, 3]; 1128 let data = &[1i32, 2, 3];
1129 //^^^^ &[i32; _] 1129 //^^^^ &[i32; 3]
1130 for i 1130 for i
1131}"#, 1131}"#,
1132 ); 1132 );
diff --git a/crates/ide_assists/src/handlers/auto_import.rs b/crates/ide_assists/src/handlers/auto_import.rs
index a454a2af3..506cc292c 100644
--- a/crates/ide_assists/src/handlers/auto_import.rs
+++ b/crates/ide_assists/src/handlers/auto_import.rs
@@ -969,4 +969,30 @@ mod bar {
969"#, 969"#,
970 ); 970 );
971 } 971 }
972
973 #[test]
974 fn uses_abs_path_with_extern_crate_clash() {
975 check_assist(
976 auto_import,
977 r#"
978//- /main.rs crate:main deps:foo
979mod foo {}
980
981const _: () = {
982 Foo$0
983};
984//- /foo.rs crate:foo
985pub struct Foo
986"#,
987 r#"
988use ::foo::Foo;
989
990mod foo {}
991
992const _: () = {
993 Foo
994};
995"#,
996 );
997 }
972} 998}
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 66f274fa7..8e2178391 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,20 +151,37 @@ fn create_struct_def(
151 field_list: &Either<ast::RecordFieldList, ast::TupleFieldList>, 151 field_list: &Either<ast::RecordFieldList, ast::TupleFieldList>,
152 visibility: Option<ast::Visibility>, 152 visibility: Option<ast::Visibility>,
153) -> ast::Struct { 153) -> ast::Struct {
154 let pub_vis = Some(make::visibility_pub()); 154 let pub_vis = make::visibility_pub();
155
156 let insert_pub = |node: &'_ SyntaxNode| {
157 let pub_vis = pub_vis.clone_for_update();
158 ted::insert(ted::Position::before(node), pub_vis.syntax());
159 };
160
161 // for fields without any existing visibility, use pub visibility
155 let field_list = match field_list { 162 let field_list = match field_list {
156 Either::Left(field_list) => { 163 Either::Left(field_list) => {
157 make::record_field_list(field_list.fields().flat_map(|field| { 164 let field_list = field_list.clone_for_update();
158 Some(make::record_field(pub_vis.clone(), field.name()?, field.ty()?)) 165
159 })) 166 field_list
160 .into() 167 .fields()
168 .filter(|field| field.visibility().is_none())
169 .filter_map(|field| field.name())
170 .for_each(|it| insert_pub(it.syntax()));
171
172 field_list.into()
161 } 173 }
162 Either::Right(field_list) => make::tuple_field_list( 174 Either::Right(field_list) => {
175 let field_list = field_list.clone_for_update();
176
163 field_list 177 field_list
164 .fields() 178 .fields()
165 .flat_map(|field| Some(make::tuple_field(pub_vis.clone(), field.ty()?))), 179 .filter(|field| field.visibility().is_none())
166 ) 180 .filter_map(|field| field.ty())
167 .into(), 181 .for_each(|it| insert_pub(it.syntax()));
182
183 field_list.into()
184 }
168 }; 185 };
169 186
170 make::struct_(visibility, variant_name, None, field_list).clone_for_update() 187 make::struct_(visibility, variant_name, None, field_list).clone_for_update()
@@ -295,6 +312,106 @@ enum A { One(One) }"#,
295 } 312 }
296 313
297 #[test] 314 #[test]
315 fn test_extract_struct_keep_comments_and_attrs_one_field_named() {
316 check_assist(
317 extract_struct_from_enum_variant,
318 r#"
319enum A {
320 $0One {
321 // leading comment
322 /// doc comment
323 #[an_attr]
324 foo: u32
325 // trailing comment
326 }
327}"#,
328 r#"
329struct One{
330 // leading comment
331 /// doc comment
332 #[an_attr]
333 pub foo: u32
334 // trailing comment
335 }
336
337enum A {
338 One(One)
339}"#,
340 );
341 }
342
343 #[test]
344 fn test_extract_struct_keep_comments_and_attrs_several_fields_named() {
345 check_assist(
346 extract_struct_from_enum_variant,
347 r#"
348enum A {
349 $0One {
350 // comment
351 /// doc
352 #[attr]
353 foo: u32,
354 // comment
355 #[attr]
356 /// doc
357 bar: u32
358 }
359}"#,
360 r#"
361struct One{
362 // comment
363 /// doc
364 #[attr]
365 pub foo: u32,
366 // comment
367 #[attr]
368 /// doc
369 pub bar: u32
370 }
371
372enum A {
373 One(One)
374}"#,
375 );
376 }
377
378 #[test]
379 fn test_extract_struct_keep_comments_and_attrs_several_fields_tuple() {
380 check_assist(
381 extract_struct_from_enum_variant,
382 "enum A { $0One(/* comment */ #[attr] u32, /* another */ u32 /* tail */) }",
383 r#"
384struct One(/* comment */ #[attr] pub u32, /* another */ pub u32 /* tail */);
385
386enum A { One(One) }"#,
387 );
388 }
389
390 #[test]
391 fn test_extract_struct_keep_existing_visibility_named() {
392 check_assist(
393 extract_struct_from_enum_variant,
394 "enum A { $0One{ pub a: u32, pub(crate) b: u32, pub(super) c: u32, d: u32 } }",
395 r#"
396struct One{ pub a: u32, pub(crate) b: u32, pub(super) c: u32, pub d: u32 }
397
398enum A { One(One) }"#,
399 );
400 }
401
402 #[test]
403 fn test_extract_struct_keep_existing_visibility_tuple() {
404 check_assist(
405 extract_struct_from_enum_variant,
406 "enum A { $0One(pub u32, pub(crate) u32, pub(super) u32, u32) }",
407 r#"
408struct One(pub u32, pub(crate) u32, pub(super) u32, pub u32);
409
410enum A { One(One) }"#,
411 );
412 }
413
414 #[test]
298 fn test_extract_enum_variant_name_value_namespace() { 415 fn test_extract_enum_variant_name_value_namespace() {
299 check_assist( 416 check_assist(
300 extract_struct_from_enum_variant, 417 extract_struct_from_enum_variant,
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 6e685b4b2..93f702c55 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 @@
1use ast::{edit::IndentLevel, VisibilityOwner}; 1use ast::edit::IndentLevel;
2use ide_db::base_db::AnchoredPathBuf; 2use ide_db::base_db::AnchoredPathBuf;
3use stdx::format_to; 3use stdx::format_to;
4use syntax::{ 4use syntax::{
@@ -60,12 +60,18 @@ pub(crate) fn move_module_to_file(acc: &mut Assists, ctx: &AssistContext) -> Opt
60 }; 60 };
61 61
62 let mut buf = String::new(); 62 let mut buf = String::new();
63 if let Some(v) = module_ast.visibility() {
64 format_to!(buf, "{} ", v);
65 }
66 format_to!(buf, "mod {};", module_name); 63 format_to!(buf, "mod {};", module_name);
67 64
68 builder.replace(module_ast.syntax().text_range(), buf); 65 let replacement_start = if let Some(mod_token) = module_ast.mod_token() {
66 mod_token.text_range().start()
67 } else {
68 module_ast.syntax().text_range().start()
69 };
70
71 builder.replace(
72 TextRange::new(replacement_start, module_ast.syntax().text_range().end()),
73 buf,
74 );
69 75
70 let dst = AnchoredPathBuf { anchor: ctx.frange.file_id, path }; 76 let dst = AnchoredPathBuf { anchor: ctx.frange.file_id, path };
71 builder.create_file(dst, contents); 77 builder.create_file(dst, contents);
@@ -184,4 +190,26 @@ pub(crate) mod tests;
184 cov_mark::check!(available_before_curly); 190 cov_mark::check!(available_before_curly);
185 check_assist_not_applicable(move_module_to_file, r#"mod m { $0 }"#); 191 check_assist_not_applicable(move_module_to_file, r#"mod m { $0 }"#);
186 } 192 }
193
194 #[test]
195 fn keep_outer_comments_and_attributes() {
196 check_assist(
197 move_module_to_file,
198 r#"
199/// doc comment
200#[attribute]
201mod $0tests {
202 #[test] fn t() {}
203}
204"#,
205 r#"
206//- /main.rs
207/// doc comment
208#[attribute]
209mod tests;
210//- /tests.rs
211#[test] fn t() {}
212"#,
213 );
214 }
187} 215}
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 0fec961b4..a3bfa221c 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;
17 17
18// Assist: replace_unwrap_with_match 18// Assist: replace_unwrap_with_match
19// 19//
20// Replaces `unwrap` a `match` expression. Works for Result and Option. 20// Replaces `unwrap` with a `match` expression. Works for Result and Option.
21// 21//
22// ``` 22// ```
23// enum Result<T, E> { Ok(T), Err(E) } 23// enum Result<T, E> { Ok(T), Err(E) }