Implement nullable shorthand for params
This commit is contained in:
1 parent
7e538ed8aa
commit
9db5b12c31
3 files changed
+205
-5
No files matched your search
@@ -2641,8 +2641,31 @@ class Compiler(
|
||||
access
|
||||
}
|
||||
|
||||
// Nullable shorthand: "x?" means Object? (or makes explicit type nullable)
|
||||
var nullableHint = false
|
||||
val nullableHintPos = cc.savePos()
|
||||
cc.skipWsTokens()
|
||||
if (cc.peekNextNonWhitespace().type == Token.Type.QUESTION) {
|
||||
cc.nextNonWhitespace()
|
||||
nullableHint = true
|
||||
} else {
|
||||
cc.restorePos(nullableHintPos)
|
||||
}
|
||||
|
||||
// type information (semantic + mini syntax)
|
||||
val (typeInfo, miniType) = parseTypeDeclarationWithMini()
|
||||
if (nullableHint) {
|
||||
val afterHint = cc.savePos()
|
||||
cc.skipWsTokens()
|
||||
if (cc.peekNextNonWhitespace().type == Token.Type.COLON) {
|
||||
throw ScriptError(t.pos, "nullable shorthand '?' cannot be combined with explicit type")
|
||||
}
|
||||
cc.restorePos(afterHint)
|
||||
}
|
||||
var (typeInfo, miniType) = parseTypeDeclarationWithMini()
|
||||
if (nullableHint) {
|
||||
typeInfo = makeTypeDeclNullable(typeInfo)
|
||||
miniType = miniType?.let { makeMiniTypeNullable(it) }
|
||||
}
|
||||
|
||||
var defaultValue: Statement? = null
|
||||
cc.ifNextIs(Token.Type.ASSIGN) {
|
||||
@@ -2713,6 +2736,31 @@ class Compiler(
|
||||
return parseTypeUnionWithMini()
|
||||
}
|
||||
|
||||
private fun makeTypeDeclNullable(type: TypeDecl): TypeDecl {
|
||||
if (type.isNullable) return type
|
||||
return when (type) {
|
||||
TypeDecl.TypeAny -> TypeDecl.TypeNullableAny
|
||||
TypeDecl.TypeNullableAny -> type
|
||||
is TypeDecl.Function -> type.copy(nullable = true)
|
||||
is TypeDecl.TypeVar -> type.copy(nullable = true)
|
||||
is TypeDecl.Union -> type.copy(nullable = true)
|
||||
is TypeDecl.Intersection -> type.copy(nullable = true)
|
||||
is TypeDecl.Simple -> TypeDecl.Simple(type.name, true)
|
||||
is TypeDecl.Generic -> TypeDecl.Generic(type.name, type.args, true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun makeMiniTypeNullable(type: MiniTypeRef): MiniTypeRef {
|
||||
return when (type) {
|
||||
is MiniTypeName -> type.copy(nullable = true)
|
||||
is MiniGenericType -> type.copy(nullable = true)
|
||||
is MiniFunctionType -> type.copy(nullable = true)
|
||||
is MiniTypeVar -> type.copy(nullable = true)
|
||||
is MiniTypeUnion -> type.copy(nullable = true)
|
||||
is MiniTypeIntersection -> type.copy(nullable = true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseTypeUnionWithMini(): Pair<TypeDecl, MiniTypeRef> {
|
||||
var left = parseTypeIntersectionWithMini()
|
||||
val options = mutableListOf(left)
|
||||
|
||||
@@ -146,4 +146,24 @@ class TypesTest {
|
||||
println("Result: "+limit)
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNullableHints() = runTest {
|
||||
eval("""
|
||||
// nullable, without type os Object?
|
||||
class N(x=null)
|
||||
assertEquals(null, N().x)
|
||||
assertEquals("foo", N("foo").x)
|
||||
// nullable shortcut (x?)is same as (var x: Object?)
|
||||
class A(x?)
|
||||
assertEquals(null, A(null).x)
|
||||
assertEquals("ok", A("ok").x)
|
||||
|
||||
// same in function: x? is a shortcut for (x: Object?)
|
||||
fun f(x?) = x?.let { x + "!" }
|
||||
assertEquals(null, f(null))
|
||||
assertEquals("ok!", f("ok"))
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user