aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/hir/src/lib.rs9
-rw-r--r--crates/hir_def/src/body/tests.rs2
-rw-r--r--crates/hir_def/src/nameres/tests/diagnostics.rs2
-rw-r--r--crates/hir_expand/src/builtin_macro.rs2
-rw-r--r--crates/hir_ty/src/chalk_ext.rs49
-rw-r--r--crates/hir_ty/src/display.rs46
-rw-r--r--crates/hir_ty/src/infer.rs2
-rw-r--r--crates/hir_ty/src/infer/coerce.rs2
-rw-r--r--crates/hir_ty/src/infer/pat.rs2
-rw-r--r--crates/hir_ty/src/infer/path.rs3
-rw-r--r--crates/hir_ty/src/infer/unify.rs3
-rw-r--r--crates/hir_ty/src/lib.rs62
-rw-r--r--crates/hir_ty/src/lower.rs2
-rw-r--r--crates/hir_ty/src/method_resolution.rs6
-rw-r--r--crates/hir_ty/src/traits.rs2
-rw-r--r--crates/hir_ty/src/traits/chalk.rs2
-rw-r--r--crates/hir_ty/src/traits/chalk/mapping.rs10
-rw-r--r--crates/hir_ty/src/types.rs14
-rw-r--r--crates/hir_ty/src/utils.rs4
-rw-r--r--crates/ide/src/folding_ranges.rs17
-rw-r--r--crates/ide/src/typing.rs168
-rw-r--r--crates/ide_assists/src/handlers/remove_dbg.rs105
-rw-r--r--crates/rust-analyzer/src/caps.rs2
-rw-r--r--crates/rust-analyzer/src/handlers.rs1
-rw-r--r--crates/rust-analyzer/src/to_proto.rs3
25 files changed, 385 insertions, 135 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 13aaa408a..0afc06906 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -59,7 +59,8 @@ use hir_ty::{
59 traits::FnTrait, 59 traits::FnTrait,
60 AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, 60 AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast,
61 DebruijnIndex, InEnvironment, Interner, QuantifiedWhereClause, Scalar, Solution, Substitution, 61 DebruijnIndex, InEnvironment, Interner, QuantifiedWhereClause, Scalar, Solution, Substitution,
62 TraitEnvironment, Ty, TyBuilder, TyDefId, TyExt, TyKind, TyVariableKind, WhereClause, 62 TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, TyVariableKind,
63 WhereClause,
63}; 64};
64use itertools::Itertools; 65use itertools::Itertools;
65use rustc_hash::FxHashSet; 66use rustc_hash::FxHashSet;
@@ -1790,7 +1791,7 @@ impl Type {
1790 .build(); 1791 .build();
1791 1792
1792 let goal = Canonical { 1793 let goal = Canonical {
1793 value: hir_ty::InEnvironment::new(self.env.env.clone(), trait_ref.cast(&Interner)), 1794 value: hir_ty::InEnvironment::new(&self.env.env, trait_ref.cast(&Interner)),
1794 binders: CanonicalVarKinds::empty(&Interner), 1795 binders: CanonicalVarKinds::empty(&Interner),
1795 }; 1796 };
1796 1797
@@ -1807,9 +1808,9 @@ impl Type {
1807 .push(self.ty.clone()) 1808 .push(self.ty.clone())
1808 .fill(args.iter().map(|t| t.ty.clone())) 1809 .fill(args.iter().map(|t| t.ty.clone()))
1809 .build(); 1810 .build();
1810 let goal = Canonical::new( 1811 let goal = hir_ty::make_canonical(
1811 InEnvironment::new( 1812 InEnvironment::new(
1812 self.env.env.clone(), 1813 &self.env.env,
1813 AliasEq { 1814 AliasEq {
1814 alias: AliasTy::Projection(projection), 1815 alias: AliasTy::Projection(projection),
1815 ty: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)) 1816 ty: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0))
diff --git a/crates/hir_def/src/body/tests.rs b/crates/hir_def/src/body/tests.rs
index faa133297..c1d3e998f 100644
--- a/crates/hir_def/src/body/tests.rs
+++ b/crates/hir_def/src/body/tests.rs
@@ -143,7 +143,7 @@ fn f() {
143 //^^^^^^^^^^^^^ could not convert tokens 143 //^^^^^^^^^^^^^ could not convert tokens
144 144
145 env!("OUT_DIR"); 145 env!("OUT_DIR");
146 //^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "load out dirs from check" to fix 146 //^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix
147 147
148 compile_error!("compile_error works"); 148 compile_error!("compile_error works");
149 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ compile_error works 149 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ compile_error works
diff --git a/crates/hir_def/src/nameres/tests/diagnostics.rs b/crates/hir_def/src/nameres/tests/diagnostics.rs
index fefdadb22..1ac88fc89 100644
--- a/crates/hir_def/src/nameres/tests/diagnostics.rs
+++ b/crates/hir_def/src/nameres/tests/diagnostics.rs
@@ -233,7 +233,7 @@ fn good_out_dir_diagnostic() {
233 macro_rules! concat { () => {} } 233 macro_rules! concat { () => {} }
234 234
235 include!(concat!(env!("OUT_DIR"), "/out.rs")); 235 include!(concat!(env!("OUT_DIR"), "/out.rs"));
236 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "load out dirs from check" to fix 236 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix
237 "#, 237 "#,
238 ); 238 );
239} 239}
diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs
index 75ec4196b..a7d0f5b1f 100644
--- a/crates/hir_expand/src/builtin_macro.rs
+++ b/crates/hir_expand/src/builtin_macro.rs
@@ -490,7 +490,7 @@ fn env_expand(
490 // unnecessary diagnostics for eg. `CARGO_PKG_NAME`. 490 // unnecessary diagnostics for eg. `CARGO_PKG_NAME`.
491 if key == "OUT_DIR" { 491 if key == "OUT_DIR" {
492 err = Some(mbe::ExpandError::Other( 492 err = Some(mbe::ExpandError::Other(
493 r#"`OUT_DIR` not set, enable "load out dirs from check" to fix"#.into(), 493 r#"`OUT_DIR` not set, enable "run build scripts" to fix"#.into(),
494 )); 494 ));
495 } 495 }
496 496
diff --git a/crates/hir_ty/src/chalk_ext.rs b/crates/hir_ty/src/chalk_ext.rs
index 8e8a1aa48..28ed3aac6 100644
--- a/crates/hir_ty/src/chalk_ext.rs
+++ b/crates/hir_ty/src/chalk_ext.rs
@@ -8,7 +8,7 @@ use hir_def::{
8use crate::{ 8use crate::{
9 db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, 9 db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id,
10 from_placeholder_idx, to_chalk_trait_id, AdtId, AliasEq, AliasTy, Binders, CallableDefId, 10 from_placeholder_idx, to_chalk_trait_id, AdtId, AliasEq, AliasTy, Binders, CallableDefId,
11 CallableSig, ImplTraitId, Interner, Lifetime, ProjectionTy, QuantifiedWhereClause, 11 CallableSig, FnPointer, ImplTraitId, Interner, Lifetime, ProjectionTy, QuantifiedWhereClause,
12 Substitution, TraitRef, Ty, TyBuilder, TyKind, WhereClause, 12 Substitution, TraitRef, Ty, TyBuilder, TyKind, WhereClause,
13}; 13};
14 14
@@ -34,6 +34,9 @@ pub trait TyExt {
34 34
35 fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<QuantifiedWhereClause>>; 35 fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<QuantifiedWhereClause>>;
36 fn associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<TraitId>; 36 fn associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<TraitId>;
37
38 /// FIXME: Get rid of this, it's not a good abstraction
39 fn equals_ctor(&self, other: &Ty) -> bool;
37} 40}
38 41
39impl TyExt for Ty { 42impl TyExt for Ty {
@@ -199,12 +202,12 @@ impl TyExt for Ty {
199 .map(|pred| pred.clone().substitute(&Interner, &substs)) 202 .map(|pred| pred.clone().substitute(&Interner, &substs))
200 .filter(|wc| match &wc.skip_binders() { 203 .filter(|wc| match &wc.skip_binders() {
201 WhereClause::Implemented(tr) => { 204 WhereClause::Implemented(tr) => {
202 tr.self_type_parameter(&Interner) == self 205 &tr.self_type_parameter(&Interner) == self
203 } 206 }
204 WhereClause::AliasEq(AliasEq { 207 WhereClause::AliasEq(AliasEq {
205 alias: AliasTy::Projection(proj), 208 alias: AliasTy::Projection(proj),
206 ty: _, 209 ty: _,
207 }) => proj.self_type_parameter(&Interner) == self, 210 }) => &proj.self_type_parameter(&Interner) == self,
208 _ => false, 211 _ => false,
209 }) 212 })
210 .collect::<Vec<_>>(); 213 .collect::<Vec<_>>();
@@ -238,6 +241,36 @@ impl TyExt for Ty {
238 _ => None, 241 _ => None,
239 } 242 }
240 } 243 }
244
245 fn equals_ctor(&self, other: &Ty) -> bool {
246 match (self.kind(&Interner), other.kind(&Interner)) {
247 (TyKind::Adt(adt, ..), TyKind::Adt(adt2, ..)) => adt == adt2,
248 (TyKind::Slice(_), TyKind::Slice(_)) | (TyKind::Array(_, _), TyKind::Array(_, _)) => {
249 true
250 }
251 (TyKind::FnDef(def_id, ..), TyKind::FnDef(def_id2, ..)) => def_id == def_id2,
252 (TyKind::OpaqueType(ty_id, ..), TyKind::OpaqueType(ty_id2, ..)) => ty_id == ty_id2,
253 (TyKind::AssociatedType(ty_id, ..), TyKind::AssociatedType(ty_id2, ..)) => {
254 ty_id == ty_id2
255 }
256 (TyKind::Foreign(ty_id, ..), TyKind::Foreign(ty_id2, ..)) => ty_id == ty_id2,
257 (TyKind::Closure(id1, _), TyKind::Closure(id2, _)) => id1 == id2,
258 (TyKind::Ref(mutability, ..), TyKind::Ref(mutability2, ..))
259 | (TyKind::Raw(mutability, ..), TyKind::Raw(mutability2, ..)) => {
260 mutability == mutability2
261 }
262 (
263 TyKind::Function(FnPointer { num_binders, sig, .. }),
264 TyKind::Function(FnPointer { num_binders: num_binders2, sig: sig2, .. }),
265 ) => num_binders == num_binders2 && sig == sig2,
266 (TyKind::Tuple(cardinality, _), TyKind::Tuple(cardinality2, _)) => {
267 cardinality == cardinality2
268 }
269 (TyKind::Str, TyKind::Str) | (TyKind::Never, TyKind::Never) => true,
270 (TyKind::Scalar(scalar), TyKind::Scalar(scalar2)) => scalar == scalar2,
271 _ => false,
272 }
273 }
241} 274}
242 275
243pub trait ProjectionTyExt { 276pub trait ProjectionTyExt {
@@ -260,3 +293,13 @@ impl ProjectionTyExt for ProjectionTy {
260 } 293 }
261 } 294 }
262} 295}
296
297pub trait TraitRefExt {
298 fn hir_trait_id(&self) -> TraitId;
299}
300
301impl TraitRefExt for TraitRef {
302 fn hir_trait_id(&self) -> TraitId {
303 from_chalk_trait_id(self.trait_id)
304 }
305}
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs
index 9e6bbcdf1..e0ca96c6d 100644
--- a/crates/hir_ty/src/display.rs
+++ b/crates/hir_ty/src/display.rs
@@ -24,7 +24,7 @@ use crate::{
24 traits::chalk::from_chalk, utils::generics, AdtId, AliasEq, AliasTy, CallableDefId, 24 traits::chalk::from_chalk, utils::generics, AdtId, AliasEq, AliasTy, CallableDefId,
25 CallableSig, Const, ConstValue, DomainGoal, GenericArg, ImplTraitId, Interner, Lifetime, 25 CallableSig, Const, ConstValue, DomainGoal, GenericArg, ImplTraitId, Interner, Lifetime,
26 LifetimeData, LifetimeOutlives, Mutability, OpaqueTy, ProjectionTy, ProjectionTyExt, 26 LifetimeData, LifetimeOutlives, Mutability, OpaqueTy, ProjectionTy, ProjectionTyExt,
27 QuantifiedWhereClause, Scalar, TraitRef, Ty, TyExt, TyKind, WhereClause, 27 QuantifiedWhereClause, Scalar, TraitRef, TraitRefExt, Ty, TyExt, TyKind, WhereClause,
28}; 28};
29 29
30pub struct HirFormatter<'a> { 30pub struct HirFormatter<'a> {
@@ -616,12 +616,12 @@ impl HirDisplay for Ty {
616 .map(|pred| pred.clone().substitute(&Interner, &substs)) 616 .map(|pred| pred.clone().substitute(&Interner, &substs))
617 .filter(|wc| match &wc.skip_binders() { 617 .filter(|wc| match &wc.skip_binders() {
618 WhereClause::Implemented(tr) => { 618 WhereClause::Implemented(tr) => {
619 tr.self_type_parameter(&Interner) == self 619 &tr.self_type_parameter(&Interner) == self
620 } 620 }
621 WhereClause::AliasEq(AliasEq { 621 WhereClause::AliasEq(AliasEq {
622 alias: AliasTy::Projection(proj), 622 alias: AliasTy::Projection(proj),
623 ty: _, 623 ty: _,
624 }) => proj.self_type_parameter(&Interner) == self, 624 }) => &proj.self_type_parameter(&Interner) == self,
625 _ => false, 625 _ => false,
626 }) 626 })
627 .collect::<Vec<_>>(); 627 .collect::<Vec<_>>();
@@ -745,7 +745,7 @@ fn write_bounds_like_dyn_trait(
745 // existential) here, which is the only thing that's 745 // existential) here, which is the only thing that's
746 // possible in actual Rust, and hence don't print it 746 // possible in actual Rust, and hence don't print it
747 write!(f, "{}", f.db.trait_data(trait_).name)?; 747 write!(f, "{}", f.db.trait_data(trait_).name)?;
748 if let [_, params @ ..] = &*trait_ref.substitution.interned() { 748 if let [_, params @ ..] = &*trait_ref.substitution.interned().as_slice() {
749 if is_fn_trait { 749 if is_fn_trait {
750 if let Some(args) = 750 if let Some(args) =
751 params.first().and_then(|it| it.assert_ty_ref(&Interner).as_tuple()) 751 params.first().and_then(|it| it.assert_ty_ref(&Interner).as_tuple())
@@ -792,31 +792,29 @@ fn write_bounds_like_dyn_trait(
792 Ok(()) 792 Ok(())
793} 793}
794 794
795impl TraitRef { 795fn fmt_trait_ref(tr: &TraitRef, f: &mut HirFormatter, use_as: bool) -> Result<(), HirDisplayError> {
796 fn hir_fmt_ext(&self, f: &mut HirFormatter, use_as: bool) -> Result<(), HirDisplayError> { 796 if f.should_truncate() {
797 if f.should_truncate() { 797 return write!(f, "{}", TYPE_HINT_TRUNCATION);
798 return write!(f, "{}", TYPE_HINT_TRUNCATION); 798 }
799 }
800 799
801 self.self_type_parameter(&Interner).hir_fmt(f)?; 800 tr.self_type_parameter(&Interner).hir_fmt(f)?;
802 if use_as { 801 if use_as {
803 write!(f, " as ")?; 802 write!(f, " as ")?;
804 } else { 803 } else {
805 write!(f, ": ")?; 804 write!(f, ": ")?;
806 }
807 write!(f, "{}", f.db.trait_data(self.hir_trait_id()).name)?;
808 if self.substitution.len(&Interner) > 1 {
809 write!(f, "<")?;
810 f.write_joined(&self.substitution.interned()[1..], ", ")?;
811 write!(f, ">")?;
812 }
813 Ok(())
814 } 805 }
806 write!(f, "{}", f.db.trait_data(tr.hir_trait_id()).name)?;
807 if tr.substitution.len(&Interner) > 1 {
808 write!(f, "<")?;
809 f.write_joined(&tr.substitution.interned()[1..], ", ")?;
810 write!(f, ">")?;
811 }
812 Ok(())
815} 813}
816 814
817impl HirDisplay for TraitRef { 815impl HirDisplay for TraitRef {
818 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { 816 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
819 self.hir_fmt_ext(f, false) 817 fmt_trait_ref(self, f, false)
820 } 818 }
821} 819}
822 820
@@ -830,7 +828,7 @@ impl HirDisplay for WhereClause {
830 WhereClause::Implemented(trait_ref) => trait_ref.hir_fmt(f)?, 828 WhereClause::Implemented(trait_ref) => trait_ref.hir_fmt(f)?,
831 WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => { 829 WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => {
832 write!(f, "<")?; 830 write!(f, "<")?;
833 projection_ty.trait_ref(f.db).hir_fmt_ext(f, true)?; 831 fmt_trait_ref(&projection_ty.trait_ref(f.db), f, true)?;
834 write!( 832 write!(
835 f, 833 f,
836 ">::{} = ", 834 ">::{} = ",
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs
index 6af0c59b8..531159e54 100644
--- a/crates/hir_ty/src/infer.rs
+++ b/crates/hir_ty/src/infer.rs
@@ -336,7 +336,7 @@ impl<'a> InferenceContext<'a> {
336 self.last_obligations_check = Some(self.table.revision); 336 self.last_obligations_check = Some(self.table.revision);
337 let obligations = mem::replace(&mut self.obligations, Vec::new()); 337 let obligations = mem::replace(&mut self.obligations, Vec::new());
338 for obligation in obligations { 338 for obligation in obligations {
339 let in_env = InEnvironment::new(self.trait_env.env.clone(), obligation.clone()); 339 let in_env = InEnvironment::new(&self.trait_env.env, obligation.clone());
340 let canonicalized = self.canonicalizer().canonicalize_obligation(in_env); 340 let canonicalized = self.canonicalizer().canonicalize_obligation(in_env);
341 let solution = 341 let solution =
342 self.db.trait_solve(self.resolver.krate().unwrap(), canonicalized.value.clone()); 342 self.db.trait_solve(self.resolver.krate().unwrap(), canonicalized.value.clone());
diff --git a/crates/hir_ty/src/infer/coerce.rs b/crates/hir_ty/src/infer/coerce.rs
index f1af2a0bd..fd679f444 100644
--- a/crates/hir_ty/src/infer/coerce.rs
+++ b/crates/hir_ty/src/infer/coerce.rs
@@ -139,7 +139,7 @@ impl<'a> InferenceContext<'a> {
139 b.push(from_ty.clone()).push(to_ty.clone()).build() 139 b.push(from_ty.clone()).push(to_ty.clone()).build()
140 }; 140 };
141 141
142 let goal = InEnvironment::new(self.trait_env.env.clone(), trait_ref.cast(&Interner)); 142 let goal = InEnvironment::new(&self.trait_env.env, trait_ref.cast(&Interner));
143 143
144 let canonicalizer = self.canonicalizer(); 144 let canonicalizer = self.canonicalizer();
145 let canonicalized = canonicalizer.canonicalize_obligation(goal); 145 let canonicalized = canonicalizer.canonicalize_obligation(goal);
diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs
index f88d5c5d3..a41e8e116 100644
--- a/crates/hir_ty/src/infer/pat.rs
+++ b/crates/hir_ty/src/infer/pat.rs
@@ -122,7 +122,7 @@ impl<'a> InferenceContext<'a> {
122 let ty = match &body[pat] { 122 let ty = match &body[pat] {
123 &Pat::Tuple { ref args, ellipsis } => { 123 &Pat::Tuple { ref args, ellipsis } => {
124 let expectations = match expected.as_tuple() { 124 let expectations = match expected.as_tuple() {
125 Some(parameters) => &*parameters.interned(), 125 Some(parameters) => &*parameters.interned().as_slice(),
126 _ => &[], 126 _ => &[],
127 }; 127 };
128 128
diff --git a/crates/hir_ty/src/infer/path.rs b/crates/hir_ty/src/infer/path.rs
index b19d67bb1..f8955aa32 100644
--- a/crates/hir_ty/src/infer/path.rs
+++ b/crates/hir_ty/src/infer/path.rs
@@ -11,7 +11,8 @@ use hir_def::{
11use hir_expand::name::Name; 11use hir_expand::name::Name;
12 12
13use crate::{ 13use crate::{
14 method_resolution, Interner, Substitution, Ty, TyBuilder, TyExt, TyKind, ValueTyDefId, 14 method_resolution, Interner, Substitution, TraitRefExt, Ty, TyBuilder, TyExt, TyKind,
15 ValueTyDefId,
15}; 16};
16 17
17use super::{ExprOrPatId, InferenceContext, TraitRef}; 18use super::{ExprOrPatId, InferenceContext, TraitRef};
diff --git a/crates/hir_ty/src/infer/unify.rs b/crates/hir_ty/src/infer/unify.rs
index d717e3375..2ea9dd920 100644
--- a/crates/hir_ty/src/infer/unify.rs
+++ b/crates/hir_ty/src/infer/unify.rs
@@ -8,7 +8,8 @@ use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue};
8use super::{DomainGoal, InferenceContext}; 8use super::{DomainGoal, InferenceContext};
9use crate::{ 9use crate::{
10 AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds, DebruijnIndex, FnPointer, FnSubst, 10 AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds, DebruijnIndex, FnPointer, FnSubst,
11 InEnvironment, InferenceVar, Interner, Scalar, Substitution, Ty, TyKind, TypeWalk, WhereClause, 11 InEnvironment, InferenceVar, Interner, Scalar, Substitution, Ty, TyExt, TyKind, TypeWalk,
12 WhereClause,
12}; 13};
13 14
14impl<'a> InferenceContext<'a> { 15impl<'a> InferenceContext<'a> {
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs
index 84645c435..87f10e9d5 100644
--- a/crates/hir_ty/src/lib.rs
+++ b/crates/hir_ty/src/lib.rs
@@ -41,7 +41,7 @@ use crate::{db::HirDatabase, display::HirDisplay, utils::generics};
41 41
42pub use autoderef::autoderef; 42pub use autoderef::autoderef;
43pub use builder::TyBuilder; 43pub use builder::TyBuilder;
44pub use chalk_ext::{ProjectionTyExt, TyExt}; 44pub use chalk_ext::*;
45pub use infer::{could_unify, InferenceResult}; 45pub use infer::{could_unify, InferenceResult};
46pub use lower::{ 46pub use lower::{
47 associated_type_shorthand_candidates, callable_item_sig, CallableDefId, ImplTraitLoweringMode, 47 associated_type_shorthand_candidates, callable_item_sig, CallableDefId, ImplTraitLoweringMode,
@@ -107,22 +107,18 @@ pub fn make_only_type_binders<T>(num_vars: usize, value: T) -> Binders<T> {
107 ) 107 )
108} 108}
109 109
110impl TraitRef { 110// FIXME: get rid of this
111 pub fn hir_trait_id(&self) -> TraitId { 111pub fn make_canonical<T>(
112 from_chalk_trait_id(self.trait_id) 112 value: T,
113 } 113 kinds: impl IntoIterator<Item = TyVariableKind>,
114} 114) -> Canonical<T> {
115 115 let kinds = kinds.into_iter().map(|tk| {
116impl<T> Canonical<T> { 116 chalk_ir::CanonicalVarKind::new(
117 pub fn new(value: T, kinds: impl IntoIterator<Item = TyVariableKind>) -> Self { 117 chalk_ir::VariableKind::Ty(tk),
118 let kinds = kinds.into_iter().map(|tk| { 118 chalk_ir::UniverseIndex::ROOT,
119 chalk_ir::CanonicalVarKind::new( 119 )
120 chalk_ir::VariableKind::Ty(tk), 120 });
121 chalk_ir::UniverseIndex::ROOT, 121 Canonical { value, binders: chalk_ir::CanonicalVarKinds::from_iter(&Interner, kinds) }
122 )
123 });
124 Self { value, binders: chalk_ir::CanonicalVarKinds::from_iter(&Interner, kinds) }
125 }
126} 122}
127 123
128/// A function signature as seen by type inference: Several parameter types and 124/// A function signature as seen by type inference: Several parameter types and
@@ -168,37 +164,7 @@ impl CallableSig {
168 } 164 }
169} 165}
170 166
171impl Ty { 167impl Ty {}
172 pub fn equals_ctor(&self, other: &Ty) -> bool {
173 match (self.kind(&Interner), other.kind(&Interner)) {
174 (TyKind::Adt(adt, ..), TyKind::Adt(adt2, ..)) => adt == adt2,
175 (TyKind::Slice(_), TyKind::Slice(_)) | (TyKind::Array(_, _), TyKind::Array(_, _)) => {
176 true
177 }
178 (TyKind::FnDef(def_id, ..), TyKind::FnDef(def_id2, ..)) => def_id == def_id2,
179 (TyKind::OpaqueType(ty_id, ..), TyKind::OpaqueType(ty_id2, ..)) => ty_id == ty_id2,
180 (TyKind::AssociatedType(ty_id, ..), TyKind::AssociatedType(ty_id2, ..)) => {
181 ty_id == ty_id2
182 }
183 (TyKind::Foreign(ty_id, ..), TyKind::Foreign(ty_id2, ..)) => ty_id == ty_id2,
184 (TyKind::Closure(id1, _), TyKind::Closure(id2, _)) => id1 == id2,
185 (TyKind::Ref(mutability, ..), TyKind::Ref(mutability2, ..))
186 | (TyKind::Raw(mutability, ..), TyKind::Raw(mutability2, ..)) => {
187 mutability == mutability2
188 }
189 (
190 TyKind::Function(FnPointer { num_binders, sig, .. }),
191 TyKind::Function(FnPointer { num_binders: num_binders2, sig: sig2, .. }),
192 ) => num_binders == num_binders2 && sig == sig2,
193 (TyKind::Tuple(cardinality, _), TyKind::Tuple(cardinality2, _)) => {
194 cardinality == cardinality2
195 }
196 (TyKind::Str, TyKind::Str) | (TyKind::Never, TyKind::Never) => true,
197 (TyKind::Scalar(scalar), TyKind::Scalar(scalar2)) => scalar == scalar2,
198 _ => false,
199 }
200 }
201}
202 168
203#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] 169#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
204pub enum ImplTraitId { 170pub enum ImplTraitId {
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index 4ca6aa538..e6903e189 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -35,7 +35,7 @@ use crate::{
35 AliasEq, AliasTy, Binders, BoundVar, CallableSig, DebruijnIndex, DynTy, FnPointer, FnSig, 35 AliasEq, AliasTy, Binders, BoundVar, CallableSig, DebruijnIndex, DynTy, FnPointer, FnSig,
36 FnSubst, ImplTraitId, OpaqueTy, PolyFnSig, ProjectionTy, QuantifiedWhereClause, 36 FnSubst, ImplTraitId, OpaqueTy, PolyFnSig, ProjectionTy, QuantifiedWhereClause,
37 QuantifiedWhereClauses, ReturnTypeImplTrait, ReturnTypeImplTraits, Substitution, 37 QuantifiedWhereClauses, ReturnTypeImplTrait, ReturnTypeImplTraits, Substitution,
38 TraitEnvironment, TraitRef, Ty, TyBuilder, TyKind, TypeWalk, WhereClause, 38 TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyKind, TypeWalk, WhereClause,
39}; 39};
40 40
41#[derive(Debug)] 41#[derive(Debug)]
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs
index c601f2d53..7e09a1539 100644
--- a/crates/hir_ty/src/method_resolution.rs
+++ b/crates/hir_ty/src/method_resolution.rs
@@ -22,8 +22,8 @@ use crate::{
22 static_lifetime, 22 static_lifetime,
23 utils::all_super_traits, 23 utils::all_super_traits,
24 AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, FnPointer, FnSig, ForeignDefId, 24 AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, FnPointer, FnSig, ForeignDefId,
25 InEnvironment, Interner, Scalar, Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, 25 InEnvironment, Interner, Scalar, Substitution, TraitEnvironment, TraitRefExt, Ty, TyBuilder,
26 TypeWalk, 26 TyExt, TyKind, TypeWalk,
27}; 27};
28 28
29/// This is used as a key for indexing impls. 29/// This is used as a key for indexing impls.
@@ -845,7 +845,7 @@ fn generic_implements_goal(
845 let obligation = trait_ref.cast(&Interner); 845 let obligation = trait_ref.cast(&Interner);
846 Canonical { 846 Canonical {
847 binders: CanonicalVarKinds::from_iter(&Interner, kinds), 847 binders: CanonicalVarKinds::from_iter(&Interner, kinds),
848 value: InEnvironment::new(env.env.clone(), obligation), 848 value: InEnvironment::new(&env.env, obligation),
849 } 849 }
850} 850}
851 851
diff --git a/crates/hir_ty/src/traits.rs b/crates/hir_ty/src/traits.rs
index 3374532c3..7d87741b8 100644
--- a/crates/hir_ty/src/traits.rs
+++ b/crates/hir_ty/src/traits.rs
@@ -9,7 +9,7 @@ use stdx::panic_context;
9 9
10use crate::{ 10use crate::{
11 db::HirDatabase, AliasEq, AliasTy, Canonical, DomainGoal, Guidance, HirDisplay, InEnvironment, 11 db::HirDatabase, AliasEq, AliasTy, Canonical, DomainGoal, Guidance, HirDisplay, InEnvironment,
12 Solution, Ty, TyKind, WhereClause, 12 Solution, TraitRefExt, Ty, TyKind, WhereClause,
13}; 13};
14 14
15use self::chalk::{from_chalk, Interner, ToChalk}; 15use self::chalk::{from_chalk, Interner, ToChalk};
diff --git a/crates/hir_ty/src/traits/chalk.rs b/crates/hir_ty/src/traits/chalk.rs
index f03b92422..090f6492b 100644
--- a/crates/hir_ty/src/traits/chalk.rs
+++ b/crates/hir_ty/src/traits/chalk.rs
@@ -22,7 +22,7 @@ use crate::{
22 to_assoc_type_id, to_chalk_trait_id, 22 to_assoc_type_id, to_chalk_trait_id,
23 utils::generics, 23 utils::generics,
24 AliasEq, AliasTy, BoundVar, CallableDefId, DebruijnIndex, FnDefId, ProjectionTy, Substitution, 24 AliasEq, AliasTy, BoundVar, CallableDefId, DebruijnIndex, FnDefId, ProjectionTy, Substitution,
25 TraitRef, Ty, TyBuilder, TyExt, TyKind, WhereClause, 25 TraitRef, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, WhereClause,
26}; 26};
27use mapping::{ 27use mapping::{
28 convert_where_clauses, generic_predicate_to_inline_bound, make_binders, TypeAliasAsValue, 28 convert_where_clauses, generic_predicate_to_inline_bound, make_binders, TypeAliasAsValue,
diff --git a/crates/hir_ty/src/traits/chalk/mapping.rs b/crates/hir_ty/src/traits/chalk/mapping.rs
index 84abd99b2..701359e6f 100644
--- a/crates/hir_ty/src/traits/chalk/mapping.rs
+++ b/crates/hir_ty/src/traits/chalk/mapping.rs
@@ -10,9 +10,9 @@ use base_db::salsa::InternKey;
10use hir_def::{GenericDefId, TypeAliasId}; 10use hir_def::{GenericDefId, TypeAliasId};
11 11
12use crate::{ 12use crate::{
13 chalk_ext::ProjectionTyExt, db::HirDatabase, static_lifetime, AliasTy, CallableDefId, 13 db::HirDatabase, static_lifetime, AliasTy, CallableDefId, Canonical, ConstrainedSubst,
14 Canonical, ConstrainedSubst, DomainGoal, FnPointer, GenericArg, InEnvironment, OpaqueTy, 14 DomainGoal, FnPointer, GenericArg, InEnvironment, OpaqueTy, ProjectionTy, ProjectionTyExt,
15 ProjectionTy, QuantifiedWhereClause, Substitution, TraitRef, Ty, TypeWalk, WhereClause, 15 QuantifiedWhereClause, Substitution, TraitRef, Ty, TypeWalk, WhereClause,
16}; 16};
17 17
18use super::interner::*; 18use super::interner::*;
@@ -509,7 +509,7 @@ pub(super) fn generic_predicate_to_inline_bound(
509 let (pred, binders) = pred.as_ref().into_value_and_skipped_binders(); 509 let (pred, binders) = pred.as_ref().into_value_and_skipped_binders();
510 match pred { 510 match pred {
511 WhereClause::Implemented(trait_ref) => { 511 WhereClause::Implemented(trait_ref) => {
512 if trait_ref.self_type_parameter(&Interner) != &self_ty_shifted_in { 512 if trait_ref.self_type_parameter(&Interner) != self_ty_shifted_in {
513 // we can only convert predicates back to type bounds if they 513 // we can only convert predicates back to type bounds if they
514 // have the expected self type 514 // have the expected self type
515 return None; 515 return None;
@@ -522,7 +522,7 @@ pub(super) fn generic_predicate_to_inline_bound(
522 Some(chalk_ir::Binders::new(binders, rust_ir::InlineBound::TraitBound(trait_bound))) 522 Some(chalk_ir::Binders::new(binders, rust_ir::InlineBound::TraitBound(trait_bound)))
523 } 523 }
524 WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => { 524 WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => {
525 if projection_ty.self_type_parameter(&Interner) != &self_ty_shifted_in { 525 if projection_ty.self_type_parameter(&Interner) != self_ty_shifted_in {
526 return None; 526 return None;
527 } 527 }
528 let trait_ = projection_ty.trait_(db); 528 let trait_ = projection_ty.trait_(db);
diff --git a/crates/hir_ty/src/types.rs b/crates/hir_ty/src/types.rs
index c25bc2d6a..89adad108 100644
--- a/crates/hir_ty/src/types.rs
+++ b/crates/hir_ty/src/types.rs
@@ -30,8 +30,8 @@ pub struct ProjectionTy {
30} 30}
31 31
32impl ProjectionTy { 32impl ProjectionTy {
33 pub fn self_type_parameter(&self, interner: &Interner) -> &Ty { 33 pub fn self_type_parameter(&self, interner: &Interner) -> Ty {
34 &self.substitution.interned()[0].assert_ty_ref(interner) 34 self.substitution.interned()[0].assert_ty_ref(interner).clone()
35 } 35 }
36} 36}
37 37
@@ -282,7 +282,7 @@ impl GenericArg {
282pub struct Substitution(SmallVec<[GenericArg; 2]>); 282pub struct Substitution(SmallVec<[GenericArg; 2]>);
283 283
284impl Substitution { 284impl Substitution {
285 pub fn interned(&self) -> &[GenericArg] { 285 pub fn interned(&self) -> &SmallVec<[GenericArg; 2]> {
286 &self.0 286 &self.0
287 } 287 }
288 288
@@ -413,8 +413,8 @@ pub struct TraitRef {
413} 413}
414 414
415impl TraitRef { 415impl TraitRef {
416 pub fn self_type_parameter(&self, interner: &Interner) -> &Ty { 416 pub fn self_type_parameter(&self, interner: &Interner) -> Ty {
417 &self.substitution.at(interner, 0).assert_ty_ref(interner) 417 self.substitution.at(interner, 0).assert_ty_ref(interner).clone()
418 } 418 }
419} 419}
420 420
@@ -470,8 +470,8 @@ pub struct InEnvironment<T> {
470} 470}
471 471
472impl<T> InEnvironment<T> { 472impl<T> InEnvironment<T> {
473 pub fn new(environment: chalk_ir::Environment<Interner>, value: T) -> InEnvironment<T> { 473 pub fn new(environment: &chalk_ir::Environment<Interner>, value: T) -> InEnvironment<T> {
474 InEnvironment { environment, goal: value } 474 InEnvironment { environment: environment.clone(), goal: value }
475 } 475 }
476} 476}
477 477
diff --git a/crates/hir_ty/src/utils.rs b/crates/hir_ty/src/utils.rs
index 0a424f607..8d5d5cd73 100644
--- a/crates/hir_ty/src/utils.rs
+++ b/crates/hir_ty/src/utils.rs
@@ -16,7 +16,9 @@ use hir_def::{
16}; 16};
17use hir_expand::name::{name, Name}; 17use hir_expand::name::{name, Name};
18 18
19use crate::{db::HirDatabase, Interner, Substitution, TraitRef, TyKind, TypeWalk, WhereClause}; 19use crate::{
20 db::HirDatabase, Interner, Substitution, TraitRef, TraitRefExt, TyKind, TypeWalk, WhereClause,
21};
20 22
21fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { 23fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> {
22 let resolver = trait_.resolver(db); 24 let resolver = trait_.resolver(db);
diff --git a/crates/ide/src/folding_ranges.rs b/crates/ide/src/folding_ranges.rs
index 153726ce8..2b9ed123c 100644
--- a/crates/ide/src/folding_ranges.rs
+++ b/crates/ide/src/folding_ranges.rs
@@ -19,6 +19,7 @@ pub enum FoldKind {
19 Region, 19 Region,
20 Consts, 20 Consts,
21 Statics, 21 Statics,
22 Array,
22} 23}
23 24
24#[derive(Debug)] 25#[derive(Debug)]
@@ -119,6 +120,7 @@ fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
119 match kind { 120 match kind {
120 COMMENT => Some(FoldKind::Comment), 121 COMMENT => Some(FoldKind::Comment),
121 ARG_LIST | PARAM_LIST => Some(FoldKind::ArgList), 122 ARG_LIST | PARAM_LIST => Some(FoldKind::ArgList),
123 ARRAY_EXPR => Some(FoldKind::Array),
122 ASSOC_ITEM_LIST 124 ASSOC_ITEM_LIST
123 | RECORD_FIELD_LIST 125 | RECORD_FIELD_LIST
124 | RECORD_PAT_FIELD_LIST 126 | RECORD_PAT_FIELD_LIST
@@ -269,6 +271,7 @@ mod tests {
269 FoldKind::Region => "region", 271 FoldKind::Region => "region",
270 FoldKind::Consts => "consts", 272 FoldKind::Consts => "consts",
271 FoldKind::Statics => "statics", 273 FoldKind::Statics => "statics",
274 FoldKind::Array => "array",
272 }; 275 };
273 assert_eq!(kind, &attr.unwrap()); 276 assert_eq!(kind, &attr.unwrap());
274 } 277 }
@@ -465,6 +468,20 @@ fn foo<fold arglist>(
465 } 468 }
466 469
467 #[test] 470 #[test]
471 fn fold_multiline_array() {
472 check(
473 r#"
474const FOO: [usize; 4] = <fold array>[
475 1,
476 2,
477 3,
478 4,
479]</fold>;
480"#,
481 )
482 }
483
484 #[test]
468 fn fold_region() { 485 fn fold_region() {
469 check( 486 check(
470 r#" 487 r#"
diff --git a/crates/ide/src/typing.rs b/crates/ide/src/typing.rs
index 11408d445..1378048e5 100644
--- a/crates/ide/src/typing.rs
+++ b/crates/ide/src/typing.rs
@@ -22,18 +22,19 @@ use ide_db::{
22use syntax::{ 22use syntax::{
23 algo::find_node_at_offset, 23 algo::find_node_at_offset,
24 ast::{self, edit::IndentLevel, AstToken}, 24 ast::{self, edit::IndentLevel, AstToken},
25 AstNode, SourceFile, 25 AstNode, Parse, SourceFile,
26 SyntaxKind::{FIELD_EXPR, METHOD_CALL_EXPR}, 26 SyntaxKind::{FIELD_EXPR, METHOD_CALL_EXPR},
27 TextRange, TextSize, 27 TextRange, TextSize,
28}; 28};
29 29
30use text_edit::TextEdit; 30use text_edit::{Indel, TextEdit};
31 31
32use crate::SourceChange; 32use crate::SourceChange;
33 33
34pub(crate) use on_enter::on_enter; 34pub(crate) use on_enter::on_enter;
35 35
36pub(crate) const TRIGGER_CHARS: &str = ".=>"; 36// Don't forget to add new trigger characters to `server_capabilities` in `caps.rs`.
37pub(crate) const TRIGGER_CHARS: &str = ".=>{";
37 38
38// Feature: On Typing Assists 39// Feature: On Typing Assists
39// 40//
@@ -41,6 +42,7 @@ pub(crate) const TRIGGER_CHARS: &str = ".=>";
41// 42//
42// - typing `let =` tries to smartly add `;` if `=` is followed by an existing expression 43// - typing `let =` tries to smartly add `;` if `=` is followed by an existing expression
43// - typing `.` in a chain method call auto-indents 44// - typing `.` in a chain method call auto-indents
45// - typing `{` in front of an expression inserts a closing `}` after the expression
44// 46//
45// VS Code:: 47// VS Code::
46// 48//
@@ -57,28 +59,79 @@ pub(crate) fn on_char_typed(
57 position: FilePosition, 59 position: FilePosition,
58 char_typed: char, 60 char_typed: char,
59) -> Option<SourceChange> { 61) -> Option<SourceChange> {
60 assert!(TRIGGER_CHARS.contains(char_typed)); 62 if !stdx::always!(TRIGGER_CHARS.contains(char_typed)) {
61 let file = &db.parse(position.file_id).tree(); 63 return None;
62 assert_eq!(file.syntax().text().char_at(position.offset), Some(char_typed)); 64 }
65 let file = &db.parse(position.file_id);
66 if !stdx::always!(file.tree().syntax().text().char_at(position.offset) == Some(char_typed)) {
67 return None;
68 }
63 let edit = on_char_typed_inner(file, position.offset, char_typed)?; 69 let edit = on_char_typed_inner(file, position.offset, char_typed)?;
64 Some(SourceChange::from_text_edit(position.file_id, edit)) 70 Some(SourceChange::from_text_edit(position.file_id, edit))
65} 71}
66 72
67fn on_char_typed_inner(file: &SourceFile, offset: TextSize, char_typed: char) -> Option<TextEdit> { 73fn on_char_typed_inner(
68 assert!(TRIGGER_CHARS.contains(char_typed)); 74 file: &Parse<SourceFile>,
75 offset: TextSize,
76 char_typed: char,
77) -> Option<TextEdit> {
78 if !stdx::always!(TRIGGER_CHARS.contains(char_typed)) {
79 return None;
80 }
69 match char_typed { 81 match char_typed {
70 '.' => on_dot_typed(file, offset), 82 '.' => on_dot_typed(&file.tree(), offset),
71 '=' => on_eq_typed(file, offset), 83 '=' => on_eq_typed(&file.tree(), offset),
72 '>' => on_arrow_typed(file, offset), 84 '>' => on_arrow_typed(&file.tree(), offset),
85 '{' => on_opening_brace_typed(file, offset),
73 _ => unreachable!(), 86 _ => unreachable!(),
74 } 87 }
75} 88}
76 89
90/// Inserts a closing `}` when the user types an opening `{`, wrapping an existing expression in a
91/// block.
92fn on_opening_brace_typed(file: &Parse<SourceFile>, offset: TextSize) -> Option<TextEdit> {
93 if !stdx::always!(file.tree().syntax().text().char_at(offset) == Some('{')) {
94 return None;
95 }
96
97 let brace_token = file.tree().syntax().token_at_offset(offset).right_biased()?;
98
99 // Remove the `{` to get a better parse tree, and reparse
100 let file = file.reparse(&Indel::delete(brace_token.text_range()));
101
102 let mut expr: ast::Expr = find_node_at_offset(file.tree().syntax(), offset)?;
103 if expr.syntax().text_range().start() != offset {
104 return None;
105 }
106
107 // Enclose the outermost expression starting at `offset`
108 while let Some(parent) = expr.syntax().parent() {
109 if parent.text_range().start() != expr.syntax().text_range().start() {
110 break;
111 }
112
113 match ast::Expr::cast(parent) {
114 Some(parent) => expr = parent,
115 None => break,
116 }
117 }
118
119 // If it's a statement in a block, we don't know how many statements should be included
120 if ast::ExprStmt::can_cast(expr.syntax().parent()?.kind()) {
121 return None;
122 }
123
124 // Insert `}` right after the expression.
125 Some(TextEdit::insert(expr.syntax().text_range().end() + TextSize::of("{"), "}".to_string()))
126}
127
77/// Returns an edit which should be applied after `=` was typed. Primarily, 128/// Returns an edit which should be applied after `=` was typed. Primarily,
78/// this works when adding `let =`. 129/// this works when adding `let =`.
79// FIXME: use a snippet completion instead of this hack here. 130// FIXME: use a snippet completion instead of this hack here.
80fn on_eq_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> { 131fn on_eq_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
81 assert_eq!(file.syntax().text().char_at(offset), Some('=')); 132 if !stdx::always!(file.syntax().text().char_at(offset) == Some('=')) {
133 return None;
134 }
82 let let_stmt: ast::LetStmt = find_node_at_offset(file.syntax(), offset)?; 135 let let_stmt: ast::LetStmt = find_node_at_offset(file.syntax(), offset)?;
83 if let_stmt.semicolon_token().is_some() { 136 if let_stmt.semicolon_token().is_some() {
84 return None; 137 return None;
@@ -100,7 +153,9 @@ fn on_eq_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
100 153
101/// Returns an edit which should be applied when a dot ('.') is typed on a blank line, indenting the line appropriately. 154/// Returns an edit which should be applied when a dot ('.') is typed on a blank line, indenting the line appropriately.
102fn on_dot_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> { 155fn on_dot_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
103 assert_eq!(file.syntax().text().char_at(offset), Some('.')); 156 if !stdx::always!(file.syntax().text().char_at(offset) == Some('.')) {
157 return None;
158 }
104 let whitespace = 159 let whitespace =
105 file.syntax().token_at_offset(offset).left_biased().and_then(ast::Whitespace::cast)?; 160 file.syntax().token_at_offset(offset).left_biased().and_then(ast::Whitespace::cast)?;
106 161
@@ -129,7 +184,9 @@ fn on_dot_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
129/// Adds a space after an arrow when `fn foo() { ... }` is turned into `fn foo() -> { ... }` 184/// Adds a space after an arrow when `fn foo() { ... }` is turned into `fn foo() -> { ... }`
130fn on_arrow_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> { 185fn on_arrow_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
131 let file_text = file.syntax().text(); 186 let file_text = file.syntax().text();
132 assert_eq!(file_text.char_at(offset), Some('>')); 187 if !stdx::always!(file_text.char_at(offset) == Some('>')) {
188 return None;
189 }
133 let after_arrow = offset + TextSize::of('>'); 190 let after_arrow = offset + TextSize::of('>');
134 if file_text.char_at(after_arrow) != Some('{') { 191 if file_text.char_at(after_arrow) != Some('{') {
135 return None; 192 return None;
@@ -152,7 +209,7 @@ mod tests {
152 let edit = TextEdit::insert(offset, char_typed.to_string()); 209 let edit = TextEdit::insert(offset, char_typed.to_string());
153 edit.apply(&mut before); 210 edit.apply(&mut before);
154 let parse = SourceFile::parse(&before); 211 let parse = SourceFile::parse(&before);
155 on_char_typed_inner(&parse.tree(), offset, char_typed).map(|it| { 212 on_char_typed_inner(&parse, offset, char_typed).map(|it| {
156 it.apply(&mut before); 213 it.apply(&mut before);
157 before.to_string() 214 before.to_string()
158 }) 215 })
@@ -373,4 +430,85 @@ fn main() {
373 fn adds_space_after_return_type() { 430 fn adds_space_after_return_type() {
374 type_char('>', "fn foo() -$0{ 92 }", "fn foo() -> { 92 }") 431 type_char('>', "fn foo() -$0{ 92 }", "fn foo() -> { 92 }")
375 } 432 }
433
434 #[test]
435 fn adds_closing_brace() {
436 type_char(
437 '{',
438 r#"
439fn f() { match () { _ => $0() } }
440 "#,
441 r#"
442fn f() { match () { _ => {()} } }
443 "#,
444 );
445 type_char(
446 '{',
447 r#"
448fn f() { $0() }
449 "#,
450 r#"
451fn f() { {()} }
452 "#,
453 );
454 type_char(
455 '{',
456 r#"
457fn f() { let x = $0(); }
458 "#,
459 r#"
460fn f() { let x = {()}; }
461 "#,
462 );
463 type_char(
464 '{',
465 r#"
466fn f() { let x = $0a.b(); }
467 "#,
468 r#"
469fn f() { let x = {a.b()}; }
470 "#,
471 );
472 type_char(
473 '{',
474 r#"
475const S: () = $0();
476fn f() {}
477 "#,
478 r#"
479const S: () = {()};
480fn f() {}
481 "#,
482 );
483 type_char(
484 '{',
485 r#"
486const S: () = $0a.b();
487fn f() {}
488 "#,
489 r#"
490const S: () = {a.b()};
491fn f() {}
492 "#,
493 );
494 type_char(
495 '{',
496 r#"
497fn f() {
498 match x {
499 0 => $0(),
500 1 => (),
501 }
502}
503 "#,
504 r#"
505fn f() {
506 match x {
507 0 => {()},
508 1 => (),
509 }
510}
511 "#,
512 );
513 }
376} 514}
diff --git a/crates/ide_assists/src/handlers/remove_dbg.rs b/crates/ide_assists/src/handlers/remove_dbg.rs
index 6114091f2..2862cfa9c 100644
--- a/crates/ide_assists/src/handlers/remove_dbg.rs
+++ b/crates/ide_assists/src/handlers/remove_dbg.rs
@@ -1,5 +1,5 @@
1use syntax::{ 1use syntax::{
2 ast::{self, AstNode}, 2 ast::{self, AstNode, AstToken},
3 match_ast, SyntaxElement, TextRange, TextSize, T, 3 match_ast, SyntaxElement, TextRange, TextSize, T,
4}; 4};
5 5
@@ -24,7 +24,39 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
24 let macro_call = ctx.find_node_at_offset::<ast::MacroCall>()?; 24 let macro_call = ctx.find_node_at_offset::<ast::MacroCall>()?;
25 let new_contents = adjusted_macro_contents(&macro_call)?; 25 let new_contents = adjusted_macro_contents(&macro_call)?;
26 26
27 let macro_text_range = macro_call.syntax().text_range(); 27 let parent = macro_call.syntax().parent();
28
29 let macro_text_range = if let Some(it) = parent.as_ref() {
30 if new_contents.is_empty() {
31 match_ast! {
32 match it {
33 ast::BlockExpr(it) => {
34 macro_call.syntax()
35 .prev_sibling_or_token()
36 .and_then(whitespace_start)
37 .map(|start| TextRange::new(start, macro_call.syntax().text_range().end()))
38 .unwrap_or(macro_call.syntax().text_range())
39 },
40 ast::ExprStmt(it) => {
41 let start = it
42 .syntax()
43 .prev_sibling_or_token()
44 .and_then(whitespace_start)
45 .unwrap_or(it.syntax().text_range().start());
46 let end = it.syntax().text_range().end();
47
48 TextRange::new(start, end)
49 },
50 _ => macro_call.syntax().text_range()
51 }
52 }
53 } else {
54 macro_call.syntax().text_range()
55 }
56 } else {
57 macro_call.syntax().text_range()
58 };
59
28 let macro_end = if macro_call.semicolon_token().is_some() { 60 let macro_end = if macro_call.semicolon_token().is_some() {
29 macro_text_range.end() - TextSize::of(';') 61 macro_text_range.end() - TextSize::of(';')
30 } else { 62 } else {
@@ -36,11 +68,22 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
36 "Remove dbg!()", 68 "Remove dbg!()",
37 macro_text_range, 69 macro_text_range,
38 |builder| { 70 |builder| {
39 builder.replace(TextRange::new(macro_text_range.start(), macro_end), new_contents); 71 builder.replace(
72 TextRange::new(macro_text_range.start(), macro_end),
73 if new_contents.is_empty() && parent.and_then(ast::LetStmt::cast).is_some() {
74 ast::make::expr_unit().to_string()
75 } else {
76 new_contents
77 },
78 );
40 }, 79 },
41 ) 80 )
42} 81}
43 82
83fn whitespace_start(it: SyntaxElement) -> Option<TextSize> {
84 Some(it.into_token().and_then(ast::Whitespace::cast)?.syntax().text_range().start())
85}
86
44fn adjusted_macro_contents(macro_call: &ast::MacroCall) -> Option<String> { 87fn adjusted_macro_contents(macro_call: &ast::MacroCall) -> Option<String> {
45 let contents = get_valid_macrocall_contents(&macro_call, "dbg")?; 88 let contents = get_valid_macrocall_contents(&macro_call, "dbg")?;
46 let macro_text_with_brackets = macro_call.token_tree()?.syntax().text(); 89 let macro_text_with_brackets = macro_call.token_tree()?.syntax().text();
@@ -94,15 +137,11 @@ fn get_valid_macrocall_contents(
94 let mut contents_between_brackets = children_with_tokens.collect::<Vec<_>>(); 137 let mut contents_between_brackets = children_with_tokens.collect::<Vec<_>>();
95 let last_child = contents_between_brackets.pop()?; 138 let last_child = contents_between_brackets.pop()?;
96 139
97 if contents_between_brackets.is_empty() { 140 match (first_child.kind(), last_child.kind()) {
98 None 141 (T!['('], T![')']) | (T!['['], T![']']) | (T!['{'], T!['}']) => {
99 } else { 142 Some(contents_between_brackets)
100 match (first_child.kind(), last_child.kind()) {
101 (T!['('], T![')']) | (T!['['], T![']']) | (T!['{'], T!['}']) => {
102 Some(contents_between_brackets)
103 }
104 _ => None,
105 } 143 }
144 _ => None,
106 } 145 }
107} 146}
108 147
@@ -418,4 +457,48 @@ fn main() {
418}"#, 457}"#,
419 ); 458 );
420 } 459 }
460
461 #[test]
462 fn test_remove_empty_dbg() {
463 check_assist(remove_dbg, r#"fn foo() { $0dbg!(); }"#, r#"fn foo() { }"#);
464 check_assist(
465 remove_dbg,
466 r#"
467fn foo() {
468 $0dbg!();
469}
470"#,
471 r#"
472fn foo() {
473}
474"#,
475 );
476 check_assist(
477 remove_dbg,
478 r#"
479fn foo() {
480 let test = $0dbg!();
481}"#,
482 r#"
483fn foo() {
484 let test = ();
485}"#,
486 );
487 check_assist(
488 remove_dbg,
489 r#"
490fn foo() {
491 let t = {
492 println!("Hello, world");
493 $0dbg!()
494 };
495}"#,
496 r#"
497fn foo() {
498 let t = {
499 println!("Hello, world");
500 };
501}"#,
502 );
503 }
421} 504}
diff --git a/crates/rust-analyzer/src/caps.rs b/crates/rust-analyzer/src/caps.rs
index 7a5bcb8c7..3c87782f2 100644
--- a/crates/rust-analyzer/src/caps.rs
+++ b/crates/rust-analyzer/src/caps.rs
@@ -57,7 +57,7 @@ pub fn server_capabilities(client_caps: &ClientCapabilities) -> ServerCapabiliti
57 document_range_formatting_provider: None, 57 document_range_formatting_provider: None,
58 document_on_type_formatting_provider: Some(DocumentOnTypeFormattingOptions { 58 document_on_type_formatting_provider: Some(DocumentOnTypeFormattingOptions {
59 first_trigger_character: "=".to_string(), 59 first_trigger_character: "=".to_string(),
60 more_trigger_character: Some(vec![".".to_string(), ">".to_string()]), 60 more_trigger_character: Some(vec![".".to_string(), ">".to_string(), "{".to_string()]),
61 }), 61 }),
62 selection_range_provider: Some(SelectionRangeProviderCapability::Simple(true)), 62 selection_range_provider: Some(SelectionRangeProviderCapability::Simple(true)),
63 folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)), 63 folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)),
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index 4d10a2ead..31d8c487b 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -231,7 +231,6 @@ pub(crate) fn handle_on_enter(
231 Ok(Some(edit)) 231 Ok(Some(edit))
232} 232}
233 233
234// Don't forget to add new trigger characters to `ServerCapabilities` in `caps.rs`.
235pub(crate) fn handle_on_type_formatting( 234pub(crate) fn handle_on_type_formatting(
236 snap: GlobalStateSnapshot, 235 snap: GlobalStateSnapshot,
237 params: lsp_types::DocumentOnTypeFormattingParams, 236 params: lsp_types::DocumentOnTypeFormattingParams,
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index c3820944b..2ac31d981 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -497,7 +497,8 @@ pub(crate) fn folding_range(
497 | FoldKind::Block 497 | FoldKind::Block
498 | FoldKind::ArgList 498 | FoldKind::ArgList
499 | FoldKind::Consts 499 | FoldKind::Consts
500 | FoldKind::Statics => None, 500 | FoldKind::Statics
501 | FoldKind::Array => None,
501 }; 502 };
502 503
503 let range = range(line_index, fold.range); 504 let range = range(line_index, fold.range);