diff options
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 | }; |
64 | use itertools::Itertools; | 65 | use itertools::Itertools; |
65 | use rustc_hash::FxHashSet; | 66 | use 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::{ | |||
8 | use crate::{ | 8 | use 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 | ||
39 | impl TyExt for Ty { | 42 | impl 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 | ||
243 | pub trait ProjectionTyExt { | 276 | pub trait ProjectionTyExt { |
@@ -260,3 +293,13 @@ impl ProjectionTyExt for ProjectionTy { | |||
260 | } | 293 | } |
261 | } | 294 | } |
262 | } | 295 | } |
296 | |||
297 | pub trait TraitRefExt { | ||
298 | fn hir_trait_id(&self) -> TraitId; | ||
299 | } | ||
300 | |||
301 | impl 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 | ||
30 | pub struct HirFormatter<'a> { | 30 | pub 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 | ||
795 | impl TraitRef { | 795 | fn 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 | ||
817 | impl HirDisplay for TraitRef { | 815 | impl 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::{ | |||
11 | use hir_expand::name::Name; | 11 | use hir_expand::name::Name; |
12 | 12 | ||
13 | use crate::{ | 13 | use 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 | ||
17 | use super::{ExprOrPatId, InferenceContext, TraitRef}; | 18 | use 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}; | |||
8 | use super::{DomainGoal, InferenceContext}; | 8 | use super::{DomainGoal, InferenceContext}; |
9 | use crate::{ | 9 | use 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 | ||
14 | impl<'a> InferenceContext<'a> { | 15 | impl<'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 | ||
42 | pub use autoderef::autoderef; | 42 | pub use autoderef::autoderef; |
43 | pub use builder::TyBuilder; | 43 | pub use builder::TyBuilder; |
44 | pub use chalk_ext::{ProjectionTyExt, TyExt}; | 44 | pub use chalk_ext::*; |
45 | pub use infer::{could_unify, InferenceResult}; | 45 | pub use infer::{could_unify, InferenceResult}; |
46 | pub use lower::{ | 46 | pub 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 | ||
110 | impl TraitRef { | 110 | // FIXME: get rid of this |
111 | pub fn hir_trait_id(&self) -> TraitId { | 111 | pub 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| { | |
116 | impl<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 | ||
171 | impl Ty { | 167 | impl 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)] |
204 | pub enum ImplTraitId { | 170 | pub 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 | ||
10 | use crate::{ | 10 | use 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 | ||
15 | use self::chalk::{from_chalk, Interner, ToChalk}; | 15 | use 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 | }; |
27 | use mapping::{ | 27 | use 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; | |||
10 | use hir_def::{GenericDefId, TypeAliasId}; | 10 | use hir_def::{GenericDefId, TypeAliasId}; |
11 | 11 | ||
12 | use crate::{ | 12 | use 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 | ||
18 | use super::interner::*; | 18 | use 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 | ||
32 | impl ProjectionTy { | 32 | impl 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 { | |||
282 | pub struct Substitution(SmallVec<[GenericArg; 2]>); | 282 | pub struct Substitution(SmallVec<[GenericArg; 2]>); |
283 | 283 | ||
284 | impl Substitution { | 284 | impl 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 | ||
415 | impl TraitRef { | 415 | impl 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 | ||
472 | impl<T> InEnvironment<T> { | 472 | impl<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 | }; |
17 | use hir_expand::name::{name, Name}; | 17 | use hir_expand::name::{name, Name}; |
18 | 18 | ||
19 | use crate::{db::HirDatabase, Interner, Substitution, TraitRef, TyKind, TypeWalk, WhereClause}; | 19 | use crate::{ |
20 | db::HirDatabase, Interner, Substitution, TraitRef, TraitRefExt, TyKind, TypeWalk, WhereClause, | ||
21 | }; | ||
20 | 22 | ||
21 | fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { | 23 | fn 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#" | ||
474 | const 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::{ | |||
22 | use syntax::{ | 22 | use 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 | ||
30 | use text_edit::TextEdit; | 30 | use text_edit::{Indel, TextEdit}; |
31 | 31 | ||
32 | use crate::SourceChange; | 32 | use crate::SourceChange; |
33 | 33 | ||
34 | pub(crate) use on_enter::on_enter; | 34 | pub(crate) use on_enter::on_enter; |
35 | 35 | ||
36 | pub(crate) const TRIGGER_CHARS: &str = ".=>"; | 36 | // Don't forget to add new trigger characters to `server_capabilities` in `caps.rs`. |
37 | pub(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 | ||
67 | fn on_char_typed_inner(file: &SourceFile, offset: TextSize, char_typed: char) -> Option<TextEdit> { | 73 | fn 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. | ||
92 | fn 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. |
80 | fn on_eq_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> { | 131 | fn 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. |
102 | fn on_dot_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> { | 155 | fn 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() -> { ... }` |
130 | fn on_arrow_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> { | 185 | fn 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#" | ||
439 | fn f() { match () { _ => $0() } } | ||
440 | "#, | ||
441 | r#" | ||
442 | fn f() { match () { _ => {()} } } | ||
443 | "#, | ||
444 | ); | ||
445 | type_char( | ||
446 | '{', | ||
447 | r#" | ||
448 | fn f() { $0() } | ||
449 | "#, | ||
450 | r#" | ||
451 | fn f() { {()} } | ||
452 | "#, | ||
453 | ); | ||
454 | type_char( | ||
455 | '{', | ||
456 | r#" | ||
457 | fn f() { let x = $0(); } | ||
458 | "#, | ||
459 | r#" | ||
460 | fn f() { let x = {()}; } | ||
461 | "#, | ||
462 | ); | ||
463 | type_char( | ||
464 | '{', | ||
465 | r#" | ||
466 | fn f() { let x = $0a.b(); } | ||
467 | "#, | ||
468 | r#" | ||
469 | fn f() { let x = {a.b()}; } | ||
470 | "#, | ||
471 | ); | ||
472 | type_char( | ||
473 | '{', | ||
474 | r#" | ||
475 | const S: () = $0(); | ||
476 | fn f() {} | ||
477 | "#, | ||
478 | r#" | ||
479 | const S: () = {()}; | ||
480 | fn f() {} | ||
481 | "#, | ||
482 | ); | ||
483 | type_char( | ||
484 | '{', | ||
485 | r#" | ||
486 | const S: () = $0a.b(); | ||
487 | fn f() {} | ||
488 | "#, | ||
489 | r#" | ||
490 | const S: () = {a.b()}; | ||
491 | fn f() {} | ||
492 | "#, | ||
493 | ); | ||
494 | type_char( | ||
495 | '{', | ||
496 | r#" | ||
497 | fn f() { | ||
498 | match x { | ||
499 | 0 => $0(), | ||
500 | 1 => (), | ||
501 | } | ||
502 | } | ||
503 | "#, | ||
504 | r#" | ||
505 | fn 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 @@ | |||
1 | use syntax::{ | 1 | use 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(¯o_call)?; | 25 | let new_contents = adjusted_macro_contents(¯o_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 | ||
83 | fn whitespace_start(it: SyntaxElement) -> Option<TextSize> { | ||
84 | Some(it.into_token().and_then(ast::Whitespace::cast)?.syntax().text_range().start()) | ||
85 | } | ||
86 | |||
44 | fn adjusted_macro_contents(macro_call: &ast::MacroCall) -> Option<String> { | 87 | fn adjusted_macro_contents(macro_call: &ast::MacroCall) -> Option<String> { |
45 | let contents = get_valid_macrocall_contents(¯o_call, "dbg")?; | 88 | let contents = get_valid_macrocall_contents(¯o_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#" | ||
467 | fn foo() { | ||
468 | $0dbg!(); | ||
469 | } | ||
470 | "#, | ||
471 | r#" | ||
472 | fn foo() { | ||
473 | } | ||
474 | "#, | ||
475 | ); | ||
476 | check_assist( | ||
477 | remove_dbg, | ||
478 | r#" | ||
479 | fn foo() { | ||
480 | let test = $0dbg!(); | ||
481 | }"#, | ||
482 | r#" | ||
483 | fn foo() { | ||
484 | let test = (); | ||
485 | }"#, | ||
486 | ); | ||
487 | check_assist( | ||
488 | remove_dbg, | ||
489 | r#" | ||
490 | fn foo() { | ||
491 | let t = { | ||
492 | println!("Hello, world"); | ||
493 | $0dbg!() | ||
494 | }; | ||
495 | }"#, | ||
496 | r#" | ||
497 | fn 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`. | ||
235 | pub(crate) fn handle_on_type_formatting( | 234 | pub(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); |