aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/ty/traits/chalk.rs
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2019-09-24 22:12:26 +0100
committerGitHub <[email protected]>2019-09-24 22:12:26 +0100
commitc7420ddaaa76741d1eebe393406b38ba5596e54a (patch)
treeff9c2f3c665ef95ebf509dc69ff82d39ec42d176 /crates/ra_hir/src/ty/traits/chalk.rs
parent36fb3f53d712a11b7e3fc4bbd92094d1c8f19522 (diff)
parent6a8670665032f6103ca14e38ed9106126b20063d (diff)
Merge #1845
1845: Closure types r=flodiebold a=flodiebold This adds types for closures and makes them implement the `Fn` traits (we don't currently care or try to infer `Fn` vs. `FnMut` vs. `FnOnce`; this would require move analysis, I think). This requires some changes in Chalk; one is that we need to know the self type when asked for impls, so we can synthesize `Fn` trait impls for closures; but also there's a problem that prevents us from normalizing the closure output type correctly that I _think_ will be fixed on the Chalk side (basically, we ask too early and try to solve `Normalize(<?1 as FnOnce<(u32,)>>::Output => ?0)` -- note the variable in the self type -- and instead of an ambiguous answer, we get back that it can't be solved, so we don't try again. Niko mentioned he's making all goals where the self type is unconstrained flounder, which I think would mean this would be ambiguous). Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates/ra_hir/src/ty/traits/chalk.rs')
-rw-r--r--crates/ra_hir/src/ty/traits/chalk.rs136
1 files changed, 126 insertions, 10 deletions
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs
index 462156021..d83706f86 100644
--- a/crates/ra_hir/src/ty/traits/chalk.rs
+++ b/crates/ra_hir/src/ty/traits/chalk.rs
@@ -12,7 +12,7 @@ use chalk_rust_ir::{AssociatedTyDatum, ImplDatum, StructDatum, TraitDatum};
12use ra_db::salsa::{InternId, InternKey}; 12use ra_db::salsa::{InternId, InternKey};
13use test_utils::tested_by; 13use test_utils::tested_by;
14 14
15use super::{Canonical, ChalkContext, Obligation}; 15use super::{Canonical, ChalkContext, Impl, Obligation};
16use crate::{ 16use crate::{
17 db::HirDatabase, 17 db::HirDatabase,
18 generics::GenericDef, 18 generics::GenericDef,
@@ -111,7 +111,7 @@ impl ToChalk for Ty {
111 } 111 }
112 chalk_ir::Ty::ForAll(_) => unimplemented!(), 112 chalk_ir::Ty::ForAll(_) => unimplemented!(),
113 chalk_ir::Ty::BoundVar(idx) => Ty::Bound(idx as u32), 113 chalk_ir::Ty::BoundVar(idx) => Ty::Bound(idx as u32),
114 chalk_ir::Ty::InferenceVar(_iv) => panic!("unexpected chalk infer ty"), 114 chalk_ir::Ty::InferenceVar(_iv) => Ty::Unknown,
115 } 115 }
116 } 116 }
117} 117}
@@ -175,15 +175,15 @@ impl ToChalk for TypeCtor {
175 } 175 }
176} 176}
177 177
178impl ToChalk for ImplBlock { 178impl ToChalk for Impl {
179 type Chalk = chalk_ir::ImplId; 179 type Chalk = chalk_ir::ImplId;
180 180
181 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::ImplId { 181 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::ImplId {
182 db.intern_impl_block(self).into() 182 db.intern_impl(self).into()
183 } 183 }
184 184
185 fn from_chalk(db: &impl HirDatabase, impl_id: chalk_ir::ImplId) -> ImplBlock { 185 fn from_chalk(db: &impl HirDatabase, impl_id: chalk_ir::ImplId) -> Impl {
186 db.lookup_intern_impl_block(impl_id.into()) 186 db.lookup_intern_impl(impl_id.into())
187 } 187 }
188} 188}
189 189
@@ -388,19 +388,36 @@ where
388 fn impls_for_trait( 388 fn impls_for_trait(
389 &self, 389 &self,
390 trait_id: chalk_ir::TraitId, 390 trait_id: chalk_ir::TraitId,
391 _parameters: &[Parameter], 391 parameters: &[Parameter],
392 ) -> Vec<ImplId> { 392 ) -> Vec<ImplId> {
393 debug!("impls_for_trait {:?}", trait_id); 393 debug!("impls_for_trait {:?}", trait_id);
394 if trait_id == UNKNOWN_TRAIT { 394 if trait_id == UNKNOWN_TRAIT {
395 return Vec::new(); 395 return Vec::new();
396 } 396 }
397 let trait_: Trait = from_chalk(self.db, trait_id); 397 let trait_: Trait = from_chalk(self.db, trait_id);
398 let result: Vec<_> = self 398 let mut result: Vec<_> = self
399 .db 399 .db
400 .impls_for_trait(self.krate, trait_) 400 .impls_for_trait(self.krate, trait_)
401 .iter() 401 .iter()
402 .map(|impl_block| impl_block.to_chalk(self.db)) 402 .copied()
403 .map(Impl::ImplBlock)
404 .map(|impl_| impl_.to_chalk(self.db))
403 .collect(); 405 .collect();
406
407 let ty: Ty = from_chalk(self.db, parameters[0].assert_ty_ref().clone());
408 if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Closure { def, expr }, .. }) = ty {
409 for &fn_trait in
410 [super::FnTrait::FnOnce, super::FnTrait::FnMut, super::FnTrait::Fn].iter()
411 {
412 if let Some(actual_trait) = get_fn_trait(self.db, self.krate, fn_trait) {
413 if trait_ == actual_trait {
414 let impl_ = super::ClosureFnTraitImplData { def, expr, fn_trait };
415 result.push(Impl::ClosureFnTraitImpl(impl_).to_chalk(self.db));
416 }
417 }
418 }
419 }
420
404 debug!("impls_for_trait returned {} impls", result.len()); 421 debug!("impls_for_trait returned {} impls", result.len());
405 result 422 result
406 } 423 }
@@ -571,6 +588,10 @@ pub(crate) fn struct_datum_query(
571 type_alias.krate(db) != Some(krate), 588 type_alias.krate(db) != Some(krate),
572 ) 589 )
573 } 590 }
591 TypeCtor::Closure { def, .. } => {
592 let upstream = def.krate(db) != Some(krate);
593 (1, vec![], upstream)
594 }
574 }; 595 };
575 let flags = chalk_rust_ir::StructFlags { 596 let flags = chalk_rust_ir::StructFlags {
576 upstream, 597 upstream,
@@ -598,7 +619,21 @@ pub(crate) fn impl_datum_query(
598) -> Arc<ImplDatum> { 619) -> Arc<ImplDatum> {
599 let _p = ra_prof::profile("impl_datum"); 620 let _p = ra_prof::profile("impl_datum");
600 debug!("impl_datum {:?}", impl_id); 621 debug!("impl_datum {:?}", impl_id);
601 let impl_block: ImplBlock = from_chalk(db, impl_id); 622 let impl_: Impl = from_chalk(db, impl_id);
623 match impl_ {
624 Impl::ImplBlock(impl_block) => impl_block_datum(db, krate, impl_id, impl_block),
625 Impl::ClosureFnTraitImpl(data) => {
626 closure_fn_trait_impl_datum(db, krate, impl_id, data).unwrap_or_else(invalid_impl_datum)
627 }
628 }
629}
630
631fn impl_block_datum(
632 db: &impl HirDatabase,
633 krate: Crate,
634 impl_id: ImplId,
635 impl_block: ImplBlock,
636) -> Arc<ImplDatum> {
602 let generic_params = impl_block.generic_params(db); 637 let generic_params = impl_block.generic_params(db);
603 let bound_vars = Substs::bound_vars(&generic_params); 638 let bound_vars = Substs::bound_vars(&generic_params);
604 let trait_ref = impl_block 639 let trait_ref = impl_block
@@ -657,6 +692,87 @@ pub(crate) fn impl_datum_query(
657 Arc::new(impl_datum) 692 Arc::new(impl_datum)
658} 693}
659 694
695fn invalid_impl_datum() -> Arc<ImplDatum> {
696 let trait_ref = chalk_ir::TraitRef {
697 trait_id: UNKNOWN_TRAIT,
698 parameters: vec![chalk_ir::Ty::BoundVar(0).cast()],
699 };
700 let impl_datum_bound = chalk_rust_ir::ImplDatumBound {
701 trait_ref: chalk_rust_ir::PolarizedTraitRef::Positive(trait_ref),
702 where_clauses: Vec::new(),
703 associated_ty_values: Vec::new(),
704 impl_type: chalk_rust_ir::ImplType::External,
705 };
706 let impl_datum = ImplDatum { binders: make_binders(impl_datum_bound, 1) };
707 Arc::new(impl_datum)
708}
709
710fn closure_fn_trait_impl_datum(
711 db: &impl HirDatabase,
712 krate: Crate,
713 impl_id: ImplId,
714 data: super::ClosureFnTraitImplData,
715) -> Option<Arc<ImplDatum>> {
716 // for some closure |X, Y| -> Z:
717 // impl<T, U, V> Fn<(T, U)> for closure<fn(T, U) -> V> { Output = V }
718
719 let fn_once_trait = get_fn_trait(db, krate, super::FnTrait::FnOnce)?;
720 let trait_ = get_fn_trait(db, krate, data.fn_trait)?; // get corresponding fn trait
721
722 let num_args: u16 = match &db.body_hir(data.def)[data.expr] {
723 crate::expr::Expr::Lambda { args, .. } => args.len() as u16,
724 _ => {
725 log::warn!("closure for closure type {:?} not found", data);
726 0
727 }
728 };
729
730 let arg_ty = Ty::apply(
731 TypeCtor::Tuple { cardinality: num_args },
732 (0..num_args).map(|i| Ty::Bound(i.into())).collect::<Vec<_>>().into(),
733 );
734 let output_ty = Ty::Bound(num_args.into());
735 let sig_ty = Ty::apply(
736 TypeCtor::FnPtr { num_args },
737 (0..num_args + 1).map(|i| Ty::Bound(i.into())).collect::<Vec<_>>().into(),
738 );
739
740 let self_ty = Ty::apply_one(TypeCtor::Closure { def: data.def, expr: data.expr }, sig_ty);
741
742 let trait_ref = TraitRef { trait_, substs: vec![self_ty, arg_ty].into() };
743
744 let output_ty_id = fn_once_trait.associated_type_by_name(db, &crate::name::OUTPUT_TYPE)?;
745
746 let output_ty_value = chalk_rust_ir::AssociatedTyValue {
747 associated_ty_id: output_ty_id.to_chalk(db),
748 impl_id,
749 value: make_binders(
750 chalk_rust_ir::AssociatedTyValueBound { ty: output_ty.to_chalk(db) },
751 0,
752 ),
753 };
754
755 let impl_type = chalk_rust_ir::ImplType::External;
756
757 let impl_datum_bound = chalk_rust_ir::ImplDatumBound {
758 trait_ref: chalk_rust_ir::PolarizedTraitRef::Positive(trait_ref.to_chalk(db)),
759 where_clauses: Vec::new(),
760 associated_ty_values: vec![output_ty_value],
761 impl_type,
762 };
763 let impl_datum = ImplDatum { binders: make_binders(impl_datum_bound, num_args as usize + 1) };
764 Some(Arc::new(impl_datum))
765}
766
767fn get_fn_trait(db: &impl HirDatabase, krate: Crate, fn_trait: super::FnTrait) -> Option<Trait> {
768 let lang_items = db.lang_items(krate);
769 let target = lang_items.target(fn_trait.lang_item_name())?;
770 match target {
771 crate::lang_item::LangItemTarget::Trait(t) => Some(*t),
772 _ => None,
773 }
774}
775
660fn id_from_chalk<T: InternKey>(chalk_id: chalk_ir::RawId) -> T { 776fn id_from_chalk<T: InternKey>(chalk_id: chalk_ir::RawId) -> T {
661 T::from_intern_id(InternId::from(chalk_id.index)) 777 T::from_intern_id(InternId::from(chalk_id.index))
662} 778}