aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock8
-rw-r--r--crates/hir/src/lib.rs13
-rw-r--r--crates/hir_def/src/body/tests.rs2
-rw-r--r--crates/hir_def/src/nameres/tests/diagnostics.rs2
-rw-r--r--crates/hir_expand/src/builtin_macro.rs2
-rw-r--r--crates/hir_ty/src/builder.rs12
-rw-r--r--crates/hir_ty/src/chalk_cast.rs65
-rw-r--r--crates/hir_ty/src/chalk_ext.rs49
-rw-r--r--crates/hir_ty/src/display.rs64
-rw-r--r--crates/hir_ty/src/infer.rs28
-rw-r--r--crates/hir_ty/src/infer/coerce.rs12
-rw-r--r--crates/hir_ty/src/infer/expr.rs3
-rw-r--r--crates/hir_ty/src/infer/pat.rs2
-rw-r--r--crates/hir_ty/src/infer/path.rs3
-rw-r--r--crates/hir_ty/src/infer/unify.rs165
-rw-r--r--crates/hir_ty/src/lib.rs180
-rw-r--r--crates/hir_ty/src/lower.rs41
-rw-r--r--crates/hir_ty/src/method_resolution.rs27
-rw-r--r--crates/hir_ty/src/traits.rs30
-rw-r--r--crates/hir_ty/src/traits/chalk.rs77
-rw-r--r--crates/hir_ty/src/traits/chalk/mapping.rs435
-rw-r--r--crates/hir_ty/src/types.rs549
-rw-r--r--crates/hir_ty/src/utils.rs16
-rw-r--r--crates/hir_ty/src/walk.rs287
-rw-r--r--crates/ide/src/folding_ranges.rs17
-rw-r--r--crates/ide/src/typing.rs168
-rw-r--r--crates/ide_assists/src/handlers/remove_dbg.rs105
-rw-r--r--crates/rust-analyzer/Cargo.toml2
-rw-r--r--crates/rust-analyzer/src/caps.rs2
-rw-r--r--crates/rust-analyzer/src/handlers.rs1
-rw-r--r--crates/rust-analyzer/src/to_proto.rs3
-rw-r--r--docs/dev/architecture.md4
32 files changed, 709 insertions, 1665 deletions
diff --git a/Cargo.lock b/Cargo.lock
index bcb1cbd9f..d7e6d3ac8 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -852,9 +852,9 @@ dependencies = [
852 852
853[[package]] 853[[package]]
854name = "lsp-types" 854name = "lsp-types"
855version = "0.88.0" 855version = "0.89.0"
856source = "registry+https://github.com/rust-lang/crates.io-index" 856source = "registry+https://github.com/rust-lang/crates.io-index"
857checksum = "d8e8e042772e4e10b3785822f63c82399d0dd233825de44d2596f7fa86e023e0" 857checksum = "07731ecd4ee0654728359a5b95e2a254c857876c04b85225496a35d60345daa7"
858dependencies = [ 858dependencies = [
859 "bitflags", 859 "bitflags",
860 "serde", 860 "serde",
@@ -1577,9 +1577,9 @@ dependencies = [
1577 1577
1578[[package]] 1578[[package]]
1579name = "syn" 1579name = "syn"
1580version = "1.0.68" 1580version = "1.0.69"
1581source = "registry+https://github.com/rust-lang/crates.io-index" 1581source = "registry+https://github.com/rust-lang/crates.io-index"
1582checksum = "3ce15dd3ed8aa2f8eeac4716d6ef5ab58b6b9256db41d7e1a0224c2788e8fd87" 1582checksum = "48fe99c6bd8b1cc636890bcc071842de909d902c81ac7dab53ba33c421ab8ffb"
1583dependencies = [ 1583dependencies = [
1584 "proc-macro2", 1584 "proc-macro2",
1585 "quote", 1585 "quote",
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 13aaa408a..817a01db1 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -59,7 +59,8 @@ use hir_ty::{
59 traits::FnTrait, 59 traits::FnTrait,
60 AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, 60 AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast,
61 DebruijnIndex, InEnvironment, Interner, QuantifiedWhereClause, Scalar, Solution, Substitution, 61 DebruijnIndex, InEnvironment, Interner, QuantifiedWhereClause, Scalar, Solution, Substitution,
62 TraitEnvironment, Ty, TyBuilder, TyDefId, TyExt, TyKind, TyVariableKind, WhereClause, 62 TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, TyVariableKind,
63 WhereClause,
63}; 64};
64use itertools::Itertools; 65use itertools::Itertools;
65use rustc_hash::FxHashSet; 66use rustc_hash::FxHashSet;
@@ -1790,7 +1791,7 @@ impl Type {
1790 .build(); 1791 .build();
1791 1792
1792 let goal = Canonical { 1793 let goal = Canonical {
1793 value: hir_ty::InEnvironment::new(self.env.env.clone(), trait_ref.cast(&Interner)), 1794 value: hir_ty::InEnvironment::new(&self.env.env, trait_ref.cast(&Interner)),
1794 binders: CanonicalVarKinds::empty(&Interner), 1795 binders: CanonicalVarKinds::empty(&Interner),
1795 }; 1796 };
1796 1797
@@ -1807,9 +1808,9 @@ impl Type {
1807 .push(self.ty.clone()) 1808 .push(self.ty.clone())
1808 .fill(args.iter().map(|t| t.ty.clone())) 1809 .fill(args.iter().map(|t| t.ty.clone()))
1809 .build(); 1810 .build();
1810 let goal = Canonical::new( 1811 let goal = hir_ty::make_canonical(
1811 InEnvironment::new( 1812 InEnvironment::new(
1812 self.env.env.clone(), 1813 &self.env.env,
1813 AliasEq { 1814 AliasEq {
1814 alias: AliasTy::Projection(projection), 1815 alias: AliasTy::Projection(projection),
1815 ty: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)) 1816 ty: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0))
@@ -1902,7 +1903,9 @@ impl Type {
1902 | TyKind::Dyn(_) 1903 | TyKind::Dyn(_)
1903 | TyKind::Function(_) 1904 | TyKind::Function(_)
1904 | TyKind::Alias(_) 1905 | TyKind::Alias(_)
1905 | TyKind::Foreign(_) => false, 1906 | TyKind::Foreign(_)
1907 | TyKind::Generator(..)
1908 | TyKind::GeneratorWitness(..) => false,
1906 } 1909 }
1907 } 1910 }
1908 } 1911 }
diff --git a/crates/hir_def/src/body/tests.rs b/crates/hir_def/src/body/tests.rs
index faa133297..c1d3e998f 100644
--- a/crates/hir_def/src/body/tests.rs
+++ b/crates/hir_def/src/body/tests.rs
@@ -143,7 +143,7 @@ fn f() {
143 //^^^^^^^^^^^^^ could not convert tokens 143 //^^^^^^^^^^^^^ could not convert tokens
144 144
145 env!("OUT_DIR"); 145 env!("OUT_DIR");
146 //^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "load out dirs from check" to fix 146 //^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix
147 147
148 compile_error!("compile_error works"); 148 compile_error!("compile_error works");
149 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ compile_error works 149 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ compile_error works
diff --git a/crates/hir_def/src/nameres/tests/diagnostics.rs b/crates/hir_def/src/nameres/tests/diagnostics.rs
index fefdadb22..1ac88fc89 100644
--- a/crates/hir_def/src/nameres/tests/diagnostics.rs
+++ b/crates/hir_def/src/nameres/tests/diagnostics.rs
@@ -233,7 +233,7 @@ fn good_out_dir_diagnostic() {
233 macro_rules! concat { () => {} } 233 macro_rules! concat { () => {} }
234 234
235 include!(concat!(env!("OUT_DIR"), "/out.rs")); 235 include!(concat!(env!("OUT_DIR"), "/out.rs"));
236 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "load out dirs from check" to fix 236 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix
237 "#, 237 "#,
238 ); 238 );
239} 239}
diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs
index 75ec4196b..a7d0f5b1f 100644
--- a/crates/hir_expand/src/builtin_macro.rs
+++ b/crates/hir_expand/src/builtin_macro.rs
@@ -490,7 +490,7 @@ fn env_expand(
490 // unnecessary diagnostics for eg. `CARGO_PKG_NAME`. 490 // unnecessary diagnostics for eg. `CARGO_PKG_NAME`.
491 if key == "OUT_DIR" { 491 if key == "OUT_DIR" {
492 err = Some(mbe::ExpandError::Other( 492 err = Some(mbe::ExpandError::Other(
493 r#"`OUT_DIR` not set, enable "load out dirs from check" to fix"#.into(), 493 r#"`OUT_DIR` not set, enable "run build scripts" to fix"#.into(),
494 )); 494 ));
495 } 495 }
496 496
diff --git a/crates/hir_ty/src/builder.rs b/crates/hir_ty/src/builder.rs
index 09512d1ce..e25ef866d 100644
--- a/crates/hir_ty/src/builder.rs
+++ b/crates/hir_ty/src/builder.rs
@@ -4,6 +4,7 @@ use std::iter;
4 4
5use chalk_ir::{ 5use chalk_ir::{
6 cast::{Cast, CastTo, Caster}, 6 cast::{Cast, CastTo, Caster},
7 fold::Fold,
7 interner::HasInterner, 8 interner::HasInterner,
8 AdtId, BoundVar, DebruijnIndex, Safety, Scalar, 9 AdtId, BoundVar, DebruijnIndex, Safety, Scalar,
9}; 10};
@@ -13,7 +14,7 @@ use smallvec::SmallVec;
13use crate::{ 14use crate::{
14 db::HirDatabase, primitive, to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders, 15 db::HirDatabase, primitive, to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders,
15 CallableSig, FnPointer, FnSig, FnSubst, GenericArg, Interner, ProjectionTy, Substitution, 16 CallableSig, FnPointer, FnSig, FnSubst, GenericArg, Interner, ProjectionTy, Substitution,
16 TraitRef, Ty, TyDefId, TyExt, TyKind, TypeWalk, ValueTyDefId, 17 TraitRef, Ty, TyDefId, TyExt, TyKind, ValueTyDefId,
17}; 18};
18 19
19/// This is a builder for `Ty` or anything that needs a `Substitution`. 20/// This is a builder for `Ty` or anything that needs a `Substitution`.
@@ -32,8 +33,7 @@ impl<D> TyBuilder<D> {
32 33
33 fn build_internal(self) -> (D, Substitution) { 34 fn build_internal(self) -> (D, Substitution) {
34 assert_eq!(self.vec.len(), self.param_count); 35 assert_eq!(self.vec.len(), self.param_count);
35 // FIXME: would be good to have a way to construct a chalk_ir::Substitution from the interned form 36 let subst = Substitution::from_iter(&Interner, self.vec);
36 let subst = Substitution::intern(self.vec);
37 (self.data, subst) 37 (self.data, subst)
38 } 38 }
39 39
@@ -141,7 +141,7 @@ impl TyBuilder<hir_def::AdtId> {
141 self.vec.push(fallback().cast(&Interner)); 141 self.vec.push(fallback().cast(&Interner));
142 } else { 142 } else {
143 // each default can depend on the previous parameters 143 // each default can depend on the previous parameters
144 let subst_so_far = Substitution::intern(self.vec.clone()); 144 let subst_so_far = Substitution::from_iter(&Interner, self.vec.clone());
145 self.vec 145 self.vec
146 .push(default_ty.clone().substitute(&Interner, &subst_so_far).cast(&Interner)); 146 .push(default_ty.clone().substitute(&Interner, &subst_so_far).cast(&Interner));
147 } 147 }
@@ -196,13 +196,13 @@ impl TyBuilder<TypeAliasId> {
196 } 196 }
197} 197}
198 198
199impl<T: TypeWalk + HasInterner<Interner = Interner>> TyBuilder<Binders<T>> { 199impl<T: HasInterner<Interner = Interner> + Fold<Interner>> TyBuilder<Binders<T>> {
200 fn subst_binders(b: Binders<T>) -> Self { 200 fn subst_binders(b: Binders<T>) -> Self {
201 let param_count = b.binders.len(&Interner); 201 let param_count = b.binders.len(&Interner);
202 TyBuilder::new(b, param_count) 202 TyBuilder::new(b, param_count)
203 } 203 }
204 204
205 pub fn build(self) -> T { 205 pub fn build(self) -> <T as Fold<Interner>>::Result {
206 let (b, subst) = self.build_internal(); 206 let (b, subst) = self.build_internal();
207 b.substitute(&Interner, &subst) 207 b.substitute(&Interner, &subst)
208 } 208 }
diff --git a/crates/hir_ty/src/chalk_cast.rs b/crates/hir_ty/src/chalk_cast.rs
index df6492113..f27dee3fd 100644
--- a/crates/hir_ty/src/chalk_cast.rs
+++ b/crates/hir_ty/src/chalk_cast.rs
@@ -1,11 +1,8 @@
1//! Implementations of the Chalk `Cast` trait for our types. 1//! Implementations of the Chalk `Cast` trait for our types.
2 2
3use chalk_ir::{ 3use chalk_ir::interner::HasInterner;
4 cast::{Cast, CastTo},
5 interner::HasInterner,
6};
7 4
8use crate::{AliasEq, DomainGoal, GenericArg, GenericArgData, Interner, TraitRef, Ty, WhereClause}; 5use crate::{CallableSig, ReturnTypeImplTraits};
9 6
10macro_rules! has_interner { 7macro_rules! has_interner {
11 ($t:ty) => { 8 ($t:ty) => {
@@ -15,59 +12,5 @@ macro_rules! has_interner {
15 }; 12 };
16} 13}
17 14
18has_interner!(WhereClause); 15has_interner!(CallableSig);
19has_interner!(DomainGoal); 16has_interner!(ReturnTypeImplTraits);
20has_interner!(GenericArg);
21has_interner!(Ty);
22
23impl CastTo<WhereClause> for TraitRef {
24 fn cast_to(self, _interner: &Interner) -> WhereClause {
25 WhereClause::Implemented(self)
26 }
27}
28
29impl CastTo<WhereClause> for AliasEq {
30 fn cast_to(self, _interner: &Interner) -> WhereClause {
31 WhereClause::AliasEq(self)
32 }
33}
34
35impl CastTo<DomainGoal> for WhereClause {
36 fn cast_to(self, _interner: &Interner) -> DomainGoal {
37 DomainGoal::Holds(self)
38 }
39}
40
41impl CastTo<GenericArg> for Ty {
42 fn cast_to(self, interner: &Interner) -> GenericArg {
43 GenericArg::new(interner, GenericArgData::Ty(self))
44 }
45}
46
47macro_rules! transitive_impl {
48 ($a:ty, $b:ty, $c:ty) => {
49 impl CastTo<$c> for $a {
50 fn cast_to(self, interner: &Interner) -> $c {
51 self.cast::<$b>(interner).cast(interner)
52 }
53 }
54 };
55}
56
57// In Chalk, these can be done as blanket impls, but that doesn't work here
58// because of coherence
59
60transitive_impl!(TraitRef, WhereClause, DomainGoal);
61transitive_impl!(AliasEq, WhereClause, DomainGoal);
62
63macro_rules! reflexive_impl {
64 ($a:ty) => {
65 impl CastTo<$a> for $a {
66 fn cast_to(self, _interner: &Interner) -> $a {
67 self
68 }
69 }
70 };
71}
72
73reflexive_impl!(GenericArg);
diff --git a/crates/hir_ty/src/chalk_ext.rs b/crates/hir_ty/src/chalk_ext.rs
index 8e8a1aa48..28ed3aac6 100644
--- a/crates/hir_ty/src/chalk_ext.rs
+++ b/crates/hir_ty/src/chalk_ext.rs
@@ -8,7 +8,7 @@ use hir_def::{
8use crate::{ 8use crate::{
9 db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, 9 db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id,
10 from_placeholder_idx, to_chalk_trait_id, AdtId, AliasEq, AliasTy, Binders, CallableDefId, 10 from_placeholder_idx, to_chalk_trait_id, AdtId, AliasEq, AliasTy, Binders, CallableDefId,
11 CallableSig, ImplTraitId, Interner, Lifetime, ProjectionTy, QuantifiedWhereClause, 11 CallableSig, FnPointer, ImplTraitId, Interner, Lifetime, ProjectionTy, QuantifiedWhereClause,
12 Substitution, TraitRef, Ty, TyBuilder, TyKind, WhereClause, 12 Substitution, TraitRef, Ty, TyBuilder, TyKind, WhereClause,
13}; 13};
14 14
@@ -34,6 +34,9 @@ pub trait TyExt {
34 34
35 fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<QuantifiedWhereClause>>; 35 fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<QuantifiedWhereClause>>;
36 fn associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<TraitId>; 36 fn associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<TraitId>;
37
38 /// FIXME: Get rid of this, it's not a good abstraction
39 fn equals_ctor(&self, other: &Ty) -> bool;
37} 40}
38 41
39impl TyExt for Ty { 42impl TyExt for Ty {
@@ -199,12 +202,12 @@ impl TyExt for Ty {
199 .map(|pred| pred.clone().substitute(&Interner, &substs)) 202 .map(|pred| pred.clone().substitute(&Interner, &substs))
200 .filter(|wc| match &wc.skip_binders() { 203 .filter(|wc| match &wc.skip_binders() {
201 WhereClause::Implemented(tr) => { 204 WhereClause::Implemented(tr) => {
202 tr.self_type_parameter(&Interner) == self 205 &tr.self_type_parameter(&Interner) == self
203 } 206 }
204 WhereClause::AliasEq(AliasEq { 207 WhereClause::AliasEq(AliasEq {
205 alias: AliasTy::Projection(proj), 208 alias: AliasTy::Projection(proj),
206 ty: _, 209 ty: _,
207 }) => proj.self_type_parameter(&Interner) == self, 210 }) => &proj.self_type_parameter(&Interner) == self,
208 _ => false, 211 _ => false,
209 }) 212 })
210 .collect::<Vec<_>>(); 213 .collect::<Vec<_>>();
@@ -238,6 +241,36 @@ impl TyExt for Ty {
238 _ => None, 241 _ => None,
239 } 242 }
240 } 243 }
244
245 fn equals_ctor(&self, other: &Ty) -> bool {
246 match (self.kind(&Interner), other.kind(&Interner)) {
247 (TyKind::Adt(adt, ..), TyKind::Adt(adt2, ..)) => adt == adt2,
248 (TyKind::Slice(_), TyKind::Slice(_)) | (TyKind::Array(_, _), TyKind::Array(_, _)) => {
249 true
250 }
251 (TyKind::FnDef(def_id, ..), TyKind::FnDef(def_id2, ..)) => def_id == def_id2,
252 (TyKind::OpaqueType(ty_id, ..), TyKind::OpaqueType(ty_id2, ..)) => ty_id == ty_id2,
253 (TyKind::AssociatedType(ty_id, ..), TyKind::AssociatedType(ty_id2, ..)) => {
254 ty_id == ty_id2
255 }
256 (TyKind::Foreign(ty_id, ..), TyKind::Foreign(ty_id2, ..)) => ty_id == ty_id2,
257 (TyKind::Closure(id1, _), TyKind::Closure(id2, _)) => id1 == id2,
258 (TyKind::Ref(mutability, ..), TyKind::Ref(mutability2, ..))
259 | (TyKind::Raw(mutability, ..), TyKind::Raw(mutability2, ..)) => {
260 mutability == mutability2
261 }
262 (
263 TyKind::Function(FnPointer { num_binders, sig, .. }),
264 TyKind::Function(FnPointer { num_binders: num_binders2, sig: sig2, .. }),
265 ) => num_binders == num_binders2 && sig == sig2,
266 (TyKind::Tuple(cardinality, _), TyKind::Tuple(cardinality2, _)) => {
267 cardinality == cardinality2
268 }
269 (TyKind::Str, TyKind::Str) | (TyKind::Never, TyKind::Never) => true,
270 (TyKind::Scalar(scalar), TyKind::Scalar(scalar2)) => scalar == scalar2,
271 _ => false,
272 }
273 }
241} 274}
242 275
243pub trait ProjectionTyExt { 276pub trait ProjectionTyExt {
@@ -260,3 +293,13 @@ impl ProjectionTyExt for ProjectionTy {
260 } 293 }
261 } 294 }
262} 295}
296
297pub trait TraitRefExt {
298 fn hir_trait_id(&self) -> TraitId;
299}
300
301impl TraitRefExt for TraitRef {
302 fn hir_trait_id(&self) -> TraitId {
303 from_chalk_trait_id(self.trait_id)
304 }
305}
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs
index 9e6bbcdf1..d7a3977e5 100644
--- a/crates/hir_ty/src/display.rs
+++ b/crates/hir_ty/src/display.rs
@@ -24,7 +24,7 @@ use crate::{
24 traits::chalk::from_chalk, utils::generics, AdtId, AliasEq, AliasTy, CallableDefId, 24 traits::chalk::from_chalk, utils::generics, AdtId, AliasEq, AliasTy, CallableDefId,
25 CallableSig, Const, ConstValue, DomainGoal, GenericArg, ImplTraitId, Interner, Lifetime, 25 CallableSig, Const, ConstValue, DomainGoal, GenericArg, ImplTraitId, Interner, Lifetime,
26 LifetimeData, LifetimeOutlives, Mutability, OpaqueTy, ProjectionTy, ProjectionTyExt, 26 LifetimeData, LifetimeOutlives, Mutability, OpaqueTy, ProjectionTy, ProjectionTyExt,
27 QuantifiedWhereClause, Scalar, TraitRef, Ty, TyExt, TyKind, WhereClause, 27 QuantifiedWhereClause, Scalar, TraitRef, TraitRefExt, Ty, TyExt, TyKind, WhereClause,
28}; 28};
29 29
30pub struct HirFormatter<'a> { 30pub struct HirFormatter<'a> {
@@ -287,6 +287,8 @@ impl HirDisplay for GenericArg {
287 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { 287 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
288 match self.interned() { 288 match self.interned() {
289 crate::GenericArgData::Ty(ty) => ty.hir_fmt(f), 289 crate::GenericArgData::Ty(ty) => ty.hir_fmt(f),
290 crate::GenericArgData::Lifetime(lt) => lt.hir_fmt(f),
291 crate::GenericArgData::Const(c) => c.hir_fmt(f),
290 } 292 }
291 } 293 }
292} 294}
@@ -616,12 +618,12 @@ impl HirDisplay for Ty {
616 .map(|pred| pred.clone().substitute(&Interner, &substs)) 618 .map(|pred| pred.clone().substitute(&Interner, &substs))
617 .filter(|wc| match &wc.skip_binders() { 619 .filter(|wc| match &wc.skip_binders() {
618 WhereClause::Implemented(tr) => { 620 WhereClause::Implemented(tr) => {
619 tr.self_type_parameter(&Interner) == self 621 &tr.self_type_parameter(&Interner) == self
620 } 622 }
621 WhereClause::AliasEq(AliasEq { 623 WhereClause::AliasEq(AliasEq {
622 alias: AliasTy::Projection(proj), 624 alias: AliasTy::Projection(proj),
623 ty: _, 625 ty: _,
624 }) => proj.self_type_parameter(&Interner) == self, 626 }) => &proj.self_type_parameter(&Interner) == self,
625 _ => false, 627 _ => false,
626 }) 628 })
627 .collect::<Vec<_>>(); 629 .collect::<Vec<_>>();
@@ -664,6 +666,8 @@ impl HirDisplay for Ty {
664 write!(f, "{{unknown}}")?; 666 write!(f, "{{unknown}}")?;
665 } 667 }
666 TyKind::InferenceVar(..) => write!(f, "_")?, 668 TyKind::InferenceVar(..) => write!(f, "_")?,
669 TyKind::Generator(..) => write!(f, "{{generator}}")?,
670 TyKind::GeneratorWitness(..) => write!(f, "{{generator witness}}")?,
667 } 671 }
668 Ok(()) 672 Ok(())
669 } 673 }
@@ -741,11 +745,11 @@ fn write_bounds_like_dyn_trait(
741 if !first { 745 if !first {
742 write!(f, " + ")?; 746 write!(f, " + ")?;
743 } 747 }
744 // We assume that the self type is $0 (i.e. the 748 // We assume that the self type is ^0.0 (i.e. the
745 // existential) here, which is the only thing that's 749 // existential) here, which is the only thing that's
746 // possible in actual Rust, and hence don't print it 750 // possible in actual Rust, and hence don't print it
747 write!(f, "{}", f.db.trait_data(trait_).name)?; 751 write!(f, "{}", f.db.trait_data(trait_).name)?;
748 if let [_, params @ ..] = &*trait_ref.substitution.interned() { 752 if let [_, params @ ..] = &*trait_ref.substitution.interned().as_slice() {
749 if is_fn_trait { 753 if is_fn_trait {
750 if let Some(args) = 754 if let Some(args) =
751 params.first().and_then(|it| it.assert_ty_ref(&Interner).as_tuple()) 755 params.first().and_then(|it| it.assert_ty_ref(&Interner).as_tuple())
@@ -783,6 +787,10 @@ fn write_bounds_like_dyn_trait(
783 } 787 }
784 ty.hir_fmt(f)?; 788 ty.hir_fmt(f)?;
785 } 789 }
790
791 // FIXME implement these
792 WhereClause::LifetimeOutlives(_) => {}
793 WhereClause::TypeOutlives(_) => {}
786 } 794 }
787 first = false; 795 first = false;
788 } 796 }
@@ -792,31 +800,29 @@ fn write_bounds_like_dyn_trait(
792 Ok(()) 800 Ok(())
793} 801}
794 802
795impl TraitRef { 803fn fmt_trait_ref(tr: &TraitRef, f: &mut HirFormatter, use_as: bool) -> Result<(), HirDisplayError> {
796 fn hir_fmt_ext(&self, f: &mut HirFormatter, use_as: bool) -> Result<(), HirDisplayError> { 804 if f.should_truncate() {
797 if f.should_truncate() { 805 return write!(f, "{}", TYPE_HINT_TRUNCATION);
798 return write!(f, "{}", TYPE_HINT_TRUNCATION); 806 }
799 }
800 807
801 self.self_type_parameter(&Interner).hir_fmt(f)?; 808 tr.self_type_parameter(&Interner).hir_fmt(f)?;
802 if use_as { 809 if use_as {
803 write!(f, " as ")?; 810 write!(f, " as ")?;
804 } else { 811 } else {
805 write!(f, ": ")?; 812 write!(f, ": ")?;
806 }
807 write!(f, "{}", f.db.trait_data(self.hir_trait_id()).name)?;
808 if self.substitution.len(&Interner) > 1 {
809 write!(f, "<")?;
810 f.write_joined(&self.substitution.interned()[1..], ", ")?;
811 write!(f, ">")?;
812 }
813 Ok(())
814 } 813 }
814 write!(f, "{}", f.db.trait_data(tr.hir_trait_id()).name)?;
815 if tr.substitution.len(&Interner) > 1 {
816 write!(f, "<")?;
817 f.write_joined(&tr.substitution.interned()[1..], ", ")?;
818 write!(f, ">")?;
819 }
820 Ok(())
815} 821}
816 822
817impl HirDisplay for TraitRef { 823impl HirDisplay for TraitRef {
818 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { 824 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
819 self.hir_fmt_ext(f, false) 825 fmt_trait_ref(self, f, false)
820 } 826 }
821} 827}
822 828
@@ -830,7 +836,7 @@ impl HirDisplay for WhereClause {
830 WhereClause::Implemented(trait_ref) => trait_ref.hir_fmt(f)?, 836 WhereClause::Implemented(trait_ref) => trait_ref.hir_fmt(f)?,
831 WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => { 837 WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => {
832 write!(f, "<")?; 838 write!(f, "<")?;
833 projection_ty.trait_ref(f.db).hir_fmt_ext(f, true)?; 839 fmt_trait_ref(&projection_ty.trait_ref(f.db), f, true)?;
834 write!( 840 write!(
835 f, 841 f,
836 ">::{} = ", 842 ">::{} = ",
@@ -839,6 +845,10 @@ impl HirDisplay for WhereClause {
839 ty.hir_fmt(f)?; 845 ty.hir_fmt(f)?;
840 } 846 }
841 WhereClause::AliasEq(_) => write!(f, "{{error}}")?, 847 WhereClause::AliasEq(_) => write!(f, "{{error}}")?,
848
849 // FIXME implement these
850 WhereClause::TypeOutlives(..) => {}
851 WhereClause::LifetimeOutlives(..) => {}
842 } 852 }
843 Ok(()) 853 Ok(())
844 } 854 }
@@ -883,9 +893,11 @@ impl HirDisplay for DomainGoal {
883 DomainGoal::Holds(wc) => { 893 DomainGoal::Holds(wc) => {
884 write!(f, "Holds(")?; 894 write!(f, "Holds(")?;
885 wc.hir_fmt(f)?; 895 wc.hir_fmt(f)?;
886 write!(f, ")") 896 write!(f, ")")?;
887 } 897 }
898 _ => write!(f, "?")?,
888 } 899 }
900 Ok(())
889 } 901 }
890} 902}
891 903
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs
index 6af0c59b8..bf2da2d4a 100644
--- a/crates/hir_ty/src/infer.rs
+++ b/crates/hir_ty/src/infer.rs
@@ -18,7 +18,7 @@ use std::mem;
18use std::ops::Index; 18use std::ops::Index;
19use std::sync::Arc; 19use std::sync::Arc;
20 20
21use chalk_ir::{cast::Cast, Mutability}; 21use chalk_ir::{cast::Cast, DebruijnIndex, Mutability};
22use hir_def::{ 22use hir_def::{
23 body::Body, 23 body::Body,
24 data::{ConstData, FunctionData, StaticData}, 24 data::{ConstData, FunctionData, StaticData},
@@ -38,11 +38,11 @@ use syntax::SmolStr;
38 38
39use super::{ 39use super::{
40 DomainGoal, Guidance, InEnvironment, ProjectionTy, Solution, TraitEnvironment, TraitRef, Ty, 40 DomainGoal, Guidance, InEnvironment, ProjectionTy, Solution, TraitEnvironment, TraitRef, Ty,
41 TypeWalk,
42}; 41};
43use crate::{ 42use crate::{
44 db::HirDatabase, infer::diagnostics::InferenceDiagnostic, lower::ImplTraitLoweringMode, 43 db::HirDatabase, fold_tys, infer::diagnostics::InferenceDiagnostic,
45 to_assoc_type_id, AliasEq, AliasTy, Canonical, Interner, TyBuilder, TyExt, TyKind, 44 lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, Canonical, Interner,
45 TyBuilder, TyExt, TyKind,
46}; 46};
47 47
48// This lint has a false positive here. See the link below for details. 48// This lint has a false positive here. See the link below for details.
@@ -323,7 +323,7 @@ impl<'a> InferenceContext<'a> {
323 } 323 }
324 324
325 fn insert_type_vars(&mut self, ty: Ty) -> Ty { 325 fn insert_type_vars(&mut self, ty: Ty) -> Ty {
326 ty.fold(&mut |ty| self.insert_type_vars_shallow(ty)) 326 fold_tys(ty, |ty, _| self.insert_type_vars_shallow(ty), DebruijnIndex::INNERMOST)
327 } 327 }
328 328
329 fn resolve_obligations_as_possible(&mut self) { 329 fn resolve_obligations_as_possible(&mut self) {
@@ -336,7 +336,7 @@ impl<'a> InferenceContext<'a> {
336 self.last_obligations_check = Some(self.table.revision); 336 self.last_obligations_check = Some(self.table.revision);
337 let obligations = mem::replace(&mut self.obligations, Vec::new()); 337 let obligations = mem::replace(&mut self.obligations, Vec::new());
338 for obligation in obligations { 338 for obligation in obligations {
339 let in_env = InEnvironment::new(self.trait_env.env.clone(), obligation.clone()); 339 let in_env = InEnvironment::new(&self.trait_env.env, obligation.clone());
340 let canonicalized = self.canonicalizer().canonicalize_obligation(in_env); 340 let canonicalized = self.canonicalizer().canonicalize_obligation(in_env);
341 let solution = 341 let solution =
342 self.db.trait_solve(self.resolver.krate().unwrap(), canonicalized.value.clone()); 342 self.db.trait_solve(self.resolver.krate().unwrap(), canonicalized.value.clone());
@@ -434,12 +434,16 @@ impl<'a> InferenceContext<'a> {
434 /// to do it as well. 434 /// to do it as well.
435 fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty { 435 fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty {
436 let ty = self.resolve_ty_as_possible(ty); 436 let ty = self.resolve_ty_as_possible(ty);
437 ty.fold(&mut |ty| match ty.kind(&Interner) { 437 fold_tys(
438 TyKind::Alias(AliasTy::Projection(proj_ty)) => { 438 ty,
439 self.normalize_projection_ty(proj_ty.clone()) 439 |ty, _| match ty.kind(&Interner) {
440 } 440 TyKind::Alias(AliasTy::Projection(proj_ty)) => {
441 _ => ty, 441 self.normalize_projection_ty(proj_ty.clone())
442 }) 442 }
443 _ => ty,
444 },
445 DebruijnIndex::INNERMOST,
446 )
443 } 447 }
444 448
445 fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty { 449 fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty {
diff --git a/crates/hir_ty/src/infer/coerce.rs b/crates/hir_ty/src/infer/coerce.rs
index f1af2a0bd..1f463a425 100644
--- a/crates/hir_ty/src/infer/coerce.rs
+++ b/crates/hir_ty/src/infer/coerce.rs
@@ -71,12 +71,14 @@ impl<'a> InferenceContext<'a> {
71 } 71 }
72 72
73 // Pointer weakening and function to pointer 73 // Pointer weakening and function to pointer
74 match (from_ty.interned_mut(), to_ty.kind(&Interner)) { 74 match (from_ty.kind(&Interner), to_ty.kind(&Interner)) {
75 // `*mut T` -> `*const T` 75 // `*mut T` -> `*const T`
76 (TyKind::Raw(_, inner), TyKind::Raw(m2 @ Mutability::Not, ..)) => {
77 from_ty = TyKind::Raw(*m2, inner.clone()).intern(&Interner);
78 }
76 // `&mut T` -> `&T` 79 // `&mut T` -> `&T`
77 (TyKind::Raw(m1, ..), TyKind::Raw(m2 @ Mutability::Not, ..)) 80 (TyKind::Ref(_, lt, inner), TyKind::Ref(m2 @ Mutability::Not, ..)) => {
78 | (TyKind::Ref(m1, ..), TyKind::Ref(m2 @ Mutability::Not, ..)) => { 81 from_ty = TyKind::Ref(*m2, lt.clone(), inner.clone()).intern(&Interner);
79 *m1 = *m2;
80 } 82 }
81 // `&T` -> `*const T` 83 // `&T` -> `*const T`
82 // `&mut T` -> `*mut T`/`*const T` 84 // `&mut T` -> `*mut T`/`*const T`
@@ -139,7 +141,7 @@ impl<'a> InferenceContext<'a> {
139 b.push(from_ty.clone()).push(to_ty.clone()).build() 141 b.push(from_ty.clone()).push(to_ty.clone()).build()
140 }; 142 };
141 143
142 let goal = InEnvironment::new(self.trait_env.env.clone(), trait_ref.cast(&Interner)); 144 let goal = InEnvironment::new(&self.trait_env.env, trait_ref.cast(&Interner));
143 145
144 let canonicalizer = self.canonicalizer(); 146 let canonicalizer = self.canonicalizer();
145 let canonicalized = canonicalizer.canonicalize_obligation(goal); 147 let canonicalized = canonicalizer.canonicalize_obligation(goal);
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index 9841988c5..cbbfa8b5c 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -3,7 +3,7 @@
3use std::iter::{repeat, repeat_with}; 3use std::iter::{repeat, repeat_with};
4use std::{mem, sync::Arc}; 4use std::{mem, sync::Arc};
5 5
6use chalk_ir::{cast::Cast, Mutability, TyVariableKind}; 6use chalk_ir::{cast::Cast, fold::Shift, Mutability, TyVariableKind};
7use hir_def::{ 7use hir_def::{
8 expr::{Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp}, 8 expr::{Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp},
9 path::{GenericArg, GenericArgs}, 9 path::{GenericArg, GenericArgs},
@@ -24,7 +24,6 @@ use crate::{
24 utils::{generics, Generics}, 24 utils::{generics, Generics},
25 AdtId, Binders, CallableDefId, FnPointer, FnSig, FnSubst, InEnvironment, Interner, 25 AdtId, Binders, CallableDefId, FnPointer, FnSig, FnSubst, InEnvironment, Interner,
26 ProjectionTyExt, Rawness, Scalar, Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind, 26 ProjectionTyExt, Rawness, Scalar, Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind,
27 TypeWalk,
28}; 27};
29 28
30use super::{ 29use super::{
diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs
index f88d5c5d3..a41e8e116 100644
--- a/crates/hir_ty/src/infer/pat.rs
+++ b/crates/hir_ty/src/infer/pat.rs
@@ -122,7 +122,7 @@ impl<'a> InferenceContext<'a> {
122 let ty = match &body[pat] { 122 let ty = match &body[pat] {
123 &Pat::Tuple { ref args, ellipsis } => { 123 &Pat::Tuple { ref args, ellipsis } => {
124 let expectations = match expected.as_tuple() { 124 let expectations = match expected.as_tuple() {
125 Some(parameters) => &*parameters.interned(), 125 Some(parameters) => &*parameters.interned().as_slice(),
126 _ => &[], 126 _ => &[],
127 }; 127 };
128 128
diff --git a/crates/hir_ty/src/infer/path.rs b/crates/hir_ty/src/infer/path.rs
index b19d67bb1..f8955aa32 100644
--- a/crates/hir_ty/src/infer/path.rs
+++ b/crates/hir_ty/src/infer/path.rs
@@ -11,7 +11,8 @@ use hir_def::{
11use hir_expand::name::Name; 11use hir_expand::name::Name;
12 12
13use crate::{ 13use crate::{
14 method_resolution, Interner, Substitution, Ty, TyBuilder, TyExt, TyKind, ValueTyDefId, 14 method_resolution, Interner, Substitution, TraitRefExt, Ty, TyBuilder, TyExt, TyKind,
15 ValueTyDefId,
15}; 16};
16 17
17use super::{ExprOrPatId, InferenceContext, TraitRef}; 18use super::{ExprOrPatId, InferenceContext, TraitRef};
diff --git a/crates/hir_ty/src/infer/unify.rs b/crates/hir_ty/src/infer/unify.rs
index d717e3375..a887e20b0 100644
--- a/crates/hir_ty/src/infer/unify.rs
+++ b/crates/hir_ty/src/infer/unify.rs
@@ -2,13 +2,17 @@
2 2
3use std::borrow::Cow; 3use std::borrow::Cow;
4 4
5use chalk_ir::{FloatTy, IntTy, TyVariableKind, UniverseIndex, VariableKind}; 5use chalk_ir::{
6 cast::Cast, fold::Fold, interner::HasInterner, FloatTy, IntTy, TyVariableKind, UniverseIndex,
7 VariableKind,
8};
6use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue}; 9use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue};
7 10
8use super::{DomainGoal, InferenceContext}; 11use super::{DomainGoal, InferenceContext};
9use crate::{ 12use crate::{
10 AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds, DebruijnIndex, FnPointer, FnSubst, 13 fold_tys, static_lifetime, AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds,
11 InEnvironment, InferenceVar, Interner, Scalar, Substitution, Ty, TyKind, TypeWalk, WhereClause, 14 DebruijnIndex, FnPointer, FnSubst, InEnvironment, InferenceVar, Interner, Scalar, Substitution,
15 Ty, TyExt, TyKind, WhereClause,
12}; 16};
13 17
14impl<'a> InferenceContext<'a> { 18impl<'a> InferenceContext<'a> {
@@ -33,7 +37,10 @@ where
33} 37}
34 38
35#[derive(Debug)] 39#[derive(Debug)]
36pub(super) struct Canonicalized<T> { 40pub(super) struct Canonicalized<T>
41where
42 T: HasInterner<Interner = Interner>,
43{
37 pub(super) value: Canonical<T>, 44 pub(super) value: Canonical<T>,
38 free_vars: Vec<(InferenceVar, TyVariableKind)>, 45 free_vars: Vec<(InferenceVar, TyVariableKind)>,
39} 46}
@@ -47,9 +54,14 @@ impl<'a, 'b> Canonicalizer<'a, 'b> {
47 }) 54 })
48 } 55 }
49 56
50 fn do_canonicalize<T: TypeWalk>(&mut self, t: T, binders: DebruijnIndex) -> T { 57 fn do_canonicalize<T: Fold<Interner, Result = T> + HasInterner<Interner = Interner>>(
51 t.fold_binders( 58 &mut self,
52 &mut |ty, binders| match ty.kind(&Interner) { 59 t: T,
60 binders: DebruijnIndex,
61 ) -> T {
62 fold_tys(
63 t,
64 |ty, binders| match ty.kind(&Interner) {
53 &TyKind::InferenceVar(var, kind) => { 65 &TyKind::InferenceVar(var, kind) => {
54 let inner = from_inference_var(var); 66 let inner = from_inference_var(var);
55 if self.var_stack.contains(&inner) { 67 if self.var_stack.contains(&inner) {
@@ -75,7 +87,10 @@ impl<'a, 'b> Canonicalizer<'a, 'b> {
75 ) 87 )
76 } 88 }
77 89
78 fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> { 90 fn into_canonicalized<T: HasInterner<Interner = Interner>>(
91 self,
92 result: T,
93 ) -> Canonicalized<T> {
79 let kinds = self 94 let kinds = self
80 .free_vars 95 .free_vars
81 .iter() 96 .iter()
@@ -102,28 +117,18 @@ impl<'a, 'b> Canonicalizer<'a, 'b> {
102 DomainGoal::Holds(wc) => { 117 DomainGoal::Holds(wc) => {
103 DomainGoal::Holds(self.do_canonicalize(wc, DebruijnIndex::INNERMOST)) 118 DomainGoal::Holds(self.do_canonicalize(wc, DebruijnIndex::INNERMOST))
104 } 119 }
120 _ => unimplemented!(),
105 }; 121 };
106 self.into_canonicalized(InEnvironment { goal: result, environment: obligation.environment }) 122 self.into_canonicalized(InEnvironment { goal: result, environment: obligation.environment })
107 } 123 }
108} 124}
109 125
110impl<T> Canonicalized<T> { 126impl<T: HasInterner<Interner = Interner>> Canonicalized<T> {
111 pub(super) fn decanonicalize_ty(&self, ty: Ty) -> Ty { 127 pub(super) fn decanonicalize_ty(&self, ty: Ty) -> Ty {
112 ty.fold_binders( 128 crate::fold_free_vars(ty, |bound, _binders| {
113 &mut |ty, binders| { 129 let (v, k) = self.free_vars[bound.index];
114 if let TyKind::BoundVar(bound) = ty.kind(&Interner) { 130 TyKind::InferenceVar(v, k).intern(&Interner)
115 if bound.debruijn >= binders { 131 })
116 let (v, k) = self.free_vars[bound.index];
117 TyKind::InferenceVar(v, k).intern(&Interner)
118 } else {
119 ty
120 }
121 } else {
122 ty
123 }
124 },
125 DebruijnIndex::INNERMOST,
126 )
127 } 132 }
128 133
129 pub(super) fn apply_solution( 134 pub(super) fn apply_solution(
@@ -135,15 +140,17 @@ impl<T> Canonicalized<T> {
135 let new_vars = Substitution::from_iter( 140 let new_vars = Substitution::from_iter(
136 &Interner, 141 &Interner,
137 solution.binders.iter(&Interner).map(|k| match k.kind { 142 solution.binders.iter(&Interner).map(|k| match k.kind {
138 VariableKind::Ty(TyVariableKind::General) => ctx.table.new_type_var(), 143 VariableKind::Ty(TyVariableKind::General) => {
139 VariableKind::Ty(TyVariableKind::Integer) => ctx.table.new_integer_var(), 144 ctx.table.new_type_var().cast(&Interner)
140 VariableKind::Ty(TyVariableKind::Float) => ctx.table.new_float_var(), 145 }
141 // HACK: Chalk can sometimes return new lifetime variables. We 146 VariableKind::Ty(TyVariableKind::Integer) => {
142 // want to just skip them, but to not mess up the indices of 147 ctx.table.new_integer_var().cast(&Interner)
143 // other variables, we'll just create a new type variable in 148 }
144 // their place instead. This should not matter (we never see the 149 VariableKind::Ty(TyVariableKind::Float) => {
145 // actual *uses* of the lifetime variable). 150 ctx.table.new_float_var().cast(&Interner)
146 VariableKind::Lifetime => ctx.table.new_type_var(), 151 }
152 // Chalk can sometimes return new lifetime variables. We just use the static lifetime everywhere
153 VariableKind::Lifetime => static_lifetime().cast(&Interner),
147 _ => panic!("const variable in solution"), 154 _ => panic!("const variable in solution"),
148 }), 155 }),
149 ); 156 );
@@ -487,55 +494,63 @@ impl InferenceTable {
487 /// be resolved as far as possible, i.e. contain no type variables with 494 /// be resolved as far as possible, i.e. contain no type variables with
488 /// known type. 495 /// known type.
489 fn resolve_ty_as_possible_inner(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty { 496 fn resolve_ty_as_possible_inner(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty {
490 ty.fold(&mut |ty| match ty.kind(&Interner) { 497 fold_tys(
491 &TyKind::InferenceVar(tv, kind) => { 498 ty,
492 let inner = from_inference_var(tv); 499 |ty, _| match ty.kind(&Interner) {
493 if tv_stack.contains(&inner) { 500 &TyKind::InferenceVar(tv, kind) => {
494 cov_mark::hit!(type_var_cycles_resolve_as_possible); 501 let inner = from_inference_var(tv);
495 // recursive type 502 if tv_stack.contains(&inner) {
496 return self.type_variable_table.fallback_value(tv, kind); 503 cov_mark::hit!(type_var_cycles_resolve_as_possible);
497 } 504 // recursive type
498 if let Some(known_ty) = 505 return self.type_variable_table.fallback_value(tv, kind);
499 self.var_unification_table.inlined_probe_value(inner).known() 506 }
500 { 507 if let Some(known_ty) =
501 // known_ty may contain other variables that are known by now 508 self.var_unification_table.inlined_probe_value(inner).known()
502 tv_stack.push(inner); 509 {
503 let result = self.resolve_ty_as_possible_inner(tv_stack, known_ty.clone()); 510 // known_ty may contain other variables that are known by now
504 tv_stack.pop(); 511 tv_stack.push(inner);
505 result 512 let result = self.resolve_ty_as_possible_inner(tv_stack, known_ty.clone());
506 } else { 513 tv_stack.pop();
507 ty 514 result
515 } else {
516 ty
517 }
508 } 518 }
509 } 519 _ => ty,
510 _ => ty, 520 },
511 }) 521 DebruijnIndex::INNERMOST,
522 )
512 } 523 }
513 524
514 /// Resolves the type completely; type variables without known type are 525 /// Resolves the type completely; type variables without known type are
515 /// replaced by TyKind::Unknown. 526 /// replaced by TyKind::Unknown.
516 fn resolve_ty_completely_inner(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty { 527 fn resolve_ty_completely_inner(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty {
517 ty.fold(&mut |ty| match ty.kind(&Interner) { 528 fold_tys(
518 &TyKind::InferenceVar(tv, kind) => { 529 ty,
519 let inner = from_inference_var(tv); 530 |ty, _| match ty.kind(&Interner) {
520 if tv_stack.contains(&inner) { 531 &TyKind::InferenceVar(tv, kind) => {
521 cov_mark::hit!(type_var_cycles_resolve_completely); 532 let inner = from_inference_var(tv);
522 // recursive type 533 if tv_stack.contains(&inner) {
523 return self.type_variable_table.fallback_value(tv, kind); 534 cov_mark::hit!(type_var_cycles_resolve_completely);
524 } 535 // recursive type
525 if let Some(known_ty) = 536 return self.type_variable_table.fallback_value(tv, kind);
526 self.var_unification_table.inlined_probe_value(inner).known() 537 }
527 { 538 if let Some(known_ty) =
528 // known_ty may contain other variables that are known by now 539 self.var_unification_table.inlined_probe_value(inner).known()
529 tv_stack.push(inner); 540 {
530 let result = self.resolve_ty_completely_inner(tv_stack, known_ty.clone()); 541 // known_ty may contain other variables that are known by now
531 tv_stack.pop(); 542 tv_stack.push(inner);
532 result 543 let result = self.resolve_ty_completely_inner(tv_stack, known_ty.clone());
533 } else { 544 tv_stack.pop();
534 self.type_variable_table.fallback_value(tv, kind) 545 result
546 } else {
547 self.type_variable_table.fallback_value(tv, kind)
548 }
535 } 549 }
536 } 550 _ => ty,
537 _ => ty, 551 },
538 }) 552 DebruijnIndex::INNERMOST,
553 )
539 } 554 }
540} 555}
541 556
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs
index 84645c435..874c95411 100644
--- a/crates/hir_ty/src/lib.rs
+++ b/crates/hir_ty/src/lib.rs
@@ -1,5 +1,6 @@
1//! The type system. We currently use this to infer types for completion, hover 1//! The type system. We currently use this to infer types for completion, hover
2//! information and various assists. 2//! information and various assists.
3
3#[allow(unused)] 4#[allow(unused)]
4macro_rules! eprintln { 5macro_rules! eprintln {
5 ($($tt:tt)*) => { stdx::eprintln!($($tt)*) }; 6 ($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
@@ -17,7 +18,6 @@ mod chalk_cast;
17mod chalk_ext; 18mod chalk_ext;
18mod builder; 19mod builder;
19mod walk; 20mod walk;
20mod types;
21 21
22pub mod display; 22pub mod display;
23pub mod db; 23pub mod db;
@@ -31,7 +31,11 @@ mod test_db;
31use std::sync::Arc; 31use std::sync::Arc;
32 32
33use base_db::salsa; 33use base_db::salsa;
34use chalk_ir::UintTy; 34use chalk_ir::{
35 fold::{Fold, Shift},
36 interner::HasInterner,
37 UintTy,
38};
35use hir_def::{ 39use hir_def::{
36 expr::ExprId, type_ref::Rawness, ConstParamId, LifetimeParamId, TraitId, TypeAliasId, 40 expr::ExprId, type_ref::Rawness, ConstParamId, LifetimeParamId, TraitId, TypeAliasId,
37 TypeParamId, 41 TypeParamId,
@@ -41,14 +45,13 @@ use crate::{db::HirDatabase, display::HirDisplay, utils::generics};
41 45
42pub use autoderef::autoderef; 46pub use autoderef::autoderef;
43pub use builder::TyBuilder; 47pub use builder::TyBuilder;
44pub use chalk_ext::{ProjectionTyExt, TyExt}; 48pub use chalk_ext::*;
45pub use infer::{could_unify, InferenceResult}; 49pub use infer::{could_unify, InferenceResult};
46pub use lower::{ 50pub use lower::{
47 associated_type_shorthand_candidates, callable_item_sig, CallableDefId, ImplTraitLoweringMode, 51 associated_type_shorthand_candidates, callable_item_sig, CallableDefId, ImplTraitLoweringMode,
48 TyDefId, TyLoweringContext, ValueTyDefId, 52 TyDefId, TyLoweringContext, ValueTyDefId,
49}; 53};
50pub use traits::{chalk::Interner, TraitEnvironment}; 54pub use traits::{chalk::Interner, TraitEnvironment};
51pub use types::*;
52pub use walk::TypeWalk; 55pub use walk::TypeWalk;
53 56
54pub use chalk_ir::{ 57pub use chalk_ir::{
@@ -65,6 +68,21 @@ pub type PlaceholderIndex = chalk_ir::PlaceholderIndex;
65pub type VariableKind = chalk_ir::VariableKind<Interner>; 68pub type VariableKind = chalk_ir::VariableKind<Interner>;
66pub type VariableKinds = chalk_ir::VariableKinds<Interner>; 69pub type VariableKinds = chalk_ir::VariableKinds<Interner>;
67pub type CanonicalVarKinds = chalk_ir::CanonicalVarKinds<Interner>; 70pub type CanonicalVarKinds = chalk_ir::CanonicalVarKinds<Interner>;
71pub type Binders<T> = chalk_ir::Binders<T>;
72pub type Substitution = chalk_ir::Substitution<Interner>;
73pub type GenericArg = chalk_ir::GenericArg<Interner>;
74pub type GenericArgData = chalk_ir::GenericArgData<Interner>;
75
76pub type Ty = chalk_ir::Ty<Interner>;
77pub type TyKind = chalk_ir::TyKind<Interner>;
78pub type DynTy = chalk_ir::DynTy<Interner>;
79pub type FnPointer = chalk_ir::FnPointer<Interner>;
80// pub type FnSubst = chalk_ir::FnSubst<Interner>;
81pub use chalk_ir::FnSubst;
82pub type ProjectionTy = chalk_ir::ProjectionTy<Interner>;
83pub type AliasTy = chalk_ir::AliasTy<Interner>;
84pub type OpaqueTy = chalk_ir::OpaqueTy<Interner>;
85pub type InferenceVar = chalk_ir::InferenceVar;
68 86
69pub type Lifetime = chalk_ir::Lifetime<Interner>; 87pub type Lifetime = chalk_ir::Lifetime<Interner>;
70pub type LifetimeData = chalk_ir::LifetimeData<Interner>; 88pub type LifetimeData = chalk_ir::LifetimeData<Interner>;
@@ -79,9 +97,20 @@ pub type ChalkTraitId = chalk_ir::TraitId<Interner>;
79 97
80pub type FnSig = chalk_ir::FnSig<Interner>; 98pub type FnSig = chalk_ir::FnSig<Interner>;
81 99
100pub type InEnvironment<T> = chalk_ir::InEnvironment<T>;
101pub type DomainGoal = chalk_ir::DomainGoal<Interner>;
102pub type AliasEq = chalk_ir::AliasEq<Interner>;
103pub type Solution = chalk_solve::Solution<Interner>;
104pub type ConstrainedSubst = chalk_ir::ConstrainedSubst<Interner>;
105pub type Guidance = chalk_solve::Guidance<Interner>;
106pub type WhereClause = chalk_ir::WhereClause<Interner>;
107
82// FIXME: get rid of this 108// FIXME: get rid of this
83pub fn subst_prefix(s: &Substitution, n: usize) -> Substitution { 109pub fn subst_prefix(s: &Substitution, n: usize) -> Substitution {
84 Substitution::intern(s.interned()[..std::cmp::min(s.len(&Interner), n)].into()) 110 Substitution::from_iter(
111 &Interner,
112 s.interned()[..std::cmp::min(s.len(&Interner), n)].iter().cloned(),
113 )
85} 114}
86 115
87/// Return an index of a parameter in the generic type parameter list by it's id. 116/// Return an index of a parameter in the generic type parameter list by it's id.
@@ -91,12 +120,15 @@ pub fn param_idx(db: &dyn HirDatabase, id: TypeParamId) -> Option<usize> {
91 120
92pub fn wrap_empty_binders<T>(value: T) -> Binders<T> 121pub fn wrap_empty_binders<T>(value: T) -> Binders<T>
93where 122where
94 T: TypeWalk, 123 T: Fold<Interner, Result = T> + HasInterner<Interner = Interner>,
95{ 124{
96 Binders::empty(&Interner, value.shifted_in_from(DebruijnIndex::ONE)) 125 Binders::empty(&Interner, value.shifted_in_from(&Interner, DebruijnIndex::ONE))
97} 126}
98 127
99pub fn make_only_type_binders<T>(num_vars: usize, value: T) -> Binders<T> { 128pub fn make_only_type_binders<T: HasInterner<Interner = Interner>>(
129 num_vars: usize,
130 value: T,
131) -> Binders<T> {
100 Binders::new( 132 Binders::new(
101 VariableKinds::from_iter( 133 VariableKinds::from_iter(
102 &Interner, 134 &Interner,
@@ -107,23 +139,27 @@ pub fn make_only_type_binders<T>(num_vars: usize, value: T) -> Binders<T> {
107 ) 139 )
108} 140}
109 141
110impl TraitRef { 142// FIXME: get rid of this
111 pub fn hir_trait_id(&self) -> TraitId { 143pub fn make_canonical<T: HasInterner<Interner = Interner>>(
112 from_chalk_trait_id(self.trait_id) 144 value: T,
113 } 145 kinds: impl IntoIterator<Item = TyVariableKind>,
146) -> Canonical<T> {
147 let kinds = kinds.into_iter().map(|tk| {
148 chalk_ir::CanonicalVarKind::new(
149 chalk_ir::VariableKind::Ty(tk),
150 chalk_ir::UniverseIndex::ROOT,
151 )
152 });
153 Canonical { value, binders: chalk_ir::CanonicalVarKinds::from_iter(&Interner, kinds) }
114} 154}
115 155
116impl<T> Canonical<T> { 156pub type TraitRef = chalk_ir::TraitRef<Interner>;
117 pub fn new(value: T, kinds: impl IntoIterator<Item = TyVariableKind>) -> Self { 157
118 let kinds = kinds.into_iter().map(|tk| { 158pub type QuantifiedWhereClause = Binders<WhereClause>;
119 chalk_ir::CanonicalVarKind::new( 159
120 chalk_ir::VariableKind::Ty(tk), 160pub type QuantifiedWhereClauses = chalk_ir::QuantifiedWhereClauses<Interner>;
121 chalk_ir::UniverseIndex::ROOT, 161
122 ) 162pub type Canonical<T> = chalk_ir::Canonical<T>;
123 });
124 Self { value, binders: chalk_ir::CanonicalVarKinds::from_iter(&Interner, kinds) }
125 }
126}
127 163
128/// A function signature as seen by type inference: Several parameter types and 164/// A function signature as seen by type inference: Several parameter types and
129/// one return type. 165/// one return type.
@@ -148,7 +184,7 @@ impl CallableSig {
148 params_and_return: fn_ptr 184 params_and_return: fn_ptr
149 .substitution 185 .substitution
150 .clone() 186 .clone()
151 .shifted_out_to(DebruijnIndex::ONE) 187 .shifted_out_to(&Interner, DebruijnIndex::ONE)
152 .expect("unexpected lifetime vars in fn ptr") 188 .expect("unexpected lifetime vars in fn ptr")
153 .0 189 .0
154 .interned() 190 .interned()
@@ -168,35 +204,20 @@ impl CallableSig {
168 } 204 }
169} 205}
170 206
171impl Ty { 207impl Fold<Interner> for CallableSig {
172 pub fn equals_ctor(&self, other: &Ty) -> bool { 208 type Result = CallableSig;
173 match (self.kind(&Interner), other.kind(&Interner)) { 209
174 (TyKind::Adt(adt, ..), TyKind::Adt(adt2, ..)) => adt == adt2, 210 fn fold_with<'i>(
175 (TyKind::Slice(_), TyKind::Slice(_)) | (TyKind::Array(_, _), TyKind::Array(_, _)) => { 211 self,
176 true 212 folder: &mut dyn chalk_ir::fold::Folder<'i, Interner>,
177 } 213 outer_binder: DebruijnIndex,
178 (TyKind::FnDef(def_id, ..), TyKind::FnDef(def_id2, ..)) => def_id == def_id2, 214 ) -> chalk_ir::Fallible<Self::Result>
179 (TyKind::OpaqueType(ty_id, ..), TyKind::OpaqueType(ty_id2, ..)) => ty_id == ty_id2, 215 where
180 (TyKind::AssociatedType(ty_id, ..), TyKind::AssociatedType(ty_id2, ..)) => { 216 Interner: 'i,
181 ty_id == ty_id2 217 {
182 } 218 let vec = self.params_and_return.to_vec();
183 (TyKind::Foreign(ty_id, ..), TyKind::Foreign(ty_id2, ..)) => ty_id == ty_id2, 219 let folded = vec.fold_with(folder, outer_binder)?;
184 (TyKind::Closure(id1, _), TyKind::Closure(id2, _)) => id1 == id2, 220 Ok(CallableSig { params_and_return: folded.into(), is_varargs: self.is_varargs })
185 (TyKind::Ref(mutability, ..), TyKind::Ref(mutability2, ..))
186 | (TyKind::Raw(mutability, ..), TyKind::Raw(mutability2, ..)) => {
187 mutability == mutability2
188 }
189 (
190 TyKind::Function(FnPointer { num_binders, sig, .. }),
191 TyKind::Function(FnPointer { num_binders: num_binders2, sig: sig2, .. }),
192 ) => num_binders == num_binders2 && sig == sig2,
193 (TyKind::Tuple(cardinality, _), TyKind::Tuple(cardinality2, _)) => {
194 cardinality == cardinality2
195 }
196 (TyKind::Str, TyKind::Str) | (TyKind::Never, TyKind::Never) => true,
197 (TyKind::Scalar(scalar), TyKind::Scalar(scalar2)) => scalar == scalar2,
198 _ => false,
199 }
200 } 221 }
201} 222}
202 223
@@ -278,3 +299,56 @@ pub fn dummy_usize_const() -> Const {
278 } 299 }
279 .intern(&Interner) 300 .intern(&Interner)
280} 301}
302
303pub(crate) fn fold_free_vars<T: HasInterner<Interner = Interner> + Fold<Interner>>(
304 t: T,
305 f: impl FnMut(BoundVar, DebruijnIndex) -> Ty,
306) -> T::Result {
307 use chalk_ir::{fold::Folder, Fallible};
308 struct FreeVarFolder<F>(F);
309 impl<'i, F: FnMut(BoundVar, DebruijnIndex) -> Ty + 'i> Folder<'i, Interner> for FreeVarFolder<F> {
310 fn as_dyn(&mut self) -> &mut dyn Folder<'i, Interner> {
311 self
312 }
313
314 fn interner(&self) -> &'i Interner {
315 &Interner
316 }
317
318 fn fold_free_var_ty(
319 &mut self,
320 bound_var: BoundVar,
321 outer_binder: DebruijnIndex,
322 ) -> Fallible<Ty> {
323 Ok(self.0(bound_var, outer_binder))
324 }
325 }
326 t.fold_with(&mut FreeVarFolder(f), DebruijnIndex::INNERMOST).expect("fold failed unexpectedly")
327}
328
329pub(crate) fn fold_tys<T: HasInterner<Interner = Interner> + Fold<Interner>>(
330 t: T,
331 f: impl FnMut(Ty, DebruijnIndex) -> Ty,
332 binders: DebruijnIndex,
333) -> T::Result {
334 use chalk_ir::{
335 fold::{Folder, SuperFold},
336 Fallible,
337 };
338 struct TyFolder<F>(F);
339 impl<'i, F: FnMut(Ty, DebruijnIndex) -> Ty + 'i> Folder<'i, Interner> for TyFolder<F> {
340 fn as_dyn(&mut self) -> &mut dyn Folder<'i, Interner> {
341 self
342 }
343
344 fn interner(&self) -> &'i Interner {
345 &Interner
346 }
347
348 fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Fallible<Ty> {
349 let ty = ty.super_fold_with(self.as_dyn(), outer_binder)?;
350 Ok(self.0(ty, outer_binder))
351 }
352 }
353 t.fold_with(&mut TyFolder(f), binders).expect("fold failed unexpectedly")
354}
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index 4ca6aa538..8a22d9ea3 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -8,7 +8,7 @@
8use std::{iter, sync::Arc}; 8use std::{iter, sync::Arc};
9 9
10use base_db::CrateId; 10use base_db::CrateId;
11use chalk_ir::{cast::Cast, Mutability, Safety}; 11use chalk_ir::{cast::Cast, fold::Shift, interner::HasInterner, Mutability, Safety};
12use hir_def::{ 12use hir_def::{
13 adt::StructKind, 13 adt::StructKind,
14 builtin_type::BuiltinType, 14 builtin_type::BuiltinType,
@@ -35,7 +35,7 @@ use crate::{
35 AliasEq, AliasTy, Binders, BoundVar, CallableSig, DebruijnIndex, DynTy, FnPointer, FnSig, 35 AliasEq, AliasTy, Binders, BoundVar, CallableSig, DebruijnIndex, DynTy, FnPointer, FnSig,
36 FnSubst, ImplTraitId, OpaqueTy, PolyFnSig, ProjectionTy, QuantifiedWhereClause, 36 FnSubst, ImplTraitId, OpaqueTy, PolyFnSig, ProjectionTy, QuantifiedWhereClause,
37 QuantifiedWhereClauses, ReturnTypeImplTrait, ReturnTypeImplTraits, Substitution, 37 QuantifiedWhereClauses, ReturnTypeImplTrait, ReturnTypeImplTraits, Substitution,
38 TraitEnvironment, TraitRef, Ty, TyBuilder, TyKind, TypeWalk, WhereClause, 38 TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyKind, WhereClause,
39}; 39};
40 40
41#[derive(Debug)] 41#[derive(Debug)]
@@ -488,7 +488,7 @@ impl<'a> TyLoweringContext<'a> {
488 }; 488 };
489 // We need to shift in the bound vars, since 489 // We need to shift in the bound vars, since
490 // associated_type_shorthand_candidates does not do that 490 // associated_type_shorthand_candidates does not do that
491 let substs = substs.shifted_in_from(self.in_binders); 491 let substs = substs.shifted_in_from(&Interner, self.in_binders);
492 // FIXME handle type parameters on the segment 492 // FIXME handle type parameters on the segment
493 return Some( 493 return Some(
494 TyKind::Alias(AliasTy::Projection(ProjectionTy { 494 TyKind::Alias(AliasTy::Projection(ProjectionTy {
@@ -847,7 +847,7 @@ pub fn associated_type_shorthand_candidates<R>(
847 // FIXME: how to correctly handle higher-ranked bounds here? 847 // FIXME: how to correctly handle higher-ranked bounds here?
848 WhereClause::Implemented(tr) => search( 848 WhereClause::Implemented(tr) => search(
849 tr.clone() 849 tr.clone()
850 .shifted_out_to(DebruijnIndex::ONE) 850 .shifted_out_to(&Interner, DebruijnIndex::ONE)
851 .expect("FIXME unexpected higher-ranked trait bound"), 851 .expect("FIXME unexpected higher-ranked trait bound"),
852 ), 852 ),
853 _ => None, 853 _ => None,
@@ -950,8 +950,7 @@ pub(crate) fn trait_environment_query(
950 traits_in_scope 950 traits_in_scope
951 .push((tr.self_type_parameter(&Interner).clone(), tr.hir_trait_id())); 951 .push((tr.self_type_parameter(&Interner).clone(), tr.hir_trait_id()));
952 } 952 }
953 let program_clause: chalk_ir::ProgramClause<Interner> = 953 let program_clause: chalk_ir::ProgramClause<Interner> = pred.clone().cast(&Interner);
954 pred.clone().to_chalk(db).cast(&Interner);
955 clauses.push(program_clause.into_from_env_clause(&Interner)); 954 clauses.push(program_clause.into_from_env_clause(&Interner));
956 } 955 }
957 } 956 }
@@ -974,7 +973,7 @@ pub(crate) fn trait_environment_query(
974 let substs = TyBuilder::type_params_subst(db, trait_id); 973 let substs = TyBuilder::type_params_subst(db, trait_id);
975 let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution: substs }; 974 let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution: substs };
976 let pred = WhereClause::Implemented(trait_ref); 975 let pred = WhereClause::Implemented(trait_ref);
977 let program_clause: chalk_ir::ProgramClause<Interner> = pred.to_chalk(db).cast(&Interner); 976 let program_clause: chalk_ir::ProgramClause<Interner> = pred.cast(&Interner);
978 clauses.push(program_clause.into_from_env_clause(&Interner)); 977 clauses.push(program_clause.into_from_env_clause(&Interner));
979 } 978 }
980 979
@@ -1016,22 +1015,16 @@ pub(crate) fn generic_defaults_query(
1016 p.default.as_ref().map_or(TyKind::Error.intern(&Interner), |t| ctx.lower_ty(t)); 1015 p.default.as_ref().map_or(TyKind::Error.intern(&Interner), |t| ctx.lower_ty(t));
1017 1016
1018 // Each default can only refer to previous parameters. 1017 // Each default can only refer to previous parameters.
1019 ty = ty.fold_binders( 1018 ty = crate::fold_free_vars(ty, |bound, binders| {
1020 &mut |ty, binders| match ty.kind(&Interner) { 1019 if bound.index >= idx && bound.debruijn == DebruijnIndex::INNERMOST {
1021 TyKind::BoundVar(BoundVar { debruijn, index }) if *debruijn == binders => { 1020 // type variable default referring to parameter coming
1022 if *index >= idx { 1021 // after it. This is forbidden (FIXME: report
1023 // type variable default referring to parameter coming 1022 // diagnostic)
1024 // after it. This is forbidden (FIXME: report 1023 TyKind::Error.intern(&Interner)
1025 // diagnostic) 1024 } else {
1026 TyKind::Error.intern(&Interner) 1025 bound.shifted_in_from(binders).to_ty(&Interner)
1027 } else { 1026 }
1028 ty 1027 });
1029 }
1030 }
1031 _ => ty,
1032 },
1033 DebruijnIndex::INNERMOST,
1034 );
1035 1028
1036 crate::make_only_type_binders(idx, ty) 1029 crate::make_only_type_binders(idx, ty)
1037 }) 1030 })
@@ -1307,6 +1300,6 @@ pub(crate) fn lower_to_chalk_mutability(m: hir_def::type_ref::Mutability) -> Mut
1307 } 1300 }
1308} 1301}
1309 1302
1310fn make_binders<T>(generics: &Generics, value: T) -> Binders<T> { 1303fn make_binders<T: HasInterner<Interner = Interner>>(generics: &Generics, value: T) -> Binders<T> {
1311 crate::make_only_type_binders(generics.len(), value) 1304 crate::make_only_type_binders(generics.len(), value)
1312} 1305}
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs
index c601f2d53..be3e4f09a 100644
--- a/crates/hir_ty/src/method_resolution.rs
+++ b/crates/hir_ty/src/method_resolution.rs
@@ -22,8 +22,8 @@ use crate::{
22 static_lifetime, 22 static_lifetime,
23 utils::all_super_traits, 23 utils::all_super_traits,
24 AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, FnPointer, FnSig, ForeignDefId, 24 AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, FnPointer, FnSig, ForeignDefId,
25 InEnvironment, Interner, Scalar, Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, 25 InEnvironment, Interner, Scalar, Substitution, TraitEnvironment, TraitRefExt, Ty, TyBuilder,
26 TypeWalk, 26 TyExt, TyKind,
27}; 27};
28 28
29/// This is used as a key for indexing impls. 29/// This is used as a key for indexing impls.
@@ -757,20 +757,13 @@ pub(crate) fn inherent_impl_substs(
757/// This replaces any 'free' Bound vars in `s` (i.e. those with indices past 757/// This replaces any 'free' Bound vars in `s` (i.e. those with indices past
758/// num_vars_to_keep) by `TyKind::Unknown`. 758/// num_vars_to_keep) by `TyKind::Unknown`.
759fn fallback_bound_vars(s: Substitution, num_vars_to_keep: usize) -> Substitution { 759fn fallback_bound_vars(s: Substitution, num_vars_to_keep: usize) -> Substitution {
760 s.fold_binders( 760 crate::fold_free_vars(s, |bound, binders| {
761 &mut |ty, binders| { 761 if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
762 if let TyKind::BoundVar(bound) = ty.kind(&Interner) { 762 TyKind::Error.intern(&Interner)
763 if bound.index >= num_vars_to_keep && bound.debruijn >= binders { 763 } else {
764 TyKind::Error.intern(&Interner) 764 bound.shifted_in_from(binders).to_ty(&Interner)
765 } else { 765 }
766 ty 766 })
767 }
768 } else {
769 ty
770 }
771 },
772 DebruijnIndex::INNERMOST,
773 )
774} 767}
775 768
776fn transform_receiver_ty( 769fn transform_receiver_ty(
@@ -845,7 +838,7 @@ fn generic_implements_goal(
845 let obligation = trait_ref.cast(&Interner); 838 let obligation = trait_ref.cast(&Interner);
846 Canonical { 839 Canonical {
847 binders: CanonicalVarKinds::from_iter(&Interner, kinds), 840 binders: CanonicalVarKinds::from_iter(&Interner, kinds),
848 value: InEnvironment::new(env.env.clone(), obligation), 841 value: InEnvironment::new(&env.env, obligation),
849 } 842 }
850} 843}
851 844
diff --git a/crates/hir_ty/src/traits.rs b/crates/hir_ty/src/traits.rs
index 3374532c3..1cda72d22 100644
--- a/crates/hir_ty/src/traits.rs
+++ b/crates/hir_ty/src/traits.rs
@@ -9,10 +9,10 @@ use stdx::panic_context;
9 9
10use crate::{ 10use crate::{
11 db::HirDatabase, AliasEq, AliasTy, Canonical, DomainGoal, Guidance, HirDisplay, InEnvironment, 11 db::HirDatabase, AliasEq, AliasTy, Canonical, DomainGoal, Guidance, HirDisplay, InEnvironment,
12 Solution, Ty, TyKind, WhereClause, 12 Solution, TraitRefExt, Ty, TyKind, WhereClause,
13}; 13};
14 14
15use self::chalk::{from_chalk, Interner, ToChalk}; 15use self::chalk::Interner;
16 16
17pub(crate) mod chalk; 17pub(crate) mod chalk;
18 18
@@ -81,6 +81,7 @@ pub(crate) fn trait_solve_query(
81 db.trait_data(it.hir_trait_id()).name.to_string() 81 db.trait_data(it.hir_trait_id()).name.to_string()
82 } 82 }
83 DomainGoal::Holds(WhereClause::AliasEq(_)) => "alias_eq".to_string(), 83 DomainGoal::Holds(WhereClause::AliasEq(_)) => "alias_eq".to_string(),
84 _ => "??".to_string(),
84 }); 85 });
85 log::info!("trait_solve_query({})", goal.value.goal.display(db)); 86 log::info!("trait_solve_query({})", goal.value.goal.display(db));
86 87
@@ -95,13 +96,12 @@ pub(crate) fn trait_solve_query(
95 } 96 }
96 } 97 }
97 98
98 let canonical = goal.to_chalk(db).cast(&Interner); 99 let canonical = goal.cast(&Interner);
99 100
100 // We currently don't deal with universes (I think / hope they're not yet 101 // We currently don't deal with universes (I think / hope they're not yet
101 // relevant for our use cases?) 102 // relevant for our use cases?)
102 let u_canonical = chalk_ir::UCanonical { canonical, universes: 1 }; 103 let u_canonical = chalk_ir::UCanonical { canonical, universes: 1 };
103 let solution = solve(db, krate, &u_canonical); 104 solve(db, krate, &u_canonical)
104 solution.map(|solution| solution_from_chalk(db, solution))
105} 105}
106 106
107fn solve( 107fn solve(
@@ -169,26 +169,6 @@ fn is_chalk_print() -> bool {
169 std::env::var("CHALK_PRINT").is_ok() 169 std::env::var("CHALK_PRINT").is_ok()
170} 170}
171 171
172fn solution_from_chalk(
173 db: &dyn HirDatabase,
174 solution: chalk_solve::Solution<Interner>,
175) -> Solution {
176 match solution {
177 chalk_solve::Solution::Unique(constr_subst) => {
178 Solution::Unique(from_chalk(db, constr_subst))
179 }
180 chalk_solve::Solution::Ambig(chalk_solve::Guidance::Definite(subst)) => {
181 Solution::Ambig(Guidance::Definite(from_chalk(db, subst)))
182 }
183 chalk_solve::Solution::Ambig(chalk_solve::Guidance::Suggested(subst)) => {
184 Solution::Ambig(Guidance::Suggested(from_chalk(db, subst)))
185 }
186 chalk_solve::Solution::Ambig(chalk_solve::Guidance::Unknown) => {
187 Solution::Ambig(Guidance::Unknown)
188 }
189 }
190}
191
192#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 172#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
193pub enum FnTrait { 173pub enum FnTrait {
194 FnOnce, 174 FnOnce,
diff --git a/crates/hir_ty/src/traits/chalk.rs b/crates/hir_ty/src/traits/chalk.rs
index f03b92422..b8c390b2e 100644
--- a/crates/hir_ty/src/traits/chalk.rs
+++ b/crates/hir_ty/src/traits/chalk.rs
@@ -17,16 +17,14 @@ use super::ChalkContext;
17use crate::{ 17use crate::{
18 db::HirDatabase, 18 db::HirDatabase,
19 display::HirDisplay, 19 display::HirDisplay,
20 from_assoc_type_id, 20 from_assoc_type_id, make_only_type_binders,
21 method_resolution::{TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS}, 21 method_resolution::{TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS},
22 to_assoc_type_id, to_chalk_trait_id, 22 to_assoc_type_id, to_chalk_trait_id,
23 utils::generics, 23 utils::generics,
24 AliasEq, AliasTy, BoundVar, CallableDefId, DebruijnIndex, FnDefId, ProjectionTy, Substitution, 24 AliasEq, AliasTy, BoundVar, CallableDefId, DebruijnIndex, FnDefId, ProjectionTy, Substitution,
25 TraitRef, Ty, TyBuilder, TyExt, TyKind, WhereClause, 25 TraitRef, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, WhereClause,
26};
27use mapping::{
28 convert_where_clauses, generic_predicate_to_inline_bound, make_binders, TypeAliasAsValue,
29}; 26};
27use mapping::{convert_where_clauses, generic_predicate_to_inline_bound, TypeAliasAsValue};
30 28
31pub use self::interner::Interner; 29pub use self::interner::Interner;
32pub(crate) use self::interner::*; 30pub(crate) use self::interner::*;
@@ -86,7 +84,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
86 debug!("impls_for_trait {:?}", trait_id); 84 debug!("impls_for_trait {:?}", trait_id);
87 let trait_: hir_def::TraitId = from_chalk(self.db, trait_id); 85 let trait_: hir_def::TraitId = from_chalk(self.db, trait_id);
88 86
89 let ty: Ty = from_chalk(self.db, parameters[0].assert_ty_ref(&Interner).clone()); 87 let ty: Ty = parameters[0].assert_ty_ref(&Interner).clone();
90 88
91 fn binder_kind( 89 fn binder_kind(
92 ty: &Ty, 90 ty: &Ty,
@@ -187,16 +185,11 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
187 let (datas, binders) = (*datas).as_ref().into_value_and_skipped_binders(); 185 let (datas, binders) = (*datas).as_ref().into_value_and_skipped_binders();
188 let data = &datas.impl_traits[idx as usize]; 186 let data = &datas.impl_traits[idx as usize];
189 let bound = OpaqueTyDatumBound { 187 let bound = OpaqueTyDatumBound {
190 bounds: make_binders( 188 bounds: make_only_type_binders(
191 data.bounds
192 .skip_binders()
193 .iter()
194 .cloned()
195 .map(|b| b.to_chalk(self.db))
196 .collect(),
197 1, 189 1,
190 data.bounds.skip_binders().iter().cloned().collect(),
198 ), 191 ),
199 where_clauses: make_binders(vec![], 0), 192 where_clauses: make_only_type_binders(0, vec![]),
200 }; 193 };
201 chalk_ir::Binders::new(binders, bound) 194 chalk_ir::Binders::new(binders, bound)
202 } 195 }
@@ -244,25 +237,25 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
244 .intern(&Interner), 237 .intern(&Interner),
245 }); 238 });
246 let bound = OpaqueTyDatumBound { 239 let bound = OpaqueTyDatumBound {
247 bounds: make_binders( 240 bounds: make_only_type_binders(
241 1,
248 vec![ 242 vec![
249 crate::wrap_empty_binders(impl_bound).to_chalk(self.db), 243 crate::wrap_empty_binders(impl_bound),
250 crate::wrap_empty_binders(proj_bound).to_chalk(self.db), 244 crate::wrap_empty_binders(proj_bound),
251 ], 245 ],
252 1,
253 ), 246 ),
254 where_clauses: make_binders(vec![], 0), 247 where_clauses: make_only_type_binders(0, vec![]),
255 }; 248 };
256 // The opaque type has 1 parameter. 249 // The opaque type has 1 parameter.
257 make_binders(bound, 1) 250 make_only_type_binders(1, bound)
258 } else { 251 } else {
259 // If failed to find Symbol’s value as variable is void: Future::Output, return empty bounds as fallback. 252 // If failed to find Symbol’s value as variable is void: Future::Output, return empty bounds as fallback.
260 let bound = OpaqueTyDatumBound { 253 let bound = OpaqueTyDatumBound {
261 bounds: make_binders(vec![], 0), 254 bounds: make_only_type_binders(0, vec![]),
262 where_clauses: make_binders(vec![], 0), 255 where_clauses: make_only_type_binders(0, vec![]),
263 }; 256 };
264 // The opaque type has 1 parameter. 257 // The opaque type has 1 parameter.
265 make_binders(bound, 1) 258 make_only_type_binders(1, bound)
266 } 259 }
267 } 260 }
268 }; 261 };
@@ -272,7 +265,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
272 265
273 fn hidden_opaque_type(&self, _id: chalk_ir::OpaqueTyId<Interner>) -> chalk_ir::Ty<Interner> { 266 fn hidden_opaque_type(&self, _id: chalk_ir::OpaqueTyId<Interner>) -> chalk_ir::Ty<Interner> {
274 // FIXME: actually provide the hidden type; it is relevant for auto traits 267 // FIXME: actually provide the hidden type; it is relevant for auto traits
275 TyKind::Error.intern(&Interner).to_chalk(self.db) 268 TyKind::Error.intern(&Interner)
276 } 269 }
277 270
278 fn is_object_safe(&self, _trait_id: chalk_ir::TraitId<Interner>) -> bool { 271 fn is_object_safe(&self, _trait_id: chalk_ir::TraitId<Interner>) -> bool {
@@ -293,29 +286,28 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
293 _closure_id: chalk_ir::ClosureId<Interner>, 286 _closure_id: chalk_ir::ClosureId<Interner>,
294 substs: &chalk_ir::Substitution<Interner>, 287 substs: &chalk_ir::Substitution<Interner>,
295 ) -> chalk_ir::Binders<rust_ir::FnDefInputsAndOutputDatum<Interner>> { 288 ) -> chalk_ir::Binders<rust_ir::FnDefInputsAndOutputDatum<Interner>> {
296 let sig_ty: Ty = 289 let sig_ty = substs.at(&Interner, 0).assert_ty_ref(&Interner).clone();
297 from_chalk(self.db, substs.at(&Interner, 0).assert_ty_ref(&Interner).clone());
298 let sig = &sig_ty.callable_sig(self.db).expect("first closure param should be fn ptr"); 290 let sig = &sig_ty.callable_sig(self.db).expect("first closure param should be fn ptr");
299 let io = rust_ir::FnDefInputsAndOutputDatum { 291 let io = rust_ir::FnDefInputsAndOutputDatum {
300 argument_types: sig.params().iter().map(|ty| ty.clone().to_chalk(self.db)).collect(), 292 argument_types: sig.params().iter().cloned().collect(),
301 return_type: sig.ret().clone().to_chalk(self.db), 293 return_type: sig.ret().clone(),
302 }; 294 };
303 make_binders(io.shifted_in(&Interner), 0) 295 make_only_type_binders(0, io.shifted_in(&Interner))
304 } 296 }
305 fn closure_upvars( 297 fn closure_upvars(
306 &self, 298 &self,
307 _closure_id: chalk_ir::ClosureId<Interner>, 299 _closure_id: chalk_ir::ClosureId<Interner>,
308 _substs: &chalk_ir::Substitution<Interner>, 300 _substs: &chalk_ir::Substitution<Interner>,
309 ) -> chalk_ir::Binders<chalk_ir::Ty<Interner>> { 301 ) -> chalk_ir::Binders<chalk_ir::Ty<Interner>> {
310 let ty = TyBuilder::unit().to_chalk(self.db); 302 let ty = TyBuilder::unit();
311 make_binders(ty, 0) 303 make_only_type_binders(0, ty)
312 } 304 }
313 fn closure_fn_substitution( 305 fn closure_fn_substitution(
314 &self, 306 &self,
315 _closure_id: chalk_ir::ClosureId<Interner>, 307 _closure_id: chalk_ir::ClosureId<Interner>,
316 _substs: &chalk_ir::Substitution<Interner>, 308 _substs: &chalk_ir::Substitution<Interner>,
317 ) -> chalk_ir::Substitution<Interner> { 309 ) -> chalk_ir::Substitution<Interner> {
318 Substitution::empty(&Interner).to_chalk(self.db) 310 Substitution::empty(&Interner)
319 } 311 }
320 312
321 fn trait_name(&self, trait_id: chalk_ir::TraitId<Interner>) -> String { 313 fn trait_name(&self, trait_id: chalk_ir::TraitId<Interner>) -> String {
@@ -410,10 +402,10 @@ pub(crate) fn associated_ty_data_query(
410 let where_clauses = convert_where_clauses(db, type_alias.into(), &bound_vars); 402 let where_clauses = convert_where_clauses(db, type_alias.into(), &bound_vars);
411 let bound_data = rust_ir::AssociatedTyDatumBound { bounds, where_clauses }; 403 let bound_data = rust_ir::AssociatedTyDatumBound { bounds, where_clauses };
412 let datum = AssociatedTyDatum { 404 let datum = AssociatedTyDatum {
413 trait_id: trait_.to_chalk(db), 405 trait_id: to_chalk_trait_id(trait_),
414 id, 406 id,
415 name: type_alias, 407 name: type_alias,
416 binders: make_binders(bound_data, generic_params.len()), 408 binders: make_only_type_binders(generic_params.len(), bound_data),
417 }; 409 };
418 Arc::new(datum) 410 Arc::new(datum)
419} 411}
@@ -446,7 +438,7 @@ pub(crate) fn trait_datum_query(
446 lang_attr(db.upcast(), trait_).and_then(|name| well_known_trait_from_lang_attr(&name)); 438 lang_attr(db.upcast(), trait_).and_then(|name| well_known_trait_from_lang_attr(&name));
447 let trait_datum = TraitDatum { 439 let trait_datum = TraitDatum {
448 id: trait_id, 440 id: trait_id,
449 binders: make_binders(trait_datum_bound, bound_vars.len(&Interner)), 441 binders: make_only_type_binders(bound_vars.len(&Interner), trait_datum_bound),
450 flags, 442 flags,
451 associated_ty_ids, 443 associated_ty_ids,
452 well_known, 444 well_known,
@@ -515,7 +507,7 @@ pub(crate) fn struct_datum_query(
515 // FIXME set ADT kind 507 // FIXME set ADT kind
516 kind: rust_ir::AdtKind::Struct, 508 kind: rust_ir::AdtKind::Struct,
517 id: struct_id, 509 id: struct_id,
518 binders: make_binders(struct_datum_bound, num_params), 510 binders: make_only_type_binders(num_params, struct_datum_bound),
519 flags, 511 flags,
520 }; 512 };
521 Arc::new(struct_datum) 513 Arc::new(struct_datum)
@@ -563,7 +555,6 @@ fn impl_def_datum(
563 trait_ref.display(db), 555 trait_ref.display(db),
564 where_clauses 556 where_clauses
565 ); 557 );
566 let trait_ref = trait_ref.to_chalk(db);
567 558
568 let polarity = if negative { rust_ir::Polarity::Negative } else { rust_ir::Polarity::Positive }; 559 let polarity = if negative { rust_ir::Polarity::Negative } else { rust_ir::Polarity::Positive };
569 560
@@ -585,7 +576,7 @@ fn impl_def_datum(
585 .collect(); 576 .collect();
586 debug!("impl_datum: {:?}", impl_datum_bound); 577 debug!("impl_datum: {:?}", impl_datum_bound);
587 let impl_datum = ImplDatum { 578 let impl_datum = ImplDatum {
588 binders: make_binders(impl_datum_bound, bound_vars.len(&Interner)), 579 binders: make_only_type_binders(bound_vars.len(&Interner), impl_datum_bound),
589 impl_type, 580 impl_type,
590 polarity, 581 polarity,
591 associated_ty_value_ids, 582 associated_ty_value_ids,
@@ -624,7 +615,7 @@ fn type_alias_associated_ty_value(
624 .associated_type_by_name(&type_alias_data.name) 615 .associated_type_by_name(&type_alias_data.name)
625 .expect("assoc ty value should not exist"); // validated when building the impl data as well 616 .expect("assoc ty value should not exist"); // validated when building the impl data as well
626 let (ty, binders) = db.ty(type_alias.into()).into_value_and_skipped_binders(); 617 let (ty, binders) = db.ty(type_alias.into()).into_value_and_skipped_binders();
627 let value_bound = rust_ir::AssociatedTyValueBound { ty: ty.to_chalk(db) }; 618 let value_bound = rust_ir::AssociatedTyValueBound { ty };
628 let value = rust_ir::AssociatedTyValue { 619 let value = rust_ir::AssociatedTyValue {
629 impl_id: impl_id.to_chalk(db), 620 impl_id: impl_id.to_chalk(db),
630 associated_ty_id: to_assoc_type_id(assoc_ty), 621 associated_ty_id: to_assoc_type_id(assoc_ty),
@@ -645,13 +636,13 @@ pub(crate) fn fn_def_datum_query(
645 let where_clauses = convert_where_clauses(db, callable_def.into(), &bound_vars); 636 let where_clauses = convert_where_clauses(db, callable_def.into(), &bound_vars);
646 let bound = rust_ir::FnDefDatumBound { 637 let bound = rust_ir::FnDefDatumBound {
647 // Note: Chalk doesn't actually use this information yet as far as I am aware, but we provide it anyway 638 // Note: Chalk doesn't actually use this information yet as far as I am aware, but we provide it anyway
648 inputs_and_output: make_binders( 639 inputs_and_output: make_only_type_binders(
640 0,
649 rust_ir::FnDefInputsAndOutputDatum { 641 rust_ir::FnDefInputsAndOutputDatum {
650 argument_types: sig.params().iter().map(|ty| ty.clone().to_chalk(db)).collect(), 642 argument_types: sig.params().iter().cloned().collect(),
651 return_type: sig.ret().clone().to_chalk(db), 643 return_type: sig.ret().clone(),
652 } 644 }
653 .shifted_in(&Interner), 645 .shifted_in(&Interner),
654 0,
655 ), 646 ),
656 where_clauses, 647 where_clauses,
657 }; 648 };
diff --git a/crates/hir_ty/src/traits/chalk/mapping.rs b/crates/hir_ty/src/traits/chalk/mapping.rs
index 84abd99b2..7818f6387 100644
--- a/crates/hir_ty/src/traits/chalk/mapping.rs
+++ b/crates/hir_ty/src/traits/chalk/mapping.rs
@@ -3,233 +3,20 @@
3//! Chalk (in both directions); plus some helper functions for more specialized 3//! Chalk (in both directions); plus some helper functions for more specialized
4//! conversions. 4//! conversions.
5 5
6use chalk_ir::{cast::Cast, interner::HasInterner}; 6use chalk_ir::cast::Cast;
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::{GenericDefId, TypeAliasId}; 10use hir_def::{GenericDefId, TypeAliasId};
11 11
12use crate::{ 12use crate::{
13 chalk_ext::ProjectionTyExt, db::HirDatabase, static_lifetime, AliasTy, CallableDefId, 13 db::HirDatabase, AliasTy, CallableDefId, ProjectionTyExt, QuantifiedWhereClause, Substitution,
14 Canonical, ConstrainedSubst, DomainGoal, FnPointer, GenericArg, InEnvironment, OpaqueTy, 14 Ty, WhereClause,
15 ProjectionTy, QuantifiedWhereClause, Substitution, TraitRef, Ty, TypeWalk, WhereClause,
16}; 15};
17 16
18use super::interner::*; 17use super::interner::*;
19use super::*; 18use super::*;
20 19
21impl ToChalk for Ty {
22 type Chalk = chalk_ir::Ty<Interner>;
23 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Ty<Interner> {
24 match self.into_inner() {
25 TyKind::Ref(m, lt, ty) => {
26 chalk_ir::TyKind::Ref(m, lt, ty.to_chalk(db)).intern(&Interner)
27 }
28 TyKind::Array(ty, size) => {
29 chalk_ir::TyKind::Array(ty.to_chalk(db), size).intern(&Interner)
30 }
31 TyKind::Function(FnPointer { sig, substitution: substs, num_binders }) => {
32 let substitution = chalk_ir::FnSubst(substs.0.to_chalk(db));
33 chalk_ir::TyKind::Function(chalk_ir::FnPointer { num_binders, sig, substitution })
34 .intern(&Interner)
35 }
36 TyKind::AssociatedType(assoc_type_id, substs) => {
37 let substitution = substs.to_chalk(db);
38 chalk_ir::TyKind::AssociatedType(assoc_type_id, substitution).intern(&Interner)
39 }
40
41 TyKind::OpaqueType(id, substs) => {
42 let substitution = substs.to_chalk(db);
43 chalk_ir::TyKind::OpaqueType(id, substitution).intern(&Interner)
44 }
45
46 TyKind::Foreign(id) => chalk_ir::TyKind::Foreign(id).intern(&Interner),
47
48 TyKind::Scalar(scalar) => chalk_ir::TyKind::Scalar(scalar).intern(&Interner),
49
50 TyKind::Tuple(cardinality, substs) => {
51 let substitution = substs.to_chalk(db);
52 chalk_ir::TyKind::Tuple(cardinality, substitution).intern(&Interner)
53 }
54 TyKind::Raw(mutability, ty) => {
55 let ty = ty.to_chalk(db);
56 chalk_ir::TyKind::Raw(mutability, ty).intern(&Interner)
57 }
58 TyKind::Slice(ty) => chalk_ir::TyKind::Slice(ty.to_chalk(db)).intern(&Interner),
59 TyKind::Str => chalk_ir::TyKind::Str.intern(&Interner),
60 TyKind::FnDef(id, substs) => {
61 let substitution = substs.to_chalk(db);
62 chalk_ir::TyKind::FnDef(id, substitution).intern(&Interner)
63 }
64 TyKind::Never => chalk_ir::TyKind::Never.intern(&Interner),
65
66 TyKind::Closure(closure_id, substs) => {
67 let substitution = substs.to_chalk(db);
68 chalk_ir::TyKind::Closure(closure_id, substitution).intern(&Interner)
69 }
70
71 TyKind::Adt(adt_id, substs) => {
72 let substitution = substs.to_chalk(db);
73 chalk_ir::TyKind::Adt(adt_id, substitution).intern(&Interner)
74 }
75 TyKind::Alias(AliasTy::Projection(proj_ty)) => {
76 chalk_ir::AliasTy::Projection(proj_ty.to_chalk(db))
77 .cast(&Interner)
78 .intern(&Interner)
79 }
80 TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
81 chalk_ir::AliasTy::Opaque(opaque_ty.to_chalk(db)).cast(&Interner).intern(&Interner)
82 }
83 TyKind::Placeholder(idx) => idx.to_ty::<Interner>(&Interner),
84 TyKind::BoundVar(idx) => chalk_ir::TyKind::BoundVar(idx).intern(&Interner),
85 TyKind::InferenceVar(..) => panic!("uncanonicalized infer ty"),
86 TyKind::Dyn(dyn_ty) => {
87 let (bounds, binders) = dyn_ty.bounds.into_value_and_skipped_binders();
88 let where_clauses = chalk_ir::QuantifiedWhereClauses::from_iter(
89 &Interner,
90 bounds.interned().iter().cloned().map(|p| p.to_chalk(db)),
91 );
92 let bounded_ty = chalk_ir::DynTy {
93 bounds: chalk_ir::Binders::new(binders, where_clauses),
94 lifetime: dyn_ty.lifetime,
95 };
96 chalk_ir::TyKind::Dyn(bounded_ty).intern(&Interner)
97 }
98 TyKind::Error => chalk_ir::TyKind::Error.intern(&Interner),
99 }
100 }
101 fn from_chalk(db: &dyn HirDatabase, chalk: chalk_ir::Ty<Interner>) -> Self {
102 match chalk.data(&Interner).kind.clone() {
103 chalk_ir::TyKind::Error => TyKind::Error,
104 chalk_ir::TyKind::Array(ty, size) => TyKind::Array(from_chalk(db, ty), size),
105 chalk_ir::TyKind::Placeholder(idx) => TyKind::Placeholder(idx),
106 chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Projection(proj)) => {
107 TyKind::Alias(AliasTy::Projection(from_chalk(db, proj)))
108 }
109 chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Opaque(opaque_ty)) => {
110 TyKind::Alias(AliasTy::Opaque(from_chalk(db, opaque_ty)))
111 }
112 chalk_ir::TyKind::Function(chalk_ir::FnPointer {
113 num_binders,
114 sig,
115 substitution,
116 ..
117 }) => {
118 assert_eq!(num_binders, 0);
119 let substs = crate::FnSubst(from_chalk(db, substitution.0));
120 TyKind::Function(FnPointer { num_binders, sig, substitution: substs })
121 }
122 chalk_ir::TyKind::BoundVar(idx) => TyKind::BoundVar(idx),
123 chalk_ir::TyKind::InferenceVar(_iv, _kind) => TyKind::Error,
124 chalk_ir::TyKind::Dyn(dyn_ty) => {
125 assert_eq!(dyn_ty.bounds.binders.len(&Interner), 1);
126 let (bounds, binders) = dyn_ty.bounds.into_value_and_skipped_binders();
127 let where_clauses = crate::QuantifiedWhereClauses::from_iter(
128 &Interner,
129 bounds.interned().iter().cloned().map(|p| from_chalk(db, p)),
130 );
131 TyKind::Dyn(crate::DynTy {
132 bounds: crate::Binders::new(binders, where_clauses),
133 // HACK: we sometimes get lifetime variables back in solutions
134 // from Chalk, and don't have the infrastructure to substitute
135 // them yet. So for now we just turn them into 'static right
136 // when we get them
137 lifetime: static_lifetime(),
138 })
139 }
140
141 chalk_ir::TyKind::Adt(adt_id, subst) => TyKind::Adt(adt_id, from_chalk(db, subst)),
142 chalk_ir::TyKind::AssociatedType(type_id, subst) => {
143 TyKind::AssociatedType(type_id, from_chalk(db, subst))
144 }
145
146 chalk_ir::TyKind::OpaqueType(opaque_type_id, subst) => {
147 TyKind::OpaqueType(opaque_type_id, from_chalk(db, subst))
148 }
149
150 chalk_ir::TyKind::Scalar(scalar) => TyKind::Scalar(scalar),
151 chalk_ir::TyKind::Tuple(cardinality, subst) => {
152 TyKind::Tuple(cardinality, from_chalk(db, subst))
153 }
154 chalk_ir::TyKind::Raw(mutability, ty) => TyKind::Raw(mutability, from_chalk(db, ty)),
155 chalk_ir::TyKind::Slice(ty) => TyKind::Slice(from_chalk(db, ty)),
156 chalk_ir::TyKind::Ref(mutability, _lifetime, ty) => {
157 // HACK: we sometimes get lifetime variables back in solutions
158 // from Chalk, and don't have the infrastructure to substitute
159 // them yet. So for now we just turn them into 'static right
160 // when we get them
161 TyKind::Ref(mutability, static_lifetime(), from_chalk(db, ty))
162 }
163 chalk_ir::TyKind::Str => TyKind::Str,
164 chalk_ir::TyKind::Never => TyKind::Never,
165
166 chalk_ir::TyKind::FnDef(fn_def_id, subst) => {
167 TyKind::FnDef(fn_def_id, from_chalk(db, subst))
168 }
169
170 chalk_ir::TyKind::Closure(id, subst) => TyKind::Closure(id, from_chalk(db, subst)),
171
172 chalk_ir::TyKind::Foreign(foreign_def_id) => TyKind::Foreign(foreign_def_id),
173 chalk_ir::TyKind::Generator(_, _) => unimplemented!(), // FIXME
174 chalk_ir::TyKind::GeneratorWitness(_, _) => unimplemented!(), // FIXME
175 }
176 .intern(&Interner)
177 }
178}
179
180impl ToChalk for GenericArg {
181 type Chalk = chalk_ir::GenericArg<Interner>;
182
183 fn to_chalk(self, db: &dyn HirDatabase) -> Self::Chalk {
184 match self.interned() {
185 crate::GenericArgData::Ty(ty) => ty.clone().to_chalk(db).cast(&Interner),
186 }
187 }
188
189 fn from_chalk(db: &dyn HirDatabase, chalk: Self::Chalk) -> Self {
190 match chalk.interned() {
191 chalk_ir::GenericArgData::Ty(ty) => Ty::from_chalk(db, ty.clone()).cast(&Interner),
192 chalk_ir::GenericArgData::Lifetime(_) => unimplemented!(),
193 chalk_ir::GenericArgData::Const(_) => unimplemented!(),
194 }
195 }
196}
197
198impl ToChalk for Substitution {
199 type Chalk = chalk_ir::Substitution<Interner>;
200
201 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Substitution<Interner> {
202 chalk_ir::Substitution::from_iter(
203 &Interner,
204 self.iter(&Interner).map(|ty| ty.clone().to_chalk(db)),
205 )
206 }
207
208 fn from_chalk(
209 db: &dyn HirDatabase,
210 parameters: chalk_ir::Substitution<Interner>,
211 ) -> Substitution {
212 let tys = parameters.iter(&Interner).map(|p| from_chalk(db, p.clone())).collect();
213 Substitution::intern(tys)
214 }
215}
216
217impl ToChalk for TraitRef {
218 type Chalk = chalk_ir::TraitRef<Interner>;
219
220 fn to_chalk(self: TraitRef, db: &dyn HirDatabase) -> chalk_ir::TraitRef<Interner> {
221 let trait_id = self.trait_id;
222 let substitution = self.substitution.to_chalk(db);
223 chalk_ir::TraitRef { trait_id, substitution }
224 }
225
226 fn from_chalk(db: &dyn HirDatabase, trait_ref: chalk_ir::TraitRef<Interner>) -> Self {
227 let trait_id = trait_ref.trait_id;
228 let substs = from_chalk(db, trait_ref.substitution);
229 TraitRef { trait_id, substitution: substs }
230 }
231}
232
233impl ToChalk for hir_def::TraitId { 20impl ToChalk for hir_def::TraitId {
234 type Chalk = TraitId; 21 type Chalk = TraitId;
235 22
@@ -283,208 +70,6 @@ impl ToChalk for TypeAliasAsValue {
283 } 70 }
284} 71}
285 72
286impl ToChalk for WhereClause {
287 type Chalk = chalk_ir::WhereClause<Interner>;
288
289 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::WhereClause<Interner> {
290 match self {
291 WhereClause::Implemented(trait_ref) => {
292 chalk_ir::WhereClause::Implemented(trait_ref.to_chalk(db))
293 }
294 WhereClause::AliasEq(alias_eq) => chalk_ir::WhereClause::AliasEq(alias_eq.to_chalk(db)),
295 }
296 }
297
298 fn from_chalk(
299 db: &dyn HirDatabase,
300 where_clause: chalk_ir::WhereClause<Interner>,
301 ) -> WhereClause {
302 match where_clause {
303 chalk_ir::WhereClause::Implemented(tr) => WhereClause::Implemented(from_chalk(db, tr)),
304 chalk_ir::WhereClause::AliasEq(alias_eq) => {
305 WhereClause::AliasEq(from_chalk(db, alias_eq))
306 }
307
308 chalk_ir::WhereClause::LifetimeOutlives(_) => {
309 // we shouldn't get these from Chalk
310 panic!("encountered LifetimeOutlives from Chalk")
311 }
312
313 chalk_ir::WhereClause::TypeOutlives(_) => {
314 // we shouldn't get these from Chalk
315 panic!("encountered TypeOutlives from Chalk")
316 }
317 }
318 }
319}
320
321impl ToChalk for ProjectionTy {
322 type Chalk = chalk_ir::ProjectionTy<Interner>;
323
324 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::ProjectionTy<Interner> {
325 chalk_ir::ProjectionTy {
326 associated_ty_id: self.associated_ty_id,
327 substitution: self.substitution.to_chalk(db),
328 }
329 }
330
331 fn from_chalk(
332 db: &dyn HirDatabase,
333 projection_ty: chalk_ir::ProjectionTy<Interner>,
334 ) -> ProjectionTy {
335 ProjectionTy {
336 associated_ty_id: projection_ty.associated_ty_id,
337 substitution: from_chalk(db, projection_ty.substitution),
338 }
339 }
340}
341impl ToChalk for OpaqueTy {
342 type Chalk = chalk_ir::OpaqueTy<Interner>;
343
344 fn to_chalk(self, db: &dyn HirDatabase) -> Self::Chalk {
345 chalk_ir::OpaqueTy {
346 opaque_ty_id: self.opaque_ty_id,
347 substitution: self.substitution.to_chalk(db),
348 }
349 }
350
351 fn from_chalk(db: &dyn HirDatabase, chalk: Self::Chalk) -> Self {
352 OpaqueTy {
353 opaque_ty_id: chalk.opaque_ty_id,
354 substitution: from_chalk(db, chalk.substitution),
355 }
356 }
357}
358
359impl ToChalk for AliasTy {
360 type Chalk = chalk_ir::AliasTy<Interner>;
361
362 fn to_chalk(self, db: &dyn HirDatabase) -> Self::Chalk {
363 match self {
364 AliasTy::Projection(projection_ty) => {
365 chalk_ir::AliasTy::Projection(projection_ty.to_chalk(db))
366 }
367 AliasTy::Opaque(opaque_ty) => chalk_ir::AliasTy::Opaque(opaque_ty.to_chalk(db)),
368 }
369 }
370
371 fn from_chalk(db: &dyn HirDatabase, chalk: Self::Chalk) -> Self {
372 match chalk {
373 chalk_ir::AliasTy::Projection(projection_ty) => {
374 AliasTy::Projection(from_chalk(db, projection_ty))
375 }
376 chalk_ir::AliasTy::Opaque(opaque_ty) => AliasTy::Opaque(from_chalk(db, opaque_ty)),
377 }
378 }
379}
380
381impl ToChalk for AliasEq {
382 type Chalk = chalk_ir::AliasEq<Interner>;
383
384 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::AliasEq<Interner> {
385 chalk_ir::AliasEq { alias: self.alias.to_chalk(db), ty: self.ty.to_chalk(db) }
386 }
387
388 fn from_chalk(db: &dyn HirDatabase, alias_eq: chalk_ir::AliasEq<Interner>) -> Self {
389 AliasEq { alias: from_chalk(db, alias_eq.alias), ty: from_chalk(db, alias_eq.ty) }
390 }
391}
392
393impl ToChalk for DomainGoal {
394 type Chalk = chalk_ir::DomainGoal<Interner>;
395
396 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::DomainGoal<Interner> {
397 match self {
398 DomainGoal::Holds(WhereClause::Implemented(tr)) => tr.to_chalk(db).cast(&Interner),
399 DomainGoal::Holds(WhereClause::AliasEq(alias_eq)) => {
400 alias_eq.to_chalk(db).cast(&Interner)
401 }
402 }
403 }
404
405 fn from_chalk(_db: &dyn HirDatabase, _goal: chalk_ir::DomainGoal<Interner>) -> Self {
406 unimplemented!()
407 }
408}
409
410impl<T> ToChalk for Canonical<T>
411where
412 T: ToChalk,
413 T::Chalk: HasInterner<Interner = Interner>,
414{
415 type Chalk = chalk_ir::Canonical<T::Chalk>;
416
417 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Canonical<T::Chalk> {
418 let value = self.value.to_chalk(db);
419 chalk_ir::Canonical { value, binders: self.binders }
420 }
421
422 fn from_chalk(db: &dyn HirDatabase, canonical: chalk_ir::Canonical<T::Chalk>) -> Canonical<T> {
423 Canonical { binders: canonical.binders, value: from_chalk(db, canonical.value) }
424 }
425}
426
427impl<T: ToChalk> ToChalk for InEnvironment<T>
428where
429 T::Chalk: chalk_ir::interner::HasInterner<Interner = Interner>,
430{
431 type Chalk = chalk_ir::InEnvironment<T::Chalk>;
432
433 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::InEnvironment<T::Chalk> {
434 chalk_ir::InEnvironment { environment: self.environment, goal: self.goal.to_chalk(db) }
435 }
436
437 fn from_chalk(
438 _db: &dyn HirDatabase,
439 _in_env: chalk_ir::InEnvironment<T::Chalk>,
440 ) -> InEnvironment<T> {
441 unimplemented!()
442 }
443}
444
445impl<T: ToChalk> ToChalk for crate::Binders<T>
446where
447 T::Chalk: chalk_ir::interner::HasInterner<Interner = Interner>,
448{
449 type Chalk = chalk_ir::Binders<T::Chalk>;
450
451 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Binders<T::Chalk> {
452 let (value, binders) = self.into_value_and_skipped_binders();
453 chalk_ir::Binders::new(binders, value.to_chalk(db))
454 }
455
456 fn from_chalk(db: &dyn HirDatabase, binders: chalk_ir::Binders<T::Chalk>) -> crate::Binders<T> {
457 let (v, b) = binders.into_value_and_skipped_binders();
458 crate::Binders::new(b, from_chalk(db, v))
459 }
460}
461
462impl ToChalk for crate::ConstrainedSubst {
463 type Chalk = chalk_ir::ConstrainedSubst<Interner>;
464
465 fn to_chalk(self, _db: &dyn HirDatabase) -> Self::Chalk {
466 unimplemented!()
467 }
468
469 fn from_chalk(db: &dyn HirDatabase, chalk: Self::Chalk) -> Self {
470 ConstrainedSubst { subst: from_chalk(db, chalk.subst) }
471 }
472}
473
474pub(super) fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T>
475where
476 T: HasInterner<Interner = Interner>,
477{
478 chalk_ir::Binders::new(
479 chalk_ir::VariableKinds::from_iter(
480 &Interner,
481 std::iter::repeat(chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General))
482 .take(num_vars),
483 ),
484 value,
485 )
486}
487
488pub(super) fn convert_where_clauses( 73pub(super) fn convert_where_clauses(
489 db: &dyn HirDatabase, 74 db: &dyn HirDatabase,
490 def: GenericDefId, 75 def: GenericDefId,
@@ -493,7 +78,7 @@ pub(super) fn convert_where_clauses(
493 let generic_predicates = db.generic_predicates(def); 78 let generic_predicates = db.generic_predicates(def);
494 let mut result = Vec::with_capacity(generic_predicates.len()); 79 let mut result = Vec::with_capacity(generic_predicates.len());
495 for pred in generic_predicates.iter() { 80 for pred in generic_predicates.iter() {
496 result.push(pred.clone().substitute(&Interner, substs).to_chalk(db)); 81 result.push(pred.clone().substitute(&Interner, substs));
497 } 82 }
498 result 83 result
499} 84}
@@ -505,33 +90,33 @@ pub(super) fn generic_predicate_to_inline_bound(
505) -> Option<chalk_ir::Binders<rust_ir::InlineBound<Interner>>> { 90) -> Option<chalk_ir::Binders<rust_ir::InlineBound<Interner>>> {
506 // An InlineBound is like a GenericPredicate, except the self type is left out. 91 // An InlineBound is like a GenericPredicate, except the self type is left out.
507 // We don't have a special type for this, but Chalk does. 92 // We don't have a special type for this, but Chalk does.
508 let self_ty_shifted_in = self_ty.clone().shifted_in_from(DebruijnIndex::ONE); 93 let self_ty_shifted_in = self_ty.clone().shifted_in_from(&Interner, DebruijnIndex::ONE);
509 let (pred, binders) = pred.as_ref().into_value_and_skipped_binders(); 94 let (pred, binders) = pred.as_ref().into_value_and_skipped_binders();
510 match pred { 95 match pred {
511 WhereClause::Implemented(trait_ref) => { 96 WhereClause::Implemented(trait_ref) => {
512 if trait_ref.self_type_parameter(&Interner) != &self_ty_shifted_in { 97 if trait_ref.self_type_parameter(&Interner) != self_ty_shifted_in {
513 // we can only convert predicates back to type bounds if they 98 // we can only convert predicates back to type bounds if they
514 // have the expected self type 99 // have the expected self type
515 return None; 100 return None;
516 } 101 }
517 let args_no_self = trait_ref.substitution.interned()[1..] 102 let args_no_self = trait_ref.substitution.interned()[1..]
518 .iter() 103 .iter()
519 .map(|ty| ty.clone().to_chalk(db).cast(&Interner)) 104 .map(|ty| ty.clone().cast(&Interner))
520 .collect(); 105 .collect();
521 let trait_bound = rust_ir::TraitBound { trait_id: trait_ref.trait_id, args_no_self }; 106 let trait_bound = rust_ir::TraitBound { trait_id: trait_ref.trait_id, args_no_self };
522 Some(chalk_ir::Binders::new(binders, rust_ir::InlineBound::TraitBound(trait_bound))) 107 Some(chalk_ir::Binders::new(binders, rust_ir::InlineBound::TraitBound(trait_bound)))
523 } 108 }
524 WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => { 109 WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => {
525 if projection_ty.self_type_parameter(&Interner) != &self_ty_shifted_in { 110 if projection_ty.self_type_parameter(&Interner) != self_ty_shifted_in {
526 return None; 111 return None;
527 } 112 }
528 let trait_ = projection_ty.trait_(db); 113 let trait_ = projection_ty.trait_(db);
529 let args_no_self = projection_ty.substitution.interned()[1..] 114 let args_no_self = projection_ty.substitution.interned()[1..]
530 .iter() 115 .iter()
531 .map(|ty| ty.clone().to_chalk(db).cast(&Interner)) 116 .map(|ty| ty.clone().cast(&Interner))
532 .collect(); 117 .collect();
533 let alias_eq_bound = rust_ir::AliasEqBound { 118 let alias_eq_bound = rust_ir::AliasEqBound {
534 value: ty.clone().to_chalk(db), 119 value: ty.clone(),
535 trait_bound: rust_ir::TraitBound { trait_id: trait_.to_chalk(db), args_no_self }, 120 trait_bound: rust_ir::TraitBound { trait_id: trait_.to_chalk(db), args_no_self },
536 associated_ty_id: projection_ty.associated_ty_id, 121 associated_ty_id: projection_ty.associated_ty_id,
537 parameters: Vec::new(), // FIXME we don't support generic associated types yet 122 parameters: Vec::new(), // FIXME we don't support generic associated types yet
diff --git a/crates/hir_ty/src/types.rs b/crates/hir_ty/src/types.rs
deleted file mode 100644
index c25bc2d6a..000000000
--- a/crates/hir_ty/src/types.rs
+++ /dev/null
@@ -1,549 +0,0 @@
1//! This is the home of `Ty` etc. until they get replaced by their chalk_ir
2//! equivalents.
3
4use std::sync::Arc;
5
6use chalk_ir::{
7 cast::{Cast, CastTo, Caster},
8 BoundVar, Mutability, Scalar, TyVariableKind,
9};
10use smallvec::SmallVec;
11
12use crate::{
13 AssocTypeId, CanonicalVarKinds, ChalkTraitId, ClosureId, Const, FnDefId, FnSig, ForeignDefId,
14 Interner, Lifetime, OpaqueTyId, PlaceholderIndex, TypeWalk, VariableKind, VariableKinds,
15};
16
17#[derive(Clone, PartialEq, Eq, Debug, Hash)]
18pub struct OpaqueTy {
19 pub opaque_ty_id: OpaqueTyId,
20 pub substitution: Substitution,
21}
22
23/// A "projection" type corresponds to an (unnormalized)
24/// projection like `<P0 as Trait<P1..Pn>>::Foo`. Note that the
25/// trait and all its parameters are fully known.
26#[derive(Clone, PartialEq, Eq, Debug, Hash)]
27pub struct ProjectionTy {
28 pub associated_ty_id: AssocTypeId,
29 pub substitution: Substitution,
30}
31
32impl ProjectionTy {
33 pub fn self_type_parameter(&self, interner: &Interner) -> &Ty {
34 &self.substitution.interned()[0].assert_ty_ref(interner)
35 }
36}
37
38#[derive(Clone, PartialEq, Eq, Debug, Hash)]
39pub struct DynTy {
40 /// The unknown self type.
41 pub bounds: Binders<QuantifiedWhereClauses>,
42 pub lifetime: Lifetime,
43}
44
45#[derive(Clone, PartialEq, Eq, Debug, Hash)]
46pub struct FnPointer {
47 pub num_binders: usize,
48 pub sig: FnSig,
49 pub substitution: FnSubst,
50}
51/// A wrapper for the substs on a Fn.
52#[derive(Clone, PartialEq, Eq, Debug, Hash)]
53pub struct FnSubst(pub Substitution);
54
55impl FnPointer {
56 /// Represent the current `Fn` as if it was wrapped in `Binders`
57 pub fn into_binders(self, interner: &Interner) -> Binders<FnSubst> {
58 Binders::new(
59 VariableKinds::from_iter(
60 interner,
61 (0..self.num_binders).map(|_| VariableKind::Lifetime),
62 ),
63 self.substitution,
64 )
65 }
66
67 /// Represent the current `Fn` as if it was wrapped in `Binders`
68 pub fn as_binders(&self, interner: &Interner) -> Binders<&FnSubst> {
69 Binders::new(
70 VariableKinds::from_iter(
71 interner,
72 (0..self.num_binders).map(|_| VariableKind::Lifetime),
73 ),
74 &self.substitution,
75 )
76 }
77}
78
79#[derive(Clone, PartialEq, Eq, Debug, Hash)]
80pub enum AliasTy {
81 /// A "projection" type corresponds to an (unnormalized)
82 /// projection like `<P0 as Trait<P1..Pn>>::Foo`. Note that the
83 /// trait and all its parameters are fully known.
84 Projection(ProjectionTy),
85 /// An opaque type (`impl Trait`).
86 ///
87 /// This is currently only used for return type impl trait; each instance of
88 /// `impl Trait` in a return type gets its own ID.
89 Opaque(OpaqueTy),
90}
91
92/// A type.
93///
94/// See also the `TyKind` enum in rustc (librustc/ty/sty.rs), which represents
95/// the same thing (but in a different way).
96///
97/// This should be cheap to clone.
98#[derive(Clone, PartialEq, Eq, Debug, Hash)]
99pub enum TyKind {
100 /// Structures, enumerations and unions.
101 Adt(chalk_ir::AdtId<Interner>, Substitution),
102
103 /// Represents an associated item like `Iterator::Item`. This is used
104 /// when we have tried to normalize a projection like `T::Item` but
105 /// couldn't find a better representation. In that case, we generate
106 /// an **application type** like `(Iterator::Item)<T>`.
107 AssociatedType(AssocTypeId, Substitution),
108
109 /// a scalar type like `bool` or `u32`
110 Scalar(Scalar),
111
112 /// A tuple type. For example, `(i32, bool)`.
113 Tuple(usize, Substitution),
114
115 /// An array with the given length. Written as `[T; n]`.
116 Array(Ty, Const),
117
118 /// The pointee of an array slice. Written as `[T]`.
119 Slice(Ty),
120
121 /// A raw pointer. Written as `*mut T` or `*const T`
122 Raw(Mutability, Ty),
123
124 /// A reference; a pointer with an associated lifetime. Written as
125 /// `&'a mut T` or `&'a T`.
126 Ref(Mutability, Lifetime, Ty),
127
128 /// This represents a placeholder for an opaque type in situations where we
129 /// don't know the hidden type (i.e. currently almost always). This is
130 /// analogous to the `AssociatedType` type constructor.
131 /// It is also used as the type of async block, with one type parameter
132 /// representing the Future::Output type.
133 OpaqueType(OpaqueTyId, Substitution),
134
135 /// The anonymous type of a function declaration/definition. Each
136 /// function has a unique type, which is output (for a function
137 /// named `foo` returning an `i32`) as `fn() -> i32 {foo}`.
138 ///
139 /// This includes tuple struct / enum variant constructors as well.
140 ///
141 /// For example the type of `bar` here:
142 ///
143 /// ```
144 /// fn foo() -> i32 { 1 }
145 /// let bar = foo; // bar: fn() -> i32 {foo}
146 /// ```
147 FnDef(FnDefId, Substitution),
148
149 /// The pointee of a string slice. Written as `str`.
150 Str,
151
152 /// The never type `!`.
153 Never,
154
155 /// The type of a specific closure.
156 ///
157 /// The closure signature is stored in a `FnPtr` type in the first type
158 /// parameter.
159 Closure(ClosureId, Substitution),
160
161 /// Represents a foreign type declared in external blocks.
162 Foreign(ForeignDefId),
163
164 /// A pointer to a function. Written as `fn() -> i32`.
165 ///
166 /// For example the type of `bar` here:
167 ///
168 /// ```
169 /// fn foo() -> i32 { 1 }
170 /// let bar: fn() -> i32 = foo;
171 /// ```
172 Function(FnPointer),
173
174 /// An "alias" type represents some form of type alias, such as:
175 /// - An associated type projection like `<T as Iterator>::Item`
176 /// - `impl Trait` types
177 /// - Named type aliases like `type Foo<X> = Vec<X>`
178 Alias(AliasTy),
179
180 /// A placeholder for a type parameter; for example, `T` in `fn f<T>(x: T)
181 /// {}` when we're type-checking the body of that function. In this
182 /// situation, we know this stands for *some* type, but don't know the exact
183 /// type.
184 Placeholder(PlaceholderIndex),
185
186 /// A bound type variable. This is used in various places: when representing
187 /// some polymorphic type like the type of function `fn f<T>`, the type
188 /// parameters get turned into variables; during trait resolution, inference
189 /// variables get turned into bound variables and back; and in `Dyn` the
190 /// `Self` type is represented with a bound variable as well.
191 BoundVar(BoundVar),
192
193 /// A type variable used during type checking.
194 InferenceVar(InferenceVar, TyVariableKind),
195
196 /// A trait object (`dyn Trait` or bare `Trait` in pre-2018 Rust).
197 ///
198 /// The predicates are quantified over the `Self` type, i.e. `Ty::Bound(0)`
199 /// represents the `Self` type inside the bounds. This is currently
200 /// implicit; Chalk has the `Binders` struct to make it explicit, but it
201 /// didn't seem worth the overhead yet.
202 Dyn(DynTy),
203
204 /// A placeholder for a type which could not be computed; this is propagated
205 /// to avoid useless error messages. Doubles as a placeholder where type
206 /// variables are inserted before type checking, since we want to try to
207 /// infer a better type here anyway -- for the IDE use case, we want to try
208 /// to infer as much as possible even in the presence of type errors.
209 Error,
210}
211
212#[derive(Clone, PartialEq, Eq, Debug, Hash)]
213pub struct Ty(Arc<TyKind>);
214
215impl TyKind {
216 pub fn intern(self, _interner: &Interner) -> Ty {
217 Ty(Arc::new(self))
218 }
219}
220
221impl Ty {
222 pub fn kind(&self, _interner: &Interner) -> &TyKind {
223 &self.0
224 }
225
226 pub fn interned_mut(&mut self) -> &mut TyKind {
227 Arc::make_mut(&mut self.0)
228 }
229
230 pub fn into_inner(self) -> TyKind {
231 Arc::try_unwrap(self.0).unwrap_or_else(|a| (*a).clone())
232 }
233}
234
235#[derive(Clone, PartialEq, Eq, Debug, Hash)]
236pub struct GenericArg {
237 interned: GenericArgData,
238}
239
240#[derive(Clone, PartialEq, Eq, Debug, Hash)]
241pub enum GenericArgData {
242 Ty(Ty),
243}
244
245impl GenericArg {
246 /// Constructs a generic argument using `GenericArgData`.
247 pub fn new(_interner: &Interner, data: GenericArgData) -> Self {
248 GenericArg { interned: data }
249 }
250
251 /// Gets the interned value.
252 pub fn interned(&self) -> &GenericArgData {
253 &self.interned
254 }
255
256 /// Asserts that this is a type argument.
257 pub fn assert_ty_ref(&self, interner: &Interner) -> &Ty {
258 self.ty(interner).unwrap()
259 }
260
261 /// Checks whether the generic argument is a type.
262 pub fn is_ty(&self, _interner: &Interner) -> bool {
263 match self.interned() {
264 GenericArgData::Ty(_) => true,
265 }
266 }
267
268 /// Returns the type if it is one, `None` otherwise.
269 pub fn ty(&self, _interner: &Interner) -> Option<&Ty> {
270 match self.interned() {
271 GenericArgData::Ty(t) => Some(t),
272 }
273 }
274
275 pub fn interned_mut(&mut self) -> &mut GenericArgData {
276 &mut self.interned
277 }
278}
279
280/// A list of substitutions for generic parameters.
281#[derive(Clone, PartialEq, Eq, Debug, Hash)]
282pub struct Substitution(SmallVec<[GenericArg; 2]>);
283
284impl Substitution {
285 pub fn interned(&self) -> &[GenericArg] {
286 &self.0
287 }
288
289 pub fn len(&self, _: &Interner) -> usize {
290 self.0.len()
291 }
292
293 pub fn is_empty(&self, _: &Interner) -> bool {
294 self.0.is_empty()
295 }
296
297 pub fn at(&self, _: &Interner, i: usize) -> &GenericArg {
298 &self.0[i]
299 }
300
301 pub fn empty(_: &Interner) -> Substitution {
302 Substitution(SmallVec::new())
303 }
304
305 pub fn iter(&self, _: &Interner) -> std::slice::Iter<'_, GenericArg> {
306 self.0.iter()
307 }
308
309 pub fn from1(_interner: &Interner, ty: Ty) -> Substitution {
310 Substitution::intern({
311 let mut v = SmallVec::new();
312 v.push(ty.cast(&Interner));
313 v
314 })
315 }
316
317 pub fn from_iter(
318 interner: &Interner,
319 elements: impl IntoIterator<Item = impl CastTo<GenericArg>>,
320 ) -> Self {
321 Substitution(elements.into_iter().casted(interner).collect())
322 }
323
324 pub fn apply<T: TypeWalk>(&self, value: T, _interner: &Interner) -> T {
325 value.subst_bound_vars(self)
326 }
327
328 // Temporary helper functions, to be removed
329 pub fn intern(interned: SmallVec<[GenericArg; 2]>) -> Substitution {
330 Substitution(interned)
331 }
332
333 pub fn interned_mut(&mut self) -> &mut SmallVec<[GenericArg; 2]> {
334 &mut self.0
335 }
336}
337
338#[derive(Clone, PartialEq, Eq, Hash)]
339pub struct Binders<T> {
340 /// The binders that quantify over the value.
341 pub binders: VariableKinds,
342 value: T,
343}
344
345impl<T> Binders<T> {
346 pub fn new(binders: VariableKinds, value: T) -> Self {
347 Self { binders, value }
348 }
349
350 pub fn empty(_interner: &Interner, value: T) -> Self {
351 crate::make_only_type_binders(0, value)
352 }
353
354 pub fn as_ref(&self) -> Binders<&T> {
355 Binders { binders: self.binders.clone(), value: &self.value }
356 }
357
358 pub fn map<U>(self, f: impl FnOnce(T) -> U) -> Binders<U> {
359 Binders { binders: self.binders, value: f(self.value) }
360 }
361
362 pub fn filter_map<U>(self, f: impl FnOnce(T) -> Option<U>) -> Option<Binders<U>> {
363 Some(Binders { binders: self.binders, value: f(self.value)? })
364 }
365
366 pub fn skip_binders(&self) -> &T {
367 &self.value
368 }
369
370 pub fn into_value_and_skipped_binders(self) -> (T, VariableKinds) {
371 (self.value, self.binders)
372 }
373
374 /// Returns the number of binders.
375 pub fn len(&self, interner: &Interner) -> usize {
376 self.binders.len(interner)
377 }
378
379 // Temporary helper function, to be removed
380 pub fn skip_binders_mut(&mut self) -> &mut T {
381 &mut self.value
382 }
383}
384
385impl<T: Clone> Binders<&T> {
386 pub fn cloned(&self) -> Binders<T> {
387 Binders::new(self.binders.clone(), self.value.clone())
388 }
389}
390
391impl<T: TypeWalk> Binders<T> {
392 /// Substitutes all variables.
393 pub fn substitute(self, interner: &Interner, subst: &Substitution) -> T {
394 let (value, binders) = self.into_value_and_skipped_binders();
395 assert_eq!(subst.len(interner), binders.len(interner));
396 value.subst_bound_vars(subst)
397 }
398}
399
400impl<T: std::fmt::Debug> std::fmt::Debug for Binders<T> {
401 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
402 let Binders { ref binders, ref value } = *self;
403 write!(fmt, "for{:?} ", binders.inner_debug(&Interner))?;
404 std::fmt::Debug::fmt(value, fmt)
405 }
406}
407
408/// A trait with type parameters. This includes the `Self`, so this represents a concrete type implementing the trait.
409#[derive(Clone, PartialEq, Eq, Debug, Hash)]
410pub struct TraitRef {
411 pub trait_id: ChalkTraitId,
412 pub substitution: Substitution,
413}
414
415impl TraitRef {
416 pub fn self_type_parameter(&self, interner: &Interner) -> &Ty {
417 &self.substitution.at(interner, 0).assert_ty_ref(interner)
418 }
419}
420
421/// Like `generics::WherePredicate`, but with resolved types: A condition on the
422/// parameters of a generic item.
423#[derive(Debug, Clone, PartialEq, Eq, Hash)]
424pub enum WhereClause {
425 /// The given trait needs to be implemented for its type parameters.
426 Implemented(TraitRef),
427 /// An associated type bindings like in `Iterator<Item = T>`.
428 AliasEq(AliasEq),
429}
430
431pub type QuantifiedWhereClause = Binders<WhereClause>;
432
433#[derive(Debug, Clone, PartialEq, Eq, Hash)]
434pub struct QuantifiedWhereClauses(Arc<[QuantifiedWhereClause]>);
435
436impl QuantifiedWhereClauses {
437 pub fn from_iter(
438 _interner: &Interner,
439 elements: impl IntoIterator<Item = QuantifiedWhereClause>,
440 ) -> Self {
441 QuantifiedWhereClauses(elements.into_iter().collect())
442 }
443
444 pub fn interned(&self) -> &Arc<[QuantifiedWhereClause]> {
445 &self.0
446 }
447
448 pub fn interned_mut(&mut self) -> &mut Arc<[QuantifiedWhereClause]> {
449 &mut self.0
450 }
451}
452
453/// Basically a claim (currently not validated / checked) that the contained
454/// type / trait ref contains no inference variables; any inference variables it
455/// contained have been replaced by bound variables, and `kinds` tells us how
456/// many there are and whether they were normal or float/int variables. This is
457/// used to erase irrelevant differences between types before using them in
458/// queries.
459#[derive(Debug, Clone, PartialEq, Eq, Hash)]
460pub struct Canonical<T> {
461 pub value: T,
462 pub binders: CanonicalVarKinds,
463}
464
465/// Something (usually a goal), along with an environment.
466#[derive(Clone, Debug, PartialEq, Eq, Hash)]
467pub struct InEnvironment<T> {
468 pub environment: chalk_ir::Environment<Interner>,
469 pub goal: T,
470}
471
472impl<T> InEnvironment<T> {
473 pub fn new(environment: chalk_ir::Environment<Interner>, value: T) -> InEnvironment<T> {
474 InEnvironment { environment, goal: value }
475 }
476}
477
478/// Something that needs to be proven (by Chalk) during type checking, e.g. that
479/// a certain type implements a certain trait. Proving the Obligation might
480/// result in additional information about inference variables.
481#[derive(Clone, Debug, PartialEq, Eq, Hash)]
482pub enum DomainGoal {
483 Holds(WhereClause),
484}
485
486#[derive(Clone, Debug, PartialEq, Eq, Hash)]
487pub struct AliasEq {
488 pub alias: AliasTy,
489 pub ty: Ty,
490}
491
492#[derive(Clone, Debug, PartialEq, Eq)]
493pub struct ConstrainedSubst {
494 pub subst: Substitution,
495}
496
497#[derive(Clone, Debug, PartialEq, Eq)]
498/// A (possible) solution for a proposed goal.
499pub enum Solution {
500 /// The goal indeed holds, and there is a unique value for all existential
501 /// variables.
502 Unique(Canonical<ConstrainedSubst>),
503
504 /// The goal may be provable in multiple ways, but regardless we may have some guidance
505 /// for type inference. In this case, we don't return any lifetime
506 /// constraints, since we have not "committed" to any particular solution
507 /// yet.
508 Ambig(Guidance),
509}
510
511#[derive(Clone, Debug, PartialEq, Eq)]
512/// When a goal holds ambiguously (e.g., because there are multiple possible
513/// solutions), we issue a set of *guidance* back to type inference.
514pub enum Guidance {
515 /// The existential variables *must* have the given values if the goal is
516 /// ever to hold, but that alone isn't enough to guarantee the goal will
517 /// actually hold.
518 Definite(Canonical<Substitution>),
519
520 /// There are multiple plausible values for the existentials, but the ones
521 /// here are suggested as the preferred choice heuristically. These should
522 /// be used for inference fallback only.
523 Suggested(Canonical<Substitution>),
524
525 /// There's no useful information to feed back to type inference
526 Unknown,
527}
528
529/// The kinds of placeholders we need during type inference. There's separate
530/// values for general types, and for integer and float variables. The latter
531/// two are used for inference of literal values (e.g. `100` could be one of
532/// several integer types).
533#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
534pub struct InferenceVar {
535 index: u32,
536}
537
538impl From<u32> for InferenceVar {
539 fn from(index: u32) -> InferenceVar {
540 InferenceVar { index }
541 }
542}
543
544impl InferenceVar {
545 /// Gets the underlying index value.
546 pub fn index(self) -> u32 {
547 self.index
548 }
549}
diff --git a/crates/hir_ty/src/utils.rs b/crates/hir_ty/src/utils.rs
index 0a424f607..5f6cb052a 100644
--- a/crates/hir_ty/src/utils.rs
+++ b/crates/hir_ty/src/utils.rs
@@ -1,8 +1,7 @@
1//! Helper functions for working with def, which don't need to be a separate 1//! Helper functions for working with def, which don't need to be a separate
2//! query, but can't be computed directly from `*Data` (ie, which need a `db`). 2//! query, but can't be computed directly from `*Data` (ie, which need a `db`).
3use std::sync::Arc;
4 3
5use chalk_ir::{BoundVar, DebruijnIndex}; 4use chalk_ir::{fold::Shift, BoundVar, DebruijnIndex};
6use hir_def::{ 5use hir_def::{
7 db::DefDatabase, 6 db::DefDatabase,
8 generics::{ 7 generics::{
@@ -16,7 +15,7 @@ use hir_def::{
16}; 15};
17use hir_expand::name::{name, Name}; 16use hir_expand::name::{name, Name};
18 17
19use crate::{db::HirDatabase, Interner, Substitution, TraitRef, TyKind, TypeWalk, WhereClause}; 18use crate::{db::HirDatabase, Interner, Substitution, TraitRef, TraitRefExt, TyKind, WhereClause};
20 19
21fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { 20fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> {
22 let resolver = trait_.resolver(db); 21 let resolver = trait_.resolver(db);
@@ -67,7 +66,7 @@ fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef) -> Vec<Tr
67 // FIXME: how to correctly handle higher-ranked bounds here? 66 // FIXME: how to correctly handle higher-ranked bounds here?
68 WhereClause::Implemented(tr) => Some( 67 WhereClause::Implemented(tr) => Some(
69 tr.clone() 68 tr.clone()
70 .shifted_out_to(DebruijnIndex::ONE) 69 .shifted_out_to(&Interner, DebruijnIndex::ONE)
71 .expect("FIXME unexpected higher-ranked trait bound"), 70 .expect("FIXME unexpected higher-ranked trait bound"),
72 ), 71 ),
73 _ => None, 72 _ => None,
@@ -135,15 +134,6 @@ pub(super) fn associated_type_by_name_including_super_traits(
135 }) 134 })
136} 135}
137 136
138/// Helper for mutating `Arc<[T]>` (i.e. `Arc::make_mut` for Arc slices).
139/// The underlying values are cloned if there are other strong references.
140pub(crate) fn make_mut_slice<T: Clone>(a: &mut Arc<[T]>) -> &mut [T] {
141 if Arc::get_mut(a).is_none() {
142 *a = a.iter().cloned().collect();
143 }
144 Arc::get_mut(a).unwrap()
145}
146
147pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics { 137pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics {
148 let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def))); 138 let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def)));
149 Generics { def, params: db.generic_params(def), parent_generics } 139 Generics { def, params: db.generic_params(def), parent_generics }
diff --git a/crates/hir_ty/src/walk.rs b/crates/hir_ty/src/walk.rs
index 91116dcda..6ef1d5336 100644
--- a/crates/hir_ty/src/walk.rs
+++ b/crates/hir_ty/src/walk.rs
@@ -1,138 +1,17 @@
1//! The `TypeWalk` trait (probably to be replaced by Chalk's `Fold` and 1//! The `TypeWalk` trait (probably to be replaced by Chalk's `Fold` and
2//! `Visit`). 2//! `Visit`).
3 3
4use std::mem; 4use chalk_ir::interner::HasInterner;
5
6use chalk_ir::DebruijnIndex;
7 5
8use crate::{ 6use crate::{
9 utils::make_mut_slice, AliasEq, AliasTy, Binders, CallableSig, FnSubst, GenericArg, 7 AliasEq, AliasTy, Binders, CallableSig, FnSubst, GenericArg, GenericArgData, Interner,
10 GenericArgData, Interner, OpaqueTy, ProjectionTy, Substitution, TraitRef, Ty, TyKind, 8 OpaqueTy, ProjectionTy, Substitution, TraitRef, Ty, TyKind, WhereClause,
11 WhereClause,
12}; 9};
13 10
14/// This allows walking structures that contain types to do something with those 11/// This allows walking structures that contain types to do something with those
15/// types, similar to Chalk's `Fold` trait. 12/// types, similar to Chalk's `Fold` trait.
16pub trait TypeWalk { 13pub trait TypeWalk {
17 fn walk(&self, f: &mut impl FnMut(&Ty)); 14 fn walk(&self, f: &mut impl FnMut(&Ty));
18 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
19 self.walk_mut_binders(&mut |ty, _binders| f(ty), DebruijnIndex::INNERMOST);
20 }
21 /// Walk the type, counting entered binders.
22 ///
23 /// `TyKind::Bound` variables use DeBruijn indexing, which means that 0 refers
24 /// to the innermost binder, 1 to the next, etc.. So when we want to
25 /// substitute a certain bound variable, we can't just walk the whole type
26 /// and blindly replace each instance of a certain index; when we 'enter'
27 /// things that introduce new bound variables, we have to keep track of
28 /// that. Currently, the only thing that introduces bound variables on our
29 /// side are `TyKind::Dyn` and `TyKind::Opaque`, which each introduce a bound
30 /// variable for the self type.
31 fn walk_mut_binders(
32 &mut self,
33 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
34 binders: DebruijnIndex,
35 );
36
37 fn fold_binders(
38 mut self,
39 f: &mut impl FnMut(Ty, DebruijnIndex) -> Ty,
40 binders: DebruijnIndex,
41 ) -> Self
42 where
43 Self: Sized,
44 {
45 self.walk_mut_binders(
46 &mut |ty_mut, binders| {
47 let ty = mem::replace(ty_mut, TyKind::Error.intern(&Interner));
48 *ty_mut = f(ty, binders);
49 },
50 binders,
51 );
52 self
53 }
54
55 fn fold(mut self, f: &mut impl FnMut(Ty) -> Ty) -> Self
56 where
57 Self: Sized,
58 {
59 self.walk_mut(&mut |ty_mut| {
60 let ty = mem::replace(ty_mut, TyKind::Error.intern(&Interner));
61 *ty_mut = f(ty);
62 });
63 self
64 }
65
66 /// Substitutes `TyKind::Bound` vars with the given substitution.
67 fn subst_bound_vars(self, substs: &Substitution) -> Self
68 where
69 Self: Sized,
70 {
71 self.subst_bound_vars_at_depth(substs, DebruijnIndex::INNERMOST)
72 }
73
74 /// Substitutes `TyKind::Bound` vars with the given substitution.
75 fn subst_bound_vars_at_depth(mut self, substs: &Substitution, depth: DebruijnIndex) -> Self
76 where
77 Self: Sized,
78 {
79 self.walk_mut_binders(
80 &mut |ty, binders| {
81 if let &mut TyKind::BoundVar(bound) = ty.interned_mut() {
82 if bound.debruijn >= binders {
83 *ty = substs.interned()[bound.index]
84 .assert_ty_ref(&Interner)
85 .clone()
86 .shifted_in_from(binders);
87 }
88 }
89 },
90 depth,
91 );
92 self
93 }
94
95 fn shifted_in(self, _interner: &Interner) -> Self
96 where
97 Self: Sized,
98 {
99 self.shifted_in_from(DebruijnIndex::ONE)
100 }
101
102 /// Shifts up debruijn indices of `TyKind::Bound` vars by `n`.
103 fn shifted_in_from(self, n: DebruijnIndex) -> Self
104 where
105 Self: Sized,
106 {
107 self.fold_binders(
108 &mut |ty, binders| match ty.kind(&Interner) {
109 TyKind::BoundVar(bound) if bound.debruijn >= binders => {
110 TyKind::BoundVar(bound.shifted_in_from(n)).intern(&Interner)
111 }
112 _ => ty,
113 },
114 DebruijnIndex::INNERMOST,
115 )
116 }
117
118 /// Shifts debruijn indices of `TyKind::Bound` vars out (down) by `n`.
119 fn shifted_out_to(self, n: DebruijnIndex) -> Option<Self>
120 where
121 Self: Sized + std::fmt::Debug,
122 {
123 Some(self.fold_binders(
124 &mut |ty, binders| {
125 match ty.kind(&Interner) {
126 TyKind::BoundVar(bound) if bound.debruijn >= binders => {
127 TyKind::BoundVar(bound.shifted_out_to(n).unwrap_or(bound.clone()))
128 .intern(&Interner)
129 }
130 _ => ty,
131 }
132 },
133 DebruijnIndex::INNERMOST,
134 ))
135 }
136} 15}
137 16
138impl TypeWalk for Ty { 17impl TypeWalk for Ty {
@@ -174,45 +53,6 @@ impl TypeWalk for Ty {
174 } 53 }
175 f(self); 54 f(self);
176 } 55 }
177
178 fn walk_mut_binders(
179 &mut self,
180 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
181 binders: DebruijnIndex,
182 ) {
183 match self.interned_mut() {
184 TyKind::Alias(AliasTy::Projection(p_ty)) => {
185 p_ty.substitution.walk_mut_binders(f, binders);
186 }
187 TyKind::Dyn(dyn_ty) => {
188 for p in make_mut_slice(dyn_ty.bounds.skip_binders_mut().interned_mut()) {
189 p.walk_mut_binders(f, binders.shifted_in());
190 }
191 }
192 TyKind::Alias(AliasTy::Opaque(o_ty)) => {
193 o_ty.substitution.walk_mut_binders(f, binders);
194 }
195 TyKind::Slice(ty)
196 | TyKind::Array(ty, _)
197 | TyKind::Ref(_, _, ty)
198 | TyKind::Raw(_, ty) => {
199 ty.walk_mut_binders(f, binders);
200 }
201 TyKind::Function(fn_pointer) => {
202 fn_pointer.substitution.0.walk_mut_binders(f, binders.shifted_in());
203 }
204 TyKind::Adt(_, substs)
205 | TyKind::FnDef(_, substs)
206 | TyKind::Tuple(_, substs)
207 | TyKind::OpaqueType(_, substs)
208 | TyKind::AssociatedType(_, substs)
209 | TyKind::Closure(.., substs) => {
210 substs.walk_mut_binders(f, binders);
211 }
212 _ => {}
213 }
214 f(self, binders);
215 }
216} 56}
217 57
218impl<T: TypeWalk> TypeWalk for Vec<T> { 58impl<T: TypeWalk> TypeWalk for Vec<T> {
@@ -221,43 +61,18 @@ impl<T: TypeWalk> TypeWalk for Vec<T> {
221 t.walk(f); 61 t.walk(f);
222 } 62 }
223 } 63 }
224 fn walk_mut_binders(
225 &mut self,
226 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
227 binders: DebruijnIndex,
228 ) {
229 for t in self {
230 t.walk_mut_binders(f, binders);
231 }
232 }
233} 64}
234 65
235impl TypeWalk for OpaqueTy { 66impl TypeWalk for OpaqueTy {
236 fn walk(&self, f: &mut impl FnMut(&Ty)) { 67 fn walk(&self, f: &mut impl FnMut(&Ty)) {
237 self.substitution.walk(f); 68 self.substitution.walk(f);
238 } 69 }
239
240 fn walk_mut_binders(
241 &mut self,
242 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
243 binders: DebruijnIndex,
244 ) {
245 self.substitution.walk_mut_binders(f, binders);
246 }
247} 70}
248 71
249impl TypeWalk for ProjectionTy { 72impl TypeWalk for ProjectionTy {
250 fn walk(&self, f: &mut impl FnMut(&Ty)) { 73 fn walk(&self, f: &mut impl FnMut(&Ty)) {
251 self.substitution.walk(f); 74 self.substitution.walk(f);
252 } 75 }
253
254 fn walk_mut_binders(
255 &mut self,
256 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
257 binders: DebruijnIndex,
258 ) {
259 self.substitution.walk_mut_binders(f, binders);
260 }
261} 76}
262 77
263impl TypeWalk for AliasTy { 78impl TypeWalk for AliasTy {
@@ -267,17 +82,6 @@ impl TypeWalk for AliasTy {
267 AliasTy::Opaque(it) => it.walk(f), 82 AliasTy::Opaque(it) => it.walk(f),
268 } 83 }
269 } 84 }
270
271 fn walk_mut_binders(
272 &mut self,
273 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
274 binders: DebruijnIndex,
275 ) {
276 match self {
277 AliasTy::Projection(it) => it.walk_mut_binders(f, binders),
278 AliasTy::Opaque(it) => it.walk_mut_binders(f, binders),
279 }
280 }
281} 85}
282 86
283impl TypeWalk for GenericArg { 87impl TypeWalk for GenericArg {
@@ -286,18 +90,7 @@ impl TypeWalk for GenericArg {
286 GenericArgData::Ty(ty) => { 90 GenericArgData::Ty(ty) => {
287 ty.walk(f); 91 ty.walk(f);
288 } 92 }
289 } 93 _ => {}
290 }
291
292 fn walk_mut_binders(
293 &mut self,
294 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
295 binders: DebruijnIndex,
296 ) {
297 match self.interned_mut() {
298 GenericArgData::Ty(ty) => {
299 ty.walk_mut_binders(f, binders);
300 }
301 } 94 }
302 } 95 }
303} 96}
@@ -308,44 +101,18 @@ impl TypeWalk for Substitution {
308 t.walk(f); 101 t.walk(f);
309 } 102 }
310 } 103 }
311
312 fn walk_mut_binders(
313 &mut self,
314 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
315 binders: DebruijnIndex,
316 ) {
317 for t in self.interned_mut() {
318 t.walk_mut_binders(f, binders);
319 }
320 }
321} 104}
322 105
323impl<T: TypeWalk> TypeWalk for Binders<T> { 106impl<T: TypeWalk + HasInterner<Interner = Interner>> TypeWalk for Binders<T> {
324 fn walk(&self, f: &mut impl FnMut(&Ty)) { 107 fn walk(&self, f: &mut impl FnMut(&Ty)) {
325 self.skip_binders().walk(f); 108 self.skip_binders().walk(f);
326 } 109 }
327
328 fn walk_mut_binders(
329 &mut self,
330 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
331 binders: DebruijnIndex,
332 ) {
333 self.skip_binders_mut().walk_mut_binders(f, binders.shifted_in())
334 }
335} 110}
336 111
337impl TypeWalk for TraitRef { 112impl TypeWalk for TraitRef {
338 fn walk(&self, f: &mut impl FnMut(&Ty)) { 113 fn walk(&self, f: &mut impl FnMut(&Ty)) {
339 self.substitution.walk(f); 114 self.substitution.walk(f);
340 } 115 }
341
342 fn walk_mut_binders(
343 &mut self,
344 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
345 binders: DebruijnIndex,
346 ) {
347 self.substitution.walk_mut_binders(f, binders);
348 }
349} 116}
350 117
351impl TypeWalk for WhereClause { 118impl TypeWalk for WhereClause {
@@ -353,17 +120,7 @@ impl TypeWalk for WhereClause {
353 match self { 120 match self {
354 WhereClause::Implemented(trait_ref) => trait_ref.walk(f), 121 WhereClause::Implemented(trait_ref) => trait_ref.walk(f),
355 WhereClause::AliasEq(alias_eq) => alias_eq.walk(f), 122 WhereClause::AliasEq(alias_eq) => alias_eq.walk(f),
356 } 123 _ => {}
357 }
358
359 fn walk_mut_binders(
360 &mut self,
361 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
362 binders: DebruijnIndex,
363 ) {
364 match self {
365 WhereClause::Implemented(trait_ref) => trait_ref.walk_mut_binders(f, binders),
366 WhereClause::AliasEq(alias_eq) => alias_eq.walk_mut_binders(f, binders),
367 } 124 }
368 } 125 }
369} 126}
@@ -374,16 +131,6 @@ impl TypeWalk for CallableSig {
374 t.walk(f); 131 t.walk(f);
375 } 132 }
376 } 133 }
377
378 fn walk_mut_binders(
379 &mut self,
380 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
381 binders: DebruijnIndex,
382 ) {
383 for t in make_mut_slice(&mut self.params_and_return) {
384 t.walk_mut_binders(f, binders);
385 }
386 }
387} 134}
388 135
389impl TypeWalk for AliasEq { 136impl TypeWalk for AliasEq {
@@ -394,30 +141,10 @@ impl TypeWalk for AliasEq {
394 AliasTy::Opaque(opaque) => opaque.walk(f), 141 AliasTy::Opaque(opaque) => opaque.walk(f),
395 } 142 }
396 } 143 }
397
398 fn walk_mut_binders(
399 &mut self,
400 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
401 binders: DebruijnIndex,
402 ) {
403 self.ty.walk_mut_binders(f, binders);
404 match &mut self.alias {
405 AliasTy::Projection(projection_ty) => projection_ty.walk_mut_binders(f, binders),
406 AliasTy::Opaque(opaque) => opaque.walk_mut_binders(f, binders),
407 }
408 }
409} 144}
410 145
411impl TypeWalk for FnSubst { 146impl TypeWalk for FnSubst<Interner> {
412 fn walk(&self, f: &mut impl FnMut(&Ty)) { 147 fn walk(&self, f: &mut impl FnMut(&Ty)) {
413 self.0.walk(f) 148 self.0.walk(f)
414 } 149 }
415
416 fn walk_mut_binders(
417 &mut self,
418 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
419 binders: DebruijnIndex,
420 ) {
421 self.0.walk_mut_binders(f, binders)
422 }
423} 150}
diff --git a/crates/ide/src/folding_ranges.rs b/crates/ide/src/folding_ranges.rs
index 153726ce8..2b9ed123c 100644
--- a/crates/ide/src/folding_ranges.rs
+++ b/crates/ide/src/folding_ranges.rs
@@ -19,6 +19,7 @@ pub enum FoldKind {
19 Region, 19 Region,
20 Consts, 20 Consts,
21 Statics, 21 Statics,
22 Array,
22} 23}
23 24
24#[derive(Debug)] 25#[derive(Debug)]
@@ -119,6 +120,7 @@ fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
119 match kind { 120 match kind {
120 COMMENT => Some(FoldKind::Comment), 121 COMMENT => Some(FoldKind::Comment),
121 ARG_LIST | PARAM_LIST => Some(FoldKind::ArgList), 122 ARG_LIST | PARAM_LIST => Some(FoldKind::ArgList),
123 ARRAY_EXPR => Some(FoldKind::Array),
122 ASSOC_ITEM_LIST 124 ASSOC_ITEM_LIST
123 | RECORD_FIELD_LIST 125 | RECORD_FIELD_LIST
124 | RECORD_PAT_FIELD_LIST 126 | RECORD_PAT_FIELD_LIST
@@ -269,6 +271,7 @@ mod tests {
269 FoldKind::Region => "region", 271 FoldKind::Region => "region",
270 FoldKind::Consts => "consts", 272 FoldKind::Consts => "consts",
271 FoldKind::Statics => "statics", 273 FoldKind::Statics => "statics",
274 FoldKind::Array => "array",
272 }; 275 };
273 assert_eq!(kind, &attr.unwrap()); 276 assert_eq!(kind, &attr.unwrap());
274 } 277 }
@@ -465,6 +468,20 @@ fn foo<fold arglist>(
465 } 468 }
466 469
467 #[test] 470 #[test]
471 fn fold_multiline_array() {
472 check(
473 r#"
474const FOO: [usize; 4] = <fold array>[
475 1,
476 2,
477 3,
478 4,
479]</fold>;
480"#,
481 )
482 }
483
484 #[test]
468 fn fold_region() { 485 fn fold_region() {
469 check( 486 check(
470 r#" 487 r#"
diff --git a/crates/ide/src/typing.rs b/crates/ide/src/typing.rs
index 11408d445..1378048e5 100644
--- a/crates/ide/src/typing.rs
+++ b/crates/ide/src/typing.rs
@@ -22,18 +22,19 @@ use ide_db::{
22use syntax::{ 22use syntax::{
23 algo::find_node_at_offset, 23 algo::find_node_at_offset,
24 ast::{self, edit::IndentLevel, AstToken}, 24 ast::{self, edit::IndentLevel, AstToken},
25 AstNode, SourceFile, 25 AstNode, Parse, SourceFile,
26 SyntaxKind::{FIELD_EXPR, METHOD_CALL_EXPR}, 26 SyntaxKind::{FIELD_EXPR, METHOD_CALL_EXPR},
27 TextRange, TextSize, 27 TextRange, TextSize,
28}; 28};
29 29
30use text_edit::TextEdit; 30use text_edit::{Indel, TextEdit};
31 31
32use crate::SourceChange; 32use crate::SourceChange;
33 33
34pub(crate) use on_enter::on_enter; 34pub(crate) use on_enter::on_enter;
35 35
36pub(crate) const TRIGGER_CHARS: &str = ".=>"; 36// Don't forget to add new trigger characters to `server_capabilities` in `caps.rs`.
37pub(crate) const TRIGGER_CHARS: &str = ".=>{";
37 38
38// Feature: On Typing Assists 39// Feature: On Typing Assists
39// 40//
@@ -41,6 +42,7 @@ pub(crate) const TRIGGER_CHARS: &str = ".=>";
41// 42//
42// - typing `let =` tries to smartly add `;` if `=` is followed by an existing expression 43// - typing `let =` tries to smartly add `;` if `=` is followed by an existing expression
43// - typing `.` in a chain method call auto-indents 44// - typing `.` in a chain method call auto-indents
45// - typing `{` in front of an expression inserts a closing `}` after the expression
44// 46//
45// VS Code:: 47// VS Code::
46// 48//
@@ -57,28 +59,79 @@ pub(crate) fn on_char_typed(
57 position: FilePosition, 59 position: FilePosition,
58 char_typed: char, 60 char_typed: char,
59) -> Option<SourceChange> { 61) -> Option<SourceChange> {
60 assert!(TRIGGER_CHARS.contains(char_typed)); 62 if !stdx::always!(TRIGGER_CHARS.contains(char_typed)) {
61 let file = &db.parse(position.file_id).tree(); 63 return None;
62 assert_eq!(file.syntax().text().char_at(position.offset), Some(char_typed)); 64 }
65 let file = &db.parse(position.file_id);
66 if !stdx::always!(file.tree().syntax().text().char_at(position.offset) == Some(char_typed)) {
67 return None;
68 }
63 let edit = on_char_typed_inner(file, position.offset, char_typed)?; 69 let edit = on_char_typed_inner(file, position.offset, char_typed)?;
64 Some(SourceChange::from_text_edit(position.file_id, edit)) 70 Some(SourceChange::from_text_edit(position.file_id, edit))
65} 71}
66 72
67fn on_char_typed_inner(file: &SourceFile, offset: TextSize, char_typed: char) -> Option<TextEdit> { 73fn on_char_typed_inner(
68 assert!(TRIGGER_CHARS.contains(char_typed)); 74 file: &Parse<SourceFile>,
75 offset: TextSize,
76 char_typed: char,
77) -> Option<TextEdit> {
78 if !stdx::always!(TRIGGER_CHARS.contains(char_typed)) {
79 return None;
80 }
69 match char_typed { 81 match char_typed {
70 '.' => on_dot_typed(file, offset), 82 '.' => on_dot_typed(&file.tree(), offset),
71 '=' => on_eq_typed(file, offset), 83 '=' => on_eq_typed(&file.tree(), offset),
72 '>' => on_arrow_typed(file, offset), 84 '>' => on_arrow_typed(&file.tree(), offset),
85 '{' => on_opening_brace_typed(file, offset),
73 _ => unreachable!(), 86 _ => unreachable!(),
74 } 87 }
75} 88}
76 89
90/// Inserts a closing `}` when the user types an opening `{`, wrapping an existing expression in a
91/// block.
92fn on_opening_brace_typed(file: &Parse<SourceFile>, offset: TextSize) -> Option<TextEdit> {
93 if !stdx::always!(file.tree().syntax().text().char_at(offset) == Some('{')) {
94 return None;
95 }
96
97 let brace_token = file.tree().syntax().token_at_offset(offset).right_biased()?;
98
99 // Remove the `{` to get a better parse tree, and reparse
100 let file = file.reparse(&Indel::delete(brace_token.text_range()));
101
102 let mut expr: ast::Expr = find_node_at_offset(file.tree().syntax(), offset)?;
103 if expr.syntax().text_range().start() != offset {
104 return None;
105 }
106
107 // Enclose the outermost expression starting at `offset`
108 while let Some(parent) = expr.syntax().parent() {
109 if parent.text_range().start() != expr.syntax().text_range().start() {
110 break;
111 }
112
113 match ast::Expr::cast(parent) {
114 Some(parent) => expr = parent,
115 None => break,
116 }
117 }
118
119 // If it's a statement in a block, we don't know how many statements should be included
120 if ast::ExprStmt::can_cast(expr.syntax().parent()?.kind()) {
121 return None;
122 }
123
124 // Insert `}` right after the expression.
125 Some(TextEdit::insert(expr.syntax().text_range().end() + TextSize::of("{"), "}".to_string()))
126}
127
77/// Returns an edit which should be applied after `=` was typed. Primarily, 128/// Returns an edit which should be applied after `=` was typed. Primarily,
78/// this works when adding `let =`. 129/// this works when adding `let =`.
79// FIXME: use a snippet completion instead of this hack here. 130// FIXME: use a snippet completion instead of this hack here.
80fn on_eq_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> { 131fn on_eq_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
81 assert_eq!(file.syntax().text().char_at(offset), Some('=')); 132 if !stdx::always!(file.syntax().text().char_at(offset) == Some('=')) {
133 return None;
134 }
82 let let_stmt: ast::LetStmt = find_node_at_offset(file.syntax(), offset)?; 135 let let_stmt: ast::LetStmt = find_node_at_offset(file.syntax(), offset)?;
83 if let_stmt.semicolon_token().is_some() { 136 if let_stmt.semicolon_token().is_some() {
84 return None; 137 return None;
@@ -100,7 +153,9 @@ fn on_eq_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
100 153
101/// Returns an edit which should be applied when a dot ('.') is typed on a blank line, indenting the line appropriately. 154/// Returns an edit which should be applied when a dot ('.') is typed on a blank line, indenting the line appropriately.
102fn on_dot_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> { 155fn on_dot_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
103 assert_eq!(file.syntax().text().char_at(offset), Some('.')); 156 if !stdx::always!(file.syntax().text().char_at(offset) == Some('.')) {
157 return None;
158 }
104 let whitespace = 159 let whitespace =
105 file.syntax().token_at_offset(offset).left_biased().and_then(ast::Whitespace::cast)?; 160 file.syntax().token_at_offset(offset).left_biased().and_then(ast::Whitespace::cast)?;
106 161
@@ -129,7 +184,9 @@ fn on_dot_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
129/// Adds a space after an arrow when `fn foo() { ... }` is turned into `fn foo() -> { ... }` 184/// Adds a space after an arrow when `fn foo() { ... }` is turned into `fn foo() -> { ... }`
130fn on_arrow_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> { 185fn on_arrow_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
131 let file_text = file.syntax().text(); 186 let file_text = file.syntax().text();
132 assert_eq!(file_text.char_at(offset), Some('>')); 187 if !stdx::always!(file_text.char_at(offset) == Some('>')) {
188 return None;
189 }
133 let after_arrow = offset + TextSize::of('>'); 190 let after_arrow = offset + TextSize::of('>');
134 if file_text.char_at(after_arrow) != Some('{') { 191 if file_text.char_at(after_arrow) != Some('{') {
135 return None; 192 return None;
@@ -152,7 +209,7 @@ mod tests {
152 let edit = TextEdit::insert(offset, char_typed.to_string()); 209 let edit = TextEdit::insert(offset, char_typed.to_string());
153 edit.apply(&mut before); 210 edit.apply(&mut before);
154 let parse = SourceFile::parse(&before); 211 let parse = SourceFile::parse(&before);
155 on_char_typed_inner(&parse.tree(), offset, char_typed).map(|it| { 212 on_char_typed_inner(&parse, offset, char_typed).map(|it| {
156 it.apply(&mut before); 213 it.apply(&mut before);
157 before.to_string() 214 before.to_string()
158 }) 215 })
@@ -373,4 +430,85 @@ fn main() {
373 fn adds_space_after_return_type() { 430 fn adds_space_after_return_type() {
374 type_char('>', "fn foo() -$0{ 92 }", "fn foo() -> { 92 }") 431 type_char('>', "fn foo() -$0{ 92 }", "fn foo() -> { 92 }")
375 } 432 }
433
434 #[test]
435 fn adds_closing_brace() {
436 type_char(
437 '{',
438 r#"
439fn f() { match () { _ => $0() } }
440 "#,
441 r#"
442fn f() { match () { _ => {()} } }
443 "#,
444 );
445 type_char(
446 '{',
447 r#"
448fn f() { $0() }
449 "#,
450 r#"
451fn f() { {()} }
452 "#,
453 );
454 type_char(
455 '{',
456 r#"
457fn f() { let x = $0(); }
458 "#,
459 r#"
460fn f() { let x = {()}; }
461 "#,
462 );
463 type_char(
464 '{',
465 r#"
466fn f() { let x = $0a.b(); }
467 "#,
468 r#"
469fn f() { let x = {a.b()}; }
470 "#,
471 );
472 type_char(
473 '{',
474 r#"
475const S: () = $0();
476fn f() {}
477 "#,
478 r#"
479const S: () = {()};
480fn f() {}
481 "#,
482 );
483 type_char(
484 '{',
485 r#"
486const S: () = $0a.b();
487fn f() {}
488 "#,
489 r#"
490const S: () = {a.b()};
491fn f() {}
492 "#,
493 );
494 type_char(
495 '{',
496 r#"
497fn f() {
498 match x {
499 0 => $0(),
500 1 => (),
501 }
502}
503 "#,
504 r#"
505fn f() {
506 match x {
507 0 => {()},
508 1 => (),
509 }
510}
511 "#,
512 );
513 }
376} 514}
diff --git a/crates/ide_assists/src/handlers/remove_dbg.rs b/crates/ide_assists/src/handlers/remove_dbg.rs
index 6114091f2..2862cfa9c 100644
--- a/crates/ide_assists/src/handlers/remove_dbg.rs
+++ b/crates/ide_assists/src/handlers/remove_dbg.rs
@@ -1,5 +1,5 @@
1use syntax::{ 1use syntax::{
2 ast::{self, AstNode}, 2 ast::{self, AstNode, AstToken},
3 match_ast, SyntaxElement, TextRange, TextSize, T, 3 match_ast, SyntaxElement, TextRange, TextSize, T,
4}; 4};
5 5
@@ -24,7 +24,39 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
24 let macro_call = ctx.find_node_at_offset::<ast::MacroCall>()?; 24 let macro_call = ctx.find_node_at_offset::<ast::MacroCall>()?;
25 let new_contents = adjusted_macro_contents(&macro_call)?; 25 let new_contents = adjusted_macro_contents(&macro_call)?;
26 26
27 let macro_text_range = macro_call.syntax().text_range(); 27 let parent = macro_call.syntax().parent();
28
29 let macro_text_range = if let Some(it) = parent.as_ref() {
30 if new_contents.is_empty() {
31 match_ast! {
32 match it {
33 ast::BlockExpr(it) => {
34 macro_call.syntax()
35 .prev_sibling_or_token()
36 .and_then(whitespace_start)
37 .map(|start| TextRange::new(start, macro_call.syntax().text_range().end()))
38 .unwrap_or(macro_call.syntax().text_range())
39 },
40 ast::ExprStmt(it) => {
41 let start = it
42 .syntax()
43 .prev_sibling_or_token()
44 .and_then(whitespace_start)
45 .unwrap_or(it.syntax().text_range().start());
46 let end = it.syntax().text_range().end();
47
48 TextRange::new(start, end)
49 },
50 _ => macro_call.syntax().text_range()
51 }
52 }
53 } else {
54 macro_call.syntax().text_range()
55 }
56 } else {
57 macro_call.syntax().text_range()
58 };
59
28 let macro_end = if macro_call.semicolon_token().is_some() { 60 let macro_end = if macro_call.semicolon_token().is_some() {
29 macro_text_range.end() - TextSize::of(';') 61 macro_text_range.end() - TextSize::of(';')
30 } else { 62 } else {
@@ -36,11 +68,22 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
36 "Remove dbg!()", 68 "Remove dbg!()",
37 macro_text_range, 69 macro_text_range,
38 |builder| { 70 |builder| {
39 builder.replace(TextRange::new(macro_text_range.start(), macro_end), new_contents); 71 builder.replace(
72 TextRange::new(macro_text_range.start(), macro_end),
73 if new_contents.is_empty() && parent.and_then(ast::LetStmt::cast).is_some() {
74 ast::make::expr_unit().to_string()
75 } else {
76 new_contents
77 },
78 );
40 }, 79 },
41 ) 80 )
42} 81}
43 82
83fn whitespace_start(it: SyntaxElement) -> Option<TextSize> {
84 Some(it.into_token().and_then(ast::Whitespace::cast)?.syntax().text_range().start())
85}
86
44fn adjusted_macro_contents(macro_call: &ast::MacroCall) -> Option<String> { 87fn adjusted_macro_contents(macro_call: &ast::MacroCall) -> Option<String> {
45 let contents = get_valid_macrocall_contents(&macro_call, "dbg")?; 88 let contents = get_valid_macrocall_contents(&macro_call, "dbg")?;
46 let macro_text_with_brackets = macro_call.token_tree()?.syntax().text(); 89 let macro_text_with_brackets = macro_call.token_tree()?.syntax().text();
@@ -94,15 +137,11 @@ fn get_valid_macrocall_contents(
94 let mut contents_between_brackets = children_with_tokens.collect::<Vec<_>>(); 137 let mut contents_between_brackets = children_with_tokens.collect::<Vec<_>>();
95 let last_child = contents_between_brackets.pop()?; 138 let last_child = contents_between_brackets.pop()?;
96 139
97 if contents_between_brackets.is_empty() { 140 match (first_child.kind(), last_child.kind()) {
98 None 141 (T!['('], T![')']) | (T!['['], T![']']) | (T!['{'], T!['}']) => {
99 } else { 142 Some(contents_between_brackets)
100 match (first_child.kind(), last_child.kind()) {
101 (T!['('], T![')']) | (T!['['], T![']']) | (T!['{'], T!['}']) => {
102 Some(contents_between_brackets)
103 }
104 _ => None,
105 } 143 }
144 _ => None,
106 } 145 }
107} 146}
108 147
@@ -418,4 +457,48 @@ fn main() {
418}"#, 457}"#,
419 ); 458 );
420 } 459 }
460
461 #[test]
462 fn test_remove_empty_dbg() {
463 check_assist(remove_dbg, r#"fn foo() { $0dbg!(); }"#, r#"fn foo() { }"#);
464 check_assist(
465 remove_dbg,
466 r#"
467fn foo() {
468 $0dbg!();
469}
470"#,
471 r#"
472fn foo() {
473}
474"#,
475 );
476 check_assist(
477 remove_dbg,
478 r#"
479fn foo() {
480 let test = $0dbg!();
481}"#,
482 r#"
483fn foo() {
484 let test = ();
485}"#,
486 );
487 check_assist(
488 remove_dbg,
489 r#"
490fn foo() {
491 let t = {
492 println!("Hello, world");
493 $0dbg!()
494 };
495}"#,
496 r#"
497fn foo() {
498 let t = {
499 println!("Hello, world");
500 };
501}"#,
502 );
503 }
421} 504}
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml
index 3130785cc..0571a912c 100644
--- a/crates/rust-analyzer/Cargo.toml
+++ b/crates/rust-analyzer/Cargo.toml
@@ -22,7 +22,7 @@ env_logger = { version = "0.8.1", default-features = false }
22itertools = "0.10.0" 22itertools = "0.10.0"
23jod-thread = "0.1.0" 23jod-thread = "0.1.0"
24log = "0.4.8" 24log = "0.4.8"
25lsp-types = { version = "0.88.0", features = ["proposed"] } 25lsp-types = { version = "0.89.0", features = ["proposed"] }
26parking_lot = "0.11.0" 26parking_lot = "0.11.0"
27xflags = "0.2.1" 27xflags = "0.2.1"
28oorandom = "11.1.2" 28oorandom = "11.1.2"
diff --git a/crates/rust-analyzer/src/caps.rs b/crates/rust-analyzer/src/caps.rs
index 7a5bcb8c7..3c87782f2 100644
--- a/crates/rust-analyzer/src/caps.rs
+++ b/crates/rust-analyzer/src/caps.rs
@@ -57,7 +57,7 @@ pub fn server_capabilities(client_caps: &ClientCapabilities) -> ServerCapabiliti
57 document_range_formatting_provider: None, 57 document_range_formatting_provider: None,
58 document_on_type_formatting_provider: Some(DocumentOnTypeFormattingOptions { 58 document_on_type_formatting_provider: Some(DocumentOnTypeFormattingOptions {
59 first_trigger_character: "=".to_string(), 59 first_trigger_character: "=".to_string(),
60 more_trigger_character: Some(vec![".".to_string(), ">".to_string()]), 60 more_trigger_character: Some(vec![".".to_string(), ">".to_string(), "{".to_string()]),
61 }), 61 }),
62 selection_range_provider: Some(SelectionRangeProviderCapability::Simple(true)), 62 selection_range_provider: Some(SelectionRangeProviderCapability::Simple(true)),
63 folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)), 63 folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)),
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index 4d10a2ead..31d8c487b 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -231,7 +231,6 @@ pub(crate) fn handle_on_enter(
231 Ok(Some(edit)) 231 Ok(Some(edit))
232} 232}
233 233
234// Don't forget to add new trigger characters to `ServerCapabilities` in `caps.rs`.
235pub(crate) fn handle_on_type_formatting( 234pub(crate) fn handle_on_type_formatting(
236 snap: GlobalStateSnapshot, 235 snap: GlobalStateSnapshot,
237 params: lsp_types::DocumentOnTypeFormattingParams, 236 params: lsp_types::DocumentOnTypeFormattingParams,
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index c3820944b..2ac31d981 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -497,7 +497,8 @@ pub(crate) fn folding_range(
497 | FoldKind::Block 497 | FoldKind::Block
498 | FoldKind::ArgList 498 | FoldKind::ArgList
499 | FoldKind::Consts 499 | FoldKind::Consts
500 | FoldKind::Statics => None, 500 | FoldKind::Statics
501 | FoldKind::Array => None,
501 }; 502 };
502 503
503 let range = range(line_index, fold.range); 504 let range = range(line_index, fold.range);
diff --git a/docs/dev/architecture.md b/docs/dev/architecture.md
index 3ffd9e8cb..39edf9e19 100644
--- a/docs/dev/architecture.md
+++ b/docs/dev/architecture.md
@@ -139,7 +139,7 @@ If an AST method returns an `Option`, it *can* be `None` at runtime, even if thi
139### `crates/base_db` 139### `crates/base_db`
140 140
141We use the [salsa](https://github.com/salsa-rs/salsa) crate for incremental and on-demand computation. 141We use the [salsa](https://github.com/salsa-rs/salsa) crate for incremental and on-demand computation.
142Roughly, you can think of salsa as a key-value store, but it can also compute derived values using specified functions. 142Roughly, you can think of salsa as a key-value store, but it can also compute derived values using specified functions.
143The `base_db` crate provides basic infrastructure for interacting with salsa. 143The `base_db` crate provides basic infrastructure for interacting with salsa.
144Crucially, it defines most of the "input" queries: facts supplied by the client of the analyzer. 144Crucially, it defines most of the "input" queries: facts supplied by the client of the analyzer.
145Reading the docs of the `base_db::input` module should be useful: everything else is strictly derived from those inputs. 145Reading the docs of the `base_db::input` module should be useful: everything else is strictly derived from those inputs.
@@ -308,7 +308,7 @@ This sections talks about the things which are everywhere and nowhere in particu
308 308
309### Code generation 309### Code generation
310 310
311Some ]components in this repository are generated through automatic processes. 311Some components in this repository are generated through automatic processes.
312Generated code is updated automatically on `cargo test`. 312Generated code is updated automatically on `cargo test`.
313Generated code is generally committed to the git repository. 313Generated code is generally committed to the git repository.
314 314