mirror of
https://github.com/apple/pkl.git
synced 2026-09-13 13:21:47 +02:00
Correctly type check Class<T> (#1698)
This commit is contained in:
+2
@@ -0,0 +1,2 @@
|
||||
module classType
|
||||
class Foo
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
module classType
|
||||
class Foo
|
||||
@@ -0,0 +1,36 @@
|
||||
open module classType
|
||||
|
||||
import "pkl:reflect"
|
||||
|
||||
open class A
|
||||
open class B
|
||||
class C extends A
|
||||
class D extends module
|
||||
typealias E = A
|
||||
typealias BB = B
|
||||
|
||||
res0 = C is Class<C>
|
||||
res0a = C is Class<(C)>
|
||||
res0b = C is Class<((C))>
|
||||
res1 = C is Class<A>
|
||||
res2 = C is Class<E>
|
||||
|
||||
res3 = C is Class
|
||||
res4 = C is Class<unknown>
|
||||
res5 = C is Class<Any>
|
||||
|
||||
res15 = D is Class<module>
|
||||
res16 = D is Class<Object>
|
||||
res17 = D is Class<Typed>
|
||||
res18 = D is Class<Dynamic>
|
||||
res19 = D is Class<Int>
|
||||
|
||||
typealias F<T> = List<Class<T>>
|
||||
res20 = List(A, C) is F<A>
|
||||
res21 = List(new A {}, new B {}, new C {}).filterIsInstance(A).length
|
||||
|
||||
hidden $res22: Class<A> = A
|
||||
res22 =
|
||||
let (t = reflect.Module(module).moduleClass.properties["$res22"].type as reflect.DeclaredType)
|
||||
let (arg = t.typeArguments.single as reflect.DeclaredType)
|
||||
"\(t.referent.enclosingDeclaration.uri)#\(t.referent.name)<\(arg.referent.enclosingDeclaration.uri)#\(arg.referent.name)>"
|
||||
@@ -0,0 +1,3 @@
|
||||
extends "classType.pkl"
|
||||
|
||||
res2 = C as Class<B>
|
||||
@@ -0,0 +1,3 @@
|
||||
extends "classType.pkl"
|
||||
|
||||
res14 = C as Class<module>
|
||||
@@ -0,0 +1,3 @@
|
||||
extends "classType.pkl"
|
||||
|
||||
res22 = List(A, C) as F<A | B>
|
||||
@@ -0,0 +1,5 @@
|
||||
extends "classType.pkl"
|
||||
|
||||
typealias G<T> = F<T>
|
||||
|
||||
res22 = List(A, C) as G<A | B>
|
||||
@@ -0,0 +1,5 @@
|
||||
extends "classType.pkl"
|
||||
|
||||
typealias G<T> = F<T | B>
|
||||
|
||||
res22 = List(A, C) as G<A>
|
||||
@@ -0,0 +1,6 @@
|
||||
extends "classType.pkl"
|
||||
|
||||
import ".../input-helper/types/classTypeA.pkl"
|
||||
import ".../input-helper/types/classTypeB.pkl"
|
||||
|
||||
res6 = classTypeA.getClass() as Class<classTypeB>
|
||||
@@ -0,0 +1,6 @@
|
||||
extends "classType.pkl"
|
||||
|
||||
import ".../input-helper/types/classTypeA.pkl"
|
||||
import ".../input-helper/types/classTypeB.pkl"
|
||||
|
||||
res7 = classTypeA.Foo as Class<classTypeB.Foo>
|
||||
@@ -0,0 +1,3 @@
|
||||
extends "classType.pkl"
|
||||
|
||||
res8 = C as Class<A | B>
|
||||
@@ -0,0 +1,3 @@
|
||||
extends "classType.pkl"
|
||||
|
||||
res9 = C as Class<A?>
|
||||
@@ -0,0 +1,3 @@
|
||||
extends "classType.pkl"
|
||||
|
||||
res10 = C as Class<"foo">
|
||||
@@ -0,0 +1,3 @@
|
||||
extends "classType.pkl"
|
||||
|
||||
res11 = C as Class<nothing>
|
||||
@@ -0,0 +1,3 @@
|
||||
extends "classType.pkl"
|
||||
|
||||
res12 = C as Class<A(true)>
|
||||
@@ -0,0 +1,3 @@
|
||||
extends "classType.pkl"
|
||||
|
||||
res13 = C as Class<BB>
|
||||
@@ -0,0 +1,16 @@
|
||||
res0 = true
|
||||
res0a = true
|
||||
res0b = true
|
||||
res1 = true
|
||||
res2 = true
|
||||
res3 = true
|
||||
res4 = true
|
||||
res5 = true
|
||||
res15 = true
|
||||
res16 = true
|
||||
res17 = true
|
||||
res18 = false
|
||||
res19 = false
|
||||
res20 = true
|
||||
res21 = 2
|
||||
res22 = "pkl:base#Class<file:///$snippetsDir/input/types/classType.pkl#A>"
|
||||
@@ -0,0 +1,14 @@
|
||||
–– Pkl Error ––
|
||||
Expected value of type `Class<classType#B>`, but got type `Class<classType#C>`.
|
||||
|
||||
x | res2 = C as Class<B>
|
||||
^^^^^^^^
|
||||
at classTypeErr1#res2 (file:///$snippetsDir/input/types/classTypeErr1.pkl)
|
||||
|
||||
xxx | renderer.renderDocument(value)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
at pkl.base#Module.output.text (pkl:base)
|
||||
|
||||
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||
^^^^
|
||||
at pkl.base#Module.output.bytes (pkl:base)
|
||||
@@ -0,0 +1,14 @@
|
||||
–– Pkl Error ––
|
||||
Expected value of type `Class<classTypeErr10>`, but got type `Class<classType#C>`.
|
||||
|
||||
x | res14 = C as Class<module>
|
||||
^^^^^^^^^^^^^
|
||||
at classTypeErr10#res14 (file:///$snippetsDir/input/types/classTypeErr10.pkl)
|
||||
|
||||
xxx | renderer.renderDocument(value)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
at pkl.base#Module.output.text (pkl:base)
|
||||
|
||||
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||
^^^^
|
||||
at pkl.base#Module.output.bytes (pkl:base)
|
||||
@@ -0,0 +1,16 @@
|
||||
–– Pkl Error ––
|
||||
Expected value of type `Class<classType#A | classType#B>`, but got type `Class<classType#A>`.
|
||||
|
||||
xx | typealias F<T> = List<Class<T>>
|
||||
^^^^^^^^
|
||||
at classTypeErr11#res22 (file:///$snippetsDir/input/types/classType.pkl)
|
||||
|
||||
A `Class` type check can only succeed when its type argument is an un-parameterized class, `unknown`, `module`, or an alias to one of those types.
|
||||
|
||||
xxx | renderer.renderDocument(value)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
at pkl.base#Module.output.text (pkl:base)
|
||||
|
||||
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||
^^^^
|
||||
at pkl.base#Module.output.bytes (pkl:base)
|
||||
@@ -0,0 +1,16 @@
|
||||
–– Pkl Error ––
|
||||
Expected value of type `Class<classType#A | classType#B>`, but got type `Class<classType#A>`.
|
||||
|
||||
xx | typealias F<T> = List<Class<T>>
|
||||
^^^^^^^^
|
||||
at classTypeErr12#res22 (file:///$snippetsDir/input/types/classType.pkl)
|
||||
|
||||
A `Class` type check can only succeed when its type argument is an un-parameterized class, `unknown`, `module`, or an alias to one of those types.
|
||||
|
||||
xxx | renderer.renderDocument(value)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
at pkl.base#Module.output.text (pkl:base)
|
||||
|
||||
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||
^^^^
|
||||
at pkl.base#Module.output.bytes (pkl:base)
|
||||
@@ -0,0 +1,16 @@
|
||||
–– Pkl Error ––
|
||||
Expected value of type `Class<classType#A | classType#B>`, but got type `Class<classType#A>`.
|
||||
|
||||
xx | typealias F<T> = List<Class<T>>
|
||||
^^^^^^^^
|
||||
at classTypeErr13#res22 (file:///$snippetsDir/input/types/classType.pkl)
|
||||
|
||||
A `Class` type check can only succeed when its type argument is an un-parameterized class, `unknown`, `module`, or an alias to one of those types.
|
||||
|
||||
xxx | renderer.renderDocument(value)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
at pkl.base#Module.output.text (pkl:base)
|
||||
|
||||
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||
^^^^
|
||||
at pkl.base#Module.output.bytes (pkl:base)
|
||||
@@ -0,0 +1,15 @@
|
||||
–– Pkl Error ––
|
||||
Module version conflict: Expected value of type `Class<classType>` defined by module `file:///$snippetsDir/input-helper/types/classTypeB.pkl`, but got type `Class<classType>` defined by module `file:///$snippetsDir/input-helper/types/classTypeA.pkl`.
|
||||
|
||||
|
||||
x | res6 = classTypeA.getClass() as Class<classTypeB>
|
||||
^^^^^^^^^^^^^^^^^
|
||||
at classTypeErr2#res6 (file:///$snippetsDir/input/types/classTypeErr2.pkl)
|
||||
|
||||
xxx | renderer.renderDocument(value)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
at pkl.base#Module.output.text (pkl:base)
|
||||
|
||||
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||
^^^^
|
||||
at pkl.base#Module.output.bytes (pkl:base)
|
||||
@@ -0,0 +1,15 @@
|
||||
–– Pkl Error ––
|
||||
Module version conflict: Expected value of type `Class<classType#Foo>` defined in module `file:///$snippetsDir/input-helper/types/classTypeB.pkl`, but got type `Class<classType#Foo>` defined in module `file:///$snippetsDir/input-helper/types/classTypeA.pkl`.
|
||||
|
||||
|
||||
x | res7 = classTypeA.Foo as Class<classTypeB.Foo>
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
at classTypeErr3#res7 (file:///$snippetsDir/input/types/classTypeErr3.pkl)
|
||||
|
||||
xxx | renderer.renderDocument(value)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
at pkl.base#Module.output.text (pkl:base)
|
||||
|
||||
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||
^^^^
|
||||
at pkl.base#Module.output.bytes (pkl:base)
|
||||
@@ -0,0 +1,16 @@
|
||||
–– Pkl Error ––
|
||||
Expected value of type `Class<classType#A | classType#B>`, but got type `Class<classType#C>`.
|
||||
|
||||
x | res8 = C as Class<A | B>
|
||||
^^^^^^^^^^^^
|
||||
at classTypeErr4#res8 (file:///$snippetsDir/input/types/classTypeErr4.pkl)
|
||||
|
||||
A `Class` type check can only succeed when its type argument is an un-parameterized class, `unknown`, `module`, or an alias to one of those types.
|
||||
|
||||
xxx | renderer.renderDocument(value)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
at pkl.base#Module.output.text (pkl:base)
|
||||
|
||||
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||
^^^^
|
||||
at pkl.base#Module.output.bytes (pkl:base)
|
||||
@@ -0,0 +1,16 @@
|
||||
–– Pkl Error ––
|
||||
Expected value of type `Class<classType#A?>`, but got type `Class<classType#C>`.
|
||||
|
||||
x | res9 = C as Class<A?>
|
||||
^^^^^^^^^
|
||||
at classTypeErr5#res9 (file:///$snippetsDir/input/types/classTypeErr5.pkl)
|
||||
|
||||
A `Class` type check can only succeed when its type argument is an un-parameterized class, `unknown`, `module`, or an alias to one of those types.
|
||||
|
||||
xxx | renderer.renderDocument(value)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
at pkl.base#Module.output.text (pkl:base)
|
||||
|
||||
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||
^^^^
|
||||
at pkl.base#Module.output.bytes (pkl:base)
|
||||
@@ -0,0 +1,16 @@
|
||||
–– Pkl Error ––
|
||||
Expected value of type `Class<"foo">`, but got type `Class<classType#C>`.
|
||||
|
||||
x | res10 = C as Class<"foo">
|
||||
^^^^^^^^^^^^
|
||||
at classTypeErr6#res10 (file:///$snippetsDir/input/types/classTypeErr6.pkl)
|
||||
|
||||
A `Class` type check can only succeed when its type argument is an un-parameterized class, `unknown`, `module`, or an alias to one of those types.
|
||||
|
||||
xxx | renderer.renderDocument(value)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
at pkl.base#Module.output.text (pkl:base)
|
||||
|
||||
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||
^^^^
|
||||
at pkl.base#Module.output.bytes (pkl:base)
|
||||
@@ -0,0 +1,16 @@
|
||||
–– Pkl Error ––
|
||||
Expected value of type `Class<nothing>`, but got type `Class<classType#C>`.
|
||||
|
||||
x | res11 = C as Class<nothing>
|
||||
^^^^^^^^^^^^^^
|
||||
at classTypeErr7#res11 (file:///$snippetsDir/input/types/classTypeErr7.pkl)
|
||||
|
||||
A `Class` type check can only succeed when its type argument is an un-parameterized class, `unknown`, `module`, or an alias to one of those types.
|
||||
|
||||
xxx | renderer.renderDocument(value)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
at pkl.base#Module.output.text (pkl:base)
|
||||
|
||||
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||
^^^^
|
||||
at pkl.base#Module.output.bytes (pkl:base)
|
||||
@@ -0,0 +1,16 @@
|
||||
–– Pkl Error ––
|
||||
Expected value of type `Class<classType#A(true)>`, but got type `Class<classType#C>`.
|
||||
|
||||
x | res12 = C as Class<A(true)>
|
||||
^^^^^^^^^^^^^^
|
||||
at classTypeErr8#res12 (file:///$snippetsDir/input/types/classTypeErr8.pkl)
|
||||
|
||||
A `Class` type check can only succeed when its type argument is an un-parameterized class, `unknown`, `module`, or an alias to one of those types.
|
||||
|
||||
xxx | renderer.renderDocument(value)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
at pkl.base#Module.output.text (pkl:base)
|
||||
|
||||
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||
^^^^
|
||||
at pkl.base#Module.output.bytes (pkl:base)
|
||||
@@ -0,0 +1,14 @@
|
||||
–– Pkl Error ––
|
||||
Expected value of type `Class<classType#B>`, but got type `Class<classType#C>`.
|
||||
|
||||
x | res13 = C as Class<BB>
|
||||
^^^^^^^^^
|
||||
at classTypeErr9#res13 (file:///$snippetsDir/input/types/classTypeErr9.pkl)
|
||||
|
||||
xxx | renderer.renderDocument(value)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
at pkl.base#Module.output.text (pkl:base)
|
||||
|
||||
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
|
||||
^^^^
|
||||
at pkl.base#Module.output.bytes (pkl:base)
|
||||
@@ -772,6 +772,24 @@ class EvaluatorTest {
|
||||
.doesNotThrowAnyException()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `eval schema containing a parameterized Class type`() {
|
||||
val evaluator = Evaluator.preconfigured()
|
||||
val schema =
|
||||
evaluator.evaluateSchema(
|
||||
text(
|
||||
"""
|
||||
foo: Class<Int>
|
||||
"""
|
||||
.trimIndent()
|
||||
)
|
||||
)
|
||||
val fooType = schema.moduleClass.properties["foo"]?.type as? PType.Class
|
||||
assertThat(fooType?.pClass?.info).isEqualTo(PClassInfo.Class)
|
||||
val argType = fooType?.typeArguments?.single() as? PType.Class
|
||||
assertThat(argType?.pClass?.info).isEqualTo(PClassInfo.Int)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `concurrent evals`() {
|
||||
val exceptions = mutableListOf<Throwable>()
|
||||
|
||||
Reference in New Issue
Block a user