diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-09-24 22:12:26 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2019-09-24 22:12:26 +0100 |
commit | c7420ddaaa76741d1eebe393406b38ba5596e54a (patch) | |
tree | ff9c2f3c665ef95ebf509dc69ff82d39ec42d176 /crates | |
parent | 36fb3f53d712a11b7e3fc4bbd92094d1c8f19522 (diff) | |
parent | 6a8670665032f6103ca14e38ed9106126b20063d (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')
-rw-r--r-- | crates/ra_hir/src/code_model.rs | 20 | ||||
-rw-r--r-- | crates/ra_hir/src/db.rs | 6 | ||||
-rw-r--r-- | crates/ra_hir/src/ty.rs | 23 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 63 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 165 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/traits.rs | 44 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/traits/chalk.rs | 136 |
7 files changed, 385 insertions, 72 deletions
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 12399c6ac..99c247a0b 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -551,6 +551,14 @@ impl DefWithBody { | |||
551 | DefWithBody::Static(s) => s.resolver(db), | 551 | DefWithBody::Static(s) => s.resolver(db), |
552 | } | 552 | } |
553 | } | 553 | } |
554 | |||
555 | pub(crate) fn krate(self, db: &impl HirDatabase) -> Option<Crate> { | ||
556 | match self { | ||
557 | DefWithBody::Const(c) => c.krate(db), | ||
558 | DefWithBody::Function(f) => f.krate(db), | ||
559 | DefWithBody::Static(s) => s.krate(db), | ||
560 | } | ||
561 | } | ||
554 | } | 562 | } |
555 | 563 | ||
556 | pub trait HasBody: Copy { | 564 | pub trait HasBody: Copy { |
@@ -671,6 +679,10 @@ impl Function { | |||
671 | self.id.module(db) | 679 | self.id.module(db) |
672 | } | 680 | } |
673 | 681 | ||
682 | pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> { | ||
683 | self.module(db).krate(db) | ||
684 | } | ||
685 | |||
674 | pub fn name(self, db: &impl HirDatabase) -> Name { | 686 | pub fn name(self, db: &impl HirDatabase) -> Name { |
675 | self.data(db).name.clone() | 687 | self.data(db).name.clone() |
676 | } | 688 | } |
@@ -745,6 +757,10 @@ impl Const { | |||
745 | self.id.module(db) | 757 | self.id.module(db) |
746 | } | 758 | } |
747 | 759 | ||
760 | pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> { | ||
761 | self.module(db).krate(db) | ||
762 | } | ||
763 | |||
748 | pub fn data(self, db: &impl HirDatabase) -> Arc<ConstData> { | 764 | pub fn data(self, db: &impl HirDatabase) -> Arc<ConstData> { |
749 | db.const_data(self) | 765 | db.const_data(self) |
750 | } | 766 | } |
@@ -824,6 +840,10 @@ impl Static { | |||
824 | self.id.module(db) | 840 | self.id.module(db) |
825 | } | 841 | } |
826 | 842 | ||
843 | pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> { | ||
844 | self.module(db).krate(db) | ||
845 | } | ||
846 | |||
827 | pub fn data(self, db: &impl HirDatabase) -> Arc<ConstData> { | 847 | pub fn data(self, db: &impl HirDatabase) -> Arc<ConstData> { |
828 | db.static_data(self) | 848 | db.static_data(self) |
829 | } | 849 | } |
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index 05259dcbb..2b20ae02b 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs | |||
@@ -13,8 +13,8 @@ use crate::{ | |||
13 | nameres::{CrateDefMap, ImportSourceMap, Namespace, RawItems}, | 13 | nameres::{CrateDefMap, ImportSourceMap, Namespace, RawItems}, |
14 | traits::TraitData, | 14 | traits::TraitData, |
15 | ty::{ | 15 | ty::{ |
16 | method_resolution::CrateImplBlocks, CallableDef, FnSig, GenericPredicate, InferenceResult, | 16 | method_resolution::CrateImplBlocks, traits::Impl, CallableDef, FnSig, GenericPredicate, |
17 | Substs, Ty, TypableDef, TypeCtor, | 17 | InferenceResult, Substs, Ty, TypableDef, TypeCtor, |
18 | }, | 18 | }, |
19 | type_alias::TypeAliasData, | 19 | type_alias::TypeAliasData, |
20 | AstIdMap, Const, ConstData, Crate, DefWithBody, Enum, ErasedFileAstId, ExprScopes, FnData, | 20 | AstIdMap, Const, ConstData, Crate, DefWithBody, Enum, ErasedFileAstId, ExprScopes, FnData, |
@@ -50,7 +50,7 @@ pub trait InternDatabase: SourceDatabase { | |||
50 | #[salsa::interned] | 50 | #[salsa::interned] |
51 | fn intern_type_ctor(&self, type_ctor: TypeCtor) -> ids::TypeCtorId; | 51 | fn intern_type_ctor(&self, type_ctor: TypeCtor) -> ids::TypeCtorId; |
52 | #[salsa::interned] | 52 | #[salsa::interned] |
53 | fn intern_impl_block(&self, impl_block: ImplBlock) -> ids::GlobalImplId; | 53 | fn intern_impl(&self, impl_: Impl) -> ids::GlobalImplId; |
54 | } | 54 | } |
55 | 55 | ||
56 | /// This database has access to source code, so queries here are not really | 56 | /// This database has access to source code, so queries here are not really |
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 36bfb10ce..e6ecbe1ea 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs | |||
@@ -16,7 +16,10 @@ use std::ops::Deref; | |||
16 | use std::sync::Arc; | 16 | use std::sync::Arc; |
17 | use std::{fmt, mem}; | 17 | use std::{fmt, mem}; |
18 | 18 | ||
19 | use crate::{db::HirDatabase, type_ref::Mutability, Adt, GenericParams, Name, Trait, TypeAlias}; | 19 | use crate::{ |
20 | db::HirDatabase, expr::ExprId, type_ref::Mutability, Adt, DefWithBody, GenericParams, Name, | ||
21 | Trait, TypeAlias, | ||
22 | }; | ||
20 | use display::{HirDisplay, HirFormatter}; | 23 | use display::{HirDisplay, HirFormatter}; |
21 | 24 | ||
22 | pub(crate) use autoderef::autoderef; | 25 | pub(crate) use autoderef::autoderef; |
@@ -100,6 +103,12 @@ pub enum TypeCtor { | |||
100 | /// couldn't find a better representation. In that case, we generate | 103 | /// couldn't find a better representation. In that case, we generate |
101 | /// an **application type** like `(Iterator::Item)<T>`. | 104 | /// an **application type** like `(Iterator::Item)<T>`. |
102 | AssociatedType(TypeAlias), | 105 | AssociatedType(TypeAlias), |
106 | |||
107 | /// The type of a specific closure. | ||
108 | /// | ||
109 | /// The closure signature is stored in a `FnPtr` type in the first type | ||
110 | /// parameter. | ||
111 | Closure { def: DefWithBody, expr: ExprId }, | ||
103 | } | 112 | } |
104 | 113 | ||
105 | /// A nominal type with (maybe 0) type parameters. This might be a primitive | 114 | /// A nominal type with (maybe 0) type parameters. This might be a primitive |
@@ -481,6 +490,10 @@ impl Ty { | |||
481 | let sig = db.callable_item_signature(def); | 490 | let sig = db.callable_item_signature(def); |
482 | Some(sig.subst(&a_ty.parameters)) | 491 | Some(sig.subst(&a_ty.parameters)) |
483 | } | 492 | } |
493 | TypeCtor::Closure { .. } => { | ||
494 | let sig_param = &a_ty.parameters[0]; | ||
495 | sig_param.callable_sig(db) | ||
496 | } | ||
484 | _ => None, | 497 | _ => None, |
485 | }, | 498 | }, |
486 | _ => None, | 499 | _ => None, |
@@ -720,6 +733,14 @@ impl HirDisplay for ApplicationTy { | |||
720 | write!(f, ">")?; | 733 | write!(f, ">")?; |
721 | } | 734 | } |
722 | } | 735 | } |
736 | TypeCtor::Closure { .. } => { | ||
737 | let sig = self.parameters[0] | ||
738 | .callable_sig(f.db) | ||
739 | .expect("first closure parameter should contain signature"); | ||
740 | write!(f, "|")?; | ||
741 | f.write_joined(sig.params(), ", ")?; | ||
742 | write!(f, "| -> {}", sig.ret().display(f.db))?; | ||
743 | } | ||
723 | } | 744 | } |
724 | Ok(()) | 745 | Ok(()) |
725 | } | 746 | } |
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 81a8623bf..378d2f829 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -790,11 +790,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
790 | }; | 790 | }; |
791 | self.unify(&expected_receiver_ty, &actual_receiver_ty); | 791 | self.unify(&expected_receiver_ty, &actual_receiver_ty); |
792 | 792 | ||
793 | let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown)); | 793 | self.check_call_arguments(args, ¶m_tys); |
794 | for (arg, param_ty) in args.iter().zip(param_iter) { | ||
795 | let param_ty = self.normalize_associated_types_in(param_ty); | ||
796 | self.infer_expr(*arg, &Expectation::has_type(param_ty)); | ||
797 | } | ||
798 | let ret_ty = self.normalize_associated_types_in(ret_ty); | 794 | let ret_ty = self.normalize_associated_types_in(ret_ty); |
799 | ret_ty | 795 | ret_ty |
800 | } | 796 | } |
@@ -885,18 +881,37 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
885 | Expr::Lambda { body, args, arg_types } => { | 881 | Expr::Lambda { body, args, arg_types } => { |
886 | assert_eq!(args.len(), arg_types.len()); | 882 | assert_eq!(args.len(), arg_types.len()); |
887 | 883 | ||
884 | let mut sig_tys = Vec::new(); | ||
885 | |||
888 | for (arg_pat, arg_type) in args.iter().zip(arg_types.iter()) { | 886 | for (arg_pat, arg_type) in args.iter().zip(arg_types.iter()) { |
889 | let expected = if let Some(type_ref) = arg_type { | 887 | let expected = if let Some(type_ref) = arg_type { |
890 | self.make_ty(type_ref) | 888 | self.make_ty(type_ref) |
891 | } else { | 889 | } else { |
892 | Ty::Unknown | 890 | Ty::Unknown |
893 | }; | 891 | }; |
894 | self.infer_pat(*arg_pat, &expected, BindingMode::default()); | 892 | let arg_ty = self.infer_pat(*arg_pat, &expected, BindingMode::default()); |
893 | sig_tys.push(arg_ty); | ||
895 | } | 894 | } |
896 | 895 | ||
897 | // FIXME: infer lambda type etc. | 896 | // add return type |
898 | let _body_ty = self.infer_expr(*body, &Expectation::none()); | 897 | let ret_ty = self.new_type_var(); |
899 | Ty::Unknown | 898 | sig_tys.push(ret_ty.clone()); |
899 | let sig_ty = Ty::apply( | ||
900 | TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1 }, | ||
901 | sig_tys.into(), | ||
902 | ); | ||
903 | let closure_ty = Ty::apply_one( | ||
904 | TypeCtor::Closure { def: self.body.owner(), expr: tgt_expr }, | ||
905 | sig_ty, | ||
906 | ); | ||
907 | |||
908 | // Eagerly try to relate the closure type with the expected | ||
909 | // type, otherwise we often won't have enough information to | ||
910 | // infer the body. | ||
911 | self.coerce(&closure_ty, &expected.ty); | ||
912 | |||
913 | self.infer_expr(*body, &Expectation::has_type(ret_ty)); | ||
914 | closure_ty | ||
900 | } | 915 | } |
901 | Expr::Call { callee, args } => { | 916 | Expr::Call { callee, args } => { |
902 | let callee_ty = self.infer_expr(*callee, &Expectation::none()); | 917 | let callee_ty = self.infer_expr(*callee, &Expectation::none()); |
@@ -909,11 +924,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
909 | } | 924 | } |
910 | }; | 925 | }; |
911 | self.register_obligations_for_call(&callee_ty); | 926 | self.register_obligations_for_call(&callee_ty); |
912 | let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown)); | 927 | self.check_call_arguments(args, ¶m_tys); |
913 | for (arg, param_ty) in args.iter().zip(param_iter) { | ||
914 | let param_ty = self.normalize_associated_types_in(param_ty); | ||
915 | self.infer_expr(*arg, &Expectation::has_type(param_ty)); | ||
916 | } | ||
917 | let ret_ty = self.normalize_associated_types_in(ret_ty); | 928 | let ret_ty = self.normalize_associated_types_in(ret_ty); |
918 | ret_ty | 929 | ret_ty |
919 | } | 930 | } |
@@ -1255,6 +1266,30 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1255 | ty | 1266 | ty |
1256 | } | 1267 | } |
1257 | 1268 | ||
1269 | fn check_call_arguments(&mut self, args: &[ExprId], param_tys: &[Ty]) { | ||
1270 | // Quoting https://github.com/rust-lang/rust/blob/6ef275e6c3cb1384ec78128eceeb4963ff788dca/src/librustc_typeck/check/mod.rs#L3325 -- | ||
1271 | // We do this in a pretty awful way: first we type-check any arguments | ||
1272 | // that are not closures, then we type-check the closures. This is so | ||
1273 | // that we have more information about the types of arguments when we | ||
1274 | // type-check the functions. This isn't really the right way to do this. | ||
1275 | for &check_closures in &[false, true] { | ||
1276 | let param_iter = param_tys.iter().cloned().chain(repeat(Ty::Unknown)); | ||
1277 | for (&arg, param_ty) in args.iter().zip(param_iter) { | ||
1278 | let is_closure = match &self.body[arg] { | ||
1279 | Expr::Lambda { .. } => true, | ||
1280 | _ => false, | ||
1281 | }; | ||
1282 | |||
1283 | if is_closure != check_closures { | ||
1284 | continue; | ||
1285 | } | ||
1286 | |||
1287 | let param_ty = self.normalize_associated_types_in(param_ty); | ||
1288 | self.infer_expr(arg, &Expectation::has_type(param_ty)); | ||
1289 | } | ||
1290 | } | ||
1291 | } | ||
1292 | |||
1258 | fn collect_const(&mut self, data: &ConstData) { | 1293 | fn collect_const(&mut self, data: &ConstData) { |
1259 | self.return_ty = self.make_ty(data.type_ref()); | 1294 | self.return_ty = self.make_ty(data.type_ref()); |
1260 | } | 1295 | } |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 3ac1fbdd5..2872cd27b 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -1077,7 +1077,6 @@ fn test(x: &i32) { | |||
1077 | } | 1077 | } |
1078 | "#), | 1078 | "#), |
1079 | @r###" | 1079 | @r###" |
1080 | |||
1081 | [9; 10) 'x': &i32 | 1080 | [9; 10) 'x': &i32 |
1082 | [18; 369) '{ ...o_x; }': () | 1081 | [18; 369) '{ ...o_x; }': () |
1083 | [28; 29) 'y': &i32 | 1082 | [28; 29) 'y': &i32 |
@@ -1107,8 +1106,8 @@ fn test(x: &i32) { | |||
1107 | [177; 205) '{ ... }': () | 1106 | [177; 205) '{ ... }': () |
1108 | [191; 192) 'h': {unknown} | 1107 | [191; 192) 'h': {unknown} |
1109 | [195; 198) 'val': {unknown} | 1108 | [195; 198) 'val': {unknown} |
1110 | [215; 221) 'lambda': {unknown} | 1109 | [215; 221) 'lambda': |u64, u64, i32| -> i32 |
1111 | [224; 256) '|a: u6...b; c }': {unknown} | 1110 | [224; 256) '|a: u6...b; c }': |u64, u64, i32| -> i32 |
1112 | [225; 226) 'a': u64 | 1111 | [225; 226) 'a': u64 |
1113 | [233; 234) 'b': u64 | 1112 | [233; 234) 'b': u64 |
1114 | [236; 237) 'c': i32 | 1113 | [236; 237) 'c': i32 |
@@ -2836,12 +2835,11 @@ fn test() -> u64 { | |||
2836 | } | 2835 | } |
2837 | "#), | 2836 | "#), |
2838 | @r###" | 2837 | @r###" |
2839 | |||
2840 | [44; 102) '{ ...0(2) }': u64 | 2838 | [44; 102) '{ ...0(2) }': u64 |
2841 | [54; 55) 'a': S | 2839 | [54; 55) 'a': S |
2842 | [58; 59) 'S': S(fn(u32) -> u64) -> S | 2840 | [58; 59) 'S': S(fn(u32) -> u64) -> S |
2843 | [58; 68) 'S(|i| 2*i)': S | 2841 | [58; 68) 'S(|i| 2*i)': S |
2844 | [60; 67) '|i| 2*i': fn(u32) -> u64 | 2842 | [60; 67) '|i| 2*i': |i32| -> i32 |
2845 | [61; 62) 'i': i32 | 2843 | [61; 62) 'i': i32 |
2846 | [64; 65) '2': i32 | 2844 | [64; 65) '2': i32 |
2847 | [64; 67) '2*i': i32 | 2845 | [64; 67) '2*i': i32 |
@@ -3802,13 +3800,13 @@ fn test<T: Trait<Type = u32>>(x: T, y: impl Trait<Type = i64>) { | |||
3802 | [296; 299) 'get': fn get<T>(T) -> <T as Trait>::Type | 3800 | [296; 299) 'get': fn get<T>(T) -> <T as Trait>::Type |
3803 | [296; 302) 'get(x)': {unknown} | 3801 | [296; 302) 'get(x)': {unknown} |
3804 | [300; 301) 'x': T | 3802 | [300; 301) 'x': T |
3805 | [308; 312) 'get2': fn get2<{unknown}, S<{unknown}>>(T) -> U | 3803 | [308; 312) 'get2': fn get2<{unknown}, T>(T) -> U |
3806 | [308; 315) 'get2(x)': {unknown} | 3804 | [308; 315) 'get2(x)': {unknown} |
3807 | [313; 314) 'x': T | 3805 | [313; 314) 'x': T |
3808 | [321; 324) 'get': fn get<impl Trait<Type = i64>>(T) -> <T as Trait>::Type | 3806 | [321; 324) 'get': fn get<impl Trait<Type = i64>>(T) -> <T as Trait>::Type |
3809 | [321; 327) 'get(y)': {unknown} | 3807 | [321; 327) 'get(y)': {unknown} |
3810 | [325; 326) 'y': impl Trait<Type = i64> | 3808 | [325; 326) 'y': impl Trait<Type = i64> |
3811 | [333; 337) 'get2': fn get2<{unknown}, S<{unknown}>>(T) -> U | 3809 | [333; 337) 'get2': fn get2<{unknown}, impl Trait<Type = i64>>(T) -> U |
3812 | [333; 340) 'get2(y)': {unknown} | 3810 | [333; 340) 'get2(y)': {unknown} |
3813 | [338; 339) 'y': impl Trait<Type = i64> | 3811 | [338; 339) 'y': impl Trait<Type = i64> |
3814 | [346; 349) 'get': fn get<S<u64>>(T) -> <T as Trait>::Type | 3812 | [346; 349) 'get': fn get<S<u64>>(T) -> <T as Trait>::Type |
@@ -3992,49 +3990,50 @@ fn test<F: FnOnce(u32, u64) -> u128>(f: F) { | |||
3992 | fn closure_1() { | 3990 | fn closure_1() { |
3993 | assert_snapshot!( | 3991 | assert_snapshot!( |
3994 | infer(r#" | 3992 | infer(r#" |
3993 | #[lang = "fn_once"] | ||
3995 | trait FnOnce<Args> { | 3994 | trait FnOnce<Args> { |
3996 | type Output; | 3995 | type Output; |
3997 | } | 3996 | } |
3998 | 3997 | ||
3999 | enum Option<T> { Some(T), None } | 3998 | enum Option<T> { Some(T), None } |
4000 | impl<T> Option<T> { | 3999 | impl<T> Option<T> { |
4001 | fn map<U, F: FnOnce(T) -> U>(self, f: F) -> U {} | 4000 | fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> {} |
4002 | } | 4001 | } |
4003 | 4002 | ||
4004 | fn test() { | 4003 | fn test() { |
4005 | let x = Option::Some(1i32); | 4004 | let x = Option::Some(1u32); |
4006 | x.map(|v| v + 1); | 4005 | x.map(|v| v + 1); |
4007 | x.map(|_v| 1u64); | 4006 | x.map(|_v| 1u64); |
4008 | let y: Option<i64> = x.map(|_v| 1); | 4007 | let y: Option<i64> = x.map(|_v| 1); |
4009 | } | 4008 | } |
4010 | "#), | 4009 | "#), |
4011 | @r###" | 4010 | @r###" |
4012 | [128; 132) 'self': Option<T> | 4011 | [148; 152) 'self': Option<T> |
4013 | [134; 135) 'f': F | 4012 | [154; 155) 'f': F |
4014 | [145; 147) '{}': () | 4013 | [173; 175) '{}': () |
4015 | [161; 280) '{ ... 1); }': () | 4014 | [189; 308) '{ ... 1); }': () |
4016 | [171; 172) 'x': Option<i32> | 4015 | [199; 200) 'x': Option<u32> |
4017 | [175; 187) 'Option::Some': Some<i32>(T) -> Option<T> | 4016 | [203; 215) 'Option::Some': Some<u32>(T) -> Option<T> |
4018 | [175; 193) 'Option...(1i32)': Option<i32> | 4017 | [203; 221) 'Option...(1u32)': Option<u32> |
4019 | [188; 192) '1i32': i32 | 4018 | [216; 220) '1u32': u32 |
4020 | [199; 200) 'x': Option<i32> | 4019 | [227; 228) 'x': Option<u32> |
4021 | [199; 215) 'x.map(...v + 1)': {unknown} | 4020 | [227; 243) 'x.map(...v + 1)': Option<u32> |
4022 | [205; 214) '|v| v + 1': {unknown} | 4021 | [233; 242) '|v| v + 1': |u32| -> u32 |
4023 | [206; 207) 'v': {unknown} | 4022 | [234; 235) 'v': u32 |
4024 | [209; 210) 'v': {unknown} | 4023 | [237; 238) 'v': u32 |
4025 | [209; 214) 'v + 1': i32 | 4024 | [237; 242) 'v + 1': u32 |
4026 | [213; 214) '1': i32 | 4025 | [241; 242) '1': u32 |
4027 | [221; 222) 'x': Option<i32> | 4026 | [249; 250) 'x': Option<u32> |
4028 | [221; 237) 'x.map(... 1u64)': {unknown} | 4027 | [249; 265) 'x.map(... 1u64)': Option<u64> |
4029 | [227; 236) '|_v| 1u64': {unknown} | 4028 | [255; 264) '|_v| 1u64': |u32| -> u64 |
4030 | [228; 230) '_v': {unknown} | 4029 | [256; 258) '_v': u32 |
4031 | [232; 236) '1u64': u64 | 4030 | [260; 264) '1u64': u64 |
4032 | [247; 248) 'y': Option<i64> | 4031 | [275; 276) 'y': Option<i64> |
4033 | [264; 265) 'x': Option<i32> | 4032 | [292; 293) 'x': Option<u32> |
4034 | [264; 277) 'x.map(|_v| 1)': Option<i64> | 4033 | [292; 305) 'x.map(|_v| 1)': Option<i64> |
4035 | [270; 276) '|_v| 1': {unknown} | 4034 | [298; 304) '|_v| 1': |u32| -> i64 |
4036 | [271; 273) '_v': {unknown} | 4035 | [299; 301) '_v': u32 |
4037 | [275; 276) '1': i32 | 4036 | [303; 304) '1': i64 |
4038 | "### | 4037 | "### |
4039 | ); | 4038 | ); |
4040 | } | 4039 | } |
@@ -4060,17 +4059,17 @@ fn test<F: FnOnce(u32) -> u64>(f: F) { | |||
4060 | [85; 86) 'f': F | 4059 | [85; 86) 'f': F |
4061 | [85; 89) 'f(1)': {unknown} | 4060 | [85; 89) 'f(1)': {unknown} |
4062 | [87; 88) '1': i32 | 4061 | [87; 88) '1': i32 |
4063 | [99; 100) 'g': {unknown} | 4062 | [99; 100) 'g': |u64| -> i32 |
4064 | [103; 112) '|v| v + 1': {unknown} | 4063 | [103; 112) '|v| v + 1': |u64| -> i32 |
4065 | [104; 105) 'v': {unknown} | 4064 | [104; 105) 'v': u64 |
4066 | [107; 108) 'v': {unknown} | 4065 | [107; 108) 'v': u64 |
4067 | [107; 112) 'v + 1': i32 | 4066 | [107; 112) 'v + 1': i32 |
4068 | [111; 112) '1': i32 | 4067 | [111; 112) '1': i32 |
4069 | [118; 119) 'g': {unknown} | 4068 | [118; 119) 'g': |u64| -> i32 |
4070 | [118; 125) 'g(1u64)': {unknown} | 4069 | [118; 125) 'g(1u64)': i32 |
4071 | [120; 124) '1u64': u64 | 4070 | [120; 124) '1u64': u64 |
4072 | [135; 136) 'h': {unknown} | 4071 | [135; 136) 'h': |u128| -> u128 |
4073 | [139; 152) '|v| 1u128 + v': {unknown} | 4072 | [139; 152) '|v| 1u128 + v': |u128| -> u128 |
4074 | [140; 141) 'v': u128 | 4073 | [140; 141) 'v': u128 |
4075 | [143; 148) '1u128': u128 | 4074 | [143; 148) '1u128': u128 |
4076 | [143; 152) '1u128 + v': u128 | 4075 | [143; 152) '1u128 + v': u128 |
@@ -4080,6 +4079,86 @@ fn test<F: FnOnce(u32) -> u64>(f: F) { | |||
4080 | } | 4079 | } |
4081 | 4080 | ||
4082 | #[test] | 4081 | #[test] |
4082 | fn closure_as_argument_inference_order() { | ||
4083 | assert_snapshot!( | ||
4084 | infer(r#" | ||
4085 | #[lang = "fn_once"] | ||
4086 | trait FnOnce<Args> { | ||
4087 | type Output; | ||
4088 | } | ||
4089 | |||
4090 | fn foo1<T, U, F: FnOnce(T) -> U>(x: T, f: F) -> U {} | ||
4091 | fn foo2<T, U, F: FnOnce(T) -> U>(f: F, x: T) -> U {} | ||
4092 | |||
4093 | struct S; | ||
4094 | impl S { | ||
4095 | fn method(self) -> u64; | ||
4096 | |||
4097 | fn foo1<T, U, F: FnOnce(T) -> U>(self, x: T, f: F) -> U {} | ||
4098 | fn foo2<T, U, F: FnOnce(T) -> U>(self, f: F, x: T) -> U {} | ||
4099 | } | ||
4100 | |||
4101 | fn test() { | ||
4102 | let x1 = foo1(S, |s| s.method()); | ||
4103 | let x2 = foo2(|s| s.method(), S); | ||
4104 | let x3 = S.foo1(S, |s| s.method()); | ||
4105 | let x4 = S.foo2(|s| s.method(), S); | ||
4106 | } | ||
4107 | "#), | ||
4108 | @r###" | ||
4109 | [95; 96) 'x': T | ||
4110 | [101; 102) 'f': F | ||
4111 | [112; 114) '{}': () | ||
4112 | [148; 149) 'f': F | ||
4113 | [154; 155) 'x': T | ||
4114 | [165; 167) '{}': () | ||
4115 | [202; 206) 'self': S | ||
4116 | [254; 258) 'self': S | ||
4117 | [260; 261) 'x': T | ||
4118 | [266; 267) 'f': F | ||
4119 | [277; 279) '{}': () | ||
4120 | [317; 321) 'self': S | ||
4121 | [323; 324) 'f': F | ||
4122 | [329; 330) 'x': T | ||
4123 | [340; 342) '{}': () | ||
4124 | [356; 515) '{ ... S); }': () | ||
4125 | [366; 368) 'x1': u64 | ||
4126 | [371; 375) 'foo1': fn foo1<S, u64, |S| -> u64>(T, F) -> U | ||
4127 | [371; 394) 'foo1(S...hod())': u64 | ||
4128 | [376; 377) 'S': S | ||
4129 | [379; 393) '|s| s.method()': |S| -> u64 | ||
4130 | [380; 381) 's': S | ||
4131 | [383; 384) 's': S | ||
4132 | [383; 393) 's.method()': u64 | ||
4133 | [404; 406) 'x2': u64 | ||
4134 | [409; 413) 'foo2': fn foo2<S, u64, |S| -> u64>(F, T) -> U | ||
4135 | [409; 432) 'foo2(|...(), S)': u64 | ||
4136 | [414; 428) '|s| s.method()': |S| -> u64 | ||
4137 | [415; 416) 's': S | ||
4138 | [418; 419) 's': S | ||
4139 | [418; 428) 's.method()': u64 | ||
4140 | [430; 431) 'S': S | ||
4141 | [442; 444) 'x3': u64 | ||
4142 | [447; 448) 'S': S | ||
4143 | [447; 472) 'S.foo1...hod())': u64 | ||
4144 | [454; 455) 'S': S | ||
4145 | [457; 471) '|s| s.method()': |S| -> u64 | ||
4146 | [458; 459) 's': S | ||
4147 | [461; 462) 's': S | ||
4148 | [461; 471) 's.method()': u64 | ||
4149 | [482; 484) 'x4': u64 | ||
4150 | [487; 488) 'S': S | ||
4151 | [487; 512) 'S.foo2...(), S)': u64 | ||
4152 | [494; 508) '|s| s.method()': |S| -> u64 | ||
4153 | [495; 496) 's': S | ||
4154 | [498; 499) 's': S | ||
4155 | [498; 508) 's.method()': u64 | ||
4156 | [510; 511) 'S': S | ||
4157 | "### | ||
4158 | ); | ||
4159 | } | ||
4160 | |||
4161 | #[test] | ||
4083 | fn unselected_projection_in_trait_env_1() { | 4162 | fn unselected_projection_in_trait_env_1() { |
4084 | let t = type_at( | 4163 | let t = type_at( |
4085 | r#" | 4164 | r#" |
diff --git a/crates/ra_hir/src/ty/traits.rs b/crates/ra_hir/src/ty/traits.rs index c0c132809..d11dab294 100644 --- a/crates/ra_hir/src/ty/traits.rs +++ b/crates/ra_hir/src/ty/traits.rs | |||
@@ -9,7 +9,7 @@ use ra_prof::profile; | |||
9 | use rustc_hash::FxHashSet; | 9 | use rustc_hash::FxHashSet; |
10 | 10 | ||
11 | use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk}; | 11 | use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk}; |
12 | use crate::{db::HirDatabase, Crate, ImplBlock, Trait}; | 12 | use crate::{db::HirDatabase, expr::ExprId, Crate, DefWithBody, ImplBlock, Trait}; |
13 | 13 | ||
14 | use self::chalk::{from_chalk, ToChalk}; | 14 | use self::chalk::{from_chalk, ToChalk}; |
15 | 15 | ||
@@ -173,6 +173,14 @@ pub(crate) fn trait_solve_query( | |||
173 | ) -> Option<Solution> { | 173 | ) -> Option<Solution> { |
174 | let _p = profile("trait_solve_query"); | 174 | let _p = profile("trait_solve_query"); |
175 | debug!("trait_solve_query({})", goal.value.value.display(db)); | 175 | debug!("trait_solve_query({})", goal.value.value.display(db)); |
176 | |||
177 | if let Obligation::Projection(pred) = &goal.value.value { | ||
178 | if let Ty::Bound(_) = &pred.projection_ty.parameters[0] { | ||
179 | // Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible | ||
180 | return Some(Solution::Ambig(Guidance::Unknown)); | ||
181 | } | ||
182 | } | ||
183 | |||
176 | let canonical = goal.to_chalk(db).cast(); | 184 | let canonical = goal.to_chalk(db).cast(); |
177 | // We currently don't deal with universes (I think / hope they're not yet | 185 | // We currently don't deal with universes (I think / hope they're not yet |
178 | // relevant for our use cases?) | 186 | // relevant for our use cases?) |
@@ -252,3 +260,37 @@ pub enum Guidance { | |||
252 | /// There's no useful information to feed back to type inference | 260 | /// There's no useful information to feed back to type inference |
253 | Unknown, | 261 | Unknown, |
254 | } | 262 | } |
263 | |||
264 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | ||
265 | pub enum FnTrait { | ||
266 | FnOnce, | ||
267 | FnMut, | ||
268 | Fn, | ||
269 | } | ||
270 | |||
271 | impl FnTrait { | ||
272 | fn lang_item_name(self) -> &'static str { | ||
273 | match self { | ||
274 | FnTrait::FnOnce => "fn_once", | ||
275 | FnTrait::FnMut => "fn_mut", | ||
276 | FnTrait::Fn => "fn", | ||
277 | } | ||
278 | } | ||
279 | } | ||
280 | |||
281 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
282 | pub struct ClosureFnTraitImplData { | ||
283 | def: DefWithBody, | ||
284 | expr: ExprId, | ||
285 | fn_trait: FnTrait, | ||
286 | } | ||
287 | |||
288 | /// An impl. Usually this comes from an impl block, but some built-in types get | ||
289 | /// synthetic impls. | ||
290 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
291 | pub enum Impl { | ||
292 | /// A normal impl from an impl block. | ||
293 | ImplBlock(ImplBlock), | ||
294 | /// Closure types implement the Fn traits synthetically. | ||
295 | ClosureFnTraitImpl(ClosureFnTraitImplData), | ||
296 | } | ||
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}; | |||
12 | use ra_db::salsa::{InternId, InternKey}; | 12 | use ra_db::salsa::{InternId, InternKey}; |
13 | use test_utils::tested_by; | 13 | use test_utils::tested_by; |
14 | 14 | ||
15 | use super::{Canonical, ChalkContext, Obligation}; | 15 | use super::{Canonical, ChalkContext, Impl, Obligation}; |
16 | use crate::{ | 16 | use 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 | ||
178 | impl ToChalk for ImplBlock { | 178 | impl 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 | |||
631 | fn 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 | ||
695 | fn 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 | |||
710 | fn 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 | |||
767 | fn 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 | |||
660 | fn id_from_chalk<T: InternKey>(chalk_id: chalk_ir::RawId) -> T { | 776 | fn 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 | } |