Move SAM resolution to frontend.java
This commit is contained in:
-39
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2013 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.jet.lang.resolve.java.sam;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.resolve.java.descriptor.JavaConstructorDescriptor;
|
||||
import org.jetbrains.jet.lang.resolve.java.descriptor.SamAdapterDescriptor;
|
||||
|
||||
/* package */ class SamAdapterConstructorDescriptor extends JavaConstructorDescriptor implements SamAdapterDescriptor<JavaConstructorDescriptor> {
|
||||
private final JavaConstructorDescriptor declaration;
|
||||
|
||||
public SamAdapterConstructorDescriptor(@NotNull JavaConstructorDescriptor declaration) {
|
||||
super(declaration.getContainingDeclaration(), null, declaration.getAnnotations(),
|
||||
declaration.isPrimary(), Kind.SYNTHESIZED, declaration.getSource());
|
||||
this.declaration = declaration;
|
||||
setHasStableParameterNames(declaration.hasStableParameterNames());
|
||||
setHasSynthesizedParameterNames(declaration.hasSynthesizedParameterNames());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JavaConstructorDescriptor getOriginForSam() {
|
||||
return declaration;
|
||||
}
|
||||
}
|
||||
-39
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2013 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.jet.lang.resolve.java.sam;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.resolve.java.descriptor.JavaMethodDescriptor;
|
||||
import org.jetbrains.jet.lang.resolve.java.descriptor.SamAdapterDescriptor;
|
||||
|
||||
/* package */ class SamAdapterFunctionDescriptor extends JavaMethodDescriptor implements SamAdapterDescriptor<JavaMethodDescriptor> {
|
||||
private final JavaMethodDescriptor declaration;
|
||||
|
||||
public SamAdapterFunctionDescriptor(@NotNull JavaMethodDescriptor declaration) {
|
||||
super(declaration.getContainingDeclaration(), null, declaration.getAnnotations(),
|
||||
declaration.getName(), Kind.SYNTHESIZED, declaration.getSource());
|
||||
this.declaration = declaration;
|
||||
setHasStableParameterNames(declaration.hasStableParameterNames());
|
||||
setHasSynthesizedParameterNames(declaration.hasSynthesizedParameterNames());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JavaMethodDescriptor getOriginForSam() {
|
||||
return declaration;
|
||||
}
|
||||
}
|
||||
-128
@@ -1,128 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2014 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.jet.lang.resolve.java.sam;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.descriptors.impl.SimpleFunctionDescriptorImpl;
|
||||
import org.jetbrains.jet.lang.resolve.ExternalOverridabilityCondition;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.TypeSubstitutor;
|
||||
import org.jetbrains.jet.lang.types.TypeUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class SamAdapterOverridabilityCondition implements ExternalOverridabilityCondition {
|
||||
@Override
|
||||
public boolean isOverridable(@NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor) {
|
||||
if (subDescriptor instanceof PropertyDescriptor) {
|
||||
return true;
|
||||
}
|
||||
|
||||
SimpleFunctionDescriptor superOriginal = getOriginalOfSamAdapterFunction((SimpleFunctionDescriptor) superDescriptor);
|
||||
SimpleFunctionDescriptor subOriginal = getOriginalOfSamAdapterFunction((SimpleFunctionDescriptor) subDescriptor);
|
||||
if (superOriginal == null || subOriginal == null) { // super or sub is/overrides DECLARATION
|
||||
return subOriginal == null; // DECLARATION can override anything
|
||||
}
|
||||
|
||||
// inheritor if SYNTHESIZED can override inheritor of SYNTHESIZED if their originals have same erasure
|
||||
return equalErasure(superOriginal, subOriginal);
|
||||
}
|
||||
|
||||
private static boolean equalErasure(@NotNull FunctionDescriptor fun1, @NotNull FunctionDescriptor fun2) {
|
||||
List<ValueParameterDescriptor> parameters1 = fun1.getValueParameters();
|
||||
List<ValueParameterDescriptor> parameters2 = fun2.getValueParameters();
|
||||
|
||||
for (ValueParameterDescriptor param1 : parameters1) {
|
||||
ValueParameterDescriptor param2 = parameters2.get(param1.getIndex());
|
||||
if (!equalClasses(param2.getType(), param1.getType())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean equalClasses(@NotNull JetType type1, @NotNull JetType type2) {
|
||||
DeclarationDescriptor declarationDescriptor1 = type1.getConstructor().getDeclarationDescriptor();
|
||||
if (declarationDescriptor1 == null) return false; // No class, classes are not equal
|
||||
DeclarationDescriptor declarationDescriptor2 = type2.getConstructor().getDeclarationDescriptor();
|
||||
if (declarationDescriptor2 == null) return false; // Class of type1 is not null
|
||||
return declarationDescriptor1.getOriginal().equals(declarationDescriptor2.getOriginal());
|
||||
}
|
||||
|
||||
// if function is or overrides declaration, returns null; otherwise, return original of sam adapter with substituted type parameters
|
||||
@Nullable
|
||||
private static SimpleFunctionDescriptor getOriginalOfSamAdapterFunction(@NotNull SimpleFunctionDescriptor callable) {
|
||||
DeclarationDescriptor containingDeclaration = callable.getContainingDeclaration();
|
||||
if (!(containingDeclaration instanceof ClassDescriptor)) {
|
||||
return null;
|
||||
}
|
||||
SamAdapterInfo declarationOrSynthesized =
|
||||
getNearestDeclarationOrSynthesized(callable, ((ClassDescriptor) containingDeclaration).getDefaultType());
|
||||
|
||||
if (declarationOrSynthesized == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
SimpleFunctionDescriptorImpl fun = (SimpleFunctionDescriptorImpl) declarationOrSynthesized.samAdapter.getOriginal();
|
||||
if (!(fun instanceof SamAdapterFunctionDescriptor)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
SimpleFunctionDescriptor originalDeclarationOfSam = ((SamAdapterFunctionDescriptor) fun).getOriginForSam();
|
||||
|
||||
return ((SimpleFunctionDescriptor) originalDeclarationOfSam.substitute(TypeSubstitutor.create(declarationOrSynthesized.ownerType)));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static SamAdapterInfo getNearestDeclarationOrSynthesized(
|
||||
@NotNull SimpleFunctionDescriptor samAdapter,
|
||||
@NotNull JetType ownerType
|
||||
) {
|
||||
if (samAdapter.getKind() != CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
|
||||
return new SamAdapterInfo(samAdapter, ownerType);
|
||||
}
|
||||
|
||||
for (CallableMemberDescriptor overridden : samAdapter.getOverriddenDescriptors()) {
|
||||
ClassDescriptor containingClass = (ClassDescriptor) overridden.getContainingDeclaration();
|
||||
|
||||
for (JetType immediateSupertype : TypeUtils.getImmediateSupertypes(ownerType)) {
|
||||
if (containingClass != immediateSupertype.getConstructor().getDeclarationDescriptor()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
SamAdapterInfo found = getNearestDeclarationOrSynthesized((SimpleFunctionDescriptor) overridden, immediateSupertype);
|
||||
if (found != null) {
|
||||
return found;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class SamAdapterInfo {
|
||||
private final SimpleFunctionDescriptor samAdapter;
|
||||
private final JetType ownerType;
|
||||
|
||||
private SamAdapterInfo(@NotNull SimpleFunctionDescriptor samAdapter, @NotNull JetType ownerType) {
|
||||
this.samAdapter = samAdapter;
|
||||
this.ownerType = ownerType;
|
||||
}
|
||||
}
|
||||
}
|
||||
-420
@@ -1,420 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2013 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.jet.lang.resolve.java.sam;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
|
||||
import org.jetbrains.jet.lang.descriptors.impl.TypeParameterDescriptorImpl;
|
||||
import org.jetbrains.jet.lang.descriptors.impl.ValueParameterDescriptorImpl;
|
||||
import org.jetbrains.jet.lang.resolve.java.JavaPackage;
|
||||
import org.jetbrains.jet.lang.resolve.java.descriptor.*;
|
||||
import org.jetbrains.jet.lang.resolve.java.lazy.types.LazyJavaTypeResolver;
|
||||
import org.jetbrains.jet.lang.resolve.java.resolver.DescriptorResolverUtils;
|
||||
import org.jetbrains.jet.lang.resolve.java.structure.*;
|
||||
import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||
import org.jetbrains.jet.lang.types.*;
|
||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.jet.lang.types.Variance.INVARIANT;
|
||||
|
||||
public class SingleAbstractMethodUtils {
|
||||
private SingleAbstractMethodUtils() {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<CallableMemberDescriptor> getAbstractMembers(@NotNull JetType type) {
|
||||
List<CallableMemberDescriptor> abstractMembers = new ArrayList<CallableMemberDescriptor>();
|
||||
for (DeclarationDescriptor member : type.getMemberScope().getAllDescriptors()) {
|
||||
if (member instanceof CallableMemberDescriptor && ((CallableMemberDescriptor) member).getModality() == Modality.ABSTRACT) {
|
||||
abstractMembers.add((CallableMemberDescriptor) member);
|
||||
}
|
||||
}
|
||||
return abstractMembers;
|
||||
}
|
||||
|
||||
private static JetType fixProjections(@NotNull JetType functionType) {
|
||||
//removes redundant projection kinds and detects conflicts
|
||||
|
||||
List<TypeParameterDescriptor> typeParameters = functionType.getConstructor().getParameters();
|
||||
List<TypeProjection> arguments = new ArrayList<TypeProjection>(typeParameters.size());
|
||||
for (TypeParameterDescriptor typeParameter : typeParameters) {
|
||||
Variance variance = typeParameter.getVariance();
|
||||
TypeProjection argument = functionType.getArguments().get(typeParameter.getIndex());
|
||||
Variance kind = argument.getProjectionKind();
|
||||
if (kind != INVARIANT && variance != INVARIANT) {
|
||||
if (kind == variance) {
|
||||
arguments.add(new TypeProjectionImpl(argument.getType()));
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
arguments.add(argument);
|
||||
}
|
||||
}
|
||||
ClassifierDescriptor classifier = functionType.getConstructor().getDeclarationDescriptor();
|
||||
assert classifier instanceof ClassDescriptor : "Not class: " + classifier;
|
||||
return new JetTypeImpl(
|
||||
functionType.getAnnotations(),
|
||||
functionType.getConstructor(),
|
||||
functionType.isNullable(),
|
||||
arguments,
|
||||
((ClassDescriptor) classifier).getMemberScope(arguments)
|
||||
);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static JetType getFunctionTypeForSamType(@NotNull JetType samType, boolean isSamConstructor) {
|
||||
// e.g. samType == Comparator<String>?
|
||||
|
||||
ClassifierDescriptor classifier = samType.getConstructor().getDeclarationDescriptor();
|
||||
if (classifier instanceof JavaClassDescriptor) {
|
||||
// Function2<T, T, Int>
|
||||
JetType functionTypeDefault = ((JavaClassDescriptor) classifier).getFunctionTypeForSamInterface();
|
||||
|
||||
if (functionTypeDefault != null) {
|
||||
// Function2<String, String, Int>?
|
||||
JetType substitute = TypeSubstitutor.create(samType).substitute(functionTypeDefault, Variance.INVARIANT);
|
||||
|
||||
if (substitute == null) return null;
|
||||
|
||||
JetType fixedProjections = fixProjections(substitute);
|
||||
if (fixedProjections == null) return null;
|
||||
|
||||
if (JavaPackage.getPLATFORM_TYPES() && !isSamConstructor) {
|
||||
return LazyJavaTypeResolver.FlexibleJavaClassifierTypeCapabilities.create(fixedProjections, TypeUtils.makeNullable(fixedProjections));
|
||||
}
|
||||
|
||||
return TypeUtils.makeNullableAsSpecified(fixedProjections, !isSamConstructor && samType.isNullable());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JetType getFunctionTypeForAbstractMethod(@NotNull FunctionDescriptor function) {
|
||||
JetType returnType = function.getReturnType();
|
||||
assert returnType != null : "function is not initialized: " + function;
|
||||
List<ValueParameterDescriptor> valueParameters = function.getValueParameters();
|
||||
List<JetType> parameterTypes = new ArrayList<JetType>(valueParameters.size());
|
||||
for (ValueParameterDescriptor parameter : valueParameters) {
|
||||
parameterTypes.add(parameter.getType());
|
||||
}
|
||||
return KotlinBuiltIns.getInstance().getFunctionType(
|
||||
Annotations.EMPTY, null, parameterTypes, returnType);
|
||||
}
|
||||
|
||||
private static boolean isSamInterface(@NotNull ClassDescriptor klass) {
|
||||
if (klass.getKind() != ClassKind.TRAIT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<CallableMemberDescriptor> abstractMembers = getAbstractMembers(klass.getDefaultType());
|
||||
if (abstractMembers.size() == 1) {
|
||||
CallableMemberDescriptor member = abstractMembers.get(0);
|
||||
if (member instanceof SimpleFunctionDescriptor) {
|
||||
return member.getTypeParameters().isEmpty();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static SamConstructorDescriptor createSamConstructorFunction(
|
||||
@NotNull DeclarationDescriptor owner,
|
||||
@NotNull JavaClassDescriptor samInterface
|
||||
) {
|
||||
assert isSamInterface(samInterface) : samInterface;
|
||||
|
||||
SamConstructorDescriptor result = new SamConstructorDescriptor(owner, samInterface);
|
||||
|
||||
TypeParameters typeParameters = recreateAndInitializeTypeParameters(samInterface.getTypeConstructor().getParameters(), result);
|
||||
|
||||
JetType parameterTypeUnsubstituted = getFunctionTypeForSamType(samInterface.getDefaultType(), true);
|
||||
assert parameterTypeUnsubstituted != null : "couldn't get function type for SAM type " + samInterface.getDefaultType();
|
||||
JetType parameterType = typeParameters.substitutor.substitute(parameterTypeUnsubstituted, Variance.IN_VARIANCE);
|
||||
assert parameterType != null : "couldn't substitute type: " + parameterTypeUnsubstituted +
|
||||
", substitutor = " + typeParameters.substitutor;
|
||||
ValueParameterDescriptor parameter = new ValueParameterDescriptorImpl(
|
||||
result, null, 0, Annotations.EMPTY, Name.identifier("function"), parameterType, false, null, SourceElement.NO_SOURCE);
|
||||
|
||||
JetType returnType = typeParameters.substitutor.substitute(samInterface.getDefaultType(), Variance.OUT_VARIANCE);
|
||||
assert returnType != null : "couldn't substitute type: " + samInterface.getDefaultType() +
|
||||
", substitutor = " + typeParameters.substitutor;
|
||||
|
||||
result.initialize(
|
||||
null,
|
||||
null,
|
||||
typeParameters.descriptors,
|
||||
Arrays.asList(parameter),
|
||||
returnType,
|
||||
Modality.FINAL,
|
||||
samInterface.getVisibility()
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static boolean isSamType(@NotNull JetType type) {
|
||||
return getFunctionTypeForSamType(type, /* irrelevant */ false) != null;
|
||||
}
|
||||
|
||||
public static boolean isSamAdapterNecessary(@NotNull FunctionDescriptor fun) {
|
||||
for (ValueParameterDescriptor param : fun.getValueParameters()) {
|
||||
if (isSamType(param.getType())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static SamAdapterDescriptor<JavaMethodDescriptor> createSamAdapterFunction(@NotNull final JavaMethodDescriptor original) {
|
||||
final SamAdapterFunctionDescriptor result = new SamAdapterFunctionDescriptor(original);
|
||||
return initSamAdapter(original, result, new FunctionInitializer() {
|
||||
@Override
|
||||
public void initialize(
|
||||
@NotNull List<TypeParameterDescriptor> typeParameters,
|
||||
@NotNull List<ValueParameterDescriptor> valueParameters,
|
||||
@Nullable JetType returnType
|
||||
) {
|
||||
result.initialize(
|
||||
null,
|
||||
original.getDispatchReceiverParameter(),
|
||||
typeParameters,
|
||||
valueParameters,
|
||||
returnType,
|
||||
Modality.FINAL,
|
||||
original.getVisibility()
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static SamAdapterDescriptor<JavaConstructorDescriptor> createSamAdapterConstructor(@NotNull final JavaConstructorDescriptor original) {
|
||||
final SamAdapterConstructorDescriptor result = new SamAdapterConstructorDescriptor(original);
|
||||
return initSamAdapter(original, result, new FunctionInitializer() {
|
||||
@Override
|
||||
public void initialize(
|
||||
@NotNull List<TypeParameterDescriptor> typeParameters,
|
||||
@NotNull List<ValueParameterDescriptor> valueParameters,
|
||||
@Nullable JetType returnType
|
||||
) {
|
||||
result.initialize(typeParameters, valueParameters, original.getVisibility());
|
||||
result.setReturnType(result.getContainingDeclaration().getDefaultType());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static <F extends FunctionDescriptor> SamAdapterDescriptor<F> initSamAdapter(
|
||||
@NotNull F original,
|
||||
@NotNull SamAdapterDescriptor<F> adapter,
|
||||
@NotNull FunctionInitializer initializer
|
||||
) {
|
||||
TypeParameters typeParameters = recreateAndInitializeTypeParameters(original.getTypeParameters(), adapter);
|
||||
|
||||
JetType returnTypeUnsubstituted = original.getReturnType();
|
||||
JetType returnType;
|
||||
if (returnTypeUnsubstituted == null) { // return type may be null for not yet initialized constructors
|
||||
returnType = null;
|
||||
}
|
||||
else {
|
||||
returnType = typeParameters.substitutor.substitute(returnTypeUnsubstituted, Variance.OUT_VARIANCE);
|
||||
assert returnType != null : "couldn't substitute type: " + returnTypeUnsubstituted +
|
||||
", substitutor = " + typeParameters.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;
|
||||
|
||||
ValueParameterDescriptor newParam = new ValueParameterDescriptorImpl(
|
||||
adapter, null, originalParam.getIndex(), originalParam.getAnnotations(),
|
||||
originalParam.getName(), newType, false, null, SourceElement.NO_SOURCE
|
||||
);
|
||||
valueParameters.add(newParam);
|
||||
}
|
||||
|
||||
initializer.initialize(typeParameters.descriptors, valueParameters, returnType);
|
||||
|
||||
return adapter;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static TypeParameters recreateAndInitializeTypeParameters(
|
||||
@NotNull List<TypeParameterDescriptor> originalParameters,
|
||||
@Nullable DeclarationDescriptor newOwner
|
||||
) {
|
||||
Map<TypeParameterDescriptor, TypeParameterDescriptorImpl> traitToFunTypeParameters =
|
||||
DescriptorResolverUtils.recreateTypeParametersAndReturnMapping(originalParameters, newOwner);
|
||||
TypeSubstitutor typeParametersSubstitutor = DescriptorResolverUtils.createSubstitutorForTypeParameters(traitToFunTypeParameters);
|
||||
for (Map.Entry<TypeParameterDescriptor, TypeParameterDescriptorImpl> mapEntry : traitToFunTypeParameters.entrySet()) {
|
||||
TypeParameterDescriptor traitTypeParameter = mapEntry.getKey();
|
||||
TypeParameterDescriptorImpl funTypeParameter = mapEntry.getValue();
|
||||
|
||||
for (JetType upperBound : traitTypeParameter.getUpperBounds()) {
|
||||
JetType upperBoundSubstituted = typeParametersSubstitutor.substitute(upperBound, Variance.INVARIANT);
|
||||
assert upperBoundSubstituted != null : "couldn't substitute type: " + upperBound + ", substitutor = " + typeParametersSubstitutor;
|
||||
funTypeParameter.addUpperBound(upperBoundSubstituted);
|
||||
}
|
||||
|
||||
funTypeParameter.setInitialized();
|
||||
}
|
||||
|
||||
List<TypeParameterDescriptor> typeParameters = new ArrayList<TypeParameterDescriptor>(traitToFunTypeParameters.values());
|
||||
return new TypeParameters(typeParameters, typeParametersSubstitutor);
|
||||
}
|
||||
|
||||
// Returns null if not SAM interface
|
||||
@Nullable
|
||||
public static JavaMethod getSamInterfaceMethod(@NotNull JavaClass javaClass) {
|
||||
FqName fqName = javaClass.getFqName();
|
||||
if (fqName == null || fqName.firstSegmentIs(KotlinBuiltIns.BUILT_INS_PACKAGE_NAME)) {
|
||||
return null;
|
||||
}
|
||||
if (!javaClass.isInterface() || javaClass.isAnnotationType()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return findOnlyAbstractMethod(javaClass);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static JavaMethod findOnlyAbstractMethod(@NotNull JavaClass javaClass) {
|
||||
OnlyAbstractMethodFinder finder = new OnlyAbstractMethodFinder();
|
||||
if (finder.find(javaClass.getDefaultType())) {
|
||||
return finder.getFoundMethod();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class TypeParameters {
|
||||
public final List<TypeParameterDescriptor> descriptors;
|
||||
public final TypeSubstitutor substitutor;
|
||||
|
||||
private TypeParameters(List<TypeParameterDescriptor> descriptors, TypeSubstitutor substitutor) {
|
||||
this.descriptors = descriptors;
|
||||
this.substitutor = substitutor;
|
||||
}
|
||||
}
|
||||
|
||||
private static abstract class FunctionInitializer {
|
||||
public abstract void initialize(
|
||||
@NotNull List<TypeParameterDescriptor> typeParameters,
|
||||
@NotNull List<ValueParameterDescriptor> valueParameters,
|
||||
@Nullable JetType returnType
|
||||
);
|
||||
}
|
||||
|
||||
private static class OnlyAbstractMethodFinder {
|
||||
private static final FqName OBJECT_FQ_NAME = new FqName("java.lang.Object");
|
||||
|
||||
private JavaMethod foundMethod;
|
||||
private JavaTypeSubstitutor foundClassSubstitutor;
|
||||
|
||||
private boolean find(@NotNull JavaClassifierType classifierType) {
|
||||
JavaTypeSubstitutor classSubstitutor = classifierType.getSubstitutor();
|
||||
JavaClassifier classifier = classifierType.getClassifier();
|
||||
if (classifier == null) {
|
||||
return false; // can't resolve class -> not a SAM interface
|
||||
}
|
||||
assert classifier instanceof JavaClass : "Classifier should be a class here: " + classifier;
|
||||
JavaClass javaClass = (JavaClass) classifier;
|
||||
if (OBJECT_FQ_NAME.equals(javaClass.getFqName())) {
|
||||
return true;
|
||||
}
|
||||
for (JavaMethod method : javaClass.getMethods()) {
|
||||
|
||||
//skip java 8 default methods
|
||||
if (!method.isAbstract()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (DescriptorResolverUtils.isObjectMethod(method)) { // e.g., ignore toString() declared in interface
|
||||
continue;
|
||||
}
|
||||
if (!method.getTypeParameters().isEmpty()) {
|
||||
return false; // if interface has generic methods, it is not a SAM interface
|
||||
}
|
||||
|
||||
if (foundMethod == null) {
|
||||
foundMethod = method;
|
||||
foundClassSubstitutor = classSubstitutor;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!areSignaturesErasureEqual(method, classSubstitutor, foundMethod, foundClassSubstitutor)) {
|
||||
return false; // different signatures
|
||||
}
|
||||
}
|
||||
|
||||
for (JavaClassifierType t : classifierType.getSupertypes()) {
|
||||
if (!find(t)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see com.intellij.psi.util.MethodSignatureUtil#areSignaturesErasureEqual
|
||||
*/
|
||||
private static boolean areSignaturesErasureEqual(
|
||||
@NotNull JavaMethod method1,
|
||||
@NotNull JavaTypeSubstitutor substitutor1,
|
||||
@NotNull JavaMethod method2,
|
||||
@NotNull JavaTypeSubstitutor substitutor2
|
||||
) {
|
||||
if (!method1.getName().equals(method2.getName())) return false;
|
||||
|
||||
Collection<JavaValueParameter> parameters1 = method1.getValueParameters();
|
||||
Collection<JavaValueParameter> parameters2 = method2.getValueParameters();
|
||||
if (parameters1.size() != parameters2.size()) return false;
|
||||
|
||||
for (Iterator<JavaValueParameter> it1 = parameters1.iterator(), it2 = parameters2.iterator(); it1.hasNext(); ) {
|
||||
JavaValueParameter param1 = it1.next();
|
||||
JavaValueParameter param2 = it2.next();
|
||||
if (param1.isVararg() != param2.isVararg()) return false;
|
||||
|
||||
JavaType type1 = DescriptorResolverUtils.erasure(substitutor1.substitute(param1.getType()), substitutor1);
|
||||
JavaType type2 = DescriptorResolverUtils.erasure(substitutor2.substitute(param2.getType()), substitutor2);
|
||||
if (!(type1 == null ? type2 == null : type1.equals(type2))) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private JavaMethod getFoundMethod() {
|
||||
return foundMethod;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user