Iniital implementation of synthetic extensions for SAM-adapter functions (non-static only)

This commit is contained in:
Valentin Kipyatkov
2015-07-28 17:13:09 +03:00
parent 8b3870cc33
commit 729085ec9a
106 changed files with 624 additions and 364 deletions
@@ -239,30 +239,40 @@ public class SingleAbstractMethodUtils {
JetType returnTypeUnsubstituted = original.getReturnType();
assert returnTypeUnsubstituted != null : "Creating SAM adapter for not initialized original: " + original;
JetType returnType = typeParameters.substitutor.substitute(returnTypeUnsubstituted, Variance.OUT_VARIANCE);
TypeSubstitutor substitutor = typeParameters.substitutor;
JetType returnType = substitutor.substitute(returnTypeUnsubstituted, Variance.OUT_VARIANCE);
assert returnType != null : "couldn't substitute type: " + returnTypeUnsubstituted +
", substitutor = " + typeParameters.substitutor;
", substitutor = " + substitutor;
List<ValueParameterDescriptor> valueParameters = createValueParametersForSamAdapter(original, adapter, substitutor);
initializer.initialize(typeParameters.descriptors, valueParameters, returnType);
return adapter;
}
public static List<ValueParameterDescriptor> createValueParametersForSamAdapter(
@NotNull FunctionDescriptor original,
@NotNull FunctionDescriptor samAdapter,
@NotNull TypeSubstitutor substitutor
) {
List<ValueParameterDescriptor> originalValueParameters = original.getValueParameters();
List<ValueParameterDescriptor> valueParameters = new ArrayList<ValueParameterDescriptor>(originalValueParameters.size());
for (ValueParameterDescriptor originalParam : originalValueParameters) {
JetType originalType = originalParam.getType();
JetType functionType = getFunctionTypeForSamType(originalType, false);
JetType newTypeUnsubstituted = functionType != null ? functionType : originalType;
JetType newType = typeParameters.substitutor.substitute(newTypeUnsubstituted, Variance.IN_VARIANCE);
assert newType != null : "couldn't substitute type: " + newTypeUnsubstituted + ", substitutor = " + typeParameters.substitutor;
JetType newType = substitutor.substitute(newTypeUnsubstituted, Variance.IN_VARIANCE);
assert newType != null : "couldn't substitute type: " + newTypeUnsubstituted + ", substitutor = " + substitutor;
ValueParameterDescriptor newParam = new ValueParameterDescriptorImpl(
adapter, null, originalParam.getIndex(), originalParam.getAnnotations(),
samAdapter, null, originalParam.getIndex(), originalParam.getAnnotations(),
originalParam.getName(), newType, false, null, SourceElement.NO_SOURCE
);
valueParameters.add(newParam);
}
initializer.initialize(typeParameters.descriptors, valueParameters, returnType);
return adapter;
return valueParameters;
}
@NotNull
@@ -0,0 +1,27 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.synthetic
import org.jetbrains.kotlin.psi.JetFile
import org.jetbrains.kotlin.resolve.lazy.FileScopeProvider
import org.jetbrains.kotlin.storage.StorageManager
class AdditionalScopesWithJavaSyntheticExtensions(storageManager: StorageManager) : FileScopeProvider.AdditionalScopes {
private val scopes = listOf(JavaSyntheticPropertiesScope(storageManager), SamAdapterFunctionsScope(storageManager))
override fun scopes(file: JetFile) = scopes
}
@@ -22,21 +22,19 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.PropertyGetterDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.PropertySetterDescriptorImpl
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.JetFile
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.lazy.FileScopeProvider
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.scopes.JetScope
import org.jetbrains.kotlin.resolve.scopes.JetScopeImpl
import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.typeUtil.isBoolean
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
import org.jetbrains.kotlin.types.typeUtil.isUnit
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
import org.jetbrains.kotlin.util.capitalizeDecapitalize.capitalizeFirstWord
import org.jetbrains.kotlin.util.capitalizeDecapitalize.decapitalizeSmart
import org.jetbrains.kotlin.utils.Printer
import org.jetbrains.kotlin.utils.addIfNotNull
import java.util.ArrayList
import java.util.HashSet
@@ -84,13 +82,7 @@ interface SyntheticJavaPropertyDescriptor : PropertyDescriptor {
}
}
class AdditionalScopesWithJavaSyntheticExtensions(storageManager: StorageManager) : FileScopeProvider.AdditionalScopes {
private val scope = JavaSyntheticExtensionsScope(storageManager)
override fun scopes(file: JetFile) = listOf(scope)
}
class JavaSyntheticExtensionsScope(storageManager: StorageManager) : JetScope by JetScope.Empty {
class JavaSyntheticPropertiesScope(storageManager: StorageManager) : JetScopeImpl() {
private val syntheticPropertyInClass = storageManager.createMemoizedFunctionWithNullableValues<Pair<ClassDescriptor, Name>, PropertyDescriptor> { pair ->
syntheticPropertyInClassNotCached(pair.first, pair.second)
}
@@ -117,13 +109,6 @@ class JavaSyntheticExtensionsScope(storageManager: StorageManager) : JetScope by
return MyPropertyDescriptor(ownerClass, getMethod.original, setMethod?.original, name, propertyType)
}
private fun FunctionDescriptor.hasJavaOriginInHierarchy(): Boolean {
return if (overriddenDescriptors.isEmpty())
containingDeclaration is JavaClassDescriptor
else
overriddenDescriptors.any { it.hasJavaOriginInHierarchy() }
}
private fun isGoodGetMethod(descriptor: FunctionDescriptor): Boolean {
val returnType = descriptor.returnType ?: return false
if (returnType.isUnit()) return false
@@ -251,6 +236,14 @@ class JavaSyntheticExtensionsScope(storageManager: StorageManager) : JetScope by
return Name.identifier("set" + identifier.removePrefix(prefix))
}
override fun getContainingDeclaration(): DeclarationDescriptor {
throw UnsupportedOperationException()
}
override fun printScopeStructure(p: Printer) {
p.println(javaClass.simpleName)
}
private class MyPropertyDescriptor(
ownerClass: ClassDescriptor,
override val getMethod: FunctionDescriptor,
@@ -0,0 +1,106 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.synthetic
import com.intellij.util.SmartList
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.load.java.sam.SingleAbstractMethodUtils
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf
import org.jetbrains.kotlin.resolve.scopes.JetScope
import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.types.DescriptorSubstitutor
import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.types.TypeSubstitution
import org.jetbrains.kotlin.types.Variance
import java.util.ArrayList
interface SamAdapterExtensionFunctionDescriptor : FunctionDescriptor {
val originalFunction: FunctionDescriptor
}
class SamAdapterFunctionsScope(storageManager: StorageManager) : JetScope by JetScope.Empty {
private val extensionForFunction = storageManager.createMemoizedFunctionWithNullableValues<FunctionDescriptor, FunctionDescriptor> { function ->
extensionForFunctionNotCached(function)
}
private fun extensionForFunctionNotCached(function: FunctionDescriptor): FunctionDescriptor? {
//TODO!
if (function.visibility == Visibilities.PRIVATE || function.visibility == Visibilities.PRIVATE_TO_THIS || function.visibility == Visibilities.INVISIBLE_FAKE) return null
if (!function.hasJavaOriginInHierarchy()) return null //TODO: should we go into base at all?
if (!SingleAbstractMethodUtils.isSamAdapterNecessary(function)) return null
val returnType = function.returnType ?: return null
return MyFunctionDescriptor(function, returnType)
}
override fun getSyntheticExtensionFunctions(receiverTypes: Collection<JetType>, name: Name): Collection<FunctionDescriptor> {
var result: SmartList<FunctionDescriptor>? = null
for (type in receiverTypes) {
for (function in type.memberScope.getFunctions(name)) {
val extension = extensionForFunction(function.original)
if (extension != null) {
if (result == null) {
result = SmartList()
}
result.add(extension)
}
}
}
return when {
result == null -> emptyList()
result.size() > 1 -> result.toSet()
else -> result
}
}
private class MyFunctionDescriptor(
override val originalFunction: FunctionDescriptor,
originalReturnType: JetType
) : SamAdapterExtensionFunctionDescriptor, SimpleFunctionDescriptorImpl(
DescriptorUtils.getContainingModule(originalFunction),
null,
Annotations.EMPTY, //TODO
originalFunction.name,
CallableMemberDescriptor.Kind.SYNTHESIZED,
originalFunction.source
) {
init {
val typeParamsSum = (originalFunction.typeParameters).toArrayList()
val ownerClass = originalFunction.containingDeclaration as ClassDescriptor
//TODO: should we go up parents for getters/setters too?
for (parent in ownerClass.parentsWithSelf) {
if (parent !is ClassDescriptor) break
typeParamsSum += parent.typeConstructor.parameters
}
//TODO: duplicated parameter names
val typeParameters = ArrayList<TypeParameterDescriptor>(typeParamsSum.size())
val typeSubstitutor = DescriptorSubstitutor.substituteTypeParameters(typeParamsSum, TypeSubstitution.EMPTY, this, typeParameters)
val returnType = typeSubstitutor.safeSubstitute(originalReturnType, Variance.OUT_VARIANCE)
val receiverType = typeSubstitutor.safeSubstitute(ownerClass.defaultType, Variance.INVARIANT)
val valueParameters = SingleAbstractMethodUtils.createValueParametersForSamAdapter(originalFunction, this, typeSubstitutor)
initialize(receiverType, null, typeParameters, valueParameters, returnType, Modality.FINAL, Visibilities.PUBLIC)
}
override fun hasStableParameterNames() = originalFunction.hasStableParameterNames()
override fun hasSynthesizedParameterNames() = originalFunction.hasSynthesizedParameterNames()
}
}
@@ -0,0 +1,27 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.synthetic
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
fun FunctionDescriptor.hasJavaOriginInHierarchy(): Boolean {
return if (overriddenDescriptors.isEmpty())
containingDeclaration is JavaClassDescriptor
else
overriddenDescriptors.any { it.hasJavaOriginInHierarchy() }
}