aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty/src/traits/chalk.rs
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-02-09 11:35:08 +0000
committerGitHub <[email protected]>2020-02-09 11:35:08 +0000
commit01836a0f35fa163025c64cabe1d0c34bb4f69c92 (patch)
treeaa1a3cf97173b2885f8b6d23002c73196f9a0b61 /crates/ra_hir_ty/src/traits/chalk.rs
parent961a69b88f923d4477ca4f746a793217a0cc8576 (diff)
parenteefe02ce6e1750b771cf99125429358e87485745 (diff)
Merge #3050
3050: Refactor type parameters, implement argument position impl trait r=matklad a=flodiebold I wanted to implement APIT by lowering to type parameters because we need to do that anyway for correctness and don't need Chalk support for it; this grew into some more wide-ranging refactoring of how type parameters are handled :sweat_smile: - use Ty::Bound instead of Ty::Param to represent polymorphism, and explicitly count binders. This gets us closer to Chalk's way of doing things, and means that we now only use Param as a placeholder for an unknown type, e.g. within a generic function. I.e. we're never using Param in a situation where we want to substitute it, and the method to do that is gone; `subst` now always works on bound variables. (This changes how the types of generic functions print; previously, you'd get something like `fn identity<i32>(T) -> T`, but now we display the substituted signature `fn identity<i32>(i32) -> i32`, which I think makes more sense.) - once we do this, it's more natural to represent `Param` by a globally unique ID; the use of indices was mostly to make substituting easier. This also means we fix the bug where `Param` loses its name when going through Chalk. - I would actually like to rename `Param` to `Placeholder` to better reflect its use and get closer to Chalk, but I'll leave that to a follow-up. - introduce a context for type lowering, to allow lowering `impl Trait` to different things depending on where we are. And since we have that, we can also lower type parameters directly to variables instead of placeholders. Also, we'll be able to use this later to collect diagnostics. - implement argument position impl trait by lowering it to type parameters. I've realized that this is necessary to correctly implement it; e.g. consider `fn foo(impl Display) -> impl Something`. It's observable that the return type of e.g. `foo(1u32)` unifies with itself, but doesn't unify with e.g. `foo(1i32)`; so the return type needs to be parameterized by the argument type. This fixes a few bugs as well: - type parameters 'losing' their name when they go through Chalk, as mentioned above (i.e. getting `[missing name]` somewhere) - impl trait not being considered as implementing the super traits (very noticeable for the `db` in RA) - the fact that argument impl trait was only turned into variables when the function got called caused type mismatches when the function was used as a value (fixes a few type mismatches in RA) The one thing I'm not so happy with here is how we're lowering `impl Trait` types to variables; since `TypeRef`s don't have an identity currently, we just count how many of them we have seen while going through the function signature. That's quite fragile though, since we have to do it while desugaring generics and while lowering the type signature, and in the exact same order in both cases. We could consider either giving only `TypeRef::ImplTrait` a local id, or maybe just giving all `TypeRef`s an identity after all (we talked about this before)... Follow-up tasks: - handle return position impl trait; we basically need to create a variable and some trait obligations for that variable - rename `Param` to `Placeholder` Co-authored-by: Florian Diebold <[email protected]> Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates/ra_hir_ty/src/traits/chalk.rs')
-rw-r--r--crates/ra_hir_ty/src/traits/chalk.rs33
1 files changed, 19 insertions, 14 deletions
diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs
index fe9cb556c..4974c565b 100644
--- a/crates/ra_hir_ty/src/traits/chalk.rs
+++ b/crates/ra_hir_ty/src/traits/chalk.rs
@@ -14,7 +14,7 @@ use ra_db::{
14use super::{builtin, AssocTyValue, Canonical, ChalkContext, Impl, Obligation}; 14use super::{builtin, AssocTyValue, Canonical, ChalkContext, Impl, Obligation};
15use crate::{ 15use crate::{
16 db::HirDatabase, display::HirDisplay, utils::generics, ApplicationTy, GenericPredicate, 16 db::HirDatabase, display::HirDisplay, utils::generics, ApplicationTy, GenericPredicate,
17 ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk, 17 ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
18}; 18};
19 19
20#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)] 20#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)]
@@ -142,9 +142,13 @@ impl ToChalk for Ty {
142 let substitution = proj_ty.parameters.to_chalk(db); 142 let substitution = proj_ty.parameters.to_chalk(db);
143 chalk_ir::AliasTy { associated_ty_id, substitution }.cast().intern() 143 chalk_ir::AliasTy { associated_ty_id, substitution }.cast().intern()
144 } 144 }
145 Ty::Param { idx, .. } => { 145 Ty::Param(id) => {
146 PlaceholderIndex { ui: UniverseIndex::ROOT, idx: idx as usize } 146 let interned_id = db.intern_type_param_id(id);
147 .to_ty::<TypeFamily>() 147 PlaceholderIndex {
148 ui: UniverseIndex::ROOT,
149 idx: interned_id.as_intern_id().as_usize(),
150 }
151 .to_ty::<TypeFamily>()
148 } 152 }
149 Ty::Bound(idx) => chalk_ir::TyData::BoundVar(idx as usize).intern(), 153 Ty::Bound(idx) => chalk_ir::TyData::BoundVar(idx as usize).intern(),
150 Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"), 154 Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"),
@@ -177,7 +181,10 @@ impl ToChalk for Ty {
177 }, 181 },
178 chalk_ir::TyData::Placeholder(idx) => { 182 chalk_ir::TyData::Placeholder(idx) => {
179 assert_eq!(idx.ui, UniverseIndex::ROOT); 183 assert_eq!(idx.ui, UniverseIndex::ROOT);
180 Ty::Param { idx: idx.idx as u32, name: crate::Name::missing() } 184 let interned_id = crate::db::GlobalTypeParamId::from_intern_id(
185 crate::salsa::InternId::from(idx.idx),
186 );
187 Ty::Param(db.lookup_intern_type_param_id(interned_id))
181 } 188 }
182 chalk_ir::TyData::Alias(proj) => { 189 chalk_ir::TyData::Alias(proj) => {
183 let associated_ty = from_chalk(db, proj.associated_ty_id); 190 let associated_ty = from_chalk(db, proj.associated_ty_id);
@@ -520,7 +527,7 @@ fn convert_where_clauses(
520 let generic_predicates = db.generic_predicates(def); 527 let generic_predicates = db.generic_predicates(def);
521 let mut result = Vec::with_capacity(generic_predicates.len()); 528 let mut result = Vec::with_capacity(generic_predicates.len());
522 for pred in generic_predicates.iter() { 529 for pred in generic_predicates.iter() {
523 if pred.is_error() { 530 if pred.value.is_error() {
524 // skip errored predicates completely 531 // skip errored predicates completely
525 continue; 532 continue;
526 } 533 }
@@ -709,12 +716,12 @@ fn impl_block_datum(
709 let trait_ref = db 716 let trait_ref = db
710 .impl_trait(impl_id) 717 .impl_trait(impl_id)
711 // ImplIds for impls where the trait ref can't be resolved should never reach Chalk 718 // ImplIds for impls where the trait ref can't be resolved should never reach Chalk
712 .expect("invalid impl passed to Chalk"); 719 .expect("invalid impl passed to Chalk")
720 .value;
713 let impl_data = db.impl_data(impl_id); 721 let impl_data = db.impl_data(impl_id);
714 722
715 let generic_params = generics(db, impl_id.into()); 723 let generic_params = generics(db, impl_id.into());
716 let bound_vars = Substs::bound_vars(&generic_params); 724 let bound_vars = Substs::bound_vars(&generic_params);
717 let trait_ref = trait_ref.subst(&bound_vars);
718 let trait_ = trait_ref.trait_; 725 let trait_ = trait_ref.trait_;
719 let impl_type = if impl_id.lookup(db).container.module(db).krate == krate { 726 let impl_type = if impl_id.lookup(db).container.module(db).krate == krate {
720 chalk_rust_ir::ImplType::Local 727 chalk_rust_ir::ImplType::Local
@@ -789,20 +796,18 @@ fn type_alias_associated_ty_value(
789 _ => panic!("assoc ty value should be in impl"), 796 _ => panic!("assoc ty value should be in impl"),
790 }; 797 };
791 798
792 let trait_ref = db.impl_trait(impl_id).expect("assoc ty value should not exist"); // we don't return any assoc ty values if the impl'd trait can't be resolved 799 let trait_ref = db.impl_trait(impl_id).expect("assoc ty value should not exist").value; // we don't return any assoc ty values if the impl'd trait can't be resolved
793 800
794 let assoc_ty = db 801 let assoc_ty = db
795 .trait_data(trait_ref.trait_) 802 .trait_data(trait_ref.trait_)
796 .associated_type_by_name(&type_alias_data.name) 803 .associated_type_by_name(&type_alias_data.name)
797 .expect("assoc ty value should not exist"); // validated when building the impl data as well 804 .expect("assoc ty value should not exist"); // validated when building the impl data as well
798 let generic_params = generics(db, impl_id.into()); 805 let ty = db.ty(type_alias.into());
799 let bound_vars = Substs::bound_vars(&generic_params); 806 let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty: ty.value.to_chalk(db) };
800 let ty = db.ty(type_alias.into()).subst(&bound_vars);
801 let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty: ty.to_chalk(db) };
802 let value = chalk_rust_ir::AssociatedTyValue { 807 let value = chalk_rust_ir::AssociatedTyValue {
803 impl_id: Impl::ImplBlock(impl_id.into()).to_chalk(db), 808 impl_id: Impl::ImplBlock(impl_id.into()).to_chalk(db),
804 associated_ty_id: assoc_ty.to_chalk(db), 809 associated_ty_id: assoc_ty.to_chalk(db),
805 value: make_binders(value_bound, bound_vars.len()), 810 value: make_binders(value_bound, ty.num_binders),
806 }; 811 };
807 Arc::new(value) 812 Arc::new(value)
808} 813}