Skip to content

Commit

Permalink
Kapt+JVM_IR: generate delegated members correctly
Browse files Browse the repository at this point in the history
Generate a declaration for each delegated member without body. If we
don't generate delegated declarations, subclasses will have incorrect IR
with unbound symbols in fake overrides.

 #KT-58027 Fixed

(cherry picked from commit bc7aea1)
  • Loading branch information
udalov committed Apr 20, 2023
1 parent ebdbaab commit d44d8ea
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,11 @@ class DelegationResolver<T : CallableMemberDescriptor> private constructor(
// descriptor = Foo
// toInterface = Bar
// delegateExpressionType = typeof(baz)
// return Map<member of Foo, corresponding member of typeOf(baz)>
//
// This method returns a map where keys are members of Foo, and values are members of typeof(baz).
//
// In case delegation is to an error type, which is useful for KAPT stub generation mode, typeof(baz) has no members, so we return
// a map from each element to it (so keys = values in the returned map).
fun getDelegates(
descriptor: ClassDescriptor,
toInterface: ClassDescriptor,
Expand All @@ -175,18 +179,22 @@ class DelegationResolver<T : CallableMemberDescriptor> private constructor(
val actualDelegates = DescriptorUtils.getAllOverriddenDescriptors(delegatingMember)
.filter { it.containingDeclaration == toInterface }
.map { overriddenDescriptor ->
val name = overriddenDescriptor.name
// this is the actual member of delegateExpressionType that we are delegating to
(scope.getContributedFunctions(name, NoLookupLocation.WHEN_CHECK_OVERRIDES) +
scope.getContributedVariables(name, NoLookupLocation.WHEN_CHECK_OVERRIDES))
.firstOrNull {
it == overriddenDescriptor || OverridingUtil.overrides(
it,
overriddenDescriptor,
it.module.isTypeRefinementEnabled(),
true
)
}
if (scopeType.isError) {
overriddenDescriptor
} else {
val name = overriddenDescriptor.name
// This is the actual member of delegateExpressionType that we are delegating to.
(scope.getContributedFunctions(name, NoLookupLocation.WHEN_CHECK_OVERRIDES) +
scope.getContributedVariables(name, NoLookupLocation.WHEN_CHECK_OVERRIDES))
.firstOrNull {
it == overriddenDescriptor || OverridingUtil.overrides(
it,
overriddenDescriptor,
it.module.isTypeRefinementEnabled(),
true
)
}
}
}

actualDelegates.firstOrNull()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,9 @@ class ClassGenerator(
// TODO could possibly refer to scoped type parameters for property accessors
irFunction.returnType = delegatedDescriptor.returnType!!.toIrType()

irFunction.body = generateDelegateFunctionBody(irDelegate, delegatedDescriptor, delegateToDescriptor, irFunction)
if (context.configuration.generateBodies) {
irFunction.body = generateDelegateFunctionBody(irDelegate, delegatedDescriptor, delegateToDescriptor, irFunction)
}
}

private fun generateDelegateFunctionBody(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// CORRECT_ERROR_TYPES

@Suppress("UNRESOLVED_REFERENCE")
interface A {
fun inject(b: B)
val x: String

companion object : B()

abstract class B : A by Unresolved
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
@kotlin.Metadata()
@kotlin.Suppress(names = {"UNRESOLVED_REFERENCE"})
public abstract interface A {
@org.jetbrains.annotations.NotNull()
public static final A.Companion Companion = null;

public abstract void inject(@org.jetbrains.annotations.NotNull()
A.B b);

@org.jetbrains.annotations.NotNull()
public abstract java.lang.String getX();

@kotlin.Metadata()
public static abstract class B implements A {

@java.lang.Override()
public void inject(@org.jetbrains.annotations.NotNull()
A.B b) {
}

@java.lang.Override()
@org.jetbrains.annotations.NotNull()
public java.lang.String getX() {
return null;
}

public B() {
super();
}
}

@kotlin.Metadata()
public static final class Companion extends A.B {

private Companion() {
super();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
@kotlin.Metadata()
@kotlin.Suppress(names = {"UNRESOLVED_REFERENCE"})
public abstract interface A {
@org.jetbrains.annotations.NotNull()
public static final A.Companion Companion = null;

public abstract void inject(@org.jetbrains.annotations.NotNull()
A.B b);

@org.jetbrains.annotations.NotNull()
public abstract java.lang.String getX();

@kotlin.Metadata()
public static abstract class B implements A {

public B() {
super();
}

@java.lang.Override()
@org.jetbrains.annotations.NotNull()
public java.lang.String getX() {
return null;
}

@java.lang.Override()
public void inject(@org.jetbrains.annotations.NotNull()
A.B b) {
}
}

@kotlin.Metadata()
public static final class Companion extends A.B {

private Companion() {
super();
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit d44d8ea

Please sign in to comment.