aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock4
-rw-r--r--crates/hir/src/display.rs2
-rw-r--r--crates/hir/src/lib.rs146
-rw-r--r--crates/hir_def/src/find_path.rs56
-rw-r--r--crates/hir_def/src/nameres.rs17
-rw-r--r--crates/hir_def/src/nameres/path_resolution.rs2
-rw-r--r--crates/hir_def/src/resolver.rs18
-rw-r--r--crates/hir_ty/src/autoderef.rs51
-rw-r--r--crates/hir_ty/src/db.rs11
-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.rs6
-rw-r--r--crates/hir_ty/src/infer/expr.rs21
-rw-r--r--crates/hir_ty/src/infer/unify.rs66
-rw-r--r--crates/hir_ty/src/lib.rs90
-rw-r--r--crates/hir_ty/src/lower.rs78
-rw-r--r--crates/hir_ty/src/method_resolution.rs53
-rw-r--r--crates/hir_ty/src/tests/regression.rs13
-rw-r--r--crates/hir_ty/src/tests/traits.rs46
-rw-r--r--crates/hir_ty/src/traits.rs17
-rw-r--r--crates/hir_ty/src/traits/chalk.rs10
-rw-r--r--crates/hir_ty/src/traits/chalk/mapping.rs124
-rw-r--r--crates/hir_ty/src/utils.rs2
-rw-r--r--crates/ide/src/lib.rs10
-rw-r--r--crates/ide/src/move_item.rs620
-rw-r--r--crates/ide_assists/src/handlers/merge_imports.rs49
-rw-r--r--crates/ide_assists/src/handlers/unmerge_use.rs30
-rw-r--r--crates/ide_db/src/helpers/insert_use.rs8
-rw-r--r--crates/rust-analyzer/src/config.rs3
-rw-r--r--crates/rust-analyzer/src/handlers.rs19
-rw-r--r--crates/rust-analyzer/src/lsp_ext.rs22
-rw-r--r--crates/rust-analyzer/src/main_loop.rs1
-rw-r--r--crates/rust-analyzer/src/to_proto.rs18
-rw-r--r--crates/syntax/Cargo.toml2
-rw-r--r--crates/syntax/src/ast/edit.rs46
-rw-r--r--crates/syntax/src/ast/edit_in_place.rs44
-rw-r--r--crates/syntax/src/ast/make.rs2
-rw-r--r--crates/syntax/src/ted.rs28
-rw-r--r--docs/dev/README.md3
-rw-r--r--docs/dev/lsp-extensions.md28
-rw-r--r--docs/user/manual.adoc14
-rw-r--r--editors/code/package.json10
-rw-r--r--editors/code/src/commands.ts45
-rw-r--r--editors/code/src/lsp_ext.ts13
-rw-r--r--editors/code/src/main.ts2
45 files changed, 1494 insertions, 404 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 9f013c275..19ee689cb 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1324,9 +1324,9 @@ checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581"
1324 1324
1325[[package]] 1325[[package]]
1326name = "rowan" 1326name = "rowan"
1327version = "0.13.0-pre.2" 1327version = "0.13.0-pre.3"
1328source = "registry+https://github.com/rust-lang/crates.io-index" 1328source = "registry+https://github.com/rust-lang/crates.io-index"
1329checksum = "8f300be7fa17c3fa563d2bc6ab5b1a8d5163162f9111599eda4f86a563714724" 1329checksum = "77d315d6f2e33f294412faa47f41b56bdb3fce72c999d384b5e78c8d21551b13"
1330dependencies = [ 1330dependencies = [
1331 "countme", 1331 "countme",
1332 "hashbrown", 1332 "hashbrown",
diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs
index 9f6d7be48..97a78ca25 100644
--- a/crates/hir/src/display.rs
+++ b/crates/hir/src/display.rs
@@ -217,7 +217,7 @@ impl HirDisplay for Variant {
217 217
218impl HirDisplay for Type { 218impl HirDisplay for Type {
219 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { 219 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
220 self.ty.value.hir_fmt(f) 220 self.ty.hir_fmt(f)
221 } 221 }
222} 222}
223 223
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index e3ac37e4c..30b96d7e2 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -56,9 +56,9 @@ use hir_ty::{
56 primitive::UintTy, 56 primitive::UintTy,
57 to_assoc_type_id, 57 to_assoc_type_id,
58 traits::{FnTrait, Solution, SolutionVariables}, 58 traits::{FnTrait, Solution, SolutionVariables},
59 AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, Cast, DebruijnIndex, 59 AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast,
60 InEnvironment, Interner, ProjectionTy, Scalar, Substitution, Ty, TyDefId, TyKind, 60 DebruijnIndex, InEnvironment, Interner, ProjectionTy, QuantifiedWhereClause, Scalar,
61 TyVariableKind, WhereClause, 61 Substitution, TraitEnvironment, Ty, TyDefId, TyKind, TyVariableKind, WhereClause,
62}; 62};
63use itertools::Itertools; 63use itertools::Itertools;
64use rustc_hash::FxHashSet; 64use rustc_hash::FxHashSet;
@@ -851,13 +851,7 @@ impl Function {
851 .iter() 851 .iter()
852 .enumerate() 852 .enumerate()
853 .map(|(idx, type_ref)| { 853 .map(|(idx, type_ref)| {
854 let ty = Type { 854 let ty = Type { krate, env: environment.clone(), ty: ctx.lower_ty(type_ref) };
855 krate,
856 ty: InEnvironment {
857 value: ctx.lower_ty(type_ref),
858 environment: environment.clone(),
859 },
860 };
861 Param { func: self, ty, idx } 855 Param { func: self, ty, idx }
862 }) 856 })
863 .collect() 857 .collect()
@@ -1460,7 +1454,7 @@ impl TypeParam {
1460 pub fn trait_bounds(self, db: &dyn HirDatabase) -> Vec<Trait> { 1454 pub fn trait_bounds(self, db: &dyn HirDatabase) -> Vec<Trait> {
1461 db.generic_predicates_for_param(self.id) 1455 db.generic_predicates_for_param(self.id)
1462 .into_iter() 1456 .into_iter()
1463 .filter_map(|pred| match &pred.value { 1457 .filter_map(|pred| match &pred.skip_binders().skip_binders() {
1464 hir_ty::WhereClause::Implemented(trait_ref) => { 1458 hir_ty::WhereClause::Implemented(trait_ref) => {
1465 Some(Trait::from(trait_ref.hir_trait_id())) 1459 Some(Trait::from(trait_ref.hir_trait_id()))
1466 } 1460 }
@@ -1540,8 +1534,8 @@ impl Impl {
1540 inherent.all_impls().chain(trait_.all_impls()).map(Self::from).collect() 1534 inherent.all_impls().chain(trait_.all_impls()).map(Self::from).collect()
1541 } 1535 }
1542 1536
1543 pub fn all_for_type(db: &dyn HirDatabase, Type { krate, ty }: Type) -> Vec<Impl> { 1537 pub fn all_for_type(db: &dyn HirDatabase, Type { krate, ty, .. }: Type) -> Vec<Impl> {
1544 let def_crates = match ty.value.def_crates(db, krate) { 1538 let def_crates = match ty.def_crates(db, krate) {
1545 Some(def_crates) => def_crates, 1539 Some(def_crates) => def_crates,
1546 None => return Vec::new(), 1540 None => return Vec::new(),
1547 }; 1541 };
@@ -1549,14 +1543,14 @@ impl Impl {
1549 let filter = |impl_def: &Impl| { 1543 let filter = |impl_def: &Impl| {
1550 let target_ty = impl_def.target_ty(db); 1544 let target_ty = impl_def.target_ty(db);
1551 let rref = target_ty.remove_ref(); 1545 let rref = target_ty.remove_ref();
1552 ty.value.equals_ctor(rref.as_ref().map_or(&target_ty.ty.value, |it| &it.ty.value)) 1546 ty.equals_ctor(rref.as_ref().map_or(&target_ty.ty, |it| &it.ty))
1553 }; 1547 };
1554 1548
1555 let mut all = Vec::new(); 1549 let mut all = Vec::new();
1556 def_crates.iter().for_each(|&id| { 1550 def_crates.iter().for_each(|&id| {
1557 all.extend(db.inherent_impls_in_crate(id).all_impls().map(Self::from).filter(filter)) 1551 all.extend(db.inherent_impls_in_crate(id).all_impls().map(Self::from).filter(filter))
1558 }); 1552 });
1559 let fp = TyFingerprint::for_impl(&ty.value); 1553 let fp = TyFingerprint::for_impl(&ty);
1560 for id in def_crates 1554 for id in def_crates
1561 .iter() 1555 .iter()
1562 .flat_map(|&id| Crate { id }.transitive_reverse_dependencies(db)) 1556 .flat_map(|&id| Crate { id }.transitive_reverse_dependencies(db))
@@ -1643,7 +1637,8 @@ impl Impl {
1643#[derive(Clone, PartialEq, Eq, Debug)] 1637#[derive(Clone, PartialEq, Eq, Debug)]
1644pub struct Type { 1638pub struct Type {
1645 krate: CrateId, 1639 krate: CrateId,
1646 ty: InEnvironment<Ty>, 1640 env: Arc<TraitEnvironment>,
1641 ty: Ty,
1647} 1642}
1648 1643
1649impl Type { 1644impl Type {
@@ -1663,14 +1658,14 @@ impl Type {
1663 ) -> Type { 1658 ) -> Type {
1664 let environment = 1659 let environment =
1665 resolver.generic_def().map_or_else(Default::default, |d| db.trait_environment(d)); 1660 resolver.generic_def().map_or_else(Default::default, |d| db.trait_environment(d));
1666 Type { krate, ty: InEnvironment { value: ty, environment } } 1661 Type { krate, env: environment, ty }
1667 } 1662 }
1668 1663
1669 fn new(db: &dyn HirDatabase, krate: CrateId, lexical_env: impl HasResolver, ty: Ty) -> Type { 1664 fn new(db: &dyn HirDatabase, krate: CrateId, lexical_env: impl HasResolver, ty: Ty) -> Type {
1670 let resolver = lexical_env.resolver(db.upcast()); 1665 let resolver = lexical_env.resolver(db.upcast());
1671 let environment = 1666 let environment =
1672 resolver.generic_def().map_or_else(Default::default, |d| db.trait_environment(d)); 1667 resolver.generic_def().map_or_else(Default::default, |d| db.trait_environment(d));
1673 Type { krate, ty: InEnvironment { value: ty, environment } } 1668 Type { krate, env: environment, ty }
1674 } 1669 }
1675 1670
1676 fn from_def( 1671 fn from_def(
@@ -1684,29 +1679,29 @@ impl Type {
1684 } 1679 }
1685 1680
1686 pub fn is_unit(&self) -> bool { 1681 pub fn is_unit(&self) -> bool {
1687 matches!(self.ty.value.interned(&Interner), TyKind::Tuple(0, ..)) 1682 matches!(self.ty.interned(&Interner), TyKind::Tuple(0, ..))
1688 } 1683 }
1689 pub fn is_bool(&self) -> bool { 1684 pub fn is_bool(&self) -> bool {
1690 matches!(self.ty.value.interned(&Interner), TyKind::Scalar(Scalar::Bool)) 1685 matches!(self.ty.interned(&Interner), TyKind::Scalar(Scalar::Bool))
1691 } 1686 }
1692 1687
1693 pub fn is_mutable_reference(&self) -> bool { 1688 pub fn is_mutable_reference(&self) -> bool {
1694 matches!(self.ty.value.interned(&Interner), TyKind::Ref(hir_ty::Mutability::Mut, ..)) 1689 matches!(self.ty.interned(&Interner), TyKind::Ref(hir_ty::Mutability::Mut, ..))
1695 } 1690 }
1696 1691
1697 pub fn is_usize(&self) -> bool { 1692 pub fn is_usize(&self) -> bool {
1698 matches!(self.ty.value.interned(&Interner), TyKind::Scalar(Scalar::Uint(UintTy::Usize))) 1693 matches!(self.ty.interned(&Interner), TyKind::Scalar(Scalar::Uint(UintTy::Usize)))
1699 } 1694 }
1700 1695
1701 pub fn remove_ref(&self) -> Option<Type> { 1696 pub fn remove_ref(&self) -> Option<Type> {
1702 match &self.ty.value.interned(&Interner) { 1697 match &self.ty.interned(&Interner) {
1703 TyKind::Ref(.., ty) => Some(self.derived(ty.clone())), 1698 TyKind::Ref(.., ty) => Some(self.derived(ty.clone())),
1704 _ => None, 1699 _ => None,
1705 } 1700 }
1706 } 1701 }
1707 1702
1708 pub fn is_unknown(&self) -> bool { 1703 pub fn is_unknown(&self) -> bool {
1709 self.ty.value.is_unknown() 1704 self.ty.is_unknown()
1710 } 1705 }
1711 1706
1712 /// Checks that particular type `ty` implements `std::future::Future`. 1707 /// Checks that particular type `ty` implements `std::future::Future`.
@@ -1723,11 +1718,12 @@ impl Type {
1723 None => return false, 1718 None => return false,
1724 }; 1719 };
1725 1720
1726 let canonical_ty = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) }; 1721 let canonical_ty =
1722 Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(&Interner) };
1727 method_resolution::implements_trait( 1723 method_resolution::implements_trait(
1728 &canonical_ty, 1724 &canonical_ty,
1729 db, 1725 db,
1730 self.ty.environment.clone(), 1726 self.env.clone(),
1731 krate, 1727 krate,
1732 std_future_trait, 1728 std_future_trait,
1733 ) 1729 )
@@ -1745,11 +1741,12 @@ impl Type {
1745 None => return false, 1741 None => return false,
1746 }; 1742 };
1747 1743
1748 let canonical_ty = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) }; 1744 let canonical_ty =
1745 Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(&Interner) };
1749 method_resolution::implements_trait_unique( 1746 method_resolution::implements_trait_unique(
1750 &canonical_ty, 1747 &canonical_ty,
1751 db, 1748 db,
1752 self.ty.environment.clone(), 1749 self.env.clone(),
1753 krate, 1750 krate,
1754 fnonce_trait, 1751 fnonce_trait,
1755 ) 1752 )
@@ -1759,17 +1756,14 @@ impl Type {
1759 let trait_ref = hir_ty::TraitRef { 1756 let trait_ref = hir_ty::TraitRef {
1760 trait_id: hir_ty::to_chalk_trait_id(trait_.id), 1757 trait_id: hir_ty::to_chalk_trait_id(trait_.id),
1761 substitution: Substitution::build_for_def(db, trait_.id) 1758 substitution: Substitution::build_for_def(db, trait_.id)
1762 .push(self.ty.value.clone()) 1759 .push(self.ty.clone())
1763 .fill(args.iter().map(|t| t.ty.value.clone())) 1760 .fill(args.iter().map(|t| t.ty.clone()))
1764 .build(), 1761 .build(),
1765 }; 1762 };
1766 1763
1767 let goal = Canonical { 1764 let goal = Canonical {
1768 value: hir_ty::InEnvironment::new( 1765 value: hir_ty::InEnvironment::new(self.env.env.clone(), trait_ref.cast(&Interner)),
1769 self.ty.environment.clone(), 1766 binders: CanonicalVarKinds::empty(&Interner),
1770 trait_ref.cast(&Interner),
1771 ),
1772 kinds: Arc::new([]),
1773 }; 1767 };
1774 1768
1775 db.trait_solve(self.krate, goal).is_some() 1769 db.trait_solve(self.krate, goal).is_some()
@@ -1783,12 +1777,12 @@ impl Type {
1783 alias: TypeAlias, 1777 alias: TypeAlias,
1784 ) -> Option<Type> { 1778 ) -> Option<Type> {
1785 let subst = Substitution::build_for_def(db, trait_.id) 1779 let subst = Substitution::build_for_def(db, trait_.id)
1786 .push(self.ty.value.clone()) 1780 .push(self.ty.clone())
1787 .fill(args.iter().map(|t| t.ty.value.clone())) 1781 .fill(args.iter().map(|t| t.ty.clone()))
1788 .build(); 1782 .build();
1789 let goal = Canonical { 1783 let goal = Canonical::new(
1790 value: InEnvironment::new( 1784 InEnvironment::new(
1791 self.ty.environment.clone(), 1785 self.env.env.clone(),
1792 AliasEq { 1786 AliasEq {
1793 alias: AliasTy::Projection(ProjectionTy { 1787 alias: AliasTy::Projection(ProjectionTy {
1794 associated_ty_id: to_assoc_type_id(alias.id), 1788 associated_ty_id: to_assoc_type_id(alias.id),
@@ -1799,8 +1793,8 @@ impl Type {
1799 } 1793 }
1800 .cast(&Interner), 1794 .cast(&Interner),
1801 ), 1795 ),
1802 kinds: Arc::new([TyVariableKind::General]), 1796 [TyVariableKind::General].iter().copied(),
1803 }; 1797 );
1804 1798
1805 match db.trait_solve(self.krate, goal)? { 1799 match db.trait_solve(self.krate, goal)? {
1806 Solution::Unique(SolutionVariables(subst)) => { 1800 Solution::Unique(SolutionVariables(subst)) => {
@@ -1820,22 +1814,22 @@ impl Type {
1820 } 1814 }
1821 1815
1822 pub fn as_callable(&self, db: &dyn HirDatabase) -> Option<Callable> { 1816 pub fn as_callable(&self, db: &dyn HirDatabase) -> Option<Callable> {
1823 let def = self.ty.value.callable_def(db); 1817 let def = self.ty.callable_def(db);
1824 1818
1825 let sig = self.ty.value.callable_sig(db)?; 1819 let sig = self.ty.callable_sig(db)?;
1826 Some(Callable { ty: self.clone(), sig, def, is_bound_method: false }) 1820 Some(Callable { ty: self.clone(), sig, def, is_bound_method: false })
1827 } 1821 }
1828 1822
1829 pub fn is_closure(&self) -> bool { 1823 pub fn is_closure(&self) -> bool {
1830 matches!(&self.ty.value.interned(&Interner), TyKind::Closure { .. }) 1824 matches!(&self.ty.interned(&Interner), TyKind::Closure { .. })
1831 } 1825 }
1832 1826
1833 pub fn is_fn(&self) -> bool { 1827 pub fn is_fn(&self) -> bool {
1834 matches!(&self.ty.value.interned(&Interner), TyKind::FnDef(..) | TyKind::Function { .. }) 1828 matches!(&self.ty.interned(&Interner), TyKind::FnDef(..) | TyKind::Function { .. })
1835 } 1829 }
1836 1830
1837 pub fn is_packed(&self, db: &dyn HirDatabase) -> bool { 1831 pub fn is_packed(&self, db: &dyn HirDatabase) -> bool {
1838 let adt_id = match self.ty.value.interned(&Interner) { 1832 let adt_id = match self.ty.interned(&Interner) {
1839 &TyKind::Adt(hir_ty::AdtId(adt_id), ..) => adt_id, 1833 &TyKind::Adt(hir_ty::AdtId(adt_id), ..) => adt_id,
1840 _ => return false, 1834 _ => return false,
1841 }; 1835 };
@@ -1848,11 +1842,11 @@ impl Type {
1848 } 1842 }
1849 1843
1850 pub fn is_raw_ptr(&self) -> bool { 1844 pub fn is_raw_ptr(&self) -> bool {
1851 matches!(&self.ty.value.interned(&Interner), TyKind::Raw(..)) 1845 matches!(&self.ty.interned(&Interner), TyKind::Raw(..))
1852 } 1846 }
1853 1847
1854 pub fn contains_unknown(&self) -> bool { 1848 pub fn contains_unknown(&self) -> bool {
1855 return go(&self.ty.value); 1849 return go(&self.ty);
1856 1850
1857 fn go(ty: &Ty) -> bool { 1851 fn go(ty: &Ty) -> bool {
1858 match ty.interned(&Interner) { 1852 match ty.interned(&Interner) {
@@ -1884,7 +1878,7 @@ impl Type {
1884 } 1878 }
1885 1879
1886 pub fn fields(&self, db: &dyn HirDatabase) -> Vec<(Field, Type)> { 1880 pub fn fields(&self, db: &dyn HirDatabase) -> Vec<(Field, Type)> {
1887 let (variant_id, substs) = match self.ty.value.interned(&Interner) { 1881 let (variant_id, substs) = match self.ty.interned(&Interner) {
1888 &TyKind::Adt(hir_ty::AdtId(AdtId::StructId(s)), ref substs) => (s.into(), substs), 1882 &TyKind::Adt(hir_ty::AdtId(AdtId::StructId(s)), ref substs) => (s.into(), substs),
1889 &TyKind::Adt(hir_ty::AdtId(AdtId::UnionId(u)), ref substs) => (u.into(), substs), 1883 &TyKind::Adt(hir_ty::AdtId(AdtId::UnionId(u)), ref substs) => (u.into(), substs),
1890 _ => return Vec::new(), 1884 _ => return Vec::new(),
@@ -1901,7 +1895,7 @@ impl Type {
1901 } 1895 }
1902 1896
1903 pub fn tuple_fields(&self, _db: &dyn HirDatabase) -> Vec<Type> { 1897 pub fn tuple_fields(&self, _db: &dyn HirDatabase) -> Vec<Type> {
1904 if let TyKind::Tuple(_, substs) = &self.ty.value.interned(&Interner) { 1898 if let TyKind::Tuple(_, substs) = &self.ty.interned(&Interner) {
1905 substs.iter().map(|ty| self.derived(ty.clone())).collect() 1899 substs.iter().map(|ty| self.derived(ty.clone())).collect()
1906 } else { 1900 } else {
1907 Vec::new() 1901 Vec::new()
@@ -1911,9 +1905,10 @@ impl Type {
1911 pub fn autoderef<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Type> + 'a { 1905 pub fn autoderef<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Type> + 'a {
1912 // There should be no inference vars in types passed here 1906 // There should be no inference vars in types passed here
1913 // FIXME check that? 1907 // FIXME check that?
1914 let canonical = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) }; 1908 let canonical =
1915 let environment = self.ty.environment.clone(); 1909 Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(&Interner) };
1916 let ty = InEnvironment { value: canonical, environment }; 1910 let environment = self.env.env.clone();
1911 let ty = InEnvironment { goal: canonical, environment };
1917 autoderef(db, Some(self.krate), ty) 1912 autoderef(db, Some(self.krate), ty)
1918 .map(|canonical| canonical.value) 1913 .map(|canonical| canonical.value)
1919 .map(move |ty| self.derived(ty)) 1914 .map(move |ty| self.derived(ty))
@@ -1927,10 +1922,10 @@ impl Type {
1927 krate: Crate, 1922 krate: Crate,
1928 mut callback: impl FnMut(AssocItem) -> Option<T>, 1923 mut callback: impl FnMut(AssocItem) -> Option<T>,
1929 ) -> Option<T> { 1924 ) -> Option<T> {
1930 for krate in self.ty.value.def_crates(db, krate.id)? { 1925 for krate in self.ty.def_crates(db, krate.id)? {
1931 let impls = db.inherent_impls_in_crate(krate); 1926 let impls = db.inherent_impls_in_crate(krate);
1932 1927
1933 for impl_def in impls.for_self_ty(&self.ty.value) { 1928 for impl_def in impls.for_self_ty(&self.ty) {
1934 for &item in db.impl_data(*impl_def).items.iter() { 1929 for &item in db.impl_data(*impl_def).items.iter() {
1935 if let Some(result) = callback(item.into()) { 1930 if let Some(result) = callback(item.into()) {
1936 return Some(result); 1931 return Some(result);
@@ -1943,7 +1938,6 @@ impl Type {
1943 1938
1944 pub fn type_parameters(&self) -> impl Iterator<Item = Type> + '_ { 1939 pub fn type_parameters(&self) -> impl Iterator<Item = Type> + '_ {
1945 self.ty 1940 self.ty
1946 .value
1947 .strip_references() 1941 .strip_references()
1948 .substs() 1942 .substs()
1949 .into_iter() 1943 .into_iter()
@@ -1962,9 +1956,10 @@ impl Type {
1962 // There should be no inference vars in types passed here 1956 // There should be no inference vars in types passed here
1963 // FIXME check that? 1957 // FIXME check that?
1964 // FIXME replace Unknown by bound vars here 1958 // FIXME replace Unknown by bound vars here
1965 let canonical = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) }; 1959 let canonical =
1960 Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(&Interner) };
1966 1961
1967 let env = self.ty.environment.clone(); 1962 let env = self.env.clone();
1968 let krate = krate.id; 1963 let krate = krate.id;
1969 1964
1970 method_resolution::iterate_method_candidates( 1965 method_resolution::iterate_method_candidates(
@@ -1993,9 +1988,10 @@ impl Type {
1993 // There should be no inference vars in types passed here 1988 // There should be no inference vars in types passed here
1994 // FIXME check that? 1989 // FIXME check that?
1995 // FIXME replace Unknown by bound vars here 1990 // FIXME replace Unknown by bound vars here
1996 let canonical = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) }; 1991 let canonical =
1992 Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(&Interner) };
1997 1993
1998 let env = self.ty.environment.clone(); 1994 let env = self.env.clone();
1999 let krate = krate.id; 1995 let krate = krate.id;
2000 1996
2001 method_resolution::iterate_method_candidates( 1997 method_resolution::iterate_method_candidates(
@@ -2011,18 +2007,18 @@ impl Type {
2011 } 2007 }
2012 2008
2013 pub fn as_adt(&self) -> Option<Adt> { 2009 pub fn as_adt(&self) -> Option<Adt> {
2014 let (adt, _subst) = self.ty.value.as_adt()?; 2010 let (adt, _subst) = self.ty.as_adt()?;
2015 Some(adt.into()) 2011 Some(adt.into())
2016 } 2012 }
2017 2013
2018 pub fn as_dyn_trait(&self) -> Option<Trait> { 2014 pub fn as_dyn_trait(&self) -> Option<Trait> {
2019 self.ty.value.dyn_trait().map(Into::into) 2015 self.ty.dyn_trait().map(Into::into)
2020 } 2016 }
2021 2017
2022 pub fn as_impl_traits(&self, db: &dyn HirDatabase) -> Option<Vec<Trait>> { 2018 pub fn as_impl_traits(&self, db: &dyn HirDatabase) -> Option<Vec<Trait>> {
2023 self.ty.value.impl_trait_bounds(db).map(|it| { 2019 self.ty.impl_trait_bounds(db).map(|it| {
2024 it.into_iter() 2020 it.into_iter()
2025 .filter_map(|pred| match pred { 2021 .filter_map(|pred| match pred.skip_binders() {
2026 hir_ty::WhereClause::Implemented(trait_ref) => { 2022 hir_ty::WhereClause::Implemented(trait_ref) => {
2027 Some(Trait::from(trait_ref.hir_trait_id())) 2023 Some(Trait::from(trait_ref.hir_trait_id()))
2028 } 2024 }
@@ -2033,14 +2029,11 @@ impl Type {
2033 } 2029 }
2034 2030
2035 pub fn as_associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<Trait> { 2031 pub fn as_associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<Trait> {
2036 self.ty.value.associated_type_parent_trait(db).map(Into::into) 2032 self.ty.associated_type_parent_trait(db).map(Into::into)
2037 } 2033 }
2038 2034
2039 fn derived(&self, ty: Ty) -> Type { 2035 fn derived(&self, ty: Ty) -> Type {
2040 Type { 2036 Type { krate: self.krate, env: self.env.clone(), ty }
2041 krate: self.krate,
2042 ty: InEnvironment { value: ty, environment: self.ty.environment.clone() },
2043 }
2044 } 2037 }
2045 2038
2046 pub fn walk(&self, db: &dyn HirDatabase, mut cb: impl FnMut(Type)) { 2039 pub fn walk(&self, db: &dyn HirDatabase, mut cb: impl FnMut(Type)) {
@@ -2061,11 +2054,11 @@ impl Type {
2061 fn walk_bounds( 2054 fn walk_bounds(
2062 db: &dyn HirDatabase, 2055 db: &dyn HirDatabase,
2063 type_: &Type, 2056 type_: &Type,
2064 bounds: &[WhereClause], 2057 bounds: &[QuantifiedWhereClause],
2065 cb: &mut impl FnMut(Type), 2058 cb: &mut impl FnMut(Type),
2066 ) { 2059 ) {
2067 for pred in bounds { 2060 for pred in bounds {
2068 match pred { 2061 match pred.skip_binders() {
2069 WhereClause::Implemented(trait_ref) => { 2062 WhereClause::Implemented(trait_ref) => {
2070 cb(type_.clone()); 2063 cb(type_.clone());
2071 // skip the self type. it's likely the type we just got the bounds from 2064 // skip the self type. it's likely the type we just got the bounds from
@@ -2079,7 +2072,7 @@ impl Type {
2079 } 2072 }
2080 2073
2081 fn walk_type(db: &dyn HirDatabase, type_: &Type, cb: &mut impl FnMut(Type)) { 2074 fn walk_type(db: &dyn HirDatabase, type_: &Type, cb: &mut impl FnMut(Type)) {
2082 let ty = type_.ty.value.strip_references(); 2075 let ty = type_.ty.strip_references();
2083 match ty.interned(&Interner) { 2076 match ty.interned(&Interner) {
2084 TyKind::Adt(..) => { 2077 TyKind::Adt(..) => {
2085 cb(type_.derived(ty.clone())); 2078 cb(type_.derived(ty.clone()));
@@ -2107,7 +2100,12 @@ impl Type {
2107 } 2100 }
2108 } 2101 }
2109 TyKind::Dyn(bounds) => { 2102 TyKind::Dyn(bounds) => {
2110 walk_bounds(db, &type_.derived(ty.clone()), bounds.as_ref(), cb); 2103 walk_bounds(
2104 db,
2105 &type_.derived(ty.clone()),
2106 bounds.bounds.skip_binders().interned(),
2107 cb,
2108 );
2111 } 2109 }
2112 2110
2113 TyKind::Ref(_, ty) | TyKind::Raw(_, ty) | TyKind::Array(ty) | TyKind::Slice(ty) => { 2111 TyKind::Ref(_, ty) | TyKind::Raw(_, ty) | TyKind::Array(ty) | TyKind::Slice(ty) => {
diff --git a/crates/hir_def/src/find_path.rs b/crates/hir_def/src/find_path.rs
index de08e2737..109d3552f 100644
--- a/crates/hir_def/src/find_path.rs
+++ b/crates/hir_def/src/find_path.rs
@@ -18,7 +18,8 @@ use crate::{
18/// *from where* you're referring to the item, hence the `from` parameter. 18/// *from where* you're referring to the item, hence the `from` parameter.
19pub fn find_path(db: &dyn DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> { 19pub fn find_path(db: &dyn DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> {
20 let _p = profile::span("find_path"); 20 let _p = profile::span("find_path");
21 find_path_inner(db, item, from, MAX_PATH_LEN, None) 21 let mut visited_modules = FxHashSet::default();
22 find_path_inner(db, item, from, MAX_PATH_LEN, None, &mut visited_modules)
22} 23}
23 24
24pub fn find_path_prefixed( 25pub fn find_path_prefixed(
@@ -28,7 +29,8 @@ pub fn find_path_prefixed(
28 prefix_kind: PrefixKind, 29 prefix_kind: PrefixKind,
29) -> Option<ModPath> { 30) -> Option<ModPath> {
30 let _p = profile::span("find_path_prefixed"); 31 let _p = profile::span("find_path_prefixed");
31 find_path_inner(db, item, from, MAX_PATH_LEN, Some(prefix_kind)) 32 let mut visited_modules = FxHashSet::default();
33 find_path_inner(db, item, from, MAX_PATH_LEN, Some(prefix_kind), &mut visited_modules)
32} 34}
33 35
34const MAX_PATH_LEN: usize = 15; 36const MAX_PATH_LEN: usize = 15;
@@ -97,6 +99,7 @@ fn find_path_inner(
97 from: ModuleId, 99 from: ModuleId,
98 max_len: usize, 100 max_len: usize,
99 mut prefixed: Option<PrefixKind>, 101 mut prefixed: Option<PrefixKind>,
102 visited_modules: &mut FxHashSet<ModuleId>,
100) -> Option<ModPath> { 103) -> Option<ModPath> {
101 if max_len == 0 { 104 if max_len == 0 {
102 return None; 105 return None;
@@ -176,15 +179,18 @@ fn find_path_inner(
176 if item.krate(db) == Some(from.krate) { 179 if item.krate(db) == Some(from.krate) {
177 // Item was defined in the same crate that wants to import it. It cannot be found in any 180 // Item was defined in the same crate that wants to import it. It cannot be found in any
178 // dependency in this case. 181 // dependency in this case.
179 182 for (module_id, name) in find_local_import_locations(db, item, from) {
180 let local_imports = find_local_import_locations(db, item, from); 183 if !visited_modules.insert(module_id) {
181 for (module_id, name) in local_imports { 184 cov_mark::hit!(recursive_imports);
185 continue;
186 }
182 if let Some(mut path) = find_path_inner( 187 if let Some(mut path) = find_path_inner(
183 db, 188 db,
184 ItemInNs::Types(ModuleDefId::ModuleId(module_id)), 189 ItemInNs::Types(ModuleDefId::ModuleId(module_id)),
185 from, 190 from,
186 best_path_len - 1, 191 best_path_len - 1,
187 prefixed, 192 prefixed,
193 visited_modules,
188 ) { 194 ) {
189 path.push_segment(name); 195 path.push_segment(name);
190 196
@@ -213,6 +219,7 @@ fn find_path_inner(
213 from, 219 from,
214 best_path_len - 1, 220 best_path_len - 1,
215 prefixed, 221 prefixed,
222 visited_modules,
216 )?; 223 )?;
217 cov_mark::hit!(partially_imported); 224 cov_mark::hit!(partially_imported);
218 path.push_segment(info.path.segments.last().unwrap().clone()); 225 path.push_segment(info.path.segments.last().unwrap().clone());
@@ -391,8 +398,15 @@ mod tests {
391 .take_types() 398 .take_types()
392 .unwrap(); 399 .unwrap();
393 400
394 let found_path = 401 let mut visited_modules = FxHashSet::default();
395 find_path_inner(&db, ItemInNs::Types(resolved), module, MAX_PATH_LEN, prefix_kind); 402 let found_path = find_path_inner(
403 &db,
404 ItemInNs::Types(resolved),
405 module,
406 MAX_PATH_LEN,
407 prefix_kind,
408 &mut visited_modules,
409 );
396 assert_eq!(found_path, Some(mod_path), "{:?}", prefix_kind); 410 assert_eq!(found_path, Some(mod_path), "{:?}", prefix_kind);
397 } 411 }
398 412
@@ -878,4 +892,32 @@ mod tests {
878 "self::module::CompleteMe", 892 "self::module::CompleteMe",
879 ) 893 )
880 } 894 }
895
896 #[test]
897 fn recursive_pub_mod_reexport() {
898 cov_mark::check!(recursive_imports);
899 check_found_path(
900 r#"
901fn main() {
902 let _ = 22_i32.as_name$0();
903}
904
905pub mod name {
906 pub trait AsName {
907 fn as_name(&self) -> String;
908 }
909 impl AsName for i32 {
910 fn as_name(&self) -> String {
911 format!("Name: {}", self)
912 }
913 }
914 pub use crate::name;
915}
916"#,
917 "name::AsName",
918 "name::AsName",
919 "crate::name::AsName",
920 "self::name::AsName",
921 );
922 }
881} 923}
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs
index 0d3a0b54f..9e8e4e9ec 100644
--- a/crates/hir_def/src/nameres.rs
+++ b/crates/hir_def/src/nameres.rs
@@ -322,6 +322,23 @@ impl DefMap {
322 (res.resolved_def, res.segment_index) 322 (res.resolved_def, res.segment_index)
323 } 323 }
324 324
325 pub(crate) fn resolve_path_locally(
326 &self,
327 db: &dyn DefDatabase,
328 original_module: LocalModuleId,
329 path: &ModPath,
330 shadow: BuiltinShadowMode,
331 ) -> (PerNs, Option<usize>) {
332 let res = self.resolve_path_fp_with_macro_single(
333 db,
334 ResolveMode::Other,
335 original_module,
336 path,
337 shadow,
338 );
339 (res.resolved_def, res.segment_index)
340 }
341
325 /// Ascends the `DefMap` hierarchy and calls `f` with every `DefMap` and containing module. 342 /// Ascends the `DefMap` hierarchy and calls `f` with every `DefMap` and containing module.
326 /// 343 ///
327 /// If `f` returns `Some(val)`, iteration is stopped and `Some(val)` is returned. If `f` returns 344 /// If `f` returns `Some(val)`, iteration is stopped and `Some(val)` is returned. If `f` returns
diff --git a/crates/hir_def/src/nameres/path_resolution.rs b/crates/hir_def/src/nameres/path_resolution.rs
index db459b1ed..60471937c 100644
--- a/crates/hir_def/src/nameres/path_resolution.rs
+++ b/crates/hir_def/src/nameres/path_resolution.rs
@@ -156,7 +156,7 @@ impl DefMap {
156 } 156 }
157 } 157 }
158 158
159 fn resolve_path_fp_with_macro_single( 159 pub(super) fn resolve_path_fp_with_macro_single(
160 &self, 160 &self,
161 db: &dyn DefDatabase, 161 db: &dyn DefDatabase,
162 mode: ResolveMode, 162 mode: ResolveMode,
diff --git a/crates/hir_def/src/resolver.rs b/crates/hir_def/src/resolver.rs
index 04ea9c5d7..a73585ee7 100644
--- a/crates/hir_def/src/resolver.rs
+++ b/crates/hir_def/src/resolver.rs
@@ -548,7 +548,7 @@ impl ModuleItemMap {
548 path: &ModPath, 548 path: &ModPath,
549 ) -> Option<ResolveValueResult> { 549 ) -> Option<ResolveValueResult> {
550 let (module_def, idx) = 550 let (module_def, idx) =
551 self.def_map.resolve_path(db, self.module_id, &path, BuiltinShadowMode::Other); 551 self.def_map.resolve_path_locally(db, self.module_id, &path, BuiltinShadowMode::Other);
552 match idx { 552 match idx {
553 None => { 553 None => {
554 let value = to_value_ns(module_def)?; 554 let value = to_value_ns(module_def)?;
@@ -578,7 +578,7 @@ impl ModuleItemMap {
578 path: &ModPath, 578 path: &ModPath,
579 ) -> Option<(TypeNs, Option<usize>)> { 579 ) -> Option<(TypeNs, Option<usize>)> {
580 let (module_def, idx) = 580 let (module_def, idx) =
581 self.def_map.resolve_path(db, self.module_id, &path, BuiltinShadowMode::Other); 581 self.def_map.resolve_path_locally(db, self.module_id, &path, BuiltinShadowMode::Other);
582 let res = to_type_ns(module_def)?; 582 let res = to_type_ns(module_def)?;
583 Some((res, idx)) 583 Some((res, idx))
584 } 584 }
@@ -627,8 +627,18 @@ pub trait HasResolver: Copy {
627 627
628impl HasResolver for ModuleId { 628impl HasResolver for ModuleId {
629 fn resolver(self, db: &dyn DefDatabase) -> Resolver { 629 fn resolver(self, db: &dyn DefDatabase) -> Resolver {
630 let def_map = self.def_map(db); 630 let mut def_map = self.def_map(db);
631 Resolver::default().push_module_scope(def_map, self.local_id) 631 let mut modules = Vec::new();
632 modules.push((def_map.clone(), self.local_id));
633 while let Some(parent) = def_map.parent() {
634 def_map = parent.def_map(db);
635 modules.push((def_map.clone(), parent.local_id));
636 }
637 let mut resolver = Resolver::default();
638 for (def_map, module) in modules.into_iter().rev() {
639 resolver = resolver.push_module_scope(def_map, module);
640 }
641 resolver
632 } 642 }
633} 643}
634 644
diff --git a/crates/hir_ty/src/autoderef.rs b/crates/hir_ty/src/autoderef.rs
index 23ab042c1..dc5fc759a 100644
--- a/crates/hir_ty/src/autoderef.rs
+++ b/crates/hir_ty/src/autoderef.rs
@@ -16,8 +16,8 @@ use crate::{
16 to_assoc_type_id, to_chalk_trait_id, 16 to_assoc_type_id, to_chalk_trait_id,
17 traits::{InEnvironment, Solution}, 17 traits::{InEnvironment, Solution},
18 utils::generics, 18 utils::generics,
19 AliasEq, AliasTy, BoundVar, Canonical, DebruijnIndex, Interner, ProjectionTy, Substitution, 19 AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds, DebruijnIndex, Interner,
20 TraitRef, Ty, TyKind, 20 ProjectionTy, Substitution, TraitRef, Ty, TyKind,
21}; 21};
22 22
23const AUTODEREF_RECURSION_LIMIT: usize = 10; 23const AUTODEREF_RECURSION_LIMIT: usize = 10;
@@ -27,9 +27,9 @@ pub fn autoderef<'a>(
27 krate: Option<CrateId>, 27 krate: Option<CrateId>,
28 ty: InEnvironment<Canonical<Ty>>, 28 ty: InEnvironment<Canonical<Ty>>,
29) -> impl Iterator<Item = Canonical<Ty>> + 'a { 29) -> impl Iterator<Item = Canonical<Ty>> + 'a {
30 let InEnvironment { value: ty, environment } = ty; 30 let InEnvironment { goal: ty, environment } = ty;
31 successors(Some(ty), move |ty| { 31 successors(Some(ty), move |ty| {
32 deref(db, krate?, InEnvironment { value: ty, environment: environment.clone() }) 32 deref(db, krate?, InEnvironment { goal: ty, environment: environment.clone() })
33 }) 33 })
34 .take(AUTODEREF_RECURSION_LIMIT) 34 .take(AUTODEREF_RECURSION_LIMIT)
35} 35}
@@ -39,8 +39,8 @@ pub(crate) fn deref(
39 krate: CrateId, 39 krate: CrateId,
40 ty: InEnvironment<&Canonical<Ty>>, 40 ty: InEnvironment<&Canonical<Ty>>,
41) -> Option<Canonical<Ty>> { 41) -> Option<Canonical<Ty>> {
42 if let Some(derefed) = ty.value.value.builtin_deref() { 42 if let Some(derefed) = ty.goal.value.builtin_deref() {
43 Some(Canonical { value: derefed, kinds: ty.value.kinds.clone() }) 43 Some(Canonical { value: derefed, binders: ty.goal.binders.clone() })
44 } else { 44 } else {
45 deref_by_trait(db, krate, ty) 45 deref_by_trait(db, krate, ty)
46 } 46 }
@@ -67,15 +67,15 @@ fn deref_by_trait(
67 // FIXME make the Canonical / bound var handling nicer 67 // FIXME make the Canonical / bound var handling nicer
68 68
69 let parameters = 69 let parameters =
70 Substitution::build_for_generics(&generic_params).push(ty.value.value.clone()).build(); 70 Substitution::build_for_generics(&generic_params).push(ty.goal.value.clone()).build();
71 71
72 // Check that the type implements Deref at all 72 // Check that the type implements Deref at all
73 let trait_ref = 73 let trait_ref =
74 TraitRef { trait_id: to_chalk_trait_id(deref_trait), substitution: parameters.clone() }; 74 TraitRef { trait_id: to_chalk_trait_id(deref_trait), substitution: parameters.clone() };
75 let implements_goal = Canonical { 75 let implements_goal = Canonical {
76 kinds: ty.value.kinds.clone(), 76 binders: ty.goal.binders.clone(),
77 value: InEnvironment { 77 value: InEnvironment {
78 value: trait_ref.cast(&Interner), 78 goal: trait_ref.cast(&Interner),
79 environment: ty.environment.clone(), 79 environment: ty.environment.clone(),
80 }, 80 },
81 }; 81 };
@@ -89,18 +89,27 @@ fn deref_by_trait(
89 associated_ty_id: to_assoc_type_id(target), 89 associated_ty_id: to_assoc_type_id(target),
90 substitution: parameters, 90 substitution: parameters,
91 }), 91 }),
92 ty: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, ty.value.kinds.len())) 92 ty: TyKind::BoundVar(BoundVar::new(
93 .intern(&Interner), 93 DebruijnIndex::INNERMOST,
94 ty.goal.binders.len(&Interner),
95 ))
96 .intern(&Interner),
94 }; 97 };
95 98
96 let obligation = projection.cast(&Interner); 99 let obligation = projection.cast(&Interner);
97 100
98 let in_env = InEnvironment { value: obligation, environment: ty.environment }; 101 let in_env = InEnvironment { goal: obligation, environment: ty.environment };
99 102
100 let canonical = Canonical::new( 103 let canonical = Canonical {
101 in_env, 104 value: in_env,
102 ty.value.kinds.iter().copied().chain(Some(chalk_ir::TyVariableKind::General)), 105 binders: CanonicalVarKinds::from_iter(
103 ); 106 &Interner,
107 ty.goal.binders.iter(&Interner).cloned().chain(Some(chalk_ir::WithKind::new(
108 chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General),
109 chalk_ir::UniverseIndex::ROOT,
110 ))),
111 ),
112 };
104 113
105 let solution = db.trait_solve(krate, canonical)?; 114 let solution = db.trait_solve(krate, canonical)?;
106 115
@@ -121,21 +130,21 @@ fn deref_by_trait(
121 // assumptions will be broken. We would need to properly introduce 130 // assumptions will be broken. We would need to properly introduce
122 // new variables in that case 131 // new variables in that case
123 132
124 for i in 1..vars.0.kinds.len() { 133 for i in 1..vars.0.binders.len(&Interner) {
125 if vars.0.value[i - 1].interned(&Interner) 134 if vars.0.value[i - 1].interned(&Interner)
126 != &TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, i - 1)) 135 != &TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, i - 1))
127 { 136 {
128 warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.value, solution); 137 warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.goal, solution);
129 return None; 138 return None;
130 } 139 }
131 } 140 }
132 Some(Canonical { 141 Some(Canonical {
133 value: vars.0.value[vars.0.value.len() - 1].clone(), 142 value: vars.0.value[vars.0.value.len() - 1].clone(),
134 kinds: vars.0.kinds.clone(), 143 binders: vars.0.binders.clone(),
135 }) 144 })
136 } 145 }
137 Solution::Ambig(_) => { 146 Solution::Ambig(_) => {
138 info!("Ambiguous solution for derefing {:?}: {:?}", ty.value, solution); 147 info!("Ambiguous solution for derefing {:?}: {:?}", ty.goal, solution);
139 None 148 None
140 } 149 }
141 } 150 }
diff --git a/crates/hir_ty/src/db.rs b/crates/hir_ty/src/db.rs
index 91a2e0b5b..58e4247c6 100644
--- a/crates/hir_ty/src/db.rs
+++ b/crates/hir_ty/src/db.rs
@@ -12,8 +12,8 @@ use la_arena::ArenaMap;
12use crate::{ 12use crate::{
13 method_resolution::{InherentImpls, TraitImpls}, 13 method_resolution::{InherentImpls, TraitImpls},
14 traits::chalk, 14 traits::chalk,
15 Binders, CallableDefId, FnDefId, ImplTraitId, InferenceResult, PolyFnSig, ReturnTypeImplTraits, 15 Binders, CallableDefId, FnDefId, ImplTraitId, InferenceResult, PolyFnSig,
16 TraitRef, Ty, TyDefId, ValueTyDefId, WhereClause, 16 QuantifiedWhereClause, ReturnTypeImplTraits, TraitRef, Ty, TyDefId, ValueTyDefId,
17}; 17};
18use hir_expand::name::Name; 18use hir_expand::name::Name;
19 19
@@ -57,10 +57,13 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
57 57
58 #[salsa::invoke(crate::lower::generic_predicates_for_param_query)] 58 #[salsa::invoke(crate::lower::generic_predicates_for_param_query)]
59 #[salsa::cycle(crate::lower::generic_predicates_for_param_recover)] 59 #[salsa::cycle(crate::lower::generic_predicates_for_param_recover)]
60 fn generic_predicates_for_param(&self, param_id: TypeParamId) -> Arc<[Binders<WhereClause>]>; 60 fn generic_predicates_for_param(
61 &self,
62 param_id: TypeParamId,
63 ) -> Arc<[Binders<QuantifiedWhereClause>]>;
61 64
62 #[salsa::invoke(crate::lower::generic_predicates_query)] 65 #[salsa::invoke(crate::lower::generic_predicates_query)]
63 fn generic_predicates(&self, def: GenericDefId) -> Arc<[Binders<WhereClause>]>; 66 fn generic_predicates(&self, def: GenericDefId) -> Arc<[Binders<QuantifiedWhereClause>]>;
64 67
65 #[salsa::invoke(crate::lower::trait_environment_query)] 68 #[salsa::invoke(crate::lower::trait_environment_query)]
66 fn trait_environment(&self, def: GenericDefId) -> Arc<crate::TraitEnvironment>; 69 fn trait_environment(&self, def: GenericDefId) -> Arc<crate::TraitEnvironment>;
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs
index 9d3b79be3..6149067c7 100644
--- a/crates/hir_ty/src/display.rs
+++ b/crates/hir_ty/src/display.rs
@@ -1,6 +1,6 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use std::{borrow::Cow, fmt}; 3use std::fmt;
4 4
5use arrayvec::ArrayVec; 5use arrayvec::ArrayVec;
6use chalk_ir::Mutability; 6use chalk_ir::Mutability;
@@ -20,7 +20,7 @@ use crate::{
20 db::HirDatabase, from_assoc_type_id, from_foreign_def_id, from_placeholder_idx, primitive, 20 db::HirDatabase, from_assoc_type_id, from_foreign_def_id, from_placeholder_idx, primitive,
21 to_assoc_type_id, traits::chalk::from_chalk, utils::generics, AdtId, AliasEq, AliasTy, 21 to_assoc_type_id, traits::chalk::from_chalk, utils::generics, AdtId, AliasEq, AliasTy,
22 CallableDefId, CallableSig, DomainGoal, ImplTraitId, Interner, Lifetime, OpaqueTy, 22 CallableDefId, CallableSig, DomainGoal, ImplTraitId, Interner, Lifetime, OpaqueTy,
23 ProjectionTy, Scalar, Substitution, TraitRef, Ty, TyKind, WhereClause, 23 ProjectionTy, QuantifiedWhereClause, Scalar, Substitution, TraitRef, Ty, TyKind, WhereClause,
24}; 24};
25 25
26pub struct HirFormatter<'a> { 26pub struct HirFormatter<'a> {
@@ -190,6 +190,7 @@ impl DisplayTarget {
190pub enum DisplaySourceCodeError { 190pub enum DisplaySourceCodeError {
191 PathNotFound, 191 PathNotFound,
192 UnknownType, 192 UnknownType,
193 Closure,
193} 194}
194 195
195pub enum HirDisplayError { 196pub enum HirDisplayError {
@@ -328,9 +329,9 @@ impl HirDisplay for Ty {
328 329
329 // FIXME: all this just to decide whether to use parentheses... 330 // FIXME: all this just to decide whether to use parentheses...
330 let datas; 331 let datas;
331 let predicates = match t.interned(&Interner) { 332 let predicates: Vec<_> = match t.interned(&Interner) {
332 TyKind::Dyn(predicates) if predicates.len() > 1 => { 333 TyKind::Dyn(dyn_ty) if dyn_ty.bounds.skip_binders().interned().len() > 1 => {
333 Cow::Borrowed(predicates.as_ref()) 334 dyn_ty.bounds.skip_binders().interned().iter().cloned().collect()
334 } 335 }
335 &TyKind::Alias(AliasTy::Opaque(OpaqueTy { 336 &TyKind::Alias(AliasTy::Opaque(OpaqueTy {
336 opaque_ty_id, 337 opaque_ty_id,
@@ -345,17 +346,21 @@ impl HirDisplay for Ty {
345 .as_ref() 346 .as_ref()
346 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); 347 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
347 let bounds = data.subst(parameters); 348 let bounds = data.subst(parameters);
348 Cow::Owned(bounds.value) 349 bounds.value
349 } else { 350 } else {
350 Cow::Borrowed(&[][..]) 351 Vec::new()
351 } 352 }
352 } 353 }
353 _ => Cow::Borrowed(&[][..]), 354 _ => Vec::new(),
354 }; 355 };
355 356
356 if let [WhereClause::Implemented(trait_ref), _] = predicates.as_ref() { 357 if let Some(WhereClause::Implemented(trait_ref)) =
358 predicates.get(0).map(|b| b.skip_binders())
359 {
357 let trait_ = trait_ref.hir_trait_id(); 360 let trait_ = trait_ref.hir_trait_id();
358 if fn_traits(f.db.upcast(), trait_).any(|it| it == trait_) { 361 if fn_traits(f.db.upcast(), trait_).any(|it| it == trait_)
362 && predicates.len() <= 2
363 {
359 return write!(f, "{}", ty_display); 364 return write!(f, "{}", ty_display);
360 } 365 }
361 } 366 }
@@ -539,6 +544,11 @@ impl HirDisplay for Ty {
539 } 544 }
540 } 545 }
541 TyKind::Closure(.., substs) => { 546 TyKind::Closure(.., substs) => {
547 if f.display_target.is_source_code() {
548 return Err(HirDisplayError::DisplaySourceCodeError(
549 DisplaySourceCodeError::Closure,
550 ));
551 }
542 let sig = substs[0].callable_sig(f.db); 552 let sig = substs[0].callable_sig(f.db);
543 if let Some(sig) = sig { 553 if let Some(sig) = sig {
544 if sig.params().is_empty() { 554 if sig.params().is_empty() {
@@ -577,7 +587,7 @@ impl HirDisplay for Ty {
577 .generic_predicates(id.parent) 587 .generic_predicates(id.parent)
578 .into_iter() 588 .into_iter()
579 .map(|pred| pred.clone().subst(&substs)) 589 .map(|pred| pred.clone().subst(&substs))
580 .filter(|wc| match &wc { 590 .filter(|wc| match &wc.skip_binders() {
581 WhereClause::Implemented(tr) => tr.self_type_parameter() == self, 591 WhereClause::Implemented(tr) => tr.self_type_parameter() == self,
582 WhereClause::AliasEq(AliasEq { 592 WhereClause::AliasEq(AliasEq {
583 alias: AliasTy::Projection(proj), 593 alias: AliasTy::Projection(proj),
@@ -591,8 +601,12 @@ impl HirDisplay for Ty {
591 } 601 }
592 } 602 }
593 TyKind::BoundVar(idx) => write!(f, "?{}.{}", idx.debruijn.depth(), idx.index)?, 603 TyKind::BoundVar(idx) => write!(f, "?{}.{}", idx.debruijn.depth(), idx.index)?,
594 TyKind::Dyn(predicates) => { 604 TyKind::Dyn(dyn_ty) => {
595 write_bounds_like_dyn_trait_with_prefix("dyn", predicates, f)?; 605 write_bounds_like_dyn_trait_with_prefix(
606 "dyn",
607 dyn_ty.bounds.skip_binders().interned(),
608 f,
609 )?;
596 } 610 }
597 TyKind::Alias(AliasTy::Projection(p_ty)) => p_ty.hir_fmt(f)?, 611 TyKind::Alias(AliasTy::Projection(p_ty)) => p_ty.hir_fmt(f)?,
598 TyKind::Alias(AliasTy::Opaque(opaque_ty)) => { 612 TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
@@ -661,7 +675,7 @@ fn fn_traits(db: &dyn DefDatabase, trait_: TraitId) -> impl Iterator<Item = Trai
661 675
662pub fn write_bounds_like_dyn_trait_with_prefix( 676pub fn write_bounds_like_dyn_trait_with_prefix(
663 prefix: &str, 677 prefix: &str,
664 predicates: &[WhereClause], 678 predicates: &[QuantifiedWhereClause],
665 f: &mut HirFormatter, 679 f: &mut HirFormatter,
666) -> Result<(), HirDisplayError> { 680) -> Result<(), HirDisplayError> {
667 write!(f, "{}", prefix)?; 681 write!(f, "{}", prefix)?;
@@ -674,7 +688,7 @@ pub fn write_bounds_like_dyn_trait_with_prefix(
674} 688}
675 689
676fn write_bounds_like_dyn_trait( 690fn write_bounds_like_dyn_trait(
677 predicates: &[WhereClause], 691 predicates: &[QuantifiedWhereClause],
678 f: &mut HirFormatter, 692 f: &mut HirFormatter,
679) -> Result<(), HirDisplayError> { 693) -> Result<(), HirDisplayError> {
680 // Note: This code is written to produce nice results (i.e. 694 // Note: This code is written to produce nice results (i.e.
@@ -687,7 +701,7 @@ fn write_bounds_like_dyn_trait(
687 let mut angle_open = false; 701 let mut angle_open = false;
688 let mut is_fn_trait = false; 702 let mut is_fn_trait = false;
689 for p in predicates.iter() { 703 for p in predicates.iter() {
690 match p { 704 match p.skip_binders() {
691 WhereClause::Implemented(trait_ref) => { 705 WhereClause::Implemented(trait_ref) => {
692 let trait_ = trait_ref.hir_trait_id(); 706 let trait_ = trait_ref.hir_trait_id();
693 if !is_fn_trait { 707 if !is_fn_trait {
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs
index b9e434c78..8f9cf7480 100644
--- a/crates/hir_ty/src/infer.rs
+++ b/crates/hir_ty/src/infer.rs
@@ -331,7 +331,7 @@ impl<'a> InferenceContext<'a> {
331 fn resolve_obligations_as_possible(&mut self) { 331 fn resolve_obligations_as_possible(&mut self) {
332 let obligations = mem::replace(&mut self.obligations, Vec::new()); 332 let obligations = mem::replace(&mut self.obligations, Vec::new());
333 for obligation in obligations { 333 for obligation in obligations {
334 let in_env = InEnvironment::new(self.trait_env.clone(), obligation.clone()); 334 let in_env = InEnvironment::new(self.trait_env.env.clone(), obligation.clone());
335 let canonicalized = self.canonicalizer().canonicalize_obligation(in_env); 335 let canonicalized = self.canonicalizer().canonicalize_obligation(in_env);
336 let solution = 336 let solution =
337 self.db.trait_solve(self.resolver.krate().unwrap(), canonicalized.value.clone()); 337 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 07eb96573..9c62932b1 100644
--- a/crates/hir_ty/src/infer/coerce.rs
+++ b/crates/hir_ty/src/infer/coerce.rs
@@ -142,7 +142,7 @@ impl<'a> InferenceContext<'a> {
142 .build(); 142 .build();
143 let trait_ref = 143 let trait_ref =
144 TraitRef { trait_id: to_chalk_trait_id(coerce_unsized_trait), substitution: substs }; 144 TraitRef { trait_id: to_chalk_trait_id(coerce_unsized_trait), substitution: substs };
145 let goal = InEnvironment::new(self.trait_env.clone(), trait_ref.cast(&Interner)); 145 let goal = InEnvironment::new(self.trait_env.env.clone(), trait_ref.cast(&Interner));
146 146
147 let canonicalizer = self.canonicalizer(); 147 let canonicalizer = self.canonicalizer();
148 let canonicalized = canonicalizer.canonicalize_obligation(goal); 148 let canonicalized = canonicalizer.canonicalize_obligation(goal);
@@ -170,8 +170,8 @@ impl<'a> InferenceContext<'a> {
170 self.db, 170 self.db,
171 self.resolver.krate(), 171 self.resolver.krate(),
172 InEnvironment { 172 InEnvironment {
173 value: canonicalized.value.clone(), 173 goal: canonicalized.value.clone(),
174 environment: self.trait_env.clone(), 174 environment: self.trait_env.env.clone(),
175 }, 175 },
176 ) { 176 ) {
177 let derefed_ty = canonicalized.decanonicalize_ty(derefed_ty.value); 177 let derefed_ty = canonicalized.decanonicalize_ty(derefed_ty.value);
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index 24deff707..19249973c 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -11,6 +11,7 @@ use hir_def::{
11 AssocContainerId, FieldId, Lookup, 11 AssocContainerId, FieldId, Lookup,
12}; 12};
13use hir_expand::name::{name, Name}; 13use hir_expand::name::{name, Name};
14use stdx::always;
14use syntax::ast::RangeOp; 15use syntax::ast::RangeOp;
15 16
16use crate::{ 17use crate::{
@@ -89,12 +90,12 @@ impl<'a> InferenceContext<'a> {
89 let substs = 90 let substs =
90 Substitution::build_for_generics(&generic_params).push(ty.clone()).push(arg_ty).build(); 91 Substitution::build_for_generics(&generic_params).push(ty.clone()).push(arg_ty).build();
91 92
92 let trait_env = Arc::clone(&self.trait_env); 93 let trait_env = self.trait_env.env.clone();
93 let implements_fn_trait: DomainGoal = 94 let implements_fn_trait: DomainGoal =
94 TraitRef { trait_id: to_chalk_trait_id(fn_once_trait), substitution: substs.clone() } 95 TraitRef { trait_id: to_chalk_trait_id(fn_once_trait), substitution: substs.clone() }
95 .cast(&Interner); 96 .cast(&Interner);
96 let goal = self.canonicalizer().canonicalize_obligation(InEnvironment { 97 let goal = self.canonicalizer().canonicalize_obligation(InEnvironment {
97 value: implements_fn_trait.clone(), 98 goal: implements_fn_trait.clone(),
98 environment: trait_env, 99 environment: trait_env,
99 }); 100 });
100 if self.db.trait_solve(krate, goal.value).is_some() { 101 if self.db.trait_solve(krate, goal.value).is_some() {
@@ -298,8 +299,8 @@ impl<'a> InferenceContext<'a> {
298 self.db, 299 self.db,
299 self.resolver.krate(), 300 self.resolver.krate(),
300 InEnvironment { 301 InEnvironment {
301 value: canonicalized.value.clone(), 302 goal: canonicalized.value.clone(),
302 environment: self.trait_env.clone(), 303 environment: self.trait_env.env.clone(),
303 }, 304 },
304 ); 305 );
305 let (param_tys, ret_ty): (Vec<Ty>, Ty) = derefs 306 let (param_tys, ret_ty): (Vec<Ty>, Ty) = derefs
@@ -437,8 +438,8 @@ impl<'a> InferenceContext<'a> {
437 self.db, 438 self.db,
438 self.resolver.krate(), 439 self.resolver.krate(),
439 InEnvironment { 440 InEnvironment {
440 value: canonicalized.value.clone(), 441 goal: canonicalized.value.clone(),
441 environment: self.trait_env.clone(), 442 environment: self.trait_env.env.clone(),
442 }, 443 },
443 ) 444 )
444 .find_map(|derefed_ty| { 445 .find_map(|derefed_ty| {
@@ -537,8 +538,8 @@ impl<'a> InferenceContext<'a> {
537 self.db, 538 self.db,
538 krate, 539 krate,
539 InEnvironment { 540 InEnvironment {
540 value: &canonicalized.value, 541 goal: &canonicalized.value,
541 environment: self.trait_env.clone(), 542 environment: self.trait_env.env.clone(),
542 }, 543 },
543 ) { 544 ) {
544 Some(derefed_ty) => { 545 Some(derefed_ty) => {
@@ -936,7 +937,9 @@ impl<'a> InferenceContext<'a> {
936 let def: CallableDefId = from_chalk(self.db, *fn_def); 937 let def: CallableDefId = from_chalk(self.db, *fn_def);
937 let generic_predicates = self.db.generic_predicates(def.into()); 938 let generic_predicates = self.db.generic_predicates(def.into());
938 for predicate in generic_predicates.iter() { 939 for predicate in generic_predicates.iter() {
939 let predicate = predicate.clone().subst(parameters); 940 let (predicate, binders) =
941 predicate.clone().subst(parameters).into_value_and_skipped_binders();
942 always!(binders == 0); // quantified where clauses not yet handled
940 self.obligations.push(predicate.cast(&Interner)); 943 self.obligations.push(predicate.cast(&Interner));
941 } 944 }
942 // add obligation for trait implementation, if this is a trait method 945 // add obligation for trait implementation, if this is a trait method
diff --git a/crates/hir_ty/src/infer/unify.rs b/crates/hir_ty/src/infer/unify.rs
index 1fc03c8f4..75250a369 100644
--- a/crates/hir_ty/src/infer/unify.rs
+++ b/crates/hir_ty/src/infer/unify.rs
@@ -2,13 +2,13 @@
2 2
3use std::borrow::Cow; 3use std::borrow::Cow;
4 4
5use chalk_ir::{FloatTy, IntTy, TyVariableKind}; 5use chalk_ir::{FloatTy, IntTy, TyVariableKind, UniverseIndex, VariableKind};
6use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue}; 6use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue};
7 7
8use super::{DomainGoal, InferenceContext}; 8use super::{DomainGoal, InferenceContext};
9use crate::{ 9use crate::{
10 AliasEq, AliasTy, BoundVar, Canonical, DebruijnIndex, FnPointer, InEnvironment, InferenceVar, 10 AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds, DebruijnIndex, FnPointer,
11 Interner, Scalar, Substitution, Ty, TyKind, TypeWalk, WhereClause, 11 InEnvironment, InferenceVar, Interner, Scalar, Substitution, Ty, TyKind, TypeWalk, WhereClause,
12}; 12};
13 13
14impl<'a> InferenceContext<'a> { 14impl<'a> InferenceContext<'a> {
@@ -76,8 +76,17 @@ impl<'a, 'b> Canonicalizer<'a, 'b> {
76 } 76 }
77 77
78 fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> { 78 fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> {
79 let kinds = self.free_vars.iter().map(|&(_, k)| k).collect(); 79 let kinds = self
80 Canonicalized { value: Canonical { value: result, kinds }, free_vars: self.free_vars } 80 .free_vars
81 .iter()
82 .map(|&(_, k)| chalk_ir::WithKind::new(VariableKind::Ty(k), UniverseIndex::ROOT));
83 Canonicalized {
84 value: Canonical {
85 value: result,
86 binders: CanonicalVarKinds::from_iter(&Interner, kinds),
87 },
88 free_vars: self.free_vars,
89 }
81 } 90 }
82 91
83 pub(crate) fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> { 92 pub(crate) fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> {
@@ -89,15 +98,12 @@ impl<'a, 'b> Canonicalizer<'a, 'b> {
89 mut self, 98 mut self,
90 obligation: InEnvironment<DomainGoal>, 99 obligation: InEnvironment<DomainGoal>,
91 ) -> Canonicalized<InEnvironment<DomainGoal>> { 100 ) -> Canonicalized<InEnvironment<DomainGoal>> {
92 let result = match obligation.value { 101 let result = match obligation.goal {
93 DomainGoal::Holds(wc) => { 102 DomainGoal::Holds(wc) => {
94 DomainGoal::Holds(self.do_canonicalize(wc, DebruijnIndex::INNERMOST)) 103 DomainGoal::Holds(self.do_canonicalize(wc, DebruijnIndex::INNERMOST))
95 } 104 }
96 }; 105 };
97 self.into_canonicalized(InEnvironment { 106 self.into_canonicalized(InEnvironment { goal: result, environment: obligation.environment })
98 value: result,
99 environment: obligation.environment,
100 })
101 } 107 }
102} 108}
103 109
@@ -125,12 +131,19 @@ impl<T> Canonicalized<T> {
125 // the solution may contain new variables, which we need to convert to new inference vars 131 // the solution may contain new variables, which we need to convert to new inference vars
126 let new_vars = Substitution( 132 let new_vars = Substitution(
127 solution 133 solution
128 .kinds 134 .binders
129 .iter() 135 .iter(&Interner)
130 .map(|k| match k { 136 .map(|k| match k.kind {
131 TyVariableKind::General => ctx.table.new_type_var(), 137 VariableKind::Ty(TyVariableKind::General) => ctx.table.new_type_var(),
132 TyVariableKind::Integer => ctx.table.new_integer_var(), 138 VariableKind::Ty(TyVariableKind::Integer) => ctx.table.new_integer_var(),
133 TyVariableKind::Float => ctx.table.new_float_var(), 139 VariableKind::Ty(TyVariableKind::Float) => ctx.table.new_float_var(),
140 // HACK: Chalk can sometimes return new lifetime variables. We
141 // want to just skip them, but to not mess up the indices of
142 // other variables, we'll just create a new type variable in
143 // their place instead. This should not matter (we never see the
144 // actual *uses* of the lifetime variable).
145 VariableKind::Lifetime => ctx.table.new_type_var(),
146 _ => panic!("const variable in solution"),
134 }) 147 })
135 .collect(), 148 .collect(),
136 ); 149 );
@@ -147,8 +160,8 @@ impl<T> Canonicalized<T> {
147pub(crate) fn unify(tys: &Canonical<(Ty, Ty)>) -> Option<Substitution> { 160pub(crate) fn unify(tys: &Canonical<(Ty, Ty)>) -> Option<Substitution> {
148 let mut table = InferenceTable::new(); 161 let mut table = InferenceTable::new();
149 let vars = Substitution( 162 let vars = Substitution(
150 tys.kinds 163 tys.binders
151 .iter() 164 .iter(&Interner)
152 // we always use type vars here because we want everything to 165 // we always use type vars here because we want everything to
153 // fallback to Unknown in the end (kind of hacky, as below) 166 // fallback to Unknown in the end (kind of hacky, as below)
154 .map(|_| table.new_type_var()) 167 .map(|_| table.new_type_var())
@@ -170,7 +183,7 @@ pub(crate) fn unify(tys: &Canonical<(Ty, Ty)>) -> Option<Substitution> {
170 } 183 }
171 } 184 }
172 Some( 185 Some(
173 Substitution::builder(tys.kinds.len()) 186 Substitution::builder(tys.binders.len(&Interner))
174 .fill(vars.iter().map(|v| table.resolve_ty_completely(v.clone()))) 187 .fill(vars.iter().map(|v| table.resolve_ty_completely(v.clone())))
175 .build(), 188 .build(),
176 ) 189 )
@@ -310,9 +323,18 @@ impl InferenceTable {
310 323
311 (TyKind::Placeholder(p1), TyKind::Placeholder(p2)) if *p1 == *p2 => true, 324 (TyKind::Placeholder(p1), TyKind::Placeholder(p2)) if *p1 == *p2 => true,
312 325
313 (TyKind::Dyn(dyn1), TyKind::Dyn(dyn2)) if dyn1.len() == dyn2.len() => { 326 (TyKind::Dyn(dyn1), TyKind::Dyn(dyn2))
314 for (pred1, pred2) in dyn1.iter().zip(dyn2.iter()) { 327 if dyn1.bounds.skip_binders().interned().len()
315 if !self.unify_preds(pred1, pred2, depth + 1) { 328 == dyn2.bounds.skip_binders().interned().len() =>
329 {
330 for (pred1, pred2) in dyn1
331 .bounds
332 .skip_binders()
333 .interned()
334 .iter()
335 .zip(dyn2.bounds.skip_binders().interned().iter())
336 {
337 if !self.unify_preds(pred1.skip_binders(), pred2.skip_binders(), depth + 1) {
316 return false; 338 return false;
317 } 339 }
318 } 340 }
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs
index ad908f957..0f49dd39b 100644
--- a/crates/hir_ty/src/lib.rs
+++ b/crates/hir_ty/src/lib.rs
@@ -61,6 +61,8 @@ pub type ClosureId = chalk_ir::ClosureId<Interner>;
61pub type OpaqueTyId = chalk_ir::OpaqueTyId<Interner>; 61pub type OpaqueTyId = chalk_ir::OpaqueTyId<Interner>;
62pub type PlaceholderIndex = chalk_ir::PlaceholderIndex; 62pub type PlaceholderIndex = chalk_ir::PlaceholderIndex;
63 63
64pub type CanonicalVarKinds = chalk_ir::CanonicalVarKinds<Interner>;
65
64pub type ChalkTraitId = chalk_ir::TraitId<Interner>; 66pub type ChalkTraitId = chalk_ir::TraitId<Interner>;
65 67
66#[derive(Clone, PartialEq, Eq, Debug, Hash)] 68#[derive(Clone, PartialEq, Eq, Debug, Hash)]
@@ -132,6 +134,12 @@ impl TypeWalk for ProjectionTy {
132 } 134 }
133} 135}
134 136
137#[derive(Clone, PartialEq, Eq, Debug, Hash)]
138pub struct DynTy {
139 /// The unknown self type.
140 pub bounds: Binders<QuantifiedWhereClauses>,
141}
142
135pub type FnSig = chalk_ir::FnSig<Interner>; 143pub type FnSig = chalk_ir::FnSig<Interner>;
136 144
137#[derive(Clone, PartialEq, Eq, Debug, Hash)] 145#[derive(Clone, PartialEq, Eq, Debug, Hash)]
@@ -283,7 +291,7 @@ pub enum TyKind {
283 /// represents the `Self` type inside the bounds. This is currently 291 /// represents the `Self` type inside the bounds. This is currently
284 /// implicit; Chalk has the `Binders` struct to make it explicit, but it 292 /// implicit; Chalk has the `Binders` struct to make it explicit, but it
285 /// didn't seem worth the overhead yet. 293 /// didn't seem worth the overhead yet.
286 Dyn(Arc<[WhereClause]>), 294 Dyn(DynTy),
287 295
288 /// A placeholder for a type which could not be computed; this is propagated 296 /// A placeholder for a type which could not be computed; this is propagated
289 /// to avoid useless error messages. Doubles as a placeholder where type 297 /// to avoid useless error messages. Doubles as a placeholder where type
@@ -490,6 +498,13 @@ impl<T> Binders<T> {
490 Self { num_binders, value } 498 Self { num_binders, value }
491 } 499 }
492 500
501 pub fn wrap_empty(value: T) -> Self
502 where
503 T: TypeWalk,
504 {
505 Self { num_binders: 0, value: value.shift_bound_vars(DebruijnIndex::ONE) }
506 }
507
493 pub fn as_ref(&self) -> Binders<&T> { 508 pub fn as_ref(&self) -> Binders<&T> {
494 Binders { num_binders: self.num_binders, value: &self.value } 509 Binders { num_binders: self.num_binders, value: &self.value }
495 } 510 }
@@ -501,6 +516,14 @@ impl<T> Binders<T> {
501 pub fn filter_map<U>(self, f: impl FnOnce(T) -> Option<U>) -> Option<Binders<U>> { 516 pub fn filter_map<U>(self, f: impl FnOnce(T) -> Option<U>) -> Option<Binders<U>> {
502 Some(Binders { num_binders: self.num_binders, value: f(self.value)? }) 517 Some(Binders { num_binders: self.num_binders, value: f(self.value)? })
503 } 518 }
519
520 pub fn skip_binders(&self) -> &T {
521 &self.value
522 }
523
524 pub fn into_value_and_skipped_binders(self) -> (T, usize) {
525 (self.value, self.num_binders)
526 }
504} 527}
505 528
506impl<T: Clone> Binders<&T> { 529impl<T: Clone> Binders<&T> {
@@ -614,6 +637,24 @@ impl TypeWalk for WhereClause {
614 } 637 }
615} 638}
616 639
640pub type QuantifiedWhereClause = Binders<WhereClause>;
641
642#[derive(Debug, Clone, PartialEq, Eq, Hash)]
643pub struct QuantifiedWhereClauses(Arc<[QuantifiedWhereClause]>);
644
645impl QuantifiedWhereClauses {
646 pub fn from_iter(
647 _interner: &Interner,
648 elements: impl IntoIterator<Item = QuantifiedWhereClause>,
649 ) -> Self {
650 QuantifiedWhereClauses(elements.into_iter().collect())
651 }
652
653 pub fn interned(&self) -> &Arc<[QuantifiedWhereClause]> {
654 &self.0
655 }
656}
657
617/// Basically a claim (currently not validated / checked) that the contained 658/// Basically a claim (currently not validated / checked) that the contained
618/// type / trait ref contains no inference variables; any inference variables it 659/// type / trait ref contains no inference variables; any inference variables it
619/// contained have been replaced by bound variables, and `kinds` tells us how 660/// contained have been replaced by bound variables, and `kinds` tells us how
@@ -623,12 +664,18 @@ impl TypeWalk for WhereClause {
623#[derive(Debug, Clone, PartialEq, Eq, Hash)] 664#[derive(Debug, Clone, PartialEq, Eq, Hash)]
624pub struct Canonical<T> { 665pub struct Canonical<T> {
625 pub value: T, 666 pub value: T,
626 pub kinds: Arc<[TyVariableKind]>, 667 pub binders: CanonicalVarKinds,
627} 668}
628 669
629impl<T> Canonical<T> { 670impl<T> Canonical<T> {
630 pub fn new(value: T, kinds: impl IntoIterator<Item = TyVariableKind>) -> Self { 671 pub fn new(value: T, kinds: impl IntoIterator<Item = TyVariableKind>) -> Self {
631 Self { value, kinds: kinds.into_iter().collect() } 672 let kinds = kinds.into_iter().map(|tk| {
673 chalk_ir::CanonicalVarKind::new(
674 chalk_ir::VariableKind::Ty(tk),
675 chalk_ir::UniverseIndex::ROOT,
676 )
677 });
678 Self { value, binders: chalk_ir::CanonicalVarKinds::from_iter(&Interner, kinds) }
632 } 679 }
633} 680}
634 681
@@ -810,12 +857,14 @@ impl Ty {
810 } 857 }
811 858
812 /// If this is a `dyn Trait` type, this returns the `Trait` part. 859 /// If this is a `dyn Trait` type, this returns the `Trait` part.
813 pub fn dyn_trait_ref(&self) -> Option<&TraitRef> { 860 fn dyn_trait_ref(&self) -> Option<&TraitRef> {
814 match self.interned(&Interner) { 861 match self.interned(&Interner) {
815 TyKind::Dyn(bounds) => bounds.get(0).and_then(|b| match b { 862 TyKind::Dyn(dyn_ty) => {
816 WhereClause::Implemented(trait_ref) => Some(trait_ref), 863 dyn_ty.bounds.value.interned().get(0).and_then(|b| match b.skip_binders() {
817 _ => None, 864 WhereClause::Implemented(trait_ref) => Some(trait_ref),
818 }), 865 _ => None,
866 })
867 }
819 _ => None, 868 _ => None,
820 } 869 }
821 } 870 }
@@ -892,7 +941,7 @@ impl Ty {
892 } 941 }
893 } 942 }
894 943
895 pub fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<WhereClause>> { 944 pub fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<QuantifiedWhereClause>> {
896 match self.interned(&Interner) { 945 match self.interned(&Interner) {
897 TyKind::OpaqueType(opaque_ty_id, ..) => { 946 TyKind::OpaqueType(opaque_ty_id, ..) => {
898 match db.lookup_intern_impl_trait_id((*opaque_ty_id).into()) { 947 match db.lookup_intern_impl_trait_id((*opaque_ty_id).into()) {
@@ -905,10 +954,13 @@ impl Ty {
905 // This is only used by type walking. 954 // This is only used by type walking.
906 // Parameters will be walked outside, and projection predicate is not used. 955 // Parameters will be walked outside, and projection predicate is not used.
907 // So just provide the Future trait. 956 // So just provide the Future trait.
908 let impl_bound = WhereClause::Implemented(TraitRef { 957 let impl_bound = Binders::new(
909 trait_id: to_chalk_trait_id(future_trait), 958 0,
910 substitution: Substitution::empty(), 959 WhereClause::Implemented(TraitRef {
911 }); 960 trait_id: to_chalk_trait_id(future_trait),
961 substitution: Substitution::empty(),
962 }),
963 );
912 Some(vec![impl_bound]) 964 Some(vec![impl_bound])
913 } else { 965 } else {
914 None 966 None
@@ -945,7 +997,7 @@ impl Ty {
945 .generic_predicates(id.parent) 997 .generic_predicates(id.parent)
946 .into_iter() 998 .into_iter()
947 .map(|pred| pred.clone().subst(&substs)) 999 .map(|pred| pred.clone().subst(&substs))
948 .filter(|wc| match &wc { 1000 .filter(|wc| match &wc.skip_binders() {
949 WhereClause::Implemented(tr) => tr.self_type_parameter() == self, 1001 WhereClause::Implemented(tr) => tr.self_type_parameter() == self,
950 WhereClause::AliasEq(AliasEq { 1002 WhereClause::AliasEq(AliasEq {
951 alias: AliasTy::Projection(proj), 1003 alias: AliasTy::Projection(proj),
@@ -1094,8 +1146,8 @@ impl TypeWalk for Ty {
1094 t.walk(f); 1146 t.walk(f);
1095 } 1147 }
1096 } 1148 }
1097 TyKind::Dyn(predicates) => { 1149 TyKind::Dyn(dyn_ty) => {
1098 for p in predicates.iter() { 1150 for p in dyn_ty.bounds.value.interned().iter() {
1099 p.walk(f); 1151 p.walk(f);
1100 } 1152 }
1101 } 1153 }
@@ -1122,8 +1174,8 @@ impl TypeWalk for Ty {
1122 TyKind::Alias(AliasTy::Projection(p_ty)) => { 1174 TyKind::Alias(AliasTy::Projection(p_ty)) => {
1123 p_ty.substitution.walk_mut_binders(f, binders); 1175 p_ty.substitution.walk_mut_binders(f, binders);
1124 } 1176 }
1125 TyKind::Dyn(predicates) => { 1177 TyKind::Dyn(dyn_ty) => {
1126 for p in make_mut_slice(predicates) { 1178 for p in make_mut_slice(&mut dyn_ty.bounds.value.0) {
1127 p.walk_mut_binders(f, binders.shifted_in()); 1179 p.walk_mut_binders(f, binders.shifted_in());
1128 } 1180 }
1129 } 1181 }
@@ -1173,7 +1225,7 @@ pub struct ReturnTypeImplTraits {
1173 1225
1174#[derive(Clone, PartialEq, Eq, Debug, Hash)] 1226#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1175pub(crate) struct ReturnTypeImplTrait { 1227pub(crate) struct ReturnTypeImplTrait {
1176 pub(crate) bounds: Binders<Vec<WhereClause>>, 1228 pub(crate) bounds: Binders<Vec<QuantifiedWhereClause>>,
1177} 1229}
1178 1230
1179pub fn to_foreign_def_id(id: TypeAliasId) -> ForeignDefId { 1231pub fn to_foreign_def_id(id: TypeAliasId) -> ForeignDefId {
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index fd451a823..3153b5b74 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -33,9 +33,10 @@ use crate::{
33 all_super_trait_refs, associated_type_by_name_including_super_traits, generics, 33 all_super_trait_refs, associated_type_by_name_including_super_traits, generics,
34 variant_data, 34 variant_data,
35 }, 35 },
36 AliasEq, AliasTy, Binders, BoundVar, CallableSig, DebruijnIndex, FnPointer, FnSig, ImplTraitId, 36 AliasEq, AliasTy, Binders, BoundVar, CallableSig, DebruijnIndex, DynTy, FnPointer, FnSig,
37 OpaqueTy, PolyFnSig, ProjectionTy, ReturnTypeImplTrait, ReturnTypeImplTraits, Substitution, 37 ImplTraitId, OpaqueTy, PolyFnSig, ProjectionTy, QuantifiedWhereClause, QuantifiedWhereClauses,
38 TraitEnvironment, TraitRef, Ty, TyKind, TypeWalk, WhereClause, 38 ReturnTypeImplTrait, ReturnTypeImplTraits, Substitution, TraitEnvironment, TraitRef, Ty,
39 TyKind, TypeWalk, WhereClause,
39}; 40};
40 41
41#[derive(Debug)] 42#[derive(Debug)]
@@ -188,13 +189,14 @@ impl<'a> TyLoweringContext<'a> {
188 TypeRef::DynTrait(bounds) => { 189 TypeRef::DynTrait(bounds) => {
189 let self_ty = 190 let self_ty =
190 TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(&Interner); 191 TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(&Interner);
191 let predicates = self.with_shifted_in(DebruijnIndex::ONE, |ctx| { 192 let bounds = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
192 bounds 193 QuantifiedWhereClauses::from_iter(
193 .iter() 194 &Interner,
194 .flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)) 195 bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)),
195 .collect() 196 )
196 }); 197 });
197 TyKind::Dyn(predicates).intern(&Interner) 198 let bounds = Binders::new(1, bounds);
199 TyKind::Dyn(DynTy { bounds }).intern(&Interner)
198 } 200 }
199 TypeRef::ImplTrait(bounds) => { 201 TypeRef::ImplTrait(bounds) => {
200 match self.impl_trait_mode { 202 match self.impl_trait_mode {
@@ -376,7 +378,16 @@ impl<'a> TyLoweringContext<'a> {
376 // FIXME report error (ambiguous associated type) 378 // FIXME report error (ambiguous associated type)
377 TyKind::Unknown.intern(&Interner) 379 TyKind::Unknown.intern(&Interner)
378 } else { 380 } else {
379 TyKind::Dyn(Arc::new([WhereClause::Implemented(trait_ref)])).intern(&Interner) 381 let dyn_ty = DynTy {
382 bounds: Binders::new(
383 1,
384 QuantifiedWhereClauses::from_iter(
385 &Interner,
386 Some(Binders::wrap_empty(WhereClause::Implemented(trait_ref))),
387 ),
388 ),
389 };
390 TyKind::Dyn(dyn_ty).intern(&Interner)
380 }; 391 };
381 return (ty, None); 392 return (ty, None);
382 } 393 }
@@ -510,7 +521,7 @@ impl<'a> TyLoweringContext<'a> {
510 TyDefId::AdtId(it) => Some(it.into()), 521 TyDefId::AdtId(it) => Some(it.into()),
511 TyDefId::TypeAliasId(it) => Some(it.into()), 522 TyDefId::TypeAliasId(it) => Some(it.into()),
512 }; 523 };
513 let substs = self.substs_from_path_segment(segment, generic_def, infer_args); 524 let substs = self.substs_from_path_segment(segment, generic_def, infer_args, None);
514 self.db.ty(typeable).subst(&substs) 525 self.db.ty(typeable).subst(&substs)
515 } 526 }
516 527
@@ -547,7 +558,7 @@ impl<'a> TyLoweringContext<'a> {
547 (segment, Some(var.parent.into())) 558 (segment, Some(var.parent.into()))
548 } 559 }
549 }; 560 };
550 self.substs_from_path_segment(segment, generic_def, infer_args) 561 self.substs_from_path_segment(segment, generic_def, infer_args, None)
551 } 562 }
552 563
553 fn substs_from_path_segment( 564 fn substs_from_path_segment(
@@ -555,6 +566,7 @@ impl<'a> TyLoweringContext<'a> {
555 segment: PathSegment<'_>, 566 segment: PathSegment<'_>,
556 def_generic: Option<GenericDefId>, 567 def_generic: Option<GenericDefId>,
557 infer_args: bool, 568 infer_args: bool,
569 explicit_self_ty: Option<Ty>,
558 ) -> Substitution { 570 ) -> Substitution {
559 let mut substs = Vec::new(); 571 let mut substs = Vec::new();
560 let def_generics = def_generic.map(|def| generics(self.db.upcast(), def)); 572 let def_generics = def_generic.map(|def| generics(self.db.upcast(), def));
@@ -565,11 +577,19 @@ impl<'a> TyLoweringContext<'a> {
565 577
566 substs.extend(iter::repeat(TyKind::Unknown.intern(&Interner)).take(parent_params)); 578 substs.extend(iter::repeat(TyKind::Unknown.intern(&Interner)).take(parent_params));
567 579
580 let fill_self_params = || {
581 substs.extend(
582 explicit_self_ty
583 .into_iter()
584 .chain(iter::repeat(TyKind::Unknown.intern(&Interner)))
585 .take(self_params),
586 )
587 };
568 let mut had_explicit_type_args = false; 588 let mut had_explicit_type_args = false;
569 589
570 if let Some(generic_args) = &segment.args_and_bindings { 590 if let Some(generic_args) = &segment.args_and_bindings {
571 if !generic_args.has_self_type { 591 if !generic_args.has_self_type {
572 substs.extend(iter::repeat(TyKind::Unknown.intern(&Interner)).take(self_params)); 592 fill_self_params();
573 } 593 }
574 let expected_num = 594 let expected_num =
575 if generic_args.has_self_type { self_params + type_params } else { type_params }; 595 if generic_args.has_self_type { self_params + type_params } else { type_params };
@@ -591,6 +611,8 @@ impl<'a> TyLoweringContext<'a> {
591 GenericArg::Lifetime(_) => {} 611 GenericArg::Lifetime(_) => {}
592 } 612 }
593 } 613 }
614 } else {
615 fill_self_params();
594 } 616 }
595 617
596 // handle defaults. In expression or pattern path segments without 618 // handle defaults. In expression or pattern path segments without
@@ -639,10 +661,7 @@ impl<'a> TyLoweringContext<'a> {
639 segment: PathSegment<'_>, 661 segment: PathSegment<'_>,
640 explicit_self_ty: Option<Ty>, 662 explicit_self_ty: Option<Ty>,
641 ) -> TraitRef { 663 ) -> TraitRef {
642 let mut substs = self.trait_ref_substs_from_path(segment, resolved); 664 let substs = self.trait_ref_substs_from_path(segment, resolved, explicit_self_ty);
643 if let Some(self_ty) = explicit_self_ty {
644 substs.0[0] = self_ty;
645 }
646 TraitRef { trait_id: to_chalk_trait_id(resolved), substitution: substs } 665 TraitRef { trait_id: to_chalk_trait_id(resolved), substitution: substs }
647 } 666 }
648 667
@@ -662,15 +681,16 @@ impl<'a> TyLoweringContext<'a> {
662 &self, 681 &self,
663 segment: PathSegment<'_>, 682 segment: PathSegment<'_>,
664 resolved: TraitId, 683 resolved: TraitId,
684 explicit_self_ty: Option<Ty>,
665 ) -> Substitution { 685 ) -> Substitution {
666 self.substs_from_path_segment(segment, Some(resolved.into()), false) 686 self.substs_from_path_segment(segment, Some(resolved.into()), false, explicit_self_ty)
667 } 687 }
668 688
669 pub(crate) fn lower_where_predicate( 689 pub(crate) fn lower_where_predicate(
670 &'a self, 690 &'a self,
671 where_predicate: &'a WherePredicate, 691 where_predicate: &'a WherePredicate,
672 ignore_bindings: bool, 692 ignore_bindings: bool,
673 ) -> impl Iterator<Item = WhereClause> + 'a { 693 ) -> impl Iterator<Item = QuantifiedWhereClause> + 'a {
674 match where_predicate { 694 match where_predicate {
675 WherePredicate::ForLifetime { target, bound, .. } 695 WherePredicate::ForLifetime { target, bound, .. }
676 | WherePredicate::TypeBound { target, bound } => { 696 | WherePredicate::TypeBound { target, bound } => {
@@ -705,12 +725,12 @@ impl<'a> TyLoweringContext<'a> {
705 bound: &'a TypeBound, 725 bound: &'a TypeBound,
706 self_ty: Ty, 726 self_ty: Ty,
707 ignore_bindings: bool, 727 ignore_bindings: bool,
708 ) -> impl Iterator<Item = WhereClause> + 'a { 728 ) -> impl Iterator<Item = QuantifiedWhereClause> + 'a {
709 let mut bindings = None; 729 let mut bindings = None;
710 let trait_ref = match bound { 730 let trait_ref = match bound {
711 TypeBound::Path(path) => { 731 TypeBound::Path(path) => {
712 bindings = self.lower_trait_ref_from_path(path, Some(self_ty)); 732 bindings = self.lower_trait_ref_from_path(path, Some(self_ty));
713 bindings.clone().map(WhereClause::Implemented) 733 bindings.clone().map(WhereClause::Implemented).map(|b| Binders::wrap_empty(b))
714 } 734 }
715 TypeBound::Lifetime(_) => None, 735 TypeBound::Lifetime(_) => None,
716 TypeBound::Error => None, 736 TypeBound::Error => None,
@@ -727,7 +747,7 @@ impl<'a> TyLoweringContext<'a> {
727 &'a self, 747 &'a self,
728 bound: &'a TypeBound, 748 bound: &'a TypeBound,
729 trait_ref: TraitRef, 749 trait_ref: TraitRef,
730 ) -> impl Iterator<Item = WhereClause> + 'a { 750 ) -> impl Iterator<Item = QuantifiedWhereClause> + 'a {
731 let last_segment = match bound { 751 let last_segment = match bound {
732 TypeBound::Path(path) => path.segments().last(), 752 TypeBound::Path(path) => path.segments().last(),
733 TypeBound::Error | TypeBound::Lifetime(_) => None, 753 TypeBound::Error | TypeBound::Lifetime(_) => None,
@@ -743,7 +763,7 @@ impl<'a> TyLoweringContext<'a> {
743 &binding.name, 763 &binding.name,
744 ); 764 );
745 let (super_trait_ref, associated_ty) = match found { 765 let (super_trait_ref, associated_ty) = match found {
746 None => return SmallVec::<[WhereClause; 1]>::new(), 766 None => return SmallVec::<[QuantifiedWhereClause; 1]>::new(),
747 Some(t) => t, 767 Some(t) => t,
748 }; 768 };
749 let projection_ty = ProjectionTy { 769 let projection_ty = ProjectionTy {
@@ -757,7 +777,7 @@ impl<'a> TyLoweringContext<'a> {
757 let ty = self.lower_ty(type_ref); 777 let ty = self.lower_ty(type_ref);
758 let alias_eq = 778 let alias_eq =
759 AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty }; 779 AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty };
760 preds.push(WhereClause::AliasEq(alias_eq)); 780 preds.push(Binders::wrap_empty(WhereClause::AliasEq(alias_eq)));
761 } 781 }
762 for bound in &binding.bounds { 782 for bound in &binding.bounds {
763 preds.extend(self.lower_type_bound( 783 preds.extend(self.lower_type_bound(
@@ -814,7 +834,7 @@ pub fn associated_type_shorthand_candidates<R>(
814 let predicates = db.generic_predicates_for_param(param_id); 834 let predicates = db.generic_predicates_for_param(param_id);
815 let mut traits_: Vec<_> = predicates 835 let mut traits_: Vec<_> = predicates
816 .iter() 836 .iter()
817 .filter_map(|pred| match &pred.value { 837 .filter_map(|pred| match &pred.value.value {
818 WhereClause::Implemented(tr) => Some(tr.clone()), 838 WhereClause::Implemented(tr) => Some(tr.clone()),
819 _ => None, 839 _ => None,
820 }) 840 })
@@ -887,7 +907,7 @@ pub(crate) fn field_types_query(
887pub(crate) fn generic_predicates_for_param_query( 907pub(crate) fn generic_predicates_for_param_query(
888 db: &dyn HirDatabase, 908 db: &dyn HirDatabase,
889 param_id: TypeParamId, 909 param_id: TypeParamId,
890) -> Arc<[Binders<WhereClause>]> { 910) -> Arc<[Binders<QuantifiedWhereClause>]> {
891 let resolver = param_id.parent.resolver(db.upcast()); 911 let resolver = param_id.parent.resolver(db.upcast());
892 let ctx = 912 let ctx =
893 TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable); 913 TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
@@ -915,7 +935,7 @@ pub(crate) fn generic_predicates_for_param_recover(
915 _db: &dyn HirDatabase, 935 _db: &dyn HirDatabase,
916 _cycle: &[String], 936 _cycle: &[String],
917 _param_id: &TypeParamId, 937 _param_id: &TypeParamId,
918) -> Arc<[Binders<WhereClause>]> { 938) -> Arc<[Binders<QuantifiedWhereClause>]> {
919 Arc::new([]) 939 Arc::new([])
920} 940}
921 941
@@ -930,7 +950,7 @@ pub(crate) fn trait_environment_query(
930 let mut clauses = Vec::new(); 950 let mut clauses = Vec::new();
931 for pred in resolver.where_predicates_in_scope() { 951 for pred in resolver.where_predicates_in_scope() {
932 for pred in ctx.lower_where_predicate(pred, false) { 952 for pred in ctx.lower_where_predicate(pred, false) {
933 if let WhereClause::Implemented(tr) = &pred { 953 if let WhereClause::Implemented(tr) = &pred.skip_binders() {
934 traits_in_scope.push((tr.self_type_parameter().clone(), tr.hir_trait_id())); 954 traits_in_scope.push((tr.self_type_parameter().clone(), tr.hir_trait_id()));
935 } 955 }
936 let program_clause: chalk_ir::ProgramClause<Interner> = 956 let program_clause: chalk_ir::ProgramClause<Interner> =
@@ -970,7 +990,7 @@ pub(crate) fn trait_environment_query(
970pub(crate) fn generic_predicates_query( 990pub(crate) fn generic_predicates_query(
971 db: &dyn HirDatabase, 991 db: &dyn HirDatabase,
972 def: GenericDefId, 992 def: GenericDefId,
973) -> Arc<[Binders<WhereClause>]> { 993) -> Arc<[Binders<QuantifiedWhereClause>]> {
974 let resolver = def.resolver(db.upcast()); 994 let resolver = def.resolver(db.upcast());
975 let ctx = 995 let ctx =
976 TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable); 996 TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs
index da6bc2a4a..8e986ddde 100644
--- a/crates/hir_ty/src/method_resolution.rs
+++ b/crates/hir_ty/src/method_resolution.rs
@@ -6,7 +6,7 @@ use std::{iter, sync::Arc};
6 6
7use arrayvec::ArrayVec; 7use arrayvec::ArrayVec;
8use base_db::CrateId; 8use base_db::CrateId;
9use chalk_ir::{cast::Cast, Mutability}; 9use chalk_ir::{cast::Cast, Mutability, UniverseIndex};
10use hir_def::{ 10use hir_def::{
11 lang_item::LangItemTarget, AssocContainerId, AssocItemId, FunctionId, GenericDefId, HasModule, 11 lang_item::LangItemTarget, AssocContainerId, AssocItemId, FunctionId, GenericDefId, HasModule,
12 ImplId, Lookup, ModuleId, TraitId, 12 ImplId, Lookup, ModuleId, TraitId,
@@ -21,8 +21,9 @@ use crate::{
21 primitive::{self, FloatTy, IntTy, UintTy}, 21 primitive::{self, FloatTy, IntTy, UintTy},
22 to_chalk_trait_id, 22 to_chalk_trait_id,
23 utils::all_super_traits, 23 utils::all_super_traits,
24 AdtId, Canonical, DebruijnIndex, FnPointer, FnSig, ForeignDefId, InEnvironment, Interner, 24 AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, FnPointer, FnSig, ForeignDefId,
25 Scalar, Substitution, TraitEnvironment, TraitRef, Ty, TyKind, TypeWalk, 25 InEnvironment, Interner, Scalar, Substitution, TraitEnvironment, TraitRef, Ty, TyKind,
26 TypeWalk,
26}; 27};
27 28
28/// This is used as a key for indexing impls. 29/// This is used as a key for indexing impls.
@@ -375,7 +376,7 @@ fn iterate_method_candidates_impl(
375 // Also note that when we've got a receiver like &S, even if the method we 376 // Also note that when we've got a receiver like &S, even if the method we
376 // find in the end takes &self, we still do the autoderef step (just as 377 // find in the end takes &self, we still do the autoderef step (just as
377 // rustc does an autoderef and then autoref again). 378 // rustc does an autoderef and then autoref again).
378 let ty = InEnvironment { value: ty.clone(), environment: env.clone() }; 379 let ty = InEnvironment { goal: ty.clone(), environment: env.env.clone() };
379 380
380 // We have to be careful about the order we're looking at candidates 381 // We have to be careful about the order we're looking at candidates
381 // in here. Consider the case where we're resolving `x.clone()` 382 // in here. Consider the case where we're resolving `x.clone()`
@@ -443,7 +444,7 @@ fn iterate_method_candidates_with_autoref(
443 return true; 444 return true;
444 } 445 }
445 let refed = Canonical { 446 let refed = Canonical {
446 kinds: deref_chain[0].kinds.clone(), 447 binders: deref_chain[0].binders.clone(),
447 value: TyKind::Ref(Mutability::Not, deref_chain[0].value.clone()).intern(&Interner), 448 value: TyKind::Ref(Mutability::Not, deref_chain[0].value.clone()).intern(&Interner),
448 }; 449 };
449 if iterate_method_candidates_by_receiver( 450 if iterate_method_candidates_by_receiver(
@@ -459,7 +460,7 @@ fn iterate_method_candidates_with_autoref(
459 return true; 460 return true;
460 } 461 }
461 let ref_muted = Canonical { 462 let ref_muted = Canonical {
462 kinds: deref_chain[0].kinds.clone(), 463 binders: deref_chain[0].binders.clone(),
463 value: TyKind::Ref(Mutability::Mut, deref_chain[0].value.clone()).intern(&Interner), 464 value: TyKind::Ref(Mutability::Mut, deref_chain[0].value.clone()).intern(&Interner),
464 }; 465 };
465 if iterate_method_candidates_by_receiver( 466 if iterate_method_candidates_by_receiver(
@@ -621,7 +622,7 @@ pub fn resolve_indexing_op(
621 krate: CrateId, 622 krate: CrateId,
622 index_trait: TraitId, 623 index_trait: TraitId,
623) -> Option<Canonical<Ty>> { 624) -> Option<Canonical<Ty>> {
624 let ty = InEnvironment { value: ty.clone(), environment: env.clone() }; 625 let ty = InEnvironment { goal: ty.clone(), environment: env.env.clone() };
625 let deref_chain = autoderef_method_receiver(db, krate, ty); 626 let deref_chain = autoderef_method_receiver(db, krate, ty);
626 for ty in deref_chain { 627 for ty in deref_chain {
627 let goal = generic_implements_goal(db, env.clone(), index_trait, ty.clone()); 628 let goal = generic_implements_goal(db, env.clone(), index_trait, ty.clone());
@@ -677,19 +678,28 @@ pub(crate) fn inherent_impl_substs(
677 // we create a var for each type parameter of the impl; we need to keep in 678 // we create a var for each type parameter of the impl; we need to keep in
678 // mind here that `self_ty` might have vars of its own 679 // mind here that `self_ty` might have vars of its own
679 let vars = Substitution::build_for_def(db, impl_id) 680 let vars = Substitution::build_for_def(db, impl_id)
680 .fill_with_bound_vars(DebruijnIndex::INNERMOST, self_ty.kinds.len()) 681 .fill_with_bound_vars(DebruijnIndex::INNERMOST, self_ty.binders.len(&Interner))
681 .build(); 682 .build();
682 let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars); 683 let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars);
683 let mut kinds = self_ty.kinds.to_vec(); 684 let mut kinds = self_ty.binders.interned().to_vec();
684 kinds.extend(iter::repeat(chalk_ir::TyVariableKind::General).take(vars.len())); 685 kinds.extend(
685 let tys = Canonical { kinds: kinds.into(), value: (self_ty_with_vars, self_ty.value.clone()) }; 686 iter::repeat(chalk_ir::WithKind::new(
687 chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General),
688 UniverseIndex::ROOT,
689 ))
690 .take(vars.len()),
691 );
692 let tys = Canonical {
693 binders: CanonicalVarKinds::from_iter(&Interner, kinds),
694 value: (self_ty_with_vars, self_ty.value.clone()),
695 };
686 let substs = super::infer::unify(&tys); 696 let substs = super::infer::unify(&tys);
687 // We only want the substs for the vars we added, not the ones from self_ty. 697 // We only want the substs for the vars we added, not the ones from self_ty.
688 // Also, if any of the vars we added are still in there, we replace them by 698 // Also, if any of the vars we added are still in there, we replace them by
689 // Unknown. I think this can only really happen if self_ty contained 699 // Unknown. I think this can only really happen if self_ty contained
690 // Unknown, and in that case we want the result to contain Unknown in those 700 // Unknown, and in that case we want the result to contain Unknown in those
691 // places again. 701 // places again.
692 substs.map(|s| fallback_bound_vars(s.suffix(vars.len()), self_ty.kinds.len())) 702 substs.map(|s| fallback_bound_vars(s.suffix(vars.len()), self_ty.binders.len(&Interner)))
693} 703}
694 704
695/// This replaces any 'free' Bound vars in `s` (i.e. those with indices past 705/// This replaces any 'free' Bound vars in `s` (i.e. those with indices past
@@ -768,15 +778,24 @@ fn generic_implements_goal(
768 trait_: TraitId, 778 trait_: TraitId,
769 self_ty: Canonical<Ty>, 779 self_ty: Canonical<Ty>,
770) -> Canonical<InEnvironment<super::DomainGoal>> { 780) -> Canonical<InEnvironment<super::DomainGoal>> {
771 let mut kinds = self_ty.kinds.to_vec(); 781 let mut kinds = self_ty.binders.interned().to_vec();
772 let substs = super::Substitution::build_for_def(db, trait_) 782 let substs = super::Substitution::build_for_def(db, trait_)
773 .push(self_ty.value) 783 .push(self_ty.value)
774 .fill_with_bound_vars(DebruijnIndex::INNERMOST, kinds.len()) 784 .fill_with_bound_vars(DebruijnIndex::INNERMOST, kinds.len())
775 .build(); 785 .build();
776 kinds.extend(iter::repeat(chalk_ir::TyVariableKind::General).take(substs.len() - 1)); 786 kinds.extend(
787 iter::repeat(chalk_ir::WithKind::new(
788 chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General),
789 UniverseIndex::ROOT,
790 ))
791 .take(substs.len() - 1),
792 );
777 let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs }; 793 let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs };
778 let obligation = trait_ref.cast(&Interner); 794 let obligation = trait_ref.cast(&Interner);
779 Canonical { kinds: kinds.into(), value: InEnvironment::new(env, obligation) } 795 Canonical {
796 binders: CanonicalVarKinds::from_iter(&Interner, kinds),
797 value: InEnvironment::new(env.env.clone(), obligation),
798 }
780} 799}
781 800
782fn autoderef_method_receiver( 801fn autoderef_method_receiver(
@@ -789,9 +808,9 @@ fn autoderef_method_receiver(
789 if let Some(TyKind::Array(parameters)) = 808 if let Some(TyKind::Array(parameters)) =
790 deref_chain.last().map(|ty| ty.value.interned(&Interner)) 809 deref_chain.last().map(|ty| ty.value.interned(&Interner))
791 { 810 {
792 let kinds = deref_chain.last().unwrap().kinds.clone(); 811 let kinds = deref_chain.last().unwrap().binders.clone();
793 let unsized_ty = TyKind::Slice(parameters.clone()).intern(&Interner); 812 let unsized_ty = TyKind::Slice(parameters.clone()).intern(&Interner);
794 deref_chain.push(Canonical { value: unsized_ty, kinds }) 813 deref_chain.push(Canonical { value: unsized_ty, binders: kinds })
795 } 814 }
796 deref_chain 815 deref_chain
797} 816}
diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs
index 69314e245..b69f86050 100644
--- a/crates/hir_ty/src/tests/regression.rs
+++ b/crates/hir_ty/src/tests/regression.rs
@@ -961,3 +961,16 @@ fn issue_6852() {
961 "#]], 961 "#]],
962 ); 962 );
963} 963}
964
965#[test]
966fn param_overrides_fn() {
967 check_types(
968 r#"
969 fn example(example: i32) {
970 fn f() {}
971 example;
972 //^^^^^^^ i32
973 }
974 "#,
975 )
976}
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs
index 37cd04c6f..45a1958e3 100644
--- a/crates/hir_ty/src/tests/traits.rs
+++ b/crates/hir_ty/src/tests/traits.rs
@@ -3324,3 +3324,49 @@ fn f() {
3324 "#]], 3324 "#]],
3325 ) 3325 )
3326} 3326}
3327
3328#[test]
3329fn infer_default_trait_type_parameter() {
3330 check_infer(
3331 r#"
3332struct A;
3333
3334trait Op<RHS=Self> {
3335 type Output;
3336
3337 fn do_op(self, rhs: RHS) -> Self::Output;
3338}
3339
3340impl Op for A {
3341 type Output = bool;
3342
3343 fn do_op(self, rhs: Self) -> Self::Output {
3344 true
3345 }
3346}
3347
3348fn test() {
3349 let x = A;
3350 let y = A;
3351 let r = x.do_op(y);
3352}
3353 "#,
3354 expect![[r#"
3355 63..67 'self': Self
3356 69..72 'rhs': RHS
3357 153..157 'self': A
3358 159..162 'rhs': A
3359 186..206 '{ ... }': bool
3360 196..200 'true': bool
3361 220..277 '{ ...(y); }': ()
3362 230..231 'x': A
3363 234..235 'A': A
3364 245..246 'y': A
3365 249..250 'A': A
3366 260..261 'r': bool
3367 264..265 'x': A
3368 264..274 'x.do_op(y)': bool
3369 272..273 'y': A
3370 "#]],
3371 )
3372}
diff --git a/crates/hir_ty/src/traits.rs b/crates/hir_ty/src/traits.rs
index 7dadd1ffb..ccee0e5ad 100644
--- a/crates/hir_ty/src/traits.rs
+++ b/crates/hir_ty/src/traits.rs
@@ -1,6 +1,5 @@
1//! Trait solving using Chalk. 1//! Trait solving using Chalk.
2use std::env::var; 2use std::env::var;
3use std::sync::Arc;
4 3
5use base_db::CrateId; 4use base_db::CrateId;
6use chalk_ir::cast::Cast; 5use chalk_ir::cast::Cast;
@@ -44,7 +43,7 @@ pub struct TraitEnvironment {
44 // When we're using Chalk's Ty we can make this a BTreeMap since it's Ord, 43 // When we're using Chalk's Ty we can make this a BTreeMap since it's Ord,
45 // but for now it's too annoying... 44 // but for now it's too annoying...
46 pub(crate) traits_from_clauses: Vec<(Ty, TraitId)>, 45 pub(crate) traits_from_clauses: Vec<(Ty, TraitId)>,
47 pub(crate) env: chalk_ir::Environment<Interner>, 46 pub env: chalk_ir::Environment<Interner>,
48} 47}
49 48
50impl TraitEnvironment { 49impl TraitEnvironment {
@@ -74,13 +73,13 @@ impl Default for TraitEnvironment {
74/// Something (usually a goal), along with an environment. 73/// Something (usually a goal), along with an environment.
75#[derive(Clone, Debug, PartialEq, Eq, Hash)] 74#[derive(Clone, Debug, PartialEq, Eq, Hash)]
76pub struct InEnvironment<T> { 75pub struct InEnvironment<T> {
77 pub environment: Arc<TraitEnvironment>, 76 pub environment: chalk_ir::Environment<Interner>,
78 pub value: T, 77 pub goal: T,
79} 78}
80 79
81impl<T> InEnvironment<T> { 80impl<T> InEnvironment<T> {
82 pub fn new(environment: Arc<TraitEnvironment>, value: T) -> InEnvironment<T> { 81 pub fn new(environment: chalk_ir::Environment<Interner>, value: T) -> InEnvironment<T> {
83 InEnvironment { environment, value } 82 InEnvironment { environment, goal: value }
84 } 83 }
85} 84}
86 85
@@ -126,18 +125,18 @@ pub(crate) fn trait_solve_query(
126 krate: CrateId, 125 krate: CrateId,
127 goal: Canonical<InEnvironment<DomainGoal>>, 126 goal: Canonical<InEnvironment<DomainGoal>>,
128) -> Option<Solution> { 127) -> Option<Solution> {
129 let _p = profile::span("trait_solve_query").detail(|| match &goal.value.value { 128 let _p = profile::span("trait_solve_query").detail(|| match &goal.value.goal {
130 DomainGoal::Holds(WhereClause::Implemented(it)) => { 129 DomainGoal::Holds(WhereClause::Implemented(it)) => {
131 db.trait_data(it.hir_trait_id()).name.to_string() 130 db.trait_data(it.hir_trait_id()).name.to_string()
132 } 131 }
133 DomainGoal::Holds(WhereClause::AliasEq(_)) => "alias_eq".to_string(), 132 DomainGoal::Holds(WhereClause::AliasEq(_)) => "alias_eq".to_string(),
134 }); 133 });
135 log::info!("trait_solve_query({})", goal.value.value.display(db)); 134 log::info!("trait_solve_query({})", goal.value.goal.display(db));
136 135
137 if let DomainGoal::Holds(WhereClause::AliasEq(AliasEq { 136 if let DomainGoal::Holds(WhereClause::AliasEq(AliasEq {
138 alias: AliasTy::Projection(projection_ty), 137 alias: AliasTy::Projection(projection_ty),
139 .. 138 ..
140 })) = &goal.value.value 139 })) = &goal.value.goal
141 { 140 {
142 if let TyKind::BoundVar(_) = &projection_ty.substitution[0].interned(&Interner) { 141 if let TyKind::BoundVar(_) = &projection_ty.substitution[0].interned(&Interner) {
143 // Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible 142 // Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible
diff --git a/crates/hir_ty/src/traits/chalk.rs b/crates/hir_ty/src/traits/chalk.rs
index 944145603..4019fdf17 100644
--- a/crates/hir_ty/src/traits/chalk.rs
+++ b/crates/hir_ty/src/traits/chalk.rs
@@ -238,7 +238,10 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
238 }); 238 });
239 let bound = OpaqueTyDatumBound { 239 let bound = OpaqueTyDatumBound {
240 bounds: make_binders( 240 bounds: make_binders(
241 vec![impl_bound.to_chalk(self.db), proj_bound.to_chalk(self.db)], 241 vec![
242 wrap_in_empty_binders(impl_bound).to_chalk(self.db),
243 wrap_in_empty_binders(proj_bound).to_chalk(self.db),
244 ],
242 1, 245 1,
243 ), 246 ),
244 where_clauses: make_binders(vec![], 0), 247 where_clauses: make_binders(vec![], 0),
@@ -397,7 +400,6 @@ pub(crate) fn associated_ty_data_query(
397 .iter() 400 .iter()
398 .flat_map(|bound| ctx.lower_type_bound(bound, self_ty.clone(), false)) 401 .flat_map(|bound| ctx.lower_type_bound(bound, self_ty.clone(), false))
399 .filter_map(|pred| generic_predicate_to_inline_bound(db, &pred, &self_ty)) 402 .filter_map(|pred| generic_predicate_to_inline_bound(db, &pred, &self_ty))
400 .map(|bound| make_binders(bound.shifted_in(&Interner), 0))
401 .collect(); 403 .collect();
402 404
403 let where_clauses = convert_where_clauses(db, type_alias.into(), &bound_vars); 405 let where_clauses = convert_where_clauses(db, type_alias.into(), &bound_vars);
@@ -720,3 +722,7 @@ impl From<crate::db::InternedClosureId> for chalk_ir::ClosureId<Interner> {
720 chalk_ir::ClosureId(id.as_intern_id()) 722 chalk_ir::ClosureId(id.as_intern_id())
721 } 723 }
722} 724}
725
726fn wrap_in_empty_binders<T: crate::TypeWalk>(value: T) -> crate::Binders<T> {
727 crate::Binders::wrap_empty(value)
728}
diff --git a/crates/hir_ty/src/traits/chalk/mapping.rs b/crates/hir_ty/src/traits/chalk/mapping.rs
index 65feb82e5..aef6b8a15 100644
--- a/crates/hir_ty/src/traits/chalk/mapping.rs
+++ b/crates/hir_ty/src/traits/chalk/mapping.rs
@@ -7,15 +7,14 @@ use chalk_ir::{cast::Cast, fold::shift::Shift, interner::HasInterner, LifetimeDa
7use chalk_solve::rust_ir; 7use chalk_solve::rust_ir;
8 8
9use base_db::salsa::InternKey; 9use base_db::salsa::InternKey;
10use hir_def::{AssocContainerId, GenericDefId, Lookup, TypeAliasId}; 10use hir_def::{GenericDefId, TypeAliasId};
11 11
12use crate::{ 12use crate::{
13 db::HirDatabase, 13 db::HirDatabase,
14 from_assoc_type_id,
15 primitive::UintTy, 14 primitive::UintTy,
16 traits::{Canonical, DomainGoal}, 15 traits::{Canonical, DomainGoal},
17 AliasTy, CallableDefId, FnPointer, InEnvironment, OpaqueTy, ProjectionTy, Scalar, Substitution, 16 AliasTy, CallableDefId, FnPointer, InEnvironment, OpaqueTy, ProjectionTy,
18 TraitRef, Ty, WhereClause, 17 QuantifiedWhereClause, Scalar, Substitution, TraitRef, Ty, TypeWalk, WhereClause,
19}; 18};
20 19
21use super::interner::*; 20use super::interner::*;
@@ -95,10 +94,10 @@ impl ToChalk for Ty {
95 TyKind::Placeholder(idx) => idx.to_ty::<Interner>(&Interner), 94 TyKind::Placeholder(idx) => idx.to_ty::<Interner>(&Interner),
96 TyKind::BoundVar(idx) => chalk_ir::TyKind::BoundVar(idx).intern(&Interner), 95 TyKind::BoundVar(idx) => chalk_ir::TyKind::BoundVar(idx).intern(&Interner),
97 TyKind::InferenceVar(..) => panic!("uncanonicalized infer ty"), 96 TyKind::InferenceVar(..) => panic!("uncanonicalized infer ty"),
98 TyKind::Dyn(predicates) => { 97 TyKind::Dyn(dyn_ty) => {
99 let where_clauses = chalk_ir::QuantifiedWhereClauses::from_iter( 98 let where_clauses = chalk_ir::QuantifiedWhereClauses::from_iter(
100 &Interner, 99 &Interner,
101 predicates.iter().cloned().map(|p| p.to_chalk(db)), 100 dyn_ty.bounds.value.interned().iter().cloned().map(|p| p.to_chalk(db)),
102 ); 101 );
103 let bounded_ty = chalk_ir::DynTy { 102 let bounded_ty = chalk_ir::DynTy {
104 bounds: make_binders(where_clauses, 1), 103 bounds: make_binders(where_clauses, 1),
@@ -144,13 +143,17 @@ impl ToChalk for Ty {
144 chalk_ir::TyKind::InferenceVar(_iv, _kind) => TyKind::Unknown, 143 chalk_ir::TyKind::InferenceVar(_iv, _kind) => TyKind::Unknown,
145 chalk_ir::TyKind::Dyn(where_clauses) => { 144 chalk_ir::TyKind::Dyn(where_clauses) => {
146 assert_eq!(where_clauses.bounds.binders.len(&Interner), 1); 145 assert_eq!(where_clauses.bounds.binders.len(&Interner), 1);
147 let predicates = where_clauses 146 let bounds = where_clauses
148 .bounds 147 .bounds
149 .skip_binders() 148 .skip_binders()
150 .iter(&Interner) 149 .iter(&Interner)
151 .map(|c| from_chalk(db, c.clone())) 150 .map(|c| from_chalk(db, c.clone()));
152 .collect(); 151 TyKind::Dyn(crate::DynTy {
153 TyKind::Dyn(predicates) 152 bounds: crate::Binders::new(
153 1,
154 crate::QuantifiedWhereClauses::from_iter(&Interner, bounds),
155 ),
156 })
154 } 157 }
155 158
156 chalk_ir::TyKind::Adt(adt_id, subst) => TyKind::Adt(adt_id, from_chalk(db, subst)), 159 chalk_ir::TyKind::Adt(adt_id, subst) => TyKind::Adt(adt_id, from_chalk(db, subst)),
@@ -305,33 +308,22 @@ impl ToChalk for TypeAliasAsValue {
305} 308}
306 309
307impl ToChalk for WhereClause { 310impl ToChalk for WhereClause {
308 type Chalk = chalk_ir::QuantifiedWhereClause<Interner>; 311 type Chalk = chalk_ir::WhereClause<Interner>;
309 312
310 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::QuantifiedWhereClause<Interner> { 313 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::WhereClause<Interner> {
311 match self { 314 match self {
312 WhereClause::Implemented(trait_ref) => { 315 WhereClause::Implemented(trait_ref) => {
313 let chalk_trait_ref = trait_ref.to_chalk(db); 316 chalk_ir::WhereClause::Implemented(trait_ref.to_chalk(db))
314 let chalk_trait_ref = chalk_trait_ref.shifted_in(&Interner);
315 make_binders(chalk_ir::WhereClause::Implemented(chalk_trait_ref), 0)
316 } 317 }
317 WhereClause::AliasEq(alias_eq) => make_binders( 318 WhereClause::AliasEq(alias_eq) => chalk_ir::WhereClause::AliasEq(alias_eq.to_chalk(db)),
318 chalk_ir::WhereClause::AliasEq(alias_eq.to_chalk(db).shifted_in(&Interner)),
319 0,
320 ),
321 } 319 }
322 } 320 }
323 321
324 fn from_chalk( 322 fn from_chalk(
325 db: &dyn HirDatabase, 323 db: &dyn HirDatabase,
326 where_clause: chalk_ir::QuantifiedWhereClause<Interner>, 324 where_clause: chalk_ir::WhereClause<Interner>,
327 ) -> WhereClause { 325 ) -> WhereClause {
328 // we don't produce any where clauses with binders and can't currently deal with them 326 match where_clause {
329 match where_clause
330 .skip_binders()
331 .clone()
332 .shifted_out(&Interner)
333 .expect("unexpected bound vars in where clause")
334 {
335 chalk_ir::WhereClause::Implemented(tr) => WhereClause::Implemented(from_chalk(db, tr)), 327 chalk_ir::WhereClause::Implemented(tr) => WhereClause::Implemented(from_chalk(db, tr)),
336 chalk_ir::WhereClause::AliasEq(alias_eq) => { 328 chalk_ir::WhereClause::AliasEq(alias_eq) => {
337 WhereClause::AliasEq(from_chalk(db, alias_eq)) 329 WhereClause::AliasEq(from_chalk(db, alias_eq))
@@ -447,35 +439,12 @@ where
447 type Chalk = chalk_ir::Canonical<T::Chalk>; 439 type Chalk = chalk_ir::Canonical<T::Chalk>;
448 440
449 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Canonical<T::Chalk> { 441 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Canonical<T::Chalk> {
450 let kinds = self.kinds.iter().map(|&tk| {
451 chalk_ir::CanonicalVarKind::new(
452 chalk_ir::VariableKind::Ty(tk),
453 chalk_ir::UniverseIndex::ROOT,
454 )
455 });
456 let value = self.value.to_chalk(db); 442 let value = self.value.to_chalk(db);
457 chalk_ir::Canonical { 443 chalk_ir::Canonical { value, binders: self.binders }
458 value,
459 binders: chalk_ir::CanonicalVarKinds::from_iter(&Interner, kinds),
460 }
461 } 444 }
462 445
463 fn from_chalk(db: &dyn HirDatabase, canonical: chalk_ir::Canonical<T::Chalk>) -> Canonical<T> { 446 fn from_chalk(db: &dyn HirDatabase, canonical: chalk_ir::Canonical<T::Chalk>) -> Canonical<T> {
464 let kinds = canonical 447 Canonical { binders: canonical.binders, value: from_chalk(db, canonical.value) }
465 .binders
466 .iter(&Interner)
467 .map(|k| match k.kind {
468 chalk_ir::VariableKind::Ty(tk) => tk,
469 // HACK: Chalk can sometimes return new lifetime variables. We
470 // want to just skip them, but to not mess up the indices of
471 // other variables, we'll just create a new type variable in
472 // their place instead. This should not matter (we never see the
473 // actual *uses* of the lifetime variable).
474 chalk_ir::VariableKind::Lifetime => chalk_ir::TyVariableKind::General,
475 chalk_ir::VariableKind::Const(_) => panic!("unexpected const from Chalk"),
476 })
477 .collect();
478 Canonical { kinds, value: from_chalk(db, canonical.value) }
479 } 448 }
480} 449}
481 450
@@ -486,10 +455,7 @@ where
486 type Chalk = chalk_ir::InEnvironment<T::Chalk>; 455 type Chalk = chalk_ir::InEnvironment<T::Chalk>;
487 456
488 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::InEnvironment<T::Chalk> { 457 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::InEnvironment<T::Chalk> {
489 chalk_ir::InEnvironment { 458 chalk_ir::InEnvironment { environment: self.environment, goal: self.goal.to_chalk(db) }
490 environment: self.environment.env.clone(),
491 goal: self.value.to_chalk(db),
492 }
493 } 459 }
494 460
495 fn from_chalk( 461 fn from_chalk(
@@ -500,6 +466,29 @@ where
500 } 466 }
501} 467}
502 468
469impl<T: ToChalk> ToChalk for crate::Binders<T>
470where
471 T::Chalk: chalk_ir::interner::HasInterner<Interner = Interner>,
472{
473 type Chalk = chalk_ir::Binders<T::Chalk>;
474
475 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Binders<T::Chalk> {
476 chalk_ir::Binders::new(
477 chalk_ir::VariableKinds::from_iter(
478 &Interner,
479 std::iter::repeat(chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General))
480 .take(self.num_binders),
481 ),
482 self.value.to_chalk(db),
483 )
484 }
485
486 fn from_chalk(db: &dyn HirDatabase, binders: chalk_ir::Binders<T::Chalk>) -> crate::Binders<T> {
487 let (v, b) = binders.into_value_and_skipped_binders();
488 crate::Binders::new(b.len(&Interner), from_chalk(db, v))
489 }
490}
491
503pub(super) fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> 492pub(super) fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T>
504where 493where
505 T: HasInterner<Interner = Interner>, 494 T: HasInterner<Interner = Interner>,
@@ -529,14 +518,15 @@ pub(super) fn convert_where_clauses(
529 518
530pub(super) fn generic_predicate_to_inline_bound( 519pub(super) fn generic_predicate_to_inline_bound(
531 db: &dyn HirDatabase, 520 db: &dyn HirDatabase,
532 pred: &WhereClause, 521 pred: &QuantifiedWhereClause,
533 self_ty: &Ty, 522 self_ty: &Ty,
534) -> Option<rust_ir::InlineBound<Interner>> { 523) -> Option<chalk_ir::Binders<rust_ir::InlineBound<Interner>>> {
535 // An InlineBound is like a GenericPredicate, except the self type is left out. 524 // An InlineBound is like a GenericPredicate, except the self type is left out.
536 // We don't have a special type for this, but Chalk does. 525 // We don't have a special type for this, but Chalk does.
537 match pred { 526 let self_ty_shifted_in = self_ty.clone().shift_bound_vars(DebruijnIndex::ONE);
527 match &pred.value {
538 WhereClause::Implemented(trait_ref) => { 528 WhereClause::Implemented(trait_ref) => {
539 if &trait_ref.substitution[0] != self_ty { 529 if trait_ref.self_type_parameter() != &self_ty_shifted_in {
540 // we can only convert predicates back to type bounds if they 530 // we can only convert predicates back to type bounds if they
541 // have the expected self type 531 // have the expected self type
542 return None; 532 return None;
@@ -546,19 +536,13 @@ pub(super) fn generic_predicate_to_inline_bound(
546 .map(|ty| ty.clone().to_chalk(db).cast(&Interner)) 536 .map(|ty| ty.clone().to_chalk(db).cast(&Interner))
547 .collect(); 537 .collect();
548 let trait_bound = rust_ir::TraitBound { trait_id: trait_ref.trait_id, args_no_self }; 538 let trait_bound = rust_ir::TraitBound { trait_id: trait_ref.trait_id, args_no_self };
549 Some(rust_ir::InlineBound::TraitBound(trait_bound)) 539 Some(make_binders(rust_ir::InlineBound::TraitBound(trait_bound), pred.num_binders))
550 } 540 }
551 WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => { 541 WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => {
552 if &projection_ty.substitution[0] != self_ty { 542 if projection_ty.self_type_parameter() != &self_ty_shifted_in {
553 return None; 543 return None;
554 } 544 }
555 let trait_ = match from_assoc_type_id(projection_ty.associated_ty_id) 545 let trait_ = projection_ty.trait_(db);
556 .lookup(db.upcast())
557 .container
558 {
559 AssocContainerId::TraitId(t) => t,
560 _ => panic!("associated type not in trait"),
561 };
562 let args_no_self = projection_ty.substitution[1..] 546 let args_no_self = projection_ty.substitution[1..]
563 .iter() 547 .iter()
564 .map(|ty| ty.clone().to_chalk(db).cast(&Interner)) 548 .map(|ty| ty.clone().to_chalk(db).cast(&Interner))
@@ -569,7 +553,7 @@ pub(super) fn generic_predicate_to_inline_bound(
569 associated_ty_id: projection_ty.associated_ty_id, 553 associated_ty_id: projection_ty.associated_ty_id,
570 parameters: Vec::new(), // FIXME we don't support generic associated types yet 554 parameters: Vec::new(), // FIXME we don't support generic associated types yet
571 }; 555 };
572 Some(rust_ir::InlineBound::AliasEqBound(alias_eq_bound)) 556 Some(make_binders(rust_ir::InlineBound::AliasEqBound(alias_eq_bound), pred.num_binders))
573 } 557 }
574 _ => None, 558 _ => None,
575 } 559 }
diff --git a/crates/hir_ty/src/utils.rs b/crates/hir_ty/src/utils.rs
index 1ec1ecd43..19874e42b 100644
--- a/crates/hir_ty/src/utils.rs
+++ b/crates/hir_ty/src/utils.rs
@@ -63,7 +63,7 @@ fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef) -> Vec<Tr
63 db.generic_predicates_for_param(trait_self) 63 db.generic_predicates_for_param(trait_self)
64 .iter() 64 .iter()
65 .filter_map(|pred| { 65 .filter_map(|pred| {
66 pred.as_ref().filter_map(|pred| match pred { 66 pred.as_ref().filter_map(|pred| match pred.skip_binders() {
67 WhereClause::Implemented(tr) => Some(tr.clone()), 67 WhereClause::Implemented(tr) => Some(tr.clone()),
68 _ => None, 68 _ => None,
69 }) 69 })
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 662da5a96..3f73c0632 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -37,6 +37,7 @@ mod hover;
37mod inlay_hints; 37mod inlay_hints;
38mod join_lines; 38mod join_lines;
39mod matching_brace; 39mod matching_brace;
40mod move_item;
40mod parent_module; 41mod parent_module;
41mod references; 42mod references;
42mod fn_references; 43mod fn_references;
@@ -76,6 +77,7 @@ pub use crate::{
76 hover::{HoverAction, HoverConfig, HoverGotoTypeData, HoverResult}, 77 hover::{HoverAction, HoverConfig, HoverGotoTypeData, HoverResult},
77 inlay_hints::{InlayHint, InlayHintsConfig, InlayKind}, 78 inlay_hints::{InlayHint, InlayHintsConfig, InlayKind},
78 markup::Markup, 79 markup::Markup,
80 move_item::Direction,
79 prime_caches::PrimeCachesProgress, 81 prime_caches::PrimeCachesProgress,
80 references::{rename::RenameError, ReferenceSearchResult}, 82 references::{rename::RenameError, ReferenceSearchResult},
81 runnables::{Runnable, RunnableKind, TestId}, 83 runnables::{Runnable, RunnableKind, TestId},
@@ -583,6 +585,14 @@ impl Analysis {
583 self.with_db(|db| annotations::resolve_annotation(db, annotation)) 585 self.with_db(|db| annotations::resolve_annotation(db, annotation))
584 } 586 }
585 587
588 pub fn move_item(
589 &self,
590 range: FileRange,
591 direction: Direction,
592 ) -> Cancelable<Option<TextEdit>> {
593 self.with_db(|db| move_item::move_item(db, range, direction))
594 }
595
586 /// Performs an operation on that may be Canceled. 596 /// Performs an operation on that may be Canceled.
587 fn with_db<F, T>(&self, f: F) -> Cancelable<T> 597 fn with_db<F, T>(&self, f: F) -> Cancelable<T>
588 where 598 where
diff --git a/crates/ide/src/move_item.rs b/crates/ide/src/move_item.rs
new file mode 100644
index 000000000..48690b073
--- /dev/null
+++ b/crates/ide/src/move_item.rs
@@ -0,0 +1,620 @@
1use std::iter::once;
2
3use hir::Semantics;
4use ide_db::{base_db::FileRange, RootDatabase};
5use itertools::Itertools;
6use syntax::{
7 algo, ast, match_ast, AstNode, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, TextRange,
8};
9use text_edit::{TextEdit, TextEditBuilder};
10
11pub enum Direction {
12 Up,
13 Down,
14}
15
16// Feature: Move Item
17//
18// Move item under cursor or selection up and down.
19//
20// |===
21// | Editor | Action Name
22//
23// | VS Code | **Rust Analyzer: Move item up**
24// | VS Code | **Rust Analyzer: Move item down**
25// |===
26pub(crate) fn move_item(
27 db: &RootDatabase,
28 range: FileRange,
29 direction: Direction,
30) -> Option<TextEdit> {
31 let sema = Semantics::new(db);
32 let file = sema.parse(range.file_id);
33
34 let item = file.syntax().covering_element(range.range);
35 find_ancestors(item, direction, range.range)
36}
37
38fn find_ancestors(item: SyntaxElement, direction: Direction, range: TextRange) -> Option<TextEdit> {
39 let root = match item {
40 NodeOrToken::Node(node) => node,
41 NodeOrToken::Token(token) => token.parent()?,
42 };
43
44 let movable = [
45 SyntaxKind::ARG_LIST,
46 SyntaxKind::GENERIC_PARAM_LIST,
47 SyntaxKind::GENERIC_ARG_LIST,
48 SyntaxKind::VARIANT_LIST,
49 SyntaxKind::TYPE_BOUND_LIST,
50 SyntaxKind::MATCH_ARM,
51 SyntaxKind::PARAM,
52 SyntaxKind::LET_STMT,
53 SyntaxKind::EXPR_STMT,
54 SyntaxKind::MATCH_EXPR,
55 SyntaxKind::MACRO_CALL,
56 SyntaxKind::TYPE_ALIAS,
57 SyntaxKind::TRAIT,
58 SyntaxKind::IMPL,
59 SyntaxKind::MACRO_DEF,
60 SyntaxKind::STRUCT,
61 SyntaxKind::UNION,
62 SyntaxKind::ENUM,
63 SyntaxKind::FN,
64 SyntaxKind::MODULE,
65 SyntaxKind::USE,
66 SyntaxKind::STATIC,
67 SyntaxKind::CONST,
68 SyntaxKind::MACRO_RULES,
69 ];
70
71 let ancestor = once(root.clone())
72 .chain(root.ancestors())
73 .find(|ancestor| movable.contains(&ancestor.kind()))?;
74
75 move_in_direction(&ancestor, direction, range)
76}
77
78fn move_in_direction(
79 node: &SyntaxNode,
80 direction: Direction,
81 range: TextRange,
82) -> Option<TextEdit> {
83 match_ast! {
84 match node {
85 ast::ArgList(it) => swap_sibling_in_list(it.args(), range, direction),
86 ast::GenericParamList(it) => swap_sibling_in_list(it.generic_params(), range, direction),
87 ast::GenericArgList(it) => swap_sibling_in_list(it.generic_args(), range, direction),
88 ast::VariantList(it) => swap_sibling_in_list(it.variants(), range, direction),
89 ast::TypeBoundList(it) => swap_sibling_in_list(it.bounds(), range, direction),
90 _ => Some(replace_nodes(node, &match direction {
91 Direction::Up => node.prev_sibling(),
92 Direction::Down => node.next_sibling(),
93 }?))
94 }
95 }
96}
97
98fn swap_sibling_in_list<A: AstNode + Clone, I: Iterator<Item = A>>(
99 list: I,
100 range: TextRange,
101 direction: Direction,
102) -> Option<TextEdit> {
103 let (l, r) = list
104 .tuple_windows()
105 .filter(|(l, r)| match direction {
106 Direction::Up => r.syntax().text_range().contains_range(range),
107 Direction::Down => l.syntax().text_range().contains_range(range),
108 })
109 .next()?;
110
111 Some(replace_nodes(l.syntax(), r.syntax()))
112}
113
114fn replace_nodes(first: &SyntaxNode, second: &SyntaxNode) -> TextEdit {
115 let mut edit = TextEditBuilder::default();
116
117 algo::diff(first, second).into_text_edit(&mut edit);
118 algo::diff(second, first).into_text_edit(&mut edit);
119
120 edit.finish()
121}
122
123#[cfg(test)]
124mod tests {
125 use crate::fixture;
126 use expect_test::{expect, Expect};
127
128 use crate::Direction;
129
130 fn check(ra_fixture: &str, expect: Expect, direction: Direction) {
131 let (analysis, range) = fixture::range(ra_fixture);
132 let edit = analysis.move_item(range, direction).unwrap().unwrap_or_default();
133 let mut file = analysis.file_text(range.file_id).unwrap().to_string();
134 edit.apply(&mut file);
135 expect.assert_eq(&file);
136 }
137
138 #[test]
139 fn test_moves_match_arm_up() {
140 check(
141 r#"
142fn main() {
143 match true {
144 true => {
145 println!("Hello, world");
146 },
147 false =>$0$0 {
148 println!("Test");
149 }
150 };
151}
152 "#,
153 expect![[r#"
154fn main() {
155 match true {
156 false => {
157 println!("Test");
158 },
159 true => {
160 println!("Hello, world");
161 }
162 };
163}
164 "#]],
165 Direction::Up,
166 );
167 }
168
169 #[test]
170 fn test_moves_match_arm_down() {
171 check(
172 r#"
173fn main() {
174 match true {
175 true =>$0$0 {
176 println!("Hello, world");
177 },
178 false => {
179 println!("Test");
180 }
181 };
182}
183 "#,
184 expect![[r#"
185fn main() {
186 match true {
187 false => {
188 println!("Test");
189 },
190 true => {
191 println!("Hello, world");
192 }
193 };
194}
195 "#]],
196 Direction::Down,
197 );
198 }
199
200 #[test]
201 fn test_nowhere_to_move() {
202 check(
203 r#"
204fn main() {
205 match true {
206 true =>$0$0 {
207 println!("Hello, world");
208 },
209 false => {
210 println!("Test");
211 }
212 };
213}
214 "#,
215 expect![[r#"
216fn main() {
217 match true {
218 true => {
219 println!("Hello, world");
220 },
221 false => {
222 println!("Test");
223 }
224 };
225}
226 "#]],
227 Direction::Up,
228 );
229 }
230
231 #[test]
232 fn test_moves_let_stmt_up() {
233 check(
234 r#"
235fn main() {
236 let test = 123;
237 let test2$0$0 = 456;
238}
239 "#,
240 expect![[r#"
241fn main() {
242 let test2 = 456;
243 let test = 123;
244}
245 "#]],
246 Direction::Up,
247 );
248 }
249
250 #[test]
251 fn test_moves_expr_up() {
252 check(
253 r#"
254fn main() {
255 println!("Hello, world");
256 println!("All I want to say is...");$0$0
257}
258 "#,
259 expect![[r#"
260fn main() {
261 println!("All I want to say is...");
262 println!("Hello, world");
263}
264 "#]],
265 Direction::Up,
266 );
267 }
268
269 #[test]
270 fn test_nowhere_to_move_stmt() {
271 check(
272 r#"
273fn main() {
274 println!("All I want to say is...");$0$0
275 println!("Hello, world");
276}
277 "#,
278 expect![[r#"
279fn main() {
280 println!("All I want to say is...");
281 println!("Hello, world");
282}
283 "#]],
284 Direction::Up,
285 );
286 }
287
288 #[test]
289 fn test_move_item() {
290 check(
291 r#"
292fn main() {}
293
294fn foo() {}$0$0
295 "#,
296 expect![[r#"
297fn foo() {}
298
299fn main() {}
300 "#]],
301 Direction::Up,
302 );
303 }
304
305 #[test]
306 fn test_move_impl_up() {
307 check(
308 r#"
309struct Yay;
310
311trait Wow {}
312
313impl Wow for Yay $0$0{}
314 "#,
315 expect![[r#"
316struct Yay;
317
318impl Wow for Yay {}
319
320trait Wow {}
321 "#]],
322 Direction::Up,
323 );
324 }
325
326 #[test]
327 fn test_move_use_up() {
328 check(
329 r#"
330use std::vec::Vec;
331use std::collections::HashMap$0$0;
332 "#,
333 expect![[r#"
334use std::collections::HashMap;
335use std::vec::Vec;
336 "#]],
337 Direction::Up,
338 );
339 }
340
341 #[test]
342 fn test_moves_match_expr_up() {
343 check(
344 r#"
345fn main() {
346 let test = 123;
347
348 $0match test {
349 456 => {},
350 _ => {}
351 };$0
352}
353 "#,
354 expect![[r#"
355fn main() {
356 match test {
357 456 => {},
358 _ => {}
359 };
360
361 let test = 123;
362}
363 "#]],
364 Direction::Up,
365 );
366 }
367
368 #[test]
369 fn test_moves_param_up() {
370 check(
371 r#"
372fn test(one: i32, two$0$0: u32) {}
373
374fn main() {
375 test(123, 456);
376}
377 "#,
378 expect![[r#"
379fn test(two: u32, one: i32) {}
380
381fn main() {
382 test(123, 456);
383}
384 "#]],
385 Direction::Up,
386 );
387 }
388
389 #[test]
390 fn test_moves_arg_up() {
391 check(
392 r#"
393fn test(one: i32, two: u32) {}
394
395fn main() {
396 test(123, 456$0$0);
397}
398 "#,
399 expect![[r#"
400fn test(one: i32, two: u32) {}
401
402fn main() {
403 test(456, 123);
404}
405 "#]],
406 Direction::Up,
407 );
408 }
409
410 #[test]
411 fn test_moves_arg_down() {
412 check(
413 r#"
414fn test(one: i32, two: u32) {}
415
416fn main() {
417 test(123$0$0, 456);
418}
419 "#,
420 expect![[r#"
421fn test(one: i32, two: u32) {}
422
423fn main() {
424 test(456, 123);
425}
426 "#]],
427 Direction::Down,
428 );
429 }
430
431 #[test]
432 fn test_nowhere_to_move_arg() {
433 check(
434 r#"
435fn test(one: i32, two: u32) {}
436
437fn main() {
438 test(123$0$0, 456);
439}
440 "#,
441 expect![[r#"
442fn test(one: i32, two: u32) {}
443
444fn main() {
445 test(123, 456);
446}
447 "#]],
448 Direction::Up,
449 );
450 }
451
452 #[test]
453 fn test_moves_generic_param_up() {
454 check(
455 r#"
456struct Test<A, B$0$0>(A, B);
457
458fn main() {}
459 "#,
460 expect![[r#"
461struct Test<B, A>(A, B);
462
463fn main() {}
464 "#]],
465 Direction::Up,
466 );
467 }
468
469 #[test]
470 fn test_moves_generic_arg_up() {
471 check(
472 r#"
473struct Test<A, B>(A, B);
474
475fn main() {
476 let t = Test::<i32, &str$0$0>(123, "yay");
477}
478 "#,
479 expect![[r#"
480struct Test<A, B>(A, B);
481
482fn main() {
483 let t = Test::<&str, i32>(123, "yay");
484}
485 "#]],
486 Direction::Up,
487 );
488 }
489
490 #[test]
491 fn test_moves_variant_up() {
492 check(
493 r#"
494enum Hello {
495 One,
496 Two$0$0
497}
498
499fn main() {}
500 "#,
501 expect![[r#"
502enum Hello {
503 Two,
504 One
505}
506
507fn main() {}
508 "#]],
509 Direction::Up,
510 );
511 }
512
513 #[test]
514 fn test_moves_type_bound_up() {
515 check(
516 r#"
517trait One {}
518
519trait Two {}
520
521fn test<T: One + Two$0$0>(t: T) {}
522
523fn main() {}
524 "#,
525 expect![[r#"
526trait One {}
527
528trait Two {}
529
530fn test<T: Two + One>(t: T) {}
531
532fn main() {}
533 "#]],
534 Direction::Up,
535 );
536 }
537
538 #[test]
539 fn test_prioritizes_trait_items() {
540 check(
541 r#"
542struct Test;
543
544trait Yay {
545 type One;
546
547 type Two;
548
549 fn inner();
550}
551
552impl Yay for Test {
553 type One = i32;
554
555 type Two = u32;
556
557 fn inner() {$0$0
558 println!("Mmmm");
559 }
560}
561 "#,
562 expect![[r#"
563struct Test;
564
565trait Yay {
566 type One;
567
568 type Two;
569
570 fn inner();
571}
572
573impl Yay for Test {
574 type One = i32;
575
576 fn inner() {
577 println!("Mmmm");
578 }
579
580 type Two = u32;
581}
582 "#]],
583 Direction::Up,
584 );
585 }
586
587 #[test]
588 fn test_weird_nesting() {
589 check(
590 r#"
591fn test() {
592 mod hello {
593 fn inner() {}
594 }
595
596 mod hi {$0$0
597 fn inner() {}
598 }
599}
600 "#,
601 expect![[r#"
602fn test() {
603 mod hi {
604 fn inner() {}
605 }
606
607 mod hello {
608 fn inner() {}
609 }
610}
611 "#]],
612 Direction::Up,
613 );
614 }
615
616 #[test]
617 fn handles_empty_file() {
618 check(r#"$0$0"#, expect![[r#""#]], Direction::Up);
619 }
620}
diff --git a/crates/ide_assists/src/handlers/merge_imports.rs b/crates/ide_assists/src/handlers/merge_imports.rs
index 7bd7e1e36..cfc472a32 100644
--- a/crates/ide_assists/src/handlers/merge_imports.rs
+++ b/crates/ide_assists/src/handlers/merge_imports.rs
@@ -1,8 +1,5 @@
1use ide_db::helpers::insert_use::{try_merge_imports, try_merge_trees, MergeBehavior}; 1use ide_db::helpers::insert_use::{try_merge_imports, try_merge_trees, MergeBehavior};
2use syntax::{ 2use syntax::{algo::neighbor, ast, ted, AstNode};
3 algo::{neighbor, SyntaxRewriter},
4 ast, AstNode,
5};
6 3
7use crate::{ 4use crate::{
8 assist_context::{AssistContext, Assists}, 5 assist_context::{AssistContext, Assists},
@@ -24,33 +21,29 @@ use crate::{
24// ``` 21// ```
25pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 22pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
26 let tree: ast::UseTree = ctx.find_node_at_offset()?; 23 let tree: ast::UseTree = ctx.find_node_at_offset()?;
27 let mut rewriter = SyntaxRewriter::default(); 24 let original_parent = tree.syntax().ancestors().last()?;
25
26 let tree = tree.clone_for_update();
27 let new_parent = tree.syntax().ancestors().last()?;
28
28 let mut offset = ctx.offset(); 29 let mut offset = ctx.offset();
29 30
31 let mut imports = None;
32 let mut uses = None;
30 if let Some(use_item) = tree.syntax().parent().and_then(ast::Use::cast) { 33 if let Some(use_item) = tree.syntax().parent().and_then(ast::Use::cast) {
31 let (merged, to_delete) = 34 let (merged, to_remove) =
32 next_prev().filter_map(|dir| neighbor(&use_item, dir)).find_map(|use_item2| { 35 next_prev().filter_map(|dir| neighbor(&use_item, dir)).find_map(|use_item2| {
33 try_merge_imports(&use_item, &use_item2, MergeBehavior::Full).zip(Some(use_item2)) 36 try_merge_imports(&use_item, &use_item2, MergeBehavior::Full).zip(Some(use_item2))
34 })?; 37 })?;
35 38
36 rewriter.replace_ast(&use_item, &merged); 39 imports = Some((use_item, merged, to_remove));
37 rewriter += to_delete.remove();
38
39 if to_delete.syntax().text_range().end() < offset {
40 offset -= to_delete.syntax().text_range().len();
41 }
42 } else { 40 } else {
43 let (merged, to_delete) = 41 let (merged, to_remove) =
44 next_prev().filter_map(|dir| neighbor(&tree, dir)).find_map(|use_tree| { 42 next_prev().filter_map(|dir| neighbor(&tree, dir)).find_map(|use_tree| {
45 try_merge_trees(&tree, &use_tree, MergeBehavior::Full).zip(Some(use_tree)) 43 try_merge_trees(&tree, &use_tree, MergeBehavior::Full).zip(Some(use_tree))
46 })?; 44 })?;
47 45
48 rewriter.replace_ast(&tree, &merged); 46 uses = Some((tree.clone(), merged, to_remove))
49 rewriter += to_delete.remove();
50
51 if to_delete.syntax().text_range().end() < offset {
52 offset -= to_delete.syntax().text_range().len();
53 }
54 }; 47 };
55 48
56 let target = tree.syntax().text_range(); 49 let target = tree.syntax().text_range();
@@ -59,7 +52,23 @@ pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext) -> Option<()
59 "Merge imports", 52 "Merge imports",
60 target, 53 target,
61 |builder| { 54 |builder| {
62 builder.rewrite(rewriter); 55 if let Some((to_replace, replacement, to_remove)) = imports {
56 if to_remove.syntax().text_range().end() < offset {
57 offset -= to_remove.syntax().text_range().len();
58 }
59 ted::replace(to_replace.syntax().clone(), replacement.syntax().clone());
60 to_remove.remove();
61 }
62
63 if let Some((to_replace, replacement, to_remove)) = uses {
64 if to_remove.syntax().text_range().end() < offset {
65 offset -= to_remove.syntax().text_range().len();
66 }
67 ted::replace(to_replace.syntax().clone(), replacement.syntax().clone());
68 to_remove.remove()
69 }
70
71 builder.replace(original_parent.text_range(), new_parent.to_string())
63 }, 72 },
64 ) 73 )
65} 74}
diff --git a/crates/ide_assists/src/handlers/unmerge_use.rs b/crates/ide_assists/src/handlers/unmerge_use.rs
index 616af7c2e..8d271e056 100644
--- a/crates/ide_assists/src/handlers/unmerge_use.rs
+++ b/crates/ide_assists/src/handlers/unmerge_use.rs
@@ -1,6 +1,6 @@
1use syntax::{ 1use syntax::{
2 algo::SyntaxRewriter, 2 ast::{self, VisibilityOwner},
3 ast::{self, edit::AstNodeEdit, VisibilityOwner}, 3 ted::{self, Position},
4 AstNode, SyntaxKind, 4 AstNode, SyntaxKind,
5}; 5};
6 6
@@ -22,7 +22,7 @@ use crate::{
22// use std::fmt::Display; 22// use std::fmt::Display;
23// ``` 23// ```
24pub(crate) fn unmerge_use(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 24pub(crate) fn unmerge_use(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
25 let tree: ast::UseTree = ctx.find_node_at_offset()?; 25 let tree: ast::UseTree = ctx.find_node_at_offset::<ast::UseTree>()?.clone_for_update();
26 26
27 let tree_list = tree.syntax().parent().and_then(ast::UseTreeList::cast)?; 27 let tree_list = tree.syntax().parent().and_then(ast::UseTreeList::cast)?;
28 if tree_list.use_trees().count() < 2 { 28 if tree_list.use_trees().count() < 2 {
@@ -33,6 +33,9 @@ pub(crate) fn unmerge_use(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
33 let use_: ast::Use = tree_list.syntax().ancestors().find_map(ast::Use::cast)?; 33 let use_: ast::Use = tree_list.syntax().ancestors().find_map(ast::Use::cast)?;
34 let path = resolve_full_path(&tree)?; 34 let path = resolve_full_path(&tree)?;
35 35
36 let old_parent_range = use_.syntax().parent()?.text_range();
37 let new_parent = use_.syntax().parent()?;
38
36 let target = tree.syntax().text_range(); 39 let target = tree.syntax().text_range();
37 acc.add( 40 acc.add(
38 AssistId("unmerge_use", AssistKind::RefactorRewrite), 41 AssistId("unmerge_use", AssistKind::RefactorRewrite),
@@ -47,20 +50,13 @@ pub(crate) fn unmerge_use(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
47 tree.rename(), 50 tree.rename(),
48 tree.star_token().is_some(), 51 tree.star_token().is_some(),
49 ), 52 ),
50 ); 53 )
51 54 .clone_for_update();
52 let mut rewriter = SyntaxRewriter::default(); 55
53 rewriter += tree.remove(); 56 tree.remove();
54 rewriter.insert_after(use_.syntax(), &ast::make::tokens::single_newline()); 57 ted::insert(Position::after(use_.syntax()), new_use.syntax());
55 if let ident_level @ 1..=usize::MAX = use_.indent_level().0 as usize { 58
56 rewriter.insert_after( 59 builder.replace(old_parent_range, new_parent.to_string());
57 use_.syntax(),
58 &ast::make::tokens::whitespace(&" ".repeat(4 * ident_level)),
59 );
60 }
61 rewriter.insert_after(use_.syntax(), new_use.syntax());
62
63 builder.rewrite(rewriter);
64 }, 60 },
65 ) 61 )
66} 62}
diff --git a/crates/ide_db/src/helpers/insert_use.rs b/crates/ide_db/src/helpers/insert_use.rs
index 9e0cb91c3..20c195f82 100644
--- a/crates/ide_db/src/helpers/insert_use.rs
+++ b/crates/ide_db/src/helpers/insert_use.rs
@@ -14,10 +14,12 @@ use syntax::{
14 AstToken, InsertPosition, NodeOrToken, SyntaxElement, SyntaxNode, SyntaxToken, 14 AstToken, InsertPosition, NodeOrToken, SyntaxElement, SyntaxNode, SyntaxToken,
15}; 15};
16 16
17pub use hir::PrefixKind;
18
17#[derive(Clone, Copy, Debug, PartialEq, Eq)] 19#[derive(Clone, Copy, Debug, PartialEq, Eq)]
18pub struct InsertUseConfig { 20pub struct InsertUseConfig {
19 pub merge: Option<MergeBehavior>, 21 pub merge: Option<MergeBehavior>,
20 pub prefix_kind: hir::PrefixKind, 22 pub prefix_kind: PrefixKind,
21 pub group: bool, 23 pub group: bool,
22} 24}
23 25
@@ -211,7 +213,7 @@ pub fn try_merge_imports(
211 let lhs_tree = lhs.use_tree()?; 213 let lhs_tree = lhs.use_tree()?;
212 let rhs_tree = rhs.use_tree()?; 214 let rhs_tree = rhs.use_tree()?;
213 let merged = try_merge_trees(&lhs_tree, &rhs_tree, merge_behavior)?; 215 let merged = try_merge_trees(&lhs_tree, &rhs_tree, merge_behavior)?;
214 Some(lhs.with_use_tree(merged)) 216 Some(lhs.with_use_tree(merged).clone_for_update())
215} 217}
216 218
217pub fn try_merge_trees( 219pub fn try_merge_trees(
@@ -232,7 +234,7 @@ pub fn try_merge_trees(
232 } else { 234 } else {
233 (lhs.split_prefix(&lhs_prefix), rhs.split_prefix(&rhs_prefix)) 235 (lhs.split_prefix(&lhs_prefix), rhs.split_prefix(&rhs_prefix))
234 }; 236 };
235 recursive_merge(&lhs, &rhs, merge) 237 recursive_merge(&lhs, &rhs, merge).map(|it| it.clone_for_update())
236} 238}
237 239
238/// Recursively "zips" together lhs and rhs. 240/// Recursively "zips" together lhs and rhs.
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 8f541976e..5c88c3a9b 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -10,10 +10,9 @@
10use std::{ffi::OsString, iter, path::PathBuf}; 10use std::{ffi::OsString, iter, path::PathBuf};
11 11
12use flycheck::FlycheckConfig; 12use flycheck::FlycheckConfig;
13use hir::PrefixKind;
14use ide::{AssistConfig, CompletionConfig, DiagnosticsConfig, HoverConfig, InlayHintsConfig}; 13use ide::{AssistConfig, CompletionConfig, DiagnosticsConfig, HoverConfig, InlayHintsConfig};
15use ide_db::helpers::{ 14use ide_db::helpers::{
16 insert_use::{InsertUseConfig, MergeBehavior}, 15 insert_use::{InsertUseConfig, MergeBehavior, PrefixKind},
17 SnippetCap, 16 SnippetCap,
18}; 17};
19use lsp_types::{ClientCapabilities, MarkupKind}; 18use lsp_types::{ClientCapabilities, MarkupKind};
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index 880fea622..85e67554c 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -1427,6 +1427,25 @@ pub(crate) fn handle_open_cargo_toml(
1427 Ok(Some(res)) 1427 Ok(Some(res))
1428} 1428}
1429 1429
1430pub(crate) fn handle_move_item(
1431 snap: GlobalStateSnapshot,
1432 params: lsp_ext::MoveItemParams,
1433) -> Result<Option<lsp_types::TextDocumentEdit>> {
1434 let _p = profile::span("handle_move_item");
1435 let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
1436 let range = from_proto::file_range(&snap, params.text_document, params.range)?;
1437
1438 let direction = match params.direction {
1439 lsp_ext::MoveItemDirection::Up => ide::Direction::Up,
1440 lsp_ext::MoveItemDirection::Down => ide::Direction::Down,
1441 };
1442
1443 match snap.analysis.move_item(range, direction)? {
1444 Some(text_edit) => Ok(Some(to_proto::text_document_edit(&snap, file_id, text_edit)?)),
1445 None => Ok(None),
1446 }
1447}
1448
1430fn to_command_link(command: lsp_types::Command, tooltip: String) -> lsp_ext::CommandLink { 1449fn to_command_link(command: lsp_types::Command, tooltip: String) -> lsp_ext::CommandLink {
1431 lsp_ext::CommandLink { tooltip: Some(tooltip), command } 1450 lsp_ext::CommandLink { tooltip: Some(tooltip), command }
1432} 1451}
diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs
index efcdcd1d9..0e1fec209 100644
--- a/crates/rust-analyzer/src/lsp_ext.rs
+++ b/crates/rust-analyzer/src/lsp_ext.rs
@@ -402,3 +402,25 @@ pub(crate) enum CodeLensResolveData {
402pub fn supports_utf8(caps: &lsp_types::ClientCapabilities) -> bool { 402pub fn supports_utf8(caps: &lsp_types::ClientCapabilities) -> bool {
403 caps.offset_encoding.as_deref().unwrap_or_default().iter().any(|it| it == "utf-8") 403 caps.offset_encoding.as_deref().unwrap_or_default().iter().any(|it| it == "utf-8")
404} 404}
405
406pub enum MoveItem {}
407
408impl Request for MoveItem {
409 type Params = MoveItemParams;
410 type Result = Option<lsp_types::TextDocumentEdit>;
411 const METHOD: &'static str = "experimental/moveItem";
412}
413
414#[derive(Serialize, Deserialize, Debug)]
415#[serde(rename_all = "camelCase")]
416pub struct MoveItemParams {
417 pub direction: MoveItemDirection,
418 pub text_document: TextDocumentIdentifier,
419 pub range: Range,
420}
421
422#[derive(Serialize, Deserialize, Debug)]
423pub enum MoveItemDirection {
424 Up,
425 Down,
426}
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index c63a0eaea..e88f16cc1 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -504,6 +504,7 @@ impl GlobalState {
504 .on::<lsp_ext::HoverRequest>(handlers::handle_hover) 504 .on::<lsp_ext::HoverRequest>(handlers::handle_hover)
505 .on::<lsp_ext::ExternalDocs>(handlers::handle_open_docs) 505 .on::<lsp_ext::ExternalDocs>(handlers::handle_open_docs)
506 .on::<lsp_ext::OpenCargoToml>(handlers::handle_open_cargo_toml) 506 .on::<lsp_ext::OpenCargoToml>(handlers::handle_open_cargo_toml)
507 .on::<lsp_ext::MoveItem>(handlers::handle_move_item)
507 .on::<lsp_types::request::OnTypeFormatting>(handlers::handle_on_type_formatting) 508 .on::<lsp_types::request::OnTypeFormatting>(handlers::handle_on_type_formatting)
508 .on::<lsp_types::request::DocumentSymbolRequest>(handlers::handle_document_symbol) 509 .on::<lsp_types::request::DocumentSymbolRequest>(handlers::handle_document_symbol)
509 .on::<lsp_types::request::WorkspaceSymbol>(handlers::handle_workspace_symbol) 510 .on::<lsp_types::request::WorkspaceSymbol>(handlers::handle_workspace_symbol)
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 1ddea9278..25169005f 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -658,6 +658,18 @@ pub(crate) fn goto_definition_response(
658 } 658 }
659} 659}
660 660
661pub(crate) fn text_document_edit(
662 snap: &GlobalStateSnapshot,
663 file_id: FileId,
664 edit: TextEdit,
665) -> Result<lsp_types::TextDocumentEdit> {
666 let text_document = optional_versioned_text_document_identifier(snap, file_id);
667 let line_index = snap.file_line_index(file_id)?;
668 let edits =
669 edit.into_iter().map(|it| lsp_types::OneOf::Left(text_edit(&line_index, it))).collect();
670 Ok(lsp_types::TextDocumentEdit { text_document, edits })
671}
672
661pub(crate) fn snippet_text_document_edit( 673pub(crate) fn snippet_text_document_edit(
662 snap: &GlobalStateSnapshot, 674 snap: &GlobalStateSnapshot,
663 is_snippet: bool, 675 is_snippet: bool,
@@ -1073,9 +1085,11 @@ pub(crate) fn rename_error(err: RenameError) -> crate::LspError {
1073mod tests { 1085mod tests {
1074 use std::sync::Arc; 1086 use std::sync::Arc;
1075 1087
1076 use hir::PrefixKind;
1077 use ide::Analysis; 1088 use ide::Analysis;
1078 use ide_db::helpers::{insert_use::InsertUseConfig, SnippetCap}; 1089 use ide_db::helpers::{
1090 insert_use::{InsertUseConfig, PrefixKind},
1091 SnippetCap,
1092 };
1079 1093
1080 use super::*; 1094 use super::*;
1081 1095
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml
index 74cafaa8d..0c3fec3c7 100644
--- a/crates/syntax/Cargo.toml
+++ b/crates/syntax/Cargo.toml
@@ -13,7 +13,7 @@ doctest = false
13[dependencies] 13[dependencies]
14cov-mark = { version = "1.1", features = ["thread-local"] } 14cov-mark = { version = "1.1", features = ["thread-local"] }
15itertools = "0.10.0" 15itertools = "0.10.0"
16rowan = "0.13.0-pre.2" 16rowan = "0.13.0-pre.3"
17rustc_lexer = { version = "710.0.0", package = "rustc-ap-rustc_lexer" } 17rustc_lexer = { version = "710.0.0", package = "rustc-ap-rustc_lexer" }
18rustc-hash = "1.1.0" 18rustc-hash = "1.1.0"
19arrayvec = "0.5.1" 19arrayvec = "0.5.1"
diff --git a/crates/syntax/src/ast/edit.rs b/crates/syntax/src/ast/edit.rs
index 347862b8a..18820786a 100644
--- a/crates/syntax/src/ast/edit.rs
+++ b/crates/syntax/src/ast/edit.rs
@@ -9,7 +9,7 @@ use std::{
9use arrayvec::ArrayVec; 9use arrayvec::ArrayVec;
10 10
11use crate::{ 11use crate::{
12 algo::{self, neighbor, SyntaxRewriter}, 12 algo::{self, SyntaxRewriter},
13 ast::{ 13 ast::{
14 self, 14 self,
15 make::{self, tokens}, 15 make::{self, tokens},
@@ -322,27 +322,6 @@ impl ast::Use {
322 } 322 }
323 self.clone() 323 self.clone()
324 } 324 }
325
326 pub fn remove(&self) -> SyntaxRewriter<'static> {
327 let mut res = SyntaxRewriter::default();
328 res.delete(self.syntax());
329 let next_ws = self
330 .syntax()
331 .next_sibling_or_token()
332 .and_then(|it| it.into_token())
333 .and_then(ast::Whitespace::cast);
334 if let Some(next_ws) = next_ws {
335 let ws_text = next_ws.syntax().text();
336 if let Some(rest) = ws_text.strip_prefix('\n') {
337 if rest.is_empty() {
338 res.delete(next_ws.syntax())
339 } else {
340 res.replace(next_ws.syntax(), &make::tokens::whitespace(rest));
341 }
342 }
343 }
344 res
345 }
346} 325}
347 326
348impl ast::UseTree { 327impl ast::UseTree {
@@ -396,22 +375,6 @@ impl ast::UseTree {
396 Some(res) 375 Some(res)
397 } 376 }
398 } 377 }
399
400 pub fn remove(&self) -> SyntaxRewriter<'static> {
401 let mut res = SyntaxRewriter::default();
402 res.delete(self.syntax());
403 for &dir in [Direction::Next, Direction::Prev].iter() {
404 if let Some(nb) = neighbor(self, dir) {
405 self.syntax()
406 .siblings_with_tokens(dir)
407 .skip(1)
408 .take_while(|it| it.as_node() != Some(nb.syntax()))
409 .for_each(|el| res.delete(&el));
410 return res;
411 }
412 }
413 res
414 }
415} 378}
416 379
417impl ast::MatchArmList { 380impl ast::MatchArmList {
@@ -592,6 +555,13 @@ impl ops::Add<u8> for IndentLevel {
592} 555}
593 556
594impl IndentLevel { 557impl IndentLevel {
558 pub fn from_element(element: &SyntaxElement) -> IndentLevel {
559 match element {
560 rowan::NodeOrToken::Node(it) => IndentLevel::from_node(it),
561 rowan::NodeOrToken::Token(it) => IndentLevel::from_token(it),
562 }
563 }
564
595 pub fn from_node(node: &SyntaxNode) -> IndentLevel { 565 pub fn from_node(node: &SyntaxNode) -> IndentLevel {
596 match node.first_token() { 566 match node.first_token() {
597 Some(it) => Self::from_token(&it), 567 Some(it) => Self::from_token(&it),
diff --git a/crates/syntax/src/ast/edit_in_place.rs b/crates/syntax/src/ast/edit_in_place.rs
index b1eed0a2c..529bd0eb1 100644
--- a/crates/syntax/src/ast/edit_in_place.rs
+++ b/crates/syntax/src/ast/edit_in_place.rs
@@ -2,13 +2,13 @@
2 2
3use std::iter::empty; 3use std::iter::empty;
4 4
5use ast::{edit::AstNodeEdit, make, GenericParamsOwner, WhereClause};
6use parser::T; 5use parser::T;
7 6
8use crate::{ 7use crate::{
9 ast, 8 algo::neighbor,
9 ast::{self, edit::AstNodeEdit, make, GenericParamsOwner, WhereClause},
10 ted::{self, Position}, 10 ted::{self, Position},
11 AstNode, Direction, 11 AstNode, AstToken, Direction,
12}; 12};
13 13
14use super::NameOwner; 14use super::NameOwner;
@@ -126,3 +126,41 @@ impl ast::TypeBoundList {
126 } 126 }
127 } 127 }
128} 128}
129
130impl ast::UseTree {
131 pub fn remove(&self) {
132 for &dir in [Direction::Next, Direction::Prev].iter() {
133 if let Some(next_use_tree) = neighbor(self, dir) {
134 let separators = self
135 .syntax()
136 .siblings_with_tokens(dir)
137 .skip(1)
138 .take_while(|it| it.as_node() != Some(next_use_tree.syntax()));
139 ted::remove_all_iter(separators);
140 break;
141 }
142 }
143 ted::remove(self.syntax())
144 }
145}
146
147impl ast::Use {
148 pub fn remove(&self) {
149 let next_ws = self
150 .syntax()
151 .next_sibling_or_token()
152 .and_then(|it| it.into_token())
153 .and_then(ast::Whitespace::cast);
154 if let Some(next_ws) = next_ws {
155 let ws_text = next_ws.syntax().text();
156 if let Some(rest) = ws_text.strip_prefix('\n') {
157 if rest.is_empty() {
158 ted::remove(next_ws.syntax())
159 } else {
160 ted::replace(next_ws.syntax(), make::tokens::whitespace(rest))
161 }
162 }
163 }
164 ted::remove(self.syntax())
165 }
166}
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs
index 7049affd9..c08f2c14f 100644
--- a/crates/syntax/src/ast/make.rs
+++ b/crates/syntax/src/ast/make.rs
@@ -560,7 +560,7 @@ pub mod tokens {
560 pub fn whitespace(text: &str) -> SyntaxToken { 560 pub fn whitespace(text: &str) -> SyntaxToken {
561 assert!(text.trim().is_empty()); 561 assert!(text.trim().is_empty());
562 let sf = SourceFile::parse(text).ok().unwrap(); 562 let sf = SourceFile::parse(text).ok().unwrap();
563 sf.syntax().first_child_or_token().unwrap().into_token().unwrap() 563 sf.syntax().clone_for_update().first_child_or_token().unwrap().into_token().unwrap()
564 } 564 }
565 565
566 pub fn doc_comment(text: &str) -> SyntaxToken { 566 pub fn doc_comment(text: &str) -> SyntaxToken {
diff --git a/crates/syntax/src/ted.rs b/crates/syntax/src/ted.rs
index be2b846b1..177d4ff67 100644
--- a/crates/syntax/src/ted.rs
+++ b/crates/syntax/src/ted.rs
@@ -2,11 +2,14 @@
2//! 2//!
3//! The `_raw`-suffixed functions insert elements as is, unsuffixed versions fix 3//! The `_raw`-suffixed functions insert elements as is, unsuffixed versions fix
4//! up elements around the edges. 4//! up elements around the edges.
5use std::ops::RangeInclusive; 5use std::{mem, ops::RangeInclusive};
6 6
7use parser::T; 7use parser::T;
8 8
9use crate::{ast::make, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken}; 9use crate::{
10 ast::{edit::IndentLevel, make},
11 SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken,
12};
10 13
11/// Utility trait to allow calling `ted` functions with references or owned 14/// Utility trait to allow calling `ted` functions with references or owned
12/// nodes. Do not use outside of this module. 15/// nodes. Do not use outside of this module.
@@ -101,12 +104,25 @@ pub fn insert_all_raw(position: Position, elements: Vec<SyntaxElement>) {
101} 104}
102 105
103pub fn remove(elem: impl Element) { 106pub fn remove(elem: impl Element) {
104 let elem = elem.syntax_element(); 107 elem.syntax_element().detach()
105 remove_all(elem.clone()..=elem)
106} 108}
107pub fn remove_all(range: RangeInclusive<SyntaxElement>) { 109pub fn remove_all(range: RangeInclusive<SyntaxElement>) {
108 replace_all(range, Vec::new()) 110 replace_all(range, Vec::new())
109} 111}
112pub fn remove_all_iter(range: impl IntoIterator<Item = SyntaxElement>) {
113 let mut it = range.into_iter();
114 if let Some(mut first) = it.next() {
115 match it.last() {
116 Some(mut last) => {
117 if first.index() > last.index() {
118 mem::swap(&mut first, &mut last)
119 }
120 remove_all(first..=last)
121 }
122 None => remove(first),
123 }
124 }
125}
110 126
111pub fn replace(old: impl Element, new: impl Element) { 127pub fn replace(old: impl Element, new: impl Element) {
112 let old = old.syntax_element(); 128 let old = old.syntax_element();
@@ -149,5 +165,9 @@ fn ws_between(left: &SyntaxElement, right: &SyntaxElement) -> Option<SyntaxToken
149 if right.kind() == T![;] || right.kind() == T![,] { 165 if right.kind() == T![;] || right.kind() == T![,] {
150 return None; 166 return None;
151 } 167 }
168 if right.kind() == SyntaxKind::USE {
169 let indent = IndentLevel::from_element(left);
170 return Some(make::tokens::whitespace(&format!("\n{}", indent)));
171 }
152 Some(make::tokens::single_space()) 172 Some(make::tokens::single_space())
153} 173}
diff --git a/docs/dev/README.md b/docs/dev/README.md
index b91013f13..57162a47d 100644
--- a/docs/dev/README.md
+++ b/docs/dev/README.md
@@ -226,6 +226,9 @@ If the GitHub Actions release fails because of a transient problem like a timeou
226If it fails because of something that needs to be fixed, remove the release tag (if needed), fix the problem, then start over. 226If it fails because of something that needs to be fixed, remove the release tag (if needed), fix the problem, then start over.
227Make sure to remove the new changelog post created when running `cargo xtask release` a second time. 227Make sure to remove the new changelog post created when running `cargo xtask release` a second time.
228 228
229We release "nightly" every night automatically and promote the latest nightly to "stable" manually, every week.
230We don't do "patch" releases, unless something truly egregious comes up.
231
229# Permissions 232# Permissions
230 233
231There are three sets of people with extra permissions: 234There are three sets of people with extra permissions:
diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md
index 694fafcd5..8a6f9f06e 100644
--- a/docs/dev/lsp-extensions.md
+++ b/docs/dev/lsp-extensions.md
@@ -1,5 +1,5 @@
1<!--- 1<!---
2lsp_ext.rs hash: 4dfa8d7035f4aee7 2lsp_ext.rs hash: e8a7502bd2b2c2f5
3 3
4If you need to change the above hash to make the test pass, please check if you 4If you need to change the above hash to make the test pass, please check if you
5need to adjust this doc as well and ping this issue: 5need to adjust this doc as well and ping this issue:
@@ -595,3 +595,29 @@ interface TestInfo {
595 runnable: Runnable; 595 runnable: Runnable;
596} 596}
597``` 597```
598
599## Hover Actions
600
601**Issue:** https://github.com/rust-analyzer/rust-analyzer/issues/6823
602
603This request is sent from client to server to move item under cursor or selection in some direction.
604
605**Method:** `experimental/moveItemUp`
606**Method:** `experimental/moveItemDown`
607
608**Request:** `MoveItemParams`
609
610**Response:** `TextDocumentEdit | null`
611
612```typescript
613export interface MoveItemParams {
614 textDocument: lc.TextDocumentIdentifier,
615 range: lc.Range,
616 direction: Direction
617}
618
619export const enum Direction {
620 Up = "Up",
621 Down = "Down"
622}
623```
diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc
index dba2197de..8656dd1da 100644
--- a/docs/user/manual.adoc
+++ b/docs/user/manual.adoc
@@ -516,6 +516,20 @@ See https://github.com/rust-analyzer/rust-project.json-example for a small examp
516 516
517You can set `RA_LOG` environmental variable to `rust_analyzer=info` to inspect how rust-analyzer handles config and project loading. 517You can set `RA_LOG` environmental variable to `rust_analyzer=info` to inspect how rust-analyzer handles config and project loading.
518 518
519== Security
520
521At the moment, rust-analyzer assumes that all code is trusted.
522Here is a **non-exhaustive** list of ways to make rust-analyzer execute arbitrary code:
523
524* proc macros and build scripts are executed by default
525* `.cargo/config` can override `rustc` with an arbitrary executable
526* VS Code plugin reads configuration from project directory, and that can be used to override paths to various executables, like `rustfmt` or `rust-analyzer` itself.
527* rust-analyzer's syntax trees library uses a lot of `unsafe` and hasn't been properly audited for memory safety.
528
529rust-analyzer itself doesn't access the network.
530The VS Code plugin doesn't access the network unless the nightly channel is selected in the settings.
531In that case, the plugin uses the GitHub API to check for and download updates.
532
519== Features 533== Features
520 534
521include::./generated_features.adoc[] 535include::./generated_features.adoc[]
diff --git a/editors/code/package.json b/editors/code/package.json
index a2ed9b2d5..faec45276 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -208,6 +208,16 @@
208 "command": "rust-analyzer.peekTests", 208 "command": "rust-analyzer.peekTests",
209 "title": "Peek related tests", 209 "title": "Peek related tests",
210 "category": "Rust Analyzer" 210 "category": "Rust Analyzer"
211 },
212 {
213 "command": "rust-analyzer.moveItemUp",
214 "title": "Move item up",
215 "category": "Rust Analyzer"
216 },
217 {
218 "command": "rust-analyzer.moveItemDown",
219 "title": "Move item down",
220 "category": "Rust Analyzer"
211 } 221 }
212 ], 222 ],
213 "keybindings": [ 223 "keybindings": [
diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts
index bed1f0116..1a0805bd3 100644
--- a/editors/code/src/commands.ts
+++ b/editors/code/src/commands.ts
@@ -134,6 +134,51 @@ export function joinLines(ctx: Ctx): Cmd {
134 }; 134 };
135} 135}
136 136
137export function moveItemUp(ctx: Ctx): Cmd {
138 return moveItem(ctx, ra.Direction.Up);
139}
140
141export function moveItemDown(ctx: Ctx): Cmd {
142 return moveItem(ctx, ra.Direction.Down);
143}
144
145export function moveItem(ctx: Ctx, direction: ra.Direction): Cmd {
146 return async () => {
147 const editor = ctx.activeRustEditor;
148 const client = ctx.client;
149 if (!editor || !client) return;
150
151 const edit = await client.sendRequest(ra.moveItem, {
152 range: client.code2ProtocolConverter.asRange(editor.selection),
153 textDocument: ctx.client.code2ProtocolConverter.asTextDocumentIdentifier(editor.document),
154 direction
155 });
156
157 if (!edit) return;
158
159 let cursor: vscode.Position | null = null;
160
161 await editor.edit((builder) => {
162 client.protocol2CodeConverter.asTextEdits(edit.edits).forEach((edit: any) => {
163 builder.replace(edit.range, edit.newText);
164
165 if (direction === ra.Direction.Up) {
166 if (!cursor || edit.range.end.isBeforeOrEqual(cursor)) {
167 cursor = edit.range.end;
168 }
169 } else {
170 if (!cursor || edit.range.end.isAfterOrEqual(cursor)) {
171 cursor = edit.range.end;
172 }
173 }
174 });
175 }).then(() => {
176 const newPosition = cursor ?? editor.selection.start;
177 editor.selection = new vscode.Selection(newPosition, newPosition);
178 });
179 };
180}
181
137export function onEnter(ctx: Ctx): Cmd { 182export function onEnter(ctx: Ctx): Cmd {
138 async function handleKeypress() { 183 async function handleKeypress() {
139 const editor = ctx.activeRustEditor; 184 const editor = ctx.activeRustEditor;
diff --git a/editors/code/src/lsp_ext.ts b/editors/code/src/lsp_ext.ts
index 52de29e04..00e128b8c 100644
--- a/editors/code/src/lsp_ext.ts
+++ b/editors/code/src/lsp_ext.ts
@@ -127,3 +127,16 @@ export const openCargoToml = new lc.RequestType<OpenCargoTomlParams, lc.Location
127export interface OpenCargoTomlParams { 127export interface OpenCargoTomlParams {
128 textDocument: lc.TextDocumentIdentifier; 128 textDocument: lc.TextDocumentIdentifier;
129} 129}
130
131export const moveItem = new lc.RequestType<MoveItemParams, lc.TextDocumentEdit | void, void>("experimental/moveItem");
132
133export interface MoveItemParams {
134 textDocument: lc.TextDocumentIdentifier;
135 range: lc.Range;
136 direction: Direction;
137}
138
139export const enum Direction {
140 Up = "Up",
141 Down = "Down"
142}
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts
index 925103f56..643fb643f 100644
--- a/editors/code/src/main.ts
+++ b/editors/code/src/main.ts
@@ -114,6 +114,8 @@ async function tryActivate(context: vscode.ExtensionContext) {
114 ctx.registerCommand('openDocs', commands.openDocs); 114 ctx.registerCommand('openDocs', commands.openDocs);
115 ctx.registerCommand('openCargoToml', commands.openCargoToml); 115 ctx.registerCommand('openCargoToml', commands.openCargoToml);
116 ctx.registerCommand('peekTests', commands.peekTests); 116 ctx.registerCommand('peekTests', commands.peekTests);
117 ctx.registerCommand('moveItemUp', commands.moveItemUp);
118 ctx.registerCommand('moveItemDown', commands.moveItemDown);
117 119
118 defaultOnEnter.dispose(); 120 defaultOnEnter.dispose();
119 ctx.registerCommand('onEnter', commands.onEnter); 121 ctx.registerCommand('onEnter', commands.onEnter);