Scope filtering according to type projections supported
This commit is contained in:
Generated
+1
@@ -3,6 +3,7 @@
|
|||||||
<words>
|
<words>
|
||||||
<w>inferrer</w>
|
<w>inferrer</w>
|
||||||
<w>nullable</w>
|
<w>nullable</w>
|
||||||
|
<w>substitutor</w>
|
||||||
<w>subtyping</w>
|
<w>subtyping</w>
|
||||||
<w>supertype</w>
|
<w>supertype</w>
|
||||||
<w>supertypes</w>
|
<w>supertypes</w>
|
||||||
|
|||||||
@@ -7,10 +7,7 @@ import org.jetbrains.jet.lang.psi.*;
|
|||||||
import org.jetbrains.jet.lang.types.*;
|
import org.jetbrains.jet.lang.types.*;
|
||||||
import org.jetbrains.jet.lexer.JetTokens;
|
import org.jetbrains.jet.lexer.JetTokens;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author abreslav
|
* @author abreslav
|
||||||
@@ -222,7 +219,7 @@ public class ClassDescriptorResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public List<TypeParameterDescriptor> resolveTypeParameters(DeclarationDescriptor containingDescriptor, WritableScope extensibleScope, List<JetTypeParameter> typeParameters) {
|
public List<TypeParameterDescriptor> resolveTypeParameters(DeclarationDescriptor containingDescriptor, WritableScope extensibleScope, List<JetTypeParameter> typeParameters) {
|
||||||
// TODO : When-clause
|
// TODO : Where-clause
|
||||||
List<TypeParameterDescriptor> result = new ArrayList<TypeParameterDescriptor>();
|
List<TypeParameterDescriptor> result = new ArrayList<TypeParameterDescriptor>();
|
||||||
for (JetTypeParameter typeParameter : typeParameters) {
|
for (JetTypeParameter typeParameter : typeParameters) {
|
||||||
result.add(resolveTypeParameter(containingDescriptor, extensibleScope, typeParameter));
|
result.add(resolveTypeParameter(containingDescriptor, extensibleScope, typeParameter));
|
||||||
@@ -231,15 +228,18 @@ public class ClassDescriptorResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private TypeParameterDescriptor resolveTypeParameter(DeclarationDescriptor containingDescriptor, WritableScope extensibleScope, JetTypeParameter typeParameter) {
|
private TypeParameterDescriptor resolveTypeParameter(DeclarationDescriptor containingDescriptor, WritableScope extensibleScope, JetTypeParameter typeParameter) {
|
||||||
|
// TODO: other bounds from where-clause
|
||||||
JetTypeReference extendsBound = typeParameter.getExtendsBound();
|
JetTypeReference extendsBound = typeParameter.getExtendsBound();
|
||||||
|
JetType bound = extendsBound == null
|
||||||
|
? JetStandardClasses.getDefaultBound()
|
||||||
|
: typeResolver.resolveType(extensibleScope, extendsBound);
|
||||||
TypeParameterDescriptor typeParameterDescriptor = new TypeParameterDescriptor(
|
TypeParameterDescriptor typeParameterDescriptor = new TypeParameterDescriptor(
|
||||||
containingDescriptor,
|
containingDescriptor,
|
||||||
AttributeResolver.INSTANCE.resolveAttributes(typeParameter.getModifierList()),
|
AttributeResolver.INSTANCE.resolveAttributes(typeParameter.getModifierList()),
|
||||||
typeParameter.getVariance(),
|
typeParameter.getVariance(),
|
||||||
typeParameter.getName(),
|
typeParameter.getName(),
|
||||||
extendsBound == null
|
Collections.singleton(bound),
|
||||||
? Collections.<JetType>singleton(JetStandardClasses.getDefaultBound())
|
bound
|
||||||
: Collections.singleton(typeResolver.resolveType(extensibleScope, extendsBound))
|
|
||||||
);
|
);
|
||||||
extensibleScope.addTypeParameterDescriptor(typeParameterDescriptor);
|
extensibleScope.addTypeParameterDescriptor(typeParameterDescriptor);
|
||||||
trace.recordDeclarationResolution(typeParameter, typeParameterDescriptor);
|
trace.recordDeclarationResolution(typeParameter, typeParameterDescriptor);
|
||||||
|
|||||||
@@ -38,6 +38,12 @@ public class LazySubstitutingClassDescriptor implements ClassDescriptor {
|
|||||||
return new SubstitutingScope(memberScope, substitutionContext);
|
return new SubstitutingScope(memberScope, substitutionContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public JetType getDefaultType() {
|
||||||
|
throw new UnsupportedOperationException(); // TODO
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public FunctionGroup getConstructors(List<TypeProjection> typeArguments) {
|
public FunctionGroup getConstructors(List<TypeProjection> typeArguments) {
|
||||||
|
|||||||
@@ -35,10 +35,16 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme
|
|||||||
@Override
|
@Override
|
||||||
public JetScope getMemberScope(List<TypeProjection> typeArguments) {
|
public JetScope getMemberScope(List<TypeProjection> typeArguments) {
|
||||||
List<TypeParameterDescriptor> typeParameters = getTypeConstructor().getParameters();
|
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);
|
return new SubstitutingScope(unsubstitutedMemberScope, substitutionContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public JetType getDefaultType() {
|
||||||
|
return TypeUtils.makeUnsubstitutedType(this, unsubstitutedMemberScope);
|
||||||
|
}
|
||||||
|
|
||||||
public void addConstructor(@NotNull ConstructorDescriptor constructorDescriptor) {
|
public void addConstructor(@NotNull ConstructorDescriptor constructorDescriptor) {
|
||||||
assert constructorDescriptor.getContainingDeclaration() == this;
|
assert constructorDescriptor.getContainingDeclaration() == this;
|
||||||
constructors.addFunction(constructorDescriptor);
|
constructors.addFunction(constructorDescriptor);
|
||||||
@@ -49,11 +55,12 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme
|
|||||||
public FunctionGroup getConstructors(List<TypeProjection> typeArguments) {
|
public FunctionGroup getConstructors(List<TypeProjection> typeArguments) {
|
||||||
// TODO : Duplicates ClassDescriptorImpl
|
// TODO : Duplicates ClassDescriptorImpl
|
||||||
assert typeArguments.size() == getTypeConstructor().getParameters().size();
|
assert typeArguments.size() == getTypeConstructor().getParameters().size();
|
||||||
|
|
||||||
if (typeArguments.size() == 0) {
|
if (typeArguments.size() == 0) {
|
||||||
return constructors;
|
return constructors;
|
||||||
}
|
}
|
||||||
Map<TypeConstructor, TypeProjection> substitutionContext = TypeSubstitutor.INSTANCE.buildSubstitutionContext(getTypeConstructor().getParameters(), typeArguments);
|
Map<TypeConstructor, TypeProjection> substitutionContext = TypeUtils.buildSubstitutionContext(getTypeConstructor().getParameters(), typeArguments);
|
||||||
return new LazySubstitutingFunctionGroup(substitutionContext, constructors);
|
return new LazySubstitutingFunctionGroup(substitutionContext, constructors, TypeSubstitutor.INSTANCE_FOR_CONSTRUCTORS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import org.jetbrains.jet.lang.types.*;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author abreslav
|
* @author abreslav
|
||||||
@@ -148,8 +147,8 @@ public class TypeResolver {
|
|||||||
JetProjectionKind projectionKind = argumentElement.getProjectionKind();
|
JetProjectionKind projectionKind = argumentElement.getProjectionKind();
|
||||||
JetType type;
|
JetType type;
|
||||||
if (projectionKind == JetProjectionKind.STAR) {
|
if (projectionKind == JetProjectionKind.STAR) {
|
||||||
Set<JetType> upperBounds = constructor.getParameters().get(i).getUpperBounds();
|
TypeParameterDescriptor parameterDescriptor = constructor.getParameters().get(i);
|
||||||
arguments.add(new TypeProjection(Variance.OUT_VARIANCE, TypeUtils.intersect(semanticServices.getTypeChecker(), upperBounds)));
|
arguments.add(TypeUtils.makeStarProjection(parameterDescriptor));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// TODO : handle the Foo<in *> case
|
// TODO : handle the Foo<in *> case
|
||||||
|
|||||||
@@ -59,7 +59,9 @@ public class WritableFunctionGroup implements FunctionGroup {
|
|||||||
if (functionDescriptor.getTypeParameters().size() == typeArgCount) {
|
if (functionDescriptor.getTypeParameters().size() == typeArgCount) {
|
||||||
if (FunctionDescriptorUtil.getMinimumArity(functionDescriptor) <= valueArgCount &&
|
if (FunctionDescriptorUtil.getMinimumArity(functionDescriptor) <= valueArgCount &&
|
||||||
valueArgCount <= FunctionDescriptorUtil.getMaximumArity(functionDescriptor)) {
|
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
|
@Override
|
||||||
@NotNull
|
@NotNull
|
||||||
DeclarationDescriptor getContainingDeclaration();
|
DeclarationDescriptor getContainingDeclaration();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return type A<T> for the class A<T>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
JetType getDefaultType();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,13 +24,6 @@ public class ClassDescriptorImpl extends DeclarationDescriptorImpl implements Cl
|
|||||||
super(containingDeclaration, attributes, name);
|
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,
|
public final ClassDescriptorImpl initialize(boolean sealed,
|
||||||
@NotNull List<TypeParameterDescriptor> typeParameters,
|
@NotNull List<TypeParameterDescriptor> typeParameters,
|
||||||
@NotNull Collection<? extends JetType> superclasses,
|
@NotNull Collection<? extends JetType> superclasses,
|
||||||
@@ -55,10 +48,16 @@ public class ClassDescriptorImpl extends DeclarationDescriptorImpl implements Cl
|
|||||||
if (typeConstructor.getParameters().isEmpty()) {
|
if (typeConstructor.getParameters().isEmpty()) {
|
||||||
return memberDeclarations;
|
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);
|
return new SubstitutingScope(memberDeclarations, substitutionContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public JetType getDefaultType() {
|
||||||
|
return TypeUtils.makeUnsubstitutedType(this, memberDeclarations);
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public FunctionGroup getConstructors(List<TypeProjection> typeArguments) {
|
public FunctionGroup getConstructors(List<TypeProjection> typeArguments) {
|
||||||
@@ -66,8 +65,8 @@ public class ClassDescriptorImpl extends DeclarationDescriptorImpl implements Cl
|
|||||||
if (typeArguments.size() == 0) {
|
if (typeArguments.size() == 0) {
|
||||||
return constructors;
|
return constructors;
|
||||||
}
|
}
|
||||||
Map<TypeConstructor, TypeProjection> substitutionContext = TypeSubstitutor.INSTANCE.buildSubstitutionContext(getTypeConstructor().getParameters(), typeArguments);
|
Map<TypeConstructor, TypeProjection> substitutionContext = TypeUtils.buildSubstitutionContext(getTypeConstructor().getParameters(), typeArguments);
|
||||||
return new LazySubstitutingFunctionGroup(substitutionContext, constructors);
|
return new LazySubstitutingFunctionGroup(substitutionContext, constructors, TypeSubstitutor.INSTANCE_FOR_CONSTRUCTORS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -64,6 +64,6 @@ public class ConstructorDescriptorImpl extends FunctionDescriptorImpl implements
|
|||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public JetType getUnsubstitutedReturnType() {
|
public JetType getUnsubstitutedReturnType() {
|
||||||
return TypeUtils.makeUnsubstitutedType(getContainingDeclaration());
|
return getContainingDeclaration().getDefaultType();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -179,6 +179,10 @@ public class ErrorType {
|
|||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return constructor.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ErrorType() {}
|
private ErrorType() {}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.jetbrains.jet.lang.types;
|
package org.jetbrains.jet.lang.types;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@@ -37,29 +38,9 @@ public class FunctionDescriptorUtil {
|
|||||||
return unsubstitutedValueParameters.size();
|
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) {
|
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>();
|
Map<TypeConstructor, TypeProjection> result = new HashMap<TypeConstructor, TypeProjection>();
|
||||||
|
|
||||||
int typeArgumentsSize = typeArguments.size();
|
int typeArgumentsSize = typeArguments.size();
|
||||||
@@ -73,26 +54,64 @@ public class FunctionDescriptorUtil {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@Nullable
|
||||||
public static JetType getSubstitutedReturnType(@NotNull FunctionDescriptor functionDescriptor, @NotNull List<JetType> typeArguments) {
|
private static List<ValueParameterDescriptor> getSubstitutedValueParameters(FunctionDescriptor substitutedDescriptor, @NotNull FunctionDescriptor functionDescriptor, Map<TypeConstructor, TypeProjection> substitutionContext, TypeSubstitutor typeSubstitutor) {
|
||||||
// TODO : Review, maybe duplicates LazySubstitutingFunctionDescriptor
|
List<ValueParameterDescriptor> result = new ArrayList<ValueParameterDescriptor>();
|
||||||
return TypeSubstitutor.INSTANCE.substitute(createSubstitutionContext(functionDescriptor, typeArguments), functionDescriptor.getUnsubstitutedReturnType(), Variance.OUT_VARIANCE);
|
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) {
|
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;
|
return functionDescriptor;
|
||||||
}
|
}
|
||||||
FunctionDescriptorImpl substitutedDescriptor = new FunctionDescriptorImpl(
|
FunctionDescriptorImpl substitutedDescriptor = new FunctionDescriptorImpl(
|
||||||
functionDescriptor,
|
functionDescriptor,
|
||||||
// TODO : substitute
|
// TODO : safeSubstitute
|
||||||
functionDescriptor.getAttributes(),
|
functionDescriptor.getAttributes(),
|
||||||
functionDescriptor.getName());
|
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(
|
substitutedDescriptor.initialize(
|
||||||
Collections.<TypeParameterDescriptor>emptyList(), // TODO : questionable
|
Collections.<TypeParameterDescriptor>emptyList(), // TODO : questionable
|
||||||
getSubstitutedValueParameters(substitutedDescriptor, functionDescriptor, typeArguments),
|
substitutedValueParameters,
|
||||||
getSubstitutedReturnType(functionDescriptor, typeArguments)
|
substitutedReturnType
|
||||||
);
|
);
|
||||||
return substitutedDescriptor;
|
return substitutedDescriptor;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,8 +94,7 @@ public class JetStandardClasses {
|
|||||||
parameters.add(new TypeParameterDescriptor(
|
parameters.add(new TypeParameterDescriptor(
|
||||||
classDescriptor,
|
classDescriptor,
|
||||||
Collections.<Attribute>emptyList(),
|
Collections.<Attribute>emptyList(),
|
||||||
Variance.OUT_VARIANCE, "T" + j,
|
Variance.OUT_VARIANCE, "T" + j));
|
||||||
Collections.singleton(getNullableAnyType())));
|
|
||||||
}
|
}
|
||||||
TUPLE[i] = classDescriptor.initialize(
|
TUPLE[i] = classDescriptor.initialize(
|
||||||
true,
|
true,
|
||||||
@@ -132,8 +131,7 @@ public class JetStandardClasses {
|
|||||||
parameters.add(0, new TypeParameterDescriptor(
|
parameters.add(0, new TypeParameterDescriptor(
|
||||||
receiverFunction,
|
receiverFunction,
|
||||||
Collections.<Attribute>emptyList(),
|
Collections.<Attribute>emptyList(),
|
||||||
Variance.IN_VARIANCE, "T",
|
Variance.IN_VARIANCE, "T"));
|
||||||
Collections.singleton(getNullableAnyType())));
|
|
||||||
RECEIVER_FUNCTION[i] = receiverFunction.initialize(
|
RECEIVER_FUNCTION[i] = receiverFunction.initialize(
|
||||||
false,
|
false,
|
||||||
parameters,
|
parameters,
|
||||||
@@ -147,14 +145,12 @@ public class JetStandardClasses {
|
|||||||
parameters.add(new TypeParameterDescriptor(
|
parameters.add(new TypeParameterDescriptor(
|
||||||
function,
|
function,
|
||||||
Collections.<Attribute>emptyList(),
|
Collections.<Attribute>emptyList(),
|
||||||
Variance.IN_VARIANCE, "P" + j,
|
Variance.IN_VARIANCE, "P" + j));
|
||||||
Collections.singleton(getNullableAnyType())));
|
|
||||||
}
|
}
|
||||||
parameters.add(new TypeParameterDescriptor(
|
parameters.add(new TypeParameterDescriptor(
|
||||||
function,
|
function,
|
||||||
Collections.<Attribute>emptyList(),
|
Collections.<Attribute>emptyList(),
|
||||||
Variance.OUT_VARIANCE, "R",
|
Variance.OUT_VARIANCE, "R"));
|
||||||
Collections.singleton(getNullableAnyType())));
|
|
||||||
return parameters;
|
return parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ public class JetTypeChecker {
|
|||||||
}
|
}
|
||||||
commonSupertypes = computeCommonRawSupertypes(merge);
|
commonSupertypes = computeCommonRawSupertypes(merge);
|
||||||
}
|
}
|
||||||
assert !commonSupertypes.isEmpty();
|
assert !commonSupertypes.isEmpty() : commonSupertypes;
|
||||||
Map.Entry<TypeConstructor, Set<JetType>> entry = commonSupertypes.entrySet().iterator().next();
|
Map.Entry<TypeConstructor, Set<JetType>> entry = commonSupertypes.entrySet().iterator().next();
|
||||||
JetType result = computeSupertypeProjections(entry.getKey(), entry.getValue());
|
JetType result = computeSupertypeProjections(entry.getKey(), entry.getValue());
|
||||||
|
|
||||||
@@ -274,13 +274,13 @@ public class JetTypeChecker {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
handler.beforeChildren(current);
|
handler.beforeChildren(current);
|
||||||
Map<TypeConstructor, TypeProjection> substitutionContext = TypeSubstitutor.INSTANCE.buildSubstitutionContext(current);
|
Map<TypeConstructor, TypeProjection> substitutionContext = TypeUtils.buildSubstitutionContext(current);
|
||||||
for (JetType supertype : current.getConstructor().getSupertypes()) {
|
for (JetType supertype : current.getConstructor().getSupertypes()) {
|
||||||
TypeConstructor supertypeConstructor = supertype.getConstructor();
|
TypeConstructor supertypeConstructor = supertype.getConstructor();
|
||||||
if (visited.contains(supertypeConstructor)) {
|
if (visited.contains(supertypeConstructor)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
JetType substitutedSupertype = TypeSubstitutor.INSTANCE.substitute(substitutionContext, supertype, Variance.INVARIANT);
|
JetType substitutedSupertype = TypeSubstitutor.INSTANCE.safeSubstitute(substitutionContext, supertype, Variance.INVARIANT);
|
||||||
dfs(substitutedSupertype, visited, handler);
|
dfs(substitutedSupertype, visited, handler);
|
||||||
}
|
}
|
||||||
handler.afterChildren(current);
|
handler.afterChildren(current);
|
||||||
@@ -331,7 +331,7 @@ public class JetTypeChecker {
|
|||||||
for (JetType immediateSupertype : constructor.getSupertypes()) {
|
for (JetType immediateSupertype : constructor.getSupertypes()) {
|
||||||
JetType correspondingSupertype = findCorrespondingSupertype(immediateSupertype, supertype);
|
JetType correspondingSupertype = findCorrespondingSupertype(immediateSupertype, supertype);
|
||||||
if (correspondingSupertype != null) {
|
if (correspondingSupertype != null) {
|
||||||
return TypeSubstitutor.INSTANCE.substitute(subtype, correspondingSupertype, Variance.INVARIANT);
|
return TypeSubstitutor.INSTANCE.safeSubstitute(subtype, correspondingSupertype, Variance.INVARIANT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@@ -339,7 +339,7 @@ public class JetTypeChecker {
|
|||||||
|
|
||||||
private boolean checkSubtypeForTheSameConstructor(@NotNull JetType subtype, @NotNull JetType supertype) {
|
private boolean checkSubtypeForTheSameConstructor(@NotNull JetType subtype, @NotNull JetType supertype) {
|
||||||
TypeConstructor constructor = subtype.getConstructor();
|
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> subArguments = subtype.getArguments();
|
||||||
List<TypeProjection> superArguments = supertype.getArguments();
|
List<TypeProjection> superArguments = supertype.getArguments();
|
||||||
|
|||||||
@@ -499,10 +499,10 @@ public class JetTypeInferrer {
|
|||||||
JetUserType typeElement = (JetUserType) superTypeQualifier.getTypeElement();
|
JetUserType typeElement = (JetUserType) superTypeQualifier.getTypeElement();
|
||||||
ClassDescriptor superclass = typeResolver.resolveClass(scope, typeElement);
|
ClassDescriptor superclass = typeResolver.resolveClass(scope, typeElement);
|
||||||
Collection<? extends JetType> supertypes = thisType.getConstructor().getSupertypes();
|
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) {
|
for (JetType declaredSupertype : supertypes) {
|
||||||
if (declaredSupertype.getConstructor().equals(superclass.getTypeConstructor())) {
|
if (declaredSupertype.getConstructor().equals(superclass.getTypeConstructor())) {
|
||||||
result = TypeSubstitutor.INSTANCE.substitute(substitutionContext, declaredSupertype, Variance.INVARIANT);
|
result = TypeSubstitutor.INSTANCE.safeSubstitute(substitutionContext, declaredSupertype, Variance.INVARIANT);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ public class LazySubstitutedPropertyDescriptorImpl implements PropertyDescriptor
|
|||||||
@Override
|
@Override
|
||||||
public JetType getType() {
|
public JetType getType() {
|
||||||
if (propertyType == null) {
|
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;
|
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;
|
package org.jetbrains.jet.lang.types;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.lang.resolve.OverloadResolutionResult;
|
import org.jetbrains.jet.lang.resolve.OverloadResolutionResult;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -14,10 +15,16 @@ import java.util.Map;
|
|||||||
public class LazySubstitutingFunctionGroup implements FunctionGroup {
|
public class LazySubstitutingFunctionGroup implements FunctionGroup {
|
||||||
private final Map<TypeConstructor, TypeProjection> substitutionContext;
|
private final Map<TypeConstructor, TypeProjection> substitutionContext;
|
||||||
private final FunctionGroup functionGroup;
|
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.substitutionContext = substitutionContext;
|
||||||
this.functionGroup = functionGroup;
|
this.functionGroup = functionGroup;
|
||||||
|
this.typeSubstitutor = typeSubstitutor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LazySubstitutingFunctionGroup(Map<TypeConstructor, TypeProjection> substitutionContext, FunctionGroup functionGroup) {
|
||||||
|
this(substitutionContext, functionGroup, TypeSubstitutor.INSTANCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -34,15 +41,27 @@ public class LazySubstitutingFunctionGroup implements FunctionGroup {
|
|||||||
|
|
||||||
Collection<FunctionDescriptor> result = new ArrayList<FunctionDescriptor>();
|
Collection<FunctionDescriptor> result = new ArrayList<FunctionDescriptor>();
|
||||||
for (FunctionDescriptor function : resolutionResult.getFunctionDescriptors()) {
|
for (FunctionDescriptor function : resolutionResult.getFunctionDescriptors()) {
|
||||||
if (substitutionContext.isEmpty()) {
|
FunctionDescriptor functionDescriptor = substitute(substitutionContext, function, typeSubstitutor);
|
||||||
result.add(function);
|
if (functionDescriptor != null) {
|
||||||
} else {
|
result.add(functionDescriptor);
|
||||||
result.add(new LazySubstitutingFunctionDescriptor(substitutionContext, function));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return resolutionResult.newContents(result);
|
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
|
@Override
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
return functionGroup.isEmpty();
|
return functionGroup.isEmpty();
|
||||||
|
|||||||
@@ -13,8 +13,15 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl {
|
|||||||
private final Variance variance;
|
private final Variance variance;
|
||||||
private final Set<JetType> upperBounds;
|
private final Set<JetType> upperBounds;
|
||||||
private final TypeConstructor typeConstructor;
|
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);
|
super(containingDeclaration, attributes, name);
|
||||||
this.variance = variance;
|
this.variance = variance;
|
||||||
this.upperBounds = upperBounds;
|
this.upperBounds = upperBounds;
|
||||||
@@ -26,10 +33,21 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl {
|
|||||||
"&" + name,
|
"&" + name,
|
||||||
Collections.<TypeParameterDescriptor>emptyList(),
|
Collections.<TypeParameterDescriptor>emptyList(),
|
||||||
upperBounds);
|
upperBounds);
|
||||||
|
this.boundsAsType = boundsAsType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TypeParameterDescriptor(@NotNull DeclarationDescriptor containingDeclaration, List<Attribute> attributes, Variance variance, String name) {
|
public TypeParameterDescriptor(
|
||||||
this(containingDeclaration, attributes, variance, name, Collections.singleton(JetStandardClasses.getNullableAnyType()));
|
@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() {
|
public Variance getVariance() {
|
||||||
@@ -49,6 +67,11 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl {
|
|||||||
return typeConstructor.toString();
|
return typeConstructor.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public JetType getBoundsAsType() {
|
||||||
|
return boundsAsType;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <R, D> R accept(DeclarationDescriptorVisitor<R, D> visitor, D data) {
|
public <R, D> R accept(DeclarationDescriptorVisitor<R, D> visitor, D data) {
|
||||||
return visitor.visitTypeParameterDescriptor(this, data);
|
return visitor.visitTypeParameterDescriptor(this, data);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.jetbrains.jet.lang.types;
|
package org.jetbrains.jet.lang.types;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.lang.resolve.SubstitutingScope;
|
import org.jetbrains.jet.lang.resolve.SubstitutingScope;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@@ -9,75 +10,135 @@ import java.util.*;
|
|||||||
* @author abreslav
|
* @author abreslav
|
||||||
*/
|
*/
|
||||||
public class TypeSubstitutor {
|
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 = new TypeSubstitutor();
|
||||||
|
|
||||||
|
public static final TypeSubstitutor INSTANCE_FOR_CONSTRUCTORS = new TypeSubstitutor() {
|
||||||
|
@Override
|
||||||
|
protected boolean errorCondition(Variance ve, Variance p1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private TypeSubstitutor() {}
|
private TypeSubstitutor() {}
|
||||||
|
|
||||||
public JetType substitute(@NotNull JetType context, @NotNull JetType subject, @NotNull Variance howThisTypeIsUsed) {
|
public JetType safeSubstitute(@NotNull JetType context, @NotNull JetType subject, @NotNull Variance howThisTypeIsUsed) {
|
||||||
return substitute(buildSubstitutionContext(context), subject, howThisTypeIsUsed);
|
return safeSubstitute(TypeUtils.buildSubstitutionContext(context), subject, howThisTypeIsUsed);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@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) {
|
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) {
|
if (value != null) {
|
||||||
Variance projectionKind = value.getProjectionKind();
|
assert constructor.getDeclarationDescriptor() instanceof TypeParameterDescriptor;
|
||||||
if (howThisTypeIsUsed.allowsInPosition() && !projectionKind.allowsInPosition()
|
|
||||||
|| howThisTypeIsUsed.allowsOutPosition() && !projectionKind.allowsOutPosition()) {
|
if (errorCondition(howThisTypeIsUsed, value.getProjectionKind())) {
|
||||||
return ErrorType.createWrongVarianceErrorType(value);
|
throw new SubstitutionException("!!" + value.toString());
|
||||||
}
|
}
|
||||||
return value.getType();
|
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(
|
return new JetTypeImpl(
|
||||||
subjectType.getAttributes(),
|
subjectType.getAttributes(),
|
||||||
subjectType.getConstructor(),
|
subjectType.getConstructor(),
|
||||||
subjectType.isNullable(),
|
subjectType.isNullable(),
|
||||||
substituteInArguments(substitutionContext, subjectType),
|
newArguments,
|
||||||
new SubstitutingScope(subjectType.getMemberScope(), substitutionContext));
|
new SubstitutingScope(subjectType.getMemberScope(), substitutionContext));
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<TypeProjection> substituteInArguments(Map<TypeConstructor, TypeProjection> substitutionContext, JetType subjectType) {
|
@NotNull
|
||||||
List<TypeProjection> newArguments = new ArrayList<TypeProjection>();
|
private TypeProjection substituteInProjection(
|
||||||
for (TypeProjection argument : subjectType.getArguments()) {
|
@NotNull Map<TypeConstructor, TypeProjection> substitutionContext,
|
||||||
newArguments.add(substituteInProjection(substitutionContext, argument));
|
@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
|
protected boolean errorCondition(Variance ve, Variance p1) {
|
||||||
private TypeProjection substituteInProjection(Map<TypeConstructor, TypeProjection> substitutionContext, TypeProjection subject) {
|
return !allows(ve, p1);
|
||||||
JetType subjectType = subject.getType();
|
|
||||||
TypeProjection value = substitutionContext.get(subjectType.getConstructor());
|
|
||||||
if (value != null) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
return new TypeProjection(subject.getProjectionKind(), specializeType(subjectType, substitutionContext));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<JetType> substituteInSet(Map<TypeConstructor, TypeProjection> substitutionContext, Set<JetType> types, Variance howTheseTypesWillBeUsed) {
|
public Set<JetType> substituteInSet(Map<TypeConstructor, TypeProjection> substitutionContext, Set<JetType> types, Variance howTheseTypesWillBeUsed) {
|
||||||
Set<JetType> result = new HashSet<JetType>();
|
Set<JetType> result = new HashSet<JetType>();
|
||||||
for (JetType type : types) {
|
for (JetType type : types) {
|
||||||
result.add(substitute(substitutionContext, type, howTheseTypesWillBeUsed));
|
result.add(safeSubstitute(substitutionContext, type, howTheseTypesWillBeUsed));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<TypeConstructor, TypeProjection> buildSubstitutionContext(JetType context) {
|
private boolean allows(Variance declarationSiteVariance, Variance callSiteVariance) {
|
||||||
return buildSubstitutionContext(context.getConstructor().getParameters(), context.getArguments());
|
switch (declarationSiteVariance) {
|
||||||
}
|
case INVARIANT: return true;
|
||||||
|
case IN_VARIANCE: return callSiteVariance != Variance.OUT_VARIANCE;
|
||||||
public Map<TypeConstructor, TypeProjection> buildSubstitutionContext(List<TypeParameterDescriptor> parameters, List<TypeProjection> contextArguments) {
|
case OUT_VARIANCE: return callSiteVariance != Variance.IN_VARIANCE;
|
||||||
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;
|
throw new IllegalStateException(declarationSiteVariance.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -147,14 +147,14 @@ public class TypeUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static JetType makeUnsubstitutedType(ClassDescriptor classDescriptor) {
|
public static JetType makeUnsubstitutedType(ClassDescriptor classDescriptor, JetScope unsubstitutedMemberScope) {
|
||||||
List<TypeProjection> arguments = getArguments(classDescriptor);
|
List<TypeProjection> arguments = getArguments(classDescriptor);
|
||||||
return new JetTypeImpl(
|
return new JetTypeImpl(
|
||||||
Collections.<Attribute>emptyList(),
|
Collections.<Attribute>emptyList(),
|
||||||
classDescriptor.getTypeConstructor(),
|
classDescriptor.getTypeConstructor(),
|
||||||
false,
|
false,
|
||||||
arguments,
|
arguments,
|
||||||
classDescriptor.getMemberScope(arguments)
|
unsubstitutedMemberScope
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,4 +166,25 @@ public class TypeUtils {
|
|||||||
}
|
}
|
||||||
return result;
|
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
|
* @author max
|
||||||
*/
|
*/
|
||||||
public enum Variance {
|
public enum Variance {
|
||||||
INVARIANT("", true, true),
|
INVARIANT("", true, true, 0),
|
||||||
IN_VARIANCE("in", true, false),
|
IN_VARIANCE("in", true, false, -1),
|
||||||
OUT_VARIANCE("out", false, true);
|
OUT_VARIANCE("out", false, true, +1);
|
||||||
|
|
||||||
private final String label;
|
private final String label;
|
||||||
private final boolean allowsInPosition;
|
private final boolean allowsInPosition;
|
||||||
private final boolean allowsOutPosition;
|
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.label = label;
|
||||||
this.allowsInPosition = allowsInPosition;
|
this.allowsInPosition = allowsInPosition;
|
||||||
this.allowsOutPosition = allowsOutPosition;
|
this.allowsOutPosition = allowsOutPosition;
|
||||||
|
this.superpositionFactor = superpositionFactor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean allowsInPosition() {
|
public boolean allowsInPosition() {
|
||||||
@@ -26,6 +28,16 @@ public enum Variance {
|
|||||||
return allowsOutPosition;
|
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
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return label;
|
return label;
|
||||||
|
|||||||
@@ -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);
|
doTest("/resolve/ResolveOfInfixExpressions.jet", true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testProjections() throws Exception {
|
||||||
|
doTest("/resolve/Projections.jet", true, true);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user