Relax type parameter constraint for Closeable.use and AutoCloseable.use to allow nullable receiver.

#KT-12894 Fixed
This commit is contained in:
Ilya Gorbunov
2016-06-29 17:19:57 +03:00
parent e04873957e
commit 22ee3a8dc1
5 changed files with 68 additions and 6 deletions
+3 -3
View File
@@ -3,17 +3,17 @@ package kotlin
@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
@kotlin.internal.InlineOnly
public inline fun <T : AutoCloseable, R> T.use(block: (T) -> R): R {
public inline fun <T : AutoCloseable?, R> T.use(block: (T) -> R): R {
var closed = false
try {
return block(this)
} catch (e: Throwable) {
closed = true
@Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE")
closeSuppressed(e)
this?.closeSuppressed(e)
throw e
} finally {
if (!closed) {
if (this != null && !closed) {
close()
}
}
@@ -2,11 +2,14 @@ package kotlin.jdk7.test
import java.io.*
import org.junit.Test
import java.util.*
import kotlin.test.*
class TryWithResourcesAutoCloseableTest {
@Suppress("HasPlatformType") fun <T> platformNull() = Collections.singletonList(null as T).first()
class Resource(val faultyClose: Boolean = false) : AutoCloseable {
var isClosed = false
@@ -80,7 +83,31 @@ class TryWithResourcesAutoCloseableTest {
assertEquals("nonLocal", result)
assertTrue(resource.isClosed)
}
}
@Test fun nullableResourceSuccess() {
val resource: Resource? = null
val result = resource.use { "ok" }
assertEquals("ok", result)
}
@Test fun nullableResourceOpFails() {
val resource: Resource? = null
val e = assertFails {
resource.use { requireNotNull(it) }
}
assertTrue(e is IllegalArgumentException)
assertTrue(e.suppressed.isEmpty())
}
@Test fun platformResourceOpFails() {
val resource = platformNull<Resource>()
val e = assertFails {
resource.use { requireNotNull(it) }
}
assertTrue(e is IllegalArgumentException)
assertTrue(e.suppressed.isEmpty())
}
}
@@ -2,10 +2,13 @@ package kotlin.jdk7.test
import java.io.*
import org.junit.Test
import java.util.*
import kotlin.test.*
class TryWithResourcesCloseableTest {
@Suppress("HasPlatformType") fun <T> platformNull() = Collections.singletonList(null as T).first()
class Resource(val faultyClose: Boolean = false) : Closeable {
var isClosed = false
@@ -81,4 +84,27 @@ class TryWithResourcesCloseableTest {
}
@Test fun nullableResourceSuccess() {
val resource: Resource? = null
val result = resource.use { "ok" }
assertEquals("ok", result)
}
@Test fun nullableResourceOpFails() {
val resource: Resource? = null
val e = assertFails {
resource.use { requireNotNull(it) }
}
assertTrue(e is IllegalArgumentException)
assertTrue(e.suppressed.isEmpty())
}
@Test fun platformResourceOpFails() {
val resource = platformNull<Resource>()
val e = assertFails {
resource.use { requireNotNull(it) }
}
assertTrue(e is IllegalArgumentException)
assertTrue(e.suppressed.isEmpty())
}
}
+3 -3
View File
@@ -152,17 +152,17 @@ public fun URL.readBytes(): ByteArray = openStream().use { it.readBytes() }
* @return the result of [block] function on this closable resource.
*/
@kotlin.internal.InlineOnly
public inline fun <T : Closeable, R> T.use(block: (T) -> R): R {
public inline fun <T : Closeable?, R> T.use(block: (T) -> R): R {
var closed = false
try {
return block(this)
} catch (e: Throwable) {
closed = true
@Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE")
platformCloseSuppressed(this, e)
if (this != null) platformCloseSuppressed(this, e)
throw e
} finally {
if (!closed) {
if (this != null && !closed) {
close()
}
}
+9
View File
@@ -141,6 +141,15 @@ class ReadWriteTest {
assertEquals(arrayListOf("Hello", "World"), list)
}
@test fun testPlatformNullUse() {
fun <T> platformNull() = java.util.Collections.singleton(null as T).first()
val resource = platformNull<java.io.Closeable>()
val result = resource.use {
"ok"
}
assertEquals("ok", result)
}
@test fun testURL() {
val url = URL("http://kotlinlang.org")
val text = url.readText()