diff --git a/.idea/dictionaries/abreslav.xml b/.idea/dictionaries/abreslav.xml index bec9ce9fb24..db3d985c5e2 100644 --- a/.idea/dictionaries/abreslav.xml +++ b/.idea/dictionaries/abreslav.xml @@ -3,6 +3,7 @@ inferrer nullable + substitutor subtyping supertype supertypes diff --git a/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java index e4cc15230c9..570e7a6d2f7 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java @@ -7,10 +7,7 @@ import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lexer.JetTokens; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; +import java.util.*; /** * @author abreslav @@ -222,7 +219,7 @@ public class ClassDescriptorResolver { } public List resolveTypeParameters(DeclarationDescriptor containingDescriptor, WritableScope extensibleScope, List typeParameters) { - // TODO : When-clause + // TODO : Where-clause List result = new ArrayList(); for (JetTypeParameter typeParameter : typeParameters) { result.add(resolveTypeParameter(containingDescriptor, extensibleScope, typeParameter)); @@ -231,15 +228,18 @@ public class ClassDescriptorResolver { } private TypeParameterDescriptor resolveTypeParameter(DeclarationDescriptor containingDescriptor, WritableScope extensibleScope, JetTypeParameter typeParameter) { + // TODO: other bounds from where-clause JetTypeReference extendsBound = typeParameter.getExtendsBound(); + JetType bound = extendsBound == null + ? JetStandardClasses.getDefaultBound() + : typeResolver.resolveType(extensibleScope, extendsBound); TypeParameterDescriptor typeParameterDescriptor = new TypeParameterDescriptor( containingDescriptor, AttributeResolver.INSTANCE.resolveAttributes(typeParameter.getModifierList()), typeParameter.getVariance(), typeParameter.getName(), - extendsBound == null - ? Collections.singleton(JetStandardClasses.getDefaultBound()) - : Collections.singleton(typeResolver.resolveType(extensibleScope, extendsBound)) + Collections.singleton(bound), + bound ); extensibleScope.addTypeParameterDescriptor(typeParameterDescriptor); trace.recordDeclarationResolution(typeParameter, typeParameterDescriptor); diff --git a/idea/src/org/jetbrains/jet/lang/resolve/LazySubstitutingClassDescriptor.java b/idea/src/org/jetbrains/jet/lang/resolve/LazySubstitutingClassDescriptor.java index 38ab2483748..0b30c6c7a08 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/LazySubstitutingClassDescriptor.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/LazySubstitutingClassDescriptor.java @@ -38,6 +38,12 @@ public class LazySubstitutingClassDescriptor implements ClassDescriptor { return new SubstitutingScope(memberScope, substitutionContext); } + @NotNull + @Override + public JetType getDefaultType() { + throw new UnsupportedOperationException(); // TODO + } + @NotNull @Override public FunctionGroup getConstructors(List typeArguments) { diff --git a/idea/src/org/jetbrains/jet/lang/resolve/MutableClassDescriptor.java b/idea/src/org/jetbrains/jet/lang/resolve/MutableClassDescriptor.java index 8d67fa50916..1529a843e2a 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/MutableClassDescriptor.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/MutableClassDescriptor.java @@ -35,10 +35,16 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme @Override public JetScope getMemberScope(List typeArguments) { List typeParameters = getTypeConstructor().getParameters(); - Map substitutionContext = TypeSubstitutor.INSTANCE.buildSubstitutionContext(typeParameters, typeArguments); + Map substitutionContext = TypeUtils.buildSubstitutionContext(typeParameters, typeArguments); return new SubstitutingScope(unsubstitutedMemberScope, substitutionContext); } + @NotNull + @Override + public JetType getDefaultType() { + return TypeUtils.makeUnsubstitutedType(this, unsubstitutedMemberScope); + } + public void addConstructor(@NotNull ConstructorDescriptor constructorDescriptor) { assert constructorDescriptor.getContainingDeclaration() == this; constructors.addFunction(constructorDescriptor); @@ -49,11 +55,12 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme public FunctionGroup getConstructors(List typeArguments) { // TODO : Duplicates ClassDescriptorImpl assert typeArguments.size() == getTypeConstructor().getParameters().size(); + if (typeArguments.size() == 0) { return constructors; } - Map substitutionContext = TypeSubstitutor.INSTANCE.buildSubstitutionContext(getTypeConstructor().getParameters(), typeArguments); - return new LazySubstitutingFunctionGroup(substitutionContext, constructors); + Map substitutionContext = TypeUtils.buildSubstitutionContext(getTypeConstructor().getParameters(), typeArguments); + return new LazySubstitutingFunctionGroup(substitutionContext, constructors, TypeSubstitutor.INSTANCE_FOR_CONSTRUCTORS); } @NotNull diff --git a/idea/src/org/jetbrains/jet/lang/resolve/TypeResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/TypeResolver.java index bf460c1f9ee..a8fe8dda02f 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/TypeResolver.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/TypeResolver.java @@ -9,7 +9,6 @@ import org.jetbrains.jet.lang.types.*; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.Set; /** * @author abreslav @@ -148,8 +147,8 @@ public class TypeResolver { JetProjectionKind projectionKind = argumentElement.getProjectionKind(); JetType type; if (projectionKind == JetProjectionKind.STAR) { - Set upperBounds = constructor.getParameters().get(i).getUpperBounds(); - arguments.add(new TypeProjection(Variance.OUT_VARIANCE, TypeUtils.intersect(semanticServices.getTypeChecker(), upperBounds))); + TypeParameterDescriptor parameterDescriptor = constructor.getParameters().get(i); + arguments.add(TypeUtils.makeStarProjection(parameterDescriptor)); } else { // TODO : handle the Foo case diff --git a/idea/src/org/jetbrains/jet/lang/resolve/WritableFunctionGroup.java b/idea/src/org/jetbrains/jet/lang/resolve/WritableFunctionGroup.java index 7bac48a0e03..a1249333de1 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/WritableFunctionGroup.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/WritableFunctionGroup.java @@ -59,7 +59,9 @@ public class WritableFunctionGroup implements FunctionGroup { if (functionDescriptor.getTypeParameters().size() == typeArgCount) { if (FunctionDescriptorUtil.getMinimumArity(functionDescriptor) <= valueArgCount && valueArgCount <= FunctionDescriptorUtil.getMaximumArity(functionDescriptor)) { - result.add(FunctionDescriptorUtil.substituteFunctionDescriptor(typeArguments, functionDescriptor)); + FunctionDescriptor substitutedFunctionDescriptor = FunctionDescriptorUtil.substituteFunctionDescriptor(typeArguments, functionDescriptor); + assert substitutedFunctionDescriptor != null; + result.add(substitutedFunctionDescriptor); } } } diff --git a/idea/src/org/jetbrains/jet/lang/types/ClassDescriptor.java b/idea/src/org/jetbrains/jet/lang/types/ClassDescriptor.java index ac15a99bdd9..2d55620f257 100644 --- a/idea/src/org/jetbrains/jet/lang/types/ClassDescriptor.java +++ b/idea/src/org/jetbrains/jet/lang/types/ClassDescriptor.java @@ -21,4 +21,10 @@ public interface ClassDescriptor extends DeclarationDescriptor { @Override @NotNull DeclarationDescriptor getContainingDeclaration(); + + /** + * @return type A<T> for the class A<T> + */ + @NotNull + JetType getDefaultType(); } diff --git a/idea/src/org/jetbrains/jet/lang/types/ClassDescriptorImpl.java b/idea/src/org/jetbrains/jet/lang/types/ClassDescriptorImpl.java index 2ebc609887d..e9603e2036c 100644 --- a/idea/src/org/jetbrains/jet/lang/types/ClassDescriptorImpl.java +++ b/idea/src/org/jetbrains/jet/lang/types/ClassDescriptorImpl.java @@ -24,13 +24,6 @@ public class ClassDescriptorImpl extends DeclarationDescriptorImpl implements Cl super(containingDeclaration, attributes, name); } -// public ClassDescriptorImpl(@NotNull DeclarationDescriptor containingDeclaration, String name, JetScope memberDeclarations) { -// this(containingDeclaration, Collections.emptyList(), name); -// this.initialize(Collections.emptyList(), true, -// name, Collections.emptyList(), -// Collections.singleton(JetStandardClasses.getAnyType()), memberDeclarations); -// } -// public final ClassDescriptorImpl initialize(boolean sealed, @NotNull List typeParameters, @NotNull Collection superclasses, @@ -55,10 +48,16 @@ public class ClassDescriptorImpl extends DeclarationDescriptorImpl implements Cl if (typeConstructor.getParameters().isEmpty()) { return memberDeclarations; } - Map substitutionContext = TypeSubstitutor.INSTANCE.buildSubstitutionContext(typeConstructor.getParameters(), typeArguments); + Map substitutionContext = TypeUtils.buildSubstitutionContext(typeConstructor.getParameters(), typeArguments); return new SubstitutingScope(memberDeclarations, substitutionContext); } + @NotNull + @Override + public JetType getDefaultType() { + return TypeUtils.makeUnsubstitutedType(this, memberDeclarations); + } + @NotNull @Override public FunctionGroup getConstructors(List typeArguments) { @@ -66,8 +65,8 @@ public class ClassDescriptorImpl extends DeclarationDescriptorImpl implements Cl if (typeArguments.size() == 0) { return constructors; } - Map substitutionContext = TypeSubstitutor.INSTANCE.buildSubstitutionContext(getTypeConstructor().getParameters(), typeArguments); - return new LazySubstitutingFunctionGroup(substitutionContext, constructors); + Map substitutionContext = TypeUtils.buildSubstitutionContext(getTypeConstructor().getParameters(), typeArguments); + return new LazySubstitutingFunctionGroup(substitutionContext, constructors, TypeSubstitutor.INSTANCE_FOR_CONSTRUCTORS); } @Override diff --git a/idea/src/org/jetbrains/jet/lang/types/ConstructorDescriptorImpl.java b/idea/src/org/jetbrains/jet/lang/types/ConstructorDescriptorImpl.java index 0ef331378e9..a4c3280dcee 100644 --- a/idea/src/org/jetbrains/jet/lang/types/ConstructorDescriptorImpl.java +++ b/idea/src/org/jetbrains/jet/lang/types/ConstructorDescriptorImpl.java @@ -64,6 +64,6 @@ public class ConstructorDescriptorImpl extends FunctionDescriptorImpl implements @NotNull @Override public JetType getUnsubstitutedReturnType() { - return TypeUtils.makeUnsubstitutedType(getContainingDeclaration()); + return getContainingDeclaration().getDefaultType(); } } diff --git a/idea/src/org/jetbrains/jet/lang/types/ErrorType.java b/idea/src/org/jetbrains/jet/lang/types/ErrorType.java index 06a8686075e..54a9d2dbaa1 100644 --- a/idea/src/org/jetbrains/jet/lang/types/ErrorType.java +++ b/idea/src/org/jetbrains/jet/lang/types/ErrorType.java @@ -179,6 +179,10 @@ public class ErrorType { return Collections.emptyList(); } + @Override + public String toString() { + return constructor.toString(); + } } private ErrorType() {} diff --git a/idea/src/org/jetbrains/jet/lang/types/FunctionDescriptorUtil.java b/idea/src/org/jetbrains/jet/lang/types/FunctionDescriptorUtil.java index d6da415cb93..348b7465aba 100644 --- a/idea/src/org/jetbrains/jet/lang/types/FunctionDescriptorUtil.java +++ b/idea/src/org/jetbrains/jet/lang/types/FunctionDescriptorUtil.java @@ -1,6 +1,7 @@ package org.jetbrains.jet.lang.types; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.*; @@ -37,29 +38,9 @@ public class FunctionDescriptorUtil { return unsubstitutedValueParameters.size(); } - @NotNull - public static List getSubstitutedValueParameters(FunctionDescriptor substitutedDescriptor, @NotNull FunctionDescriptor functionDescriptor, @NotNull List typeArguments) { - // TODO : Review, maybe duplicates LazySubstitutingFunctionDescriptor - List result = new ArrayList(); - Map context = createSubstitutionContext(functionDescriptor, typeArguments); - List 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 createSubstitutionContext(@NotNull FunctionDescriptor functionDescriptor, List typeArguments) { + if (functionDescriptor.getTypeParameters().isEmpty()) return Collections.emptyMap(); + Map result = new HashMap(); int typeArgumentsSize = typeArguments.size(); @@ -73,26 +54,64 @@ public class FunctionDescriptorUtil { return result; } - @NotNull - public static JetType getSubstitutedReturnType(@NotNull FunctionDescriptor functionDescriptor, @NotNull List typeArguments) { - // TODO : Review, maybe duplicates LazySubstitutingFunctionDescriptor - return TypeSubstitutor.INSTANCE.substitute(createSubstitutionContext(functionDescriptor, typeArguments), functionDescriptor.getUnsubstitutedReturnType(), Variance.OUT_VARIANCE); + @Nullable + private static List getSubstitutedValueParameters(FunctionDescriptor substitutedDescriptor, @NotNull FunctionDescriptor functionDescriptor, Map substitutionContext, TypeSubstitutor typeSubstitutor) { + 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); + 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 substitutionContext, TypeSubstitutor typeSubstitutor) { + return typeSubstitutor.substitute(substitutionContext, functionDescriptor.getUnsubstitutedReturnType(), Variance.OUT_VARIANCE); + } + + @Nullable public static FunctionDescriptor substituteFunctionDescriptor(@NotNull List typeArguments, @NotNull FunctionDescriptor functionDescriptor) { - if (functionDescriptor.getTypeParameters().isEmpty()) { + Map substitutionContext = createSubstitutionContext(functionDescriptor, typeArguments); + return substituteFunctionDescriptor(functionDescriptor, substitutionContext, TypeSubstitutor.INSTANCE); + } + + @Nullable + public static FunctionDescriptor substituteFunctionDescriptor(FunctionDescriptor functionDescriptor, Map substitutionContext, TypeSubstitutor typeSubstitutor) { + if (substitutionContext.isEmpty()) { return functionDescriptor; } FunctionDescriptorImpl substitutedDescriptor = new FunctionDescriptorImpl( functionDescriptor, - // TODO : substitute + // TODO : safeSubstitute functionDescriptor.getAttributes(), functionDescriptor.getName()); + + List substitutedValueParameters = getSubstitutedValueParameters(substitutedDescriptor, functionDescriptor, substitutionContext, typeSubstitutor); + if (substitutedValueParameters == null) { + return null; + } + + JetType substitutedReturnType = getSubstitutedReturnType(functionDescriptor, substitutionContext, typeSubstitutor); + if (substitutedReturnType == null) { + return null; + } + substitutedDescriptor.initialize( Collections.emptyList(), // TODO : questionable - getSubstitutedValueParameters(substitutedDescriptor, functionDescriptor, typeArguments), - getSubstitutedReturnType(functionDescriptor, typeArguments) + substitutedValueParameters, + substitutedReturnType ); return substitutedDescriptor; } diff --git a/idea/src/org/jetbrains/jet/lang/types/JetStandardClasses.java b/idea/src/org/jetbrains/jet/lang/types/JetStandardClasses.java index 1e67287c008..67239a5cf63 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetStandardClasses.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetStandardClasses.java @@ -94,8 +94,7 @@ public class JetStandardClasses { parameters.add(new TypeParameterDescriptor( classDescriptor, Collections.emptyList(), - Variance.OUT_VARIANCE, "T" + j, - Collections.singleton(getNullableAnyType()))); + Variance.OUT_VARIANCE, "T" + j)); } TUPLE[i] = classDescriptor.initialize( true, @@ -132,8 +131,7 @@ public class JetStandardClasses { parameters.add(0, new TypeParameterDescriptor( receiverFunction, Collections.emptyList(), - Variance.IN_VARIANCE, "T", - Collections.singleton(getNullableAnyType()))); + Variance.IN_VARIANCE, "T")); RECEIVER_FUNCTION[i] = receiverFunction.initialize( false, parameters, @@ -147,14 +145,12 @@ public class JetStandardClasses { parameters.add(new TypeParameterDescriptor( function, Collections.emptyList(), - Variance.IN_VARIANCE, "P" + j, - Collections.singleton(getNullableAnyType()))); + Variance.IN_VARIANCE, "P" + j)); } parameters.add(new TypeParameterDescriptor( function, Collections.emptyList(), - Variance.OUT_VARIANCE, "R", - Collections.singleton(getNullableAnyType()))); + Variance.OUT_VARIANCE, "R")); return parameters; } diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java index bcd37da59f1..3e36cd86fe9 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java @@ -98,7 +98,7 @@ public class JetTypeChecker { } commonSupertypes = computeCommonRawSupertypes(merge); } - assert !commonSupertypes.isEmpty(); + assert !commonSupertypes.isEmpty() : commonSupertypes; Map.Entry> entry = commonSupertypes.entrySet().iterator().next(); JetType result = computeSupertypeProjections(entry.getKey(), entry.getValue()); @@ -274,13 +274,13 @@ public class JetTypeChecker { return; } handler.beforeChildren(current); - Map substitutionContext = TypeSubstitutor.INSTANCE.buildSubstitutionContext(current); + Map substitutionContext = TypeUtils.buildSubstitutionContext(current); for (JetType supertype : current.getConstructor().getSupertypes()) { TypeConstructor supertypeConstructor = supertype.getConstructor(); if (visited.contains(supertypeConstructor)) { continue; } - JetType substitutedSupertype = TypeSubstitutor.INSTANCE.substitute(substitutionContext, supertype, Variance.INVARIANT); + JetType substitutedSupertype = TypeSubstitutor.INSTANCE.safeSubstitute(substitutionContext, supertype, Variance.INVARIANT); dfs(substitutedSupertype, visited, handler); } handler.afterChildren(current); @@ -331,7 +331,7 @@ public class JetTypeChecker { for (JetType immediateSupertype : constructor.getSupertypes()) { JetType correspondingSupertype = findCorrespondingSupertype(immediateSupertype, supertype); if (correspondingSupertype != null) { - return TypeSubstitutor.INSTANCE.substitute(subtype, correspondingSupertype, Variance.INVARIANT); + return TypeSubstitutor.INSTANCE.safeSubstitute(subtype, correspondingSupertype, Variance.INVARIANT); } } return null; @@ -339,7 +339,7 @@ public class JetTypeChecker { private boolean checkSubtypeForTheSameConstructor(@NotNull JetType subtype, @NotNull JetType supertype) { TypeConstructor constructor = subtype.getConstructor(); - assert constructor.equals(supertype.getConstructor()); + assert constructor.equals(supertype.getConstructor()) : constructor + " is not " + supertype.getConstructor(); List subArguments = subtype.getArguments(); List superArguments = supertype.getArguments(); diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index 81c492f5f2e..6a971526b4b 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -499,10 +499,10 @@ public class JetTypeInferrer { JetUserType typeElement = (JetUserType) superTypeQualifier.getTypeElement(); ClassDescriptor superclass = typeResolver.resolveClass(scope, typeElement); Collection supertypes = thisType.getConstructor().getSupertypes(); - Map substitutionContext = TypeSubstitutor.INSTANCE.buildSubstitutionContext(thisType); + Map substitutionContext = TypeUtils.buildSubstitutionContext(thisType); for (JetType declaredSupertype : supertypes) { if (declaredSupertype.getConstructor().equals(superclass.getTypeConstructor())) { - result = TypeSubstitutor.INSTANCE.substitute(substitutionContext, declaredSupertype, Variance.INVARIANT); + result = TypeSubstitutor.INSTANCE.safeSubstitute(substitutionContext, declaredSupertype, Variance.INVARIANT); break; } } diff --git a/idea/src/org/jetbrains/jet/lang/types/LazySubstitutedPropertyDescriptorImpl.java b/idea/src/org/jetbrains/jet/lang/types/LazySubstitutedPropertyDescriptorImpl.java index e387454c1a4..57ef5254149 100644 --- a/idea/src/org/jetbrains/jet/lang/types/LazySubstitutedPropertyDescriptorImpl.java +++ b/idea/src/org/jetbrains/jet/lang/types/LazySubstitutedPropertyDescriptorImpl.java @@ -21,7 +21,7 @@ public class LazySubstitutedPropertyDescriptorImpl implements PropertyDescriptor @Override public JetType getType() { 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; } diff --git a/idea/src/org/jetbrains/jet/lang/types/LazySubstitutingFunctionDescriptor.java b/idea/src/org/jetbrains/jet/lang/types/LazySubstitutingFunctionDescriptor.java deleted file mode 100644 index 56cee728333..00000000000 --- a/idea/src/org/jetbrains/jet/lang/types/LazySubstitutingFunctionDescriptor.java +++ /dev/null @@ -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 substitutionContext; - private final FunctionDescriptor functionDescriptor; - - public LazySubstitutingFunctionDescriptor(Map substitutionContext, FunctionDescriptor functionDescriptor) { - this.substitutionContext = substitutionContext; - this.functionDescriptor = functionDescriptor; - } - - @NotNull - @Override - public List getTypeParameters() { - List result = new ArrayList(); - 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 getUnsubstitutedValueParameters() { - List result = new ArrayList(); - List 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 getAttributes() { - // TODO : Substitute? - return functionDescriptor.getAttributes(); - } - - @Override - public String getName() { - return functionDescriptor.getName(); - } - - @NotNull - @Override - public DeclarationDescriptor getContainingDeclaration() { - return functionDescriptor.getContainingDeclaration(); - } - - @Override - public R accept(DeclarationDescriptorVisitor visitor, D data) { - return visitor.visitFunctionDescriptor(this, data); - } - - @Override - public void acceptVoid(DeclarationDescriptorVisitor visitor) { - accept(visitor, null); - } -} - diff --git a/idea/src/org/jetbrains/jet/lang/types/LazySubstitutingFunctionGroup.java b/idea/src/org/jetbrains/jet/lang/types/LazySubstitutingFunctionGroup.java index e0a214d011e..326ea5311ea 100644 --- a/idea/src/org/jetbrains/jet/lang/types/LazySubstitutingFunctionGroup.java +++ b/idea/src/org/jetbrains/jet/lang/types/LazySubstitutingFunctionGroup.java @@ -1,6 +1,7 @@ package org.jetbrains.jet.lang.types; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.resolve.OverloadResolutionResult; import java.util.ArrayList; @@ -14,10 +15,16 @@ 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) { + 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); } @NotNull @@ -34,15 +41,27 @@ public class LazySubstitutingFunctionGroup implements FunctionGroup { Collection result = new ArrayList(); for (FunctionDescriptor function : resolutionResult.getFunctionDescriptors()) { - if (substitutionContext.isEmpty()) { - result.add(function); - } else { - result.add(new LazySubstitutingFunctionDescriptor(substitutionContext, function)); + FunctionDescriptor functionDescriptor = substitute(substitutionContext, function, typeSubstitutor); + if (functionDescriptor != null) { + result.add(functionDescriptor); } } return resolutionResult.newContents(result); } + @Nullable + public FunctionDescriptor substitute( + @NotNull Map 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 public boolean isEmpty() { return functionGroup.isEmpty(); diff --git a/idea/src/org/jetbrains/jet/lang/types/TypeParameterDescriptor.java b/idea/src/org/jetbrains/jet/lang/types/TypeParameterDescriptor.java index fc778a3670a..9a728880f93 100644 --- a/idea/src/org/jetbrains/jet/lang/types/TypeParameterDescriptor.java +++ b/idea/src/org/jetbrains/jet/lang/types/TypeParameterDescriptor.java @@ -13,8 +13,15 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl { private final Variance variance; private final Set upperBounds; private final TypeConstructor typeConstructor; + private final JetType boundsAsType; - public TypeParameterDescriptor(@NotNull DeclarationDescriptor containingDeclaration, List attributes, Variance variance, String name, Set upperBounds) { + public TypeParameterDescriptor( + @NotNull DeclarationDescriptor containingDeclaration, + @NotNull List attributes, + @NotNull Variance variance, + @NotNull String name, + @NotNull Set upperBounds, + @NotNull JetType boundsAsType) { super(containingDeclaration, attributes, name); this.variance = variance; this.upperBounds = upperBounds; @@ -26,10 +33,21 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl { "&" + name, Collections.emptyList(), upperBounds); + this.boundsAsType = boundsAsType; } - public TypeParameterDescriptor(@NotNull DeclarationDescriptor containingDeclaration, List attributes, Variance variance, String name) { - this(containingDeclaration, attributes, variance, name, Collections.singleton(JetStandardClasses.getNullableAnyType())); + public TypeParameterDescriptor( + @NotNull DeclarationDescriptor containingDeclaration, + @NotNull List attributes, + @NotNull Variance variance, + @NotNull String name) { + this( + containingDeclaration, + attributes, + variance, + name, + Collections.singleton(JetStandardClasses.getNullableAnyType()), + JetStandardClasses.getNullableAnyType()); } public Variance getVariance() { @@ -49,6 +67,11 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl { return typeConstructor.toString(); } + @NotNull + public JetType getBoundsAsType() { + return boundsAsType; + } + @Override public R accept(DeclarationDescriptorVisitor visitor, D data) { return visitor.visitTypeParameterDescriptor(this, data); diff --git a/idea/src/org/jetbrains/jet/lang/types/TypeSubstitutor.java b/idea/src/org/jetbrains/jet/lang/types/TypeSubstitutor.java index e4756accb07..067885681a2 100644 --- a/idea/src/org/jetbrains/jet/lang/types/TypeSubstitutor.java +++ b/idea/src/org/jetbrains/jet/lang/types/TypeSubstitutor.java @@ -1,6 +1,7 @@ package org.jetbrains.jet.lang.types; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.resolve.SubstitutingScope; import java.util.*; @@ -9,75 +10,135 @@ import java.util.*; * @author abreslav */ 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_FOR_CONSTRUCTORS = new TypeSubstitutor() { + @Override + protected boolean errorCondition(Variance ve, Variance p1) { + return false; + } + }; + private TypeSubstitutor() {} - public JetType substitute(@NotNull JetType context, @NotNull JetType subject, @NotNull Variance howThisTypeIsUsed) { - return substitute(buildSubstitutionContext(context), subject, howThisTypeIsUsed); + public JetType safeSubstitute(@NotNull JetType context, @NotNull JetType subject, @NotNull Variance howThisTypeIsUsed) { + return safeSubstitute(TypeUtils.buildSubstitutionContext(context), subject, howThisTypeIsUsed); } @NotNull + public JetType safeSubstitute(@NotNull Map 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 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 substitutionContext, @NotNull JetType type, @NotNull Variance howThisTypeIsUsed) throws SubstitutionException { + TypeConstructor constructor = type.getConstructor(); + TypeProjection value = substitutionContext.get(constructor); if (value != null) { - Variance projectionKind = value.getProjectionKind(); - if (howThisTypeIsUsed.allowsInPosition() && !projectionKind.allowsInPosition() - || howThisTypeIsUsed.allowsOutPosition() && !projectionKind.allowsOutPosition()) { - return ErrorType.createWrongVarianceErrorType(value); + assert constructor.getDeclarationDescriptor() instanceof TypeParameterDescriptor; + + if (errorCondition(howThisTypeIsUsed, value.getProjectionKind())) { + throw new SubstitutionException("!!" + value.toString()); } return value.getType(); } - return specializeType(type, substitutionContext); + return specializeType(type, substitutionContext, howThisTypeIsUsed); } - private JetType specializeType(JetType subjectType, Map substitutionContext) { + private JetType specializeType(JetType subjectType, Map substitutionContext, Variance callSiteVariance) throws SubstitutionException { + List newArguments = new ArrayList(); + List 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( subjectType.getAttributes(), subjectType.getConstructor(), subjectType.isNullable(), - substituteInArguments(substitutionContext, subjectType), + newArguments, new SubstitutingScope(subjectType.getMemberScope(), substitutionContext)); } - private List substituteInArguments(Map substitutionContext, JetType subjectType) { - List newArguments = new ArrayList(); - for (TypeProjection argument : subjectType.getArguments()) { - newArguments.add(substituteInProjection(substitutionContext, argument)); + @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(); + + 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 - private TypeProjection substituteInProjection(Map substitutionContext, TypeProjection subject) { - JetType subjectType = subject.getType(); - TypeProjection value = substitutionContext.get(subjectType.getConstructor()); - if (value != null) { - return value; - } - return new TypeProjection(subject.getProjectionKind(), specializeType(subjectType, substitutionContext)); + 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(substitute(substitutionContext, type, howTheseTypesWillBeUsed)); + result.add(safeSubstitute(substitutionContext, type, howTheseTypesWillBeUsed)); } return result; } - public Map buildSubstitutionContext(JetType context) { - return buildSubstitutionContext(context.getConstructor().getParameters(), context.getArguments()); - } - - public Map buildSubstitutionContext(List parameters, List contextArguments) { - Map parameterValues = new HashMap(); - 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); + private boolean allows(Variance declarationSiteVariance, Variance callSiteVariance) { + switch (declarationSiteVariance) { + case INVARIANT: return true; + case IN_VARIANCE: return callSiteVariance != Variance.OUT_VARIANCE; + case OUT_VARIANCE: return callSiteVariance != Variance.IN_VARIANCE; } - return parameterValues; + throw new IllegalStateException(declarationSiteVariance.toString()); } } diff --git a/idea/src/org/jetbrains/jet/lang/types/TypeUtils.java b/idea/src/org/jetbrains/jet/lang/types/TypeUtils.java index 03999b9ffeb..f0b75e08185 100644 --- a/idea/src/org/jetbrains/jet/lang/types/TypeUtils.java +++ b/idea/src/org/jetbrains/jet/lang/types/TypeUtils.java @@ -147,14 +147,14 @@ public class TypeUtils { } @NotNull - public static JetType makeUnsubstitutedType(ClassDescriptor classDescriptor) { + public static JetType makeUnsubstitutedType(ClassDescriptor classDescriptor, JetScope unsubstitutedMemberScope) { List arguments = getArguments(classDescriptor); return new JetTypeImpl( Collections.emptyList(), classDescriptor.getTypeConstructor(), false, arguments, - classDescriptor.getMemberScope(arguments) + unsubstitutedMemberScope ); } @@ -166,4 +166,25 @@ public class TypeUtils { } return result; } + + @NotNull + public static Map buildSubstitutionContext(@NotNull JetType context) { + return buildSubstitutionContext(context.getConstructor().getParameters(), context.getArguments()); + } + + @NotNull + public static Map buildSubstitutionContext(@NotNull List parameters, @NotNull List contextArguments) { + Map parameterValues = new HashMap(); + 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()); + } } diff --git a/idea/src/org/jetbrains/jet/lang/types/Variance.java b/idea/src/org/jetbrains/jet/lang/types/Variance.java index 0cfdc6b406d..4f1cdd3f281 100644 --- a/idea/src/org/jetbrains/jet/lang/types/Variance.java +++ b/idea/src/org/jetbrains/jet/lang/types/Variance.java @@ -4,18 +4,20 @@ package org.jetbrains.jet.lang.types; * @author max */ public enum Variance { - INVARIANT("", true, true), - IN_VARIANCE("in", true, false), - OUT_VARIANCE("out", false, true); + INVARIANT("", true, true, 0), + IN_VARIANCE("in", true, false, -1), + OUT_VARIANCE("out", false, true, +1); private final String label; private final boolean allowsInPosition; 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.allowsInPosition = allowsInPosition; this.allowsOutPosition = allowsOutPosition; + this.superpositionFactor = superpositionFactor; } public boolean allowsInPosition() { @@ -26,6 +28,16 @@ public enum Variance { 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 public String toString() { return label; diff --git a/idea/testData/resolve/Projections.jet b/idea/testData/resolve/Projections.jet new file mode 100644 index 00000000000..33b8b071452 --- /dev/null +++ b/idea/testData/resolve/Projections.jet @@ -0,0 +1,56 @@ +class In { + ~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.f~fun f() : T {} + ~Out.f(a)~fun f(a : Int) : Int {a} +} + +class Inv { + ~Inv.f~fun f(t : T) : T {t} + ~Inv.inf~fun inf(t : T) : Unit {} + ~Inv.outf~fun outf() : T {} +} + +fun testInOut() { + new In().`In.f:T->Unit`f("1"); + new In().`In.f:T->Unit`f("1"); + new In().`!`f("1") + new In<*>().`!`f("1"); + + new In().`In.f:Int->Int`f(1); + new In().`In.f:Int->Int`f(1); + new In().`In.f:Int->Int`f(1) + new In().`!`f1(1) + new In<*>().`In.f:Int->Int`f(1); + + new Out().`Out.f(a)`f(1) + new Out().`Out.f(a)`f(1) + new Out().`Out.f(a)`f(1) + new Out<*>().`Out.f(a)`f(1) + + new Out().`Out.f`f() + new Out().`Out.f`f() + new Out().`!`f() + new Out<*>().`Out.f`f() + + new Inv().`Inv.f`f(1) + new Inv().`!`f(1) + new Inv().`!`f(1) + new Inv<*>().`!`f(1) + + new Inv().`Inv.inf`inf(1) + new Inv().`Inv.inf`inf(1) + new Inv().`!`inf(1) + new Inv<*>().`!`inf(1) + + new Inv().`Inv.outf`outf() + new Inv().`!`outf() + new Inv().`Inv.outf`outf() + new Inv<*>().`Inv.outf`outf() + + new Inv().`Inv.outf`outf(1) +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/resolve/JetResolveTest.java b/idea/tests/org/jetbrains/jet/resolve/JetResolveTest.java index 12e201e18c5..13b7adcd82f 100644 --- a/idea/tests/org/jetbrains/jet/resolve/JetResolveTest.java +++ b/idea/tests/org/jetbrains/jet/resolve/JetResolveTest.java @@ -142,4 +142,8 @@ public class JetResolveTest extends ExtensibleResolveTestCase { doTest("/resolve/ResolveOfInfixExpressions.jet", true, true); } + public void testProjections() throws Exception { + doTest("/resolve/Projections.jet", true, true); + } + } \ No newline at end of file