Scope filtering according to type projections supported

This commit is contained in:
Andrey Breslav
2011-03-22 21:06:52 +03:00
parent 1ed0c11ce2
commit e6b0a64b14
23 changed files with 357 additions and 218 deletions
+1
View File
@@ -3,6 +3,7 @@
<words>
<w>inferrer</w>
<w>nullable</w>
<w>substitutor</w>
<w>subtyping</w>
<w>supertype</w>
<w>supertypes</w>
@@ -7,10 +7,7 @@ import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lexer.JetTokens;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.*;
/**
* @author abreslav
@@ -222,7 +219,7 @@ public class ClassDescriptorResolver {
}
public List<TypeParameterDescriptor> resolveTypeParameters(DeclarationDescriptor containingDescriptor, WritableScope extensibleScope, List<JetTypeParameter> typeParameters) {
// TODO : When-clause
// TODO : Where-clause
List<TypeParameterDescriptor> result = new ArrayList<TypeParameterDescriptor>();
for (JetTypeParameter typeParameter : typeParameters) {
result.add(resolveTypeParameter(containingDescriptor, extensibleScope, typeParameter));
@@ -231,15 +228,18 @@ public class ClassDescriptorResolver {
}
private TypeParameterDescriptor resolveTypeParameter(DeclarationDescriptor containingDescriptor, WritableScope extensibleScope, JetTypeParameter typeParameter) {
// TODO: other bounds from where-clause
JetTypeReference extendsBound = typeParameter.getExtendsBound();
JetType bound = extendsBound == null
? JetStandardClasses.getDefaultBound()
: typeResolver.resolveType(extensibleScope, extendsBound);
TypeParameterDescriptor typeParameterDescriptor = new TypeParameterDescriptor(
containingDescriptor,
AttributeResolver.INSTANCE.resolveAttributes(typeParameter.getModifierList()),
typeParameter.getVariance(),
typeParameter.getName(),
extendsBound == null
? Collections.<JetType>singleton(JetStandardClasses.getDefaultBound())
: Collections.singleton(typeResolver.resolveType(extensibleScope, extendsBound))
Collections.singleton(bound),
bound
);
extensibleScope.addTypeParameterDescriptor(typeParameterDescriptor);
trace.recordDeclarationResolution(typeParameter, typeParameterDescriptor);
@@ -38,6 +38,12 @@ public class LazySubstitutingClassDescriptor implements ClassDescriptor {
return new SubstitutingScope(memberScope, substitutionContext);
}
@NotNull
@Override
public JetType getDefaultType() {
throw new UnsupportedOperationException(); // TODO
}
@NotNull
@Override
public FunctionGroup getConstructors(List<TypeProjection> typeArguments) {
@@ -35,10 +35,16 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme
@Override
public JetScope getMemberScope(List<TypeProjection> typeArguments) {
List<TypeParameterDescriptor> typeParameters = getTypeConstructor().getParameters();
Map<TypeConstructor,TypeProjection> substitutionContext = TypeSubstitutor.INSTANCE.buildSubstitutionContext(typeParameters, typeArguments);
Map<TypeConstructor,TypeProjection> substitutionContext = TypeUtils.buildSubstitutionContext(typeParameters, typeArguments);
return new SubstitutingScope(unsubstitutedMemberScope, substitutionContext);
}
@NotNull
@Override
public JetType getDefaultType() {
return TypeUtils.makeUnsubstitutedType(this, unsubstitutedMemberScope);
}
public void addConstructor(@NotNull ConstructorDescriptor constructorDescriptor) {
assert constructorDescriptor.getContainingDeclaration() == this;
constructors.addFunction(constructorDescriptor);
@@ -49,11 +55,12 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme
public FunctionGroup getConstructors(List<TypeProjection> typeArguments) {
// TODO : Duplicates ClassDescriptorImpl
assert typeArguments.size() == getTypeConstructor().getParameters().size();
if (typeArguments.size() == 0) {
return constructors;
}
Map<TypeConstructor, TypeProjection> substitutionContext = TypeSubstitutor.INSTANCE.buildSubstitutionContext(getTypeConstructor().getParameters(), typeArguments);
return new LazySubstitutingFunctionGroup(substitutionContext, constructors);
Map<TypeConstructor, TypeProjection> substitutionContext = TypeUtils.buildSubstitutionContext(getTypeConstructor().getParameters(), typeArguments);
return new LazySubstitutingFunctionGroup(substitutionContext, constructors, TypeSubstitutor.INSTANCE_FOR_CONSTRUCTORS);
}
@NotNull
@@ -9,7 +9,6 @@ import org.jetbrains.jet.lang.types.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
/**
* @author abreslav
@@ -148,8 +147,8 @@ public class TypeResolver {
JetProjectionKind projectionKind = argumentElement.getProjectionKind();
JetType type;
if (projectionKind == JetProjectionKind.STAR) {
Set<JetType> upperBounds = constructor.getParameters().get(i).getUpperBounds();
arguments.add(new TypeProjection(Variance.OUT_VARIANCE, TypeUtils.intersect(semanticServices.getTypeChecker(), upperBounds)));
TypeParameterDescriptor parameterDescriptor = constructor.getParameters().get(i);
arguments.add(TypeUtils.makeStarProjection(parameterDescriptor));
}
else {
// TODO : handle the Foo<in *> case
@@ -59,7 +59,9 @@ public class WritableFunctionGroup implements FunctionGroup {
if (functionDescriptor.getTypeParameters().size() == typeArgCount) {
if (FunctionDescriptorUtil.getMinimumArity(functionDescriptor) <= valueArgCount &&
valueArgCount <= FunctionDescriptorUtil.getMaximumArity(functionDescriptor)) {
result.add(FunctionDescriptorUtil.substituteFunctionDescriptor(typeArguments, functionDescriptor));
FunctionDescriptor substitutedFunctionDescriptor = FunctionDescriptorUtil.substituteFunctionDescriptor(typeArguments, functionDescriptor);
assert substitutedFunctionDescriptor != null;
result.add(substitutedFunctionDescriptor);
}
}
}
@@ -21,4 +21,10 @@ public interface ClassDescriptor extends DeclarationDescriptor {
@Override
@NotNull
DeclarationDescriptor getContainingDeclaration();
/**
* @return type A&lt;T&gt; for the class A&lt;T&gt;
*/
@NotNull
JetType getDefaultType();
}
@@ -24,13 +24,6 @@ public class ClassDescriptorImpl extends DeclarationDescriptorImpl implements Cl
super(containingDeclaration, attributes, name);
}
// public ClassDescriptorImpl(@NotNull DeclarationDescriptor containingDeclaration, String name, JetScope memberDeclarations) {
// this(containingDeclaration, Collections.<Attribute>emptyList(), name);
// this.initialize(Collections.<Attribute>emptyList(), true,
// name, Collections.<TypeParameterDescriptor>emptyList(),
// Collections.<Type>singleton(JetStandardClasses.getAnyType()), memberDeclarations);
// }
//
public final ClassDescriptorImpl initialize(boolean sealed,
@NotNull List<TypeParameterDescriptor> typeParameters,
@NotNull Collection<? extends JetType> superclasses,
@@ -55,10 +48,16 @@ public class ClassDescriptorImpl extends DeclarationDescriptorImpl implements Cl
if (typeConstructor.getParameters().isEmpty()) {
return memberDeclarations;
}
Map<TypeConstructor, TypeProjection> substitutionContext = TypeSubstitutor.INSTANCE.buildSubstitutionContext(typeConstructor.getParameters(), typeArguments);
Map<TypeConstructor, TypeProjection> substitutionContext = TypeUtils.buildSubstitutionContext(typeConstructor.getParameters(), typeArguments);
return new SubstitutingScope(memberDeclarations, substitutionContext);
}
@NotNull
@Override
public JetType getDefaultType() {
return TypeUtils.makeUnsubstitutedType(this, memberDeclarations);
}
@NotNull
@Override
public FunctionGroup getConstructors(List<TypeProjection> typeArguments) {
@@ -66,8 +65,8 @@ public class ClassDescriptorImpl extends DeclarationDescriptorImpl implements Cl
if (typeArguments.size() == 0) {
return constructors;
}
Map<TypeConstructor, TypeProjection> substitutionContext = TypeSubstitutor.INSTANCE.buildSubstitutionContext(getTypeConstructor().getParameters(), typeArguments);
return new LazySubstitutingFunctionGroup(substitutionContext, constructors);
Map<TypeConstructor, TypeProjection> substitutionContext = TypeUtils.buildSubstitutionContext(getTypeConstructor().getParameters(), typeArguments);
return new LazySubstitutingFunctionGroup(substitutionContext, constructors, TypeSubstitutor.INSTANCE_FOR_CONSTRUCTORS);
}
@Override
@@ -64,6 +64,6 @@ public class ConstructorDescriptorImpl extends FunctionDescriptorImpl implements
@NotNull
@Override
public JetType getUnsubstitutedReturnType() {
return TypeUtils.makeUnsubstitutedType(getContainingDeclaration());
return getContainingDeclaration().getDefaultType();
}
}
@@ -179,6 +179,10 @@ public class ErrorType {
return Collections.emptyList();
}
@Override
public String toString() {
return constructor.toString();
}
}
private ErrorType() {}
@@ -1,6 +1,7 @@
package org.jetbrains.jet.lang.types;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
@@ -37,29 +38,9 @@ public class FunctionDescriptorUtil {
return unsubstitutedValueParameters.size();
}
@NotNull
public static List<ValueParameterDescriptor> getSubstitutedValueParameters(FunctionDescriptor substitutedDescriptor, @NotNull FunctionDescriptor functionDescriptor, @NotNull List<JetType> typeArguments) {
// TODO : Review, maybe duplicates LazySubstitutingFunctionDescriptor
List<ValueParameterDescriptor> result = new ArrayList<ValueParameterDescriptor>();
Map<TypeConstructor, TypeProjection> context = createSubstitutionContext(functionDescriptor, typeArguments);
List<ValueParameterDescriptor> unsubstitutedValueParameters = functionDescriptor.getUnsubstitutedValueParameters();
for (int i = 0, unsubstitutedValueParametersSize = unsubstitutedValueParameters.size(); i < unsubstitutedValueParametersSize; i++) {
ValueParameterDescriptor unsubstitutedValueParameter = unsubstitutedValueParameters.get(i);
// TODO : Lazy?
result.add(new ValueParameterDescriptorImpl(
substitutedDescriptor,
i,
unsubstitutedValueParameter.getAttributes(),
unsubstitutedValueParameter.getName(),
TypeSubstitutor.INSTANCE.substitute(context, unsubstitutedValueParameter.getType(), Variance.IN_VARIANCE),
unsubstitutedValueParameter.hasDefaultValue(),
unsubstitutedValueParameter.isVararg()
));
}
return result;
}
private static Map<TypeConstructor, TypeProjection> createSubstitutionContext(@NotNull FunctionDescriptor functionDescriptor, List<JetType> typeArguments) {
if (functionDescriptor.getTypeParameters().isEmpty()) return Collections.emptyMap();
Map<TypeConstructor, TypeProjection> result = new HashMap<TypeConstructor, TypeProjection>();
int typeArgumentsSize = typeArguments.size();
@@ -73,26 +54,64 @@ public class FunctionDescriptorUtil {
return result;
}
@NotNull
public static JetType getSubstitutedReturnType(@NotNull FunctionDescriptor functionDescriptor, @NotNull List<JetType> typeArguments) {
// TODO : Review, maybe duplicates LazySubstitutingFunctionDescriptor
return TypeSubstitutor.INSTANCE.substitute(createSubstitutionContext(functionDescriptor, typeArguments), functionDescriptor.getUnsubstitutedReturnType(), Variance.OUT_VARIANCE);
@Nullable
private static List<ValueParameterDescriptor> getSubstitutedValueParameters(FunctionDescriptor substitutedDescriptor, @NotNull FunctionDescriptor functionDescriptor, Map<TypeConstructor, TypeProjection> substitutionContext, TypeSubstitutor typeSubstitutor) {
List<ValueParameterDescriptor> result = new ArrayList<ValueParameterDescriptor>();
List<ValueParameterDescriptor> unsubstitutedValueParameters = functionDescriptor.getUnsubstitutedValueParameters();
for (int i = 0, unsubstitutedValueParametersSize = unsubstitutedValueParameters.size(); i < unsubstitutedValueParametersSize; i++) {
ValueParameterDescriptor unsubstitutedValueParameter = unsubstitutedValueParameters.get(i);
// TODO : Lazy?
JetType substitutedType = typeSubstitutor.substitute(substitutionContext, unsubstitutedValueParameter.getType(), Variance.IN_VARIANCE);
if (substitutedType == null) return null;
result.add(new ValueParameterDescriptorImpl(
substitutedDescriptor,
i,
unsubstitutedValueParameter.getAttributes(),
unsubstitutedValueParameter.getName(),
substitutedType,
unsubstitutedValueParameter.hasDefaultValue(),
unsubstitutedValueParameter.isVararg()
));
}
return result;
}
@NotNull
@Nullable
private static JetType getSubstitutedReturnType(@NotNull FunctionDescriptor functionDescriptor, Map<TypeConstructor, TypeProjection> substitutionContext, TypeSubstitutor typeSubstitutor) {
return typeSubstitutor.substitute(substitutionContext, functionDescriptor.getUnsubstitutedReturnType(), Variance.OUT_VARIANCE);
}
@Nullable
public static FunctionDescriptor substituteFunctionDescriptor(@NotNull List<JetType> typeArguments, @NotNull FunctionDescriptor functionDescriptor) {
if (functionDescriptor.getTypeParameters().isEmpty()) {
Map<TypeConstructor, TypeProjection> substitutionContext = createSubstitutionContext(functionDescriptor, typeArguments);
return substituteFunctionDescriptor(functionDescriptor, substitutionContext, TypeSubstitutor.INSTANCE);
}
@Nullable
public static FunctionDescriptor substituteFunctionDescriptor(FunctionDescriptor functionDescriptor, Map<TypeConstructor, TypeProjection> substitutionContext, TypeSubstitutor typeSubstitutor) {
if (substitutionContext.isEmpty()) {
return functionDescriptor;
}
FunctionDescriptorImpl substitutedDescriptor = new FunctionDescriptorImpl(
functionDescriptor,
// TODO : substitute
// TODO : safeSubstitute
functionDescriptor.getAttributes(),
functionDescriptor.getName());
List<ValueParameterDescriptor> substitutedValueParameters = getSubstitutedValueParameters(substitutedDescriptor, functionDescriptor, substitutionContext, typeSubstitutor);
if (substitutedValueParameters == null) {
return null;
}
JetType substitutedReturnType = getSubstitutedReturnType(functionDescriptor, substitutionContext, typeSubstitutor);
if (substitutedReturnType == null) {
return null;
}
substitutedDescriptor.initialize(
Collections.<TypeParameterDescriptor>emptyList(), // TODO : questionable
getSubstitutedValueParameters(substitutedDescriptor, functionDescriptor, typeArguments),
getSubstitutedReturnType(functionDescriptor, typeArguments)
substitutedValueParameters,
substitutedReturnType
);
return substitutedDescriptor;
}
@@ -94,8 +94,7 @@ public class JetStandardClasses {
parameters.add(new TypeParameterDescriptor(
classDescriptor,
Collections.<Attribute>emptyList(),
Variance.OUT_VARIANCE, "T" + j,
Collections.singleton(getNullableAnyType())));
Variance.OUT_VARIANCE, "T" + j));
}
TUPLE[i] = classDescriptor.initialize(
true,
@@ -132,8 +131,7 @@ public class JetStandardClasses {
parameters.add(0, new TypeParameterDescriptor(
receiverFunction,
Collections.<Attribute>emptyList(),
Variance.IN_VARIANCE, "T",
Collections.singleton(getNullableAnyType())));
Variance.IN_VARIANCE, "T"));
RECEIVER_FUNCTION[i] = receiverFunction.initialize(
false,
parameters,
@@ -147,14 +145,12 @@ public class JetStandardClasses {
parameters.add(new TypeParameterDescriptor(
function,
Collections.<Attribute>emptyList(),
Variance.IN_VARIANCE, "P" + j,
Collections.singleton(getNullableAnyType())));
Variance.IN_VARIANCE, "P" + j));
}
parameters.add(new TypeParameterDescriptor(
function,
Collections.<Attribute>emptyList(),
Variance.OUT_VARIANCE, "R",
Collections.singleton(getNullableAnyType())));
Variance.OUT_VARIANCE, "R"));
return parameters;
}
@@ -98,7 +98,7 @@ public class JetTypeChecker {
}
commonSupertypes = computeCommonRawSupertypes(merge);
}
assert !commonSupertypes.isEmpty();
assert !commonSupertypes.isEmpty() : commonSupertypes;
Map.Entry<TypeConstructor, Set<JetType>> entry = commonSupertypes.entrySet().iterator().next();
JetType result = computeSupertypeProjections(entry.getKey(), entry.getValue());
@@ -274,13 +274,13 @@ public class JetTypeChecker {
return;
}
handler.beforeChildren(current);
Map<TypeConstructor, TypeProjection> substitutionContext = TypeSubstitutor.INSTANCE.buildSubstitutionContext(current);
Map<TypeConstructor, TypeProjection> substitutionContext = TypeUtils.buildSubstitutionContext(current);
for (JetType supertype : current.getConstructor().getSupertypes()) {
TypeConstructor supertypeConstructor = supertype.getConstructor();
if (visited.contains(supertypeConstructor)) {
continue;
}
JetType substitutedSupertype = TypeSubstitutor.INSTANCE.substitute(substitutionContext, supertype, Variance.INVARIANT);
JetType substitutedSupertype = TypeSubstitutor.INSTANCE.safeSubstitute(substitutionContext, supertype, Variance.INVARIANT);
dfs(substitutedSupertype, visited, handler);
}
handler.afterChildren(current);
@@ -331,7 +331,7 @@ public class JetTypeChecker {
for (JetType immediateSupertype : constructor.getSupertypes()) {
JetType correspondingSupertype = findCorrespondingSupertype(immediateSupertype, supertype);
if (correspondingSupertype != null) {
return TypeSubstitutor.INSTANCE.substitute(subtype, correspondingSupertype, Variance.INVARIANT);
return TypeSubstitutor.INSTANCE.safeSubstitute(subtype, correspondingSupertype, Variance.INVARIANT);
}
}
return null;
@@ -339,7 +339,7 @@ public class JetTypeChecker {
private boolean checkSubtypeForTheSameConstructor(@NotNull JetType subtype, @NotNull JetType supertype) {
TypeConstructor constructor = subtype.getConstructor();
assert constructor.equals(supertype.getConstructor());
assert constructor.equals(supertype.getConstructor()) : constructor + " is not " + supertype.getConstructor();
List<TypeProjection> subArguments = subtype.getArguments();
List<TypeProjection> superArguments = supertype.getArguments();
@@ -499,10 +499,10 @@ public class JetTypeInferrer {
JetUserType typeElement = (JetUserType) superTypeQualifier.getTypeElement();
ClassDescriptor superclass = typeResolver.resolveClass(scope, typeElement);
Collection<? extends JetType> supertypes = thisType.getConstructor().getSupertypes();
Map<TypeConstructor, TypeProjection> substitutionContext = TypeSubstitutor.INSTANCE.buildSubstitutionContext(thisType);
Map<TypeConstructor, TypeProjection> substitutionContext = TypeUtils.buildSubstitutionContext(thisType);
for (JetType declaredSupertype : supertypes) {
if (declaredSupertype.getConstructor().equals(superclass.getTypeConstructor())) {
result = TypeSubstitutor.INSTANCE.substitute(substitutionContext, declaredSupertype, Variance.INVARIANT);
result = TypeSubstitutor.INSTANCE.safeSubstitute(substitutionContext, declaredSupertype, Variance.INVARIANT);
break;
}
}
@@ -21,7 +21,7 @@ public class LazySubstitutedPropertyDescriptorImpl implements PropertyDescriptor
@Override
public JetType getType() {
if (propertyType == null) {
propertyType = TypeSubstitutor.INSTANCE.substitute(substitutionContext, propertyDescriptor.getType(), Variance.OUT_VARIANCE);
propertyType = TypeSubstitutor.INSTANCE.safeSubstitute(substitutionContext, propertyDescriptor.getType(), Variance.OUT_VARIANCE);
}
return propertyType;
}
@@ -1,96 +0,0 @@
package org.jetbrains.jet.lang.types;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @author abreslav
*/
public class LazySubstitutingFunctionDescriptor implements FunctionDescriptor {
private final Map<TypeConstructor, TypeProjection> substitutionContext;
private final FunctionDescriptor functionDescriptor;
public LazySubstitutingFunctionDescriptor(Map<TypeConstructor, TypeProjection> substitutionContext, FunctionDescriptor functionDescriptor) {
this.substitutionContext = substitutionContext;
this.functionDescriptor = functionDescriptor;
}
@NotNull
@Override
public List<TypeParameterDescriptor> getTypeParameters() {
List<TypeParameterDescriptor> result = new ArrayList<TypeParameterDescriptor>();
for (TypeParameterDescriptor parameterDescriptor : functionDescriptor.getTypeParameters()) {
// TODO : lazy?
result.add(new TypeParameterDescriptor(
this,
parameterDescriptor.getAttributes(),
parameterDescriptor.getVariance(),
parameterDescriptor.getName(),
TypeSubstitutor.INSTANCE.substituteInSet(substitutionContext, parameterDescriptor.getUpperBounds(), Variance.INVARIANT)));
}
return result;
}
@NotNull
@Override
public List<ValueParameterDescriptor> getUnsubstitutedValueParameters() {
List<ValueParameterDescriptor> result = new ArrayList<ValueParameterDescriptor>();
List<ValueParameterDescriptor> unsubstitutedValueParameters = functionDescriptor.getUnsubstitutedValueParameters();
for (int i = 0, unsubstitutedValueParametersSize = unsubstitutedValueParameters.size(); i < unsubstitutedValueParametersSize; i++) {
ValueParameterDescriptor parameterDescriptor = unsubstitutedValueParameters.get(i);
result.add(new ValueParameterDescriptorImpl(
this,
i,
parameterDescriptor.getAttributes(),
parameterDescriptor.getName(),
TypeSubstitutor.INSTANCE.substitute(substitutionContext, parameterDescriptor.getType(), Variance.IN_VARIANCE),
parameterDescriptor.hasDefaultValue(),
parameterDescriptor.isVararg()
));
}
return result;
}
@NotNull
@Override
public JetType getUnsubstitutedReturnType() {
return TypeSubstitutor.INSTANCE.substitute(substitutionContext, functionDescriptor.getUnsubstitutedReturnType(), Variance.OUT_VARIANCE);
}
@NotNull
@Override
public FunctionDescriptor getOriginal() {
return functionDescriptor.getOriginal();
}
@Override
public List<Attribute> getAttributes() {
// TODO : Substitute?
return functionDescriptor.getAttributes();
}
@Override
public String getName() {
return functionDescriptor.getName();
}
@NotNull
@Override
public DeclarationDescriptor getContainingDeclaration() {
return functionDescriptor.getContainingDeclaration();
}
@Override
public <R, D> R accept(DeclarationDescriptorVisitor<R, D> visitor, D data) {
return visitor.visitFunctionDescriptor(this, data);
}
@Override
public void acceptVoid(DeclarationDescriptorVisitor<Void, Void> visitor) {
accept(visitor, null);
}
}
@@ -1,6 +1,7 @@
package org.jetbrains.jet.lang.types;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.resolve.OverloadResolutionResult;
import java.util.ArrayList;
@@ -14,10 +15,16 @@ import java.util.Map;
public class LazySubstitutingFunctionGroup implements FunctionGroup {
private final Map<TypeConstructor, TypeProjection> substitutionContext;
private final FunctionGroup functionGroup;
private final TypeSubstitutor typeSubstitutor;
public LazySubstitutingFunctionGroup(Map<TypeConstructor, TypeProjection> substitutionContext, FunctionGroup functionGroup) {
public LazySubstitutingFunctionGroup(Map<TypeConstructor, TypeProjection> substitutionContext, FunctionGroup functionGroup, TypeSubstitutor typeSubstitutor) {
this.substitutionContext = substitutionContext;
this.functionGroup = functionGroup;
this.typeSubstitutor = typeSubstitutor;
}
public LazySubstitutingFunctionGroup(Map<TypeConstructor, TypeProjection> substitutionContext, FunctionGroup functionGroup) {
this(substitutionContext, functionGroup, TypeSubstitutor.INSTANCE);
}
@NotNull
@@ -34,15 +41,27 @@ public class LazySubstitutingFunctionGroup implements FunctionGroup {
Collection<FunctionDescriptor> result = new ArrayList<FunctionDescriptor>();
for (FunctionDescriptor function : resolutionResult.getFunctionDescriptors()) {
if (substitutionContext.isEmpty()) {
result.add(function);
} else {
result.add(new LazySubstitutingFunctionDescriptor(substitutionContext, function));
FunctionDescriptor functionDescriptor = substitute(substitutionContext, function, typeSubstitutor);
if (functionDescriptor != null) {
result.add(functionDescriptor);
}
}
return resolutionResult.newContents(result);
}
@Nullable
public FunctionDescriptor substitute(
@NotNull Map<TypeConstructor, TypeProjection> substitutionContext,
@NotNull FunctionDescriptor functionDescriptor, TypeSubstitutor typeSubstitutor) {
if (substitutionContext.isEmpty()) return functionDescriptor;
FunctionDescriptor substituted = FunctionDescriptorUtil.substituteFunctionDescriptor(functionDescriptor, substitutionContext, typeSubstitutor);
if (substituted == null) {
return null;
}
return substituted;
}
@Override
public boolean isEmpty() {
return functionGroup.isEmpty();
@@ -13,8 +13,15 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl {
private final Variance variance;
private final Set<JetType> upperBounds;
private final TypeConstructor typeConstructor;
private final JetType boundsAsType;
public TypeParameterDescriptor(@NotNull DeclarationDescriptor containingDeclaration, List<Attribute> attributes, Variance variance, String name, Set<JetType> upperBounds) {
public TypeParameterDescriptor(
@NotNull DeclarationDescriptor containingDeclaration,
@NotNull List<Attribute> attributes,
@NotNull Variance variance,
@NotNull String name,
@NotNull Set<JetType> upperBounds,
@NotNull JetType boundsAsType) {
super(containingDeclaration, attributes, name);
this.variance = variance;
this.upperBounds = upperBounds;
@@ -26,10 +33,21 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl {
"&" + name,
Collections.<TypeParameterDescriptor>emptyList(),
upperBounds);
this.boundsAsType = boundsAsType;
}
public TypeParameterDescriptor(@NotNull DeclarationDescriptor containingDeclaration, List<Attribute> attributes, Variance variance, String name) {
this(containingDeclaration, attributes, variance, name, Collections.singleton(JetStandardClasses.getNullableAnyType()));
public TypeParameterDescriptor(
@NotNull DeclarationDescriptor containingDeclaration,
@NotNull List<Attribute> attributes,
@NotNull Variance variance,
@NotNull String name) {
this(
containingDeclaration,
attributes,
variance,
name,
Collections.singleton(JetStandardClasses.getNullableAnyType()),
JetStandardClasses.getNullableAnyType());
}
public Variance getVariance() {
@@ -49,6 +67,11 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl {
return typeConstructor.toString();
}
@NotNull
public JetType getBoundsAsType() {
return boundsAsType;
}
@Override
public <R, D> R accept(DeclarationDescriptorVisitor<R, D> visitor, D data) {
return visitor.visitTypeParameterDescriptor(this, data);
@@ -1,6 +1,7 @@
package org.jetbrains.jet.lang.types;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.resolve.SubstitutingScope;
import java.util.*;
@@ -9,75 +10,135 @@ import java.util.*;
* @author abreslav
*/
public class TypeSubstitutor {
public static final class SubstitutionException extends Exception {
public SubstitutionException(String message) {
super(message);
}
}
public static final TypeSubstitutor INSTANCE = new TypeSubstitutor();
public static final TypeSubstitutor INSTANCE_FOR_CONSTRUCTORS = new TypeSubstitutor() {
@Override
protected boolean errorCondition(Variance ve, Variance p1) {
return false;
}
};
private TypeSubstitutor() {}
public JetType substitute(@NotNull JetType context, @NotNull JetType subject, @NotNull Variance howThisTypeIsUsed) {
return substitute(buildSubstitutionContext(context), subject, howThisTypeIsUsed);
public JetType safeSubstitute(@NotNull JetType context, @NotNull JetType subject, @NotNull Variance howThisTypeIsUsed) {
return safeSubstitute(TypeUtils.buildSubstitutionContext(context), subject, howThisTypeIsUsed);
}
@NotNull
public JetType safeSubstitute(@NotNull Map<TypeConstructor, TypeProjection> substitutionContext, @NotNull JetType type, @NotNull Variance howThisTypeIsUsed) {
try {
return unsafeSubstitute(substitutionContext, type, howThisTypeIsUsed);
} catch (SubstitutionException e) {
return ErrorType.createErrorType(e.getMessage());
}
}
@Nullable
public JetType substitute(@NotNull Map<TypeConstructor, TypeProjection> substitutionContext, @NotNull JetType type, @NotNull Variance howThisTypeIsUsed) {
TypeProjection value = substitutionContext.get(type.getConstructor());
try {
return unsafeSubstitute(substitutionContext, type, howThisTypeIsUsed);
} catch (SubstitutionException e) {
return null;
}
}
@NotNull
private JetType unsafeSubstitute(@NotNull Map<TypeConstructor, TypeProjection> substitutionContext, @NotNull JetType type, @NotNull Variance howThisTypeIsUsed) throws SubstitutionException {
TypeConstructor constructor = type.getConstructor();
TypeProjection value = substitutionContext.get(constructor);
if (value != null) {
Variance projectionKind = value.getProjectionKind();
if (howThisTypeIsUsed.allowsInPosition() && !projectionKind.allowsInPosition()
|| howThisTypeIsUsed.allowsOutPosition() && !projectionKind.allowsOutPosition()) {
return ErrorType.createWrongVarianceErrorType(value);
assert constructor.getDeclarationDescriptor() instanceof TypeParameterDescriptor;
if (errorCondition(howThisTypeIsUsed, value.getProjectionKind())) {
throw new SubstitutionException("!!" + value.toString());
}
return value.getType();
}
return specializeType(type, substitutionContext);
return specializeType(type, substitutionContext, howThisTypeIsUsed);
}
private JetType specializeType(JetType subjectType, Map<TypeConstructor, TypeProjection> substitutionContext) {
private JetType specializeType(JetType subjectType, Map<TypeConstructor, TypeProjection> substitutionContext, Variance callSiteVariance) throws SubstitutionException {
List<TypeProjection> newArguments = new ArrayList<TypeProjection>();
List<TypeProjection> arguments = subjectType.getArguments();
for (int i = 0, argumentsSize = arguments.size(); i < argumentsSize; i++) {
TypeProjection argument = arguments.get(i);
TypeParameterDescriptor parameterDescriptor = subjectType.getConstructor().getParameters().get(i);
newArguments.add(substituteInProjection(
substitutionContext,
argument,
parameterDescriptor,
callSiteVariance));
}
return new JetTypeImpl(
subjectType.getAttributes(),
subjectType.getConstructor(),
subjectType.isNullable(),
substituteInArguments(substitutionContext, subjectType),
newArguments,
new SubstitutingScope(subjectType.getMemberScope(), substitutionContext));
}
private List<TypeProjection> substituteInArguments(Map<TypeConstructor, TypeProjection> substitutionContext, JetType subjectType) {
List<TypeProjection> newArguments = new ArrayList<TypeProjection>();
for (TypeProjection argument : subjectType.getArguments()) {
newArguments.add(substituteInProjection(substitutionContext, argument));
@NotNull
private TypeProjection substituteInProjection(
@NotNull Map<TypeConstructor, TypeProjection> substitutionContext,
@NotNull TypeProjection p0_E,
@NotNull TypeParameterDescriptor d_T, // variance of the parameter this projection is substituted for
@NotNull Variance v) throws SubstitutionException {
JetType E = p0_E.getType();
Variance p0 = p0_E.getProjectionKind();
Variance d = d_T.getVariance();
Variance p01 = (p0 == Variance.INVARIANT) ? d : p0;
Variance ve = v.superpose(p01);
TypeProjection p1_A = substitutionContext.get(E.getConstructor());
if (p1_A != null) {
assert E.getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptor;
JetType A = p1_A.getType();
Variance p1 = p1_A.getProjectionKind();
if (!allows(d, p0)) {
return TypeUtils.makeStarProjection(d_T);
}
if (errorCondition(ve, p1)) {
throw new SubstitutionException(""); // TODO : error message
}
return new TypeProjection(p0 == Variance.INVARIANT ? p1 : p0, specializeType(A, substitutionContext, ve));
}
return newArguments;
return new TypeProjection(
p0,
specializeType(E, substitutionContext, ve));
}
@NotNull
private TypeProjection substituteInProjection(Map<TypeConstructor, TypeProjection> substitutionContext, TypeProjection subject) {
JetType subjectType = subject.getType();
TypeProjection value = substitutionContext.get(subjectType.getConstructor());
if (value != null) {
return value;
}
return new TypeProjection(subject.getProjectionKind(), specializeType(subjectType, substitutionContext));
protected boolean errorCondition(Variance ve, Variance p1) {
return !allows(ve, p1);
}
public Set<JetType> substituteInSet(Map<TypeConstructor, TypeProjection> substitutionContext, Set<JetType> types, Variance howTheseTypesWillBeUsed) {
Set<JetType> result = new HashSet<JetType>();
for (JetType type : types) {
result.add(substitute(substitutionContext, type, howTheseTypesWillBeUsed));
result.add(safeSubstitute(substitutionContext, type, howTheseTypesWillBeUsed));
}
return result;
}
public Map<TypeConstructor, TypeProjection> buildSubstitutionContext(JetType context) {
return buildSubstitutionContext(context.getConstructor().getParameters(), context.getArguments());
}
public Map<TypeConstructor, TypeProjection> buildSubstitutionContext(List<TypeParameterDescriptor> parameters, List<TypeProjection> contextArguments) {
Map<TypeConstructor, TypeProjection> parameterValues = new HashMap<TypeConstructor, TypeProjection>();
for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) {
TypeParameterDescriptor parameter = parameters.get(i);
TypeProjection value = contextArguments.get(i);
parameterValues.put(parameter.getTypeConstructor(), value);
private boolean allows(Variance declarationSiteVariance, Variance callSiteVariance) {
switch (declarationSiteVariance) {
case INVARIANT: return true;
case IN_VARIANCE: return callSiteVariance != Variance.OUT_VARIANCE;
case OUT_VARIANCE: return callSiteVariance != Variance.IN_VARIANCE;
}
return parameterValues;
throw new IllegalStateException(declarationSiteVariance.toString());
}
}
@@ -147,14 +147,14 @@ public class TypeUtils {
}
@NotNull
public static JetType makeUnsubstitutedType(ClassDescriptor classDescriptor) {
public static JetType makeUnsubstitutedType(ClassDescriptor classDescriptor, JetScope unsubstitutedMemberScope) {
List<TypeProjection> arguments = getArguments(classDescriptor);
return new JetTypeImpl(
Collections.<Attribute>emptyList(),
classDescriptor.getTypeConstructor(),
false,
arguments,
classDescriptor.getMemberScope(arguments)
unsubstitutedMemberScope
);
}
@@ -166,4 +166,25 @@ public class TypeUtils {
}
return result;
}
@NotNull
public static Map<TypeConstructor, TypeProjection> buildSubstitutionContext(@NotNull JetType context) {
return buildSubstitutionContext(context.getConstructor().getParameters(), context.getArguments());
}
@NotNull
public static Map<TypeConstructor, TypeProjection> buildSubstitutionContext(@NotNull List<TypeParameterDescriptor> parameters, @NotNull List<TypeProjection> contextArguments) {
Map<TypeConstructor, TypeProjection> parameterValues = new HashMap<TypeConstructor, TypeProjection>();
for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) {
TypeParameterDescriptor parameter = parameters.get(i);
TypeProjection value = contextArguments.get(i);
parameterValues.put(parameter.getTypeConstructor(), value);
}
return parameterValues;
}
@NotNull
public static TypeProjection makeStarProjection(@NotNull TypeParameterDescriptor parameterDescriptor) {
return new TypeProjection(Variance.OUT_VARIANCE, parameterDescriptor.getBoundsAsType());
}
}
@@ -4,18 +4,20 @@ package org.jetbrains.jet.lang.types;
* @author max
*/
public enum Variance {
INVARIANT("", true, true),
IN_VARIANCE("in", true, false),
OUT_VARIANCE("out", false, true);
INVARIANT("", true, true, 0),
IN_VARIANCE("in", true, false, -1),
OUT_VARIANCE("out", false, true, +1);
private final String label;
private final boolean allowsInPosition;
private final boolean allowsOutPosition;
private final int superpositionFactor;
Variance(String label, boolean allowsInPosition, boolean allowsOutPosition) {
Variance(String label, boolean allowsInPosition, boolean allowsOutPosition, int superpositionFactor) {
this.label = label;
this.allowsInPosition = allowsInPosition;
this.allowsOutPosition = allowsOutPosition;
this.superpositionFactor = superpositionFactor;
}
public boolean allowsInPosition() {
@@ -26,6 +28,16 @@ public enum Variance {
return allowsOutPosition;
}
public Variance superpose(Variance other) {
int r = this.superpositionFactor * other.superpositionFactor;
switch (r) {
case 0: return INVARIANT;
case -1: return IN_VARIANCE;
case +1: return OUT_VARIANCE;
}
throw new IllegalStateException();
}
@Override
public String toString() {
return label;
+56
View File
@@ -0,0 +1,56 @@
class In<in T> {
~In.f:T->Unit~fun f(t : T) : Unit {}
~In.f:Int->Int~fun f(t : Int) : Int {}
~In.f1~fun f1(t : T) : Unit {}
}
class Out<out T> {
~Out.f~fun f() : T {}
~Out.f(a)~fun f(a : Int) : Int {a}
}
class Inv<T> {
~Inv.f~fun f(t : T) : T {t}
~Inv.inf~fun inf(t : T) : Unit {}
~Inv.outf~fun outf() : T {}
}
fun testInOut() {
new In<String>().`In.f:T->Unit`f("1");
new In<in String>().`In.f:T->Unit`f("1");
new In<out String>().`!`f("1")
new In<*>().`!`f("1");
new In<String>().`In.f:Int->Int`f(1);
new In<in String>().`In.f:Int->Int`f(1);
new In<out String>().`In.f:Int->Int`f(1)
new In<out String>().`!`f1(1)
new In<*>().`In.f:Int->Int`f(1);
new Out<Int>().`Out.f(a)`f(1)
new Out<out Int>().`Out.f(a)`f(1)
new Out<in Int>().`Out.f(a)`f(1)
new Out<*>().`Out.f(a)`f(1)
new Out<Int>().`Out.f`f()
new Out<out Int>().`Out.f`f()
new Out<in Int>().`!`f()
new Out<*>().`Out.f`f()
new Inv<Int>().`Inv.f`f(1)
new Inv<in Int>().`!`f(1)
new Inv<out Int>().`!`f(1)
new Inv<*>().`!`f(1)
new Inv<Int>().`Inv.inf`inf(1)
new Inv<in Int>().`Inv.inf`inf(1)
new Inv<out Int>().`!`inf(1)
new Inv<*>().`!`inf(1)
new Inv<Int>().`Inv.outf`outf()
new Inv<in Int>().`!`outf()
new Inv<out Int>().`Inv.outf`outf()
new Inv<*>().`Inv.outf`outf()
new Inv<Int>().`Inv.outf`outf(1)
}
@@ -142,4 +142,8 @@ public class JetResolveTest extends ExtensibleResolveTestCase {
doTest("/resolve/ResolveOfInfixExpressions.jet", true, true);
}
public void testProjections() throws Exception {
doTest("/resolve/Projections.jet", true, true);
}
}