aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoradamrk <[email protected]>2020-06-07 20:57:29 +0100
committeradamrk <[email protected]>2020-06-19 21:51:25 +0100
commit3f94a90c7bbc1b3116a7960ae9f25ebe35d68ad0 (patch)
tree82d8a965b9e01e136df4eeaee4c4fee4630ab2a7
parent6654055308515cb330f23942f347de5605f69be1 (diff)
Infer FnSig from Fn traits
-rw-r--r--crates/ra_hir_ty/src/infer/coerce.rs6
-rw-r--r--crates/ra_hir_ty/src/infer/expr.rs102
-rw-r--r--crates/ra_hir_ty/src/traits.rs2
-rw-r--r--crates/ra_hir_ty/src/traits/builtin.rs6
-rw-r--r--crates/ra_ide/src/hover.rs99
5 files changed, 197 insertions, 18 deletions
diff --git a/crates/ra_hir_ty/src/infer/coerce.rs b/crates/ra_hir_ty/src/infer/coerce.rs
index 32c7c57cd..4c5f171de 100644
--- a/crates/ra_hir_ty/src/infer/coerce.rs
+++ b/crates/ra_hir_ty/src/infer/coerce.rs
@@ -38,8 +38,8 @@ impl<'a> InferenceContext<'a> {
38 // Special case: two function types. Try to coerce both to 38 // Special case: two function types. Try to coerce both to
39 // pointers to have a chance at getting a match. See 39 // pointers to have a chance at getting a match. See
40 // https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916 40 // https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916
41 let sig1 = ty1.callable_sig(self.db).expect("FnDef without callable sig"); 41 let sig1 = self.callable_sig(ty1).expect("FnDef without callable sig");
42 let sig2 = ty2.callable_sig(self.db).expect("FnDef without callable sig"); 42 let sig2 = self.callable_sig(ty2).expect("FnDef without callable sig");
43 let ptr_ty1 = Ty::fn_ptr(sig1); 43 let ptr_ty1 = Ty::fn_ptr(sig1);
44 let ptr_ty2 = Ty::fn_ptr(sig2); 44 let ptr_ty2 = Ty::fn_ptr(sig2);
45 self.coerce_merge_branch(&ptr_ty1, &ptr_ty2) 45 self.coerce_merge_branch(&ptr_ty1, &ptr_ty2)
@@ -93,7 +93,7 @@ impl<'a> InferenceContext<'a> {
93 93
94 // `{function_type}` -> `fn()` 94 // `{function_type}` -> `fn()`
95 (ty_app!(TypeCtor::FnDef(_)), ty_app!(TypeCtor::FnPtr { .. })) => { 95 (ty_app!(TypeCtor::FnDef(_)), ty_app!(TypeCtor::FnPtr { .. })) => {
96 match from_ty.callable_sig(self.db) { 96 match self.callable_sig(&from_ty) {
97 None => return false, 97 None => return false,
98 Some(sig) => { 98 Some(sig) => {
99 from_ty = Ty::fn_ptr(sig); 99 from_ty = Ty::fn_ptr(sig);
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs
index 9fd310f69..bba6daeb9 100644
--- a/crates/ra_hir_ty/src/infer/expr.rs
+++ b/crates/ra_hir_ty/src/infer/expr.rs
@@ -15,15 +15,15 @@ use ra_syntax::ast::RangeOp;
15 15
16use crate::{ 16use crate::{
17 autoderef, method_resolution, op, 17 autoderef, method_resolution, op,
18 traits::InEnvironment, 18 traits::{builtin::get_fn_trait, FnTrait, InEnvironment, SolutionVariables},
19 utils::{generics, variant_data, Generics}, 19 utils::{generics, variant_data, Generics},
20 ApplicationTy, Binders, CallableDef, InferTy, IntTy, Mutability, Obligation, Rawness, Substs, 20 ApplicationTy, Binders, CallableDef, FnSig, InferTy, IntTy, Mutability, Obligation, Rawness,
21 TraitRef, Ty, TypeCtor, 21 Substs, TraitRef, Ty, TypeCtor,
22}; 22};
23 23
24use super::{ 24use super::{
25 find_breakable, BindingMode, BreakableContext, Diverges, Expectation, InferenceContext, 25 find_breakable, BindingMode, BreakableContext, Diverges, Expectation, InferenceContext,
26 InferenceDiagnostic, TypeMismatch, 26 InferenceDiagnostic, Solution, TypeMismatch,
27}; 27};
28 28
29impl<'a> InferenceContext<'a> { 29impl<'a> InferenceContext<'a> {
@@ -63,6 +63,75 @@ impl<'a> InferenceContext<'a> {
63 self.resolve_ty_as_possible(ty) 63 self.resolve_ty_as_possible(ty)
64 } 64 }
65 65
66 fn callable_sig_from_fn_trait(&mut self, ty: &Ty) -> Option<FnSig> {
67 if let Some(krate) = self.resolver.krate() {
68 let fn_traits: Vec<crate::TraitId> = [FnTrait::FnOnce, FnTrait::FnMut, FnTrait::Fn]
69 .iter()
70 .filter_map(|f| get_fn_trait(self.db, krate, *f))
71 .collect();
72 for fn_trait in fn_traits {
73 let fn_trait_data = self.db.trait_data(fn_trait);
74 let generic_params = generics(self.db.upcast(), fn_trait.into());
75 if generic_params.len() != 2 {
76 continue;
77 }
78
79 let arg_ty = self.table.new_type_var();
80 let substs = Substs::build_for_generics(&generic_params)
81 .push(ty.clone())
82 .push(arg_ty.clone())
83 .build();
84
85 let trait_ref = TraitRef { trait_: fn_trait, substs: substs.clone() };
86 let trait_env = Arc::clone(&self.trait_env);
87 let implements_fn_goal =
88 self.canonicalizer().canonicalize_obligation(InEnvironment {
89 value: Obligation::Trait(trait_ref),
90 environment: trait_env,
91 });
92 if let Some(Solution::Unique(SolutionVariables(solution))) =
93 self.db.trait_solve(krate, implements_fn_goal.value.clone())
94 {
95 match solution.value.as_slice() {
96 [Ty::Apply(ApplicationTy {
97 ctor: TypeCtor::Tuple { cardinality: _ },
98 parameters,
99 })] => {
100 let output_assoc_type = match fn_trait_data
101 .associated_types()
102 .collect::<Vec<hir_def::TypeAliasId>>()
103 .as_slice()
104 {
105 [output] => *output,
106 _ => {
107 continue;
108 }
109 };
110 let output_proj_ty = crate::ProjectionTy {
111 associated_ty: output_assoc_type,
112 parameters: substs,
113 };
114 let return_ty = self.normalize_projection_ty(output_proj_ty);
115 return Some(FnSig::from_params_and_return(
116 parameters.into_iter().map(|ty| ty.clone()).collect(),
117 return_ty,
118 ));
119 }
120 _ => (),
121 }
122 }
123 }
124 };
125 None
126 }
127
128 pub fn callable_sig(&mut self, ty: &Ty) -> Option<FnSig> {
129 match ty.callable_sig(self.db) {
130 result @ Some(_) => result,
131 None => self.callable_sig_from_fn_trait(ty),
132 }
133 }
134
66 fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { 135 fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
67 let body = Arc::clone(&self.body); // avoid borrow checker problem 136 let body = Arc::clone(&self.body); // avoid borrow checker problem
68 let ty = match &body[tgt_expr] { 137 let ty = match &body[tgt_expr] {
@@ -198,14 +267,21 @@ impl<'a> InferenceContext<'a> {
198 } 267 }
199 Expr::Call { callee, args } => { 268 Expr::Call { callee, args } => {
200 let callee_ty = self.infer_expr(*callee, &Expectation::none()); 269 let callee_ty = self.infer_expr(*callee, &Expectation::none());
201 let (param_tys, ret_ty) = match callee_ty.callable_sig(self.db) { 270 let canonicalized = self.canonicalizer().canonicalize_ty(callee_ty.clone());
202 Some(sig) => (sig.params().to_vec(), sig.ret().clone()), 271 let mut derefs = autoderef(
203 None => { 272 self.db,
204 // Not callable 273 self.resolver.krate(),
205 // FIXME: report an error 274 InEnvironment {
206 (Vec::new(), Ty::Unknown) 275 value: canonicalized.value.clone(),
207 } 276 environment: self.trait_env.clone(),
208 }; 277 },
278 );
279 let (param_tys, ret_ty): (Vec<Ty>, Ty) = derefs
280 .find_map(|callee_deref_ty| {
281 self.callable_sig(&canonicalized.decanonicalize_ty(callee_deref_ty.value))
282 .map(|sig| (sig.params().to_vec(), sig.ret().clone()))
283 })
284 .unwrap_or((Vec::new(), Ty::Unknown));
209 self.register_obligations_for_call(&callee_ty); 285 self.register_obligations_for_call(&callee_ty);
210 self.check_call_arguments(args, &param_tys); 286 self.check_call_arguments(args, &param_tys);
211 self.normalize_associated_types_in(ret_ty) 287 self.normalize_associated_types_in(ret_ty)
@@ -692,7 +768,7 @@ impl<'a> InferenceContext<'a> {
692 let method_ty = method_ty.subst(&substs); 768 let method_ty = method_ty.subst(&substs);
693 let method_ty = self.insert_type_vars(method_ty); 769 let method_ty = self.insert_type_vars(method_ty);
694 self.register_obligations_for_call(&method_ty); 770 self.register_obligations_for_call(&method_ty);
695 let (expected_receiver_ty, param_tys, ret_ty) = match method_ty.callable_sig(self.db) { 771 let (expected_receiver_ty, param_tys, ret_ty) = match self.callable_sig(&method_ty) {
696 Some(sig) => { 772 Some(sig) => {
697 if !sig.params().is_empty() { 773 if !sig.params().is_empty() {
698 (sig.params()[0].clone(), sig.params()[1..].to_vec(), sig.ret().clone()) 774 (sig.params()[0].clone(), sig.params()[1..].to_vec(), sig.ret().clone())
diff --git a/crates/ra_hir_ty/src/traits.rs b/crates/ra_hir_ty/src/traits.rs
index 6bc6d474c..9fef9240d 100644
--- a/crates/ra_hir_ty/src/traits.rs
+++ b/crates/ra_hir_ty/src/traits.rs
@@ -14,7 +14,7 @@ use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty,
14use self::chalk::{from_chalk, Interner, ToChalk}; 14use self::chalk::{from_chalk, Interner, ToChalk};
15 15
16pub(crate) mod chalk; 16pub(crate) mod chalk;
17mod builtin; 17pub(crate) mod builtin;
18 18
19// This controls the maximum size of types Chalk considers. If we set this too 19// This controls the maximum size of types Chalk considers. If we set this too
20// high, we can run into slow edge cases; if we set it too low, Chalk won't 20// high, we can run into slow edge cases; if we set it too low, Chalk won't
diff --git a/crates/ra_hir_ty/src/traits/builtin.rs b/crates/ra_hir_ty/src/traits/builtin.rs
index 88a422d2c..b05e679ad 100644
--- a/crates/ra_hir_ty/src/traits/builtin.rs
+++ b/crates/ra_hir_ty/src/traits/builtin.rs
@@ -360,7 +360,11 @@ fn super_trait_object_unsize_impl_datum(
360 BuiltinImplData { num_vars, trait_ref, where_clauses: Vec::new(), assoc_ty_values: Vec::new() } 360 BuiltinImplData { num_vars, trait_ref, where_clauses: Vec::new(), assoc_ty_values: Vec::new() }
361} 361}
362 362
363fn get_fn_trait(db: &dyn HirDatabase, krate: CrateId, fn_trait: super::FnTrait) -> Option<TraitId> { 363pub fn get_fn_trait(
364 db: &dyn HirDatabase,
365 krate: CrateId,
366 fn_trait: super::FnTrait,
367) -> Option<TraitId> {
364 let target = db.lang_item(krate, fn_trait.lang_item_name().into())?; 368 let target = db.lang_item(krate, fn_trait.lang_item_name().into())?;
365 match target { 369 match target {
366 LangItemTarget::TraitId(t) => Some(t), 370 LangItemTarget::TraitId(t) => Some(t),
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs
index d870e4cbc..9a88b4977 100644
--- a/crates/ra_ide/src/hover.rs
+++ b/crates/ra_ide/src/hover.rs
@@ -2410,4 +2410,103 @@ fn func(foo: i32) { if true { <|>foo; }; }
2410 ] 2410 ]
2411 "###); 2411 "###);
2412 } 2412 }
2413
2414 #[test]
2415 fn infer_closure_arg() {
2416 check_hover_result(
2417 r#"
2418 //- /lib.rs
2419
2420 enum Option<T> {
2421 None,
2422 Some(T)
2423 }
2424
2425 fn foo() {
2426 let s<|> = Option::None;
2427 let f = |x: Option<i32>| {};
2428 (&f)(s)
2429 }
2430 "#,
2431 &["Option<i32>"],
2432 );
2433 }
2434
2435 #[test]
2436 fn infer_fn_trait_arg() {
2437 check_hover_result(
2438 r#"
2439 //- /lib.rs deps:std
2440
2441 #[lang = "fn"]
2442 pub trait Fn<Args> {
2443 type Output;
2444
2445 extern "rust-call" fn call(&self, args: Args) -> Self::Output;
2446 }
2447
2448 enum Option<T> {
2449 None,
2450 Some(T)
2451 }
2452
2453 fn foo<F, T>(f: F) -> T
2454 where
2455 F: Fn(Option<i32>) -> T,
2456 {
2457 let s<|> = None;
2458 f(s)
2459 }
2460 "#,
2461 &["Option<i32>"],
2462 );
2463 }
2464
2465 #[test]
2466 fn infer_box_fn_arg() {
2467 check_hover_result(
2468 r#"
2469 //- /lib.rs deps:std
2470
2471 #[lang = "fn_once"]
2472 pub trait FnOnce<Args> {
2473 type Output;
2474
2475 extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
2476 }
2477
2478 #[lang = "deref"]
2479 pub trait Deref {
2480 type Target: ?Sized;
2481
2482 fn deref(&self) -> &Self::Target;
2483 }
2484
2485 #[lang = "owned_box"]
2486 pub struct Box<T: ?Sized> {
2487 inner: *mut T,
2488 }
2489
2490 impl<T: ?Sized> Deref for Box<T> {
2491 type Target = T;
2492
2493 fn deref(&self) -> &T {
2494 &self.inner
2495 }
2496 }
2497
2498 enum Option<T> {
2499 None,
2500 Some(T)
2501 }
2502
2503 fn foo() {
2504 let s<|> = Option::None;
2505 let f: Box<dyn FnOnce(&Option<i32>)> = box (|ps| {});
2506 f(&s)
2507 }
2508 "#,
2509 &["Option<i32>"],
2510 );
2511 }
2413} 2512}