You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2021/06/27 13:50:31 UTC

[groovy] branch GROOVY-9272 updated (166fbbb -> 24fcf32)

This is an automated email from the ASF dual-hosted git repository.

sunlan pushed a change to branch GROOVY-9272
in repository https://gitbox.apache.org/repos/asf/groovy.git.


    omit 166fbbb  GROOVY-9272: Support switch expression
     add d7f9edc  Trivial refactoring: extract common variables
     add d3d06f7  GROOVY-10112: IndexedProperty AST transform should only provide the getter for immutable fields
     add a556398  GROOVY-5239: prefer outer class method over static import method
     add cfd5ef0  refactor interface collect methods
     add 61df54b  refactor
     add 26a28be  GROOVY-8638: erase generics for no-signature fields/methods like bridges
     add c125919  GROOVY-8111: lowestUpperBound: primitives and self-referential types fix
     add 9a4df4d  GROOVY-10122: stubgen: find type of helper method in special ctor call
     add 445e0f6  GROOVY-5453: order category methods before taking first getter/setter
     add 0bdad76  GROOVY-10107: STC: check assign null before type parameter compatibility
     add 00fc7a4  Trivial tweak for hash table of hash-joins
     add 89f148f  Make Travis CI build work again(closes #1589)
     add eef2a82  GROOVY-10113: check class cycle for outer types and type parameters
     add 05a3963  GROOVY-3421: evaluate spread-map value only once
     add f48bb09  GROOVY-10125: fix for type parameter cycle false positive
     add 09979f9  undo edit
     add b3fd3e8  GROOVY-10126: Support parsing multiple YAML documents
     add 8ea882a  Trivial refactoring: inline variable
     add f230608  Correct a typo in quote type
     add c0b5b23  GROOVY-5245: bean-style property access for boolean "is" category method
     add 80895bc  GROOVY-8678: allow floating point literals without leading zeroes
     add 8ad3f0e  Merge pull request #1588 from nineninesevenfour/GROOVY-8678
     add bf7bb95  GROOVY-8678: extend test case
     add b76a929  try to fix dist build
     add efcfd33  GROOVY-10132: XmlUtil.serialize() Emoji bug
     add 73e6c82  GROOVY-10134: Groovy console can not highlight token properly sometimes
     add bd56a6b  Trivial tweak: avoid redundant operations when text updated
     add 32099f6  Trivial refactoring: extract common variable
     add f62e403  Trivial tweak: avoid reading preferences frequently
     add c21fe1f  GROOVY-10135: Bump jansi to 2.3.3
     add 134ed00  Trivial tweak for setting preferred size of numbers panel
     add 1e521a8  Apply thread factory to ginq thread pool
     add 051c130  Try to workaround javadoc bug
     add 6e041d3  Install graphviz
     add 7f4edba  Workaround javadoc bug
     add 8dce303  Fix javadoc issues
     add 07907ff  Tweak javadoc
     add b3bba1c  Fix javadoc issues
     add 6af09d3  GROOVY-10141: retain parse order of anon. inner types in module classes
     add 0b4b51a  GROOVY-10143: add test case
     add 0fffd2c  Trivial refactoring: remove redundant type casting
     add 9eed7a8  Trivial refactoring: extract common variable
     add eec31fa  Update GINQ user guide
     add cdb8083  minor refactor: optimize imports
     add 8ba70f6  GROOVY-10146: Groovy 3 compilation errors are less accurate than Groovy 2
     add 571e36f  Tweak syntax highlighter of groovy console
     add d4f1636  GROOVY-10145: Support JDK16 (#1598)
     add c51cb71  Add license header
     add 9087a3e  Avoid caching method repeatedly
     add 0c44604  Access more methods if "spy" found
     add 180e201  Trivial refactoring: simplify code
     add 0dfa029  Add a test for `GroovyObjectHelper`
     add 8c794fd  GROOVY-10150: Eliminate ambiguities while parsing non-static class creator
     add 237f107  Tweak `GroovyObjectHelperTest`
     add 2d0f332  Tweak `GroovyObjectHelperTest` further
     add 1bf1d6c  GROOVY-10151: Bump gradle to 6.9
     new 24fcf32  GROOVY-9272: Support switch expression

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (166fbbb)
            \
             N -- N -- N   refs/heads/GROOVY-9272 (24fcf32)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .github/workflows/gradle-snapshot-distribution.yml |   4 +-
 .travis.yml                                        |   6 +-
 build.gradle                                       |   4 +-
 .../src/main/groovy/org.apache.groovy-core.gradle  |  14 +-
 .../main/groovy/org.apache.groovy-tested.gradle    |   7 +
 gradle.properties                                  |   2 +-
 gradle/verification-metadata.xml                   |   7 +
 gradle/wrapper/gradle-wrapper.jar                  | Bin 55741 -> 59203 bytes
 gradle/wrapper/gradle-wrapper.properties           |   2 +-
 gradlew                                            |  53 +++--
 gradlew.bat                                        |  43 ++--
 src/antlr/GroovyLexer.g4                           |  21 +-
 src/antlr/GroovyParser.g4                          |   6 +-
 src/main/java/groovy/lang/MetaClassImpl.java       | 236 ++++++++++++++++-----
 .../java/groovy/transform/IndexedProperty.java     |   3 +-
 .../org/apache/groovy/lang/GroovyObjectHelper.java | 127 +++++++++++
 .../apache/groovy/parser/antlr4/AstBuilder.java    |   3 +-
 .../groovy/ast/decompiled/AsmDecompiler.java       | 165 +++++++-------
 .../ast/decompiled/MemberSignatureParser.java      | 113 +++++-----
 .../groovy/ast/expr/MethodCallExpression.java      |   4 +-
 .../codehaus/groovy/ast/tools/GeneralUtils.java    |  14 +-
 .../groovy/ast/tools/WideningCategories.java       | 153 +++++++------
 .../groovy/classgen/AsmClassGenerator.java         | 138 ++++++------
 .../org/codehaus/groovy/classgen/Verifier.java     |  39 +++-
 .../groovy/control/CompilerConfiguration.java      |   2 +-
 .../codehaus/groovy/control/ResolveVisitor.java    |  87 ++++----
 .../groovy/control/StaticImportVisitor.java        |  20 +-
 .../groovy/reflection/ReflectionUtils.java         |  63 ++++--
 .../org/codehaus/groovy/runtime/ArrayUtil.java     |   7 +-
 .../groovy/runtime/GroovyCategorySupport.java      |  44 ++--
 .../groovy/runtime/ProxyGeneratorAdapter.java      |   4 +-
 .../groovy/runtime/StreamGroovyMethods.java        |  12 +-
 .../groovy/tools/javac/JavaStubGenerator.java      |  78 +++----
 .../transform/ImmutableASTTransformation.java      |   2 +
 .../IndexedPropertyASTTransformation.java          |   8 +-
 .../transform/stc/StaticTypeCheckingSupport.java   |  46 ++--
 .../transform/stc/StaticTypeCheckingVisitor.java   |   2 +-
 .../codehaus/groovy/vmplugin/VMPluginFactory.java  |   1 +
 .../org/codehaus/groovy/vmplugin/v10/Java10.java   |   5 +
 .../org/codehaus/groovy/vmplugin/v16/Java16.java   | 116 ++++++++++
 .../vmplugin/v16/PluginDefaultGroovyMethods.java   |  13 +-
 .../vmplugin/v16/ProxyDefaultMethodHandle.java     |  56 +++++
 .../org/codehaus/groovy/vmplugin/v8/Java8.java     |  23 +-
 .../vmplugin/v8/PluginDefaultGroovyMethods.java    |   5 +-
 .../org/codehaus/groovy/vmplugin/v9/Java9.java     |  10 +-
 src/spec/doc/core-differences-java.adoc            |   2 +-
 src/spec/test/SyntaxTest.groovy                    |   1 +
 src/test/gls/innerClass/InnerClassTest.groovy      |  20 ++
 src/test/groovy/CategoryTest.groovy                |  52 ++++-
 src/test/groovy/IllegalAccessTests.groovy          |   4 +-
 src/test/groovy/bugs/Groovy10113.groovy            | 114 ++++++++++
 src/test/groovy/bugs/Groovy10143.groovy            | 111 ++++++++++
 .../{Groovy1465Bug.groovy => Groovy1465.groovy}    |  39 ++--
 .../{Groovy3904Bug.groovy => Groovy3904.groovy}    |  55 ++---
 src/test/groovy/bugs/Groovy5239.groovy             | 100 +++++++++
 .../{Groovy8048Bug.groovy => Groovy8048.groovy}    |  32 +--
 src/test/groovy/bugs/Groovy8678.groovy             | 218 +++++++++++++++++++
 src/test/groovy/bugs/Groovy8815.groovy             |   7 +
 src/test/groovy/bugs/Groovy8947.groovy             |   5 +
 .../groovy/operator/SpreadMapOperatorTest.groovy   |  26 ++-
 .../groovy/transform/stc/GenericsSTCTest.groovy    |  33 ++-
 .../groovy/lang/GroovyObjectHelperTest.groovy      |  52 +++++
 .../groovy/parser/antlr4/SyntaxErrorTest.groovy    |  23 +-
 .../groovy/ast/decompiled/AsmDecompilerTest.groovy |  32 ++-
 .../ast/decompiled/AsmDecompilerTestData.java      |   1 +
 .../groovy/ast/tools/WideningCategoriesTest.groovy |  41 +++-
 .../groovy/classgen/TransientMetaClassTest.groovy  |   4 +-
 .../codehaus/groovy/classgen/VerifierTest.groovy   |  72 +++++++
 .../codehaus/groovy/reflection/SecurityTest.java   |   3 +
 .../runtime/typehandling/NumberMathTest.groovy     |   2 +-
 .../{Groovy7306.groovy => Groovy10122.groovy}      |  25 +--
 .../transform/IndexedPropertyTransformTest.groovy  |  30 ++-
 .../TransformsAndCustomClassLoadersTest.groovy     |   5 +-
 .../groovy/console/ui/ConsoleTextEditor.java       |  27 ++-
 .../console/ui/text/SmartDocumentFilter.java       |  24 +--
 .../collection/runtime/QueryableCollection.java    |  29 ++-
 .../collection/runtime/QueryableHelper.groovy      |   8 +-
 .../groovy-ginq/src/spec/doc/ginq-userguide.adoc   |   2 +-
 .../StreamingMarkupWriter.java                     |   5 +-
 .../groovy/xml/GpathSyntaxTestSupport.groovy       |  12 +-
 .../src/test/groovy/groovy/xml/XmlUtilTest.groovy  |   9 +
 .../org/apache/groovy/yaml/util/YamlConverter.java |   8 +-
 .../spec/test/groovy/yaml/YamlParserTest.groovy    |  17 ++
 versions.properties                                |   2 +-
 84 files changed, 2237 insertions(+), 783 deletions(-)
 create mode 100644 src/main/java/org/apache/groovy/lang/GroovyObjectHelper.java
 create mode 100644 src/main/java/org/codehaus/groovy/vmplugin/v16/Java16.java
 copy subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/runtime/MacroStub.java => src/main/java/org/codehaus/groovy/vmplugin/v16/PluginDefaultGroovyMethods.java (80%)
 create mode 100644 src/main/java/org/codehaus/groovy/vmplugin/v16/ProxyDefaultMethodHandle.java
 create mode 100644 src/test/groovy/bugs/Groovy10113.groovy
 create mode 100644 src/test/groovy/bugs/Groovy10143.groovy
 rename src/test/groovy/bugs/{Groovy1465Bug.groovy => Groovy1465.groovy} (63%)
 rename src/test/groovy/bugs/{Groovy3904Bug.groovy => Groovy3904.groovy} (62%)
 create mode 100644 src/test/groovy/bugs/Groovy5239.groovy
 rename src/test/groovy/bugs/{Groovy8048Bug.groovy => Groovy8048.groovy} (65%)
 create mode 100644 src/test/groovy/bugs/Groovy8678.groovy
 create mode 100644 src/test/org/apache/groovy/lang/GroovyObjectHelperTest.groovy
 create mode 100644 src/test/org/codehaus/groovy/classgen/VerifierTest.groovy
 copy src/test/org/codehaus/groovy/tools/stubgenerator/{Groovy7306.groovy => Groovy10122.groovy} (67%)

[groovy] 01/01: GROOVY-9272: Support switch expression

Posted by su...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sunlan pushed a commit to branch GROOVY-9272
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit 24fcf3289b9dbaffc8ca8ed0afe0f8ccb6bee33e
Author: Daniel Sun <su...@apache.org>
AuthorDate: Sat May 22 13:49:17 2021 +0800

    GROOVY-9272: Support switch expression
---
 src/antlr/GroovyLexer.g4                           |   1 +
 src/antlr/GroovyParser.g4                          |  32 +++
 .../apache/groovy/parser/antlr4/AstBuilder.java    | 309 ++++++++++++++++++++-
 .../groovy/parser/antlr4/SemanticPredicates.java   |   3 +-
 .../core/SwitchExpression_01x.groovy}              |  32 +--
 .../core/SwitchExpression_02x.groovy}              |  35 +--
 .../core/SwitchExpression_03x.groovy}              |  32 +--
 .../core/SwitchExpression_04x.groovy}              |  33 +--
 .../core/SwitchExpression_05x.groovy}              |  31 +--
 .../core/SwitchExpression_06x.groovy}              |  35 +--
 .../core/SwitchExpression_07x.groovy}              |  42 ++-
 .../core/SwitchExpression_08x.groovy}              |  45 ++-
 .../core/SwitchExpression_09x.groovy}              |  32 +--
 .../core/SwitchExpression_10x.groovy}              |  58 ++--
 .../core/SwitchExpression_11x.groovy               | 111 ++++++++
 .../core/SwitchExpression_12x.groovy}              |  37 +--
 .../core/SwitchExpression_13x.groovy}              |  30 +-
 .../core/SwitchExpression_14x.groovy               |  79 ++++++
 .../core/SwitchExpression_15x.groovy}              |  35 +--
 .../core/SwitchExpression_16x.groovy}              |  39 ++-
 .../core/SwitchExpression_17x.groovy}              |  37 +--
 .../core/SwitchExpression_18x.groovy}              |  33 +--
 .../core/SwitchExpression_19x.groovy}              |  33 +--
 .../core/SwitchExpression_20x.groovy}              |  39 ++-
 .../core/SwitchExpression_21x.groovy}              |  39 ++-
 .../fail/SwitchExpression_01x.groovy}              |  31 +--
 .../fail/SwitchExpression_02x.groovy}              |  31 +--
 .../fail/SwitchExpression_03x.groovy}              |  32 +--
 .../fail/SwitchExpression_04x.groovy}              |  32 +--
 .../fail/SwitchExpression_05x.groovy}              |  31 +--
 .../fail/SwitchExpression_06x.groovy}              |  31 +--
 .../fail/SwitchExpression_07x.groovy}              |  31 +--
 .../fail/SwitchExpression_08x.groovy}              |  31 +--
 src/test/groovy/MethodInBadPositionTest.groovy     |   2 +-
 .../groovy/parser/antlr4/GroovyParserTest.groovy   |  44 ++-
 .../groovy/parser/antlr4/SyntaxErrorTest.groovy    |  13 +-
 .../apache/groovy/parser/antlr4/TestUtils.groovy   |   5 +-
 .../console/ui/text/SmartDocumentFilter.java       |   3 +-
 .../groovy-ginq/src/spec/doc/ginq-userguide.adoc   |   7 +
 .../test/org/apache/groovy/ginq/GinqTest.groovy    |  16 ++
 40 files changed, 869 insertions(+), 703 deletions(-)

diff --git a/src/antlr/GroovyLexer.g4 b/src/antlr/GroovyLexer.g4
index 53532b1..2c58768 100644
--- a/src/antlr/GroovyLexer.g4
+++ b/src/antlr/GroovyLexer.g4
@@ -417,6 +417,7 @@ fragment
 BOOLEAN       : 'boolean';
 
 BREAK         : 'break';
+YIELD         : 'yield';
 
 fragment
 BYTE          : 'byte';
diff --git a/src/antlr/GroovyParser.g4 b/src/antlr/GroovyParser.g4
index 07f1fae..839ce88 100644
--- a/src/antlr/GroovyParser.g4
+++ b/src/antlr/GroovyParser.g4
@@ -45,6 +45,7 @@ options {
 }
 
 @members {
+    private int inSwitchExpressionLevel = 0;
 
     public static class GroovyParserRuleContext extends ParserRuleContext implements NodeMetaDataHandler {
         private Map metaDataMap = null;
@@ -614,6 +615,11 @@ breakStatement
         identifier?
     ;
 
+yieldStatement
+    :   YIELD
+        expression
+    ;
+
 tryCatchStatement
     :   TRY resources? nls block
         (nls catchClause)*
@@ -634,6 +640,8 @@ statement
     |   THROW expression                                                                                    #throwStmtAlt
     |   breakStatement                                                                                      #breakStmtAlt
     |   continueStatement                                                                                   #continueStmtAlt
+    |   { inSwitchExpressionLevel > 0 }?
+        yieldStatement                                                                                      #yieldStmtAlt
     |   identifier COLON nls statement                                                                      #labeledStmtAlt
     |   assertStatement                                                                                     #assertStmtAlt
     |   localVariableDeclaration                                                                            #localVariableDeclarationStmtAlt
@@ -737,6 +745,26 @@ postfixExpression
     :   pathExpression op=(INC | DEC)?
     ;
 
+switchExpression
+@init {
+    inSwitchExpressionLevel++;
+}
+@after {
+    inSwitchExpressionLevel--;
+}
+    :   SWITCH expressionInPar nls LBRACE nls switchBlockStatementExpressionGroup* nls RBRACE
+    ;
+
+switchBlockStatementExpressionGroup
+    :   (switchExpressionLabel nls)+ blockStatements
+    ;
+
+switchExpressionLabel
+    :   (   CASE expressionList[true]
+        |   DEFAULT
+        ) ac=(ARROW | COLON)
+    ;
+
 expression
     // must come before postfixExpression to resovle the ambiguities between casting and call on parentheses expression, e.g. (int)(1 / 2)
     :   castParExpression castOperandExpression                                             #castExprAlt
@@ -744,6 +772,8 @@ expression
     // qualified names, array expressions, method invocation, post inc/dec
     |   postfixExpression                                                                   #postfixExprAlt
 
+    |   switchExpression                                                                    #switchExprAlt
+
     // ~(BNOT)/!(LNOT) (level 1)
     |   (BITNOT | NOT) nls expression                                                       #unaryNotExprAlt
 
@@ -1177,6 +1207,7 @@ identifier
 //  |   DEF
     |   TRAIT
     |   AS
+    |   YIELD
     ;
 
 builtInType
@@ -1229,6 +1260,7 @@ keywords
     |   VAR
     |   VOLATILE
     |   WHILE
+    |   YIELD
 
     |   NullLiteral
     |   BooleanLiteral
diff --git a/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java b/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java
index 3505867..eea1e49 100644
--- a/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java
+++ b/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java
@@ -214,6 +214,7 @@ import org.codehaus.groovy.ast.ASTNode;
 import org.codehaus.groovy.ast.AnnotationNode;
 import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.CodeVisitorSupport;
 import org.codehaus.groovy.ast.ConstructorNode;
 import org.codehaus.groovy.ast.EnumConstantClassNode;
 import org.codehaus.groovy.ast.FieldNode;
@@ -314,6 +315,13 @@ import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 import static groovy.lang.Tuple.tuple;
+import static org.apache.groovy.parser.antlr4.GroovyLangParser.ARROW;
+import static org.apache.groovy.parser.antlr4.GroovyLangParser.SwitchBlockStatementExpressionGroupContext;
+import static org.apache.groovy.parser.antlr4.GroovyLangParser.SwitchExprAltContext;
+import static org.apache.groovy.parser.antlr4.GroovyLangParser.SwitchExpressionContext;
+import static org.apache.groovy.parser.antlr4.GroovyLangParser.SwitchExpressionLabelContext;
+import static org.apache.groovy.parser.antlr4.GroovyLangParser.YieldStatementContext;
+import static org.apache.groovy.parser.antlr4.GroovyLangParser.YieldStmtAltContext;
 import static org.apache.groovy.parser.antlr4.GroovyParser.ADD;
 import static org.apache.groovy.parser.antlr4.GroovyParser.AS;
 import static org.apache.groovy.parser.antlr4.GroovyParser.CASE;
@@ -339,11 +347,14 @@ import static org.apache.groovy.parser.antlr4.GroovyParser.STATIC;
 import static org.apache.groovy.parser.antlr4.GroovyParser.SUB;
 import static org.apache.groovy.parser.antlr4.GroovyParser.VAR;
 import static org.apache.groovy.parser.antlr4.util.PositionConfigureUtils.configureAST;
+import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveVoid;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.assignX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.callX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.closureX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.returnS;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.stmt;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.varX;
 import static org.codehaus.groovy.classgen.asm.util.TypeUtil.isPrimitiveType;
-import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveVoid;
 import static org.codehaus.groovy.runtime.DefaultGroovyMethods.asBoolean;
 import static org.codehaus.groovy.runtime.DefaultGroovyMethods.last;
 
@@ -351,7 +362,6 @@ import static org.codehaus.groovy.runtime.DefaultGroovyMethods.last;
  * Builds the AST from the parse tree generated by Antlr4.
  */
 public class AstBuilder extends GroovyParserBaseVisitor<Object> {
-
     public AstBuilder(final SourceUnit sourceUnit, final boolean groovydocEnabled, final boolean runtimeGroovydocEnabled) {
         this.sourceUnit = sourceUnit;
         this.moduleNode = new ModuleNode(sourceUnit);
@@ -1009,6 +1019,11 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
 
     @Override
     public ReturnStatement visitReturnStmtAlt(final ReturnStmtAltContext ctx) {
+        GroovyParserRuleContext gprc = switchExpressionRuleContextStack.peek();
+        if (gprc instanceof SwitchExpressionContext) {
+            throw createParsingFailedException("switch expression does not support `return`", ctx);
+        }
+
         return configureAST(new ReturnStatement(asBoolean(ctx.expression())
                         ? (Expression) this.visit(ctx.expression())
                         : ConstantExpression.EMPTY_EXPRESSION),
@@ -1037,6 +1052,11 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
             throw createParsingFailedException("break statement is only allowed inside loops or switches", ctx);
         }
 
+        GroovyParserRuleContext gprc = switchExpressionRuleContextStack.peek();
+        if (gprc instanceof SwitchExpressionContext) {
+            throw createParsingFailedException("switch expression does not support `break`", ctx);
+        }
+
         String label = asBoolean(ctx.identifier())
                 ? this.visitIdentifier(ctx.identifier())
                 : null;
@@ -1045,11 +1065,28 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
     }
 
     @Override
+    public ReturnStatement visitYieldStatement(YieldStatementContext ctx) {
+        ReturnStatement returnStatement = (ReturnStatement) returnS((Expression) this.visit(ctx.expression()));
+        returnStatement.putNodeMetaData(IS_YIELD_STATEMENT, true);
+        return configureAST(returnStatement, ctx);
+    }
+
+    @Override
+    public ReturnStatement visitYieldStmtAlt(YieldStmtAltContext ctx) {
+        return configureAST(this.visitYieldStatement(ctx.yieldStatement()), ctx);
+    }
+
+    @Override
     public ContinueStatement visitContinueStatement(final ContinueStatementContext ctx) {
         if (visitingLoopStatementCount == 0) {
             throw createParsingFailedException("continue statement is only allowed inside loops", ctx);
         }
 
+        GroovyParserRuleContext gprc = switchExpressionRuleContextStack.peek();
+        if (gprc instanceof SwitchExpressionContext) {
+            throw createParsingFailedException("switch expression does not support `continue`", ctx);
+        }
+
         String label = asBoolean(ctx.identifier())
                 ? this.visitIdentifier(ctx.identifier())
                 : null;
@@ -1058,6 +1095,238 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
 
     }
 
+    @Override
+    public Expression visitSwitchExprAlt(SwitchExprAltContext ctx) {
+        return configureAST(this.visitSwitchExpression(ctx.switchExpression()), ctx);
+    }
+
+    /**
+     * <pre>
+     * switch(a) {
+     *     case 0, 1  ->   'a';
+     *     case 2     ->   'b';
+     *     default    ->   'z';
+     * }
+     * </pre>
+     * the above code will be transformed to:
+     * <pre>
+     * {->
+     *     switch(a) {
+     *         case 0:
+     *         case 1:  return 'a';
+     *         case 2:  return 'b';
+     *         default: return 'z';
+     *     }
+     * }()
+     * </pre>
+     *
+     * @param ctx the parse tree
+     * @return {@link MethodCallExpression} instance
+     */
+    @Override
+    public MethodCallExpression visitSwitchExpression(SwitchExpressionContext ctx) {
+        switchExpressionRuleContextStack.push(ctx);
+        try {
+            validateSwitchExpressionLabels(ctx);
+            List<Statement> statementList =
+                    ctx.switchBlockStatementExpressionGroup().stream()
+                            .map(e -> this.visitSwitchBlockStatementExpressionGroup(e))
+                            .reduce(new LinkedList<>(), (r, e) -> {
+                                r.addAll(e);
+                                return r;
+                            });
+
+            List<CaseStatement> caseStatementList = new LinkedList<>();
+            List<Statement> defaultStatementList = new LinkedList<>();
+
+            statementList.forEach(e -> {
+                if (e instanceof CaseStatement) {
+                    caseStatementList.add((CaseStatement) e);
+                } else if (isTrue(e, IS_SWITCH_DEFAULT)) {
+                    defaultStatementList.add(e);
+                }
+            });
+
+            int defaultStatementListSize = defaultStatementList.size();
+            if (defaultStatementListSize > 1) {
+                throw createParsingFailedException("switch expression should have only one default case, which should appear at last", defaultStatementList.get(0));
+            }
+
+            if (defaultStatementListSize > 0 && last(statementList) instanceof CaseStatement) {
+                throw createParsingFailedException("default case should appear at last", defaultStatementList.get(0));
+            }
+
+            SwitchStatement switchStatement = configureAST(
+                    new SwitchStatement(
+                            this.visitExpressionInPar(ctx.expressionInPar()),
+                            caseStatementList,
+                            defaultStatementListSize == 0 ? EmptyStatement.INSTANCE : defaultStatementList.get(0)
+                    ),
+                    ctx);
+
+            MethodCallExpression callClosure = callX(
+                    configureAST(
+                            closureX(null, createBlockStatement(switchStatement)),
+                            ctx
+                    ), "call");
+            callClosure.setImplicitThis(false);
+
+            return configureAST(callClosure, ctx);
+        } finally {
+            switchExpressionRuleContextStack.pop();
+        }
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public List<Statement> visitSwitchBlockStatementExpressionGroup(SwitchBlockStatementExpressionGroupContext ctx) {
+        int labelCnt = ctx.switchExpressionLabel().size();
+        List<Token> firstLabelHolder = new ArrayList<>(1);
+        final int[] arrowCntHolder = new int[1];
+
+        return (List<Statement>) ctx.switchExpressionLabel().stream()
+                .map(e -> (Object) this.visitSwitchExpressionLabel(e))
+                .reduce(new ArrayList<Statement>(4), (r, e) -> {
+                    List<Statement> statementList = (List<Statement>) r;
+                    Tuple3<Token, List<Expression>, Integer> tuple = (Tuple3<Token, List<Expression>, Integer>) e;
+
+                    boolean isArrow = ARROW == tuple.getV3();
+                    if (isArrow) {
+                        if (++arrowCntHolder[0] > 1 && !firstLabelHolder.isEmpty()) {
+                            throw createParsingFailedException("`case ... ->` does not support falling through cases", firstLabelHolder.get(0));
+                        }
+                    }
+
+                    boolean isLast = labelCnt - 1 == statementList.size();
+
+                    BlockStatement codeBlock = this.visitBlockStatements(ctx.blockStatements());
+                    List<Statement> statements = codeBlock.getStatements();
+                    int statementsCnt = statements.size();
+                    if (0 == statementsCnt) {
+                        throw createParsingFailedException("`yield` is expected", ctx.blockStatements());
+                    }
+
+                    if (statementsCnt > 1) {
+                        throw new GroovyBugError("statements count should be 1, but the count is actually: " + statementsCnt);
+                    }
+
+                    if (!isArrow) {
+                        boolean[] hasYieldHolder = new boolean[1];
+                        boolean[] hasThrowHolder = new boolean[1];
+                        codeBlock.visit(new CodeVisitorSupport() {
+                            @Override
+                            public void visitReturnStatement(ReturnStatement statement) {
+                                if (isTrue(statement, IS_YIELD_STATEMENT)) {
+                                    hasYieldHolder[0] = true;
+                                    return;
+                                }
+
+                                super.visitReturnStatement(statement);
+                            }
+
+                            @Override
+                            public void visitThrowStatement(ThrowStatement statement) {
+                                hasThrowHolder[0] = true;
+                            }
+                        });
+                        if (!(hasYieldHolder[0] || hasThrowHolder[0])) {
+                            throw createParsingFailedException("`yield` or `throw` is expected", ctx.blockStatements());
+                        }
+                    }
+
+                    Statement exprOrBlockStatement = statements.get(0);
+                    if (exprOrBlockStatement instanceof BlockStatement) {
+                        BlockStatement blockStatement = (BlockStatement) exprOrBlockStatement;
+                        List<Statement> branchStatementList = blockStatement.getStatements();
+                        if (1 == branchStatementList.size()) {
+                            exprOrBlockStatement = branchStatementList.get(0);
+                        }
+                    }
+
+                    if (!(exprOrBlockStatement instanceof ReturnStatement || exprOrBlockStatement instanceof ThrowStatement)) {
+                        MethodCallExpression callClosure = callX(
+                                configureAST(
+                                        closureX(null, exprOrBlockStatement),
+                                        exprOrBlockStatement
+                                ), "call");
+                        callClosure.setImplicitThis(false);
+
+                        codeBlock = configureAST(
+                                createBlockStatement(configureAST(
+                                        returnS(
+                                                exprOrBlockStatement instanceof ExpressionStatement
+                                                        ? ((ExpressionStatement) exprOrBlockStatement).getExpression()
+                                                        : callClosure
+                                        ),
+                                        exprOrBlockStatement
+                                )),
+                                exprOrBlockStatement
+                        );
+                    }
+
+                    switch (tuple.getV1().getType()) {
+                        case CASE: {
+                            if (!asBoolean(statementList)) {
+                                firstLabelHolder.add(tuple.getV1());
+                            }
+
+                            for (int i = 0, n = tuple.getV2().size(); i < n; i++) {
+                                Expression expr = tuple.getV2().get(i);
+
+                                statementList.add(
+                                        configureAST(
+                                                new CaseStatement(
+                                                        expr,
+
+                                                        // check whether processing the last label. if yes, block statement should be attached.
+                                                        (isLast && i == n - 1) ? codeBlock
+                                                                : EmptyStatement.INSTANCE
+                                                ),
+                                                firstLabelHolder.get(0)));
+                            }
+
+                            break;
+                        }
+                        case DEFAULT: {
+                            codeBlock.putNodeMetaData(IS_SWITCH_DEFAULT, true);
+
+                            statementList.add(
+                                    // this.configureAST(codeBlock, tuple.getKey())
+                                    codeBlock
+                            );
+
+                            break;
+                        }
+                    }
+
+                    return statementList;
+                });
+    }
+
+    private void validateSwitchExpressionLabels(SwitchExpressionContext ctx) {
+        Map<String, List<SwitchExpressionLabelContext>> acMap =
+                ctx.switchBlockStatementExpressionGroup().stream()
+                        .flatMap(e -> e.switchExpressionLabel().stream())
+                        .collect(Collectors.groupingBy(e -> e.ac.getText()));
+        if (acMap.size() > 1) {
+            List<SwitchExpressionLabelContext> lastSelcList = acMap.values().stream().reduce((prev, next) -> next).orElse(null);
+            throw createParsingFailedException(acMap.keySet().stream().collect(Collectors.joining("` and `", "`", "`")) + " cannot be used together", lastSelcList.get(0).ac);
+        }
+    }
+
+    @Override
+    public Tuple3<Token, List<Expression>, Integer> visitSwitchExpressionLabel(SwitchExpressionLabelContext ctx) {
+        final Integer acType = ctx.ac.getType();
+        if (asBoolean(ctx.CASE())) {
+            return tuple(ctx.CASE().getSymbol(), this.visitExpressionList(ctx.expressionList()), acType);
+        } else if (asBoolean(ctx.DEFAULT())) {
+            return tuple(ctx.DEFAULT().getSymbol(), Collections.singletonList(EmptyExpression.INSTANCE), acType);
+        }
+
+        throw createParsingFailedException("Unsupported switch expression label: " + ctx.getText(), ctx);
+    }
+
+
     // } statement -------------------------------------------------------------
 
     @Override
@@ -3619,7 +3888,12 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
 
     @Override
     public LambdaExpression visitStandardLambdaExpression(final StandardLambdaExpressionContext ctx) {
-        return configureAST(this.createLambda(ctx.standardLambdaParameters(), ctx.lambdaBody()), ctx);
+        switchExpressionRuleContextStack.push(ctx);
+        try {
+            return configureAST(this.createLambda(ctx.standardLambdaParameters(), ctx.lambdaBody()), ctx);
+        } finally {
+            switchExpressionRuleContextStack.pop();
+        }
     }
 
     private LambdaExpression createLambda(final StandardLambdaParametersContext standardLambdaParametersContext, final LambdaBodyContext lambdaBodyContext) {
@@ -3656,22 +3930,27 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
 
     @Override
     public ClosureExpression visitClosure(final ClosureContext ctx) {
-        visitingClosureCount += 1;
+        switchExpressionRuleContextStack.push(ctx);
+        try {
+            visitingClosureCount += 1;
 
-        Parameter[] parameters = asBoolean(ctx.formalParameterList())
-                ? this.visitFormalParameterList(ctx.formalParameterList())
-                : null;
+            Parameter[] parameters = asBoolean(ctx.formalParameterList())
+                    ? this.visitFormalParameterList(ctx.formalParameterList())
+                    : null;
 
-        if (!asBoolean(ctx.ARROW())) {
-            parameters = Parameter.EMPTY_ARRAY;
-        }
+            if (!asBoolean(ctx.ARROW())) {
+                parameters = Parameter.EMPTY_ARRAY;
+            }
 
-        Statement code = this.visitBlockStatementsOpt(ctx.blockStatementsOpt());
-        ClosureExpression result = configureAST(new ClosureExpression(parameters, code), ctx);
+            Statement code = this.visitBlockStatementsOpt(ctx.blockStatementsOpt());
+            ClosureExpression result = configureAST(new ClosureExpression(parameters, code), ctx);
 
-        visitingClosureCount -= 1;
+            visitingClosureCount -= 1;
 
-        return result;
+            return result;
+        } finally {
+            switchExpressionRuleContextStack.pop();
+        }
     }
 
     @Override
@@ -4664,6 +4943,7 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
     private final List<ClassNode> classNodeList = new LinkedList<>();
     private final Deque<ClassNode> classNodeStack = new ArrayDeque<>();
     private final Deque<List<InnerClassNode>> anonymousInnerClassesDefinedInMethodStack = new ArrayDeque<>();
+    private final Deque<GroovyParserRuleContext> switchExpressionRuleContextStack = new ArrayDeque<>();
 
     private Tuple2<GroovyParserRuleContext, Exception> numberFormatError;
 
@@ -4725,4 +5005,5 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
     private static final String INTEGER_LITERAL_TEXT = "_INTEGER_LITERAL_TEXT";
     private static final String FLOATING_POINT_LITERAL_TEXT = "_FLOATING_POINT_LITERAL_TEXT";
     private static final String ENCLOSING_INSTANCE_EXPRESSION = "_ENCLOSING_INSTANCE_EXPRESSION";
+    private static final String IS_YIELD_STATEMENT = "_IS_YIELD_STATEMENT";
 }
diff --git a/src/main/java/org/apache/groovy/parser/antlr4/SemanticPredicates.java b/src/main/java/org/apache/groovy/parser/antlr4/SemanticPredicates.java
index 78e5877..addfd47 100644
--- a/src/main/java/org/apache/groovy/parser/antlr4/SemanticPredicates.java
+++ b/src/main/java/org/apache/groovy/parser/antlr4/SemanticPredicates.java
@@ -42,6 +42,7 @@ import static org.apache.groovy.parser.antlr4.GroovyParser.PathExpressionContext
 import static org.apache.groovy.parser.antlr4.GroovyParser.PostfixExprAltContext;
 import static org.apache.groovy.parser.antlr4.GroovyParser.PostfixExpressionContext;
 import static org.apache.groovy.parser.antlr4.GroovyParser.StringLiteral;
+import static org.apache.groovy.parser.antlr4.GroovyParser.YIELD;
 import static org.apache.groovy.parser.antlr4.util.StringUtils.matches;
 
 /**
@@ -141,7 +142,7 @@ public class SemanticPredicates {
     public static boolean isInvalidMethodDeclaration(TokenStream ts) {
         int tokenType = ts.LT(1).getType();
 
-        return (Identifier == tokenType || CapitalizedIdentifier == tokenType || StringLiteral == tokenType)
+        return (Identifier == tokenType || CapitalizedIdentifier == tokenType || StringLiteral == tokenType || YIELD == tokenType)
                 && LPAREN == (ts.LT(2).getType());
     }
 
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy b/src/test-resources/core/SwitchExpression_01x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/core/SwitchExpression_01x.groovy
index 3b288ca..448719e 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/core/SwitchExpression_01x.groovy
@@ -16,30 +16,10 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
-
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || msg.contains("Unexpected input: '('")
-    }
-
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || msg.contains("Unexpected input: '('")
-    }
-}
\ No newline at end of file
+def a = 6
+def result = switch(a) {
+    case 8 -> 'b'
+    default -> 'z'
+}
+assert 'z' == result
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy b/src/test-resources/core/SwitchExpression_02x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/core/SwitchExpression_02x.groovy
index 3b288ca..5574d94 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/core/SwitchExpression_02x.groovy
@@ -16,30 +16,15 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
+def a = 6
+def result = switch(a) {
+    case 6 -> 'a'
+}
+assert 'a' == result
 
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || msg.contains("Unexpected input: '('")
-    }
-
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || msg.contains("Unexpected input: '('")
-    }
-}
\ No newline at end of file
+a = 9
+result = switch(a) {
+    case 6 -> 'a'
+}
+assert null == result
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy b/src/test-resources/core/SwitchExpression_03x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/core/SwitchExpression_03x.groovy
index 3b288ca..ef46adb 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/core/SwitchExpression_03x.groovy
@@ -16,30 +16,10 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
-
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || msg.contains("Unexpected input: '('")
-    }
-
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || msg.contains("Unexpected input: '('")
-    }
-}
\ No newline at end of file
+def a = 6
+def result = switch(a) {
+    case 6, 8 -> 'b'
+    default -> 'z'
+}
+assert 'b' == result
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy b/src/test-resources/core/SwitchExpression_04x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/core/SwitchExpression_04x.groovy
index 3b288ca..8b773cb 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/core/SwitchExpression_04x.groovy
@@ -16,30 +16,11 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
-
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || msg.contains("Unexpected input: '('")
-    }
-
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || msg.contains("Unexpected input: '('")
-    }
-}
\ No newline at end of file
+def a = 9
+def result = switch(a) {
+    case 6, 8 -> 'b'
+    case 9 -> 'c'
+    default -> 'z'
+}
+assert 'c' == result
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy b/src/test-resources/core/SwitchExpression_05x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/core/SwitchExpression_05x.groovy
index 3b288ca..5a52c93 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/core/SwitchExpression_05x.groovy
@@ -16,30 +16,9 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
-
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || msg.contains("Unexpected input: '('")
-    }
-
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || msg.contains("Unexpected input: '('")
-    }
-}
\ No newline at end of file
+def a = 6
+def result = switch(a) {
+    case 6, 8 -> 1 + 2
+}
+assert 3 == result
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy b/src/test-resources/core/SwitchExpression_06x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/core/SwitchExpression_06x.groovy
index 3b288ca..f864a24 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/core/SwitchExpression_06x.groovy
@@ -16,30 +16,15 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
+def a = 6
+def result = switch(a) {
+    case 6, 8 -> 1.plus 2
+}
+assert 3 == result
 
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || msg.contains("Unexpected input: '('")
-    }
-
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || msg.contains("Unexpected input: '('")
-    }
-}
\ No newline at end of file
+a = 8
+result = switch(a) {
+    case 6, 8 -> 1.plus 2
+}
+assert 3 == result
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy b/src/test-resources/core/SwitchExpression_07x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/core/SwitchExpression_07x.groovy
index 3b288ca..07e375b 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/core/SwitchExpression_07x.groovy
@@ -16,30 +16,24 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
+def a = 9
+def result = switch(a) {
+    case 6, 8 -> 1.plus 2
+    default -> 1.plus 5
+}
+assert 6 == result
 
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || msg.contains("Unexpected input: '('")
-    }
+a = 6
+result = switch(a) {
+    case 6, 8 -> 1.plus 2
+    default -> 1.plus 5
+}
+assert 3 == result
 
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || msg.contains("Unexpected input: '('")
-    }
-}
\ No newline at end of file
+a = 8
+result = switch(a) {
+    case 6, 8 -> 1.plus 2
+    default -> 1.plus 5
+}
+assert 3 == result
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy b/src/test-resources/core/SwitchExpression_08x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/core/SwitchExpression_08x.groovy
index 3b288ca..0b171f2 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/core/SwitchExpression_08x.groovy
@@ -16,30 +16,27 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
+def a = 6
+def result = switch(a) {
+    case 6 -> { 'a' }
+}
+assert 'a' == result
 
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || msg.contains("Unexpected input: '('")
-    }
+a = 6
+result = switch(a) {
+    case 6 -> { yield 'a' }
+}
+assert 'a' == result
 
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || msg.contains("Unexpected input: '('")
-    }
-}
\ No newline at end of file
+a = 8
+result = switch(a) {
+    case 6, 8 -> { yield 'a' }
+}
+assert 'a' == result
+
+a = 9
+result = switch(a) {
+    case 6, 8 -> { yield 'a' }
+}
+assert null == result
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy b/src/test-resources/core/SwitchExpression_09x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/core/SwitchExpression_09x.groovy
index 3b288ca..14e0dd0 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/core/SwitchExpression_09x.groovy
@@ -16,30 +16,14 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
+def a = 9
+def result = switch(a) {
+    case 6 -> { yield 'a' }
+    default -> { yield 'z' }
+}
+assert 'z' == result
+
+
 
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || msg.contains("Unexpected input: '('")
-    }
 
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || msg.contains("Unexpected input: '('")
-    }
-}
\ No newline at end of file
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy b/src/test-resources/core/SwitchExpression_10x.groovy
similarity index 52%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/core/SwitchExpression_10x.groovy
index 3b288ca..450fb24 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/core/SwitchExpression_10x.groovy
@@ -16,30 +16,44 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
+def a = 6
+def result = switch(a) {
+    case 6 -> {
+        def n = 1
+        yield 'a' + n
+    }
+    default -> { yield 'z' }
+}
+assert 'a1' == result
+
+a = 8
+result = switch(a) {
+    case 6, 8 -> {
+        def n = 1
+        yield 'a' + n
+    }
+    default -> { yield 'z' }
+}
+assert 'a1' == result
 
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || msg.contains("Unexpected input: '('")
+a = 9
+result = switch(a) {
+    case 6, 8 -> {
+        def n = 1
+        yield 'a' + n
     }
+    default -> { yield 'z' }
+}
+assert 'z' == result
 
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || msg.contains("Unexpected input: '('")
+a = 9
+result = switch(a) {
+    case 6, 8 -> {
+        def n = 1
+        yield 'a' + n
     }
-}
\ No newline at end of file
+    default -> yield 'z'
+}
+assert 'z' == result
+
diff --git a/src/test-resources/core/SwitchExpression_11x.groovy b/src/test-resources/core/SwitchExpression_11x.groovy
new file mode 100644
index 0000000..b8d55f1
--- /dev/null
+++ b/src/test-resources/core/SwitchExpression_11x.groovy
@@ -0,0 +1,111 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+try {
+    def a = 6
+    def result = switch(a) {
+        case 6 : throw new RuntimeException('a')
+    }
+} catch (e) {
+    assert 'a' == e.message
+}
+
+a = 6
+result = switch(a) {
+    case 6 : yield 'a'
+}
+assert 'a' == result
+
+a = 8
+result = switch(a) {
+    case 6 : yield 'a'
+    default: yield 'b'
+}
+assert 'b' == result
+
+a = 9
+result = switch(a) {
+    case 6, 9 : yield 'a'
+    default: yield 'b'
+}
+assert 'a' == result
+
+a = 7
+result = switch(a) {
+    case 7:
+    case 6, 9 : yield 'a'
+    default: yield 'b'
+}
+assert 'a' == result
+
+
+a = 10
+result = switch(a) {
+    case 7:
+    case 6, 9 : yield 'a'
+    case 10:
+    case 11: yield 'c'
+    default: yield 'b'
+}
+assert 'c' == result
+
+a = 10
+result = switch(a) {
+    case 7:
+    case 6, 9 : yield 'a'
+    case 10:
+    case 11: {
+            def x = 1
+            yield 'c' + x
+        }
+    default: yield 'b'
+}
+assert 'c1' == result
+
+
+a = 6
+result = switch(a) {
+    case 6 : yield 'a'
+}
+assert 'a' == result
+
+a = 6
+result = switch(a) {
+    default : yield 'b'
+}
+assert 'b' == result
+
+a = 6
+result = switch(a) {
+    case 6 : { yield 'a' }
+}
+assert 'a' == result
+
+a = 6
+result = switch(a) {
+    default : { yield 'b' }
+}
+assert 'b' == result
+
+a = 6
+result = switch(a) {
+    case 6  : yield 'a'
+    default : yield 'b'
+}
+assert 'a' == result
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy b/src/test-resources/core/SwitchExpression_12x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/core/SwitchExpression_12x.groovy
index 3b288ca..bbe8342 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/core/SwitchExpression_12x.groovy
@@ -16,30 +16,17 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
+def a = 6
+def result = switch(a) {
+    case 6 -> 'a'
+    default-> yield 'b'
+}
+assert 'a' == result
 
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || msg.contains("Unexpected input: '('")
-    }
-
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || msg.contains("Unexpected input: '('")
-    }
-}
\ No newline at end of file
+a = 6
+result = switch(a) {
+    case 6 -> 'a'
+    default -> yield 'b'
+}
+assert 'a' == result
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy b/src/test-resources/core/SwitchExpression_13x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/core/SwitchExpression_13x.groovy
index 3b288ca..4a2a7c8 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/core/SwitchExpression_13x.groovy
@@ -16,30 +16,10 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
+def yield (String msg) { return msg }
+def yield () { return 'b' }
 
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || msg.contains("Unexpected input: '('")
-    }
-
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || msg.contains("Unexpected input: '('")
-    }
-}
\ No newline at end of file
+def result = yield 'a'
+assert 'a' == result
+assert 'b'== yield()
diff --git a/src/test-resources/core/SwitchExpression_14x.groovy b/src/test-resources/core/SwitchExpression_14x.groovy
new file mode 100644
index 0000000..0a8a661
--- /dev/null
+++ b/src/test-resources/core/SwitchExpression_14x.groovy
@@ -0,0 +1,79 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+def test() {
+    def a = 2
+    def b = 1
+    def c = 0
+    def d = 99
+    def r = switch (a) {
+        case 0 -> 'a'
+        case 1 -> 'b'
+        case 2 -> 'c'
+        default -> 'z'
+    } + switch (b) {
+        case 0 -> 'a'
+        case 1 -> 'b'
+        case 2 -> 'c'
+        default -> 'z'
+    } + switch (c) {
+        case 0 -> 'a'
+        case 1 -> 'b'
+        case 2 -> 'c'
+        default -> 'z'
+    } + switch (d) {
+        case 0 -> 'a'
+        case 1 -> 'b'
+        case 2 -> 'c'
+        default -> 'z'
+    }
+    assert 'cbaz' == r
+}
+test()
+
+@groovy.transform.CompileStatic
+def testCS() {
+    def a = 2
+    def b = 1
+    def c = 0
+    def d = 99
+    def r = switch (a) {
+        case 0 -> 'a'
+        case 1 -> 'b'
+        case 2 -> 'c'
+        default -> 'z'
+    } + switch (b) {
+        case 0 -> 'a'
+        case 1 -> 'b'
+        case 2 -> 'c'
+        default -> 'z'
+    } + switch (c) {
+        case 0 -> 'a'
+        case 1 -> 'b'
+        case 2 -> 'c'
+        default -> 'z'
+    } + switch (d) {
+        case 0 -> 'a'
+        case 1 -> 'b'
+        case 2 -> 'c'
+        default -> 'z'
+    }
+    assert 'cbaz' == r
+}
+testCS()
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy b/src/test-resources/core/SwitchExpression_15x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/core/SwitchExpression_15x.groovy
index 3b288ca..58b3a12 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/core/SwitchExpression_15x.groovy
@@ -16,30 +16,15 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
-
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || msg.contains("Unexpected input: '('")
-    }
-
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || msg.contains("Unexpected input: '('")
+def a = 9
+def b = 8
+def result = switch(a) {
+    case 8 -> 'a'
+    case 9 -> switch(b) {
+        case 8 -> 'b'
+        default -> 'c'
     }
-}
\ No newline at end of file
+    default -> 'd'
+}
+assert 'b' == result
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy b/src/test-resources/core/SwitchExpression_16x.groovy
similarity index 52%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/core/SwitchExpression_16x.groovy
index 3b288ca..028d624 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/core/SwitchExpression_16x.groovy
@@ -16,30 +16,23 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
-
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || msg.contains("Unexpected input: '('")
+def a = 6
+try {
+    switch(a) {
+        case 8 -> 'b'
+        default -> throw new RuntimeException('z')
     }
+} catch (e) {
+    assert 'z' == e.message
+}
 
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || msg.contains("Unexpected input: '('")
+def r = switch(a) {
+    case 6 -> {
+        def x = 'a'
+        yield x
     }
-}
\ No newline at end of file
+    default -> throw new RuntimeException('z')
+}
+assert 'a' == r
+
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy b/src/test-resources/core/SwitchExpression_17x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/core/SwitchExpression_17x.groovy
index 3b288ca..aff965b 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/core/SwitchExpression_17x.groovy
@@ -16,30 +16,17 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
+def a = '123'
+def r = switch (a) {
+    case String -> 1
+    default -> 2
+}
+assert 1 == r
 
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || msg.contains("Unexpected input: '('")
-    }
-
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || msg.contains("Unexpected input: '('")
-    }
-}
\ No newline at end of file
+a = 123
+r = switch (a) {
+    case String -> 1
+    default -> 2
+}
+assert 2 == r
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy b/src/test-resources/core/SwitchExpression_18x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/core/SwitchExpression_18x.groovy
index 3b288ca..ba57d6b 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/core/SwitchExpression_18x.groovy
@@ -16,30 +16,11 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
-
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || msg.contains("Unexpected input: '('")
-    }
-
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || msg.contains("Unexpected input: '('")
-    }
-}
\ No newline at end of file
+cnt = 0
+void prt() { cnt++ }
+def a = '123'
+switch (a) {
+    case String -> { prt() }
+}
+assert 1 == cnt
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy b/src/test-resources/core/SwitchExpression_19x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/core/SwitchExpression_19x.groovy
index 3b288ca..f65840e 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/core/SwitchExpression_19x.groovy
@@ -16,30 +16,11 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
-
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || msg.contains("Unexpected input: '('")
-    }
-
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || msg.contains("Unexpected input: '('")
-    }
-}
\ No newline at end of file
+cnt = 0
+void prt() { cnt++ }
+def a = '123'
+switch (a) {
+    case String -> prt()
+}
+assert 1 == cnt
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy b/src/test-resources/core/SwitchExpression_20x.groovy
similarity index 52%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/core/SwitchExpression_20x.groovy
index 3b288ca..f0eec8d 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/core/SwitchExpression_20x.groovy
@@ -16,30 +16,25 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
+import groovy.transform.CompileStatic
 
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || msg.contains("Unexpected input: '('")
-    }
+@CompileStatic
+String same(String s) { s }
 
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
+@CompileStatic
+def meth() {
+    def a = 1
+    def r = switch (a) {
+        case 1 -> {
+            if (true) {
+                same 'a'
+            } else {
+                same 'b'
             }
-        ''')
-        assert msg.contains('Method definition not expected here')  || msg.contains("Unexpected input: '('")
+        }
     }
-}
\ No newline at end of file
+    r + 'z'
+}
+
+assert 'az' == meth()
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy b/src/test-resources/core/SwitchExpression_21x.groovy
similarity index 52%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/core/SwitchExpression_21x.groovy
index 3b288ca..55bac5a 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/core/SwitchExpression_21x.groovy
@@ -16,30 +16,25 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
+import groovy.transform.CompileStatic
 
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || msg.contains("Unexpected input: '('")
-    }
+@CompileStatic
+String same(String s) { s }
 
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
+@CompileStatic
+def meth() {
+    def a = 1
+    def r = switch (a) {
+        case 1 -> {
+            if (2 == 2) {
+                yield 'hello'
             }
-        ''')
-        assert msg.contains('Method definition not expected here')  || msg.contains("Unexpected input: '('")
+            yield 'hi'
+        }
+        case 2 -> 'Hello'
     }
-}
\ No newline at end of file
+    r + ', Daniel'
+}
+
+assert 'hello, Daniel' == meth()
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy b/src/test-resources/fail/SwitchExpression_01x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/fail/SwitchExpression_01x.groovy
index 3b288ca..df57b27 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/fail/SwitchExpression_01x.groovy
@@ -16,30 +16,9 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
-
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || msg.contains("Unexpected input: '('")
-    }
-
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || msg.contains("Unexpected input: '('")
-    }
-}
\ No newline at end of file
+def a = 6
+switch(a) {
+    case 8 ->
+    case 9 -> 'a'
+}
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy b/src/test-resources/fail/SwitchExpression_02x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/fail/SwitchExpression_02x.groovy
index 3b288ca..8112793 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/fail/SwitchExpression_02x.groovy
@@ -16,30 +16,9 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
-
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || msg.contains("Unexpected input: '('")
-    }
-
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || msg.contains("Unexpected input: '('")
-    }
-}
\ No newline at end of file
+def a = 6
+switch(a) {
+    case 8 ->
+    default -> 'b'
+}
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy b/src/test-resources/fail/SwitchExpression_03x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/fail/SwitchExpression_03x.groovy
index 3b288ca..64ddad8 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/fail/SwitchExpression_03x.groovy
@@ -16,30 +16,10 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
-
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || msg.contains("Unexpected input: '('")
-    }
-
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || msg.contains("Unexpected input: '('")
-    }
-}
\ No newline at end of file
+def a = 6
+switch(a) {
+    case 6 ->
+    case 8 ->
+    default -> 'b'
+}
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy b/src/test-resources/fail/SwitchExpression_04x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/fail/SwitchExpression_04x.groovy
index 3b288ca..82d52da 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/fail/SwitchExpression_04x.groovy
@@ -16,30 +16,10 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
-
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || msg.contains("Unexpected input: '('")
-    }
-
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || msg.contains("Unexpected input: '('")
-    }
-}
\ No newline at end of file
+def a = 6
+switch(a) {
+    case 6 -> 'a'
+    case 8 : yield 'b'
+    default -> 'c'
+}
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy b/src/test-resources/fail/SwitchExpression_05x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/fail/SwitchExpression_05x.groovy
index 3b288ca..13fbb69 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/fail/SwitchExpression_05x.groovy
@@ -16,30 +16,9 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
-
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || msg.contains("Unexpected input: '('")
-    }
-
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || msg.contains("Unexpected input: '('")
-    }
-}
\ No newline at end of file
+def a = 6
+def r = switch(a) {
+    case 6 : 'a'
+    default : 'c'
+}
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy b/src/test-resources/fail/SwitchExpression_06x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/fail/SwitchExpression_06x.groovy
index 3b288ca..a799824 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/fail/SwitchExpression_06x.groovy
@@ -16,30 +16,9 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
-
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || msg.contains("Unexpected input: '('")
-    }
-
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || msg.contains("Unexpected input: '('")
-    }
-}
\ No newline at end of file
+def a = 6
+def r = switch(a) {
+    case 6 : return 'a'
+    default : return 'c'
+}
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy b/src/test-resources/fail/SwitchExpression_07x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/fail/SwitchExpression_07x.groovy
index 3b288ca..592051c 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/fail/SwitchExpression_07x.groovy
@@ -16,30 +16,11 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
-
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || msg.contains("Unexpected input: '('")
-    }
-
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || msg.contains("Unexpected input: '('")
+def a = 7
+while (a-- > 0) {
+    def r = switch(a) {
+        case 6 : break
+        default : return 'c'
     }
-}
\ No newline at end of file
+}
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy b/src/test-resources/fail/SwitchExpression_08x.groovy
similarity index 51%
copy from src/test/groovy/MethodInBadPositionTest.groovy
copy to src/test-resources/fail/SwitchExpression_08x.groovy
index 3b288ca..3c61cfd 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test-resources/fail/SwitchExpression_08x.groovy
@@ -16,30 +16,11 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy
 
-import gls.CompilableTestSupport
-
-class MethodInBadPositionTest extends CompilableTestSupport {
-    /** GROOVY-4215 */
-    void testMethodDefinitionInClosure() {
-        def msg = shouldNotCompile('''
-            { ->
-                def say(String msg) {
-                  println(msg)
-                }
-            }()
-        ''')
-        assert msg.contains('Method definition not expected here') || msg.contains("Unexpected input: '('")
-    }
-
-    /** GROOVY-4215 */
-    void testXMethodDefinitionInSwitch() {
-        def msg = shouldNotCompile('''
-            switch(1) {
-                case 1: def say(){}
-            }
-        ''')
-        assert msg.contains('Method definition not expected here')  || msg.contains("Unexpected input: '('")
+def a = 7
+while (a-- > 0) {
+    def r = switch(a) {
+        case 6 : continue
+        default : return 'c'
     }
-}
\ No newline at end of file
+}
diff --git a/src/test/groovy/MethodInBadPositionTest.groovy b/src/test/groovy/MethodInBadPositionTest.groovy
index 3b288ca..453d75c 100644
--- a/src/test/groovy/MethodInBadPositionTest.groovy
+++ b/src/test/groovy/MethodInBadPositionTest.groovy
@@ -40,6 +40,6 @@ class MethodInBadPositionTest extends CompilableTestSupport {
                 case 1: def say(){}
             }
         ''')
-        assert msg.contains('Method definition not expected here')  || msg.contains("Unexpected input: '('")
+        assert msg.contains('Method definition not expected here')  || msg.contains("Unexpected input: '('") || msg.contains("Unexpected input: 'switch(1)")
     }
 }
\ No newline at end of file
diff --git a/src/test/org/apache/groovy/parser/antlr4/GroovyParserTest.groovy b/src/test/org/apache/groovy/parser/antlr4/GroovyParserTest.groovy
index f7f0e59..e15fb98 100644
--- a/src/test/org/apache/groovy/parser/antlr4/GroovyParserTest.groovy
+++ b/src/test/org/apache/groovy/parser/antlr4/GroovyParserTest.groovy
@@ -412,15 +412,39 @@ final class GroovyParserTest extends GroovyTestCase {
     }
 
     void "test groovy core - var"() {
-        doRunAndTestAntlr4('core/Var_01x.groovy');
+        doRunAndTestAntlr4('core/Var_01x.groovy')
     }
 
     void "test groovy core - String"() {
-        doRunAndTestAntlr4('core/String_01x.groovy');
+        doRunAndTestAntlr4('core/String_01x.groovy')
     }
 
     void "test groovy core - NonStaticClass"() {
-        doRunAndTestAntlr4('core/NonStaticClass_01x.groovy');
+        doRunAndTestAntlr4('core/NonStaticClass_01x.groovy')
+    }
+
+    void "test groovy core - SwitchExpression"() {
+        doRunAndTestAntlr4('core/SwitchExpression_01x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_02x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_03x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_04x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_05x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_06x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_07x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_08x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_09x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_10x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_11x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_12x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_13x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_14x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_15x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_16x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_17x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_18x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_19x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_20x.groovy')
+        doRunAndTestAntlr4('core/SwitchExpression_21x.groovy')
     }
 
     void "test groovy core - BUG"() {
@@ -445,30 +469,30 @@ final class GroovyParserTest extends GroovyTestCase {
     }
 
     void "test groovy core - GROOVY-9427"() {
-        doTest('bugs/BUG-GROOVY-9427.groovy');
+        doTest('bugs/BUG-GROOVY-9427.groovy')
     }
 
     void "test groovy core - GROOVY-9433"() {
-        doTest('bugs/BUG-GROOVY-9433.groovy');
+        doTest('bugs/BUG-GROOVY-9433.groovy')
     }
 
     void "test groovy core - GROOVY-9449"() {
-        doTest('bugs/BUG-GROOVY-9449.groovy');
+        doTest('bugs/BUG-GROOVY-9449.groovy')
     }
 
     void "test groovy core - GROOVY-9511"() {
-        doTest('bugs/BUG-GROOVY-9511.groovy', [MethodNode]);
+        doTest('bugs/BUG-GROOVY-9511.groovy', [MethodNode])
     }
 
     void "test groovy core - GROOVY-9507"() {
-        doTest('bugs/BUG-GROOVY-9507.groovy');
+        doTest('bugs/BUG-GROOVY-9507.groovy')
     }
 
     void "test groovy core - GROOVY-9522"() {
-        doTest('bugs/BUG-GROOVY-9522.groovy');
+        doTest('bugs/BUG-GROOVY-9522.groovy')
     }
 
     void "test groovy core - GROOVY-9692"() {
-        doTest('bugs/BUG-GROOVY-9692.groovy');
+        doTest('bugs/BUG-GROOVY-9692.groovy')
     }
 }
diff --git a/src/test/org/apache/groovy/parser/antlr4/SyntaxErrorTest.groovy b/src/test/org/apache/groovy/parser/antlr4/SyntaxErrorTest.groovy
index 3b993f7..e5ecbae 100644
--- a/src/test/org/apache/groovy/parser/antlr4/SyntaxErrorTest.groovy
+++ b/src/test/org/apache/groovy/parser/antlr4/SyntaxErrorTest.groovy
@@ -241,7 +241,7 @@ final class SyntaxErrorTest extends GroovyTestCase {
     }
 
     void 'test groovy core - AnnotationDeclaration 1'() {
-        TestUtils.doRunAndShouldFail('fail/AnnotationDeclaration_01x.groovy');
+        TestUtils.doRunAndShouldFail('fail/AnnotationDeclaration_01x.groovy')
     }
 
     void 'test groovy core - AnnotationDeclaration 2'() {
@@ -420,6 +420,17 @@ final class SyntaxErrorTest extends GroovyTestCase {
         TestUtils.doRunAndShouldFail('fail/Array_02x.groovy')
     }
 
+    void "test groovy core - SwitchExpression"() {
+        TestUtils.doRunAndShouldFail('fail/SwitchExpression_01x.groovy')
+        TestUtils.doRunAndShouldFail('fail/SwitchExpression_02x.groovy')
+        TestUtils.doRunAndShouldFail('fail/SwitchExpression_03x.groovy')
+        TestUtils.doRunAndShouldFail('fail/SwitchExpression_04x.groovy')
+        TestUtils.doRunAndShouldFail('fail/SwitchExpression_05x.groovy')
+        TestUtils.doRunAndShouldFail('fail/SwitchExpression_06x.groovy')
+		TestUtils.doRunAndShouldFail('fail/SwitchExpression_07x.groovy')
+		TestUtils.doRunAndShouldFail('fail/SwitchExpression_08x.groovy')
+    }
+
     @NotYetImplemented
     void 'test error alternative - Missing ")" 1'() {
         def err = expectParseError '''\
diff --git a/src/test/org/apache/groovy/parser/antlr4/TestUtils.groovy b/src/test/org/apache/groovy/parser/antlr4/TestUtils.groovy
index 3310447..c8aae4b 100644
--- a/src/test/org/apache/groovy/parser/antlr4/TestUtils.groovy
+++ b/src/test/org/apache/groovy/parser/antlr4/TestUtils.groovy
@@ -198,7 +198,7 @@ final class TestUtils {
     }
 
     static void doRunAndTestAntlr4(String path, CompilerConfiguration compilerConfiguration = CompilerConfiguration.DEFAULT) {
-        assert executeScript(createAntlr4Shell(compilerConfiguration), "$RESOURCES_PATH/$path")
+        assert executeScript(createAntlr4Shell(compilerConfiguration), path)
     }
 
     static void doRunAndTestAntlr2(String path, CompilerConfiguration compilerConfiguration = CompilerConfiguration.DEFAULT) {
@@ -255,7 +255,8 @@ final class TestUtils {
     }
 
     private static boolean executeScript(GroovyShell shell, String path) {
-        def file = new File(path)
+        File file = new File("$RESOURCES_PATH/$path")
+        assert file.exists() : "Test resource not found: $file.absolutePath"
         try {
             shell.evaluate(file.text)
             return true
diff --git a/subprojects/groovy-console/src/main/groovy/groovy/console/ui/text/SmartDocumentFilter.java b/subprojects/groovy-console/src/main/groovy/groovy/console/ui/text/SmartDocumentFilter.java
index 4496873..cdf55b2 100644
--- a/subprojects/groovy-console/src/main/groovy/groovy/console/ui/text/SmartDocumentFilter.java
+++ b/subprojects/groovy-console/src/main/groovy/groovy/console/ui/text/SmartDocumentFilter.java
@@ -108,6 +108,7 @@ import static org.apache.groovy.parser.antlr4.GroovyLexer.VAR;
 import static org.apache.groovy.parser.antlr4.GroovyLexer.VOID;
 import static org.apache.groovy.parser.antlr4.GroovyLexer.VOLATILE;
 import static org.apache.groovy.parser.antlr4.GroovyLexer.WHILE;
+import static org.apache.groovy.parser.antlr4.GroovyLexer.YIELD;
 
 
 /**
@@ -378,7 +379,7 @@ public class SmartDocumentFilter extends DocumentFilter {
                 VAR, BuiltInPrimitiveType, ABSTRACT, ASSERT, BREAK, CASE, CATCH, CLASS, CONST, CONTINUE, DEFAULT, DO,
                 ELSE, ENUM, EXTENDS, FINAL, FINALLY, FOR, IF, GOTO, IMPLEMENTS, IMPORT, INSTANCEOF, INTERFACE,
                 NATIVE, NEW, PACKAGE, PRIVATE, PROTECTED, PUBLIC, RETURN, STATIC, STRICTFP, SUPER, SWITCH, SYNCHRONIZED,
-                THIS, THROW, THROWS, TRANSIENT, TRY, VOID, VOLATILE, WHILE, NullLiteral, BooleanLiteral)) {
+                THIS, THROW, THROWS, TRANSIENT, TRY, VOID, VOLATILE, WHILE, YIELD, NullLiteral, BooleanLiteral)) {
             Style style = createDefaultStyleByTokenType(t);
             StyleConstants.setBold(style, true);
             StyleConstants.setForeground(style, Color.BLUE.darker().darker());
diff --git a/subprojects/groovy-ginq/src/spec/doc/ginq-userguide.adoc b/subprojects/groovy-ginq/src/spec/doc/ginq-userguide.adoc
index 51dedae..fae4474 100644
--- a/subprojects/groovy-ginq/src/spec/doc/ginq-userguide.adoc
+++ b/subprojects/groovy-ginq/src/spec/doc/ginq-userguide.adoc
@@ -912,6 +912,13 @@ GINQ does not support `with` clause for now. We could define a temporary variabl
 include::../test/org/apache/groovy/ginq/GinqTest.groovy[tags=ginq_tips_12,indent=0]
 ----
 
+==== Alternative for `case-when`
+`case-when` of SQL could be replaced with switch expression:
+[source, groovy]
+----
+include::../test/org/apache/groovy/ginq/GinqTest.groovy[tags=ginq_tips_13,indent=0]
+----
+
 ==== Query JSON
 [source, groovy]
 ----
diff --git a/subprojects/groovy-ginq/src/spec/test/org/apache/groovy/ginq/GinqTest.groovy b/subprojects/groovy-ginq/src/spec/test/org/apache/groovy/ginq/GinqTest.groovy
index 92bf5bc..18182f1 100644
--- a/subprojects/groovy-ginq/src/spec/test/org/apache/groovy/ginq/GinqTest.groovy
+++ b/subprojects/groovy-ginq/src/spec/test/org/apache/groovy/ginq/GinqTest.groovy
@@ -5886,6 +5886,22 @@ class GinqTest {
     }
 
     @Test
+    void "testGinq - switch - 1"() {
+        assertGinqScript '''
+// tag::ginq_tips_13[]
+            assert ['a', 'b', 'c', 'c'] == GQ {
+                from n in [1, 2, 3, 4]
+                select switch (n) {
+                    case 1 -> 'a'
+                    case 2 -> 'b'
+                    default -> 'c'
+                }
+            }.toList()
+// end::ginq_tips_13[]
+        '''
+    }
+
+    @Test
     void "testGinq - shutdown - 0"() {
         assertScript '''
             import org.apache.groovy.ginq.provider.collection.runtime.QueryableHelper