Expect<T>.toBe, contains etc. should only accept T and not Any
robstoll opened this issue · 4 comments
Platform (JVM and/or JS): all
Code related feature
assert(listOf(1, 2)).contains("apple", "banana")
val l: List<Int> = listOf(1,2)
assert(l).contains("apple", "banana")
val a: Assert<List<Int>> = assert(l)
a.contains("apple", "banana")
IMO this should result in three compile errors. Yet, it does not because the compiler falls back to type the left hand side of contains
as Assert<Iterable<Any>>
. Maybe we could improve the situation by using @OnlyInputTypes. This would require some trickery because it is not officially supported and might cause problems in the future (if it is removed by Jetbrains) but might be worth while nonetheless.
https://youtrack.jetbrains.com/issue/KT-13198
Another possibility would be to remove out
from Assert<out T>
. Has a similar result but does not rely on Kotlin's internals:
assert(1).toBe(2.0) //error Int expected
assert(listOf<Number>(1,2)).toBe(listOf<Int>(1, 2)) // still works
fun Assert<Collection<*>>.hasSize(i: Int): Assert<Collection<*>> { ... }
assert(listOf(1,2)).hasSize(1) // does not work, should have been defined as <T: Collection<*>> Assert<T>
I think this would also solve #60 as assertion functions with <T: Any?> Assert<T>
would no longer show up if we have an <T: Any> Assert<T>
- well no, it still shows up but I guess we could unify nullable and non-nullable overloads in some cases. For instance
Assert<Map<...>>.contains
containsNullable would no-longer be necessary, only for pointing nullability out (well, that's kind of true already). - nope, then we can pass
null
as value even though we don't have a nullable-value type (because Map'sV
is defined asout
). We cannot even fix this with OnlyInputTypes, we would need to be able to restrict user site variance (see https://youtrack.jetbrains.com/issue/KT-24799).
Anyway, removing out
is a BC break, so we have to wait for 1.0.0