From 3ba947da257575767ea8d6695eccf1fd43efd6ca Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Wed, 23 Mar 2011 13:41:06 +0300 Subject: [PATCH] Projections prohibited in constructor type arguments --- .../jet/lang/psi/JetModifierList.java | 10 ++++- .../jet/lang/psi/JetTypeProjection.java | 42 ++++++++++++------ .../jet/lang/types/JetTypeInferrer.java | 22 +++++++--- .../jet/lang/types/TypeSubstitutor.java | 14 +++--- idea/testData/resolve/Projections.jet | 44 +++++++++---------- 5 files changed, 81 insertions(+), 51 deletions(-) diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetModifierList.java b/idea/src/org/jetbrains/jet/lang/psi/JetModifierList.java index 8d8a202f550..a28caea1d0f 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetModifierList.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetModifierList.java @@ -2,6 +2,7 @@ package org.jetbrains.jet.lang.psi; import com.intellij.lang.ASTNode; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.JetNodeTypes; import org.jetbrains.jet.lexer.JetToken; @@ -37,11 +38,16 @@ public class JetModifierList extends JetElement { } public boolean hasModifier(JetToken token) { + return getModifierNode(token) != null; + } + + @Nullable + public ASTNode getModifierNode(JetToken token) { ASTNode node = getNode().getFirstChildNode(); while (node != null) { - if (node.getElementType() == token) return true; + if (node.getElementType() == token) return node; node = node.getTreeNext(); } - return false; + return null; } } diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetTypeProjection.java b/idea/src/org/jetbrains/jet/lang/psi/JetTypeProjection.java index 4fe88184c6b..ac860e5a351 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetTypeProjection.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetTypeProjection.java @@ -1,6 +1,7 @@ package org.jetbrains.jet.lang.psi; import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.JetNodeTypes; @@ -16,20 +17,14 @@ public class JetTypeProjection extends JetDeclaration { @NotNull public JetProjectionKind getProjectionKind() { - JetModifierList modifierList = getModifierList(); - if (modifierList != null) { - 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; - } + ASTNode projectionNode = getProjectionNode(); + if (projectionNode == null) return JetProjectionKind.NONE; - 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 @@ -41,4 +36,25 @@ public class JetTypeProjection extends JetDeclaration { public JetTypeReference getTypeReference() { 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; + } } diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index 01a0c431d58..a721e2c1bb5 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -183,7 +183,7 @@ public class JetTypeInferrer { @Override 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); @@ -209,10 +209,11 @@ public class JetTypeInferrer { private OverloadDomain wrapForTracing( @Nullable final OverloadDomain overloadDomain, - @NotNull final JetReferenceExpression referenceExpression, + final JetReferenceExpression referenceExpression, @Nullable final PsiElement argumentList, final boolean reportErrors) { if (overloadDomain == null) return OverloadDomain.EMPTY; + assert referenceExpression != null; return new OverloadDomain() { @NotNull @Override @@ -682,6 +683,19 @@ public class JetTypeInferrer { if (declarationDescriptor instanceof ClassDescriptor) { 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(); if (referenceExpression != null) { // When one writes 'new Array(...)' this does not make much sense, and an instance @@ -696,7 +710,6 @@ public class JetTypeInferrer { // The code below upcasts the type automatically List typeArguments = receiverType.getArguments(); - System.out.println("typeArguments = " + typeArguments); List projectionsStripped = new ArrayList(); for (TypeProjection typeArgument : typeArguments) { @@ -706,7 +719,6 @@ public class JetTypeInferrer { else projectionsStripped.add(typeArgument); } - System.out.println("projectionsStripped = " + projectionsStripped); FunctionGroup constructors = classDescriptor.getConstructors(projectionsStripped); OverloadDomain constructorsOverloadDomain = semanticServices.getOverloadResolver().getOverloadDomain(constructors); @@ -729,7 +741,7 @@ public class JetTypeInferrer { result = constructorReturnedType; // Automatic upcast: - result = receiverType; +// result = receiverType; } } else { diff --git a/idea/src/org/jetbrains/jet/lang/types/TypeSubstitutor.java b/idea/src/org/jetbrains/jet/lang/types/TypeSubstitutor.java index 87ef4c6d752..f6fbe822f8b 100644 --- a/idea/src/org/jetbrains/jet/lang/types/TypeSubstitutor.java +++ b/idea/src/org/jetbrains/jet/lang/types/TypeSubstitutor.java @@ -89,7 +89,7 @@ public class TypeSubstitutor { Variance passedProjectionKind = passedProjection.getProjectionKind(); Variance parameterVariance = correspondingTypeParameter.getVariance(); - Variance effectiveProjectionKind = (passedProjectionKind == Variance.INVARIANT) ? parameterVariance : passedProjectionKind; + Variance effectiveProjectionKind = asymmetricOr(passedProjectionKind, parameterVariance); Variance effectiveContextVariance = contextCallSiteVariance.superpose(effectiveProjectionKind); TypeProjection projectionValue = substitutionContext.get(typeToSubstituteIn.getConstructor()); @@ -118,15 +118,11 @@ public class TypeSubstitutor { effectiveContextVariance)); } - // public Set substituteInSet(Map substitutionContext, Set types, Variance howTheseTypesWillBeUsed) { -// Set result = new HashSet(); -// for (JetType type : types) { -// result.add(safeSubstitute(substitutionContext, type, howTheseTypesWillBeUsed)); -// } -// return result; -// } + private static Variance asymmetricOr(Variance a, Variance b) { + return a == Variance.INVARIANT ? b : a; + } - private boolean allows(Variance declarationSiteVariance, Variance callSiteVariance) { + private static boolean allows(Variance declarationSiteVariance, Variance callSiteVariance) { switch (declarationSiteVariance) { case INVARIANT: return true; case IN_VARIANCE: return callSiteVariance != Variance.OUT_VARIANCE; diff --git a/idea/testData/resolve/Projections.jet b/idea/testData/resolve/Projections.jet index 437165a7f7b..508e316931b 100644 --- a/idea/testData/resolve/Projections.jet +++ b/idea/testData/resolve/Projections.jet @@ -17,40 +17,40 @@ class Inv { 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"); + (return : In).`In.f:T->Unit`f("1"); + (return : In).`!`f("1") + (return : 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); + (return : In).`In.f:Int->Int`f(1); + (return : In).`In.f:Int->Int`f(1) + (return : In).`!`f1(1) + (return : 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) + (return : Out).`Out.f(a)`f(1) + (return : Out).`Out.f(a)`f(1) + (return : Out<*>).`Out.f(a)`f(1) new Out().`Out.f`f() - new Out().`Out.f`f() - new Out().`!`f() - new Out<*>().`Out.f`f() + (return : Out).`Out.f`f() + (return : Out).`!`f() + (return : Out<*>).`Out.f`f() new Inv().`Inv.f`f(1) - new Inv().`!`f(1) - new Inv().`!`f(1) - new Inv<*>().`!`f(1) + (return : Inv).`!`f(1) + (return : Inv).`!`f(1) + (return : Inv<*>).`!`f(1) new Inv().`Inv.inf`inf(1) - new Inv().`Inv.inf`inf(1) - new Inv().`!`inf(1) - new Inv<*>().`!`inf(1) + (return : Inv).`Inv.inf`inf(1) + (return : Inv).`!`inf(1) + (return : Inv<*>).`!`inf(1) new Inv().`Inv.outf`outf() - new Inv().`Inv.outf`outf()`:std::Any?` - new Inv().`Inv.outf`outf() - new Inv<*>().`Inv.outf`outf() + (return : Inv).`Inv.outf`outf()`:std::Any?` + (return : Inv).`Inv.outf`outf() + (return : Inv<*>).`Inv.outf`outf() new Inv().`Inv.outf`outf(1) } \ No newline at end of file