From b5dce0d72428d3068490f86018bdb50bf80f9cb7 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Wed, 23 Mar 2011 12:45:57 +0300 Subject: [PATCH] Substitutions for constructor are fixed --- .../lang/resolve/MutableClassDescriptor.java | 2 +- .../jet/lang/types/ClassDescriptorImpl.java | 2 +- .../lang/types/FunctionDescriptorUtil.java | 16 ++--- .../jet/lang/types/JetTypeInferrer.java | 37 ++++++++-- .../types/LazySubstitutingFunctionGroup.java | 16 ++--- .../jet/lang/types/TypeSubstitutor.java | 69 +++++++++---------- idea/testData/resolve/Projections.jet | 2 +- 7 files changed, 80 insertions(+), 64 deletions(-) diff --git a/idea/src/org/jetbrains/jet/lang/resolve/MutableClassDescriptor.java b/idea/src/org/jetbrains/jet/lang/resolve/MutableClassDescriptor.java index 1529a843e2a..91cf4157e88 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/MutableClassDescriptor.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/MutableClassDescriptor.java @@ -60,7 +60,7 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme return constructors; } Map substitutionContext = TypeUtils.buildSubstitutionContext(getTypeConstructor().getParameters(), typeArguments); - return new LazySubstitutingFunctionGroup(substitutionContext, constructors, TypeSubstitutor.INSTANCE_FOR_CONSTRUCTORS); + return new LazySubstitutingFunctionGroup(substitutionContext, constructors); } @NotNull diff --git a/idea/src/org/jetbrains/jet/lang/types/ClassDescriptorImpl.java b/idea/src/org/jetbrains/jet/lang/types/ClassDescriptorImpl.java index e9603e2036c..16172372d01 100644 --- a/idea/src/org/jetbrains/jet/lang/types/ClassDescriptorImpl.java +++ b/idea/src/org/jetbrains/jet/lang/types/ClassDescriptorImpl.java @@ -66,7 +66,7 @@ public class ClassDescriptorImpl extends DeclarationDescriptorImpl implements Cl return constructors; } Map substitutionContext = TypeUtils.buildSubstitutionContext(getTypeConstructor().getParameters(), typeArguments); - return new LazySubstitutingFunctionGroup(substitutionContext, constructors, TypeSubstitutor.INSTANCE_FOR_CONSTRUCTORS); + return new LazySubstitutingFunctionGroup(substitutionContext, constructors); } @Override diff --git a/idea/src/org/jetbrains/jet/lang/types/FunctionDescriptorUtil.java b/idea/src/org/jetbrains/jet/lang/types/FunctionDescriptorUtil.java index 348b7465aba..8128fc66f58 100644 --- a/idea/src/org/jetbrains/jet/lang/types/FunctionDescriptorUtil.java +++ b/idea/src/org/jetbrains/jet/lang/types/FunctionDescriptorUtil.java @@ -55,13 +55,13 @@ public class FunctionDescriptorUtil { } @Nullable - private static List getSubstitutedValueParameters(FunctionDescriptor substitutedDescriptor, @NotNull FunctionDescriptor functionDescriptor, Map substitutionContext, TypeSubstitutor typeSubstitutor) { + private static List getSubstitutedValueParameters(FunctionDescriptor substitutedDescriptor, @NotNull FunctionDescriptor functionDescriptor, Map substitutionContext) { List result = new ArrayList(); List 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 substitutionContext, TypeSubstitutor typeSubstitutor) { - return typeSubstitutor.substitute(substitutionContext, functionDescriptor.getUnsubstitutedReturnType(), Variance.OUT_VARIANCE); + private static JetType getSubstitutedReturnType(@NotNull FunctionDescriptor functionDescriptor, Map substitutionContext) { + return TypeSubstitutor.INSTANCE.substitute(substitutionContext, functionDescriptor.getUnsubstitutedReturnType(), Variance.OUT_VARIANCE); } @Nullable public static FunctionDescriptor substituteFunctionDescriptor(@NotNull List typeArguments, @NotNull FunctionDescriptor functionDescriptor) { Map substitutionContext = createSubstitutionContext(functionDescriptor, typeArguments); - return substituteFunctionDescriptor(functionDescriptor, substitutionContext, TypeSubstitutor.INSTANCE); + return substituteFunctionDescriptor(functionDescriptor, substitutionContext); } @Nullable - public static FunctionDescriptor substituteFunctionDescriptor(FunctionDescriptor functionDescriptor, Map substitutionContext, TypeSubstitutor typeSubstitutor) { + public static FunctionDescriptor substituteFunctionDescriptor(FunctionDescriptor functionDescriptor, Map substitutionContext) { if (substitutionContext.isEmpty()) { return functionDescriptor; } @@ -98,12 +98,12 @@ public class FunctionDescriptorUtil { functionDescriptor.getAttributes(), functionDescriptor.getName()); - List substitutedValueParameters = getSubstitutedValueParameters(substitutedDescriptor, functionDescriptor, substitutionContext, typeSubstitutor); + List 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; } diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index 6a971526b4b..01a0c431d58 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -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(...)' this does not make much sense, and an instance + // of 'Array' 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 = new Array(...) + // 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 typeArguments = receiverType.getArguments(); + System.out.println("typeArguments = " + typeArguments); + + List projectionsStripped = new ArrayList(); + 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.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 { diff --git a/idea/src/org/jetbrains/jet/lang/types/LazySubstitutingFunctionGroup.java b/idea/src/org/jetbrains/jet/lang/types/LazySubstitutingFunctionGroup.java index 326ea5311ea..c9923992945 100644 --- a/idea/src/org/jetbrains/jet/lang/types/LazySubstitutingFunctionGroup.java +++ b/idea/src/org/jetbrains/jet/lang/types/LazySubstitutingFunctionGroup.java @@ -15,16 +15,10 @@ import java.util.Map; public class LazySubstitutingFunctionGroup implements FunctionGroup { private final Map substitutionContext; private final FunctionGroup functionGroup; - private final TypeSubstitutor typeSubstitutor; - - public LazySubstitutingFunctionGroup(Map substitutionContext, FunctionGroup functionGroup, TypeSubstitutor typeSubstitutor) { - this.substitutionContext = substitutionContext; - this.functionGroup = functionGroup; - this.typeSubstitutor = typeSubstitutor; - } public LazySubstitutingFunctionGroup(Map 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 result = new ArrayList(); 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 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; } diff --git a/idea/src/org/jetbrains/jet/lang/types/TypeSubstitutor.java b/idea/src/org/jetbrains/jet/lang/types/TypeSubstitutor.java index 067885681a2..87ef4c6d752 100644 --- a/idea/src/org/jetbrains/jet/lang/types/TypeSubstitutor.java +++ b/idea/src/org/jetbrains/jet/lang/types/TypeSubstitutor.java @@ -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 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 substituteInSet(Map substitutionContext, Set types, Variance howTheseTypesWillBeUsed) { - Set result = new HashSet(); - for (JetType type : types) { - result.add(safeSubstitute(substitutionContext, type, howTheseTypesWillBeUsed)); - } - return result; - } + // public Set substituteInSet(Map substitutionContext, Set types, Variance howTheseTypesWillBeUsed) { +// Set result = new HashSet(); +// for (JetType type : types) { +// result.add(safeSubstitute(substitutionContext, type, howTheseTypesWillBeUsed)); +// } +// return result; +// } private boolean allows(Variance declarationSiteVariance, Variance callSiteVariance) { switch (declarationSiteVariance) { diff --git a/idea/testData/resolve/Projections.jet b/idea/testData/resolve/Projections.jet index 33b8b071452..437165a7f7b 100644 --- a/idea/testData/resolve/Projections.jet +++ b/idea/testData/resolve/Projections.jet @@ -48,7 +48,7 @@ fun testInOut() { new Inv<*>().`!`inf(1) new Inv().`Inv.outf`outf() - new Inv().`!`outf() + new Inv().`Inv.outf`outf()`:std::Any?` new Inv().`Inv.outf`outf() new Inv<*>().`Inv.outf`outf()