aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty/src/traits
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2019-12-21 14:00:44 +0000
committerFlorian Diebold <[email protected]>2019-12-22 23:08:03 +0000
commit4053fcfca0e33f133c53fa755c1b1bcc0b4c11bb (patch)
tree6a77ae7692757830e4c0f5966824b6cd6979d4a2 /crates/ra_hir_ty/src/traits
parent6b5efe5bdab160278469417734f4bb619c7bac61 (diff)
Introduce our own Chalk TypeFamily, instead of using ChalkIr
It's not very different, except we can directly use Salsa IDs instead of casting them. This means we need to refactor the handling of errors to get rid of UNKNOWN_TRAIT though.
Diffstat (limited to 'crates/ra_hir_ty/src/traits')
-rw-r--r--crates/ra_hir_ty/src/traits/builtin.rs49
-rw-r--r--crates/ra_hir_ty/src/traits/chalk.rs156
2 files changed, 122 insertions, 83 deletions
diff --git a/crates/ra_hir_ty/src/traits/builtin.rs b/crates/ra_hir_ty/src/traits/builtin.rs
index cd587a338..dd41176f0 100644
--- a/crates/ra_hir_ty/src/traits/builtin.rs
+++ b/crates/ra_hir_ty/src/traits/builtin.rs
@@ -28,24 +28,24 @@ pub(super) fn get_builtin_impls(
28 trait_: TraitId, 28 trait_: TraitId,
29 mut callback: impl FnMut(Impl), 29 mut callback: impl FnMut(Impl),
30) { 30) {
31 // Note: since impl_datum needs to be infallible, we need to make sure here
32 // that we have all prerequisites to build the respective impls.
31 if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Closure { def, expr }, .. }) = ty { 33 if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Closure { def, expr }, .. }) = ty {
32 for &fn_trait in [super::FnTrait::FnOnce, super::FnTrait::FnMut, super::FnTrait::Fn].iter() 34 for &fn_trait in [super::FnTrait::FnOnce, super::FnTrait::FnMut, super::FnTrait::Fn].iter()
33 { 35 {
34 if let Some(actual_trait) = get_fn_trait(db, krate, fn_trait) { 36 if let Some(actual_trait) = get_fn_trait(db, krate, fn_trait) {
35 if trait_ == actual_trait { 37 if trait_ == actual_trait {
36 let impl_ = super::ClosureFnTraitImplData { def: *def, expr: *expr, fn_trait }; 38 let impl_ = super::ClosureFnTraitImplData { def: *def, expr: *expr, fn_trait };
37 callback(Impl::ClosureFnTraitImpl(impl_)); 39 if check_closure_fn_trait_impl_prerequisites(db, krate, impl_) {
40 callback(Impl::ClosureFnTraitImpl(impl_));
41 }
38 } 42 }
39 } 43 }
40 } 44 }
41 } 45 }
42} 46}
43 47
44pub(super) fn impl_datum( 48pub(super) fn impl_datum(db: &impl HirDatabase, krate: CrateId, impl_: Impl) -> BuiltinImplData {
45 db: &impl HirDatabase,
46 krate: CrateId,
47 impl_: Impl,
48) -> Option<BuiltinImplData> {
49 match impl_ { 49 match impl_ {
50 Impl::ImplBlock(_) => unreachable!(), 50 Impl::ImplBlock(_) => unreachable!(),
51 Impl::ClosureFnTraitImpl(data) => closure_fn_trait_impl_datum(db, krate, data), 51 Impl::ClosureFnTraitImpl(data) => closure_fn_trait_impl_datum(db, krate, data),
@@ -65,21 +65,38 @@ pub(super) fn associated_ty_value(
65 } 65 }
66} 66}
67 67
68fn check_closure_fn_trait_impl_prerequisites(
69 db: &impl HirDatabase,
70 krate: CrateId,
71 data: super::ClosureFnTraitImplData,
72) -> bool {
73 // the respective Fn/FnOnce/FnMut trait needs to exist
74 if get_fn_trait(db, krate, data.fn_trait).is_none() {
75 return false;
76 }
77
78 // FIXME: there are more assumptions that we should probably check here:
79 // the traits having no type params, FnOnce being a supertrait
80
81 // the FnOnce trait needs to exist and have an assoc type named Output
82 let fn_once_trait = match get_fn_trait(db, krate, super::FnTrait::FnOnce) {
83 Some(t) => t,
84 None => return false,
85 };
86 db.trait_data(fn_once_trait).associated_type_by_name(&name![Output]).is_some()
87}
88
68fn closure_fn_trait_impl_datum( 89fn closure_fn_trait_impl_datum(
69 db: &impl HirDatabase, 90 db: &impl HirDatabase,
70 krate: CrateId, 91 krate: CrateId,
71 data: super::ClosureFnTraitImplData, 92 data: super::ClosureFnTraitImplData,
72) -> Option<BuiltinImplData> { 93) -> BuiltinImplData {
73 // for some closure |X, Y| -> Z: 94 // for some closure |X, Y| -> Z:
74 // impl<T, U, V> Fn<(T, U)> for closure<fn(T, U) -> V> { Output = V } 95 // impl<T, U, V> Fn<(T, U)> for closure<fn(T, U) -> V> { Output = V }
75 96
76 let trait_ = get_fn_trait(db, krate, data.fn_trait)?; // get corresponding fn trait 97 let trait_ = get_fn_trait(db, krate, data.fn_trait) // get corresponding fn trait
77 98 // the existence of the Fn trait has been checked before
78 // validate FnOnce trait, since we need it in the assoc ty value definition 99 .expect("fn trait for closure impl missing");
79 // and don't want to return a valid value only to find out later that FnOnce
80 // is broken
81 let fn_once_trait = get_fn_trait(db, krate, super::FnTrait::FnOnce)?;
82 let _output = db.trait_data(fn_once_trait).associated_type_by_name(&name![Output])?;
83 100
84 let num_args: u16 = match &db.body(data.def.into())[data.expr] { 101 let num_args: u16 = match &db.body(data.def.into())[data.expr] {
85 Expr::Lambda { args, .. } => args.len() as u16, 102 Expr::Lambda { args, .. } => args.len() as u16,
@@ -107,12 +124,12 @@ fn closure_fn_trait_impl_datum(
107 124
108 let output_ty_id = AssocTyValue::ClosureFnTraitImplOutput(data.clone()); 125 let output_ty_id = AssocTyValue::ClosureFnTraitImplOutput(data.clone());
109 126
110 Some(BuiltinImplData { 127 BuiltinImplData {
111 num_vars: num_args as usize + 1, 128 num_vars: num_args as usize + 1,
112 trait_ref, 129 trait_ref,
113 where_clauses: Vec::new(), 130 where_clauses: Vec::new(),
114 assoc_ty_values: vec![output_ty_id], 131 assoc_ty_values: vec![output_ty_id],
115 }) 132 }
116} 133}
117 134
118fn closure_fn_trait_output_assoc_ty_value( 135fn closure_fn_trait_output_assoc_ty_value(
diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs
index d53d3fdeb..9e38337e5 100644
--- a/crates/ra_hir_ty/src/traits/chalk.rs
+++ b/crates/ra_hir_ty/src/traits/chalk.rs
@@ -1,5 +1,5 @@
1//! Conversion code from/to Chalk. 1//! Conversion code from/to Chalk.
2use std::sync::Arc; 2use std::{fmt, sync::Arc};
3 3
4use log::debug; 4use log::debug;
5 5
@@ -17,7 +17,73 @@ use crate::{
17 ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk, 17 ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk,
18}; 18};
19 19
20pub type TypeFamily = chalk_ir::family::ChalkIr; 20#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)]
21pub struct TypeFamily {}
22
23impl chalk_ir::family::TypeFamily for TypeFamily {
24 type InternedType = Box<chalk_ir::TyData<Self>>;
25 type InternedLifetime = chalk_ir::LifetimeData<Self>;
26 type InternedParameter = chalk_ir::ParameterData<Self>;
27 type DefId = InternId;
28
29 // FIXME: implement these
30 fn debug_struct_id(
31 _type_kind_id: chalk_ir::StructId<Self>,
32 _fmt: &mut fmt::Formatter<'_>,
33 ) -> Option<fmt::Result> {
34 None
35 }
36
37 fn debug_trait_id(
38 _type_kind_id: chalk_ir::TraitId<Self>,
39 _fmt: &mut fmt::Formatter<'_>,
40 ) -> Option<fmt::Result> {
41 None
42 }
43
44 fn debug_assoc_type_id(
45 _id: chalk_ir::AssocTypeId<Self>,
46 _fmt: &mut fmt::Formatter<'_>,
47 ) -> Option<fmt::Result> {
48 None
49 }
50
51 fn debug_projection(
52 _projection: &chalk_ir::ProjectionTy<Self>,
53 _fmt: &mut fmt::Formatter<'_>,
54 ) -> Option<fmt::Result> {
55 None
56 }
57
58 fn intern_ty(ty: chalk_ir::TyData<Self>) -> Box<chalk_ir::TyData<Self>> {
59 Box::new(ty)
60 }
61
62 fn ty_data(ty: &Box<chalk_ir::TyData<Self>>) -> &chalk_ir::TyData<Self> {
63 ty
64 }
65
66 fn intern_lifetime(lifetime: chalk_ir::LifetimeData<Self>) -> chalk_ir::LifetimeData<Self> {
67 lifetime
68 }
69
70 fn lifetime_data(lifetime: &chalk_ir::LifetimeData<Self>) -> &chalk_ir::LifetimeData<Self> {
71 lifetime
72 }
73
74 fn intern_parameter(parameter: chalk_ir::ParameterData<Self>) -> chalk_ir::ParameterData<Self> {
75 parameter
76 }
77
78 fn parameter_data(parameter: &chalk_ir::ParameterData<Self>) -> &chalk_ir::ParameterData<Self> {
79 parameter
80 }
81}
82
83impl chalk_ir::family::HasTypeFamily for TypeFamily {
84 type TypeFamily = Self;
85}
86
21pub type AssocTypeId = chalk_ir::AssocTypeId<TypeFamily>; 87pub type AssocTypeId = chalk_ir::AssocTypeId<TypeFamily>;
22pub type AssociatedTyDatum = chalk_rust_ir::AssociatedTyDatum<TypeFamily>; 88pub type AssociatedTyDatum = chalk_rust_ir::AssociatedTyDatum<TypeFamily>;
23pub type TraitId = chalk_ir::TraitId<TypeFamily>; 89pub type TraitId = chalk_ir::TraitId<TypeFamily>;
@@ -29,9 +95,6 @@ pub type ImplDatum = chalk_rust_ir::ImplDatum<TypeFamily>;
29pub type AssociatedTyValueId = chalk_rust_ir::AssociatedTyValueId; 95pub type AssociatedTyValueId = chalk_rust_ir::AssociatedTyValueId;
30pub type AssociatedTyValue = chalk_rust_ir::AssociatedTyValue<TypeFamily>; 96pub type AssociatedTyValue = chalk_rust_ir::AssociatedTyValue<TypeFamily>;
31 97
32/// This represents a trait whose name we could not resolve.
33const UNKNOWN_TRAIT: TraitId = chalk_ir::TraitId(chalk_ir::RawId { index: u32::max_value() });
34
35pub(super) trait ToChalk { 98pub(super) trait ToChalk {
36 type Chalk; 99 type Chalk;
37 fn to_chalk(self, db: &impl HirDatabase) -> Self::Chalk; 100 fn to_chalk(self, db: &impl HirDatabase) -> Self::Chalk;
@@ -162,11 +225,11 @@ impl ToChalk for hir_def::TraitId {
162 type Chalk = TraitId; 225 type Chalk = TraitId;
163 226
164 fn to_chalk(self, _db: &impl HirDatabase) -> TraitId { 227 fn to_chalk(self, _db: &impl HirDatabase) -> TraitId {
165 chalk_ir::TraitId(id_to_chalk(self)) 228 chalk_ir::TraitId(self.as_intern_id())
166 } 229 }
167 230
168 fn from_chalk(_db: &impl HirDatabase, trait_id: TraitId) -> hir_def::TraitId { 231 fn from_chalk(_db: &impl HirDatabase, trait_id: TraitId) -> hir_def::TraitId {
169 id_from_chalk(trait_id.0) 232 InternKey::from_intern_id(trait_id.0)
170 } 233 }
171} 234}
172 235
@@ -215,11 +278,11 @@ impl ToChalk for TypeAliasId {
215 type Chalk = AssocTypeId; 278 type Chalk = AssocTypeId;
216 279
217 fn to_chalk(self, _db: &impl HirDatabase) -> AssocTypeId { 280 fn to_chalk(self, _db: &impl HirDatabase) -> AssocTypeId {
218 chalk_ir::AssocTypeId(id_to_chalk(self)) 281 chalk_ir::AssocTypeId(self.as_intern_id())
219 } 282 }
220 283
221 fn from_chalk(_db: &impl HirDatabase, type_alias_id: AssocTypeId) -> TypeAliasId { 284 fn from_chalk(_db: &impl HirDatabase, type_alias_id: AssocTypeId) -> TypeAliasId {
222 id_from_chalk(type_alias_id.0) 285 InternKey::from_intern_id(type_alias_id.0)
223 } 286 }
224} 287}
225 288
@@ -250,13 +313,7 @@ impl ToChalk for GenericPredicate {
250 }), 313 }),
251 0, 314 0,
252 ), 315 ),
253 GenericPredicate::Error => { 316 GenericPredicate::Error => panic!("tried passing GenericPredicate::Error to Chalk"),
254 let impossible_trait_ref = chalk_ir::TraitRef {
255 trait_id: UNKNOWN_TRAIT,
256 parameters: vec![Ty::Unknown.to_chalk(db).cast()],
257 };
258 make_binders(chalk_ir::WhereClause::Implemented(impossible_trait_ref), 0)
259 }
260 } 317 }
261 } 318 }
262 319
@@ -266,10 +323,6 @@ impl ToChalk for GenericPredicate {
266 ) -> GenericPredicate { 323 ) -> GenericPredicate {
267 match where_clause.value { 324 match where_clause.value {
268 chalk_ir::WhereClause::Implemented(tr) => { 325 chalk_ir::WhereClause::Implemented(tr) => {
269 if tr.trait_id == UNKNOWN_TRAIT {
270 // FIXME we need an Error enum on the Chalk side to avoid this
271 return GenericPredicate::Error;
272 }
273 GenericPredicate::Implemented(from_chalk(db, tr)) 326 GenericPredicate::Implemented(from_chalk(db, tr))
274 } 327 }
275 chalk_ir::WhereClause::ProjectionEq(projection_eq) => { 328 chalk_ir::WhereClause::ProjectionEq(projection_eq) => {
@@ -460,9 +513,8 @@ fn convert_where_clauses(
460 let mut result = Vec::with_capacity(generic_predicates.len()); 513 let mut result = Vec::with_capacity(generic_predicates.len());
461 for pred in generic_predicates.iter() { 514 for pred in generic_predicates.iter() {
462 if pred.is_error() { 515 if pred.is_error() {
463 // HACK: Return just the single predicate (which is always false 516 // skip errored predicates completely
464 // anyway), otherwise Chalk can easily get into slow situations 517 continue;
465 return vec![pred.clone().subst(substs).to_chalk(db)];
466 } 518 }
467 result.push(pred.clone().subst(substs).to_chalk(db)); 519 result.push(pred.clone().subst(substs).to_chalk(db));
468 } 520 }
@@ -491,10 +543,11 @@ where
491 parameters: &[Parameter<TypeFamily>], 543 parameters: &[Parameter<TypeFamily>],
492 ) -> Vec<ImplId> { 544 ) -> Vec<ImplId> {
493 debug!("impls_for_trait {:?}", trait_id); 545 debug!("impls_for_trait {:?}", trait_id);
494 if trait_id == UNKNOWN_TRAIT {
495 return Vec::new();
496 }
497 let trait_: hir_def::TraitId = from_chalk(self.db, trait_id); 546 let trait_: hir_def::TraitId = from_chalk(self.db, trait_id);
547
548 // Note: Since we're using impls_for_trait, only impls where the trait
549 // can be resolved should ever reach Chalk. `impl_datum` relies on that
550 // and will panic if the trait can't be resolved.
498 let mut result: Vec<_> = self 551 let mut result: Vec<_> = self
499 .db 552 .db
500 .impls_for_trait(self.krate, trait_.into()) 553 .impls_for_trait(self.krate, trait_.into())
@@ -566,24 +619,6 @@ pub(crate) fn trait_datum_query(
566 trait_id: TraitId, 619 trait_id: TraitId,
567) -> Arc<TraitDatum> { 620) -> Arc<TraitDatum> {
568 debug!("trait_datum {:?}", trait_id); 621 debug!("trait_datum {:?}", trait_id);
569 if trait_id == UNKNOWN_TRAIT {
570 let trait_datum_bound = chalk_rust_ir::TraitDatumBound { where_clauses: Vec::new() };
571
572 let flags = chalk_rust_ir::TraitFlags {
573 auto: false,
574 marker: false,
575 upstream: true,
576 fundamental: false,
577 non_enumerable: true,
578 coinductive: false,
579 };
580 return Arc::new(TraitDatum {
581 id: trait_id,
582 binders: make_binders(trait_datum_bound, 1),
583 flags,
584 associated_ty_ids: vec![],
585 });
586 }
587 let trait_: hir_def::TraitId = from_chalk(db, trait_id); 622 let trait_: hir_def::TraitId = from_chalk(db, trait_id);
588 let trait_data = db.trait_data(trait_); 623 let trait_data = db.trait_data(trait_);
589 debug!("trait {:?} = {:?}", trait_id, trait_data.name); 624 debug!("trait {:?} = {:?}", trait_id, trait_data.name);
@@ -653,9 +688,8 @@ pub(crate) fn impl_datum_query(
653 let impl_: Impl = from_chalk(db, impl_id); 688 let impl_: Impl = from_chalk(db, impl_id);
654 match impl_ { 689 match impl_ {
655 Impl::ImplBlock(impl_block) => impl_block_datum(db, krate, impl_id, impl_block), 690 Impl::ImplBlock(impl_block) => impl_block_datum(db, krate, impl_id, impl_block),
656 _ => builtin::impl_datum(db, krate, impl_).map(|d| Arc::new(d.to_chalk(db))), 691 _ => Arc::new(builtin::impl_datum(db, krate, impl_).to_chalk(db)),
657 } 692 }
658 .unwrap_or_else(invalid_impl_datum)
659} 693}
660 694
661fn impl_block_datum( 695fn impl_block_datum(
@@ -663,8 +697,11 @@ fn impl_block_datum(
663 krate: CrateId, 697 krate: CrateId,
664 chalk_id: ImplId, 698 chalk_id: ImplId,
665 impl_id: hir_def::ImplId, 699 impl_id: hir_def::ImplId,
666) -> Option<Arc<ImplDatum>> { 700) -> Arc<ImplDatum> {
667 let trait_ref = db.impl_trait(impl_id)?; 701 let trait_ref = db
702 .impl_trait(impl_id)
703 // ImplIds for impls where the trait ref can't be resolved should never reach Chalk
704 .expect("invalid impl passed to Chalk");
668 let impl_data = db.impl_data(impl_id); 705 let impl_data = db.impl_data(impl_id);
669 706
670 let generic_params = generics(db, impl_id.into()); 707 let generic_params = generics(db, impl_id.into());
@@ -716,21 +753,6 @@ fn impl_block_datum(
716 polarity, 753 polarity,
717 associated_ty_value_ids, 754 associated_ty_value_ids,
718 }; 755 };
719 Some(Arc::new(impl_datum))
720}
721
722fn invalid_impl_datum() -> Arc<ImplDatum> {
723 let trait_ref = chalk_ir::TraitRef {
724 trait_id: UNKNOWN_TRAIT,
725 parameters: vec![chalk_ir::TyData::BoundVar(0).cast().intern().cast()],
726 };
727 let impl_datum_bound = chalk_rust_ir::ImplDatumBound { trait_ref, where_clauses: Vec::new() };
728 let impl_datum = ImplDatum {
729 binders: make_binders(impl_datum_bound, 1),
730 impl_type: chalk_rust_ir::ImplType::External,
731 polarity: chalk_rust_ir::Polarity::Positive,
732 associated_ty_value_ids: Vec::new(),
733 };
734 Arc::new(impl_datum) 756 Arc::new(impl_datum)
735} 757}
736 758
@@ -786,25 +808,25 @@ fn id_to_chalk<T: InternKey>(salsa_id: T) -> chalk_ir::RawId {
786 808
787impl From<StructId> for crate::TypeCtorId { 809impl From<StructId> for crate::TypeCtorId {
788 fn from(struct_id: StructId) -> Self { 810 fn from(struct_id: StructId) -> Self {
789 id_from_chalk(struct_id.0) 811 InternKey::from_intern_id(struct_id.0)
790 } 812 }
791} 813}
792 814
793impl From<crate::TypeCtorId> for StructId { 815impl From<crate::TypeCtorId> for StructId {
794 fn from(type_ctor_id: crate::TypeCtorId) -> Self { 816 fn from(type_ctor_id: crate::TypeCtorId) -> Self {
795 chalk_ir::StructId(id_to_chalk(type_ctor_id)) 817 chalk_ir::StructId(type_ctor_id.as_intern_id())
796 } 818 }
797} 819}
798 820
799impl From<ImplId> for crate::traits::GlobalImplId { 821impl From<ImplId> for crate::traits::GlobalImplId {
800 fn from(impl_id: ImplId) -> Self { 822 fn from(impl_id: ImplId) -> Self {
801 id_from_chalk(impl_id.0) 823 InternKey::from_intern_id(impl_id.0)
802 } 824 }
803} 825}
804 826
805impl From<crate::traits::GlobalImplId> for ImplId { 827impl From<crate::traits::GlobalImplId> for ImplId {
806 fn from(impl_id: crate::traits::GlobalImplId) -> Self { 828 fn from(impl_id: crate::traits::GlobalImplId) -> Self {
807 chalk_ir::ImplId(id_to_chalk(impl_id)) 829 chalk_ir::ImplId(impl_id.as_intern_id())
808 } 830 }
809} 831}
810 832