Substitutions for constructor are fixed
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user