mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-29 21:35:20 +00:00
Support basic implicit type coerce
This commit is contained in:
parent
5205c84ec7
commit
4bb66df6de
2 changed files with 384 additions and 143 deletions
|
@ -190,6 +190,15 @@ struct InferenceContext<'a, D: HirDatabase> {
|
|||
return_ty: Ty,
|
||||
}
|
||||
|
||||
macro_rules! ty_app {
|
||||
($ctor:pat, $param:pat) => {
|
||||
Ty::Apply(ApplicationTy { ctor: $ctor, parameters: $param })
|
||||
};
|
||||
($ctor:pat) => {
|
||||
ty_app!($ctor, _)
|
||||
};
|
||||
}
|
||||
|
||||
impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||
fn new(db: &'a D, body: Arc<Body>, resolver: Resolver) -> Self {
|
||||
InferenceContext {
|
||||
|
@ -278,10 +287,16 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
let ty1 = self.resolve_ty_shallow(ty1);
|
||||
let ty2 = self.resolve_ty_shallow(ty2);
|
||||
match (&*ty1, &*ty2) {
|
||||
(Ty::Unknown, _) | (_, Ty::Unknown) => true,
|
||||
(Ty::Apply(a_ty1), Ty::Apply(a_ty2)) if a_ty1.ctor == a_ty2.ctor => {
|
||||
self.unify_substs(&a_ty1.parameters, &a_ty2.parameters, depth + 1)
|
||||
}
|
||||
_ => self.unify_inner_trivial(&ty1, &ty2),
|
||||
}
|
||||
}
|
||||
|
||||
fn unify_inner_trivial(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
|
||||
match (ty1, ty2) {
|
||||
(Ty::Unknown, _) | (_, Ty::Unknown) => true,
|
||||
(Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2)))
|
||||
| (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2)))
|
||||
| (Ty::Infer(InferTy::FloatVar(tv1)), Ty::Infer(InferTy::FloatVar(tv2))) => {
|
||||
|
@ -795,50 +810,146 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
ret_ty
|
||||
}
|
||||
|
||||
/// This is similar to unify, but it makes the first type coerce to the
|
||||
/// second one.
|
||||
/// Infer type of expression with possibly implicit coerce to the expected type.
|
||||
fn infer_expr_coerce(&mut self, expr: ExprId, expected: &Expectation) -> Ty {
|
||||
let ty = self.infer_expr_inner(expr, &expected);
|
||||
self.coerce(&ty, &expected.ty);
|
||||
ty
|
||||
}
|
||||
|
||||
/// Unify two types, but may coerce the first one to the second one
|
||||
/// using "implicit coercion rules" if needed.
|
||||
///
|
||||
/// See: https://doc.rust-lang.org/nomicon/coercions.html
|
||||
fn coerce(&mut self, from_ty: &Ty, to_ty: &Ty) -> bool {
|
||||
if is_never(from_ty) {
|
||||
// ! coerces to any type
|
||||
true
|
||||
} else {
|
||||
self.unify(from_ty, to_ty)
|
||||
}
|
||||
let from_ty = self.resolve_ty_shallow(from_ty).into_owned();
|
||||
let to_ty = self.resolve_ty_shallow(to_ty);
|
||||
self.coerce_inner(from_ty, &to_ty)
|
||||
}
|
||||
|
||||
fn unify_with_autoderef(&mut self, from_ty: &Ty, to_ty: &Ty) -> bool {
|
||||
macro_rules! ty_app {
|
||||
($ctor:pat, $param:pat) => {
|
||||
Ty::Apply(ApplicationTy { ctor: $ctor, parameters: $param })
|
||||
};
|
||||
fn coerce_inner(&mut self, mut from_ty: Ty, to_ty: &Ty) -> bool {
|
||||
match (&mut from_ty, &*to_ty) {
|
||||
// Top and bottom type
|
||||
(ty_app!(TypeCtor::Never), _) => return true,
|
||||
|
||||
// FIXME: Solve `FromTy: CoerceUnsized<ToTy>` instead of listing common impls here.
|
||||
|
||||
// `*mut T`, `&mut T, `&T`` -> `*const T`
|
||||
// `&mut T` -> `&T`
|
||||
// `&mut T` -> `*mut T`
|
||||
(ty_app!(c1@TypeCtor::RawPtr(_)), ty_app!(c2@TypeCtor::RawPtr(Mutability::Shared)))
|
||||
| (ty_app!(c1@TypeCtor::Ref(_)), ty_app!(c2@TypeCtor::RawPtr(Mutability::Shared)))
|
||||
| (ty_app!(c1@TypeCtor::Ref(_)), ty_app!(c2@TypeCtor::Ref(Mutability::Shared)))
|
||||
| (ty_app!(c1@TypeCtor::Ref(Mutability::Mut)), ty_app!(c2@TypeCtor::RawPtr(_))) => {
|
||||
*c1 = *c2;
|
||||
}
|
||||
|
||||
// If given type and expected type are compatible reference,
|
||||
// trigger auto-deref.
|
||||
let (_to_mut, from_ty, to_ty) =
|
||||
match (&*self.resolve_ty_shallow(&from_ty), &*self.resolve_ty_shallow(&to_ty)) {
|
||||
// Illegal mutablity conversion
|
||||
(
|
||||
ty_app!(TypeCtor::Ref(from_mut), from_param),
|
||||
ty_app!(TypeCtor::Ref(to_mut), to_param),
|
||||
) if *from_mut == Mutability::Mut || from_mut == to_mut => {
|
||||
(to_mut, from_param[0].clone(), to_param[0].clone())
|
||||
}
|
||||
_ => {
|
||||
// Otherwise, just unify
|
||||
return self.unify(&from_ty, &to_ty);
|
||||
}
|
||||
};
|
||||
ty_app!(TypeCtor::RawPtr(Mutability::Shared)),
|
||||
ty_app!(TypeCtor::RawPtr(Mutability::Mut)),
|
||||
)
|
||||
| (
|
||||
ty_app!(TypeCtor::Ref(Mutability::Shared)),
|
||||
ty_app!(TypeCtor::Ref(Mutability::Mut)),
|
||||
) => return false,
|
||||
|
||||
let canonicalized = self.canonicalizer().canonicalize_ty(from_ty);
|
||||
// `{function_type}` -> `fn()`
|
||||
(ty_app!(TypeCtor::FnDef(_)), ty_app!(TypeCtor::FnPtr { .. })) => {
|
||||
match from_ty.callable_sig(self.db) {
|
||||
None => return false,
|
||||
Some(sig) => {
|
||||
let num_args = sig.params_and_return.len() as u16 - 1;
|
||||
from_ty =
|
||||
Ty::apply(TypeCtor::FnPtr { num_args }, Substs(sig.params_and_return));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Trivial cases, this should go after `never` check to
|
||||
// avoid infer result type to be never
|
||||
_ => {
|
||||
if self.unify_inner_trivial(&from_ty, &to_ty) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Try coerce or unify
|
||||
match (&from_ty, &to_ty) {
|
||||
// FIXME: Solve `FromTy: CoerceUnsized<ToTy>` instead of listing common impls here.
|
||||
(ty_app!(TypeCtor::Ref(_), st1), ty_app!(TypeCtor::Ref(_), st2))
|
||||
| (ty_app!(TypeCtor::RawPtr(_), st1), ty_app!(TypeCtor::RawPtr(_), st2)) => {
|
||||
match self.try_coerce_unsized(&st1[0], &st2[0], 0) {
|
||||
Some(ret) => return ret,
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Auto Deref if cannot coerce
|
||||
match (&from_ty, &to_ty) {
|
||||
(ty_app!(TypeCtor::Ref(_), st1), ty_app!(TypeCtor::Ref(_), st2)) => {
|
||||
self.unify_autoderef_behind_ref(&st1[0], &st2[0])
|
||||
}
|
||||
|
||||
// Normal unify
|
||||
_ => self.unify(&from_ty, &to_ty),
|
||||
}
|
||||
}
|
||||
|
||||
/// Coerce a type to a DST if `FromTy: Unsize<ToTy>`
|
||||
///
|
||||
/// See: `https://doc.rust-lang.org/nightly/std/marker/trait.Unsize.html`
|
||||
fn try_coerce_unsized(&mut self, from_ty: &Ty, to_ty: &Ty, depth: usize) -> Option<bool> {
|
||||
if depth > 1000 {
|
||||
panic!("Infinite recursion in coercion");
|
||||
}
|
||||
|
||||
// FIXME: Correctly handle
|
||||
match (&from_ty, &to_ty) {
|
||||
// `[T; N]` -> `[T]`
|
||||
(ty_app!(TypeCtor::Array, st1), ty_app!(TypeCtor::Slice, st2)) => {
|
||||
Some(self.unify(&st1[0], &st2[0]))
|
||||
}
|
||||
|
||||
// `T` -> `dyn Trait` when `T: Trait`
|
||||
(_, Ty::Dyn(_)) => {
|
||||
// FIXME: Check predicates
|
||||
Some(true)
|
||||
}
|
||||
|
||||
(ty_app!(ctor1, st1), ty_app!(ctor2, st2)) if ctor1 == ctor2 => {
|
||||
for (ty1, ty2) in st1.iter().zip(st2.iter()) {
|
||||
match self.try_coerce_unsized(ty1, ty2, depth + 1) {
|
||||
Some(true) => {}
|
||||
ret => return ret,
|
||||
}
|
||||
}
|
||||
Some(true)
|
||||
}
|
||||
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Unify `from_ty` to `to_ty` with optional auto Deref
|
||||
///
|
||||
/// Note that the parameters are already stripped the outer reference.
|
||||
fn unify_autoderef_behind_ref(&mut self, from_ty: &Ty, to_ty: &Ty) -> bool {
|
||||
let canonicalized = self.canonicalizer().canonicalize_ty(from_ty.clone());
|
||||
let to_ty = self.resolve_ty_shallow(&to_ty);
|
||||
// FIXME: Auto DerefMut
|
||||
for derefed_ty in
|
||||
autoderef::autoderef(self.db, &self.resolver.clone(), canonicalized.value.clone())
|
||||
{
|
||||
let derefed_ty = canonicalized.decanonicalize_ty(derefed_ty.value);
|
||||
match (&*self.resolve_ty_shallow(&derefed_ty), &*self.resolve_ty_shallow(&to_ty)) {
|
||||
// Unify when constructor matches.
|
||||
(ty_app!(from_ctor, _), ty_app!(to_ctor, _)) if from_ctor == to_ctor => {
|
||||
return self.unify(&derefed_ty, &to_ty);
|
||||
match (&*self.resolve_ty_shallow(&derefed_ty), &*to_ty) {
|
||||
// Stop when constructor matches.
|
||||
(ty_app!(from_ctor, st1), ty_app!(to_ctor, st2)) if from_ctor == to_ctor => {
|
||||
// It will not recurse to `coerce`.
|
||||
return self.unify_substs(st1, st2, 0);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -875,10 +986,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
Some(else_branch) => self.infer_expr_inner(*else_branch, &expected),
|
||||
None => Ty::unit(),
|
||||
};
|
||||
self.coerce(&else_ty, &expected.ty);
|
||||
|
||||
if !self.coerce(&else_ty, &expected.ty) {
|
||||
self.coerce(&expected.ty, &else_ty);
|
||||
else_ty.clone()
|
||||
} else {
|
||||
expected.ty.clone()
|
||||
}
|
||||
}
|
||||
Expr::Block { statements, tail } => self.infer_block(statements, *tail, expected),
|
||||
Expr::TryBlock { body } => {
|
||||
let _inner = self.infer_expr(*body, expected);
|
||||
|
@ -973,13 +1087,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
.infer_method_call(tgt_expr, *receiver, &args, &method_name, generic_args.as_ref()),
|
||||
Expr::Match { expr, arms } => {
|
||||
let input_ty = self.infer_expr(*expr, &Expectation::none());
|
||||
let expected = if expected.ty == Ty::Unknown {
|
||||
Expectation::has_type(self.new_type_var())
|
||||
} else {
|
||||
expected.clone()
|
||||
let mut expected = match expected.ty {
|
||||
Ty::Unknown => Expectation::has_type(Ty::simple(TypeCtor::Never)),
|
||||
_ => expected.clone(),
|
||||
};
|
||||
|
||||
let mut arm_tys = Vec::with_capacity(arms.len());
|
||||
let mut all_never = true;
|
||||
|
||||
for arm in arms {
|
||||
for &pat in &arm.pats {
|
||||
|
@ -991,16 +1103,22 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
&Expectation::has_type(Ty::simple(TypeCtor::Bool)),
|
||||
);
|
||||
}
|
||||
arm_tys.push(self.infer_expr_inner(arm.expr, &expected));
|
||||
let arm_ty = self.infer_expr_inner(arm.expr, &expected);
|
||||
match &arm_ty {
|
||||
ty_app!(TypeCtor::Never) => (),
|
||||
_ => all_never = false,
|
||||
}
|
||||
if !self.coerce(&arm_ty, &expected.ty) {
|
||||
self.coerce(&expected.ty, &arm_ty);
|
||||
expected = Expectation::has_type(arm_ty);
|
||||
}
|
||||
}
|
||||
|
||||
let lub_ty = calculate_least_upper_bound(expected.ty, &arm_tys);
|
||||
|
||||
for arm_ty in &arm_tys {
|
||||
self.coerce(arm_ty, &lub_ty);
|
||||
if all_never {
|
||||
Ty::simple(TypeCtor::Never)
|
||||
} else {
|
||||
expected.ty
|
||||
}
|
||||
|
||||
lub_ty
|
||||
}
|
||||
Expr::Path(p) => {
|
||||
// FIXME this could be more efficient...
|
||||
|
@ -1289,8 +1407,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
type_ref.as_ref().map(|tr| self.make_ty(tr)).unwrap_or(Ty::Unknown);
|
||||
let decl_ty = self.insert_type_vars(decl_ty);
|
||||
let ty = if let Some(expr) = initializer {
|
||||
let expr_ty = self.infer_expr(*expr, &Expectation::has_type(decl_ty));
|
||||
expr_ty
|
||||
self.infer_expr_coerce(*expr, &Expectation::has_type(decl_ty))
|
||||
} else {
|
||||
decl_ty
|
||||
};
|
||||
|
@ -1326,8 +1443,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
}
|
||||
|
||||
let param_ty = self.normalize_associated_types_in(param_ty);
|
||||
let arg_ty = self.infer_expr_inner(arg, &Expectation::has_type(param_ty.clone()));
|
||||
self.unify_with_autoderef(&arg_ty, ¶m_ty);
|
||||
self.infer_expr_coerce(arg, &Expectation::has_type(param_ty.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1517,37 +1633,3 @@ mod diagnostics {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_never(ty: &Ty) -> bool {
|
||||
if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Never, .. }) = ty {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn calculate_least_upper_bound(expected_ty: Ty, actual_tys: &[Ty]) -> Ty {
|
||||
let mut all_never = true;
|
||||
let mut last_never_ty = None;
|
||||
let mut least_upper_bound = expected_ty;
|
||||
|
||||
for actual_ty in actual_tys {
|
||||
if is_never(actual_ty) {
|
||||
last_never_ty = Some(actual_ty.clone());
|
||||
} else {
|
||||
all_never = false;
|
||||
least_upper_bound = match (actual_ty, &least_upper_bound) {
|
||||
(_, Ty::Unknown)
|
||||
| (Ty::Infer(_), Ty::Infer(InferTy::TypeVar(_)))
|
||||
| (Ty::Apply(_), _) => actual_ty.clone(),
|
||||
_ => least_upper_bound,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if all_never && last_never_ty.is_some() {
|
||||
last_never_ty.unwrap()
|
||||
} else {
|
||||
least_upper_bound
|
||||
}
|
||||
}
|
||||
|
|
|
@ -806,14 +806,14 @@ fn infer_argument_autoderef() {
|
|||
infer(r#"
|
||||
#[lang = "deref"]
|
||||
pub trait Deref {
|
||||
type Target: ?Sized;
|
||||
type Target;
|
||||
fn deref(&self) -> &Self::Target;
|
||||
}
|
||||
|
||||
struct A<T>(T);
|
||||
|
||||
impl<T: Copy> A<T> {
|
||||
fn foo(&self) -> T {
|
||||
impl<T> A<T> {
|
||||
fn foo(&self) -> &T {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
@ -828,32 +828,33 @@ impl<T> Deref for B<T> {
|
|||
}
|
||||
|
||||
fn test() {
|
||||
A::foo(&&B(B(A(42))));
|
||||
let t = A::foo(&&B(B(A(42))));
|
||||
}
|
||||
"#),
|
||||
@r###"
|
||||
[76; 80) 'self': &Self
|
||||
[153; 157) 'self': &A<T>
|
||||
[164; 186) '{ ... }': T
|
||||
[174; 178) 'self': &A<T>
|
||||
[174; 180) 'self.0': T
|
||||
[267; 271) 'self': &B<T>
|
||||
[290; 313) '{ ... }': &T
|
||||
[300; 307) '&self.0': &T
|
||||
[301; 305) 'self': &B<T>
|
||||
[301; 307) 'self.0': T
|
||||
[327; 357) '{ ...))); }': ()
|
||||
[333; 339) 'A::foo': fn foo<i32>(&A<T>) -> T
|
||||
[333; 354) 'A::foo...42))))': i32
|
||||
[340; 353) '&&B(B(A(42)))': &&B<B<A<i32>>>
|
||||
[341; 353) '&B(B(A(42)))': &B<B<A<i32>>>
|
||||
[342; 343) 'B': B<B<A<i32>>>(T) -> B<T>
|
||||
[342; 353) 'B(B(A(42)))': B<B<A<i32>>>
|
||||
[344; 345) 'B': B<A<i32>>(T) -> B<T>
|
||||
[344; 352) 'B(A(42))': B<A<i32>>
|
||||
[346; 347) 'A': A<i32>(T) -> A<T>
|
||||
[346; 351) 'A(42)': A<i32>
|
||||
[348; 350) '42': i32
|
||||
[68; 72) 'self': &Self
|
||||
[139; 143) 'self': &A<T>
|
||||
[151; 173) '{ ... }': T
|
||||
[161; 165) 'self': &A<T>
|
||||
[161; 167) 'self.0': T
|
||||
[254; 258) 'self': &B<T>
|
||||
[277; 300) '{ ... }': &T
|
||||
[287; 294) '&self.0': &T
|
||||
[288; 292) 'self': &B<T>
|
||||
[288; 294) 'self.0': T
|
||||
[314; 352) '{ ...))); }': ()
|
||||
[324; 325) 't': &i32
|
||||
[328; 334) 'A::foo': fn foo<i32>(&A<T>) -> &T
|
||||
[328; 349) 'A::foo...42))))': &i32
|
||||
[335; 348) '&&B(B(A(42)))': &&B<B<A<i32>>>
|
||||
[336; 348) '&B(B(A(42)))': &B<B<A<i32>>>
|
||||
[337; 338) 'B': B<B<A<i32>>>(T) -> B<T>
|
||||
[337; 348) 'B(B(A(42)))': B<B<A<i32>>>
|
||||
[339; 340) 'B': B<A<i32>>(T) -> B<T>
|
||||
[339; 347) 'B(A(42))': B<A<i32>>
|
||||
[341; 342) 'A': A<i32>(T) -> A<T>
|
||||
[341; 346) 'A(42)': A<i32>
|
||||
[343; 345) '42': i32
|
||||
"###
|
||||
);
|
||||
}
|
||||
|
@ -864,15 +865,15 @@ fn infer_method_argument_autoderef() {
|
|||
infer(r#"
|
||||
#[lang = "deref"]
|
||||
pub trait Deref {
|
||||
type Target: ?Sized;
|
||||
type Target;
|
||||
fn deref(&self) -> &Self::Target;
|
||||
}
|
||||
|
||||
struct A<T>(*mut T);
|
||||
|
||||
impl<T: Copy> A<T> {
|
||||
fn foo(&self, x: &A<T>) -> T {
|
||||
x
|
||||
impl<T> A<T> {
|
||||
fn foo(&self, x: &A<T>) -> &T {
|
||||
&*x.0
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -886,38 +887,196 @@ impl<T> Deref for B<T> {
|
|||
}
|
||||
|
||||
fn test(a: A<i32>) {
|
||||
A(0 as *mut _).foo(&&B(B(a)));
|
||||
let t = A(0 as *mut _).foo(&&B(B(a)));
|
||||
}
|
||||
"#),
|
||||
@r###"
|
||||
[76; 80) 'self': &Self
|
||||
[158; 162) 'self': &A<T>
|
||||
[164; 165) 'x': &A<T>
|
||||
[179; 196) '{ ... }': &A<T>
|
||||
[189; 190) 'x': &A<T>
|
||||
[277; 281) 'self': &B<T>
|
||||
[300; 323) '{ ... }': &T
|
||||
[310; 317) '&self.0': &T
|
||||
[311; 315) 'self': &B<T>
|
||||
[311; 317) 'self.0': T
|
||||
[335; 336) 'a': A<i32>
|
||||
[346; 384) '{ ...))); }': ()
|
||||
[352; 353) 'A': A<i32>(*mut T) -> A<T>
|
||||
[352; 366) 'A(0 as *mut _)': A<i32>
|
||||
[352; 381) 'A(0 as...B(a)))': i32
|
||||
[354; 355) '0': i32
|
||||
[354; 365) '0 as *mut _': *mut i32
|
||||
[371; 380) '&&B(B(a))': &&B<B<A<i32>>>
|
||||
[372; 380) '&B(B(a))': &B<B<A<i32>>>
|
||||
[373; 374) 'B': B<B<A<i32>>>(T) -> B<T>
|
||||
[373; 380) 'B(B(a))': B<B<A<i32>>>
|
||||
[375; 376) 'B': B<A<i32>>(T) -> B<T>
|
||||
[375; 379) 'B(a)': B<A<i32>>
|
||||
[377; 378) 'a': A<i32>
|
||||
[68; 72) 'self': &Self
|
||||
[144; 148) 'self': &A<T>
|
||||
[150; 151) 'x': &A<T>
|
||||
[166; 187) '{ ... }': &T
|
||||
[176; 181) '&*x.0': &T
|
||||
[177; 181) '*x.0': T
|
||||
[178; 179) 'x': &A<T>
|
||||
[178; 181) 'x.0': *mut T
|
||||
[268; 272) 'self': &B<T>
|
||||
[291; 314) '{ ... }': &T
|
||||
[301; 308) '&self.0': &T
|
||||
[302; 306) 'self': &B<T>
|
||||
[302; 308) 'self.0': T
|
||||
[326; 327) 'a': A<i32>
|
||||
[337; 383) '{ ...))); }': ()
|
||||
[347; 348) 't': &i32
|
||||
[351; 352) 'A': A<i32>(*mut T) -> A<T>
|
||||
[351; 365) 'A(0 as *mut _)': A<i32>
|
||||
[351; 380) 'A(0 as...B(a)))': &i32
|
||||
[353; 354) '0': i32
|
||||
[353; 364) '0 as *mut _': *mut i32
|
||||
[370; 379) '&&B(B(a))': &&B<B<A<i32>>>
|
||||
[371; 379) '&B(B(a))': &B<B<A<i32>>>
|
||||
[372; 373) 'B': B<B<A<i32>>>(T) -> B<T>
|
||||
[372; 379) 'B(B(a))': B<B<A<i32>>>
|
||||
[374; 375) 'B': B<A<i32>>(T) -> B<T>
|
||||
[374; 378) 'B(a)': B<A<i32>>
|
||||
[376; 377) 'a': A<i32>
|
||||
"###
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn infer_if_coerce() {
|
||||
assert_snapshot!(
|
||||
infer(r#"
|
||||
fn foo<T>(x: &[T]) -> &[T] { loop {} }
|
||||
fn test() {
|
||||
let x = if true {
|
||||
foo(&[1])
|
||||
} else {
|
||||
&[1]
|
||||
};
|
||||
}
|
||||
"#),
|
||||
@r###"
|
||||
[11; 12) 'x': &[T]
|
||||
[28; 39) '{ loop {} }': !
|
||||
[30; 37) 'loop {}': !
|
||||
[35; 37) '{}': ()
|
||||
[50; 126) '{ ... }; }': ()
|
||||
[60; 61) 'x': &[i32]
|
||||
[64; 123) 'if tru... }': &[i32]
|
||||
[67; 71) 'true': bool
|
||||
[72; 97) '{ ... }': &[i32]
|
||||
[82; 85) 'foo': fn foo<i32>(&[T]) -> &[T]
|
||||
[82; 91) 'foo(&[1])': &[i32]
|
||||
[86; 90) '&[1]': &[i32;_]
|
||||
[87; 90) '[1]': [i32;_]
|
||||
[88; 89) '1': i32
|
||||
[103; 123) '{ ... }': &[i32;_]
|
||||
[113; 117) '&[1]': &[i32;_]
|
||||
[114; 117) '[1]': [i32;_]
|
||||
[115; 116) '1': i32
|
||||
"###
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn infer_if_else_coerce() {
|
||||
assert_snapshot!(
|
||||
infer(r#"
|
||||
fn foo<T>(x: &[T]) -> &[T] { loop {} }
|
||||
fn test() {
|
||||
let x = if true {
|
||||
&[1]
|
||||
} else {
|
||||
foo(&[1])
|
||||
};
|
||||
}
|
||||
"#),
|
||||
@r###"
|
||||
[11; 12) 'x': &[T]
|
||||
[28; 39) '{ loop {} }': !
|
||||
[30; 37) 'loop {}': !
|
||||
[35; 37) '{}': ()
|
||||
[50; 126) '{ ... }; }': ()
|
||||
[60; 61) 'x': &[i32]
|
||||
[64; 123) 'if tru... }': &[i32]
|
||||
[67; 71) 'true': bool
|
||||
[72; 92) '{ ... }': &[i32;_]
|
||||
[82; 86) '&[1]': &[i32;_]
|
||||
[83; 86) '[1]': [i32;_]
|
||||
[84; 85) '1': i32
|
||||
[98; 123) '{ ... }': &[i32]
|
||||
[108; 111) 'foo': fn foo<i32>(&[T]) -> &[T]
|
||||
[108; 117) 'foo(&[1])': &[i32]
|
||||
[112; 116) '&[1]': &[i32;_]
|
||||
[113; 116) '[1]': [i32;_]
|
||||
[114; 115) '1': i32
|
||||
"###
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn infer_match_first_coerce() {
|
||||
assert_snapshot!(
|
||||
infer(r#"
|
||||
fn foo<T>(x: &[T]) -> &[T] { loop {} }
|
||||
fn test(i: i32) {
|
||||
let x = match i {
|
||||
2 => foo(&[2]),
|
||||
1 => &[1],
|
||||
_ => &[3],
|
||||
};
|
||||
}
|
||||
"#),
|
||||
@r###"
|
||||
[11; 12) 'x': &[T]
|
||||
[28; 39) '{ loop {} }': !
|
||||
[30; 37) 'loop {}': !
|
||||
[35; 37) '{}': ()
|
||||
[48; 49) 'i': i32
|
||||
[56; 150) '{ ... }; }': ()
|
||||
[66; 67) 'x': &[i32]
|
||||
[70; 147) 'match ... }': &[i32]
|
||||
[76; 77) 'i': i32
|
||||
[88; 89) '2': i32
|
||||
[93; 96) 'foo': fn foo<i32>(&[T]) -> &[T]
|
||||
[93; 102) 'foo(&[2])': &[i32]
|
||||
[97; 101) '&[2]': &[i32;_]
|
||||
[98; 101) '[2]': [i32;_]
|
||||
[99; 100) '2': i32
|
||||
[112; 113) '1': i32
|
||||
[117; 121) '&[1]': &[i32;_]
|
||||
[118; 121) '[1]': [i32;_]
|
||||
[119; 120) '1': i32
|
||||
[131; 132) '_': i32
|
||||
[136; 140) '&[3]': &[i32;_]
|
||||
[137; 140) '[3]': [i32;_]
|
||||
[138; 139) '3': i32
|
||||
"###
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn infer_match_second_coerce() {
|
||||
assert_snapshot!(
|
||||
infer(r#"
|
||||
fn foo<T>(x: &[T]) -> &[T] { loop {} }
|
||||
fn test(i: i32) {
|
||||
let x = match i {
|
||||
1 => &[1],
|
||||
2 => foo(&[2]),
|
||||
_ => &[3],
|
||||
};
|
||||
}
|
||||
"#),
|
||||
@r###"
|
||||
[11; 12) 'x': &[T]
|
||||
[28; 39) '{ loop {} }': !
|
||||
[30; 37) 'loop {}': !
|
||||
[35; 37) '{}': ()
|
||||
[48; 49) 'i': i32
|
||||
[56; 150) '{ ... }; }': ()
|
||||
[66; 67) 'x': &[i32]
|
||||
[70; 147) 'match ... }': &[i32]
|
||||
[76; 77) 'i': i32
|
||||
[88; 89) '1': i32
|
||||
[93; 97) '&[1]': &[i32;_]
|
||||
[94; 97) '[1]': [i32;_]
|
||||
[95; 96) '1': i32
|
||||
[107; 108) '2': i32
|
||||
[112; 115) 'foo': fn foo<i32>(&[T]) -> &[T]
|
||||
[112; 121) 'foo(&[2])': &[i32]
|
||||
[116; 120) '&[2]': &[i32;_]
|
||||
[117; 120) '[2]': [i32;_]
|
||||
[118; 119) '2': i32
|
||||
[131; 132) '_': i32
|
||||
[136; 140) '&[3]': &[i32;_]
|
||||
[137; 140) '[3]': [i32;_]
|
||||
[138; 139) '3': i32
|
||||
"###
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bug_484() {
|
||||
assert_snapshot!(
|
||||
|
@ -3474,7 +3633,7 @@ trait Deref {
|
|||
}
|
||||
|
||||
struct Arc<T>;
|
||||
impl<T: ?Sized> Deref for Arc<T> {
|
||||
impl<T> Deref for Arc<T> {
|
||||
type Target = T;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue