Scope filtering according to type projections supported

This commit is contained in:
Andrey Breslav
2011-03-22 21:06:52 +03:00
parent 1ed0c11ce2
commit e6b0a64b14
23 changed files with 357 additions and 218 deletions
+1
View File
@@ -3,6 +3,7 @@
<words> <words>
<w>inferrer</w> <w>inferrer</w>
<w>nullable</w> <w>nullable</w>
<w>substitutor</w>
<w>subtyping</w> <w>subtyping</w>
<w>supertype</w> <w>supertype</w>
<w>supertypes</w> <w>supertypes</w>
@@ -7,10 +7,7 @@ import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.lexer.JetTokens;
import java.util.ArrayList; import java.util.*;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/** /**
* @author abreslav * @author abreslav
@@ -222,7 +219,7 @@ public class ClassDescriptorResolver {
} }
public List<TypeParameterDescriptor> resolveTypeParameters(DeclarationDescriptor containingDescriptor, WritableScope extensibleScope, List<JetTypeParameter> typeParameters) { public List<TypeParameterDescriptor> resolveTypeParameters(DeclarationDescriptor containingDescriptor, WritableScope extensibleScope, List<JetTypeParameter> typeParameters) {
// TODO : When-clause // TODO : Where-clause
List<TypeParameterDescriptor> result = new ArrayList<TypeParameterDescriptor>(); List<TypeParameterDescriptor> result = new ArrayList<TypeParameterDescriptor>();
for (JetTypeParameter typeParameter : typeParameters) { for (JetTypeParameter typeParameter : typeParameters) {
result.add(resolveTypeParameter(containingDescriptor, extensibleScope, typeParameter)); result.add(resolveTypeParameter(containingDescriptor, extensibleScope, typeParameter));
@@ -231,15 +228,18 @@ public class ClassDescriptorResolver {
} }
private TypeParameterDescriptor resolveTypeParameter(DeclarationDescriptor containingDescriptor, WritableScope extensibleScope, JetTypeParameter typeParameter) { private TypeParameterDescriptor resolveTypeParameter(DeclarationDescriptor containingDescriptor, WritableScope extensibleScope, JetTypeParameter typeParameter) {
// TODO: other bounds from where-clause
JetTypeReference extendsBound = typeParameter.getExtendsBound(); JetTypeReference extendsBound = typeParameter.getExtendsBound();
JetType bound = extendsBound == null
? JetStandardClasses.getDefaultBound()
: typeResolver.resolveType(extensibleScope, extendsBound);
TypeParameterDescriptor typeParameterDescriptor = new TypeParameterDescriptor( TypeParameterDescriptor typeParameterDescriptor = new TypeParameterDescriptor(
containingDescriptor, containingDescriptor,
AttributeResolver.INSTANCE.resolveAttributes(typeParameter.getModifierList()), AttributeResolver.INSTANCE.resolveAttributes(typeParameter.getModifierList()),
typeParameter.getVariance(), typeParameter.getVariance(),
typeParameter.getName(), typeParameter.getName(),
extendsBound == null Collections.singleton(bound),
? Collections.<JetType>singleton(JetStandardClasses.getDefaultBound()) bound
: Collections.singleton(typeResolver.resolveType(extensibleScope, extendsBound))
); );
extensibleScope.addTypeParameterDescriptor(typeParameterDescriptor); extensibleScope.addTypeParameterDescriptor(typeParameterDescriptor);
trace.recordDeclarationResolution(typeParameter, typeParameterDescriptor); trace.recordDeclarationResolution(typeParameter, typeParameterDescriptor);
@@ -38,6 +38,12 @@ public class LazySubstitutingClassDescriptor implements ClassDescriptor {
return new SubstitutingScope(memberScope, substitutionContext); return new SubstitutingScope(memberScope, substitutionContext);
} }
@NotNull
@Override
public JetType getDefaultType() {
throw new UnsupportedOperationException(); // TODO
}
@NotNull @NotNull
@Override @Override
public FunctionGroup getConstructors(List<TypeProjection> typeArguments) { public FunctionGroup getConstructors(List<TypeProjection> typeArguments) {
@@ -35,10 +35,16 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme
@Override @Override
public JetScope getMemberScope(List<TypeProjection> typeArguments) { public JetScope getMemberScope(List<TypeProjection> typeArguments) {
List<TypeParameterDescriptor> typeParameters = getTypeConstructor().getParameters(); List<TypeParameterDescriptor> typeParameters = getTypeConstructor().getParameters();
Map<TypeConstructor,TypeProjection> substitutionContext = TypeSubstitutor.INSTANCE.buildSubstitutionContext(typeParameters, typeArguments); Map<TypeConstructor,TypeProjection> substitutionContext = TypeUtils.buildSubstitutionContext(typeParameters, typeArguments);
return new SubstitutingScope(unsubstitutedMemberScope, substitutionContext); return new SubstitutingScope(unsubstitutedMemberScope, substitutionContext);
} }
@NotNull
@Override
public JetType getDefaultType() {
return TypeUtils.makeUnsubstitutedType(this, unsubstitutedMemberScope);
}
public void addConstructor(@NotNull ConstructorDescriptor constructorDescriptor) { public void addConstructor(@NotNull ConstructorDescriptor constructorDescriptor) {
assert constructorDescriptor.getContainingDeclaration() == this; assert constructorDescriptor.getContainingDeclaration() == this;
constructors.addFunction(constructorDescriptor); constructors.addFunction(constructorDescriptor);
@@ -49,11 +55,12 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme
public FunctionGroup getConstructors(List<TypeProjection> typeArguments) { public FunctionGroup getConstructors(List<TypeProjection> typeArguments) {
// TODO : Duplicates ClassDescriptorImpl // TODO : Duplicates ClassDescriptorImpl
assert typeArguments.size() == getTypeConstructor().getParameters().size(); assert typeArguments.size() == getTypeConstructor().getParameters().size();
if (typeArguments.size() == 0) { if (typeArguments.size() == 0) {
return constructors; return constructors;
} }
Map<TypeConstructor, TypeProjection> substitutionContext = TypeSubstitutor.INSTANCE.buildSubstitutionContext(getTypeConstructor().getParameters(), typeArguments); Map<TypeConstructor, TypeProjection> substitutionContext = TypeUtils.buildSubstitutionContext(getTypeConstructor().getParameters(), typeArguments);
return new LazySubstitutingFunctionGroup(substitutionContext, constructors); return new LazySubstitutingFunctionGroup(substitutionContext, constructors, TypeSubstitutor.INSTANCE_FOR_CONSTRUCTORS);
} }
@NotNull @NotNull
@@ -9,7 +9,6 @@ import org.jetbrains.jet.lang.types.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Set;
/** /**
* @author abreslav * @author abreslav
@@ -148,8 +147,8 @@ public class TypeResolver {
JetProjectionKind projectionKind = argumentElement.getProjectionKind(); JetProjectionKind projectionKind = argumentElement.getProjectionKind();
JetType type; JetType type;
if (projectionKind == JetProjectionKind.STAR) { if (projectionKind == JetProjectionKind.STAR) {
Set<JetType> upperBounds = constructor.getParameters().get(i).getUpperBounds(); TypeParameterDescriptor parameterDescriptor = constructor.getParameters().get(i);
arguments.add(new TypeProjection(Variance.OUT_VARIANCE, TypeUtils.intersect(semanticServices.getTypeChecker(), upperBounds))); arguments.add(TypeUtils.makeStarProjection(parameterDescriptor));
} }
else { else {
// TODO : handle the Foo<in *> case // TODO : handle the Foo<in *> case
@@ -59,7 +59,9 @@ public class WritableFunctionGroup implements FunctionGroup {
if (functionDescriptor.getTypeParameters().size() == typeArgCount) { if (functionDescriptor.getTypeParameters().size() == typeArgCount) {
if (FunctionDescriptorUtil.getMinimumArity(functionDescriptor) <= valueArgCount && if (FunctionDescriptorUtil.getMinimumArity(functionDescriptor) <= valueArgCount &&
valueArgCount <= FunctionDescriptorUtil.getMaximumArity(functionDescriptor)) { valueArgCount <= FunctionDescriptorUtil.getMaximumArity(functionDescriptor)) {
result.add(FunctionDescriptorUtil.substituteFunctionDescriptor(typeArguments, functionDescriptor)); FunctionDescriptor substitutedFunctionDescriptor = FunctionDescriptorUtil.substituteFunctionDescriptor(typeArguments, functionDescriptor);
assert substitutedFunctionDescriptor != null;
result.add(substitutedFunctionDescriptor);
} }
} }
} }
@@ -21,4 +21,10 @@ public interface ClassDescriptor extends DeclarationDescriptor {
@Override @Override
@NotNull @NotNull
DeclarationDescriptor getContainingDeclaration(); DeclarationDescriptor getContainingDeclaration();
/**
* @return type A&lt;T&gt; for the class A&lt;T&gt;
*/
@NotNull
JetType getDefaultType();
} }
@@ -24,13 +24,6 @@ public class ClassDescriptorImpl extends DeclarationDescriptorImpl implements Cl
super(containingDeclaration, attributes, name); super(containingDeclaration, attributes, name);
} }
// public ClassDescriptorImpl(@NotNull DeclarationDescriptor containingDeclaration, String name, JetScope memberDeclarations) {
// this(containingDeclaration, Collections.<Attribute>emptyList(), name);
// this.initialize(Collections.<Attribute>emptyList(), true,
// name, Collections.<TypeParameterDescriptor>emptyList(),
// Collections.<Type>singleton(JetStandardClasses.getAnyType()), memberDeclarations);
// }
//
public final ClassDescriptorImpl initialize(boolean sealed, public final ClassDescriptorImpl initialize(boolean sealed,
@NotNull List<TypeParameterDescriptor> typeParameters, @NotNull List<TypeParameterDescriptor> typeParameters,
@NotNull Collection<? extends JetType> superclasses, @NotNull Collection<? extends JetType> superclasses,
@@ -55,10 +48,16 @@ public class ClassDescriptorImpl extends DeclarationDescriptorImpl implements Cl
if (typeConstructor.getParameters().isEmpty()) { if (typeConstructor.getParameters().isEmpty()) {
return memberDeclarations; return memberDeclarations;
} }
Map<TypeConstructor, TypeProjection> substitutionContext = TypeSubstitutor.INSTANCE.buildSubstitutionContext(typeConstructor.getParameters(), typeArguments); Map<TypeConstructor, TypeProjection> substitutionContext = TypeUtils.buildSubstitutionContext(typeConstructor.getParameters(), typeArguments);
return new SubstitutingScope(memberDeclarations, substitutionContext); return new SubstitutingScope(memberDeclarations, substitutionContext);
} }
@NotNull
@Override
public JetType getDefaultType() {
return TypeUtils.makeUnsubstitutedType(this, memberDeclarations);
}
@NotNull @NotNull
@Override @Override
public FunctionGroup getConstructors(List<TypeProjection> typeArguments) { public FunctionGroup getConstructors(List<TypeProjection> typeArguments) {
@@ -66,8 +65,8 @@ public class ClassDescriptorImpl extends DeclarationDescriptorImpl implements Cl
if (typeArguments.size() == 0) { if (typeArguments.size() == 0) {
return constructors; return constructors;
} }
Map<TypeConstructor, TypeProjection> substitutionContext = TypeSubstitutor.INSTANCE.buildSubstitutionContext(getTypeConstructor().getParameters(), typeArguments); Map<TypeConstructor, TypeProjection> substitutionContext = TypeUtils.buildSubstitutionContext(getTypeConstructor().getParameters(), typeArguments);
return new LazySubstitutingFunctionGroup(substitutionContext, constructors); return new LazySubstitutingFunctionGroup(substitutionContext, constructors, TypeSubstitutor.INSTANCE_FOR_CONSTRUCTORS);
} }
@Override @Override
@@ -64,6 +64,6 @@ public class ConstructorDescriptorImpl extends FunctionDescriptorImpl implements
@NotNull @NotNull
@Override @Override
public JetType getUnsubstitutedReturnType() { public JetType getUnsubstitutedReturnType() {
return TypeUtils.makeUnsubstitutedType(getContainingDeclaration()); return getContainingDeclaration().getDefaultType();
} }
} }
@@ -179,6 +179,10 @@ public class ErrorType {
return Collections.emptyList(); return Collections.emptyList();
} }
@Override
public String toString() {
return constructor.toString();
}
} }
private ErrorType() {} private ErrorType() {}
@@ -1,6 +1,7 @@
package org.jetbrains.jet.lang.types; package org.jetbrains.jet.lang.types;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*; import java.util.*;
@@ -37,29 +38,9 @@ public class FunctionDescriptorUtil {
return unsubstitutedValueParameters.size(); return unsubstitutedValueParameters.size();
} }
@NotNull
public static List<ValueParameterDescriptor> getSubstitutedValueParameters(FunctionDescriptor substitutedDescriptor, @NotNull FunctionDescriptor functionDescriptor, @NotNull List<JetType> typeArguments) {
// TODO : Review, maybe duplicates LazySubstitutingFunctionDescriptor
List<ValueParameterDescriptor> result = new ArrayList<ValueParameterDescriptor>();
Map<TypeConstructor, TypeProjection> context = createSubstitutionContext(functionDescriptor, typeArguments);
List<ValueParameterDescriptor> 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<TypeConstructor, TypeProjection> createSubstitutionContext(@NotNull FunctionDescriptor functionDescriptor, List<JetType> typeArguments) { private static Map<TypeConstructor, TypeProjection> createSubstitutionContext(@NotNull FunctionDescriptor functionDescriptor, List<JetType> typeArguments) {
if (functionDescriptor.getTypeParameters().isEmpty()) return Collections.emptyMap();
Map<TypeConstructor, TypeProjection> result = new HashMap<TypeConstructor, TypeProjection>(); Map<TypeConstructor, TypeProjection> result = new HashMap<TypeConstructor, TypeProjection>();
int typeArgumentsSize = typeArguments.size(); int typeArgumentsSize = typeArguments.size();
@@ -73,26 +54,64 @@ public class FunctionDescriptorUtil {
return result; return result;
} }
@NotNull @Nullable
public static JetType getSubstitutedReturnType(@NotNull FunctionDescriptor functionDescriptor, @NotNull List<JetType> typeArguments) { private static List<ValueParameterDescriptor> getSubstitutedValueParameters(FunctionDescriptor substitutedDescriptor, @NotNull FunctionDescriptor functionDescriptor, Map<TypeConstructor, TypeProjection> substitutionContext, TypeSubstitutor typeSubstitutor) {
// TODO : Review, maybe duplicates LazySubstitutingFunctionDescriptor List<ValueParameterDescriptor> result = new ArrayList<ValueParameterDescriptor>();
return TypeSubstitutor.INSTANCE.substitute(createSubstitutionContext(functionDescriptor, typeArguments), functionDescriptor.getUnsubstitutedReturnType(), Variance.OUT_VARIANCE); 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);
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<TypeConstructor, TypeProjection> substitutionContext, TypeSubstitutor typeSubstitutor) {
return typeSubstitutor.substitute(substitutionContext, functionDescriptor.getUnsubstitutedReturnType(), Variance.OUT_VARIANCE);
}
@Nullable
public static FunctionDescriptor substituteFunctionDescriptor(@NotNull List<JetType> typeArguments, @NotNull FunctionDescriptor functionDescriptor) { public static FunctionDescriptor substituteFunctionDescriptor(@NotNull List<JetType> typeArguments, @NotNull FunctionDescriptor functionDescriptor) {
if (functionDescriptor.getTypeParameters().isEmpty()) { Map<TypeConstructor, TypeProjection> substitutionContext = createSubstitutionContext(functionDescriptor, typeArguments);
return substituteFunctionDescriptor(functionDescriptor, substitutionContext, TypeSubstitutor.INSTANCE);
}
@Nullable
public static FunctionDescriptor substituteFunctionDescriptor(FunctionDescriptor functionDescriptor, Map<TypeConstructor, TypeProjection> substitutionContext, TypeSubstitutor typeSubstitutor) {
if (substitutionContext.isEmpty()) {
return functionDescriptor; return functionDescriptor;
} }
FunctionDescriptorImpl substitutedDescriptor = new FunctionDescriptorImpl( FunctionDescriptorImpl substitutedDescriptor = new FunctionDescriptorImpl(
functionDescriptor, functionDescriptor,
// TODO : substitute // TODO : safeSubstitute
functionDescriptor.getAttributes(), functionDescriptor.getAttributes(),
functionDescriptor.getName()); functionDescriptor.getName());
List<ValueParameterDescriptor> substitutedValueParameters = getSubstitutedValueParameters(substitutedDescriptor, functionDescriptor, substitutionContext, typeSubstitutor);
if (substitutedValueParameters == null) {
return null;
}
JetType substitutedReturnType = getSubstitutedReturnType(functionDescriptor, substitutionContext, typeSubstitutor);
if (substitutedReturnType == null) {
return null;
}
substitutedDescriptor.initialize( substitutedDescriptor.initialize(
Collections.<TypeParameterDescriptor>emptyList(), // TODO : questionable Collections.<TypeParameterDescriptor>emptyList(), // TODO : questionable
getSubstitutedValueParameters(substitutedDescriptor, functionDescriptor, typeArguments), substitutedValueParameters,
getSubstitutedReturnType(functionDescriptor, typeArguments) substitutedReturnType
); );
return substitutedDescriptor; return substitutedDescriptor;
} }
@@ -94,8 +94,7 @@ public class JetStandardClasses {
parameters.add(new TypeParameterDescriptor( parameters.add(new TypeParameterDescriptor(
classDescriptor, classDescriptor,
Collections.<Attribute>emptyList(), Collections.<Attribute>emptyList(),
Variance.OUT_VARIANCE, "T" + j, Variance.OUT_VARIANCE, "T" + j));
Collections.singleton(getNullableAnyType())));
} }
TUPLE[i] = classDescriptor.initialize( TUPLE[i] = classDescriptor.initialize(
true, true,
@@ -132,8 +131,7 @@ public class JetStandardClasses {
parameters.add(0, new TypeParameterDescriptor( parameters.add(0, new TypeParameterDescriptor(
receiverFunction, receiverFunction,
Collections.<Attribute>emptyList(), Collections.<Attribute>emptyList(),
Variance.IN_VARIANCE, "T", Variance.IN_VARIANCE, "T"));
Collections.singleton(getNullableAnyType())));
RECEIVER_FUNCTION[i] = receiverFunction.initialize( RECEIVER_FUNCTION[i] = receiverFunction.initialize(
false, false,
parameters, parameters,
@@ -147,14 +145,12 @@ public class JetStandardClasses {
parameters.add(new TypeParameterDescriptor( parameters.add(new TypeParameterDescriptor(
function, function,
Collections.<Attribute>emptyList(), Collections.<Attribute>emptyList(),
Variance.IN_VARIANCE, "P" + j, Variance.IN_VARIANCE, "P" + j));
Collections.singleton(getNullableAnyType())));
} }
parameters.add(new TypeParameterDescriptor( parameters.add(new TypeParameterDescriptor(
function, function,
Collections.<Attribute>emptyList(), Collections.<Attribute>emptyList(),
Variance.OUT_VARIANCE, "R", Variance.OUT_VARIANCE, "R"));
Collections.singleton(getNullableAnyType())));
return parameters; return parameters;
} }
@@ -98,7 +98,7 @@ public class JetTypeChecker {
} }
commonSupertypes = computeCommonRawSupertypes(merge); commonSupertypes = computeCommonRawSupertypes(merge);
} }
assert !commonSupertypes.isEmpty(); assert !commonSupertypes.isEmpty() : commonSupertypes;
Map.Entry<TypeConstructor, Set<JetType>> entry = commonSupertypes.entrySet().iterator().next(); Map.Entry<TypeConstructor, Set<JetType>> entry = commonSupertypes.entrySet().iterator().next();
JetType result = computeSupertypeProjections(entry.getKey(), entry.getValue()); JetType result = computeSupertypeProjections(entry.getKey(), entry.getValue());
@@ -274,13 +274,13 @@ public class JetTypeChecker {
return; return;
} }
handler.beforeChildren(current); handler.beforeChildren(current);
Map<TypeConstructor, TypeProjection> substitutionContext = TypeSubstitutor.INSTANCE.buildSubstitutionContext(current); Map<TypeConstructor, TypeProjection> substitutionContext = TypeUtils.buildSubstitutionContext(current);
for (JetType supertype : current.getConstructor().getSupertypes()) { for (JetType supertype : current.getConstructor().getSupertypes()) {
TypeConstructor supertypeConstructor = supertype.getConstructor(); TypeConstructor supertypeConstructor = supertype.getConstructor();
if (visited.contains(supertypeConstructor)) { if (visited.contains(supertypeConstructor)) {
continue; continue;
} }
JetType substitutedSupertype = TypeSubstitutor.INSTANCE.substitute(substitutionContext, supertype, Variance.INVARIANT); JetType substitutedSupertype = TypeSubstitutor.INSTANCE.safeSubstitute(substitutionContext, supertype, Variance.INVARIANT);
dfs(substitutedSupertype, visited, handler); dfs(substitutedSupertype, visited, handler);
} }
handler.afterChildren(current); handler.afterChildren(current);
@@ -331,7 +331,7 @@ public class JetTypeChecker {
for (JetType immediateSupertype : constructor.getSupertypes()) { for (JetType immediateSupertype : constructor.getSupertypes()) {
JetType correspondingSupertype = findCorrespondingSupertype(immediateSupertype, supertype); JetType correspondingSupertype = findCorrespondingSupertype(immediateSupertype, supertype);
if (correspondingSupertype != null) { if (correspondingSupertype != null) {
return TypeSubstitutor.INSTANCE.substitute(subtype, correspondingSupertype, Variance.INVARIANT); return TypeSubstitutor.INSTANCE.safeSubstitute(subtype, correspondingSupertype, Variance.INVARIANT);
} }
} }
return null; return null;
@@ -339,7 +339,7 @@ public class JetTypeChecker {
private boolean checkSubtypeForTheSameConstructor(@NotNull JetType subtype, @NotNull JetType supertype) { private boolean checkSubtypeForTheSameConstructor(@NotNull JetType subtype, @NotNull JetType supertype) {
TypeConstructor constructor = subtype.getConstructor(); TypeConstructor constructor = subtype.getConstructor();
assert constructor.equals(supertype.getConstructor()); assert constructor.equals(supertype.getConstructor()) : constructor + " is not " + supertype.getConstructor();
List<TypeProjection> subArguments = subtype.getArguments(); List<TypeProjection> subArguments = subtype.getArguments();
List<TypeProjection> superArguments = supertype.getArguments(); List<TypeProjection> superArguments = supertype.getArguments();
@@ -499,10 +499,10 @@ public class JetTypeInferrer {
JetUserType typeElement = (JetUserType) superTypeQualifier.getTypeElement(); JetUserType typeElement = (JetUserType) superTypeQualifier.getTypeElement();
ClassDescriptor superclass = typeResolver.resolveClass(scope, typeElement); ClassDescriptor superclass = typeResolver.resolveClass(scope, typeElement);
Collection<? extends JetType> supertypes = thisType.getConstructor().getSupertypes(); Collection<? extends JetType> supertypes = thisType.getConstructor().getSupertypes();
Map<TypeConstructor, TypeProjection> substitutionContext = TypeSubstitutor.INSTANCE.buildSubstitutionContext(thisType); Map<TypeConstructor, TypeProjection> substitutionContext = TypeUtils.buildSubstitutionContext(thisType);
for (JetType declaredSupertype : supertypes) { for (JetType declaredSupertype : supertypes) {
if (declaredSupertype.getConstructor().equals(superclass.getTypeConstructor())) { if (declaredSupertype.getConstructor().equals(superclass.getTypeConstructor())) {
result = TypeSubstitutor.INSTANCE.substitute(substitutionContext, declaredSupertype, Variance.INVARIANT); result = TypeSubstitutor.INSTANCE.safeSubstitute(substitutionContext, declaredSupertype, Variance.INVARIANT);
break; break;
} }
} }
@@ -21,7 +21,7 @@ public class LazySubstitutedPropertyDescriptorImpl implements PropertyDescriptor
@Override @Override
public JetType getType() { public JetType getType() {
if (propertyType == null) { 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; return propertyType;
} }
@@ -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<TypeConstructor, TypeProjection> substitutionContext;
private final FunctionDescriptor functionDescriptor;
public LazySubstitutingFunctionDescriptor(Map<TypeConstructor, TypeProjection> substitutionContext, FunctionDescriptor functionDescriptor) {
this.substitutionContext = substitutionContext;
this.functionDescriptor = functionDescriptor;
}
@NotNull
@Override
public List<TypeParameterDescriptor> getTypeParameters() {
List<TypeParameterDescriptor> result = new ArrayList<TypeParameterDescriptor>();
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<ValueParameterDescriptor> getUnsubstitutedValueParameters() {
List<ValueParameterDescriptor> result = new ArrayList<ValueParameterDescriptor>();
List<ValueParameterDescriptor> 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<Attribute> getAttributes() {
// TODO : Substitute?
return functionDescriptor.getAttributes();
}
@Override
public String getName() {
return functionDescriptor.getName();
}
@NotNull
@Override
public DeclarationDescriptor getContainingDeclaration() {
return functionDescriptor.getContainingDeclaration();
}
@Override
public <R, D> R accept(DeclarationDescriptorVisitor<R, D> visitor, D data) {
return visitor.visitFunctionDescriptor(this, data);
}
@Override
public void acceptVoid(DeclarationDescriptorVisitor<Void, Void> visitor) {
accept(visitor, null);
}
}
@@ -1,6 +1,7 @@
package org.jetbrains.jet.lang.types; package org.jetbrains.jet.lang.types;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.resolve.OverloadResolutionResult; import org.jetbrains.jet.lang.resolve.OverloadResolutionResult;
import java.util.ArrayList; import java.util.ArrayList;
@@ -14,10 +15,16 @@ 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) { public LazySubstitutingFunctionGroup(Map<TypeConstructor, TypeProjection> substitutionContext, FunctionGroup functionGroup, TypeSubstitutor typeSubstitutor) {
this.substitutionContext = substitutionContext; this.substitutionContext = substitutionContext;
this.functionGroup = functionGroup; this.functionGroup = functionGroup;
this.typeSubstitutor = typeSubstitutor;
}
public LazySubstitutingFunctionGroup(Map<TypeConstructor, TypeProjection> substitutionContext, FunctionGroup functionGroup) {
this(substitutionContext, functionGroup, TypeSubstitutor.INSTANCE);
} }
@NotNull @NotNull
@@ -34,15 +41,27 @@ 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()) {
if (substitutionContext.isEmpty()) { FunctionDescriptor functionDescriptor = substitute(substitutionContext, function, typeSubstitutor);
result.add(function); if (functionDescriptor != null) {
} else { result.add(functionDescriptor);
result.add(new LazySubstitutingFunctionDescriptor(substitutionContext, function));
} }
} }
return resolutionResult.newContents(result); return resolutionResult.newContents(result);
} }
@Nullable
public FunctionDescriptor substitute(
@NotNull Map<TypeConstructor, TypeProjection> 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 @Override
public boolean isEmpty() { public boolean isEmpty() {
return functionGroup.isEmpty(); return functionGroup.isEmpty();
@@ -13,8 +13,15 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl {
private final Variance variance; private final Variance variance;
private final Set<JetType> upperBounds; private final Set<JetType> upperBounds;
private final TypeConstructor typeConstructor; private final TypeConstructor typeConstructor;
private final JetType boundsAsType;
public TypeParameterDescriptor(@NotNull DeclarationDescriptor containingDeclaration, List<Attribute> attributes, Variance variance, String name, Set<JetType> upperBounds) { public TypeParameterDescriptor(
@NotNull DeclarationDescriptor containingDeclaration,
@NotNull List<Attribute> attributes,
@NotNull Variance variance,
@NotNull String name,
@NotNull Set<JetType> upperBounds,
@NotNull JetType boundsAsType) {
super(containingDeclaration, attributes, name); super(containingDeclaration, attributes, name);
this.variance = variance; this.variance = variance;
this.upperBounds = upperBounds; this.upperBounds = upperBounds;
@@ -26,10 +33,21 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl {
"&" + name, "&" + name,
Collections.<TypeParameterDescriptor>emptyList(), Collections.<TypeParameterDescriptor>emptyList(),
upperBounds); upperBounds);
this.boundsAsType = boundsAsType;
} }
public TypeParameterDescriptor(@NotNull DeclarationDescriptor containingDeclaration, List<Attribute> attributes, Variance variance, String name) { public TypeParameterDescriptor(
this(containingDeclaration, attributes, variance, name, Collections.singleton(JetStandardClasses.getNullableAnyType())); @NotNull DeclarationDescriptor containingDeclaration,
@NotNull List<Attribute> attributes,
@NotNull Variance variance,
@NotNull String name) {
this(
containingDeclaration,
attributes,
variance,
name,
Collections.singleton(JetStandardClasses.getNullableAnyType()),
JetStandardClasses.getNullableAnyType());
} }
public Variance getVariance() { public Variance getVariance() {
@@ -49,6 +67,11 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl {
return typeConstructor.toString(); return typeConstructor.toString();
} }
@NotNull
public JetType getBoundsAsType() {
return boundsAsType;
}
@Override @Override
public <R, D> R accept(DeclarationDescriptorVisitor<R, D> visitor, D data) { public <R, D> R accept(DeclarationDescriptorVisitor<R, D> visitor, D data) {
return visitor.visitTypeParameterDescriptor(this, data); return visitor.visitTypeParameterDescriptor(this, data);
@@ -1,6 +1,7 @@
package org.jetbrains.jet.lang.types; package org.jetbrains.jet.lang.types;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.resolve.SubstitutingScope; import org.jetbrains.jet.lang.resolve.SubstitutingScope;
import java.util.*; import java.util.*;
@@ -9,75 +10,135 @@ import java.util.*;
* @author abreslav * @author abreslav
*/ */
public class TypeSubstitutor { 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 = 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 substitute(@NotNull JetType context, @NotNull JetType subject, @NotNull Variance howThisTypeIsUsed) { public JetType safeSubstitute(@NotNull JetType context, @NotNull JetType subject, @NotNull Variance howThisTypeIsUsed) {
return substitute(buildSubstitutionContext(context), subject, howThisTypeIsUsed); return safeSubstitute(TypeUtils.buildSubstitutionContext(context), subject, howThisTypeIsUsed);
} }
@NotNull @NotNull
public JetType safeSubstitute(@NotNull Map<TypeConstructor, TypeProjection> 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<TypeConstructor, TypeProjection> substitutionContext, @NotNull JetType type, @NotNull Variance howThisTypeIsUsed) { public JetType substitute(@NotNull Map<TypeConstructor, TypeProjection> 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<TypeConstructor, TypeProjection> substitutionContext, @NotNull JetType type, @NotNull Variance howThisTypeIsUsed) throws SubstitutionException {
TypeConstructor constructor = type.getConstructor();
TypeProjection value = substitutionContext.get(constructor);
if (value != null) { if (value != null) {
Variance projectionKind = value.getProjectionKind(); assert constructor.getDeclarationDescriptor() instanceof TypeParameterDescriptor;
if (howThisTypeIsUsed.allowsInPosition() && !projectionKind.allowsInPosition()
|| howThisTypeIsUsed.allowsOutPosition() && !projectionKind.allowsOutPosition()) { if (errorCondition(howThisTypeIsUsed, value.getProjectionKind())) {
return ErrorType.createWrongVarianceErrorType(value); throw new SubstitutionException("!!" + value.toString());
} }
return value.getType(); return value.getType();
} }
return specializeType(type, substitutionContext); return specializeType(type, substitutionContext, howThisTypeIsUsed);
} }
private JetType specializeType(JetType subjectType, Map<TypeConstructor, TypeProjection> substitutionContext) { private JetType specializeType(JetType subjectType, Map<TypeConstructor, TypeProjection> substitutionContext, Variance callSiteVariance) throws SubstitutionException {
List<TypeProjection> newArguments = new ArrayList<TypeProjection>();
List<TypeProjection> 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( return new JetTypeImpl(
subjectType.getAttributes(), subjectType.getAttributes(),
subjectType.getConstructor(), subjectType.getConstructor(),
subjectType.isNullable(), subjectType.isNullable(),
substituteInArguments(substitutionContext, subjectType), newArguments,
new SubstitutingScope(subjectType.getMemberScope(), substitutionContext)); new SubstitutingScope(subjectType.getMemberScope(), substitutionContext));
} }
private List<TypeProjection> substituteInArguments(Map<TypeConstructor, TypeProjection> substitutionContext, JetType subjectType) { @NotNull
List<TypeProjection> newArguments = new ArrayList<TypeProjection>(); private TypeProjection substituteInProjection(
for (TypeProjection argument : subjectType.getArguments()) { @NotNull Map<TypeConstructor, TypeProjection> substitutionContext,
newArguments.add(substituteInProjection(substitutionContext, argument)); @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 protected boolean errorCondition(Variance ve, Variance p1) {
private TypeProjection substituteInProjection(Map<TypeConstructor, TypeProjection> substitutionContext, TypeProjection subject) { return !allows(ve, p1);
JetType subjectType = subject.getType();
TypeProjection value = substitutionContext.get(subjectType.getConstructor());
if (value != null) {
return value;
}
return new TypeProjection(subject.getProjectionKind(), specializeType(subjectType, substitutionContext));
} }
public Set<JetType> substituteInSet(Map<TypeConstructor, TypeProjection> substitutionContext, Set<JetType> types, Variance howTheseTypesWillBeUsed) { public Set<JetType> substituteInSet(Map<TypeConstructor, TypeProjection> substitutionContext, Set<JetType> types, Variance howTheseTypesWillBeUsed) {
Set<JetType> result = new HashSet<JetType>(); Set<JetType> result = new HashSet<JetType>();
for (JetType type : types) { for (JetType type : types) {
result.add(substitute(substitutionContext, type, howTheseTypesWillBeUsed)); result.add(safeSubstitute(substitutionContext, type, howTheseTypesWillBeUsed));
} }
return result; return result;
} }
public Map<TypeConstructor, TypeProjection> buildSubstitutionContext(JetType context) { private boolean allows(Variance declarationSiteVariance, Variance callSiteVariance) {
return buildSubstitutionContext(context.getConstructor().getParameters(), context.getArguments()); switch (declarationSiteVariance) {
} case INVARIANT: return true;
case IN_VARIANCE: return callSiteVariance != Variance.OUT_VARIANCE;
public Map<TypeConstructor, TypeProjection> buildSubstitutionContext(List<TypeParameterDescriptor> parameters, List<TypeProjection> contextArguments) { case OUT_VARIANCE: return callSiteVariance != Variance.IN_VARIANCE;
Map<TypeConstructor, TypeProjection> parameterValues = new HashMap<TypeConstructor, TypeProjection>();
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; throw new IllegalStateException(declarationSiteVariance.toString());
} }
} }
@@ -147,14 +147,14 @@ public class TypeUtils {
} }
@NotNull @NotNull
public static JetType makeUnsubstitutedType(ClassDescriptor classDescriptor) { public static JetType makeUnsubstitutedType(ClassDescriptor classDescriptor, JetScope unsubstitutedMemberScope) {
List<TypeProjection> arguments = getArguments(classDescriptor); List<TypeProjection> arguments = getArguments(classDescriptor);
return new JetTypeImpl( return new JetTypeImpl(
Collections.<Attribute>emptyList(), Collections.<Attribute>emptyList(),
classDescriptor.getTypeConstructor(), classDescriptor.getTypeConstructor(),
false, false,
arguments, arguments,
classDescriptor.getMemberScope(arguments) unsubstitutedMemberScope
); );
} }
@@ -166,4 +166,25 @@ public class TypeUtils {
} }
return result; return result;
} }
@NotNull
public static Map<TypeConstructor, TypeProjection> buildSubstitutionContext(@NotNull JetType context) {
return buildSubstitutionContext(context.getConstructor().getParameters(), context.getArguments());
}
@NotNull
public static Map<TypeConstructor, TypeProjection> buildSubstitutionContext(@NotNull List<TypeParameterDescriptor> parameters, @NotNull List<TypeProjection> contextArguments) {
Map<TypeConstructor, TypeProjection> parameterValues = new HashMap<TypeConstructor, TypeProjection>();
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());
}
} }
@@ -4,18 +4,20 @@ package org.jetbrains.jet.lang.types;
* @author max * @author max
*/ */
public enum Variance { public enum Variance {
INVARIANT("", true, true), INVARIANT("", true, true, 0),
IN_VARIANCE("in", true, false), IN_VARIANCE("in", true, false, -1),
OUT_VARIANCE("out", false, true); OUT_VARIANCE("out", false, true, +1);
private final String label; private final String label;
private final boolean allowsInPosition; private final boolean allowsInPosition;
private final boolean allowsOutPosition; 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.label = label;
this.allowsInPosition = allowsInPosition; this.allowsInPosition = allowsInPosition;
this.allowsOutPosition = allowsOutPosition; this.allowsOutPosition = allowsOutPosition;
this.superpositionFactor = superpositionFactor;
} }
public boolean allowsInPosition() { public boolean allowsInPosition() {
@@ -26,6 +28,16 @@ public enum Variance {
return allowsOutPosition; 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 @Override
public String toString() { public String toString() {
return label; return label;
+56
View File
@@ -0,0 +1,56 @@
class In<in T> {
~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 T> {
~Out.f~fun f() : T {}
~Out.f(a)~fun f(a : Int) : Int {a}
}
class Inv<T> {
~Inv.f~fun f(t : T) : T {t}
~Inv.inf~fun inf(t : T) : Unit {}
~Inv.outf~fun outf() : T {}
}
fun testInOut() {
new In<String>().`In.f:T->Unit`f("1");
new In<in String>().`In.f:T->Unit`f("1");
new In<out String>().`!`f("1")
new In<*>().`!`f("1");
new In<String>().`In.f:Int->Int`f(1);
new In<in String>().`In.f:Int->Int`f(1);
new In<out String>().`In.f:Int->Int`f(1)
new In<out String>().`!`f1(1)
new In<*>().`In.f:Int->Int`f(1);
new Out<Int>().`Out.f(a)`f(1)
new Out<out Int>().`Out.f(a)`f(1)
new Out<in Int>().`Out.f(a)`f(1)
new Out<*>().`Out.f(a)`f(1)
new Out<Int>().`Out.f`f()
new Out<out Int>().`Out.f`f()
new Out<in Int>().`!`f()
new Out<*>().`Out.f`f()
new Inv<Int>().`Inv.f`f(1)
new Inv<in Int>().`!`f(1)
new Inv<out Int>().`!`f(1)
new Inv<*>().`!`f(1)
new Inv<Int>().`Inv.inf`inf(1)
new Inv<in Int>().`Inv.inf`inf(1)
new Inv<out Int>().`!`inf(1)
new Inv<*>().`!`inf(1)
new Inv<Int>().`Inv.outf`outf()
new Inv<in Int>().`!`outf()
new Inv<out Int>().`Inv.outf`outf()
new Inv<*>().`Inv.outf`outf()
new Inv<Int>().`Inv.outf`outf(1)
}
@@ -142,4 +142,8 @@ public class JetResolveTest extends ExtensibleResolveTestCase {
doTest("/resolve/ResolveOfInfixExpressions.jet", true, true); doTest("/resolve/ResolveOfInfixExpressions.jet", true, true);
} }
public void testProjections() throws Exception {
doTest("/resolve/Projections.jet", true, true);
}
} }