JET-72 Type inference doesn't work when iterating over ArrayList:

substitutions fixed for methods inherited from generic superclasses
This commit is contained in:
Andrey Breslav
2011-06-01 18:17:28 +04:00
parent dc25c7bb3b
commit 97de457f79
8 changed files with 98 additions and 16 deletions
@@ -81,7 +81,7 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl implement
@Override @Override
public String toString() { public String toString() {
return typeConstructor.toString(); return getContainingDeclaration() + "::" + typeConstructor.toString();
} }
@NotNull @NotNull
@@ -91,4 +91,9 @@ public class JavaClassDescriptor extends MutableDeclarationDescriptor implements
public <R, D> R accept(DeclarationDescriptorVisitor<R, D> visitor, D data) { public <R, D> R accept(DeclarationDescriptorVisitor<R, D> visitor, D data) {
return visitor.visitClassDescriptor(this, data); return visitor.visitClassDescriptor(this, data);
} }
@Override
public String toString() {
return "java class " + typeConstructor;
}
} }
@@ -110,7 +110,11 @@ public class JavaClassMembersScope implements JetScope {
public FunctionGroup getFunctionGroup(@NotNull String name) { public FunctionGroup getFunctionGroup(@NotNull String name) {
FunctionGroup functionGroup = functionGroups.get(name); FunctionGroup functionGroup = functionGroups.get(name);
if (functionGroup == null) { if (functionGroup == null) {
functionGroup = semanticServices.getDescriptorResolver().resolveFunctionGroup(psiClass, name, staticMembers); functionGroup = semanticServices.getDescriptorResolver().resolveFunctionGroup(
psiClass,
staticMembers ? null : (ClassDescriptor) containingDeclaration,
name,
staticMembers);
functionGroups.put(name, functionGroup); functionGroups.put(name, functionGroup);
} }
return functionGroup; return functionGroup;
@@ -26,7 +26,7 @@ public class JavaDescriptorResolver {
@Override @Override
public <R, D> R accept(DeclarationDescriptorVisitor<R, D> visitor, D data) { public <R, D> R accept(DeclarationDescriptorVisitor<R, D> visitor, D data) {
throw new UnsupportedOperationException(); // TODO return visitor.visitDeclarationDescriptor(this, data);
} }
}; };
@@ -73,7 +73,6 @@ public class JavaDescriptorResolver {
classDescriptorCache.put(psiClass.getQualifiedName(), null); // TODO classDescriptorCache.put(psiClass.getQualifiedName(), null); // TODO
String name = psiClass.getName(); String name = psiClass.getName();
PsiModifierList modifierList = psiClass.getModifierList();
JavaClassDescriptor classDescriptor = new JavaClassDescriptor( JavaClassDescriptor classDescriptor = new JavaClassDescriptor(
JAVA_ROOT JAVA_ROOT
); );
@@ -86,7 +85,7 @@ public class JavaDescriptorResolver {
// TODO // TODO
psiClass.hasModifierProperty(PsiModifier.FINAL), psiClass.hasModifierProperty(PsiModifier.FINAL),
name, name,
resolveTypeParameters(psiClass.getTypeParameters()), resolveTypeParameters(classDescriptor, psiClass.getTypeParameters()),
supertypes supertypes
)); ));
@@ -124,10 +123,10 @@ public class JavaDescriptorResolver {
return classDescriptor; return classDescriptor;
} }
private List<TypeParameterDescriptor> resolveTypeParameters(@NotNull PsiTypeParameter[] typeParameters) { private List<TypeParameterDescriptor> resolveTypeParameters(@NotNull DeclarationDescriptor containingDeclaration, @NotNull PsiTypeParameter[] typeParameters) {
List<TypeParameterDescriptor> result = Lists.newArrayList(); List<TypeParameterDescriptor> result = Lists.newArrayList();
for (PsiTypeParameter typeParameter : typeParameters) { for (PsiTypeParameter typeParameter : typeParameters) {
TypeParameterDescriptor typeParameterDescriptor = resolveTypeParameter(typeParameter); TypeParameterDescriptor typeParameterDescriptor = resolveTypeParameter(containingDeclaration, typeParameter);
result.add(typeParameterDescriptor); result.add(typeParameterDescriptor);
} }
return result; return result;
@@ -158,11 +157,11 @@ public class JavaDescriptorResolver {
} }
@NotNull @NotNull
public TypeParameterDescriptor resolveTypeParameter(@NotNull PsiTypeParameter psiTypeParameter) { public TypeParameterDescriptor resolveTypeParameter(@NotNull DeclarationDescriptor containingDeclaration, @NotNull PsiTypeParameter psiTypeParameter) {
TypeParameterDescriptor typeParameterDescriptor = typeParameterDescriptorCache.get(psiTypeParameter); TypeParameterDescriptor typeParameterDescriptor = typeParameterDescriptorCache.get(psiTypeParameter);
if (typeParameterDescriptor == null) { if (typeParameterDescriptor == null) {
typeParameterDescriptor = createJavaTypeParameterDescriptor(JAVA_ROOT, psiTypeParameter); typeParameterDescriptor = createJavaTypeParameterDescriptor(containingDeclaration, psiTypeParameter);
// Tis is done inside the method: typeParameterDescriptorCache.put(psiTypeParameter, typeParameterDescriptor); // This is done inside the method: typeParameterDescriptorCache.put(psiTypeParameter, typeParameterDescriptor);
} }
return typeParameterDescriptor; return typeParameterDescriptor;
} }
@@ -245,9 +244,16 @@ public class JavaDescriptorResolver {
} }
@NotNull @NotNull
public FunctionGroup resolveFunctionGroup(@NotNull PsiClass psiClass, @NotNull String methodName, boolean staticMembers) { public FunctionGroup resolveFunctionGroup(@NotNull PsiClass psiClass, @Nullable ClassDescriptor classDescriptor, @NotNull String methodName, boolean staticMembers) {
WritableFunctionGroup writableFunctionGroup = new WritableFunctionGroup(methodName); WritableFunctionGroup writableFunctionGroup = new WritableFunctionGroup(methodName);
final Collection<HierarchicalMethodSignature> signatures = psiClass.getVisibleSignatures(); final Collection<HierarchicalMethodSignature> signatures = psiClass.getVisibleSignatures();
TypeSubstitutor typeSubstitutor;
if (classDescriptor != null) {
typeSubstitutor = TypeUtils.buildDeepSubstitutor(classDescriptor.getDefaultType());
}
else {
typeSubstitutor = TypeSubstitutor.EMPTY;
}
for (HierarchicalMethodSignature signature: signatures) { for (HierarchicalMethodSignature signature: signatures) {
PsiMethod method = signature.getMethod(); PsiMethod method = signature.getMethod();
if (method.hasModifierProperty(PsiModifier.STATIC) != staticMembers) { if (method.hasModifierProperty(PsiModifier.STATIC) != staticMembers) {
@@ -258,6 +264,9 @@ public class JavaDescriptorResolver {
} }
FunctionDescriptor functionDescriptor = methodDescriptorCache.get(method); FunctionDescriptor functionDescriptor = methodDescriptorCache.get(method);
if (functionDescriptor != null) { if (functionDescriptor != null) {
if (method.getContainingClass() != psiClass) {
functionDescriptor = functionDescriptor.substitute(typeSubstitutor);
}
writableFunctionGroup.addFunction(functionDescriptor); writableFunctionGroup.addFunction(functionDescriptor);
continue; continue;
} }
@@ -270,12 +279,18 @@ public class JavaDescriptorResolver {
); );
functionDescriptorImpl.initialize( functionDescriptorImpl.initialize(
null, null,
resolveTypeParameters(method.getTypeParameters()), resolveTypeParameters(functionDescriptorImpl, method.getTypeParameters()),
semanticServices.getDescriptorResolver().resolveParameterDescriptors(functionDescriptorImpl, parameters), semanticServices.getDescriptorResolver().resolveParameterDescriptors(functionDescriptorImpl, parameters),
semanticServices.getTypeTransformer().transformToType(method.getReturnType()) semanticServices.getTypeTransformer().transformToType(method.getReturnType())
); );
semanticServices.getTrace().recordDeclarationResolution(method, functionDescriptorImpl); semanticServices.getTrace().recordDeclarationResolution(method, functionDescriptorImpl);
writableFunctionGroup.addFunction(functionDescriptorImpl); FunctionDescriptor substitutedFunctionDescriptor = functionDescriptorImpl;
if (method.getContainingClass() != psiClass) {
substitutedFunctionDescriptor = functionDescriptorImpl.substitute(typeSubstitutor);
}
if (substitutedFunctionDescriptor != null) {
writableFunctionGroup.addFunction(substitutedFunctionDescriptor);
}
methodDescriptorCache.put(method, functionDescriptorImpl); methodDescriptorCache.put(method, functionDescriptorImpl);
} }
return writableFunctionGroup; return writableFunctionGroup;
@@ -70,7 +70,7 @@ public class JavaTypeTransformer {
if (psiClass instanceof PsiTypeParameter) { if (psiClass instanceof PsiTypeParameter) {
PsiTypeParameter typeParameter = (PsiTypeParameter) psiClass; PsiTypeParameter typeParameter = (PsiTypeParameter) psiClass;
TypeParameterDescriptor typeParameterDescriptor = resolver.resolveTypeParameter(typeParameter); TypeParameterDescriptor typeParameterDescriptor = resolver.resolveTypeParameter(JavaDescriptorResolver.JAVA_ROOT, typeParameter);
return typeParameterDescriptor.getDefaultType(); return typeParameterDescriptor.getDefaultType();
} }
else { else {
@@ -5,13 +5,18 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
import org.jetbrains.jet.lang.resolve.SubstitutingScope; import org.jetbrains.jet.lang.resolve.SubstitutingScope;
import java.util.*; import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/** /**
* @author abreslav * @author abreslav
*/ */
public class TypeSubstitutor { public class TypeSubstitutor {
public static final TypeSubstitutor EMPTY = create(Collections.<TypeConstructor, TypeProjection>emptyMap());
public static final class SubstitutionException extends Exception { public static final class SubstitutionException extends Exception {
public SubstitutionException(String message) { public SubstitutionException(String message) {
super(message); super(message);
@@ -176,6 +181,10 @@ public class TypeSubstitutor {
return new TypeProjection(effectiveProjectionKindValue, specializeType(effectiveTypeValue, effectiveContextVariance)); return new TypeProjection(effectiveProjectionKindValue, specializeType(effectiveTypeValue, effectiveContextVariance));
} }
/*package*/ void addSubstitution(@NotNull TypeConstructor typeConstructor, @NotNull TypeProjection typeProjection) {
substitutionContext.put(typeConstructor, typeProjection);
}
private static Variance asymmetricOr(Variance a, Variance b) { private static Variance asymmetricOr(Variance a, Variance b) {
return a == Variance.INVARIANT ? b : a; return a == Variance.INVARIANT ? b : a;
} }
@@ -1,6 +1,7 @@
package org.jetbrains.jet.lang.types; package org.jetbrains.jet.lang.types;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -185,15 +186,46 @@ public class TypeUtils {
return buildSubstitutionContext(context.getConstructor().getParameters(), context.getArguments()); return buildSubstitutionContext(context.getConstructor().getParameters(), context.getArguments());
} }
/**
* Builds a context with all the supertypes' parameters substituted
*/
@NotNull
public static TypeSubstitutor buildDeepSubstitutor(@NotNull JetType type) {
TypeSubstitutor typeSubstitutor = TypeSubstitutor.create(Maps.<TypeConstructor, TypeProjection>newHashMap());
fillInDeepSubstitutor(type, typeSubstitutor);
return typeSubstitutor;
}
private static void fillInDeepSubstitutor(JetType context, TypeSubstitutor substitutor) {
List<TypeParameterDescriptor> parameters = context.getConstructor().getParameters();
List<TypeProjection> arguments = context.getArguments();
for (int i = 0; i < arguments.size(); i++) {
TypeProjection argument = arguments.get(i);
TypeParameterDescriptor typeParameterDescriptor = parameters.get(i);
JetType substitute = substitutor.substitute(argument.getType(), Variance.INVARIANT);
assert substitute != null;
TypeProjection substitutedTypeProjection = new TypeProjection(argument.getProjectionKind(), substitute);
substitutor.addSubstitution(typeParameterDescriptor.getTypeConstructor(), substitutedTypeProjection);
}
for (JetType supertype : context.getConstructor().getSupertypes()) {
fillInDeepSubstitutor(supertype, substitutor);
}
}
@NotNull @NotNull
public static Map<TypeConstructor, TypeProjection> buildSubstitutionContext(@NotNull List<TypeParameterDescriptor> parameters, @NotNull List<TypeProjection> contextArguments) { public static Map<TypeConstructor, TypeProjection> buildSubstitutionContext(@NotNull List<TypeParameterDescriptor> parameters, @NotNull List<TypeProjection> contextArguments) {
Map<TypeConstructor, TypeProjection> parameterValues = new HashMap<TypeConstructor, TypeProjection>(); Map<TypeConstructor, TypeProjection> parameterValues = new HashMap<TypeConstructor, TypeProjection>();
fillInSubstitutionContext(parameters, contextArguments, parameterValues);
return parameterValues;
}
private static void fillInSubstitutionContext(List<TypeParameterDescriptor> parameters, List<TypeProjection> contextArguments, Map<TypeConstructor, TypeProjection> parameterValues) {
for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) { for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) {
TypeParameterDescriptor parameter = parameters.get(i); TypeParameterDescriptor parameter = parameters.get(i);
TypeProjection value = contextArguments.get(i); TypeProjection value = contextArguments.get(i);
parameterValues.put(parameter.getTypeConstructor(), value); parameterValues.put(parameter.getTypeConstructor(), value);
} }
return parameterValues;
} }
@NotNull @NotNull
@@ -0,0 +1,17 @@
// JET-72 Type inference doesn't work when iterating over ArrayList
import java.util.ArrayList
class Item(val room: Object) {
val name : String
}
val items: ArrayList<Item> = new ArrayList<Item>
fun test(room : Object) {
for(val item: Item in items) {
if (item.room === room) {
System.out?.println("You see " + item.name)
}
}
}