mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-02 06:41:48 +00:00
parent
afa6be2435
commit
a09079f27a
4 changed files with 48 additions and 56 deletions
|
@ -40,32 +40,45 @@ impl<'a> InferenceContext<'a> {
|
||||||
/// Merge two types from different branches, with possible coercion.
|
/// Merge two types from different branches, with possible coercion.
|
||||||
///
|
///
|
||||||
/// Mostly this means trying to coerce one to the other, but
|
/// Mostly this means trying to coerce one to the other, but
|
||||||
/// - if we have two function types for different functions, we need to
|
/// - if we have two function types for different functions or closures, we need to
|
||||||
/// coerce both to function pointers;
|
/// coerce both to function pointers;
|
||||||
/// - if we were concerned with lifetime subtyping, we'd need to look for a
|
/// - if we were concerned with lifetime subtyping, we'd need to look for a
|
||||||
/// least upper bound.
|
/// least upper bound.
|
||||||
pub(super) fn coerce_merge_branch(&mut self, ty1: &Ty, ty2: &Ty) -> Ty {
|
pub(super) fn coerce_merge_branch(&mut self, ty1: &Ty, ty2: &Ty) -> Ty {
|
||||||
|
// Special case: two function types. Try to coerce both to
|
||||||
|
// pointers to have a chance at getting a match. See
|
||||||
|
// https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916
|
||||||
|
let sig = match (ty1.kind(&Interner), ty2.kind(&Interner)) {
|
||||||
|
(TyKind::FnDef(..), TyKind::FnDef(..))
|
||||||
|
| (TyKind::Closure(..), TyKind::FnDef(..))
|
||||||
|
| (TyKind::FnDef(..), TyKind::Closure(..))
|
||||||
|
| (TyKind::Closure(..), TyKind::Closure(..)) => {
|
||||||
|
// FIXME: we're ignoring safety here. To be more correct, if we have one FnDef and one Closure,
|
||||||
|
// we should be coercing the closure to a fn pointer of the safety of the FnDef
|
||||||
|
cov_mark::hit!(coerce_fn_reification);
|
||||||
|
let sig = ty1.callable_sig(self.db).expect("FnDef without callable sig");
|
||||||
|
Some(sig)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
if let Some(sig) = sig {
|
||||||
|
let target_ty = TyKind::Function(sig.to_fn_ptr()).intern(&Interner);
|
||||||
|
let result1 = self.coerce_inner(ty1.clone(), &target_ty);
|
||||||
|
let result2 = self.coerce_inner(ty2.clone(), &target_ty);
|
||||||
|
if let (Ok(_result1), Ok(_result2)) = (result1, result2) {
|
||||||
|
// TODO deal with the goals
|
||||||
|
return target_ty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if self.coerce(ty1, ty2) {
|
if self.coerce(ty1, ty2) {
|
||||||
ty2.clone()
|
ty2.clone()
|
||||||
} else if self.coerce(ty2, ty1) {
|
} else if self.coerce(ty2, ty1) {
|
||||||
ty1.clone()
|
ty1.clone()
|
||||||
} else {
|
} else {
|
||||||
if let (TyKind::FnDef(..), TyKind::FnDef(..)) =
|
// FIXME record a type mismatch
|
||||||
(ty1.kind(&Interner), ty2.kind(&Interner))
|
cov_mark::hit!(coerce_merge_fail_fallback);
|
||||||
{
|
ty1.clone()
|
||||||
cov_mark::hit!(coerce_fn_reification);
|
|
||||||
// Special case: two function types. Try to coerce both to
|
|
||||||
// pointers to have a chance at getting a match. See
|
|
||||||
// https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916
|
|
||||||
let sig1 = ty1.callable_sig(self.db).expect("FnDef without callable sig");
|
|
||||||
let sig2 = ty2.callable_sig(self.db).expect("FnDef without callable sig");
|
|
||||||
let ptr_ty1 = TyBuilder::fn_ptr(sig1);
|
|
||||||
let ptr_ty2 = TyBuilder::fn_ptr(sig2);
|
|
||||||
self.coerce_merge_branch(&ptr_ty1, &ptr_ty2)
|
|
||||||
} else {
|
|
||||||
cov_mark::hit!(coerce_merge_fail_fallback);
|
|
||||||
ty1.clone()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,8 +249,7 @@ impl<'a> InferenceContext<'a> {
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempts to coerce from the type of a Rust function item into a closure
|
/// Attempts to coerce from the type of a Rust function item into a function pointer.
|
||||||
/// or a function pointer.
|
|
||||||
fn coerce_from_fn_item(&mut self, from_ty: Ty, to_ty: &Ty) -> InferResult {
|
fn coerce_from_fn_item(&mut self, from_ty: Ty, to_ty: &Ty) -> InferResult {
|
||||||
match to_ty.kind(&Interner) {
|
match to_ty.kind(&Interner) {
|
||||||
TyKind::Function(_) => {
|
TyKind::Function(_) => {
|
||||||
|
|
|
@ -167,6 +167,7 @@ pub fn make_canonical<T: HasInterner<Interner = Interner>>(
|
||||||
Canonical { value, binders: chalk_ir::CanonicalVarKinds::from_iter(&Interner, kinds) }
|
Canonical { value, binders: chalk_ir::CanonicalVarKinds::from_iter(&Interner, kinds) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: get rid of this, just replace it by FnPointer
|
||||||
/// A function signature as seen by type inference: Several parameter types and
|
/// A function signature as seen by type inference: Several parameter types and
|
||||||
/// one return type.
|
/// one return type.
|
||||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use expect_test::expect;
|
use expect_test::expect;
|
||||||
|
|
||||||
use super::{check_infer, check_infer_with_mismatches};
|
use super::{check_infer, check_infer_with_mismatches, check_types};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn infer_block_expr_type_mismatch() {
|
fn infer_block_expr_type_mismatch() {
|
||||||
|
@ -858,3 +858,18 @@ fn coerce_unsize_generic() {
|
||||||
"]],
|
"]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn infer_two_closures_lub() {
|
||||||
|
check_types(
|
||||||
|
r#"
|
||||||
|
fn foo(c: i32) {
|
||||||
|
let add = |a: i32, b: i32| a + b;
|
||||||
|
let sub = |a, b| a - b;
|
||||||
|
//^ |i32, i32| -> i32
|
||||||
|
if c > 42 { add } else { sub };
|
||||||
|
//^ fn(i32, i32) -> i32
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
@ -1039,42 +1039,6 @@ fn infer_in_elseif() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn infer_closure_unify() {
|
|
||||||
check_infer(
|
|
||||||
r#"
|
|
||||||
fn foo(f: bool) {
|
|
||||||
let a = |x| x;
|
|
||||||
let b = |x| x;
|
|
||||||
let id = if f { a } else { b };
|
|
||||||
id(123);
|
|
||||||
}
|
|
||||||
"#,
|
|
||||||
expect![[r#"
|
|
||||||
7..8 'f': bool
|
|
||||||
16..106 '{ ...23); }': ()
|
|
||||||
26..27 'a': |i32| -> i32
|
|
||||||
30..35 '|x| x': |i32| -> i32
|
|
||||||
31..32 'x': i32
|
|
||||||
34..35 'x': i32
|
|
||||||
45..46 'b': |i32| -> i32
|
|
||||||
49..54 '|x| x': |i32| -> i32
|
|
||||||
50..51 'x': i32
|
|
||||||
53..54 'x': i32
|
|
||||||
64..66 'id': |i32| -> i32
|
|
||||||
69..90 'if f {... { b }': |i32| -> i32
|
|
||||||
72..73 'f': bool
|
|
||||||
74..79 '{ a }': |i32| -> i32
|
|
||||||
76..77 'a': |i32| -> i32
|
|
||||||
85..90 '{ b }': |i32| -> i32
|
|
||||||
87..88 'b': |i32| -> i32
|
|
||||||
96..98 'id': |i32| -> i32
|
|
||||||
96..103 'id(123)': i32
|
|
||||||
99..102 '123': i32
|
|
||||||
"#]],
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn infer_if_match_with_return() {
|
fn infer_if_match_with_return() {
|
||||||
check_infer(
|
check_infer(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue