diff --git a/grammar/src/class.grm b/grammar/src/class.grm index 6f110b4ccf7..94e8cb09baf 100644 --- a/grammar/src/class.grm +++ b/grammar/src/class.grm @@ -21,6 +21,7 @@ class typeParameters? ("wraps" valueParameters? | modifiers valueParameters?)? (":" annotations delegationSpecifier{","})? + typeConstraints (classBody? | enumClassBody) ; @@ -40,7 +41,6 @@ explicitDelegation typeParameters : "<" typeParameter{","} ">" - ("where" typeConstraint{","})? ; typeParameter @@ -51,6 +51,10 @@ typeParameter bq. See [Generic classes|Generics#Generic classes] */ +typeConstraints + : ("where" typeConstraint{","})? + ; + typeConstraint : annotations SimpleName ":" type : annotations "class" "object" SimpleName ":" type diff --git a/grammar/src/class_members.grm b/grammar/src/class_members.grm index 880ef78485b..ac73ca56d1b 100644 --- a/grammar/src/class_members.grm +++ b/grammar/src/class_members.grm @@ -83,6 +83,7 @@ function (type "." | annotations/*for receiver type*/)? SimpleName typeParameters? valueParameters (":" type)? + typeConstraints functionBody? ; @@ -95,6 +96,7 @@ property : modifiers ("val" | "var") typeParameters? (type "." | annotations)? SimpleName (":" type)? + typeConstraints ("=" expression SEMI?)? (getter? setter? | setter? getter?) SEMI? ; diff --git a/grammar/src/enum.grm b/grammar/src/enum.grm index 514adcc45bc..d0d49afcc3b 100644 --- a/grammar/src/enum.grm +++ b/grammar/src/enum.grm @@ -9,5 +9,5 @@ enumClassBody ; enumEntry - : modifiers SimpleName typeParameters? valueParameters? (":" initializer{","})? classBody? + : modifiers SimpleName typeParameters? valueParameters? (":" initializer{","})? typeConstraints classBody? ; diff --git a/grammar/src/toplevel.grm b/grammar/src/toplevel.grm index be183d75fde..44e142655f4 100644 --- a/grammar/src/toplevel.grm +++ b/grammar/src/toplevel.grm @@ -53,5 +53,5 @@ bq. See [Namespaces] [undocumented] typedef - : modifiers "type" SimpleName typeParameters? "=" type + : modifiers "type" SimpleName (typeParameters typeConstraints)? "=" type ; \ No newline at end of file diff --git a/grammar/src/when.grm b/grammar/src/when.grm index c307019e68c..ebdbcc58502 100644 --- a/grammar/src/when.grm +++ b/grammar/src/when.grm @@ -36,8 +36,8 @@ pattern decomposerPattern : type -// TODO : typeParameters will be consumed by the expression - : elvisExpression typeParameters? "@" tuplePattern +// TODO : typeArguments will be consumed by the expression + : elvisExpression typeArguments? "@" tuplePattern ; constantPattern diff --git a/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java b/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java index 6b444a8c360..11cb53c0987 100644 --- a/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java +++ b/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java @@ -384,6 +384,7 @@ public class JetParsing extends AbstractJetParsing { * ("wraps" "(" primaryConstructorParameter{","} ")") | * (modifiers "(" primaryConstructorParameter{","} ")"))? * (":" attributes delegationSpecifier{","})? + * typeConstraints * (classBody? | enumClassBody) * ; */ @@ -392,7 +393,7 @@ public class JetParsing extends AbstractJetParsing { advance(); // CLASS_KEYWORD expect(IDENTIFIER, "Class name expected", CLASS_NAME_RECOVERY_SET); - parseTypeParameterList(TYPE_PARAMETER_GT_RECOVERY_SET); + boolean typeParametersDeclared = parseTypeParameterList(TYPE_PARAMETER_GT_RECOVERY_SET); if (at(WRAPS_KEYWORD)) { advance(); // WRAPS_KEYWORD @@ -414,6 +415,8 @@ public class JetParsing extends AbstractJetParsing { parseDelegationSpecifierList(); } + parseTypeConstraintsGuarded(typeParametersDeclared); + if (at(LBRACE)) { if (enumClass) { parseEnumClassBody(); @@ -473,7 +476,7 @@ public class JetParsing extends AbstractJetParsing { /* * enumEntry - * : modifiers SimpleName typeParameters? primaryConstructorParameters? (":" initializer{","})? classBody? + * : modifiers SimpleName typeParameters? primaryConstructorParameters? (":" initializer{","})? typeConstraints classBody? * ; */ private void parseEnumEntry() { @@ -483,7 +486,7 @@ public class JetParsing extends AbstractJetParsing { advance(); // IDENTIFIER nameAsDeclaration.done(OBJECT_DECLARATION_NAME); - parseTypeParameterList(TokenSet.create(COLON, LPAR, SEMICOLON, LBRACE)); + boolean typeParametersDeclared = parseTypeParameterList(TokenSet.create(COLON, LPAR, SEMICOLON, LBRACE)); if (at(LPAR)) { parseValueParameterList(false, TokenSet.create(COLON, SEMICOLON, LBRACE)); @@ -495,6 +498,8 @@ public class JetParsing extends AbstractJetParsing { parseInitializerList(); } + parseTypeConstraintsGuarded(typeParametersDeclared); + if (at(LBRACE)) { parseClassBody(); } @@ -725,7 +730,7 @@ public class JetParsing extends AbstractJetParsing { /* * typedef - * : modifiers "type" SimpleName typeParameters? "=" type + * : modifiers "type" SimpleName (typeParameters typeConstraints)? "=" type * ; */ public JetNodeType parseTypeDef() { @@ -735,7 +740,9 @@ public class JetParsing extends AbstractJetParsing { expect(IDENTIFIER, "Type name expected", TokenSet.orSet(TokenSet.create(LT, EQ, SEMICOLON), TOPLEVEL_OBJECT_FIRST)); - parseTypeParameterList(TYPE_PARAMETER_GT_RECOVERY_SET); + if (parseTypeParameterList(TYPE_PARAMETER_GT_RECOVERY_SET)) { + parseTypeConstraints(); + } expect(EQ, "Expecting '='", TokenSet.orSet(TOPLEVEL_OBJECT_FIRST, TokenSet.create(SEMICOLON))); @@ -751,6 +758,7 @@ public class JetParsing extends AbstractJetParsing { * : modifiers ("val" | "var") * typeParameters? (type "." | attributes)? * SimpleName (":" type)? + * typeConstraints * ("=" element SEMI?)? * (getter? setter? | setter? getter?) SEMI? * ; @@ -766,9 +774,7 @@ public class JetParsing extends AbstractJetParsing { errorAndAdvance("Expecting 'val' or 'var'"); } - if (at(LT)) { - parseTypeParameterList(TokenSet.create(IDENTIFIER, EQ, COLON, SEMICOLON)); - } + boolean typeParametersDeclared = at(LT) ? parseTypeParameterList(TokenSet.create(IDENTIFIER, EQ, COLON, SEMICOLON)) : false; TokenSet propertyNameFollow = TokenSet.create(COLON, EQ, LBRACE, SEMICOLON); @@ -794,6 +800,8 @@ public class JetParsing extends AbstractJetParsing { parseTypeRef(); } + parseTypeConstraintsGuarded(typeParametersDeclared); + if (local) { if (at(EQ)) { advance(); // EQ @@ -900,6 +908,7 @@ public class JetParsing extends AbstractJetParsing { * (type "." | attributes)? * SimpleName * typeParameters? functionParameters (":" type)? + * typeConstraints * functionBody? * ; */ @@ -934,6 +943,7 @@ public class JetParsing extends AbstractJetParsing { else { error.drop(); } + typeParameterListOccurred = true; } parseValueParameterList(false, valueParametersFollow); @@ -944,6 +954,8 @@ public class JetParsing extends AbstractJetParsing { parseTypeRef(); } + parseTypeConstraintsGuarded(typeParameterListOccurred); + if (at(SEMICOLON)) { advance(); // SEMICOLON } @@ -1088,11 +1100,11 @@ public class JetParsing extends AbstractJetParsing { /* * typeParameters * : ("<" typeParameter{","} ">" - * ("where" typeConstraint{","})?)? * ; */ - private void parseTypeParameterList(TokenSet recoverySet) { + private boolean parseTypeParameterList(TokenSet recoverySet) { PsiBuilder.Marker list = mark(); + boolean result = false; if (at(LT)) { myBuilder.disableNewlines(); @@ -1108,12 +1120,34 @@ public class JetParsing extends AbstractJetParsing { expect(GT, "Missing '>'", recoverySet); myBuilder.restoreNewlinesState(); - - if (at(WHERE_KEYWORD)) { - parseTypeConstraintList(); - } + result = true; } list.done(TYPE_PARAMETER_LIST); + return result; + } + + /* + * typeConstraints + * : ("where" typeConstraint{","})? + * ; + */ + private void parseTypeConstraintsGuarded(boolean typeParameterListOccurred) { + PsiBuilder.Marker error = mark(); + boolean constraints = parseTypeConstraints(); + if (constraints && !typeParameterListOccurred) { + error.error("Type constraints are not allowed when no type parameters declared"); + } + else { + error.drop(); + } + } + + private boolean parseTypeConstraints() { + if (at(WHERE_KEYWORD)) { + parseTypeConstraintList(); + return true; + } + return false; } /* diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetTypeParameterList.java b/idea/src/org/jetbrains/jet/lang/psi/JetTypeParameterList.java index 8135266b93a..8f32e66e2ae 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetTypeParameterList.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetTypeParameterList.java @@ -2,10 +2,8 @@ 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 java.util.Collections; import java.util.List; /** @@ -20,17 +18,6 @@ public class JetTypeParameterList extends JetElement { return findChildrenByType(JetNodeTypes.TYPE_PARAMETER); } - @Nullable - public JetTypeConstraintList getTypeConstraintList() { - return (JetTypeConstraintList) findChildByType(JetNodeTypes.TYPE_CONSTRAINT_LIST); - } - - @NotNull - public List getAdditionalConstraints() { - JetTypeConstraintList list = getTypeConstraintList(); - return list != null ? list.getConstraints() : Collections.emptyList(); - } - @Override public void accept(JetVisitor visitor) { visitor.visitTypeParameterList(this); diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetTypeParameterListOwner.java b/idea/src/org/jetbrains/jet/lang/psi/JetTypeParameterListOwner.java index 4a96a97782b..a41aab6f99a 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetTypeParameterListOwner.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetTypeParameterListOwner.java @@ -21,13 +21,14 @@ public class JetTypeParameterListOwner extends JetNamedDeclaration { return (JetTypeParameterList) findChildByType(JetNodeTypes.TYPE_PARAMETER_LIST); } + @Nullable + public JetTypeConstraintList getTypeConstraintList() { + return (JetTypeConstraintList) findChildByType(JetNodeTypes.TYPE_CONSTRAINT_LIST); + } + @NotNull public List getTypeConstaints() { - JetTypeParameterList typeParameterList = getTypeParameterList(); - if (typeParameterList == null) { - return Collections.emptyList(); - } - JetTypeConstraintList typeConstraintList = typeParameterList.getTypeConstraintList(); + JetTypeConstraintList typeConstraintList = getTypeConstraintList(); if (typeConstraintList == null) { return Collections.emptyList(); } diff --git a/idea/testData/checker/MultipleBounds.jet b/idea/testData/checker/MultipleBounds.jet index 9a876731a2c..126864510c1 100644 --- a/idea/testData/checker/MultipleBounds.jet +++ b/idea/testData/checker/MultipleBounds.jet @@ -14,14 +14,14 @@ class D() { class object : A(), B () {} } -class Test1 +class Test1() where T : B, B : T, // error class object T : A, class object T : B, class object B : T - () { + { fun test(t : T) { T.foo() @@ -46,14 +46,14 @@ class Buzz where T : Bar<Int>, T : n class XFoo> class Y<T : Foo> where T : Bar -fun +fun test2(t : T) where T : B, B : T, class object B : T, class object T : B, class object T : A - test2(t : T) { +{ T.foo() T.bar() t.foo() diff --git a/idea/testData/codegen/classes/classObjectMethod.jet b/idea/testData/codegen/classes/classObjectMethod.jet index c4a67260553..2a5d25f6213 100644 --- a/idea/testData/codegen/classes/classObjectMethod.jet +++ b/idea/testData/codegen/classes/classObjectMethod.jet @@ -8,6 +8,6 @@ class MyInt() { } } -fun toDefault where class object T: Default(t: T) = T.defaultValue() +fun toDefault(t: T) where class object T: Default = T.defaultValue() fun box(): String = if (toDefault(MyInt()) == 610) "OK" else "fail" diff --git a/idea/testData/psi/TypeConstraints.txt b/idea/testData/psi/TypeConstraints.txt index 4df16bb80c5..a7b245da2ed 100644 --- a/idea/testData/psi/TypeConstraints.txt +++ b/idea/testData/psi/TypeConstraints.txt @@ -9,36 +9,36 @@ JetFile: TypeConstraints.jet TYPE_PARAMETER PsiElement(IDENTIFIER)('T') PsiElement(GT)('>') - PsiWhiteSpace(' ') - PsiElement(where)('where') - PsiWhiteSpace(' ') - TYPE_CONSTRAINT_LIST - TYPE_CONSTRAINT - REFERENCE_EXPRESSION - PsiElement(IDENTIFIER)('T') - PsiWhiteSpace(' ') - PsiElement(COLON)(':') - PsiWhiteSpace(' ') - TYPE_REFERENCE - USER_TYPE - REFERENCE_EXPRESSION - PsiElement(IDENTIFIER)('T') - PsiElement(COMMA)(',') + PsiWhiteSpace(' ') + PsiElement(where)('where') + PsiWhiteSpace(' ') + TYPE_CONSTRAINT_LIST + TYPE_CONSTRAINT + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('T') PsiWhiteSpace(' ') - TYPE_CONSTRAINT - PsiElement(class)('class') - PsiWhiteSpace(' ') - PsiElement(object)('object') - PsiWhiteSpace(' ') - REFERENCE_EXPRESSION - PsiElement(IDENTIFIER)('T') - PsiWhiteSpace(' ') - PsiElement(COLON)(':') - PsiWhiteSpace(' ') - TYPE_REFERENCE - USER_TYPE - REFERENCE_EXPRESSION - PsiElement(IDENTIFIER)('T') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('T') + PsiElement(COMMA)(',') + PsiWhiteSpace(' ') + TYPE_CONSTRAINT + PsiElement(class)('class') + PsiWhiteSpace(' ') + PsiElement(object)('object') + PsiWhiteSpace(' ') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('T') + PsiWhiteSpace(' ') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('T') PsiWhiteSpace(' ') CLASS_BODY PsiElement(LBRACE)('{') diff --git a/idea/testData/psi/examples/PolymorphicClassObjects.jet b/idea/testData/psi/examples/PolymorphicClassObjects.jet index 7479ba745be..b296741e0db 100644 --- a/idea/testData/psi/examples/PolymorphicClassObjects.jet +++ b/idea/testData/psi/examples/PolymorphicClassObjects.jet @@ -16,9 +16,9 @@ class List { } -fun where +fun Map.map(f : fun (E) : R) : T where T : Iterable, - class object T : Buildable Map.map(f : fun (E) : R) : T = { + class object T : Buildable = { val builder = T.newBuilder() for (e in this) { builder += f(e) diff --git a/idea/testData/psi/examples/PolymorphicClassObjects.txt b/idea/testData/psi/examples/PolymorphicClassObjects.txt index 6d075b580d3..1dba45398c1 100644 --- a/idea/testData/psi/examples/PolymorphicClassObjects.txt +++ b/idea/testData/psi/examples/PolymorphicClassObjects.txt @@ -211,59 +211,6 @@ JetFile: PolymorphicClassObjects.jet TYPE_PARAMETER PsiElement(IDENTIFIER)('R') PsiElement(GT)('>') - PsiWhiteSpace(' ') - PsiElement(where)('where') - PsiWhiteSpace('\n ') - TYPE_CONSTRAINT_LIST - TYPE_CONSTRAINT - REFERENCE_EXPRESSION - PsiElement(IDENTIFIER)('T') - PsiWhiteSpace(' ') - PsiElement(COLON)(':') - PsiWhiteSpace(' ') - TYPE_REFERENCE - USER_TYPE - REFERENCE_EXPRESSION - PsiElement(IDENTIFIER)('Iterable') - TYPE_ARGUMENT_LIST - PsiElement(LT)('<') - TYPE_PROJECTION - TYPE_REFERENCE - USER_TYPE - REFERENCE_EXPRESSION - PsiElement(IDENTIFIER)('E') - PsiElement(GT)('>') - PsiElement(COMMA)(',') - PsiWhiteSpace('\n ') - TYPE_CONSTRAINT - PsiElement(class)('class') - PsiWhiteSpace(' ') - PsiElement(object)('object') - PsiWhiteSpace(' ') - REFERENCE_EXPRESSION - PsiElement(IDENTIFIER)('T') - PsiWhiteSpace(' ') - PsiElement(COLON)(':') - PsiWhiteSpace(' ') - TYPE_REFERENCE - USER_TYPE - REFERENCE_EXPRESSION - PsiElement(IDENTIFIER)('Buildable') - TYPE_ARGUMENT_LIST - PsiElement(LT)('<') - TYPE_PROJECTION - TYPE_REFERENCE - USER_TYPE - REFERENCE_EXPRESSION - PsiElement(IDENTIFIER)('E') - PsiElement(COMMA)(',') - PsiWhiteSpace(' ') - TYPE_PROJECTION - TYPE_REFERENCE - USER_TYPE - REFERENCE_EXPRESSION - PsiElement(IDENTIFIER)('T') - PsiElement(GT)('>') PsiWhiteSpace(' ') TYPE_REFERENCE USER_TYPE @@ -329,6 +276,59 @@ JetFile: PolymorphicClassObjects.jet PsiElement(IDENTIFIER)('R') PsiElement(GT)('>') PsiWhiteSpace(' ') + PsiElement(where)('where') + PsiWhiteSpace('\n ') + TYPE_CONSTRAINT_LIST + TYPE_CONSTRAINT + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('T') + PsiWhiteSpace(' ') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Iterable') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('E') + PsiElement(GT)('>') + PsiElement(COMMA)(',') + PsiWhiteSpace('\n ') + TYPE_CONSTRAINT + PsiElement(class)('class') + PsiWhiteSpace(' ') + PsiElement(object)('object') + PsiWhiteSpace(' ') + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('T') + PsiWhiteSpace(' ') + PsiElement(COLON)(':') + PsiWhiteSpace(' ') + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Buildable') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('E') + PsiElement(COMMA)(',') + PsiWhiteSpace(' ') + TYPE_PROJECTION + TYPE_REFERENCE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('T') + PsiElement(GT)('>') + PsiWhiteSpace(' ') PsiElement(EQ)('=') PsiWhiteSpace(' ') FUNCTION_LITERAL_EXPRESSION