robstoll/atrium

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's V is defined as out). 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

We will turn Assert into an interface with an invariant type parameter (see #26)
We will introduce Expect as new interface (Assert will not change in order that we can keep backward compatibility)

PoC implemented db7709b, rest will follow

This issue is overlapping with #26 implemented everything needed for this issue