Projections prohibited in constructor type arguments

This commit is contained in:
Andrey Breslav
2011-03-23 13:41:06 +03:00
parent b5dce0d724
commit 3ba947da25
5 changed files with 81 additions and 51 deletions
@@ -2,6 +2,7 @@ package org.jetbrains.jet.lang.psi;
import com.intellij.lang.ASTNode; import com.intellij.lang.ASTNode;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.JetNodeTypes; import org.jetbrains.jet.JetNodeTypes;
import org.jetbrains.jet.lexer.JetToken; import org.jetbrains.jet.lexer.JetToken;
@@ -37,11 +38,16 @@ public class JetModifierList extends JetElement {
} }
public boolean hasModifier(JetToken token) { public boolean hasModifier(JetToken token) {
return getModifierNode(token) != null;
}
@Nullable
public ASTNode getModifierNode(JetToken token) {
ASTNode node = getNode().getFirstChildNode(); ASTNode node = getNode().getFirstChildNode();
while (node != null) { while (node != null) {
if (node.getElementType() == token) return true; if (node.getElementType() == token) return node;
node = node.getTreeNext(); node = node.getTreeNext();
} }
return false; return null;
} }
} }
@@ -1,6 +1,7 @@
package org.jetbrains.jet.lang.psi; package org.jetbrains.jet.lang.psi;
import com.intellij.lang.ASTNode; import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.JetNodeTypes; import org.jetbrains.jet.JetNodeTypes;
@@ -16,20 +17,14 @@ public class JetTypeProjection extends JetDeclaration {
@NotNull @NotNull
public JetProjectionKind getProjectionKind() { public JetProjectionKind getProjectionKind() {
JetModifierList modifierList = getModifierList(); ASTNode projectionNode = getProjectionNode();
if (modifierList != null) { if (projectionNode == null) return JetProjectionKind.NONE;
if (modifierList.hasModifier(JetTokens.IN_KEYWORD)) {
return JetProjectionKind.IN;
}
if (modifierList.hasModifier(JetTokens.OUT_KEYWORD)) {
return JetProjectionKind.OUT;
}
}
if (findChildByType(JetTokens.MUL) != null) {
return JetProjectionKind.STAR;
}
return JetProjectionKind.NONE; if (projectionNode.getElementType() == JetTokens.IN_KEYWORD) return JetProjectionKind.IN;
if (projectionNode.getElementType() == JetTokens.OUT_KEYWORD) return JetProjectionKind.OUT;
if (projectionNode.getElementType() == JetTokens.MUL) return JetProjectionKind.STAR;
throw new IllegalStateException(projectionNode.getText());
} }
@Override @Override
@@ -41,4 +36,25 @@ public class JetTypeProjection extends JetDeclaration {
public JetTypeReference getTypeReference() { public JetTypeReference getTypeReference() {
return (JetTypeReference) findChildByType(JetNodeTypes.TYPE_REFERENCE); return (JetTypeReference) findChildByType(JetNodeTypes.TYPE_REFERENCE);
} }
@Nullable
public ASTNode getProjectionNode() {
JetModifierList modifierList = getModifierList();
if (modifierList != null) {
ASTNode node = modifierList.getModifierNode(JetTokens.IN_KEYWORD);
if (node != null) {
return node;
}
node = modifierList.getModifierNode(JetTokens.OUT_KEYWORD);
if (node != null) {
return node;
}
}
PsiElement star = findChildByType(JetTokens.MUL);
if (star != null) {
return star.getNode();
}
return null;
}
} }
@@ -183,7 +183,7 @@ public class JetTypeInferrer {
@Override @Override
public void visitJetElement(JetElement elem) { public void visitJetElement(JetElement elem) {
throw new IllegalArgumentException("Unsupported element: " + elem); semanticServices.getErrorHandler().genericError(elem.getNode(), "Unsupported in call expression"); // TODO : Message
} }
}); });
return wrapForTracing(result[0], reference[0], argumentList, true); return wrapForTracing(result[0], reference[0], argumentList, true);
@@ -209,10 +209,11 @@ public class JetTypeInferrer {
private OverloadDomain wrapForTracing( private OverloadDomain wrapForTracing(
@Nullable final OverloadDomain overloadDomain, @Nullable final OverloadDomain overloadDomain,
@NotNull final JetReferenceExpression referenceExpression, final JetReferenceExpression referenceExpression,
@Nullable final PsiElement argumentList, @Nullable final PsiElement argumentList,
final boolean reportErrors) { final boolean reportErrors) {
if (overloadDomain == null) return OverloadDomain.EMPTY; if (overloadDomain == null) return OverloadDomain.EMPTY;
assert referenceExpression != null;
return new OverloadDomain() { return new OverloadDomain() {
@NotNull @NotNull
@Override @Override
@@ -682,6 +683,19 @@ public class JetTypeInferrer {
if (declarationDescriptor instanceof ClassDescriptor) { if (declarationDescriptor instanceof ClassDescriptor) {
ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor; ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor;
for (JetTypeProjection typeProjection : userType.getTypeArguments()) {
switch (typeProjection.getProjectionKind()) {
case IN:
case OUT:
case STAR:
// TODO : Bug in the editor
semanticServices.getErrorHandler().genericError(typeProjection.getProjectionNode(), "Projections are not allowed in constructor type arguments");
break;
case NONE:
break;
}
}
JetSimpleNameExpression referenceExpression = userType.getReferenceExpression(); JetSimpleNameExpression referenceExpression = userType.getReferenceExpression();
if (referenceExpression != null) { if (referenceExpression != null) {
// When one writes 'new Array<in T>(...)' this does not make much sense, and an instance // When one writes 'new Array<in T>(...)' this does not make much sense, and an instance
@@ -696,7 +710,6 @@ public class JetTypeInferrer {
// The code below upcasts the type automatically // The code below upcasts the type automatically
List<TypeProjection> typeArguments = receiverType.getArguments(); List<TypeProjection> typeArguments = receiverType.getArguments();
System.out.println("typeArguments = " + typeArguments);
List<TypeProjection> projectionsStripped = new ArrayList<TypeProjection>(); List<TypeProjection> projectionsStripped = new ArrayList<TypeProjection>();
for (TypeProjection typeArgument : typeArguments) { for (TypeProjection typeArgument : typeArguments) {
@@ -706,7 +719,6 @@ public class JetTypeInferrer {
else else
projectionsStripped.add(typeArgument); projectionsStripped.add(typeArgument);
} }
System.out.println("projectionsStripped = " + projectionsStripped);
FunctionGroup constructors = classDescriptor.getConstructors(projectionsStripped); FunctionGroup constructors = classDescriptor.getConstructors(projectionsStripped);
OverloadDomain constructorsOverloadDomain = semanticServices.getOverloadResolver().getOverloadDomain(constructors); OverloadDomain constructorsOverloadDomain = semanticServices.getOverloadResolver().getOverloadDomain(constructors);
@@ -729,7 +741,7 @@ public class JetTypeInferrer {
result = constructorReturnedType; result = constructorReturnedType;
// Automatic upcast: // Automatic upcast:
result = receiverType; // result = receiverType;
} }
} }
else { else {
@@ -89,7 +89,7 @@ public class TypeSubstitutor {
Variance passedProjectionKind = passedProjection.getProjectionKind(); Variance passedProjectionKind = passedProjection.getProjectionKind();
Variance parameterVariance = correspondingTypeParameter.getVariance(); Variance parameterVariance = correspondingTypeParameter.getVariance();
Variance effectiveProjectionKind = (passedProjectionKind == Variance.INVARIANT) ? parameterVariance : passedProjectionKind; Variance effectiveProjectionKind = asymmetricOr(passedProjectionKind, parameterVariance);
Variance effectiveContextVariance = contextCallSiteVariance.superpose(effectiveProjectionKind); Variance effectiveContextVariance = contextCallSiteVariance.superpose(effectiveProjectionKind);
TypeProjection projectionValue = substitutionContext.get(typeToSubstituteIn.getConstructor()); TypeProjection projectionValue = substitutionContext.get(typeToSubstituteIn.getConstructor());
@@ -118,15 +118,11 @@ public class TypeSubstitutor {
effectiveContextVariance)); effectiveContextVariance));
} }
// public Set<JetType> substituteInSet(Map<TypeConstructor, TypeProjection> substitutionContext, Set<JetType> types, Variance howTheseTypesWillBeUsed) { private static Variance asymmetricOr(Variance a, Variance b) {
// Set<JetType> result = new HashSet<JetType>(); return a == Variance.INVARIANT ? b : a;
// for (JetType type : types) { }
// result.add(safeSubstitute(substitutionContext, type, howTheseTypesWillBeUsed));
// }
// return result;
// }
private boolean allows(Variance declarationSiteVariance, Variance callSiteVariance) { private static boolean allows(Variance declarationSiteVariance, Variance callSiteVariance) {
switch (declarationSiteVariance) { switch (declarationSiteVariance) {
case INVARIANT: return true; case INVARIANT: return true;
case IN_VARIANCE: return callSiteVariance != Variance.OUT_VARIANCE; case IN_VARIANCE: return callSiteVariance != Variance.OUT_VARIANCE;
+22 -22
View File
@@ -17,40 +17,40 @@ class Inv<T> {
fun testInOut() { fun testInOut() {
new In<String>().`In.f:T->Unit`f("1"); new In<String>().`In.f:T->Unit`f("1");
new In<in String>().`In.f:T->Unit`f("1"); (return : In<in String>).`In.f:T->Unit`f("1");
new In<out String>().`!`f("1") (return : In<out String>).`!`f("1")
new In<*>().`!`f("1"); (return : In<*>).`!`f("1");
new In<String>().`In.f:Int->Int`f(1); new In<String>().`In.f:Int->Int`f(1);
new In<in String>().`In.f:Int->Int`f(1); (return : In<in String>).`In.f:Int->Int`f(1);
new In<out String>().`In.f:Int->Int`f(1) (return : In<out String>).`In.f:Int->Int`f(1)
new In<out String>().`!`f1(1) (return : In<out String>).`!`f1(1)
new In<*>().`In.f:Int->Int`f(1); (return : In<*>).`In.f:Int->Int`f(1);
new Out<Int>().`Out.f(a)`f(1) new Out<Int>().`Out.f(a)`f(1)
new Out<out Int>().`Out.f(a)`f(1) (return : Out<out Int>).`Out.f(a)`f(1)
new Out<in Int>().`Out.f(a)`f(1) (return : Out<in Int>).`Out.f(a)`f(1)
new Out<*>().`Out.f(a)`f(1) (return : Out<*>).`Out.f(a)`f(1)
new Out<Int>().`Out.f`f() new Out<Int>().`Out.f`f()
new Out<out Int>().`Out.f`f() (return : Out<out Int>).`Out.f`f()
new Out<in Int>().`!`f() (return : Out<in Int>).`!`f()
new Out<*>().`Out.f`f() (return : Out<*>).`Out.f`f()
new Inv<Int>().`Inv.f`f(1) new Inv<Int>().`Inv.f`f(1)
new Inv<in Int>().`!`f(1) (return : Inv<in Int>).`!`f(1)
new Inv<out Int>().`!`f(1) (return : Inv<out Int>).`!`f(1)
new Inv<*>().`!`f(1) (return : Inv<*>).`!`f(1)
new Inv<Int>().`Inv.inf`inf(1) new Inv<Int>().`Inv.inf`inf(1)
new Inv<in Int>().`Inv.inf`inf(1) (return : Inv<in Int>).`Inv.inf`inf(1)
new Inv<out Int>().`!`inf(1) (return : Inv<out Int>).`!`inf(1)
new Inv<*>().`!`inf(1) (return : Inv<*>).`!`inf(1)
new Inv<Int>().`Inv.outf`outf() new Inv<Int>().`Inv.outf`outf()
new Inv<in Int>().`Inv.outf`outf()`:std::Any?` (return : Inv<in Int>).`Inv.outf`outf()`:std::Any?`
new Inv<out Int>().`Inv.outf`outf() (return : Inv<out Int>).`Inv.outf`outf()
new Inv<*>().`Inv.outf`outf() (return : Inv<*>).`Inv.outf`outf()
new Inv<Int>().`Inv.outf`outf(1) new Inv<Int>().`Inv.outf`outf(1)
} }