Substitutions for constructor are fixed

This commit is contained in:
Andrey Breslav
2011-03-23 12:45:57 +03:00
parent e6b0a64b14
commit b5dce0d724
7 changed files with 80 additions and 64 deletions
@@ -60,7 +60,7 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme
return constructors;
}
Map<TypeConstructor, TypeProjection> substitutionContext = TypeUtils.buildSubstitutionContext(getTypeConstructor().getParameters(), typeArguments);
return new LazySubstitutingFunctionGroup(substitutionContext, constructors, TypeSubstitutor.INSTANCE_FOR_CONSTRUCTORS);
return new LazySubstitutingFunctionGroup(substitutionContext, constructors);
}
@NotNull
@@ -66,7 +66,7 @@ public class ClassDescriptorImpl extends DeclarationDescriptorImpl implements Cl
return constructors;
}
Map<TypeConstructor, TypeProjection> substitutionContext = TypeUtils.buildSubstitutionContext(getTypeConstructor().getParameters(), typeArguments);
return new LazySubstitutingFunctionGroup(substitutionContext, constructors, TypeSubstitutor.INSTANCE_FOR_CONSTRUCTORS);
return new LazySubstitutingFunctionGroup(substitutionContext, constructors);
}
@Override
@@ -55,13 +55,13 @@ public class FunctionDescriptorUtil {
}
@Nullable
private static List<ValueParameterDescriptor> getSubstitutedValueParameters(FunctionDescriptor substitutedDescriptor, @NotNull FunctionDescriptor functionDescriptor, Map<TypeConstructor, TypeProjection> substitutionContext, TypeSubstitutor typeSubstitutor) {
private static List<ValueParameterDescriptor> getSubstitutedValueParameters(FunctionDescriptor substitutedDescriptor, @NotNull FunctionDescriptor functionDescriptor, Map<TypeConstructor, TypeProjection> substitutionContext) {
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);
JetType substitutedType = TypeSubstitutor.INSTANCE.substitute(substitutionContext, unsubstitutedValueParameter.getType(), Variance.IN_VARIANCE);
if (substitutedType == null) return null;
result.add(new ValueParameterDescriptorImpl(
substitutedDescriptor,
@@ -77,18 +77,18 @@ public class FunctionDescriptorUtil {
}
@Nullable
private static JetType getSubstitutedReturnType(@NotNull FunctionDescriptor functionDescriptor, Map<TypeConstructor, TypeProjection> substitutionContext, TypeSubstitutor typeSubstitutor) {
return typeSubstitutor.substitute(substitutionContext, functionDescriptor.getUnsubstitutedReturnType(), Variance.OUT_VARIANCE);
private static JetType getSubstitutedReturnType(@NotNull FunctionDescriptor functionDescriptor, Map<TypeConstructor, TypeProjection> substitutionContext) {
return TypeSubstitutor.INSTANCE.substitute(substitutionContext, functionDescriptor.getUnsubstitutedReturnType(), Variance.OUT_VARIANCE);
}
@Nullable
public static FunctionDescriptor substituteFunctionDescriptor(@NotNull List<JetType> typeArguments, @NotNull FunctionDescriptor functionDescriptor) {
Map<TypeConstructor, TypeProjection> substitutionContext = createSubstitutionContext(functionDescriptor, typeArguments);
return substituteFunctionDescriptor(functionDescriptor, substitutionContext, TypeSubstitutor.INSTANCE);
return substituteFunctionDescriptor(functionDescriptor, substitutionContext);
}
@Nullable
public static FunctionDescriptor substituteFunctionDescriptor(FunctionDescriptor functionDescriptor, Map<TypeConstructor, TypeProjection> substitutionContext, TypeSubstitutor typeSubstitutor) {
public static FunctionDescriptor substituteFunctionDescriptor(FunctionDescriptor functionDescriptor, Map<TypeConstructor, TypeProjection> substitutionContext) {
if (substitutionContext.isEmpty()) {
return functionDescriptor;
}
@@ -98,12 +98,12 @@ public class FunctionDescriptorUtil {
functionDescriptor.getAttributes(),
functionDescriptor.getName());
List<ValueParameterDescriptor> substitutedValueParameters = getSubstitutedValueParameters(substitutedDescriptor, functionDescriptor, substitutionContext, typeSubstitutor);
List<ValueParameterDescriptor> substitutedValueParameters = getSubstitutedValueParameters(substitutedDescriptor, functionDescriptor, substitutionContext);
if (substitutedValueParameters == null) {
return null;
}
JetType substitutedReturnType = getSubstitutedReturnType(functionDescriptor, substitutionContext, typeSubstitutor);
JetType substitutedReturnType = getSubstitutedReturnType(functionDescriptor, substitutionContext);
if (substitutedReturnType == null) {
return null;
}
@@ -684,23 +684,52 @@ public class JetTypeInferrer {
JetSimpleNameExpression referenceExpression = userType.getReferenceExpression();
if (referenceExpression != null) {
FunctionGroup constructors = classDescriptor.getConstructors(receiverType.getArguments());
// When one writes 'new Array<in T>(...)' this does not make much sense, and an instance
// of 'Array<T>' must be created anyway.
// Thus, we should either prohibit projections in type arguments in such contexts,
// or treat them as an automatic upcast to the desired type, i.e. for the user not
// to be forced to write
// val a : Array<in T> = new Array<T>(...)
// NOTE: Array may be a bad example here, some classes may have substantial functionality
// not involving their type parameters
//
// The code below upcasts the type automatically
List<TypeProjection> typeArguments = receiverType.getArguments();
System.out.println("typeArguments = " + typeArguments);
List<TypeProjection> projectionsStripped = new ArrayList<TypeProjection>();
for (TypeProjection typeArgument : typeArguments) {
if (typeArgument.getProjectionKind() != Variance.INVARIANT) {
projectionsStripped.add(new TypeProjection(typeArgument.getType()));
}
else
projectionsStripped.add(typeArgument);
}
System.out.println("projectionsStripped = " + projectionsStripped);
FunctionGroup constructors = classDescriptor.getConstructors(projectionsStripped);
OverloadDomain constructorsOverloadDomain = semanticServices.getOverloadResolver().getOverloadDomain(constructors);
result = resolveOverloads(
JetType constructorReturnedType = resolveOverloads(
scope,
wrapForTracing(constructorsOverloadDomain, referenceExpression, expression.getArgumentList(), false),
Collections.<JetTypeProjection>emptyList(),
expression.getArguments(),
expression.getFunctionLiteralArguments());
if (result == null && !ErrorType.isErrorType(receiverType)) {
if (constructorReturnedType == null && !ErrorType.isErrorType(receiverType)) {
trace.recordReferenceResolution(referenceExpression, receiverType.getConstructor().getDeclarationDescriptor());
// TODO : more helpful message
JetArgumentList argumentList = expression.getArgumentList();
if (argumentList != null) {
semanticServices.getErrorHandler().genericError(argumentList.getNode(), "Cannot find an overload for these arguments");
}
result = receiverType;
constructorReturnedType = receiverType;
}
// If no upcast needed:
result = constructorReturnedType;
// Automatic upcast:
result = receiverType;
}
}
else {
@@ -15,16 +15,10 @@ 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, TypeSubstitutor typeSubstitutor) {
this.substitutionContext = substitutionContext;
this.functionGroup = functionGroup;
this.typeSubstitutor = typeSubstitutor;
}
public LazySubstitutingFunctionGroup(Map<TypeConstructor, TypeProjection> substitutionContext, FunctionGroup functionGroup) {
this(substitutionContext, functionGroup, TypeSubstitutor.INSTANCE);
this.substitutionContext = substitutionContext;
this.functionGroup = functionGroup;
}
@NotNull
@@ -41,7 +35,7 @@ public class LazySubstitutingFunctionGroup implements FunctionGroup {
Collection<FunctionDescriptor> result = new ArrayList<FunctionDescriptor>();
for (FunctionDescriptor function : resolutionResult.getFunctionDescriptors()) {
FunctionDescriptor functionDescriptor = substitute(substitutionContext, function, typeSubstitutor);
FunctionDescriptor functionDescriptor = substitute(substitutionContext, function);
if (functionDescriptor != null) {
result.add(functionDescriptor);
}
@@ -52,10 +46,10 @@ public class LazySubstitutingFunctionGroup implements FunctionGroup {
@Nullable
public FunctionDescriptor substitute(
@NotNull Map<TypeConstructor, TypeProjection> substitutionContext,
@NotNull FunctionDescriptor functionDescriptor, TypeSubstitutor typeSubstitutor) {
@NotNull FunctionDescriptor functionDescriptor) {
if (substitutionContext.isEmpty()) return functionDescriptor;
FunctionDescriptor substituted = FunctionDescriptorUtil.substituteFunctionDescriptor(functionDescriptor, substitutionContext, typeSubstitutor);
FunctionDescriptor substituted = FunctionDescriptorUtil.substituteFunctionDescriptor(functionDescriptor, substitutionContext);
if (substituted == null) {
return null;
}
@@ -19,13 +19,6 @@ public class 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() {}
public JetType safeSubstitute(@NotNull JetType context, @NotNull JetType subject, @NotNull Variance howThisTypeIsUsed) {
@@ -57,7 +50,7 @@ public class TypeSubstitutor {
if (value != null) {
assert constructor.getDeclarationDescriptor() instanceof TypeParameterDescriptor;
if (errorCondition(howThisTypeIsUsed, value.getProjectionKind())) {
if (!allows(howThisTypeIsUsed, value.getProjectionKind())) {
throw new SubstitutionException("!!" + value.toString());
}
return value.getType();
@@ -89,49 +82,49 @@ public class TypeSubstitutor {
@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();
@NotNull TypeProjection passedProjection,
@NotNull TypeParameterDescriptor correspondingTypeParameter,
@NotNull Variance contextCallSiteVariance) throws SubstitutionException {
JetType typeToSubstituteIn = passedProjection.getType();
Variance passedProjectionKind = passedProjection.getProjectionKind();
Variance parameterVariance = correspondingTypeParameter.getVariance();
Variance p01 = (p0 == Variance.INVARIANT) ? d : p0;
Variance ve = v.superpose(p01);
Variance effectiveProjectionKind = (passedProjectionKind == Variance.INVARIANT) ? parameterVariance : passedProjectionKind;
Variance effectiveContextVariance = contextCallSiteVariance.superpose(effectiveProjectionKind);
TypeProjection p1_A = substitutionContext.get(E.getConstructor());
if (p1_A != null) {
assert E.getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptor;
TypeProjection projectionValue = substitutionContext.get(typeToSubstituteIn.getConstructor());
if (projectionValue != null) {
assert typeToSubstituteIn.getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptor;
JetType A = p1_A.getType();
Variance p1 = p1_A.getProjectionKind();
JetType typeValue = projectionValue.getType();
Variance projectionKindValue = projectionValue.getProjectionKind();
if (!allows(d, p0)) {
return TypeUtils.makeStarProjection(d_T);
if (!allows(parameterVariance, passedProjectionKind)) {
return TypeUtils.makeStarProjection( correspondingTypeParameter);
}
if (errorCondition(ve, p1)) {
if (!allows(effectiveContextVariance, projectionKindValue)) {
throw new SubstitutionException(""); // TODO : error message
}
return new TypeProjection(p0 == Variance.INVARIANT ? p1 : p0, specializeType(A, substitutionContext, ve));
Variance effectiveProjectionKindValue = passedProjectionKind == Variance.INVARIANT ? projectionKindValue : passedProjectionKind;
return new TypeProjection(effectiveProjectionKindValue, specializeType(typeValue, substitutionContext, effectiveContextVariance));
}
return new TypeProjection(
p0,
specializeType(E, substitutionContext, ve));
passedProjectionKind,
specializeType(
typeToSubstituteIn,
substitutionContext,
effectiveContextVariance));
}
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(safeSubstitute(substitutionContext, type, howTheseTypesWillBeUsed));
}
return result;
}
// 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(safeSubstitute(substitutionContext, type, howTheseTypesWillBeUsed));
// }
// return result;
// }
private boolean allows(Variance declarationSiteVariance, Variance callSiteVariance) {
switch (declarationSiteVariance) {
+1 -1
View File
@@ -48,7 +48,7 @@ fun testInOut() {
new Inv<*>().`!`inf(1)
new Inv<Int>().`Inv.outf`outf()
new Inv<in Int>().`!`outf()
new Inv<in Int>().`Inv.outf`outf()`:std::Any?`
new Inv<out Int>().`Inv.outf`outf()
new Inv<*>().`Inv.outf`outf()