# Smart cast and type inference of generics

**URL:** <https://discuss.kotlinlang.org/t/smart-cast-and-type-inference-of-generics/9305>\
**Category:** Uncategorized\
**Created:** [September 3, 2018, 12:12pm UTC](https://discuss.kotlinlang.org/t/smart-cast-and-type-inference-of-generics/9305 "2018-09-03T12:12:44Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![wumo](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/wumo/32/3831_2.png) [@wumo](https://discuss.kotlinlang.org/u/wumo)\
**Post date:** [September 3, 2018, 12:12pm UTC](https://discuss.kotlinlang.org/t/smart-cast-and-type-inference-of-generics/9305/1 "2018-09-03T12:12:44Z")

</div>

See the code below:

```auto
interface A

class B : A

fun <T> identity(a: T): T = a

fun <T> f1(b: T) {
  if (b is B) {
    val tmp = identity(b)
    val c: B = tmp // Error:(12, 16) Kotlin: Type mismatch: inferred type is Any? but B was expected
  }
}

fun <T> f2(b: T) {
  if (b is B) {
    val tmp: B = identity(b)
    val c: B = tmp // this compiles ok.
  }
}

```

In both cases, the type of variable `tmp` is determined in compile time, and can be inferred directly.

while function `f1` doesn’t compile and throw “Error:(12, 16) Kotlin: Type mismatch: inferred type is Any? but B was expected”, function `f2` compiles without errors.

---

<div class="post-metadata">

**Author:** ![fvasco](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/fvasco/32/1961_2.png) [@fvasco](https://discuss.kotlinlang.org/u/fvasco)\
**Post date:** [September 3, 2018, 12:41pm UTC](https://discuss.kotlinlang.org/t/smart-cast-and-type-inference-of-generics/9305/2 "2018-09-03T12:41:13Z")

</div>

A quick quiz

```kotlin
if ( b is B1 && b is B2 ) {
    val tmp = identity(b)
}

```

what is the type of `tmp`?

---

<div class="post-metadata">

**Author:** ![wumo](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/wumo/32/3831_2.png) [@wumo](https://discuss.kotlinlang.org/u/wumo)\
**Post date:** [September 3, 2018, 12:46pm UTC](https://discuss.kotlinlang.org/t/smart-cast-and-type-inference-of-generics/9305/3 "2018-09-03T12:46:22Z")

</div>

It should be the intersection of B1 and B2, but Kotlin doesn’t have it.

---

<div class="post-metadata">

**Author:** ![fvasco](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/fvasco/32/1961_2.png) [@fvasco](https://discuss.kotlinlang.org/u/fvasco)\
**Post date:** [September 3, 2018, 1:24pm UTC](https://discuss.kotlinlang.org/t/smart-cast-and-type-inference-of-generics/9305/4 "2018-09-03T13:24:54Z")

</div>

> [@wumo](#):
>
> It should be the intersection

It should be the **union** of both

---

<div class="post-metadata">

**Author:** ![wumo](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/wumo/32/3831_2.png) [@wumo](https://discuss.kotlinlang.org/u/wumo)\
**Post date:** [September 3, 2018, 1:28pm UTC](https://discuss.kotlinlang.org/t/smart-cast-and-type-inference-of-generics/9305/5 "2018-09-03T13:28:47Z")

</div>

I don’t understand. Will the `tmp` of the below be `union` of B1 and B2?

```auto
if( b is B1 || b is B2){
    val tmp = identity(b)
}

```

---

<div class="post-metadata">

**Author:** ![medium](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/medium/32/10404_2.png) [@medium](https://discuss.kotlinlang.org/u/medium)\
**Post date:** [September 3, 2018, 1:36pm UTC](https://discuss.kotlinlang.org/t/smart-cast-and-type-inference-of-generics/9305/6 "2018-09-03T13:36:19Z")

</div>

It _should_ be the _union_, but it **is** the **intersection** , which is `Any` since there is no other type common to `B1` and `B2` (since Kotlin doesn’t have union types).

---

<div class="post-metadata">

**Author:** ![fatjoe79](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/fatjoe79/32/4221_2.png) [@fatjoe79](https://discuss.kotlinlang.org/u/fatjoe79)\
**Post date:** [September 3, 2018, 3:22pm UTC](https://discuss.kotlinlang.org/t/smart-cast-and-type-inference-of-generics/9305/7 "2018-09-03T15:22:48Z")

</div>

Why are you changing the Boolean operator from && to || in the middle of the conversation? It makes it very confusing to discuss.

In my opinion the answer to the original quiz (`b is B1 && b is B2`) should be the intersection. This expression can only be true if B1=B2 or there is a subtype relation between them. In the later case the answer would be the subtype, which effectively is the intersection, isn’t it?

> [@fvasco](#):
>
> what is the type of `tmp`?

Wouldn’t it be B1 or B2, whichever is the subtype of the other?

---

<div class="post-metadata">

**Author:** ![fvasco](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/fvasco/32/1961_2.png) [@fvasco](https://discuss.kotlinlang.org/u/fvasco)\
**Post date:** [September 3, 2018, 5:15pm UTC](https://discuss.kotlinlang.org/t/smart-cast-and-type-inference-of-generics/9305/8 "2018-09-03T17:15:04Z")

</div>

`B1` and `B2` in the example can be interfaces, ie: `B1 = Comparable` and `B2 = CharSequence`, so a `String` is an instance of both, so I can invoke both `compareTo` and `subSequence`.

Kotlin sarch for the greatest common parent, in the @wumo example `B1` is `B` and `B2` is the T upper bound `Any?`, so the intersection between `B` and `Any?` is `Any?`.

> [@medium](#):
>
> It _should_ be the _union_ , but it **is** the **intersection**

---

<div class="post-metadata">

**Author:** ![jstuyts](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/jstuyts/32/2141_2.png) [@jstuyts](https://discuss.kotlinlang.org/u/jstuyts)\
**Post date:** [September 3, 2018, 8:44pm UTC](https://discuss.kotlinlang.org/t/smart-cast-and-type-inference-of-generics/9305/9 "2018-09-03T20:44:43Z")

</div>

I think it is a shortcoming of the compiler. The compiler knows that `b` is a `B` (if you assign `b` instead of `tmp` to `c`, the compiler does not emit errors). So the compiler should also be able to correctly infer that the result type of `identity(b)` is `B` (because it is the most specific type that the compiler knows about).

If you start combining multiple `is` expressions, then the compiler has no choice but to choose the least specific type that satisfies the combined expression.

---

<div class="post-metadata">

**Author:** ![roryaburks](https://avatars.discourse-cdn.com/v4/letter/r/67e7ee/32.png) [@roryaburks](https://discuss.kotlinlang.org/u/roryaburks)\
**Post date:** [September 5, 2018, 9:28pm UTC](https://discuss.kotlinlang.org/t/smart-cast-and-type-inference-of-generics/9305/10 "2018-09-05T21:28:31Z")

</div>

The SmartCaster is just being a bit greedy with its types.

Line by line:

1. SmartCaster deremines that b is B
2. You assign tmp to `identity(b)`. At this point it asks “what is `<T>`?” and determines b : T, so T = T. I suppose SmartCast logic COULD determine that b is B means T is a subclass of B and use `identity<B>(b)`, but at this point that comparison only exists in this floating SmartCast logic, not as an actual trait of b, so it just grabs the type it knows.
3. Now that tmp : T, the smartcast has no idea that tmp is B. It doesn’t know that identity returned b, it just knows it got a T.

In this case there would probably be no harm in smart casting identity(b) to `identity<B>(b)` rather than `identity<T>(b)`, but in general I hesitate trying to make the SmartCaster too clever. It’s not meant to meta-compile and logically deduce everything that’s logically deducible; it’s just meant to grease the wheels and make nullables and type casting not require a ton of redundant checks in even the simplest cases.

---

<div class="post-metadata">

**Author:** ![dalewking](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/dalewking/32/1496_2.png) [@dalewking](https://discuss.kotlinlang.org/u/dalewking)\
**Post date:** [September 6, 2018, 7:19pm UTC](https://discuss.kotlinlang.org/t/smart-cast-and-type-inference-of-generics/9305/11 "2018-09-06T19:19:52Z")

</div>

Have only glanced at the new contract stuff that is coming, but would it let you tell the compiler enough to get around this?

---

<div class="post-metadata">

**Author:** ![noo.blaster](https://avatars.discourse-cdn.com/v4/letter/n/ac91a4/32.png) [@noo.blaster](https://discuss.kotlinlang.org/u/noo.blaster)\
**Post date:** [September 7, 2018, 8:56pm UTC](https://discuss.kotlinlang.org/t/smart-cast-and-type-inference-of-generics/9305/12 "2018-09-07T20:56:23Z")

</div>

Why do you expect T to be inferred as B in f1
