diff options
Diffstat (limited to 'crates')
25 files changed, 821 insertions, 374 deletions
diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs index 559ea31a0..993772aac 100644 --- a/crates/hir/src/display.rs +++ b/crates/hir/src/display.rs | |||
@@ -13,7 +13,7 @@ use syntax::ast::{self, NameOwner}; | |||
13 | 13 | ||
14 | use crate::{ | 14 | use crate::{ |
15 | Adt, Const, ConstParam, Enum, Field, Function, GenericParam, HasVisibility, LifetimeParam, | 15 | Adt, Const, ConstParam, Enum, Field, Function, GenericParam, HasVisibility, LifetimeParam, |
16 | Module, Static, Struct, Substitution, Trait, Type, TypeAlias, TypeParam, Union, Variant, | 16 | Module, Static, Struct, Trait, TyBuilder, Type, TypeAlias, TypeParam, Union, Variant, |
17 | }; | 17 | }; |
18 | 18 | ||
19 | impl HirDisplay for Function { | 19 | impl HirDisplay for Function { |
@@ -234,7 +234,7 @@ impl HirDisplay for TypeParam { | |||
234 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | 234 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { |
235 | write!(f, "{}", self.name(f.db))?; | 235 | write!(f, "{}", self.name(f.db))?; |
236 | let bounds = f.db.generic_predicates_for_param(self.id); | 236 | let bounds = f.db.generic_predicates_for_param(self.id); |
237 | let substs = Substitution::type_params(f.db, self.id.parent); | 237 | let substs = TyBuilder::type_params_subst(f.db, self.id.parent); |
238 | let predicates = bounds.iter().cloned().map(|b| b.subst(&substs)).collect::<Vec<_>>(); | 238 | let predicates = bounds.iter().cloned().map(|b| b.subst(&substs)).collect::<Vec<_>>(); |
239 | if !(predicates.is_empty() || f.omit_verbose_types()) { | 239 | if !(predicates.is_empty() || f.omit_verbose_types()) { |
240 | write_bounds_like_dyn_trait_with_prefix(":", &predicates, f)?; | 240 | write_bounds_like_dyn_trait_with_prefix(":", &predicates, f)?; |
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index eb19e4b51..19901ed33 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -55,11 +55,10 @@ use hir_ty::{ | |||
55 | autoderef, could_unify, | 55 | autoderef, could_unify, |
56 | method_resolution::{self, TyFingerprint}, | 56 | method_resolution::{self, TyFingerprint}, |
57 | primitive::UintTy, | 57 | primitive::UintTy, |
58 | to_assoc_type_id, | ||
59 | traits::{FnTrait, Solution, SolutionVariables}, | 58 | traits::{FnTrait, Solution, SolutionVariables}, |
60 | AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, | 59 | AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, |
61 | DebruijnIndex, InEnvironment, Interner, ProjectionTy, QuantifiedWhereClause, Scalar, | 60 | DebruijnIndex, InEnvironment, Interner, QuantifiedWhereClause, Scalar, Substitution, |
62 | Substitution, TraitEnvironment, Ty, TyDefId, TyKind, TyVariableKind, WhereClause, | 61 | TraitEnvironment, Ty, TyBuilder, TyDefId, TyKind, TyVariableKind, WhereClause, |
63 | }; | 62 | }; |
64 | use itertools::Itertools; | 63 | use itertools::Itertools; |
65 | use rustc_hash::FxHashSet; | 64 | use rustc_hash::FxHashSet; |
@@ -515,7 +514,7 @@ impl Field { | |||
515 | VariantDef::Union(it) => it.id.into(), | 514 | VariantDef::Union(it) => it.id.into(), |
516 | VariantDef::Variant(it) => it.parent.id.into(), | 515 | VariantDef::Variant(it) => it.parent.id.into(), |
517 | }; | 516 | }; |
518 | let substs = Substitution::type_params(db, generic_def_id); | 517 | let substs = TyBuilder::type_params_subst(db, generic_def_id); |
519 | let ty = db.field_types(var_id)[self.id].clone().subst(&substs); | 518 | let ty = db.field_types(var_id)[self.id].clone().subst(&substs); |
520 | Type::new(db, self.parent.module(db).id.krate(), var_id, ty) | 519 | Type::new(db, self.parent.module(db).id.krate(), var_id, ty) |
521 | } | 520 | } |
@@ -1129,7 +1128,7 @@ pub struct BuiltinType { | |||
1129 | impl BuiltinType { | 1128 | impl BuiltinType { |
1130 | pub fn ty(self, db: &dyn HirDatabase, module: Module) -> Type { | 1129 | pub fn ty(self, db: &dyn HirDatabase, module: Module) -> Type { |
1131 | let resolver = module.id.resolver(db.upcast()); | 1130 | let resolver = module.id.resolver(db.upcast()); |
1132 | Type::new_with_resolver(db, &resolver, Ty::builtin(self.inner)) | 1131 | Type::new_with_resolver(db, &resolver, TyBuilder::builtin(self.inner)) |
1133 | .expect("crate not present in resolver") | 1132 | .expect("crate not present in resolver") |
1134 | } | 1133 | } |
1135 | 1134 | ||
@@ -1502,7 +1501,7 @@ impl TypeParam { | |||
1502 | let resolver = self.id.parent.resolver(db.upcast()); | 1501 | let resolver = self.id.parent.resolver(db.upcast()); |
1503 | let krate = self.id.parent.module(db.upcast()).krate(); | 1502 | let krate = self.id.parent.module(db.upcast()).krate(); |
1504 | let ty = params.get(local_idx)?.clone(); | 1503 | let ty = params.get(local_idx)?.clone(); |
1505 | let subst = Substitution::type_params(db, self.id.parent); | 1504 | let subst = TyBuilder::type_params_subst(db, self.id.parent); |
1506 | let ty = ty.subst(&subst.prefix(local_idx)); | 1505 | let ty = ty.subst(&subst.prefix(local_idx)); |
1507 | Some(Type::new_with_resolver_inner(db, krate, &resolver, ty)) | 1506 | Some(Type::new_with_resolver_inner(db, krate, &resolver, ty)) |
1508 | } | 1507 | } |
@@ -1703,10 +1702,9 @@ impl Type { | |||
1703 | fn from_def( | 1702 | fn from_def( |
1704 | db: &dyn HirDatabase, | 1703 | db: &dyn HirDatabase, |
1705 | krate: CrateId, | 1704 | krate: CrateId, |
1706 | def: impl HasResolver + Into<TyDefId> + Into<GenericDefId>, | 1705 | def: impl HasResolver + Into<TyDefId>, |
1707 | ) -> Type { | 1706 | ) -> Type { |
1708 | let substs = Substitution::build_for_def(db, def).fill_with_unknown().build(); | 1707 | let ty = TyBuilder::def_ty(db, def.into()).fill_with_unknown().build(); |
1709 | let ty = db.ty(def.into()).subst(&substs); | ||
1710 | Type::new(db, krate, def, ty) | 1708 | Type::new(db, krate, def, ty) |
1711 | } | 1709 | } |
1712 | 1710 | ||
@@ -1785,13 +1783,10 @@ impl Type { | |||
1785 | } | 1783 | } |
1786 | 1784 | ||
1787 | pub fn impls_trait(&self, db: &dyn HirDatabase, trait_: Trait, args: &[Type]) -> bool { | 1785 | pub fn impls_trait(&self, db: &dyn HirDatabase, trait_: Trait, args: &[Type]) -> bool { |
1788 | let trait_ref = hir_ty::TraitRef { | 1786 | let trait_ref = TyBuilder::trait_ref(db, trait_.id) |
1789 | trait_id: hir_ty::to_chalk_trait_id(trait_.id), | 1787 | .push(self.ty.clone()) |
1790 | substitution: Substitution::build_for_def(db, trait_.id) | 1788 | .fill(args.iter().map(|t| t.ty.clone())) |
1791 | .push(self.ty.clone()) | 1789 | .build(); |
1792 | .fill(args.iter().map(|t| t.ty.clone())) | ||
1793 | .build(), | ||
1794 | }; | ||
1795 | 1790 | ||
1796 | let goal = Canonical { | 1791 | let goal = Canonical { |
1797 | value: hir_ty::InEnvironment::new(self.env.env.clone(), trait_ref.cast(&Interner)), | 1792 | value: hir_ty::InEnvironment::new(self.env.env.clone(), trait_ref.cast(&Interner)), |
@@ -1804,11 +1799,10 @@ impl Type { | |||
1804 | pub fn normalize_trait_assoc_type( | 1799 | pub fn normalize_trait_assoc_type( |
1805 | &self, | 1800 | &self, |
1806 | db: &dyn HirDatabase, | 1801 | db: &dyn HirDatabase, |
1807 | trait_: Trait, | ||
1808 | args: &[Type], | 1802 | args: &[Type], |
1809 | alias: TypeAlias, | 1803 | alias: TypeAlias, |
1810 | ) -> Option<Type> { | 1804 | ) -> Option<Type> { |
1811 | let subst = Substitution::build_for_def(db, trait_.id) | 1805 | let projection = TyBuilder::assoc_type_projection(db, alias.id) |
1812 | .push(self.ty.clone()) | 1806 | .push(self.ty.clone()) |
1813 | .fill(args.iter().map(|t| t.ty.clone())) | 1807 | .fill(args.iter().map(|t| t.ty.clone())) |
1814 | .build(); | 1808 | .build(); |
@@ -1816,10 +1810,7 @@ impl Type { | |||
1816 | InEnvironment::new( | 1810 | InEnvironment::new( |
1817 | self.env.env.clone(), | 1811 | self.env.env.clone(), |
1818 | AliasEq { | 1812 | AliasEq { |
1819 | alias: AliasTy::Projection(ProjectionTy { | 1813 | alias: AliasTy::Projection(projection), |
1820 | associated_ty_id: to_assoc_type_id(alias.id), | ||
1821 | substitution: subst, | ||
1822 | }), | ||
1823 | ty: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)) | 1814 | ty: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)) |
1824 | .intern(&Interner), | 1815 | .intern(&Interner), |
1825 | } | 1816 | } |
diff --git a/crates/hir_ty/src/autoderef.rs b/crates/hir_ty/src/autoderef.rs index c859f9491..70c56cc45 100644 --- a/crates/hir_ty/src/autoderef.rs +++ b/crates/hir_ty/src/autoderef.rs | |||
@@ -13,11 +13,9 @@ use log::{info, warn}; | |||
13 | 13 | ||
14 | use crate::{ | 14 | use crate::{ |
15 | db::HirDatabase, | 15 | db::HirDatabase, |
16 | to_assoc_type_id, to_chalk_trait_id, | ||
17 | traits::{InEnvironment, Solution}, | 16 | traits::{InEnvironment, Solution}, |
18 | utils::generics, | 17 | AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds, DebruijnIndex, Interner, Ty, |
19 | AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds, DebruijnIndex, Interner, | 18 | TyBuilder, TyKind, |
20 | ProjectionTy, Substitution, TraitRef, Ty, TyKind, | ||
21 | }; | 19 | }; |
22 | 20 | ||
23 | const AUTODEREF_RECURSION_LIMIT: usize = 10; | 21 | const AUTODEREF_RECURSION_LIMIT: usize = 10; |
@@ -57,21 +55,20 @@ fn deref_by_trait( | |||
57 | }; | 55 | }; |
58 | let target = db.trait_data(deref_trait).associated_type_by_name(&name![Target])?; | 56 | let target = db.trait_data(deref_trait).associated_type_by_name(&name![Target])?; |
59 | 57 | ||
60 | let generic_params = generics(db.upcast(), target.into()); | 58 | let projection = { |
61 | if generic_params.len() != 1 { | 59 | let b = TyBuilder::assoc_type_projection(db, target); |
62 | // the Target type + Deref trait should only have one generic parameter, | 60 | if b.remaining() != 1 { |
63 | // namely Deref's Self type | 61 | // the Target type + Deref trait should only have one generic parameter, |
64 | return None; | 62 | // namely Deref's Self type |
65 | } | 63 | return None; |
64 | } | ||
65 | b.push(ty.goal.value.clone()).build() | ||
66 | }; | ||
66 | 67 | ||
67 | // FIXME make the Canonical / bound var handling nicer | 68 | // FIXME make the Canonical / bound var handling nicer |
68 | 69 | ||
69 | let parameters = | ||
70 | Substitution::build_for_generics(&generic_params).push(ty.goal.value.clone()).build(); | ||
71 | |||
72 | // Check that the type implements Deref at all | 70 | // Check that the type implements Deref at all |
73 | let trait_ref = | 71 | let trait_ref = projection.trait_ref(db); |
74 | TraitRef { trait_id: to_chalk_trait_id(deref_trait), substitution: parameters.clone() }; | ||
75 | let implements_goal = Canonical { | 72 | let implements_goal = Canonical { |
76 | binders: ty.goal.binders.clone(), | 73 | binders: ty.goal.binders.clone(), |
77 | value: InEnvironment { | 74 | value: InEnvironment { |
@@ -84,11 +81,8 @@ fn deref_by_trait( | |||
84 | } | 81 | } |
85 | 82 | ||
86 | // Now do the assoc type projection | 83 | // Now do the assoc type projection |
87 | let projection = AliasEq { | 84 | let alias_eq = AliasEq { |
88 | alias: AliasTy::Projection(ProjectionTy { | 85 | alias: AliasTy::Projection(projection), |
89 | associated_ty_id: to_assoc_type_id(target), | ||
90 | substitution: parameters, | ||
91 | }), | ||
92 | ty: TyKind::BoundVar(BoundVar::new( | 86 | ty: TyKind::BoundVar(BoundVar::new( |
93 | DebruijnIndex::INNERMOST, | 87 | DebruijnIndex::INNERMOST, |
94 | ty.goal.binders.len(&Interner), | 88 | ty.goal.binders.len(&Interner), |
@@ -96,9 +90,7 @@ fn deref_by_trait( | |||
96 | .intern(&Interner), | 90 | .intern(&Interner), |
97 | }; | 91 | }; |
98 | 92 | ||
99 | let obligation = projection.cast(&Interner); | 93 | let in_env = InEnvironment { goal: alias_eq.cast(&Interner), environment: ty.environment }; |
100 | |||
101 | let in_env = InEnvironment { goal: obligation, environment: ty.environment }; | ||
102 | 94 | ||
103 | let canonical = Canonical { | 95 | let canonical = Canonical { |
104 | value: in_env, | 96 | value: in_env, |
diff --git a/crates/hir_ty/src/builder.rs b/crates/hir_ty/src/builder.rs new file mode 100644 index 000000000..4a9a8058f --- /dev/null +++ b/crates/hir_ty/src/builder.rs | |||
@@ -0,0 +1,219 @@ | |||
1 | //! `TyBuilder`, a helper for building instances of `Ty` and related types. | ||
2 | |||
3 | use std::iter; | ||
4 | |||
5 | use chalk_ir::{ | ||
6 | cast::{Cast, CastTo, Caster}, | ||
7 | interner::HasInterner, | ||
8 | AdtId, BoundVar, DebruijnIndex, Safety, Scalar, | ||
9 | }; | ||
10 | use hir_def::{builtin_type::BuiltinType, GenericDefId, TraitId, TypeAliasId}; | ||
11 | use smallvec::SmallVec; | ||
12 | |||
13 | use crate::{ | ||
14 | db::HirDatabase, primitive, to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders, | ||
15 | CallableSig, FnPointer, FnSig, GenericArg, Interner, ProjectionTy, Substitution, TraitRef, Ty, | ||
16 | TyDefId, TyKind, TypeWalk, ValueTyDefId, | ||
17 | }; | ||
18 | |||
19 | /// This is a builder for `Ty` or anything that needs a `Substitution`. | ||
20 | pub struct TyBuilder<D> { | ||
21 | /// The `data` field is used to keep track of what we're building (e.g. an | ||
22 | /// ADT, a `TraitRef`, ...). | ||
23 | data: D, | ||
24 | vec: SmallVec<[GenericArg; 2]>, | ||
25 | param_count: usize, | ||
26 | } | ||
27 | |||
28 | impl<D> TyBuilder<D> { | ||
29 | fn new(data: D, param_count: usize) -> TyBuilder<D> { | ||
30 | TyBuilder { data, param_count, vec: SmallVec::with_capacity(param_count) } | ||
31 | } | ||
32 | |||
33 | fn build_internal(self) -> (D, Substitution) { | ||
34 | 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(self.vec); | ||
37 | (self.data, subst) | ||
38 | } | ||
39 | |||
40 | pub fn push(mut self, arg: impl CastTo<GenericArg>) -> Self { | ||
41 | self.vec.push(arg.cast(&Interner)); | ||
42 | self | ||
43 | } | ||
44 | |||
45 | pub fn remaining(&self) -> usize { | ||
46 | self.param_count - self.vec.len() | ||
47 | } | ||
48 | |||
49 | pub fn fill_with_bound_vars(self, debruijn: DebruijnIndex, starting_from: usize) -> Self { | ||
50 | self.fill( | ||
51 | (starting_from..) | ||
52 | .map(|idx| TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(&Interner)), | ||
53 | ) | ||
54 | } | ||
55 | |||
56 | pub fn fill_with_unknown(self) -> Self { | ||
57 | self.fill(iter::repeat(TyKind::Unknown.intern(&Interner))) | ||
58 | } | ||
59 | |||
60 | pub fn fill(mut self, filler: impl Iterator<Item = impl CastTo<GenericArg>>) -> Self { | ||
61 | self.vec.extend(filler.take(self.remaining()).casted(&Interner)); | ||
62 | assert_eq!(self.remaining(), 0); | ||
63 | self | ||
64 | } | ||
65 | |||
66 | pub fn use_parent_substs(mut self, parent_substs: &Substitution) -> Self { | ||
67 | assert!(self.vec.is_empty()); | ||
68 | assert!(parent_substs.len(&Interner) <= self.param_count); | ||
69 | self.vec.extend(parent_substs.iter(&Interner).cloned()); | ||
70 | self | ||
71 | } | ||
72 | } | ||
73 | |||
74 | impl TyBuilder<()> { | ||
75 | pub fn unit() -> Ty { | ||
76 | TyKind::Tuple(0, Substitution::empty(&Interner)).intern(&Interner) | ||
77 | } | ||
78 | |||
79 | pub fn fn_ptr(sig: CallableSig) -> Ty { | ||
80 | TyKind::Function(FnPointer { | ||
81 | num_args: sig.params().len(), | ||
82 | sig: FnSig { abi: (), safety: Safety::Safe, variadic: sig.is_varargs }, | ||
83 | substs: Substitution::from_iter(&Interner, sig.params_and_return.iter().cloned()), | ||
84 | }) | ||
85 | .intern(&Interner) | ||
86 | } | ||
87 | |||
88 | pub fn builtin(builtin: BuiltinType) -> Ty { | ||
89 | match builtin { | ||
90 | BuiltinType::Char => TyKind::Scalar(Scalar::Char).intern(&Interner), | ||
91 | BuiltinType::Bool => TyKind::Scalar(Scalar::Bool).intern(&Interner), | ||
92 | BuiltinType::Str => TyKind::Str.intern(&Interner), | ||
93 | BuiltinType::Int(t) => { | ||
94 | TyKind::Scalar(Scalar::Int(primitive::int_ty_from_builtin(t))).intern(&Interner) | ||
95 | } | ||
96 | BuiltinType::Uint(t) => { | ||
97 | TyKind::Scalar(Scalar::Uint(primitive::uint_ty_from_builtin(t))).intern(&Interner) | ||
98 | } | ||
99 | BuiltinType::Float(t) => { | ||
100 | TyKind::Scalar(Scalar::Float(primitive::float_ty_from_builtin(t))).intern(&Interner) | ||
101 | } | ||
102 | } | ||
103 | } | ||
104 | |||
105 | pub fn type_params_subst(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> Substitution { | ||
106 | let params = generics(db.upcast(), def.into()); | ||
107 | params.type_params_subst(db) | ||
108 | } | ||
109 | |||
110 | pub fn subst_for_def(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> TyBuilder<()> { | ||
111 | let def = def.into(); | ||
112 | let params = generics(db.upcast(), def); | ||
113 | let param_count = params.len(); | ||
114 | TyBuilder::new((), param_count) | ||
115 | } | ||
116 | |||
117 | pub fn build(self) -> Substitution { | ||
118 | let ((), subst) = self.build_internal(); | ||
119 | subst | ||
120 | } | ||
121 | } | ||
122 | |||
123 | impl TyBuilder<hir_def::AdtId> { | ||
124 | pub fn adt(db: &dyn HirDatabase, adt: hir_def::AdtId) -> TyBuilder<hir_def::AdtId> { | ||
125 | let generics = generics(db.upcast(), adt.into()); | ||
126 | let param_count = generics.len(); | ||
127 | TyBuilder::new(adt, param_count) | ||
128 | } | ||
129 | |||
130 | pub fn fill_with_defaults( | ||
131 | mut self, | ||
132 | db: &dyn HirDatabase, | ||
133 | mut fallback: impl FnMut() -> Ty, | ||
134 | ) -> Self { | ||
135 | let defaults = db.generic_defaults(self.data.into()); | ||
136 | for default_ty in defaults.iter().skip(self.vec.len()) { | ||
137 | if default_ty.skip_binders().is_unknown() { | ||
138 | self.vec.push(fallback().cast(&Interner)); | ||
139 | } else { | ||
140 | // each default can depend on the previous parameters | ||
141 | let subst_so_far = Substitution(self.vec.clone()); | ||
142 | self.vec.push(default_ty.clone().subst(&subst_so_far).cast(&Interner)); | ||
143 | } | ||
144 | } | ||
145 | self | ||
146 | } | ||
147 | |||
148 | pub fn build(self) -> Ty { | ||
149 | let (adt, subst) = self.build_internal(); | ||
150 | TyKind::Adt(AdtId(adt), subst).intern(&Interner) | ||
151 | } | ||
152 | } | ||
153 | |||
154 | pub struct Tuple(usize); | ||
155 | impl TyBuilder<Tuple> { | ||
156 | pub fn tuple(size: usize) -> TyBuilder<Tuple> { | ||
157 | TyBuilder::new(Tuple(size), size) | ||
158 | } | ||
159 | |||
160 | pub fn build(self) -> Ty { | ||
161 | let (Tuple(size), subst) = self.build_internal(); | ||
162 | TyKind::Tuple(size, subst).intern(&Interner) | ||
163 | } | ||
164 | } | ||
165 | |||
166 | impl TyBuilder<TraitId> { | ||
167 | pub fn trait_ref(db: &dyn HirDatabase, trait_id: TraitId) -> TyBuilder<TraitId> { | ||
168 | let generics = generics(db.upcast(), trait_id.into()); | ||
169 | let param_count = generics.len(); | ||
170 | TyBuilder::new(trait_id, param_count) | ||
171 | } | ||
172 | |||
173 | pub fn build(self) -> TraitRef { | ||
174 | let (trait_id, substitution) = self.build_internal(); | ||
175 | TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution } | ||
176 | } | ||
177 | } | ||
178 | |||
179 | impl TyBuilder<TypeAliasId> { | ||
180 | pub fn assoc_type_projection( | ||
181 | db: &dyn HirDatabase, | ||
182 | type_alias: TypeAliasId, | ||
183 | ) -> TyBuilder<TypeAliasId> { | ||
184 | let generics = generics(db.upcast(), type_alias.into()); | ||
185 | let param_count = generics.len(); | ||
186 | TyBuilder::new(type_alias, param_count) | ||
187 | } | ||
188 | |||
189 | pub fn build(self) -> ProjectionTy { | ||
190 | let (type_alias, substitution) = self.build_internal(); | ||
191 | ProjectionTy { associated_ty_id: to_assoc_type_id(type_alias), substitution } | ||
192 | } | ||
193 | } | ||
194 | |||
195 | impl<T: TypeWalk + HasInterner<Interner = Interner>> TyBuilder<Binders<T>> { | ||
196 | fn subst_binders(b: Binders<T>) -> Self { | ||
197 | let param_count = b.num_binders; | ||
198 | TyBuilder::new(b, param_count) | ||
199 | } | ||
200 | |||
201 | pub fn build(self) -> T { | ||
202 | let (b, subst) = self.build_internal(); | ||
203 | b.subst(&subst) | ||
204 | } | ||
205 | } | ||
206 | |||
207 | impl TyBuilder<Binders<Ty>> { | ||
208 | pub fn def_ty(db: &dyn HirDatabase, def: TyDefId) -> TyBuilder<Binders<Ty>> { | ||
209 | TyBuilder::subst_binders(db.ty(def.into())) | ||
210 | } | ||
211 | |||
212 | pub fn impl_self_ty(db: &dyn HirDatabase, def: hir_def::ImplId) -> TyBuilder<Binders<Ty>> { | ||
213 | TyBuilder::subst_binders(db.impl_self_ty(def)) | ||
214 | } | ||
215 | |||
216 | pub fn value_ty(db: &dyn HirDatabase, def: ValueTyDefId) -> TyBuilder<Binders<Ty>> { | ||
217 | TyBuilder::subst_binders(db.value_ty(def)) | ||
218 | } | ||
219 | } | ||
diff --git a/crates/hir_ty/src/chalk_ext.rs b/crates/hir_ty/src/chalk_ext.rs new file mode 100644 index 000000000..b7463366b --- /dev/null +++ b/crates/hir_ty/src/chalk_ext.rs | |||
@@ -0,0 +1,13 @@ | |||
1 | //! Various extensions traits for Chalk types. | ||
2 | |||
3 | use crate::{Interner, Ty, TyKind}; | ||
4 | |||
5 | pub trait TyExt { | ||
6 | fn is_unit(&self) -> bool; | ||
7 | } | ||
8 | |||
9 | impl TyExt for Ty { | ||
10 | fn is_unit(&self) -> bool { | ||
11 | matches!(self.kind(&Interner), TyKind::Tuple(0, _)) | ||
12 | } | ||
13 | } | ||
diff --git a/crates/hir_ty/src/diagnostics/expr.rs b/crates/hir_ty/src/diagnostics/expr.rs index ad1259b34..8169b759f 100644 --- a/crates/hir_ty/src/diagnostics/expr.rs +++ b/crates/hir_ty/src/diagnostics/expr.rs | |||
@@ -15,7 +15,7 @@ use crate::{ | |||
15 | MissingPatFields, RemoveThisSemicolon, | 15 | MissingPatFields, RemoveThisSemicolon, |
16 | }, | 16 | }, |
17 | utils::variant_data, | 17 | utils::variant_data, |
18 | AdtId, InferenceResult, Interner, Ty, TyKind, | 18 | AdtId, InferenceResult, Interner, TyExt, TyKind, |
19 | }; | 19 | }; |
20 | 20 | ||
21 | pub(crate) use hir_def::{ | 21 | pub(crate) use hir_def::{ |
@@ -423,7 +423,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
423 | None => return, | 423 | None => return, |
424 | }; | 424 | }; |
425 | 425 | ||
426 | if mismatch.actual != Ty::unit() || mismatch.expected != *possible_tail_ty { | 426 | if !mismatch.actual.is_unit() || mismatch.expected != *possible_tail_ty { |
427 | return; | 427 | return; |
428 | } | 428 | } |
429 | 429 | ||
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs index 97f1092c6..385bd9405 100644 --- a/crates/hir_ty/src/display.rs +++ b/crates/hir_ty/src/display.rs | |||
@@ -19,7 +19,7 @@ use crate::{ | |||
19 | db::HirDatabase, from_assoc_type_id, from_foreign_def_id, from_placeholder_idx, primitive, | 19 | db::HirDatabase, from_assoc_type_id, from_foreign_def_id, from_placeholder_idx, primitive, |
20 | to_assoc_type_id, traits::chalk::from_chalk, utils::generics, AdtId, AliasEq, AliasTy, | 20 | to_assoc_type_id, traits::chalk::from_chalk, utils::generics, AdtId, AliasEq, AliasTy, |
21 | CallableDefId, CallableSig, DomainGoal, GenericArg, ImplTraitId, Interner, Lifetime, OpaqueTy, | 21 | CallableDefId, CallableSig, DomainGoal, GenericArg, ImplTraitId, Interner, Lifetime, OpaqueTy, |
22 | ProjectionTy, QuantifiedWhereClause, Scalar, Substitution, TraitRef, Ty, TyKind, WhereClause, | 22 | ProjectionTy, QuantifiedWhereClause, Scalar, TraitRef, Ty, TyExt, TyKind, WhereClause, |
23 | }; | 23 | }; |
24 | 24 | ||
25 | pub struct HirFormatter<'a> { | 25 | pub struct HirFormatter<'a> { |
@@ -423,7 +423,7 @@ impl HirDisplay for Ty { | |||
423 | f.write_joined(sig.params(), ", ")?; | 423 | f.write_joined(sig.params(), ", ")?; |
424 | write!(f, ")")?; | 424 | write!(f, ")")?; |
425 | let ret = sig.ret(); | 425 | let ret = sig.ret(); |
426 | if *ret != Ty::unit() { | 426 | if !ret.is_unit() { |
427 | let ret_display = ret.into_displayable( | 427 | let ret_display = ret.into_displayable( |
428 | f.db, | 428 | f.db, |
429 | f.max_size, | 429 | f.max_size, |
@@ -591,7 +591,7 @@ impl HirDisplay for Ty { | |||
591 | write!(f, "{}", param_data.name.clone().unwrap_or_else(Name::missing))? | 591 | write!(f, "{}", param_data.name.clone().unwrap_or_else(Name::missing))? |
592 | } | 592 | } |
593 | TypeParamProvenance::ArgumentImplTrait => { | 593 | TypeParamProvenance::ArgumentImplTrait => { |
594 | let substs = Substitution::type_params_for_generics(f.db, &generics); | 594 | let substs = generics.type_params_subst(f.db); |
595 | let bounds = f | 595 | let bounds = f |
596 | .db | 596 | .db |
597 | .generic_predicates(id.parent) | 597 | .generic_predicates(id.parent) |
@@ -663,7 +663,7 @@ impl HirDisplay for CallableSig { | |||
663 | } | 663 | } |
664 | write!(f, ")")?; | 664 | write!(f, ")")?; |
665 | let ret = self.ret(); | 665 | let ret = self.ret(); |
666 | if *ret != Ty::unit() { | 666 | if !ret.is_unit() { |
667 | let ret_display = | 667 | let ret_display = |
668 | ret.into_displayable(f.db, f.max_size, f.omit_verbose_types, f.display_target); | 668 | ret.into_displayable(f.db, f.max_size, f.omit_verbose_types, f.display_target); |
669 | write!(f, " -> {}", ret_display)?; | 669 | write!(f, " -> {}", ret_display)?; |
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs index b871594bd..1b1d4458c 100644 --- a/crates/hir_ty/src/infer.rs +++ b/crates/hir_ty/src/infer.rs | |||
@@ -38,11 +38,11 @@ use syntax::SmolStr; | |||
38 | 38 | ||
39 | use super::{ | 39 | use super::{ |
40 | traits::{DomainGoal, Guidance, Solution}, | 40 | traits::{DomainGoal, Guidance, Solution}, |
41 | InEnvironment, ProjectionTy, Substitution, TraitEnvironment, TraitRef, Ty, TypeWalk, | 41 | InEnvironment, ProjectionTy, TraitEnvironment, TraitRef, Ty, TypeWalk, |
42 | }; | 42 | }; |
43 | use crate::{ | 43 | use crate::{ |
44 | db::HirDatabase, infer::diagnostics::InferenceDiagnostic, lower::ImplTraitLoweringMode, | 44 | db::HirDatabase, infer::diagnostics::InferenceDiagnostic, lower::ImplTraitLoweringMode, |
45 | to_assoc_type_id, to_chalk_trait_id, AliasEq, AliasTy, Interner, TyKind, | 45 | to_assoc_type_id, AliasEq, AliasTy, Interner, TyBuilder, 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. |
@@ -409,16 +409,14 @@ impl<'a> InferenceContext<'a> { | |||
409 | _ => panic!("resolve_associated_type called with non-associated type"), | 409 | _ => panic!("resolve_associated_type called with non-associated type"), |
410 | }; | 410 | }; |
411 | let ty = self.table.new_type_var(); | 411 | let ty = self.table.new_type_var(); |
412 | let substs = Substitution::build_for_def(self.db, res_assoc_ty) | 412 | let trait_ref = TyBuilder::trait_ref(self.db, trait_) |
413 | .push(inner_ty) | 413 | .push(inner_ty) |
414 | .fill(params.iter().cloned()) | 414 | .fill(params.iter().cloned()) |
415 | .build(); | 415 | .build(); |
416 | let trait_ref = | ||
417 | TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs.clone() }; | ||
418 | let alias_eq = AliasEq { | 416 | let alias_eq = AliasEq { |
419 | alias: AliasTy::Projection(ProjectionTy { | 417 | alias: AliasTy::Projection(ProjectionTy { |
420 | associated_ty_id: to_assoc_type_id(res_assoc_ty), | 418 | associated_ty_id: to_assoc_type_id(res_assoc_ty), |
421 | substitution: substs, | 419 | substitution: trait_ref.substitution.clone(), |
422 | }), | 420 | }), |
423 | ty: ty.clone(), | 421 | ty: ty.clone(), |
424 | }; | 422 | }; |
@@ -489,7 +487,7 @@ impl<'a> InferenceContext<'a> { | |||
489 | } | 487 | } |
490 | TypeNs::SelfType(impl_id) => { | 488 | TypeNs::SelfType(impl_id) => { |
491 | let generics = crate::utils::generics(self.db.upcast(), impl_id.into()); | 489 | let generics = crate::utils::generics(self.db.upcast(), impl_id.into()); |
492 | let substs = Substitution::type_params_for_generics(self.db, &generics); | 490 | let substs = generics.type_params_subst(self.db); |
493 | let ty = self.db.impl_self_ty(impl_id).subst(&substs); | 491 | let ty = self.db.impl_self_ty(impl_id).subst(&substs); |
494 | match unresolved { | 492 | match unresolved { |
495 | None => { | 493 | None => { |
@@ -516,10 +514,9 @@ impl<'a> InferenceContext<'a> { | |||
516 | } | 514 | } |
517 | } | 515 | } |
518 | TypeNs::TypeAliasId(it) => { | 516 | TypeNs::TypeAliasId(it) => { |
519 | let substs = Substitution::build_for_def(self.db, it) | 517 | let ty = TyBuilder::def_ty(self.db, it.into()) |
520 | .fill(std::iter::repeat_with(|| self.table.new_type_var())) | 518 | .fill(std::iter::repeat_with(|| self.table.new_type_var())) |
521 | .build(); | 519 | .build(); |
522 | let ty = self.db.ty(it.into()).subst(&substs); | ||
523 | let variant = ty_variant(&ty); | 520 | let variant = ty_variant(&ty); |
524 | forbid_unresolved_segments((ty, variant), unresolved) | 521 | forbid_unresolved_segments((ty, variant), unresolved) |
525 | } | 522 | } |
diff --git a/crates/hir_ty/src/infer/coerce.rs b/crates/hir_ty/src/infer/coerce.rs index d887e21a2..028a4d568 100644 --- a/crates/hir_ty/src/infer/coerce.rs +++ b/crates/hir_ty/src/infer/coerce.rs | |||
@@ -7,9 +7,7 @@ | |||
7 | use chalk_ir::{cast::Cast, Mutability, TyVariableKind}; | 7 | use chalk_ir::{cast::Cast, Mutability, TyVariableKind}; |
8 | use hir_def::lang_item::LangItemTarget; | 8 | use hir_def::lang_item::LangItemTarget; |
9 | 9 | ||
10 | use crate::{ | 10 | use crate::{autoderef, traits::Solution, Interner, Ty, TyBuilder, TyKind}; |
11 | autoderef, to_chalk_trait_id, traits::Solution, Interner, Substitution, TraitRef, Ty, TyKind, | ||
12 | }; | ||
13 | 11 | ||
14 | use super::{InEnvironment, InferenceContext}; | 12 | use super::{InEnvironment, InferenceContext}; |
15 | 13 | ||
@@ -44,8 +42,8 @@ impl<'a> InferenceContext<'a> { | |||
44 | // https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916 | 42 | // https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916 |
45 | let sig1 = ty1.callable_sig(self.db).expect("FnDef without callable sig"); | 43 | let sig1 = ty1.callable_sig(self.db).expect("FnDef without callable sig"); |
46 | let sig2 = ty2.callable_sig(self.db).expect("FnDef without callable sig"); | 44 | let sig2 = ty2.callable_sig(self.db).expect("FnDef without callable sig"); |
47 | let ptr_ty1 = Ty::fn_ptr(sig1); | 45 | let ptr_ty1 = TyBuilder::fn_ptr(sig1); |
48 | let ptr_ty2 = Ty::fn_ptr(sig2); | 46 | let ptr_ty2 = TyBuilder::fn_ptr(sig2); |
49 | self.coerce_merge_branch(&ptr_ty1, &ptr_ty2) | 47 | self.coerce_merge_branch(&ptr_ty1, &ptr_ty2) |
50 | } else { | 48 | } else { |
51 | cov_mark::hit!(coerce_merge_fail_fallback); | 49 | cov_mark::hit!(coerce_merge_fail_fallback); |
@@ -95,7 +93,7 @@ impl<'a> InferenceContext<'a> { | |||
95 | (TyKind::FnDef(..), TyKind::Function { .. }) => match from_ty.callable_sig(self.db) { | 93 | (TyKind::FnDef(..), TyKind::Function { .. }) => match from_ty.callable_sig(self.db) { |
96 | None => return false, | 94 | None => return false, |
97 | Some(sig) => { | 95 | Some(sig) => { |
98 | from_ty = Ty::fn_ptr(sig); | 96 | from_ty = TyBuilder::fn_ptr(sig); |
99 | } | 97 | } |
100 | }, | 98 | }, |
101 | 99 | ||
@@ -130,18 +128,15 @@ impl<'a> InferenceContext<'a> { | |||
130 | _ => return None, | 128 | _ => return None, |
131 | }; | 129 | }; |
132 | 130 | ||
133 | let generic_params = crate::utils::generics(self.db.upcast(), coerce_unsized_trait.into()); | 131 | let trait_ref = { |
134 | if generic_params.len() != 2 { | 132 | let b = TyBuilder::trait_ref(self.db, coerce_unsized_trait); |
135 | // The CoerceUnsized trait should have two generic params: Self and T. | 133 | if b.remaining() != 2 { |
136 | return None; | 134 | // The CoerceUnsized trait should have two generic params: Self and T. |
137 | } | 135 | return None; |
136 | } | ||
137 | b.push(from_ty.clone()).push(to_ty.clone()).build() | ||
138 | }; | ||
138 | 139 | ||
139 | let substs = Substitution::build_for_generics(&generic_params) | ||
140 | .push(from_ty.clone()) | ||
141 | .push(to_ty.clone()) | ||
142 | .build(); | ||
143 | let trait_ref = | ||
144 | TraitRef { trait_id: to_chalk_trait_id(coerce_unsized_trait), substitution: substs }; | ||
145 | let goal = InEnvironment::new(self.trait_env.env.clone(), trait_ref.cast(&Interner)); | 140 | let goal = InEnvironment::new(self.trait_env.env.clone(), trait_ref.cast(&Interner)); |
146 | 141 | ||
147 | let canonicalizer = self.canonicalizer(); | 142 | let canonicalizer = self.canonicalizer(); |
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs index dd3914ec3..c584a2c08 100644 --- a/crates/hir_ty/src/infer/expr.rs +++ b/crates/hir_ty/src/infer/expr.rs | |||
@@ -19,11 +19,11 @@ use crate::{ | |||
19 | lower::lower_to_chalk_mutability, | 19 | lower::lower_to_chalk_mutability, |
20 | method_resolution, op, | 20 | method_resolution, op, |
21 | primitive::{self, UintTy}, | 21 | primitive::{self, UintTy}, |
22 | to_assoc_type_id, to_chalk_trait_id, | 22 | to_chalk_trait_id, |
23 | traits::{chalk::from_chalk, FnTrait, InEnvironment}, | 23 | traits::{chalk::from_chalk, FnTrait, InEnvironment}, |
24 | utils::{generics, variant_data, Generics}, | 24 | utils::{generics, variant_data, Generics}, |
25 | AdtId, Binders, CallableDefId, DomainGoal, FnPointer, FnSig, Interner, Rawness, Scalar, | 25 | AdtId, Binders, CallableDefId, FnPointer, FnSig, Interner, Rawness, Scalar, Substitution, |
26 | Substitution, TraitRef, Ty, TyKind, | 26 | TraitRef, Ty, TyBuilder, TyKind, |
27 | }; | 27 | }; |
28 | 28 | ||
29 | use super::{ | 29 | use super::{ |
@@ -73,38 +73,33 @@ impl<'a> InferenceContext<'a> { | |||
73 | let fn_once_trait = FnTrait::FnOnce.get_id(self.db, krate)?; | 73 | let fn_once_trait = FnTrait::FnOnce.get_id(self.db, krate)?; |
74 | let output_assoc_type = | 74 | let output_assoc_type = |
75 | self.db.trait_data(fn_once_trait).associated_type_by_name(&name![Output])?; | 75 | self.db.trait_data(fn_once_trait).associated_type_by_name(&name![Output])?; |
76 | let generic_params = generics(self.db.upcast(), fn_once_trait.into()); | ||
77 | if generic_params.len() != 2 { | ||
78 | return None; | ||
79 | } | ||
80 | 76 | ||
81 | let mut param_builder = Substitution::builder(num_args); | ||
82 | let mut arg_tys = vec![]; | 77 | let mut arg_tys = vec![]; |
83 | for _ in 0..num_args { | 78 | let arg_ty = TyBuilder::tuple(num_args) |
84 | let arg = self.table.new_type_var(); | 79 | .fill(repeat_with(|| { |
85 | param_builder = param_builder.push(arg.clone()); | 80 | let arg = self.table.new_type_var(); |
86 | arg_tys.push(arg); | 81 | arg_tys.push(arg.clone()); |
87 | } | 82 | arg |
88 | let parameters = param_builder.build(); | 83 | })) |
89 | let arg_ty = TyKind::Tuple(num_args, parameters).intern(&Interner); | 84 | .build(); |
90 | let substs = | 85 | |
91 | Substitution::build_for_generics(&generic_params).push(ty.clone()).push(arg_ty).build(); | 86 | let projection = { |
87 | let b = TyBuilder::assoc_type_projection(self.db, output_assoc_type); | ||
88 | if b.remaining() != 2 { | ||
89 | return None; | ||
90 | } | ||
91 | b.push(ty.clone()).push(arg_ty).build() | ||
92 | }; | ||
92 | 93 | ||
93 | let trait_env = self.trait_env.env.clone(); | 94 | let trait_env = self.trait_env.env.clone(); |
94 | let implements_fn_trait: DomainGoal = | 95 | let obligation = InEnvironment { |
95 | TraitRef { trait_id: to_chalk_trait_id(fn_once_trait), substitution: substs.clone() } | 96 | goal: projection.trait_ref(self.db).cast(&Interner), |
96 | .cast(&Interner); | ||
97 | let goal = self.canonicalizer().canonicalize_obligation(InEnvironment { | ||
98 | goal: implements_fn_trait.clone(), | ||
99 | environment: trait_env, | 97 | environment: trait_env, |
100 | }); | 98 | }; |
101 | if self.db.trait_solve(krate, goal.value).is_some() { | 99 | let canonical = self.canonicalizer().canonicalize_obligation(obligation.clone()); |
102 | self.push_obligation(implements_fn_trait); | 100 | if self.db.trait_solve(krate, canonical.value).is_some() { |
103 | let output_proj_ty = crate::ProjectionTy { | 101 | self.push_obligation(obligation.goal); |
104 | associated_ty_id: to_assoc_type_id(output_assoc_type), | 102 | let return_ty = self.normalize_projection_ty(projection); |
105 | substitution: substs, | ||
106 | }; | ||
107 | let return_ty = self.normalize_projection_ty(output_proj_ty); | ||
108 | Some((arg_tys, return_ty)) | 103 | Some((arg_tys, return_ty)) |
109 | } else { | 104 | } else { |
110 | None | 105 | None |
@@ -138,7 +133,7 @@ impl<'a> InferenceContext<'a> { | |||
138 | both_arms_diverge &= mem::replace(&mut self.diverges, Diverges::Maybe); | 133 | both_arms_diverge &= mem::replace(&mut self.diverges, Diverges::Maybe); |
139 | let else_ty = match else_branch { | 134 | let else_ty = match else_branch { |
140 | Some(else_branch) => self.infer_expr_inner(*else_branch, &expected), | 135 | Some(else_branch) => self.infer_expr_inner(*else_branch, &expected), |
141 | None => Ty::unit(), | 136 | None => TyBuilder::unit(), |
142 | }; | 137 | }; |
143 | both_arms_diverge &= self.diverges; | 138 | both_arms_diverge &= self.diverges; |
144 | 139 | ||
@@ -193,7 +188,7 @@ impl<'a> InferenceContext<'a> { | |||
193 | break_ty: self.table.new_type_var(), | 188 | break_ty: self.table.new_type_var(), |
194 | label: label.map(|label| self.body[label].name.clone()), | 189 | label: label.map(|label| self.body[label].name.clone()), |
195 | }); | 190 | }); |
196 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); | 191 | self.infer_expr(*body, &Expectation::has_type(TyBuilder::unit())); |
197 | 192 | ||
198 | let ctxt = self.breakables.pop().expect("breakable stack broken"); | 193 | let ctxt = self.breakables.pop().expect("breakable stack broken"); |
199 | if ctxt.may_break { | 194 | if ctxt.may_break { |
@@ -217,11 +212,11 @@ impl<'a> InferenceContext<'a> { | |||
217 | *condition, | 212 | *condition, |
218 | &Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(&Interner)), | 213 | &Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(&Interner)), |
219 | ); | 214 | ); |
220 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); | 215 | self.infer_expr(*body, &Expectation::has_type(TyBuilder::unit())); |
221 | let _ctxt = self.breakables.pop().expect("breakable stack broken"); | 216 | let _ctxt = self.breakables.pop().expect("breakable stack broken"); |
222 | // the body may not run, so it diverging doesn't mean we diverge | 217 | // the body may not run, so it diverging doesn't mean we diverge |
223 | self.diverges = Diverges::Maybe; | 218 | self.diverges = Diverges::Maybe; |
224 | Ty::unit() | 219 | TyBuilder::unit() |
225 | } | 220 | } |
226 | Expr::For { iterable, body, pat, label } => { | 221 | Expr::For { iterable, body, pat, label } => { |
227 | let iterable_ty = self.infer_expr(*iterable, &Expectation::none()); | 222 | let iterable_ty = self.infer_expr(*iterable, &Expectation::none()); |
@@ -236,11 +231,11 @@ impl<'a> InferenceContext<'a> { | |||
236 | 231 | ||
237 | self.infer_pat(*pat, &pat_ty, BindingMode::default()); | 232 | self.infer_pat(*pat, &pat_ty, BindingMode::default()); |
238 | 233 | ||
239 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); | 234 | self.infer_expr(*body, &Expectation::has_type(TyBuilder::unit())); |
240 | let _ctxt = self.breakables.pop().expect("breakable stack broken"); | 235 | let _ctxt = self.breakables.pop().expect("breakable stack broken"); |
241 | // the body may not run, so it diverging doesn't mean we diverge | 236 | // the body may not run, so it diverging doesn't mean we diverge |
242 | self.diverges = Diverges::Maybe; | 237 | self.diverges = Diverges::Maybe; |
243 | Ty::unit() | 238 | TyBuilder::unit() |
244 | } | 239 | } |
245 | Expr::Lambda { body, args, ret_type, arg_types } => { | 240 | Expr::Lambda { body, args, ret_type, arg_types } => { |
246 | assert_eq!(args.len(), arg_types.len()); | 241 | assert_eq!(args.len(), arg_types.len()); |
@@ -360,7 +355,7 @@ impl<'a> InferenceContext<'a> { | |||
360 | let val_ty = if let Some(expr) = expr { | 355 | let val_ty = if let Some(expr) = expr { |
361 | self.infer_expr(*expr, &Expectation::none()) | 356 | self.infer_expr(*expr, &Expectation::none()) |
362 | } else { | 357 | } else { |
363 | Ty::unit() | 358 | TyBuilder::unit() |
364 | }; | 359 | }; |
365 | 360 | ||
366 | let last_ty = | 361 | let last_ty = |
@@ -386,7 +381,7 @@ impl<'a> InferenceContext<'a> { | |||
386 | if let Some(expr) = expr { | 381 | if let Some(expr) = expr { |
387 | self.infer_expr_coerce(*expr, &Expectation::has_type(self.return_ty.clone())); | 382 | self.infer_expr_coerce(*expr, &Expectation::has_type(self.return_ty.clone())); |
388 | } else { | 383 | } else { |
389 | let unit = Ty::unit(); | 384 | let unit = TyBuilder::unit(); |
390 | self.coerce(&unit, &self.return_ty.clone()); | 385 | self.coerce(&unit, &self.return_ty.clone()); |
391 | } | 386 | } |
392 | TyKind::Never.intern(&Interner) | 387 | TyKind::Never.intern(&Interner) |
@@ -539,17 +534,10 @@ impl<'a> InferenceContext<'a> { | |||
539 | Expr::Box { expr } => { | 534 | Expr::Box { expr } => { |
540 | let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); | 535 | let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); |
541 | if let Some(box_) = self.resolve_boxed_box() { | 536 | if let Some(box_) = self.resolve_boxed_box() { |
542 | let mut sb = | 537 | TyBuilder::adt(self.db, box_) |
543 | Substitution::build_for_generics(&generics(self.db.upcast(), box_.into())); | 538 | .push(inner_ty) |
544 | sb = sb.push(inner_ty); | 539 | .fill_with_defaults(self.db, || self.table.new_type_var()) |
545 | match self.db.generic_defaults(box_.into()).get(1) { | 540 | .build() |
546 | Some(alloc_ty) if !alloc_ty.value.is_unknown() && sb.remaining() > 0 => { | ||
547 | sb = sb.push(alloc_ty.value.clone()); | ||
548 | } | ||
549 | _ => (), | ||
550 | } | ||
551 | sb = sb.fill(repeat_with(|| self.table.new_type_var())); | ||
552 | Ty::adt_ty(box_, sb.build()) | ||
553 | } else { | 541 | } else { |
554 | self.err_ty() | 542 | self.err_ty() |
555 | } | 543 | } |
@@ -639,31 +627,31 @@ impl<'a> InferenceContext<'a> { | |||
639 | let rhs_ty = rhs.map(|e| self.infer_expr(e, &rhs_expect)); | 627 | let rhs_ty = rhs.map(|e| self.infer_expr(e, &rhs_expect)); |
640 | match (range_type, lhs_ty, rhs_ty) { | 628 | match (range_type, lhs_ty, rhs_ty) { |
641 | (RangeOp::Exclusive, None, None) => match self.resolve_range_full() { | 629 | (RangeOp::Exclusive, None, None) => match self.resolve_range_full() { |
642 | Some(adt) => Ty::adt_ty(adt, Substitution::empty(&Interner)), | 630 | Some(adt) => TyBuilder::adt(self.db, adt).build(), |
643 | None => self.err_ty(), | 631 | None => self.err_ty(), |
644 | }, | 632 | }, |
645 | (RangeOp::Exclusive, None, Some(ty)) => match self.resolve_range_to() { | 633 | (RangeOp::Exclusive, None, Some(ty)) => match self.resolve_range_to() { |
646 | Some(adt) => Ty::adt_ty(adt, Substitution::single(ty)), | 634 | Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(), |
647 | None => self.err_ty(), | 635 | None => self.err_ty(), |
648 | }, | 636 | }, |
649 | (RangeOp::Inclusive, None, Some(ty)) => { | 637 | (RangeOp::Inclusive, None, Some(ty)) => { |
650 | match self.resolve_range_to_inclusive() { | 638 | match self.resolve_range_to_inclusive() { |
651 | Some(adt) => Ty::adt_ty(adt, Substitution::single(ty)), | 639 | Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(), |
652 | None => self.err_ty(), | 640 | None => self.err_ty(), |
653 | } | 641 | } |
654 | } | 642 | } |
655 | (RangeOp::Exclusive, Some(_), Some(ty)) => match self.resolve_range() { | 643 | (RangeOp::Exclusive, Some(_), Some(ty)) => match self.resolve_range() { |
656 | Some(adt) => Ty::adt_ty(adt, Substitution::single(ty)), | 644 | Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(), |
657 | None => self.err_ty(), | 645 | None => self.err_ty(), |
658 | }, | 646 | }, |
659 | (RangeOp::Inclusive, Some(_), Some(ty)) => { | 647 | (RangeOp::Inclusive, Some(_), Some(ty)) => { |
660 | match self.resolve_range_inclusive() { | 648 | match self.resolve_range_inclusive() { |
661 | Some(adt) => Ty::adt_ty(adt, Substitution::single(ty)), | 649 | Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(), |
662 | None => self.err_ty(), | 650 | None => self.err_ty(), |
663 | } | 651 | } |
664 | } | 652 | } |
665 | (RangeOp::Exclusive, Some(ty), None) => match self.resolve_range_from() { | 653 | (RangeOp::Exclusive, Some(ty), None) => match self.resolve_range_from() { |
666 | Some(adt) => Ty::adt_ty(adt, Substitution::single(ty)), | 654 | Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(), |
667 | None => self.err_ty(), | 655 | None => self.err_ty(), |
668 | }, | 656 | }, |
669 | (RangeOp::Inclusive, _, None) => self.err_ty(), | 657 | (RangeOp::Inclusive, _, None) => self.err_ty(), |
@@ -828,8 +816,8 @@ impl<'a> InferenceContext<'a> { | |||
828 | // we don't even make an attempt at coercion | 816 | // we don't even make an attempt at coercion |
829 | self.table.new_maybe_never_var() | 817 | self.table.new_maybe_never_var() |
830 | } else { | 818 | } else { |
831 | self.coerce(&Ty::unit(), &expected.coercion_target()); | 819 | self.coerce(&TyBuilder::unit(), &expected.coercion_target()); |
832 | Ty::unit() | 820 | TyBuilder::unit() |
833 | } | 821 | } |
834 | }; | 822 | }; |
835 | ty | 823 | ty |
diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs index 10df8d8cb..5b70d5e5a 100644 --- a/crates/hir_ty/src/infer/pat.rs +++ b/crates/hir_ty/src/infer/pat.rs | |||
@@ -13,9 +13,8 @@ use hir_expand::name::Name; | |||
13 | 13 | ||
14 | use super::{BindingMode, Expectation, InferenceContext}; | 14 | use super::{BindingMode, Expectation, InferenceContext}; |
15 | use crate::{ | 15 | use crate::{ |
16 | lower::lower_to_chalk_mutability, | 16 | lower::lower_to_chalk_mutability, utils::variant_data, Interner, Substitution, Ty, TyBuilder, |
17 | utils::{generics, variant_data}, | 17 | TyKind, |
18 | Interner, Substitution, Ty, TyKind, | ||
19 | }; | 18 | }; |
20 | 19 | ||
21 | impl<'a> InferenceContext<'a> { | 20 | impl<'a> InferenceContext<'a> { |
@@ -246,23 +245,12 @@ impl<'a> InferenceContext<'a> { | |||
246 | }; | 245 | }; |
247 | 246 | ||
248 | let inner_ty = self.infer_pat(*inner, &inner_ty, default_bm); | 247 | let inner_ty = self.infer_pat(*inner, &inner_ty, default_bm); |
249 | let mut sb = Substitution::build_for_generics(&generics( | 248 | let mut b = TyBuilder::adt(self.db, box_adt).push(inner_ty); |
250 | self.db.upcast(), | 249 | |
251 | box_adt.into(), | 250 | if let Some(alloc_ty) = alloc_ty { |
252 | )); | 251 | b = b.push(alloc_ty); |
253 | sb = sb.push(inner_ty); | ||
254 | if sb.remaining() == 1 { | ||
255 | sb = sb.push(match alloc_ty { | ||
256 | Some(alloc_ty) if !alloc_ty.is_unknown() => alloc_ty, | ||
257 | _ => match self.db.generic_defaults(box_adt.into()).get(1) { | ||
258 | Some(alloc_ty) if !alloc_ty.value.is_unknown() => { | ||
259 | alloc_ty.value.clone() | ||
260 | } | ||
261 | _ => self.table.new_type_var(), | ||
262 | }, | ||
263 | }); | ||
264 | } | 252 | } |
265 | Ty::adt_ty(box_adt, sb.build()) | 253 | b.fill_with_defaults(self.db, || self.table.new_type_var()).build() |
266 | } | 254 | } |
267 | None => self.err_ty(), | 255 | None => self.err_ty(), |
268 | }, | 256 | }, |
diff --git a/crates/hir_ty/src/infer/path.rs b/crates/hir_ty/src/infer/path.rs index 1ba15f737..671ea355f 100644 --- a/crates/hir_ty/src/infer/path.rs +++ b/crates/hir_ty/src/infer/path.rs | |||
@@ -10,9 +10,7 @@ use hir_def::{ | |||
10 | }; | 10 | }; |
11 | use hir_expand::name::Name; | 11 | use hir_expand::name::Name; |
12 | 12 | ||
13 | use crate::{ | 13 | use crate::{method_resolution, Interner, Substitution, Ty, TyBuilder, TyKind, ValueTyDefId}; |
14 | method_resolution, to_chalk_trait_id, Interner, Substitution, Ty, TyKind, ValueTyDefId, | ||
15 | }; | ||
16 | 14 | ||
17 | use super::{ExprOrPatId, InferenceContext, TraitRef}; | 15 | use super::{ExprOrPatId, InferenceContext, TraitRef}; |
18 | 16 | ||
@@ -82,7 +80,7 @@ impl<'a> InferenceContext<'a> { | |||
82 | } | 80 | } |
83 | ValueNs::ImplSelf(impl_id) => { | 81 | ValueNs::ImplSelf(impl_id) => { |
84 | let generics = crate::utils::generics(self.db.upcast(), impl_id.into()); | 82 | let generics = crate::utils::generics(self.db.upcast(), impl_id.into()); |
85 | let substs = Substitution::type_params_for_generics(self.db, &generics); | 83 | let substs = generics.type_params_subst(self.db); |
86 | let ty = self.db.impl_self_ty(impl_id).subst(&substs); | 84 | let ty = self.db.impl_self_ty(impl_id).subst(&substs); |
87 | if let Some((AdtId::StructId(struct_id), substs)) = ty.as_adt() { | 85 | if let Some((AdtId::StructId(struct_id), substs)) = ty.as_adt() { |
88 | let ty = self.db.value_ty(struct_id.into()).subst(&substs); | 86 | let ty = self.db.value_ty(struct_id.into()).subst(&substs); |
@@ -95,16 +93,13 @@ impl<'a> InferenceContext<'a> { | |||
95 | ValueNs::GenericParam(it) => return Some(self.db.const_param_ty(it)), | 93 | ValueNs::GenericParam(it) => return Some(self.db.const_param_ty(it)), |
96 | }; | 94 | }; |
97 | 95 | ||
98 | let ty = self.db.value_ty(typable); | ||
99 | // self_subst is just for the parent | ||
100 | let parent_substs = self_subst.unwrap_or_else(|| Substitution::empty(&Interner)); | 96 | let parent_substs = self_subst.unwrap_or_else(|| Substitution::empty(&Interner)); |
101 | let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); | 97 | let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); |
102 | let substs = ctx.substs_from_path(path, typable, true); | 98 | let substs = ctx.substs_from_path(path, typable, true); |
103 | let full_substs = Substitution::builder(substs.len(&Interner)) | 99 | let ty = TyBuilder::value_ty(self.db, typable) |
104 | .use_parent_substs(&parent_substs) | 100 | .use_parent_substs(&parent_substs) |
105 | .fill(substs.interned(&Interner)[parent_substs.len(&Interner)..].iter().cloned()) | 101 | .fill(substs.interned(&Interner)[parent_substs.len(&Interner)..].iter().cloned()) |
106 | .build(); | 102 | .build(); |
107 | let ty = ty.subst(&full_substs); | ||
108 | Some(ty) | 103 | Some(ty) |
109 | } | 104 | } |
110 | 105 | ||
@@ -245,7 +240,7 @@ impl<'a> InferenceContext<'a> { | |||
245 | }; | 240 | }; |
246 | let substs = match container { | 241 | let substs = match container { |
247 | AssocContainerId::ImplId(impl_id) => { | 242 | AssocContainerId::ImplId(impl_id) => { |
248 | let impl_substs = Substitution::build_for_def(self.db, impl_id) | 243 | let impl_substs = TyBuilder::subst_for_def(self.db, impl_id) |
249 | .fill(iter::repeat_with(|| self.table.new_type_var())) | 244 | .fill(iter::repeat_with(|| self.table.new_type_var())) |
250 | .build(); | 245 | .build(); |
251 | let impl_self_ty = self.db.impl_self_ty(impl_id).subst(&impl_substs); | 246 | let impl_self_ty = self.db.impl_self_ty(impl_id).subst(&impl_substs); |
@@ -254,18 +249,12 @@ impl<'a> InferenceContext<'a> { | |||
254 | } | 249 | } |
255 | AssocContainerId::TraitId(trait_) => { | 250 | AssocContainerId::TraitId(trait_) => { |
256 | // we're picking this method | 251 | // we're picking this method |
257 | let trait_substs = Substitution::build_for_def(self.db, trait_) | 252 | let trait_ref = TyBuilder::trait_ref(self.db, trait_) |
258 | .push(ty.clone()) | 253 | .push(ty.clone()) |
259 | .fill(std::iter::repeat_with(|| self.table.new_type_var())) | 254 | .fill(std::iter::repeat_with(|| self.table.new_type_var())) |
260 | .build(); | 255 | .build(); |
261 | self.push_obligation( | 256 | self.push_obligation(trait_ref.clone().cast(&Interner)); |
262 | TraitRef { | 257 | Some(trait_ref.substitution) |
263 | trait_id: to_chalk_trait_id(trait_), | ||
264 | substitution: trait_substs.clone(), | ||
265 | } | ||
266 | .cast(&Interner), | ||
267 | ); | ||
268 | Some(trait_substs) | ||
269 | } | 258 | } |
270 | AssocContainerId::ModuleId(_) => None, | 259 | AssocContainerId::ModuleId(_) => None, |
271 | }; | 260 | }; |
diff --git a/crates/hir_ty/src/infer/unify.rs b/crates/hir_ty/src/infer/unify.rs index d2496db3b..a04b935ef 100644 --- a/crates/hir_ty/src/infer/unify.rs +++ b/crates/hir_ty/src/infer/unify.rs | |||
@@ -186,14 +186,11 @@ pub(crate) fn unify(tys: &Canonical<(Ty, Ty)>) -> Option<Substitution> { | |||
186 | ); | 186 | ); |
187 | } | 187 | } |
188 | } | 188 | } |
189 | Some( | 189 | Some(Substitution::from_iter( |
190 | Substitution::builder(tys.binders.len(&Interner)) | 190 | &Interner, |
191 | .fill( | 191 | vars.iter(&Interner) |
192 | vars.iter(&Interner) | 192 | .map(|v| table.resolve_ty_completely(v.assert_ty_ref(&Interner).clone())), |
193 | .map(|v| table.resolve_ty_completely(v.assert_ty_ref(&Interner).clone())), | 193 | )) |
194 | ) | ||
195 | .build(), | ||
196 | ) | ||
197 | } | 194 | } |
198 | 195 | ||
199 | #[derive(Clone, Debug)] | 196 | #[derive(Clone, Debug)] |
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs index 4c3d904bf..a8c87eadf 100644 --- a/crates/hir_ty/src/lib.rs +++ b/crates/hir_ty/src/lib.rs | |||
@@ -14,6 +14,8 @@ mod lower; | |||
14 | pub(crate) mod infer; | 14 | pub(crate) mod infer; |
15 | pub(crate) mod utils; | 15 | pub(crate) mod utils; |
16 | mod chalk_cast; | 16 | mod chalk_cast; |
17 | mod chalk_ext; | ||
18 | mod builder; | ||
17 | 19 | ||
18 | pub mod display; | 20 | pub mod display; |
19 | pub mod db; | 21 | pub mod db; |
@@ -24,24 +26,27 @@ mod tests; | |||
24 | #[cfg(test)] | 26 | #[cfg(test)] |
25 | mod test_db; | 27 | mod test_db; |
26 | 28 | ||
27 | use std::{iter, mem, sync::Arc}; | 29 | use std::{mem, sync::Arc}; |
28 | 30 | ||
29 | use base_db::salsa; | ||
30 | use chalk_ir::cast::{CastTo, Caster}; | 31 | use chalk_ir::cast::{CastTo, Caster}; |
31 | use hir_def::{ | ||
32 | builtin_type::BuiltinType, expr::ExprId, type_ref::Rawness, AssocContainerId, FunctionId, | ||
33 | GenericDefId, HasModule, LifetimeParamId, Lookup, TraitId, TypeAliasId, TypeParamId, | ||
34 | }; | ||
35 | use itertools::Itertools; | 32 | use itertools::Itertools; |
36 | use smallvec::SmallVec; | 33 | use smallvec::SmallVec; |
37 | 34 | ||
35 | use base_db::salsa; | ||
36 | use hir_def::{ | ||
37 | expr::ExprId, type_ref::Rawness, AssocContainerId, FunctionId, GenericDefId, HasModule, | ||
38 | LifetimeParamId, Lookup, TraitId, TypeAliasId, TypeParamId, | ||
39 | }; | ||
40 | |||
38 | use crate::{ | 41 | use crate::{ |
39 | db::HirDatabase, | 42 | db::HirDatabase, |
40 | display::HirDisplay, | 43 | display::HirDisplay, |
41 | utils::{generics, make_mut_slice, Generics}, | 44 | utils::{generics, make_mut_slice}, |
42 | }; | 45 | }; |
43 | 46 | ||
44 | pub use autoderef::autoderef; | 47 | pub use autoderef::autoderef; |
48 | pub use builder::TyBuilder; | ||
49 | pub use chalk_ext::TyExt; | ||
45 | pub use infer::{could_unify, InferenceResult, InferenceVar}; | 50 | pub use infer::{could_unify, InferenceResult, InferenceVar}; |
46 | pub use lower::{ | 51 | pub use lower::{ |
47 | associated_type_shorthand_candidates, callable_item_sig, CallableDefId, ImplTraitLoweringMode, | 52 | associated_type_shorthand_candidates, callable_item_sig, CallableDefId, ImplTraitLoweringMode, |
@@ -457,51 +462,6 @@ impl Substitution { | |||
457 | ) -> Self { | 462 | ) -> Self { |
458 | Substitution(elements.into_iter().casted(interner).collect()) | 463 | Substitution(elements.into_iter().casted(interner).collect()) |
459 | } | 464 | } |
460 | |||
461 | /// Return Substs that replace each parameter by itself (i.e. `Ty::Param`). | ||
462 | pub(crate) fn type_params_for_generics( | ||
463 | db: &dyn HirDatabase, | ||
464 | generic_params: &Generics, | ||
465 | ) -> Substitution { | ||
466 | Substitution::from_iter( | ||
467 | &Interner, | ||
468 | generic_params | ||
469 | .iter() | ||
470 | .map(|(id, _)| TyKind::Placeholder(to_placeholder_idx(db, id)).intern(&Interner)), | ||
471 | ) | ||
472 | } | ||
473 | |||
474 | /// Return Substs that replace each parameter by itself (i.e. `Ty::Param`). | ||
475 | pub fn type_params(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> Substitution { | ||
476 | let params = generics(db.upcast(), def.into()); | ||
477 | Substitution::type_params_for_generics(db, ¶ms) | ||
478 | } | ||
479 | |||
480 | /// Return Substs that replace each parameter by a bound variable. | ||
481 | pub(crate) fn bound_vars(generic_params: &Generics, debruijn: DebruijnIndex) -> Substitution { | ||
482 | Substitution::from_iter( | ||
483 | &Interner, | ||
484 | generic_params | ||
485 | .iter() | ||
486 | .enumerate() | ||
487 | .map(|(idx, _)| TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(&Interner)), | ||
488 | ) | ||
489 | } | ||
490 | |||
491 | pub fn build_for_def(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> SubstsBuilder { | ||
492 | let def = def.into(); | ||
493 | let params = generics(db.upcast(), def); | ||
494 | let param_count = params.len(); | ||
495 | Substitution::builder(param_count) | ||
496 | } | ||
497 | |||
498 | pub(crate) fn build_for_generics(generic_params: &Generics) -> SubstsBuilder { | ||
499 | Substitution::builder(generic_params.len()) | ||
500 | } | ||
501 | |||
502 | fn builder(param_count: usize) -> SubstsBuilder { | ||
503 | SubstsBuilder { vec: Vec::with_capacity(param_count), param_count } | ||
504 | } | ||
505 | } | 465 | } |
506 | 466 | ||
507 | /// Return an index of a parameter in the generic type parameter list by it's id. | 467 | /// Return an index of a parameter in the generic type parameter list by it's id. |
@@ -509,52 +469,6 @@ pub fn param_idx(db: &dyn HirDatabase, id: TypeParamId) -> Option<usize> { | |||
509 | generics(db.upcast(), id.parent).param_idx(id) | 469 | generics(db.upcast(), id.parent).param_idx(id) |
510 | } | 470 | } |
511 | 471 | ||
512 | #[derive(Debug, Clone)] | ||
513 | pub struct SubstsBuilder { | ||
514 | vec: Vec<GenericArg>, | ||
515 | param_count: usize, | ||
516 | } | ||
517 | |||
518 | impl SubstsBuilder { | ||
519 | pub fn build(self) -> Substitution { | ||
520 | assert_eq!(self.vec.len(), self.param_count); | ||
521 | Substitution::from_iter(&Interner, self.vec) | ||
522 | } | ||
523 | |||
524 | pub fn push(mut self, ty: impl CastTo<GenericArg>) -> Self { | ||
525 | self.vec.push(ty.cast(&Interner)); | ||
526 | self | ||
527 | } | ||
528 | |||
529 | fn remaining(&self) -> usize { | ||
530 | self.param_count - self.vec.len() | ||
531 | } | ||
532 | |||
533 | pub fn fill_with_bound_vars(self, debruijn: DebruijnIndex, starting_from: usize) -> Self { | ||
534 | self.fill( | ||
535 | (starting_from..) | ||
536 | .map(|idx| TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(&Interner)), | ||
537 | ) | ||
538 | } | ||
539 | |||
540 | pub fn fill_with_unknown(self) -> Self { | ||
541 | self.fill(iter::repeat(TyKind::Unknown.intern(&Interner))) | ||
542 | } | ||
543 | |||
544 | pub fn fill(mut self, filler: impl Iterator<Item = impl CastTo<GenericArg>>) -> Self { | ||
545 | self.vec.extend(filler.take(self.remaining()).casted(&Interner)); | ||
546 | assert_eq!(self.remaining(), 0); | ||
547 | self | ||
548 | } | ||
549 | |||
550 | pub fn use_parent_substs(mut self, parent_substs: &Substitution) -> Self { | ||
551 | assert!(self.vec.is_empty()); | ||
552 | assert!(parent_substs.len(&Interner) <= self.param_count); | ||
553 | self.vec.extend(parent_substs.iter(&Interner).cloned()); | ||
554 | self | ||
555 | } | ||
556 | } | ||
557 | |||
558 | #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] | 472 | #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] |
559 | pub struct Binders<T> { | 473 | pub struct Binders<T> { |
560 | pub num_binders: usize, | 474 | pub num_binders: usize, |
@@ -760,7 +674,7 @@ impl CallableSig { | |||
760 | 674 | ||
761 | pub fn from_fn_ptr(fn_ptr: &FnPointer) -> CallableSig { | 675 | pub fn from_fn_ptr(fn_ptr: &FnPointer) -> CallableSig { |
762 | CallableSig { | 676 | CallableSig { |
763 | // FIXME: what to do about lifetime params? | 677 | // FIXME: what to do about lifetime params? -> return PolyFnSig |
764 | params_and_return: fn_ptr | 678 | params_and_return: fn_ptr |
765 | .substs | 679 | .substs |
766 | .clone() | 680 | .clone() |
@@ -773,16 +687,6 @@ impl CallableSig { | |||
773 | } | 687 | } |
774 | } | 688 | } |
775 | 689 | ||
776 | pub fn from_substs(substs: &Substitution) -> CallableSig { | ||
777 | CallableSig { | ||
778 | params_and_return: substs | ||
779 | .iter(&Interner) | ||
780 | .map(|arg| arg.assert_ty_ref(&Interner).clone()) | ||
781 | .collect(), | ||
782 | is_varargs: false, | ||
783 | } | ||
784 | } | ||
785 | |||
786 | pub fn params(&self) -> &[Ty] { | 690 | pub fn params(&self) -> &[Ty] { |
787 | &self.params_and_return[0..self.params_and_return.len() - 1] | 691 | &self.params_and_return[0..self.params_and_return.len() - 1] |
788 | } | 692 | } |
@@ -811,40 +715,6 @@ impl TypeWalk for CallableSig { | |||
811 | } | 715 | } |
812 | 716 | ||
813 | impl Ty { | 717 | impl Ty { |
814 | pub fn unit() -> Self { | ||
815 | TyKind::Tuple(0, Substitution::empty(&Interner)).intern(&Interner) | ||
816 | } | ||
817 | |||
818 | pub fn adt_ty(adt: hir_def::AdtId, substs: Substitution) -> Ty { | ||
819 | TyKind::Adt(AdtId(adt), substs).intern(&Interner) | ||
820 | } | ||
821 | |||
822 | pub fn fn_ptr(sig: CallableSig) -> Self { | ||
823 | TyKind::Function(FnPointer { | ||
824 | num_args: sig.params().len(), | ||
825 | sig: FnSig { abi: (), safety: Safety::Safe, variadic: sig.is_varargs }, | ||
826 | substs: Substitution::from_iter(&Interner, sig.params_and_return.iter().cloned()), | ||
827 | }) | ||
828 | .intern(&Interner) | ||
829 | } | ||
830 | |||
831 | pub fn builtin(builtin: BuiltinType) -> Self { | ||
832 | match builtin { | ||
833 | BuiltinType::Char => TyKind::Scalar(Scalar::Char).intern(&Interner), | ||
834 | BuiltinType::Bool => TyKind::Scalar(Scalar::Bool).intern(&Interner), | ||
835 | BuiltinType::Str => TyKind::Str.intern(&Interner), | ||
836 | BuiltinType::Int(t) => { | ||
837 | TyKind::Scalar(Scalar::Int(primitive::int_ty_from_builtin(t))).intern(&Interner) | ||
838 | } | ||
839 | BuiltinType::Uint(t) => { | ||
840 | TyKind::Scalar(Scalar::Uint(primitive::uint_ty_from_builtin(t))).intern(&Interner) | ||
841 | } | ||
842 | BuiltinType::Float(t) => { | ||
843 | TyKind::Scalar(Scalar::Float(primitive::float_ty_from_builtin(t))).intern(&Interner) | ||
844 | } | ||
845 | } | ||
846 | } | ||
847 | |||
848 | pub fn as_reference(&self) -> Option<(&Ty, Mutability)> { | 718 | pub fn as_reference(&self) -> Option<(&Ty, Mutability)> { |
849 | match self.kind(&Interner) { | 719 | match self.kind(&Interner) { |
850 | TyKind::Ref(mutability, ty) => Some((ty, *mutability)), | 720 | TyKind::Ref(mutability, ty) => Some((ty, *mutability)), |
@@ -1068,7 +938,7 @@ impl Ty { | |||
1068 | let param_data = &generic_params.types[id.local_id]; | 938 | let param_data = &generic_params.types[id.local_id]; |
1069 | match param_data.provenance { | 939 | match param_data.provenance { |
1070 | hir_def::generics::TypeParamProvenance::ArgumentImplTrait => { | 940 | hir_def::generics::TypeParamProvenance::ArgumentImplTrait => { |
1071 | let substs = Substitution::type_params(db, id.parent); | 941 | let substs = TyBuilder::type_params_subst(db, id.parent); |
1072 | let predicates = db | 942 | let predicates = db |
1073 | .generic_predicates(id.parent) | 943 | .generic_predicates(id.parent) |
1074 | .into_iter() | 944 | .into_iter() |
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs index e60d7c730..214655807 100644 --- a/crates/hir_ty/src/lower.rs +++ b/crates/hir_ty/src/lower.rs | |||
@@ -36,7 +36,7 @@ use crate::{ | |||
36 | AliasEq, AliasTy, Binders, BoundVar, CallableSig, DebruijnIndex, DynTy, FnPointer, FnSig, | 36 | AliasEq, AliasTy, Binders, BoundVar, CallableSig, DebruijnIndex, DynTy, FnPointer, FnSig, |
37 | ImplTraitId, OpaqueTy, PolyFnSig, ProjectionTy, QuantifiedWhereClause, QuantifiedWhereClauses, | 37 | ImplTraitId, OpaqueTy, PolyFnSig, ProjectionTy, QuantifiedWhereClause, QuantifiedWhereClauses, |
38 | ReturnTypeImplTrait, ReturnTypeImplTraits, Substitution, TraitEnvironment, TraitRef, Ty, | 38 | ReturnTypeImplTrait, ReturnTypeImplTraits, Substitution, TraitEnvironment, TraitRef, Ty, |
39 | TyKind, TypeWalk, WhereClause, | 39 | TyBuilder, TyKind, TypeWalk, WhereClause, |
40 | }; | 40 | }; |
41 | 41 | ||
42 | #[derive(Debug)] | 42 | #[derive(Debug)] |
@@ -234,7 +234,7 @@ impl<'a> TyLoweringContext<'a> { | |||
234 | let impl_trait_id = ImplTraitId::ReturnTypeImplTrait(func, idx); | 234 | let impl_trait_id = ImplTraitId::ReturnTypeImplTrait(func, idx); |
235 | let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into(); | 235 | let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into(); |
236 | let generics = generics(self.db.upcast(), func.into()); | 236 | let generics = generics(self.db.upcast(), func.into()); |
237 | let parameters = Substitution::bound_vars(&generics, self.in_binders); | 237 | let parameters = generics.bound_vars_subst(self.in_binders); |
238 | TyKind::Alias(AliasTy::Opaque(OpaqueTy { | 238 | TyKind::Alias(AliasTy::Opaque(OpaqueTy { |
239 | opaque_ty_id, | 239 | opaque_ty_id, |
240 | substitution: parameters, | 240 | substitution: parameters, |
@@ -411,24 +411,16 @@ impl<'a> TyLoweringContext<'a> { | |||
411 | TypeNs::SelfType(impl_id) => { | 411 | TypeNs::SelfType(impl_id) => { |
412 | let generics = generics(self.db.upcast(), impl_id.into()); | 412 | let generics = generics(self.db.upcast(), impl_id.into()); |
413 | let substs = match self.type_param_mode { | 413 | let substs = match self.type_param_mode { |
414 | TypeParamLoweringMode::Placeholder => { | 414 | TypeParamLoweringMode::Placeholder => generics.type_params_subst(self.db), |
415 | Substitution::type_params_for_generics(self.db, &generics) | 415 | TypeParamLoweringMode::Variable => generics.bound_vars_subst(self.in_binders), |
416 | } | ||
417 | TypeParamLoweringMode::Variable => { | ||
418 | Substitution::bound_vars(&generics, self.in_binders) | ||
419 | } | ||
420 | }; | 416 | }; |
421 | self.db.impl_self_ty(impl_id).subst(&substs) | 417 | self.db.impl_self_ty(impl_id).subst(&substs) |
422 | } | 418 | } |
423 | TypeNs::AdtSelfType(adt) => { | 419 | TypeNs::AdtSelfType(adt) => { |
424 | let generics = generics(self.db.upcast(), adt.into()); | 420 | let generics = generics(self.db.upcast(), adt.into()); |
425 | let substs = match self.type_param_mode { | 421 | let substs = match self.type_param_mode { |
426 | TypeParamLoweringMode::Placeholder => { | 422 | TypeParamLoweringMode::Placeholder => generics.type_params_subst(self.db), |
427 | Substitution::type_params_for_generics(self.db, &generics) | 423 | TypeParamLoweringMode::Variable => generics.bound_vars_subst(self.in_binders), |
428 | } | ||
429 | TypeParamLoweringMode::Variable => { | ||
430 | Substitution::bound_vars(&generics, self.in_binders) | ||
431 | } | ||
432 | }; | 424 | }; |
433 | self.db.ty(adt.into()).subst(&substs) | 425 | self.db.ty(adt.into()).subst(&substs) |
434 | } | 426 | } |
@@ -478,12 +470,13 @@ impl<'a> TyLoweringContext<'a> { | |||
478 | TypeParamLoweringMode::Placeholder => { | 470 | TypeParamLoweringMode::Placeholder => { |
479 | // if we're lowering to placeholders, we have to put | 471 | // if we're lowering to placeholders, we have to put |
480 | // them in now | 472 | // them in now |
481 | let s = Substitution::type_params( | 473 | let generics = generics( |
482 | self.db, | 474 | self.db.upcast(), |
483 | self.resolver.generic_def().expect( | 475 | self.resolver.generic_def().expect( |
484 | "there should be generics if there's a generic param", | 476 | "there should be generics if there's a generic param", |
485 | ), | 477 | ), |
486 | ); | 478 | ); |
479 | let s = generics.type_params_subst(self.db); | ||
487 | t.substitution.clone().subst_bound_vars(&s) | 480 | t.substitution.clone().subst_bound_vars(&s) |
488 | } | 481 | } |
489 | TypeParamLoweringMode::Variable => t.substitution.clone(), | 482 | TypeParamLoweringMode::Variable => t.substitution.clone(), |
@@ -860,10 +853,9 @@ pub fn associated_type_shorthand_candidates<R>( | |||
860 | if generics.params.types[param_id.local_id].provenance | 853 | if generics.params.types[param_id.local_id].provenance |
861 | == TypeParamProvenance::TraitSelf | 854 | == TypeParamProvenance::TraitSelf |
862 | { | 855 | { |
863 | let trait_ref = TraitRef { | 856 | let trait_ref = TyBuilder::trait_ref(db, trait_id) |
864 | trait_id: to_chalk_trait_id(trait_id), | 857 | .fill_with_bound_vars(DebruijnIndex::INNERMOST, 0) |
865 | substitution: Substitution::bound_vars(&generics, DebruijnIndex::INNERMOST), | 858 | .build(); |
866 | }; | ||
867 | return search(trait_ref); | 859 | return search(trait_ref); |
868 | } | 860 | } |
869 | } | 861 | } |
@@ -972,7 +964,7 @@ pub(crate) fn trait_environment_query( | |||
972 | // function default implementations (and hypothetical code | 964 | // function default implementations (and hypothetical code |
973 | // inside consts or type aliases) | 965 | // inside consts or type aliases) |
974 | cov_mark::hit!(trait_self_implements_self); | 966 | cov_mark::hit!(trait_self_implements_self); |
975 | let substs = Substitution::type_params(db, trait_id); | 967 | let substs = TyBuilder::type_params_subst(db, trait_id); |
976 | let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution: substs }; | 968 | let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution: substs }; |
977 | let pred = WhereClause::Implemented(trait_ref); | 969 | let pred = WhereClause::Implemented(trait_ref); |
978 | let program_clause: chalk_ir::ProgramClause<Interner> = pred.to_chalk(db).cast(&Interner); | 970 | let program_clause: chalk_ir::ProgramClause<Interner> = pred.to_chalk(db).cast(&Interner); |
@@ -1061,7 +1053,7 @@ fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig { | |||
1061 | /// function body. | 1053 | /// function body. |
1062 | fn type_for_fn(db: &dyn HirDatabase, def: FunctionId) -> Binders<Ty> { | 1054 | fn type_for_fn(db: &dyn HirDatabase, def: FunctionId) -> Binders<Ty> { |
1063 | let generics = generics(db.upcast(), def.into()); | 1055 | let generics = generics(db.upcast(), def.into()); |
1064 | let substs = Substitution::bound_vars(&generics, DebruijnIndex::INNERMOST); | 1056 | let substs = generics.bound_vars_subst(DebruijnIndex::INNERMOST); |
1065 | Binders::new( | 1057 | Binders::new( |
1066 | substs.len(&Interner), | 1058 | substs.len(&Interner), |
1067 | TyKind::FnDef(CallableDefId::FunctionId(def).to_chalk(db), substs).intern(&Interner), | 1059 | TyKind::FnDef(CallableDefId::FunctionId(def).to_chalk(db), substs).intern(&Interner), |
@@ -1106,7 +1098,7 @@ fn type_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> Binders<T | |||
1106 | return type_for_adt(db, def.into()); | 1098 | return type_for_adt(db, def.into()); |
1107 | } | 1099 | } |
1108 | let generics = generics(db.upcast(), def.into()); | 1100 | let generics = generics(db.upcast(), def.into()); |
1109 | let substs = Substitution::bound_vars(&generics, DebruijnIndex::INNERMOST); | 1101 | let substs = generics.bound_vars_subst(DebruijnIndex::INNERMOST); |
1110 | Binders::new( | 1102 | Binders::new( |
1111 | substs.len(&Interner), | 1103 | substs.len(&Interner), |
1112 | TyKind::FnDef(CallableDefId::StructId(def).to_chalk(db), substs).intern(&Interner), | 1104 | TyKind::FnDef(CallableDefId::StructId(def).to_chalk(db), substs).intern(&Interner), |
@@ -1133,7 +1125,7 @@ fn type_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId) - | |||
1133 | return type_for_adt(db, def.parent.into()); | 1125 | return type_for_adt(db, def.parent.into()); |
1134 | } | 1126 | } |
1135 | let generics = generics(db.upcast(), def.parent.into()); | 1127 | let generics = generics(db.upcast(), def.parent.into()); |
1136 | let substs = Substitution::bound_vars(&generics, DebruijnIndex::INNERMOST); | 1128 | let substs = generics.bound_vars_subst(DebruijnIndex::INNERMOST); |
1137 | Binders::new( | 1129 | Binders::new( |
1138 | substs.len(&Interner), | 1130 | substs.len(&Interner), |
1139 | TyKind::FnDef(CallableDefId::EnumVariantId(def).to_chalk(db), substs).intern(&Interner), | 1131 | TyKind::FnDef(CallableDefId::EnumVariantId(def).to_chalk(db), substs).intern(&Interner), |
@@ -1141,9 +1133,10 @@ fn type_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId) - | |||
1141 | } | 1133 | } |
1142 | 1134 | ||
1143 | fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> Binders<Ty> { | 1135 | fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> Binders<Ty> { |
1144 | let generics = generics(db.upcast(), adt.into()); | 1136 | let b = TyBuilder::adt(db, adt); |
1145 | let substs = Substitution::bound_vars(&generics, DebruijnIndex::INNERMOST); | 1137 | let num_binders = b.remaining(); |
1146 | Binders::new(substs.len(&Interner), Ty::adt_ty(adt, substs)) | 1138 | let ty = b.fill_with_bound_vars(DebruijnIndex::INNERMOST, 0).build(); |
1139 | Binders::new(num_binders, ty) | ||
1147 | } | 1140 | } |
1148 | 1141 | ||
1149 | fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> { | 1142 | fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> { |
@@ -1215,7 +1208,7 @@ impl_from!(FunctionId, StructId, UnionId, EnumVariantId, ConstId, StaticId for V | |||
1215 | /// namespace. | 1208 | /// namespace. |
1216 | pub(crate) fn ty_query(db: &dyn HirDatabase, def: TyDefId) -> Binders<Ty> { | 1209 | pub(crate) fn ty_query(db: &dyn HirDatabase, def: TyDefId) -> Binders<Ty> { |
1217 | match def { | 1210 | match def { |
1218 | TyDefId::BuiltinType(it) => Binders::new(0, Ty::builtin(it)), | 1211 | TyDefId::BuiltinType(it) => Binders::new(0, TyBuilder::builtin(it)), |
1219 | TyDefId::AdtId(it) => type_for_adt(db, it), | 1212 | TyDefId::AdtId(it) => type_for_adt(db, it), |
1220 | TyDefId::TypeAliasId(it) => type_for_type_alias(db, it), | 1213 | TyDefId::TypeAliasId(it) => type_for_type_alias(db, it), |
1221 | } | 1214 | } |
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs index c093fce20..a76586f0c 100644 --- a/crates/hir_ty/src/method_resolution.rs +++ b/crates/hir_ty/src/method_resolution.rs | |||
@@ -19,10 +19,9 @@ use crate::{ | |||
19 | db::HirDatabase, | 19 | db::HirDatabase, |
20 | from_foreign_def_id, | 20 | from_foreign_def_id, |
21 | primitive::{self, FloatTy, IntTy, UintTy}, | 21 | primitive::{self, FloatTy, IntTy, UintTy}, |
22 | to_chalk_trait_id, | ||
23 | utils::all_super_traits, | 22 | utils::all_super_traits, |
24 | AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, FnPointer, FnSig, ForeignDefId, | 23 | AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, FnPointer, FnSig, ForeignDefId, |
25 | InEnvironment, Interner, Scalar, Substitution, TraitEnvironment, TraitRef, Ty, TyKind, | 24 | InEnvironment, Interner, Scalar, Substitution, TraitEnvironment, Ty, TyBuilder, TyKind, |
26 | TypeWalk, | 25 | TypeWalk, |
27 | }; | 26 | }; |
28 | 27 | ||
@@ -710,7 +709,7 @@ pub(crate) fn inherent_impl_substs( | |||
710 | ) -> Option<Substitution> { | 709 | ) -> Option<Substitution> { |
711 | // we create a var for each type parameter of the impl; we need to keep in | 710 | // we create a var for each type parameter of the impl; we need to keep in |
712 | // mind here that `self_ty` might have vars of its own | 711 | // mind here that `self_ty` might have vars of its own |
713 | let vars = Substitution::build_for_def(db, impl_id) | 712 | let vars = TyBuilder::subst_for_def(db, impl_id) |
714 | .fill_with_bound_vars(DebruijnIndex::INNERMOST, self_ty.binders.len(&Interner)) | 713 | .fill_with_bound_vars(DebruijnIndex::INNERMOST, self_ty.binders.len(&Interner)) |
715 | .build(); | 714 | .build(); |
716 | let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars); | 715 | let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars); |
@@ -761,13 +760,13 @@ fn transform_receiver_ty( | |||
761 | self_ty: &Canonical<Ty>, | 760 | self_ty: &Canonical<Ty>, |
762 | ) -> Option<Ty> { | 761 | ) -> Option<Ty> { |
763 | let substs = match function_id.lookup(db.upcast()).container { | 762 | let substs = match function_id.lookup(db.upcast()).container { |
764 | AssocContainerId::TraitId(_) => Substitution::build_for_def(db, function_id) | 763 | AssocContainerId::TraitId(_) => TyBuilder::subst_for_def(db, function_id) |
765 | .push(self_ty.value.clone()) | 764 | .push(self_ty.value.clone()) |
766 | .fill_with_unknown() | 765 | .fill_with_unknown() |
767 | .build(), | 766 | .build(), |
768 | AssocContainerId::ImplId(impl_id) => { | 767 | AssocContainerId::ImplId(impl_id) => { |
769 | let impl_substs = inherent_impl_substs(db, impl_id, &self_ty)?; | 768 | let impl_substs = inherent_impl_substs(db, impl_id, &self_ty)?; |
770 | Substitution::build_for_def(db, function_id) | 769 | TyBuilder::subst_for_def(db, function_id) |
771 | .use_parent_substs(&impl_substs) | 770 | .use_parent_substs(&impl_substs) |
772 | .fill_with_unknown() | 771 | .fill_with_unknown() |
773 | .build() | 772 | .build() |
@@ -813,7 +812,7 @@ fn generic_implements_goal( | |||
813 | self_ty: Canonical<Ty>, | 812 | self_ty: Canonical<Ty>, |
814 | ) -> Canonical<InEnvironment<super::DomainGoal>> { | 813 | ) -> Canonical<InEnvironment<super::DomainGoal>> { |
815 | let mut kinds = self_ty.binders.interned().to_vec(); | 814 | let mut kinds = self_ty.binders.interned().to_vec(); |
816 | let substs = super::Substitution::build_for_def(db, trait_) | 815 | let trait_ref = TyBuilder::trait_ref(db, trait_) |
817 | .push(self_ty.value) | 816 | .push(self_ty.value) |
818 | .fill_with_bound_vars(DebruijnIndex::INNERMOST, kinds.len()) | 817 | .fill_with_bound_vars(DebruijnIndex::INNERMOST, kinds.len()) |
819 | .build(); | 818 | .build(); |
@@ -822,9 +821,8 @@ fn generic_implements_goal( | |||
822 | chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General), | 821 | chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General), |
823 | UniverseIndex::ROOT, | 822 | UniverseIndex::ROOT, |
824 | )) | 823 | )) |
825 | .take(substs.len(&Interner) - 1), | 824 | .take(trait_ref.substitution.len(&Interner) - 1), |
826 | ); | 825 | ); |
827 | let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs }; | ||
828 | let obligation = trait_ref.cast(&Interner); | 826 | let obligation = trait_ref.cast(&Interner); |
829 | Canonical { | 827 | Canonical { |
830 | binders: CanonicalVarKinds::from_iter(&Interner, kinds), | 828 | binders: CanonicalVarKinds::from_iter(&Interner, kinds), |
diff --git a/crates/hir_ty/src/op.rs b/crates/hir_ty/src/op.rs index 8533e1ed8..90dd31a35 100644 --- a/crates/hir_ty/src/op.rs +++ b/crates/hir_ty/src/op.rs | |||
@@ -2,12 +2,12 @@ | |||
2 | use chalk_ir::TyVariableKind; | 2 | use chalk_ir::TyVariableKind; |
3 | use hir_def::expr::{ArithOp, BinaryOp, CmpOp}; | 3 | use hir_def::expr::{ArithOp, BinaryOp, CmpOp}; |
4 | 4 | ||
5 | use crate::{Interner, Scalar, Ty, TyKind}; | 5 | use crate::{Interner, Scalar, Ty, TyBuilder, TyKind}; |
6 | 6 | ||
7 | pub(super) fn binary_op_return_ty(op: BinaryOp, lhs_ty: Ty, rhs_ty: Ty) -> Ty { | 7 | pub(super) fn binary_op_return_ty(op: BinaryOp, lhs_ty: Ty, rhs_ty: Ty) -> Ty { |
8 | match op { | 8 | match op { |
9 | BinaryOp::LogicOp(_) | BinaryOp::CmpOp(_) => TyKind::Scalar(Scalar::Bool).intern(&Interner), | 9 | BinaryOp::LogicOp(_) | BinaryOp::CmpOp(_) => TyKind::Scalar(Scalar::Bool).intern(&Interner), |
10 | BinaryOp::Assignment { .. } => Ty::unit(), | 10 | BinaryOp::Assignment { .. } => TyBuilder::unit(), |
11 | BinaryOp::ArithOp(ArithOp::Shl) | BinaryOp::ArithOp(ArithOp::Shr) => { | 11 | BinaryOp::ArithOp(ArithOp::Shl) | BinaryOp::ArithOp(ArithOp::Shr) => { |
12 | match lhs_ty.kind(&Interner) { | 12 | match lhs_ty.kind(&Interner) { |
13 | TyKind::Scalar(Scalar::Int(_)) | 13 | TyKind::Scalar(Scalar::Int(_)) |
diff --git a/crates/hir_ty/src/traits/chalk.rs b/crates/hir_ty/src/traits/chalk.rs index fbac51b05..541e6082f 100644 --- a/crates/hir_ty/src/traits/chalk.rs +++ b/crates/hir_ty/src/traits/chalk.rs | |||
@@ -22,7 +22,7 @@ use crate::{ | |||
22 | to_assoc_type_id, to_chalk_trait_id, | 22 | to_assoc_type_id, to_chalk_trait_id, |
23 | utils::generics, | 23 | utils::generics, |
24 | AliasEq, AliasTy, BoundVar, CallableDefId, DebruijnIndex, FnDefId, ProjectionTy, Substitution, | 24 | AliasEq, AliasTy, BoundVar, CallableDefId, DebruijnIndex, FnDefId, ProjectionTy, Substitution, |
25 | TraitRef, Ty, TyKind, WhereClause, | 25 | TraitRef, Ty, TyBuilder, TyKind, WhereClause, |
26 | }; | 26 | }; |
27 | use mapping::{ | 27 | use mapping::{ |
28 | convert_where_clauses, generic_predicate_to_inline_bound, make_binders, TypeAliasAsValue, | 28 | convert_where_clauses, generic_predicate_to_inline_bound, make_binders, TypeAliasAsValue, |
@@ -300,7 +300,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> { | |||
300 | _closure_id: chalk_ir::ClosureId<Interner>, | 300 | _closure_id: chalk_ir::ClosureId<Interner>, |
301 | _substs: &chalk_ir::Substitution<Interner>, | 301 | _substs: &chalk_ir::Substitution<Interner>, |
302 | ) -> chalk_ir::Binders<chalk_ir::Ty<Interner>> { | 302 | ) -> chalk_ir::Binders<chalk_ir::Ty<Interner>> { |
303 | let ty = Ty::unit().to_chalk(self.db); | 303 | let ty = TyBuilder::unit().to_chalk(self.db); |
304 | make_binders(ty, 0) | 304 | make_binders(ty, 0) |
305 | } | 305 | } |
306 | fn closure_fn_substitution( | 306 | fn closure_fn_substitution( |
@@ -387,7 +387,7 @@ pub(crate) fn associated_ty_data_query( | |||
387 | // Lower bounds -- we could/should maybe move this to a separate query in `lower` | 387 | // Lower bounds -- we could/should maybe move this to a separate query in `lower` |
388 | let type_alias_data = db.type_alias_data(type_alias); | 388 | let type_alias_data = db.type_alias_data(type_alias); |
389 | let generic_params = generics(db.upcast(), type_alias.into()); | 389 | let generic_params = generics(db.upcast(), type_alias.into()); |
390 | let bound_vars = Substitution::bound_vars(&generic_params, DebruijnIndex::INNERMOST); | 390 | let bound_vars = generic_params.bound_vars_subst(DebruijnIndex::INNERMOST); |
391 | let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast()); | 391 | let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast()); |
392 | let ctx = crate::TyLoweringContext::new(db, &resolver) | 392 | let ctx = crate::TyLoweringContext::new(db, &resolver) |
393 | .with_type_param_mode(crate::lower::TypeParamLoweringMode::Variable); | 393 | .with_type_param_mode(crate::lower::TypeParamLoweringMode::Variable); |
@@ -421,7 +421,7 @@ pub(crate) fn trait_datum_query( | |||
421 | let trait_data = db.trait_data(trait_); | 421 | let trait_data = db.trait_data(trait_); |
422 | debug!("trait {:?} = {:?}", trait_id, trait_data.name); | 422 | debug!("trait {:?} = {:?}", trait_id, trait_data.name); |
423 | let generic_params = generics(db.upcast(), trait_.into()); | 423 | let generic_params = generics(db.upcast(), trait_.into()); |
424 | let bound_vars = Substitution::bound_vars(&generic_params, DebruijnIndex::INNERMOST); | 424 | let bound_vars = generic_params.bound_vars_subst(DebruijnIndex::INNERMOST); |
425 | let flags = rust_ir::TraitFlags { | 425 | let flags = rust_ir::TraitFlags { |
426 | auto: trait_data.is_auto, | 426 | auto: trait_data.is_auto, |
427 | upstream: trait_.lookup(db.upcast()).container.krate() != krate, | 427 | upstream: trait_.lookup(db.upcast()).container.krate() != krate, |
@@ -490,7 +490,7 @@ pub(crate) fn struct_datum_query( | |||
490 | let upstream = adt_id.module(db.upcast()).krate() != krate; | 490 | let upstream = adt_id.module(db.upcast()).krate() != krate; |
491 | let where_clauses = { | 491 | let where_clauses = { |
492 | let generic_params = generics(db.upcast(), adt_id.into()); | 492 | let generic_params = generics(db.upcast(), adt_id.into()); |
493 | let bound_vars = Substitution::bound_vars(&generic_params, DebruijnIndex::INNERMOST); | 493 | let bound_vars = generic_params.bound_vars_subst(DebruijnIndex::INNERMOST); |
494 | convert_where_clauses(db, adt_id.into(), &bound_vars) | 494 | convert_where_clauses(db, adt_id.into(), &bound_vars) |
495 | }; | 495 | }; |
496 | let flags = rust_ir::AdtFlags { | 496 | let flags = rust_ir::AdtFlags { |
@@ -539,7 +539,7 @@ fn impl_def_datum( | |||
539 | let impl_data = db.impl_data(impl_id); | 539 | let impl_data = db.impl_data(impl_id); |
540 | 540 | ||
541 | let generic_params = generics(db.upcast(), impl_id.into()); | 541 | let generic_params = generics(db.upcast(), impl_id.into()); |
542 | let bound_vars = Substitution::bound_vars(&generic_params, DebruijnIndex::INNERMOST); | 542 | let bound_vars = generic_params.bound_vars_subst(DebruijnIndex::INNERMOST); |
543 | let trait_ = trait_ref.hir_trait_id(); | 543 | let trait_ = trait_ref.hir_trait_id(); |
544 | let impl_type = if impl_id.lookup(db.upcast()).container.krate() == krate { | 544 | let impl_type = if impl_id.lookup(db.upcast()).container.krate() == krate { |
545 | rust_ir::ImplType::Local | 545 | rust_ir::ImplType::Local |
@@ -629,7 +629,7 @@ pub(crate) fn fn_def_datum_query( | |||
629 | let callable_def: CallableDefId = from_chalk(db, fn_def_id); | 629 | let callable_def: CallableDefId = from_chalk(db, fn_def_id); |
630 | let generic_params = generics(db.upcast(), callable_def.into()); | 630 | let generic_params = generics(db.upcast(), callable_def.into()); |
631 | let sig = db.callable_item_signature(callable_def); | 631 | let sig = db.callable_item_signature(callable_def); |
632 | let bound_vars = Substitution::bound_vars(&generic_params, DebruijnIndex::INNERMOST); | 632 | let bound_vars = generic_params.bound_vars_subst(DebruijnIndex::INNERMOST); |
633 | let where_clauses = convert_where_clauses(db, callable_def.into(), &bound_vars); | 633 | let where_clauses = convert_where_clauses(db, callable_def.into(), &bound_vars); |
634 | let bound = rust_ir::FnDefDatumBound { | 634 | let bound = rust_ir::FnDefDatumBound { |
635 | // Note: Chalk doesn't actually use this information yet as far as I am aware, but we provide it anyway | 635 | // Note: Chalk doesn't actually use this information yet as far as I am aware, but we provide it anyway |
diff --git a/crates/hir_ty/src/utils.rs b/crates/hir_ty/src/utils.rs index 42d7af146..b23e91b1b 100644 --- a/crates/hir_ty/src/utils.rs +++ b/crates/hir_ty/src/utils.rs | |||
@@ -2,7 +2,7 @@ | |||
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`). |
3 | use std::sync::Arc; | 3 | use std::sync::Arc; |
4 | 4 | ||
5 | use chalk_ir::DebruijnIndex; | 5 | use chalk_ir::{BoundVar, DebruijnIndex}; |
6 | use hir_def::{ | 6 | use hir_def::{ |
7 | adt::VariantData, | 7 | adt::VariantData, |
8 | db::DefDatabase, | 8 | db::DefDatabase, |
@@ -16,7 +16,7 @@ use hir_def::{ | |||
16 | }; | 16 | }; |
17 | use hir_expand::name::{name, Name}; | 17 | use hir_expand::name::{name, Name}; |
18 | 18 | ||
19 | use crate::{db::HirDatabase, TraitRef, TypeWalk, WhereClause}; | 19 | use crate::{db::HirDatabase, Interner, Substitution, TraitRef, TyKind, TypeWalk, WhereClause}; |
20 | 20 | ||
21 | fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { | 21 | fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { |
22 | let resolver = trait_.resolver(db); | 22 | let resolver = trait_.resolver(db); |
@@ -249,6 +249,26 @@ impl Generics { | |||
249 | self.parent_generics.as_ref().and_then(|g| g.find_param(param)) | 249 | self.parent_generics.as_ref().and_then(|g| g.find_param(param)) |
250 | } | 250 | } |
251 | } | 251 | } |
252 | |||
253 | /// Returns a Substitution that replaces each parameter by a bound variable. | ||
254 | pub(crate) fn bound_vars_subst(&self, debruijn: DebruijnIndex) -> Substitution { | ||
255 | Substitution::from_iter( | ||
256 | &Interner, | ||
257 | self.iter() | ||
258 | .enumerate() | ||
259 | .map(|(idx, _)| TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(&Interner)), | ||
260 | ) | ||
261 | } | ||
262 | |||
263 | /// Returns a Substitution that replaces each parameter by itself (i.e. `Ty::Param`). | ||
264 | pub(crate) fn type_params_subst(&self, db: &dyn HirDatabase) -> Substitution { | ||
265 | Substitution::from_iter( | ||
266 | &Interner, | ||
267 | self.iter().map(|(id, _)| { | ||
268 | TyKind::Placeholder(crate::to_placeholder_idx(db, id)).intern(&Interner) | ||
269 | }), | ||
270 | ) | ||
271 | } | ||
252 | } | 272 | } |
253 | 273 | ||
254 | fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Option<GenericDefId> { | 274 | fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Option<GenericDefId> { |
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index f73edf8b6..d5ef054d8 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs | |||
@@ -234,7 +234,7 @@ fn hint_iterator( | |||
234 | hir::AssocItem::TypeAlias(alias) if alias.name(db) == known::Item => Some(alias), | 234 | hir::AssocItem::TypeAlias(alias) if alias.name(db) == known::Item => Some(alias), |
235 | _ => None, | 235 | _ => None, |
236 | })?; | 236 | })?; |
237 | if let Some(ty) = ty.normalize_trait_assoc_type(db, iter_trait, &[], assoc_type_item) { | 237 | if let Some(ty) = ty.normalize_trait_assoc_type(db, &[], assoc_type_item) { |
238 | const LABEL_START: &str = "impl Iterator<Item = "; | 238 | const LABEL_START: &str = "impl Iterator<Item = "; |
239 | const LABEL_END: &str = ">"; | 239 | const LABEL_END: &str = ">"; |
240 | 240 | ||
diff --git a/crates/ide_assists/src/handlers/convert_into_to_from.rs b/crates/ide_assists/src/handlers/convert_into_to_from.rs new file mode 100644 index 000000000..199e1ad5c --- /dev/null +++ b/crates/ide_assists/src/handlers/convert_into_to_from.rs | |||
@@ -0,0 +1,355 @@ | |||
1 | use ide_db::{ | ||
2 | helpers::{mod_path_to_ast, FamousDefs}, | ||
3 | traits::resolve_target_trait, | ||
4 | }; | ||
5 | use syntax::ast::{self, AstNode, NameOwner}; | ||
6 | |||
7 | use crate::{AssistContext, AssistId, AssistKind, Assists}; | ||
8 | |||
9 | // Assist: convert_into_to_from | ||
10 | // | ||
11 | // Converts an Into impl to an equivalent From impl. | ||
12 | // | ||
13 | // ``` | ||
14 | // # //- /lib.rs crate:core | ||
15 | // # pub mod convert { pub trait Into<T> { pub fn into(self) -> T; } } | ||
16 | // # //- /lib.rs crate:main deps:core | ||
17 | // # use core::convert::Into; | ||
18 | // impl $0Into<Thing> for usize { | ||
19 | // fn into(self) -> Thing { | ||
20 | // Thing { | ||
21 | // b: self.to_string(), | ||
22 | // a: self | ||
23 | // } | ||
24 | // } | ||
25 | // } | ||
26 | // ``` | ||
27 | // -> | ||
28 | // ``` | ||
29 | // # use core::convert::Into; | ||
30 | // impl From<usize> for Thing { | ||
31 | // fn from(val: usize) -> Self { | ||
32 | // Thing { | ||
33 | // b: val.to_string(), | ||
34 | // a: val | ||
35 | // } | ||
36 | // } | ||
37 | // } | ||
38 | // ``` | ||
39 | pub(crate) fn convert_into_to_from(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
40 | let impl_ = ctx.find_node_at_offset::<ast::Impl>()?; | ||
41 | let src_type = impl_.self_ty()?; | ||
42 | let ast_trait = impl_.trait_()?; | ||
43 | |||
44 | let module = ctx.sema.scope(impl_.syntax()).module()?; | ||
45 | |||
46 | let trait_ = resolve_target_trait(&ctx.sema, &impl_)?; | ||
47 | if trait_ != FamousDefs(&ctx.sema, Some(module.krate())).core_convert_Into()? { | ||
48 | return None; | ||
49 | } | ||
50 | |||
51 | let src_type_path = { | ||
52 | let src_type_path = src_type.syntax().descendants().find_map(ast::Path::cast)?; | ||
53 | let src_type_def = match ctx.sema.resolve_path(&src_type_path) { | ||
54 | Some(hir::PathResolution::Def(module_def)) => module_def, | ||
55 | _ => return None, | ||
56 | }; | ||
57 | |||
58 | mod_path_to_ast(&module.find_use_path(ctx.db(), src_type_def)?) | ||
59 | }; | ||
60 | |||
61 | let dest_type = match &ast_trait { | ||
62 | ast::Type::PathType(path) => { | ||
63 | path.path()?.segment()?.generic_arg_list()?.generic_args().next()? | ||
64 | } | ||
65 | _ => return None, | ||
66 | }; | ||
67 | |||
68 | let into_fn = impl_.assoc_item_list()?.assoc_items().find_map(|item| { | ||
69 | if let ast::AssocItem::Fn(f) = item { | ||
70 | if f.name()?.text() == "into" { | ||
71 | return Some(f); | ||
72 | } | ||
73 | }; | ||
74 | None | ||
75 | })?; | ||
76 | |||
77 | let into_fn_name = into_fn.name()?; | ||
78 | let into_fn_params = into_fn.param_list()?; | ||
79 | let into_fn_return = into_fn.ret_type()?; | ||
80 | |||
81 | let selfs = into_fn | ||
82 | .body()? | ||
83 | .syntax() | ||
84 | .descendants() | ||
85 | .filter_map(ast::NameRef::cast) | ||
86 | .filter(|name| name.text() == "self" || name.text() == "Self"); | ||
87 | |||
88 | acc.add( | ||
89 | AssistId("convert_into_to_from", AssistKind::RefactorRewrite), | ||
90 | "Convert Into to From", | ||
91 | impl_.syntax().text_range(), | ||
92 | |builder| { | ||
93 | builder.replace(src_type.syntax().text_range(), dest_type.to_string()); | ||
94 | builder.replace(ast_trait.syntax().text_range(), format!("From<{}>", src_type)); | ||
95 | builder.replace(into_fn_return.syntax().text_range(), "-> Self"); | ||
96 | builder.replace( | ||
97 | into_fn_params.syntax().text_range(), | ||
98 | format!("(val: {})", src_type.to_string()), | ||
99 | ); | ||
100 | builder.replace(into_fn_name.syntax().text_range(), "from"); | ||
101 | |||
102 | for s in selfs { | ||
103 | match s.text().as_ref() { | ||
104 | "self" => builder.replace(s.syntax().text_range(), "val"), | ||
105 | "Self" => builder.replace(s.syntax().text_range(), src_type_path.to_string()), | ||
106 | _ => {} | ||
107 | } | ||
108 | } | ||
109 | }, | ||
110 | ) | ||
111 | } | ||
112 | |||
113 | #[cfg(test)] | ||
114 | mod tests { | ||
115 | use super::*; | ||
116 | |||
117 | use crate::tests::check_assist; | ||
118 | |||
119 | #[test] | ||
120 | fn convert_into_to_from_converts_a_struct() { | ||
121 | check_convert_into_to_from( | ||
122 | r#" | ||
123 | struct Thing { | ||
124 | a: String, | ||
125 | b: usize | ||
126 | } | ||
127 | |||
128 | impl $0core::convert::Into<Thing> for usize { | ||
129 | fn into(self) -> Thing { | ||
130 | Thing { | ||
131 | b: self.to_string(), | ||
132 | a: self | ||
133 | } | ||
134 | } | ||
135 | } | ||
136 | "#, | ||
137 | r#" | ||
138 | struct Thing { | ||
139 | a: String, | ||
140 | b: usize | ||
141 | } | ||
142 | |||
143 | impl From<usize> for Thing { | ||
144 | fn from(val: usize) -> Self { | ||
145 | Thing { | ||
146 | b: val.to_string(), | ||
147 | a: val | ||
148 | } | ||
149 | } | ||
150 | } | ||
151 | "#, | ||
152 | ) | ||
153 | } | ||
154 | |||
155 | #[test] | ||
156 | fn convert_into_to_from_converts_enums() { | ||
157 | check_convert_into_to_from( | ||
158 | r#" | ||
159 | enum Thing { | ||
160 | Foo(String), | ||
161 | Bar(String) | ||
162 | } | ||
163 | |||
164 | impl $0core::convert::Into<String> for Thing { | ||
165 | fn into(self) -> String { | ||
166 | match self { | ||
167 | Self::Foo(s) => s, | ||
168 | Self::Bar(s) => s | ||
169 | } | ||
170 | } | ||
171 | } | ||
172 | "#, | ||
173 | r#" | ||
174 | enum Thing { | ||
175 | Foo(String), | ||
176 | Bar(String) | ||
177 | } | ||
178 | |||
179 | impl From<Thing> for String { | ||
180 | fn from(val: Thing) -> Self { | ||
181 | match val { | ||
182 | Thing::Foo(s) => s, | ||
183 | Thing::Bar(s) => s | ||
184 | } | ||
185 | } | ||
186 | } | ||
187 | "#, | ||
188 | ) | ||
189 | } | ||
190 | |||
191 | #[test] | ||
192 | fn convert_into_to_from_on_enum_with_lifetimes() { | ||
193 | check_convert_into_to_from( | ||
194 | r#" | ||
195 | enum Thing<'a> { | ||
196 | Foo(&'a str), | ||
197 | Bar(&'a str) | ||
198 | } | ||
199 | |||
200 | impl<'a> $0core::convert::Into<&'a str> for Thing<'a> { | ||
201 | fn into(self) -> &'a str { | ||
202 | match self { | ||
203 | Self::Foo(s) => s, | ||
204 | Self::Bar(s) => s | ||
205 | } | ||
206 | } | ||
207 | } | ||
208 | "#, | ||
209 | r#" | ||
210 | enum Thing<'a> { | ||
211 | Foo(&'a str), | ||
212 | Bar(&'a str) | ||
213 | } | ||
214 | |||
215 | impl<'a> From<Thing<'a>> for &'a str { | ||
216 | fn from(val: Thing<'a>) -> Self { | ||
217 | match val { | ||
218 | Thing::Foo(s) => s, | ||
219 | Thing::Bar(s) => s | ||
220 | } | ||
221 | } | ||
222 | } | ||
223 | "#, | ||
224 | ) | ||
225 | } | ||
226 | |||
227 | #[test] | ||
228 | fn convert_into_to_from_works_on_references() { | ||
229 | check_convert_into_to_from( | ||
230 | r#" | ||
231 | struct Thing(String); | ||
232 | |||
233 | impl $0core::convert::Into<String> for &Thing { | ||
234 | fn into(self) -> Thing { | ||
235 | self.0.clone() | ||
236 | } | ||
237 | } | ||
238 | "#, | ||
239 | r#" | ||
240 | struct Thing(String); | ||
241 | |||
242 | impl From<&Thing> for String { | ||
243 | fn from(val: &Thing) -> Self { | ||
244 | val.0.clone() | ||
245 | } | ||
246 | } | ||
247 | "#, | ||
248 | ) | ||
249 | } | ||
250 | |||
251 | #[test] | ||
252 | fn convert_into_to_from_works_on_qualified_structs() { | ||
253 | check_convert_into_to_from( | ||
254 | r#" | ||
255 | mod things { | ||
256 | pub struct Thing(String); | ||
257 | pub struct BetterThing(String); | ||
258 | } | ||
259 | |||
260 | impl $0core::convert::Into<things::BetterThing> for &things::Thing { | ||
261 | fn into(self) -> Thing { | ||
262 | things::BetterThing(self.0.clone()) | ||
263 | } | ||
264 | } | ||
265 | "#, | ||
266 | r#" | ||
267 | mod things { | ||
268 | pub struct Thing(String); | ||
269 | pub struct BetterThing(String); | ||
270 | } | ||
271 | |||
272 | impl From<&things::Thing> for things::BetterThing { | ||
273 | fn from(val: &things::Thing) -> Self { | ||
274 | things::BetterThing(val.0.clone()) | ||
275 | } | ||
276 | } | ||
277 | "#, | ||
278 | ) | ||
279 | } | ||
280 | |||
281 | #[test] | ||
282 | fn convert_into_to_from_works_on_qualified_enums() { | ||
283 | check_convert_into_to_from( | ||
284 | r#" | ||
285 | mod things { | ||
286 | pub enum Thing { | ||
287 | A(String) | ||
288 | } | ||
289 | pub struct BetterThing { | ||
290 | B(String) | ||
291 | } | ||
292 | } | ||
293 | |||
294 | impl $0core::convert::Into<things::BetterThing> for &things::Thing { | ||
295 | fn into(self) -> Thing { | ||
296 | match self { | ||
297 | Self::A(s) => things::BetterThing::B(s) | ||
298 | } | ||
299 | } | ||
300 | } | ||
301 | "#, | ||
302 | r#" | ||
303 | mod things { | ||
304 | pub enum Thing { | ||
305 | A(String) | ||
306 | } | ||
307 | pub struct BetterThing { | ||
308 | B(String) | ||
309 | } | ||
310 | } | ||
311 | |||
312 | impl From<&things::Thing> for things::BetterThing { | ||
313 | fn from(val: &things::Thing) -> Self { | ||
314 | match val { | ||
315 | things::Thing::A(s) => things::BetterThing::B(s) | ||
316 | } | ||
317 | } | ||
318 | } | ||
319 | "#, | ||
320 | ) | ||
321 | } | ||
322 | |||
323 | #[test] | ||
324 | fn convert_into_to_from_not_applicable_on_any_trait_named_into() { | ||
325 | check_assist_not_applicable( | ||
326 | r#" | ||
327 | pub trait Into<T> {{ | ||
328 | pub fn into(self) -> T; | ||
329 | }} | ||
330 | |||
331 | struct Thing { | ||
332 | a: String, | ||
333 | } | ||
334 | |||
335 | impl $0Into<Thing> for String { | ||
336 | fn into(self) -> Thing { | ||
337 | Thing { | ||
338 | a: self | ||
339 | } | ||
340 | } | ||
341 | } | ||
342 | "#, | ||
343 | ); | ||
344 | } | ||
345 | |||
346 | fn check_convert_into_to_from(before: &str, after: &str) { | ||
347 | let before = &format!("//- /main.rs crate:main deps:core{}{}", before, FamousDefs::FIXTURE); | ||
348 | check_assist(convert_into_to_from, before, after); | ||
349 | } | ||
350 | |||
351 | fn check_assist_not_applicable(before: &str) { | ||
352 | let before = &format!("//- /main.rs crate:main deps:core{}{}", before, FamousDefs::FIXTURE); | ||
353 | crate::tests::check_assist_not_applicable(convert_into_to_from, before); | ||
354 | } | ||
355 | } | ||
diff --git a/crates/ide_assists/src/lib.rs b/crates/ide_assists/src/lib.rs index 3d1dcef4c..3e2c82dac 100644 --- a/crates/ide_assists/src/lib.rs +++ b/crates/ide_assists/src/lib.rs | |||
@@ -117,6 +117,7 @@ mod handlers { | |||
117 | mod convert_integer_literal; | 117 | mod convert_integer_literal; |
118 | mod convert_comment_block; | 118 | mod convert_comment_block; |
119 | mod convert_iter_for_each_to_for; | 119 | mod convert_iter_for_each_to_for; |
120 | mod convert_into_to_from; | ||
120 | mod early_return; | 121 | mod early_return; |
121 | mod expand_glob_import; | 122 | mod expand_glob_import; |
122 | mod extract_function; | 123 | mod extract_function; |
@@ -185,6 +186,7 @@ mod handlers { | |||
185 | convert_integer_literal::convert_integer_literal, | 186 | convert_integer_literal::convert_integer_literal, |
186 | convert_comment_block::convert_comment_block, | 187 | convert_comment_block::convert_comment_block, |
187 | convert_iter_for_each_to_for::convert_iter_for_each_to_for, | 188 | convert_iter_for_each_to_for::convert_iter_for_each_to_for, |
189 | convert_into_to_from::convert_into_to_from, | ||
188 | early_return::convert_to_guarded_return, | 190 | early_return::convert_to_guarded_return, |
189 | expand_glob_import::expand_glob_import, | 191 | expand_glob_import::expand_glob_import, |
190 | extract_struct_from_enum_variant::extract_struct_from_enum_variant, | 192 | extract_struct_from_enum_variant::extract_struct_from_enum_variant, |
diff --git a/crates/ide_assists/src/tests/generated.rs b/crates/ide_assists/src/tests/generated.rs index 03b7fb366..27a22ca10 100644 --- a/crates/ide_assists/src/tests/generated.rs +++ b/crates/ide_assists/src/tests/generated.rs | |||
@@ -206,6 +206,38 @@ const _: i32 = 0b1010; | |||
206 | } | 206 | } |
207 | 207 | ||
208 | #[test] | 208 | #[test] |
209 | fn doctest_convert_into_to_from() { | ||
210 | check_doc_test( | ||
211 | "convert_into_to_from", | ||
212 | r#####" | ||
213 | //- /lib.rs crate:core | ||
214 | pub mod convert { pub trait Into<T> { pub fn into(self) -> T; } } | ||
215 | //- /lib.rs crate:main deps:core | ||
216 | use core::convert::Into; | ||
217 | impl $0Into<Thing> for usize { | ||
218 | fn into(self) -> Thing { | ||
219 | Thing { | ||
220 | b: self.to_string(), | ||
221 | a: self | ||
222 | } | ||
223 | } | ||
224 | } | ||
225 | "#####, | ||
226 | r#####" | ||
227 | use core::convert::Into; | ||
228 | impl From<usize> for Thing { | ||
229 | fn from(val: usize) -> Self { | ||
230 | Thing { | ||
231 | b: val.to_string(), | ||
232 | a: val | ||
233 | } | ||
234 | } | ||
235 | } | ||
236 | "#####, | ||
237 | ) | ||
238 | } | ||
239 | |||
240 | #[test] | ||
209 | fn doctest_convert_iter_for_each_to_for() { | 241 | fn doctest_convert_iter_for_each_to_for() { |
210 | check_doc_test( | 242 | check_doc_test( |
211 | "convert_iter_for_each_to_for", | 243 | "convert_iter_for_each_to_for", |
diff --git a/crates/ide_db/src/helpers.rs b/crates/ide_db/src/helpers.rs index 9992a92bd..66798ea3a 100644 --- a/crates/ide_db/src/helpers.rs +++ b/crates/ide_db/src/helpers.rs | |||
@@ -93,6 +93,10 @@ impl FamousDefs<'_, '_> { | |||
93 | self.find_trait("core:convert:From") | 93 | self.find_trait("core:convert:From") |
94 | } | 94 | } |
95 | 95 | ||
96 | pub fn core_convert_Into(&self) -> Option<Trait> { | ||
97 | self.find_trait("core:convert:Into") | ||
98 | } | ||
99 | |||
96 | pub fn core_option_Option(&self) -> Option<Enum> { | 100 | pub fn core_option_Option(&self) -> Option<Enum> { |
97 | self.find_enum("core:option:Option") | 101 | self.find_enum("core:option:Option") |
98 | } | 102 | } |
diff --git a/crates/ide_db/src/helpers/famous_defs_fixture.rs b/crates/ide_db/src/helpers/famous_defs_fixture.rs index d3464ae17..4d79e064e 100644 --- a/crates/ide_db/src/helpers/famous_defs_fixture.rs +++ b/crates/ide_db/src/helpers/famous_defs_fixture.rs | |||
@@ -14,6 +14,10 @@ pub mod convert { | |||
14 | pub trait From<T> { | 14 | pub trait From<T> { |
15 | fn from(t: T) -> Self; | 15 | fn from(t: T) -> Self; |
16 | } | 16 | } |
17 | |||
18 | pub trait Into<T> { | ||
19 | pub fn into(self) -> T; | ||
20 | } | ||
17 | } | 21 | } |
18 | 22 | ||
19 | pub mod default { | 23 | pub mod default { |
@@ -120,7 +124,7 @@ pub mod option { | |||
120 | pub mod prelude { | 124 | pub mod prelude { |
121 | pub use crate::{ | 125 | pub use crate::{ |
122 | cmp::Ord, | 126 | cmp::Ord, |
123 | convert::From, | 127 | convert::{From, Into}, |
124 | default::Default, | 128 | default::Default, |
125 | iter::{IntoIterator, Iterator}, | 129 | iter::{IntoIterator, Iterator}, |
126 | ops::{Fn, FnMut, FnOnce}, | 130 | ops::{Fn, FnMut, FnOnce}, |