KSP2 API Changes
March 19, 2025 ยท View on GitHub
While KSP2 is binary compatible with processors written for KSP1, there are some changes in the return values. The differences are listed below:
Resolve implicit type from function call: val error = mutableMapOf<String, NonExistType>()
- KSP1: The whole type will be an error type due to failed type resolution.
- KSP2: It will successfully resolve the container type, and for the non-existent type in the type argument, it will correctly report errors on the specific type argument.
Unbounded type parameter
- KSP1: No bounds
- KSP2: An upper bound of
Any?is always inserted for consistency
Resolving references to type aliases in function types and annotations
- KSP1: Expanded to the underlying, non-alias type
- KSP2: Not expanded, like uses in other places
Fully qualified names
- KSP1: Constructors have FQN if the constructor is from source, but not if the constructor is from a library.
- KSP2: Constructors do not have FQN
Type arguments of inner types
- KSP1: Inner types has arguments from outer types
- KSP2: Inner types has no arguments from outer types
Type arguments of star projections
- KSP1: Star projections have type arguments that are expanded to the effective variances according to the declaration sites.
- KSP2: No expansion. Star projections have nulls in their type arguments.
Variance of Java Array
- KSP1: Java Array has a invariant upper bound
- KSP2: Java Array has a covariant upper bound
Type of Enum Entries
- KSP1: Each enum entry has itsown type
- KSP2: All enum entries share the same type with the enclosing enum class
Evaluation of Enum Entries in Annotation Arguments
- KSP1: An annotation argument that is an enum entry is evaluated as a
KSTypeof the corresponding enum entry - KSP2: An annotation argument that is an enum entry is evaluated directly as the corresponding
KSClassDeclarationof the enum entry
Multi-override scenario
For example
interface GrandBaseInterface1 {
fun foo(): Unit
}
interface GrandBaseInterface2 {
fun foo(): Unit
}
interface BaseInterface1 : GrandBaseInterface1 {
}
interface BaseInterface2 : GrandBaseInterface2 {
}
class OverrideOrder1 : BaseInterface1, GrandBaseInterface2 {
override fun foo() = TODO()
}
class OverrideOrder2 : BaseInterface2, GrandBaseInterface1 {
override fun foo() = TODO()
}
- KSP1: Find overridden symbols in BFS order, first super type found on direct super type list that contains overridden
symbol is returned. For the example, KSP will say
OverrideOrder1.foo()overridesGrandBaseInterface2.foo()andOverrideOrder2.foo()overridesGrandBaseInterface1.foo(). - KSP2: DFS order, first super type found overridden symbols (with recursive super type look up) in direct super type
list is returned. For the example, KSP will say
OverrideOrder1.foo()overridesGrandBaseInterface1.foo()andOverrideOrder2.foo()overridesGrandBaseInterface2.foo().
Java modifier
- KSP1: Transient/volatile fields are final by default
- KSP2: Transient/volatile fields are open by default
Type annotations
- KSP1: Type annotations on a type argument is only reflected on the type argument symbol
- KSP2: Type annotations on a type argument now present in the resolved type as well
vararg parameters
- KSP1: Considered as an
Arraytype when it is from Java sources. - KSP2: Not considered as an
Arraytype. KSValueParameter returns the declared type consistently.
Synthesized members of Enums
- KSP1:
valuesandvalueOfare missing if the enum is defined in Kotlin sources - KSP2:
valuesandvalueOfare always present
Synthesized members of data classes
- KSP1:
componentNandcopyare missing if the data class is defined in Kotlin sources - KSP2:
componentNandcopyare always present
Super type of Enum classes
- KSP1: The super type of Enum classes is
Any - KSP2: The super type of Enum classes is
Enum