Substitutions for constructor are fixed
This commit is contained in:
@@ -60,7 +60,7 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme
|
|||||||
return constructors;
|
return constructors;
|
||||||
}
|
}
|
||||||
Map<TypeConstructor, TypeProjection> substitutionContext = TypeUtils.buildSubstitutionContext(getTypeConstructor().getParameters(), typeArguments);
|
Map<TypeConstructor, TypeProjection> substitutionContext = TypeUtils.buildSubstitutionContext(getTypeConstructor().getParameters(), typeArguments);
|
||||||
return new LazySubstitutingFunctionGroup(substitutionContext, constructors, TypeSubstitutor.INSTANCE_FOR_CONSTRUCTORS);
|
return new LazySubstitutingFunctionGroup(substitutionContext, constructors);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ public class ClassDescriptorImpl extends DeclarationDescriptorImpl implements Cl
|
|||||||
return constructors;
|
return constructors;
|
||||||
}
|
}
|
||||||
Map<TypeConstructor, TypeProjection> substitutionContext = TypeUtils.buildSubstitutionContext(getTypeConstructor().getParameters(), typeArguments);
|
Map<TypeConstructor, TypeProjection> substitutionContext = TypeUtils.buildSubstitutionContext(getTypeConstructor().getParameters(), typeArguments);
|
||||||
return new LazySubstitutingFunctionGroup(substitutionContext, constructors, TypeSubstitutor.INSTANCE_FOR_CONSTRUCTORS);
|
return new LazySubstitutingFunctionGroup(substitutionContext, constructors);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -55,13 +55,13 @@ public class FunctionDescriptorUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@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> result = new ArrayList<ValueParameterDescriptor>();
|
||||||
List<ValueParameterDescriptor> unsubstitutedValueParameters = functionDescriptor.getUnsubstitutedValueParameters();
|
List<ValueParameterDescriptor> unsubstitutedValueParameters = functionDescriptor.getUnsubstitutedValueParameters();
|
||||||
for (int i = 0, unsubstitutedValueParametersSize = unsubstitutedValueParameters.size(); i < unsubstitutedValueParametersSize; i++) {
|
for (int i = 0, unsubstitutedValueParametersSize = unsubstitutedValueParameters.size(); i < unsubstitutedValueParametersSize; i++) {
|
||||||
ValueParameterDescriptor unsubstitutedValueParameter = unsubstitutedValueParameters.get(i);
|
ValueParameterDescriptor unsubstitutedValueParameter = unsubstitutedValueParameters.get(i);
|
||||||
// TODO : Lazy?
|
// 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;
|
if (substitutedType == null) return null;
|
||||||
result.add(new ValueParameterDescriptorImpl(
|
result.add(new ValueParameterDescriptorImpl(
|
||||||
substitutedDescriptor,
|
substitutedDescriptor,
|
||||||
@@ -77,18 +77,18 @@ public class FunctionDescriptorUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private static JetType getSubstitutedReturnType(@NotNull FunctionDescriptor functionDescriptor, Map<TypeConstructor, TypeProjection> substitutionContext, TypeSubstitutor typeSubstitutor) {
|
private static JetType getSubstitutedReturnType(@NotNull FunctionDescriptor functionDescriptor, Map<TypeConstructor, TypeProjection> substitutionContext) {
|
||||||
return typeSubstitutor.substitute(substitutionContext, functionDescriptor.getUnsubstitutedReturnType(), Variance.OUT_VARIANCE);
|
return TypeSubstitutor.INSTANCE.substitute(substitutionContext, functionDescriptor.getUnsubstitutedReturnType(), Variance.OUT_VARIANCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static FunctionDescriptor substituteFunctionDescriptor(@NotNull List<JetType> typeArguments, @NotNull FunctionDescriptor functionDescriptor) {
|
public static FunctionDescriptor substituteFunctionDescriptor(@NotNull List<JetType> typeArguments, @NotNull FunctionDescriptor functionDescriptor) {
|
||||||
Map<TypeConstructor, TypeProjection> substitutionContext = createSubstitutionContext(functionDescriptor, typeArguments);
|
Map<TypeConstructor, TypeProjection> substitutionContext = createSubstitutionContext(functionDescriptor, typeArguments);
|
||||||
return substituteFunctionDescriptor(functionDescriptor, substitutionContext, TypeSubstitutor.INSTANCE);
|
return substituteFunctionDescriptor(functionDescriptor, substitutionContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@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()) {
|
if (substitutionContext.isEmpty()) {
|
||||||
return functionDescriptor;
|
return functionDescriptor;
|
||||||
}
|
}
|
||||||
@@ -98,12 +98,12 @@ public class FunctionDescriptorUtil {
|
|||||||
functionDescriptor.getAttributes(),
|
functionDescriptor.getAttributes(),
|
||||||
functionDescriptor.getName());
|
functionDescriptor.getName());
|
||||||
|
|
||||||
List<ValueParameterDescriptor> substitutedValueParameters = getSubstitutedValueParameters(substitutedDescriptor, functionDescriptor, substitutionContext, typeSubstitutor);
|
List<ValueParameterDescriptor> substitutedValueParameters = getSubstitutedValueParameters(substitutedDescriptor, functionDescriptor, substitutionContext);
|
||||||
if (substitutedValueParameters == null) {
|
if (substitutedValueParameters == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
JetType substitutedReturnType = getSubstitutedReturnType(functionDescriptor, substitutionContext, typeSubstitutor);
|
JetType substitutedReturnType = getSubstitutedReturnType(functionDescriptor, substitutionContext);
|
||||||
if (substitutedReturnType == null) {
|
if (substitutedReturnType == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -684,23 +684,52 @@ public class JetTypeInferrer {
|
|||||||
|
|
||||||
JetSimpleNameExpression referenceExpression = userType.getReferenceExpression();
|
JetSimpleNameExpression referenceExpression = userType.getReferenceExpression();
|
||||||
if (referenceExpression != null) {
|
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);
|
OverloadDomain constructorsOverloadDomain = semanticServices.getOverloadResolver().getOverloadDomain(constructors);
|
||||||
result = resolveOverloads(
|
JetType constructorReturnedType = resolveOverloads(
|
||||||
scope,
|
scope,
|
||||||
wrapForTracing(constructorsOverloadDomain, referenceExpression, expression.getArgumentList(), false),
|
wrapForTracing(constructorsOverloadDomain, referenceExpression, expression.getArgumentList(), false),
|
||||||
Collections.<JetTypeProjection>emptyList(),
|
Collections.<JetTypeProjection>emptyList(),
|
||||||
expression.getArguments(),
|
expression.getArguments(),
|
||||||
expression.getFunctionLiteralArguments());
|
expression.getFunctionLiteralArguments());
|
||||||
if (result == null && !ErrorType.isErrorType(receiverType)) {
|
if (constructorReturnedType == null && !ErrorType.isErrorType(receiverType)) {
|
||||||
trace.recordReferenceResolution(referenceExpression, receiverType.getConstructor().getDeclarationDescriptor());
|
trace.recordReferenceResolution(referenceExpression, receiverType.getConstructor().getDeclarationDescriptor());
|
||||||
// TODO : more helpful message
|
// TODO : more helpful message
|
||||||
JetArgumentList argumentList = expression.getArgumentList();
|
JetArgumentList argumentList = expression.getArgumentList();
|
||||||
if (argumentList != null) {
|
if (argumentList != null) {
|
||||||
semanticServices.getErrorHandler().genericError(argumentList.getNode(), "Cannot find an overload for these arguments");
|
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 {
|
else {
|
||||||
|
|||||||
@@ -15,16 +15,10 @@ 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, TypeSubstitutor typeSubstitutor) {
|
|
||||||
this.substitutionContext = substitutionContext;
|
|
||||||
this.functionGroup = functionGroup;
|
|
||||||
this.typeSubstitutor = typeSubstitutor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LazySubstitutingFunctionGroup(Map<TypeConstructor, TypeProjection> substitutionContext, FunctionGroup functionGroup) {
|
public LazySubstitutingFunctionGroup(Map<TypeConstructor, TypeProjection> substitutionContext, FunctionGroup functionGroup) {
|
||||||
this(substitutionContext, functionGroup, TypeSubstitutor.INSTANCE);
|
this.substitutionContext = substitutionContext;
|
||||||
|
this.functionGroup = functionGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -41,7 +35,7 @@ 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()) {
|
||||||
FunctionDescriptor functionDescriptor = substitute(substitutionContext, function, typeSubstitutor);
|
FunctionDescriptor functionDescriptor = substitute(substitutionContext, function);
|
||||||
if (functionDescriptor != null) {
|
if (functionDescriptor != null) {
|
||||||
result.add(functionDescriptor);
|
result.add(functionDescriptor);
|
||||||
}
|
}
|
||||||
@@ -52,10 +46,10 @@ public class LazySubstitutingFunctionGroup implements FunctionGroup {
|
|||||||
@Nullable
|
@Nullable
|
||||||
public FunctionDescriptor substitute(
|
public FunctionDescriptor substitute(
|
||||||
@NotNull Map<TypeConstructor, TypeProjection> substitutionContext,
|
@NotNull Map<TypeConstructor, TypeProjection> substitutionContext,
|
||||||
@NotNull FunctionDescriptor functionDescriptor, TypeSubstitutor typeSubstitutor) {
|
@NotNull FunctionDescriptor functionDescriptor) {
|
||||||
if (substitutionContext.isEmpty()) return functionDescriptor;
|
if (substitutionContext.isEmpty()) return functionDescriptor;
|
||||||
|
|
||||||
FunctionDescriptor substituted = FunctionDescriptorUtil.substituteFunctionDescriptor(functionDescriptor, substitutionContext, typeSubstitutor);
|
FunctionDescriptor substituted = FunctionDescriptorUtil.substituteFunctionDescriptor(functionDescriptor, substitutionContext);
|
||||||
if (substituted == null) {
|
if (substituted == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,13 +19,6 @@ public class TypeSubstitutor {
|
|||||||
|
|
||||||
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 safeSubstitute(@NotNull JetType context, @NotNull JetType subject, @NotNull Variance howThisTypeIsUsed) {
|
public JetType safeSubstitute(@NotNull JetType context, @NotNull JetType subject, @NotNull Variance howThisTypeIsUsed) {
|
||||||
@@ -57,7 +50,7 @@ public class TypeSubstitutor {
|
|||||||
if (value != null) {
|
if (value != null) {
|
||||||
assert constructor.getDeclarationDescriptor() instanceof TypeParameterDescriptor;
|
assert constructor.getDeclarationDescriptor() instanceof TypeParameterDescriptor;
|
||||||
|
|
||||||
if (errorCondition(howThisTypeIsUsed, value.getProjectionKind())) {
|
if (!allows(howThisTypeIsUsed, value.getProjectionKind())) {
|
||||||
throw new SubstitutionException("!!" + value.toString());
|
throw new SubstitutionException("!!" + value.toString());
|
||||||
}
|
}
|
||||||
return value.getType();
|
return value.getType();
|
||||||
@@ -89,49 +82,49 @@ public class TypeSubstitutor {
|
|||||||
@NotNull
|
@NotNull
|
||||||
private TypeProjection substituteInProjection(
|
private TypeProjection substituteInProjection(
|
||||||
@NotNull Map<TypeConstructor, TypeProjection> substitutionContext,
|
@NotNull Map<TypeConstructor, TypeProjection> substitutionContext,
|
||||||
@NotNull TypeProjection p0_E,
|
@NotNull TypeProjection passedProjection,
|
||||||
@NotNull TypeParameterDescriptor d_T, // variance of the parameter this projection is substituted for
|
@NotNull TypeParameterDescriptor correspondingTypeParameter,
|
||||||
@NotNull Variance v) throws SubstitutionException {
|
@NotNull Variance contextCallSiteVariance) throws SubstitutionException {
|
||||||
JetType E = p0_E.getType();
|
JetType typeToSubstituteIn = passedProjection.getType();
|
||||||
Variance p0 = p0_E.getProjectionKind();
|
Variance passedProjectionKind = passedProjection.getProjectionKind();
|
||||||
Variance d = d_T.getVariance();
|
Variance parameterVariance = correspondingTypeParameter.getVariance();
|
||||||
|
|
||||||
Variance p01 = (p0 == Variance.INVARIANT) ? d : p0;
|
Variance effectiveProjectionKind = (passedProjectionKind == Variance.INVARIANT) ? parameterVariance : passedProjectionKind;
|
||||||
Variance ve = v.superpose(p01);
|
Variance effectiveContextVariance = contextCallSiteVariance.superpose(effectiveProjectionKind);
|
||||||
|
|
||||||
TypeProjection p1_A = substitutionContext.get(E.getConstructor());
|
TypeProjection projectionValue = substitutionContext.get(typeToSubstituteIn.getConstructor());
|
||||||
if (p1_A != null) {
|
if (projectionValue != null) {
|
||||||
assert E.getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptor;
|
assert typeToSubstituteIn.getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptor;
|
||||||
|
|
||||||
JetType A = p1_A.getType();
|
JetType typeValue = projectionValue.getType();
|
||||||
Variance p1 = p1_A.getProjectionKind();
|
Variance projectionKindValue = projectionValue.getProjectionKind();
|
||||||
|
|
||||||
if (!allows(d, p0)) {
|
if (!allows(parameterVariance, passedProjectionKind)) {
|
||||||
return TypeUtils.makeStarProjection(d_T);
|
return TypeUtils.makeStarProjection( correspondingTypeParameter);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (errorCondition(ve, p1)) {
|
if (!allows(effectiveContextVariance, projectionKindValue)) {
|
||||||
throw new SubstitutionException(""); // TODO : error message
|
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(
|
return new TypeProjection(
|
||||||
p0,
|
passedProjectionKind,
|
||||||
specializeType(E, substitutionContext, ve));
|
specializeType(
|
||||||
|
typeToSubstituteIn,
|
||||||
|
substitutionContext,
|
||||||
|
effectiveContextVariance));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean errorCondition(Variance ve, Variance p1) {
|
// public Set<JetType> substituteInSet(Map<TypeConstructor, TypeProjection> substitutionContext, Set<JetType> types, Variance howTheseTypesWillBeUsed) {
|
||||||
return !allows(ve, p1);
|
// Set<JetType> result = new HashSet<JetType>();
|
||||||
}
|
// for (JetType type : types) {
|
||||||
|
// result.add(safeSubstitute(substitutionContext, type, howTheseTypesWillBeUsed));
|
||||||
public Set<JetType> substituteInSet(Map<TypeConstructor, TypeProjection> substitutionContext, Set<JetType> types, Variance howTheseTypesWillBeUsed) {
|
// }
|
||||||
Set<JetType> result = new HashSet<JetType>();
|
// return result;
|
||||||
for (JetType type : types) {
|
// }
|
||||||
result.add(safeSubstitute(substitutionContext, type, howTheseTypesWillBeUsed));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean allows(Variance declarationSiteVariance, Variance callSiteVariance) {
|
private boolean allows(Variance declarationSiteVariance, Variance callSiteVariance) {
|
||||||
switch (declarationSiteVariance) {
|
switch (declarationSiteVariance) {
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ fun testInOut() {
|
|||||||
new Inv<*>().`!`inf(1)
|
new Inv<*>().`!`inf(1)
|
||||||
|
|
||||||
new Inv<Int>().`Inv.outf`outf()
|
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<out Int>().`Inv.outf`outf()
|
||||||
new Inv<*>().`Inv.outf`outf()
|
new Inv<*>().`Inv.outf`outf()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user