This is an automated email from the ASF dual-hosted git repository.
emilles pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/master by this push:
new ed22eddeb7 reduce dynamic variables
ed22eddeb7 is described below
commit ed22eddeb7e86d0d69c3094a86510fbb409c6dda
Author: Eric Milles <[email protected]>
AuthorDate: Sat Feb 14 22:34:04 2026 -0600
reduce dynamic variables
---
.../groovy/classgen/asm/StatementWriter.java | 4 +-
src/spec/test/CoercionTest.groovy | 554 +++++++++++----------
2 files changed, 287 insertions(+), 271 deletions(-)
diff --git
a/src/main/java/org/codehaus/groovy/classgen/asm/StatementWriter.java
b/src/main/java/org/codehaus/groovy/classgen/asm/StatementWriter.java
index 309b4ae416..9af4e9c276 100644
--- a/src/main/java/org/codehaus/groovy/classgen/asm/StatementWriter.java
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/StatementWriter.java
@@ -474,12 +474,14 @@ public class StatementWriter {
writeStatementLabel(statement);
statement.getExpression().visit(controller.getAcg());
+ ClassNode exprType = controller.getOperandStack().getTopOperand();
+ if (ClassHelper.isPrimitiveType(exprType)) exprType =
ClassHelper.getWrapper(exprType);
// switch does not have a continue label; use enclosing continue label
CompileStack compileStack = controller.getCompileStack();
Label breakLabel = compileStack.pushSwitch();
- int switchVariableIndex =
compileStack.defineTemporaryVariable("switch", true);
+ int switchVariableIndex =
compileStack.defineTemporaryVariable("switch", exprType, true);
List<CaseStatement> caseStatements = statement.getCaseStatements();
int caseCount = caseStatements.size();
diff --git a/src/spec/test/CoercionTest.groovy
b/src/spec/test/CoercionTest.groovy
index c0dd0e9688..f44b6f46fd 100644
--- a/src/spec/test/CoercionTest.groovy
+++ b/src/spec/test/CoercionTest.groovy
@@ -17,287 +17,298 @@
* under the License.
*/
-final class CoercionTest extends groovy.test.GroovyTestCase {
+import org.junit.jupiter.api.Test
+import static groovy.test.GroovyAssert.assertScript
+
+final class CoercionTest {
+
+ @Test
void testStringToEnumValue() {
assertScript '''
- // tag::state_enum[]
- enum State {
- up,
- down
- }
- // end::state_enum[]
-
- try {
- // tag::enum_coerce_assignment[]
- State st = 'up'
- assert st == State.up
- // end::enum_coerce_assignment[]
- } catch (IllegalArgumentException err) {
- assert false:'Test should not have failed'
- }
-
- try {
- // tag::enum_coerce_assignment_wrong[]
- State st = 'not an enum value'
- // end::enum_coerce_assignment_wrong[]
- } catch (IllegalArgumentException err) {
- // woot!
- }
-
- try {
- // tag::enum_coerce_assignment_gstring[]
- def val = "up"
- State st = "${val}"
- assert st == State.up
- // end::enum_coerce_assignment_gstring[]
- } catch (IllegalArgumentException err) {
- assert false:'Test should not have failed'
- }
-
-
- // tag::enum_switch_method[]
- State switchState(State st) {
- switch (st) {
- case 'up':
- return State.down // explicit constant
- case 'down':
- return 'up' // implicit coercion for return types
+ // tag::state_enum[]
+ enum State {
+ up,
+ down
+ }
+ // end::state_enum[]
+
+ try {
+ // tag::enum_coerce_assignment[]
+ State st = 'up'
+ assert st == State.up
+ // end::enum_coerce_assignment[]
+ } catch (IllegalArgumentException err) {
+ assert false:'Test should not have failed'
}
- }
- // end::enum_switch_method[]
- // tag::enum_switch_test[]
- assert switchState('up' as State) == State.down
- assert switchState(State.down) == State.up
- // end::enum_switch_test[]
+ try {
+ // tag::enum_coerce_assignment_wrong[]
+ State st = 'not an enum value'
+ // end::enum_coerce_assignment_wrong[]
+ } catch (IllegalArgumentException err) {
+ // woot!
+ }
+ try {
+ // tag::enum_coerce_assignment_gstring[]
+ def val = "up"
+ State st = "${val}"
+ assert st == State.up
+ // end::enum_coerce_assignment_gstring[]
+ } catch (IllegalArgumentException err) {
+ assert false:'Test should not have failed'
+ }
+
+ // tag::enum_switch_method[]
+ State switchState(State st) {
+ switch (st) {
+ case 'up':
+ return State.down // explicit constant
+ case 'down':
+ return 'up' // implicit coercion for return types
+ }
+ }
+ // end::enum_switch_method[]
+
+ // tag::enum_switch_test[]
+ assert switchState('up' as State) == State.down
+ assert switchState(State.down) == State.up
+ // end::enum_switch_test[]
'''
}
+ @Test
void testCustomCoercion() {
assertScript '''
-import groovy.transform.ToString
-import static java.lang.Math.*
-
-@ToString(includeNames=true)
-// tag::polar_class_header[]
-class Polar {
- double r
- double phi
-// end::polar_class_header[]
-// tag::polar_class_astype[]
- def asType(Class target) {
- if (Cartesian==target) {
- return new Cartesian(x: r*cos(phi), y: r*sin(phi))
- }
- }
-// end::polar_class_astype[]
-// tag::polar_class_footer[]
-}
-// end::polar_class_footer[]
+ import groovy.transform.ToString
+ import static java.lang.Math.*
+
+ @ToString(includeNames=true)
+ // tag::polar_class_header[]
+ class Polar {
+ double r
+ double phi
+ // end::polar_class_header[]
+ // tag::polar_class_astype[]
+ def asType(Class target) {
+ if (Cartesian==target) {
+ return new Cartesian(x: r*cos(phi), y: r*sin(phi))
+ }
+ }
+ // end::polar_class_astype[]
+ // tag::polar_class_footer[]
+ }
+ // end::polar_class_footer[]
-@ToString(includeNames=true)
-// tag::cartesian_class[]
-class Cartesian {
- double x
- double y
-}
-// end::cartesian_class[]
-
-// tag::polar_astype_assert[]
-def sigma = 1E-16
-def polar = new Polar(r:1.0,phi:PI/2)
-def cartesian = polar as Cartesian
-assert abs(cartesian.x-sigma) < sigma
-// end::polar_astype_assert[]
-'''
+ @ToString(includeNames=true)
+ // tag::cartesian_class[]
+ class Cartesian {
+ double x
+ double y
+ }
+ // end::cartesian_class[]
+
+ // tag::polar_astype_assert[]
+ def sigma = 1E-16
+ def polar = new Polar(r:1.0,phi:PI/2)
+ def cartesian = polar as Cartesian
+ assert abs(cartesian.x-sigma) < sigma
+ // end::polar_astype_assert[]
+ '''
}
+ @Test
void testCustomCoercionWithExternalAsType() {
assertScript '''
-import groovy.transform.ToString
-import static java.lang.Math.*
+ import groovy.transform.ToString
+ import static java.lang.Math.*
-@ToString(includeNames=true)
-class Polar {
- double r
- double phi
+ @ToString(includeNames=true)
+ class Polar {
+ double r
+ double phi
-}
-@ToString(includeNames=true)
-class Cartesian {
- double x
- double y
-}
+ }
+ @ToString(includeNames=true)
+ class Cartesian {
+ double x
+ double y
+ }
-// tag::polar_metaclass_astype[]
-Polar.metaClass.asType = { Class target ->
- if (Cartesian==target) {
- return new Cartesian(x: r*cos(phi), y: r*sin(phi))
- }
-}
-// end::polar_metaclass_astype[]
+ // tag::polar_metaclass_astype[]
+ Polar.metaClass.asType = { Class target ->
+ if (Cartesian==target) {
+ return new Cartesian(x: r*cos(phi), y: r*sin(phi))
+ }
+ }
+ // end::polar_metaclass_astype[]
-def sigma = 1E-16
-def polar = new Polar(r:1.0,phi:PI/2)
-def cartesian = polar as Cartesian
-assert abs(cartesian.x-sigma) < sigma
-'''
+ def sigma = 1E-16
+ def polar = new Polar(r:1.0,phi:PI/2)
+ def cartesian = polar as Cartesian
+ assert abs(cartesian.x-sigma) < sigma
+ '''
}
+ @Test
void testExplicitClosureCoercion() {
assertScript '''
-// tag::filter_sam_type[]
-interface Predicate<T> {
- boolean accept(T obj)
-}
-// end::filter_sam_type[]
-// tag::greeter_sam_type[]
-abstract class Greeter {
- abstract String getName()
- void greet() {
- println "Hello, $name"
- }
-}
-// end::greeter_sam_type[]
-// tag::assertions_explicit_closure_to_sam[]
-Predicate filter = { it.contains 'G' } as Predicate
-assert filter.accept('Groovy') == true
-
-Greeter greeter = { 'Groovy' } as Greeter
-greeter.greet()
-// end::assertions_explicit_closure_to_sam[]
-'''
+ // tag::filter_sam_type[]
+ interface Predicate<T> {
+ boolean accept(T obj)
+ }
+ // end::filter_sam_type[]
+ // tag::greeter_sam_type[]
+ abstract class Greeter {
+ abstract String getName()
+ void greet() {
+ println "Hello, $name"
+ }
+ }
+ // end::greeter_sam_type[]
+ // tag::assertions_explicit_closure_to_sam[]
+ Predicate filter = { it.contains 'G' } as Predicate
+ assert filter.accept('Groovy') == true
+
+ Greeter greeter = { 'Groovy' } as Greeter
+ greeter.greet()
+ // end::assertions_explicit_closure_to_sam[]
+ '''
}
+ @Test
void testImplicitClosureCoercionWithAssignment() {
assertScript '''
-interface Predicate<T> {
- boolean accept(T obj)
-}
-
-abstract class Greeter {
- abstract String getName()
- void greet() {
- println "Hello, $name"
- }
-}
+ interface Predicate<T> {
+ boolean accept(T obj)
+ }
-// tag::assertions_implicit_closure_to_sam[]
-Predicate filter = { it.contains 'G' }
-assert filter.accept('Groovy') == true
+ abstract class Greeter {
+ abstract String getName()
+ void greet() {
+ println "Hello, $name"
+ }
+ }
-Greeter greeter = { 'Groovy' }
-greeter.greet()
-// end::assertions_implicit_closure_to_sam[]
+ // tag::assertions_implicit_closure_to_sam[]
+ Predicate filter = { it.contains 'G' }
+ assert filter.accept('Groovy') == true
-'''
+ Greeter greeter = { 'Groovy' }
+ greeter.greet()
+ // end::assertions_implicit_closure_to_sam[]
+ '''
}
+ @Test
void testImplicitClosureCoercionWithAssignmentAndMethodPointer() {
assertScript '''
-interface Predicate<T> {
- boolean accept(T obj)
-}
-
-abstract class Greeter {
- abstract String getName()
- void greet() {
- println "Hello, $name"
- }
-}
+ interface Predicate<T> {
+ boolean accept(T obj)
+ }
-// tag::assertions_implicit_closure_to_sam_and_method_pointer[]
+ abstract class Greeter {
+ abstract String getName()
+ void greet() {
+ println "Hello, $name"
+ }
+ }
-boolean doFilter(String s) { s.contains('G') }
+ // tag::assertions_implicit_closure_to_sam_and_method_pointer[]
-Predicate filter = this.&doFilter
-assert filter.accept('Groovy') == true
+ boolean doFilter(String s) { s.contains('G') }
-Greeter greeter = GroovySystem.&getVersion
-greeter.greet()
-// end::assertions_implicit_closure_to_sam_and_method_pointer[]
+ Predicate filter = this.&doFilter
+ assert filter.accept('Groovy') == true
-'''
+ Greeter greeter = GroovySystem.&getVersion
+ greeter.greet()
+ // end::assertions_implicit_closure_to_sam_and_method_pointer[]
+ '''
}
+ @Test
void testClosureCoercionWithMethodCall() {
assertScript '''
-interface Predicate<T> {
- boolean accept(T obj)
-}
+ interface Predicate<T> {
+ boolean accept(T obj)
+ }
-// tag::method_accepting_filter[]
-public <T> List<T> filter(List<T> source, Predicate<T> predicate) {
- source.findAll { predicate.accept(it) }
-}
-// end::method_accepting_filter[]
+ // tag::method_accepting_filter[]
+ public <T> List<T> filter(List<T> source, Predicate<T> predicate) {
+ source.findAll { predicate.accept(it) }
+ }
+ // end::method_accepting_filter[]
-// tag::method_call_with_explicit_coercion[]
-assert filter(['Java','Groovy'], { it.contains 'G'} as Predicate) == ['Groovy']
-// end::method_call_with_explicit_coercion[]
+ // tag::method_call_with_explicit_coercion[]
+ assert filter(['Java','Groovy'], { it.contains 'G'} as Predicate)
== ['Groovy']
+ // end::method_call_with_explicit_coercion[]
-// tag::method_call_with_implicit_coercion[]
-assert filter(['Java','Groovy']) { it.contains 'G'} == ['Groovy']
-// end::method_call_with_implicit_coercion[]
-'''
+ // tag::method_call_with_implicit_coercion[]
+ assert filter(['Java','Groovy']) { it.contains 'G'} == ['Groovy']
+ // end::method_call_with_implicit_coercion[]
+ '''
}
+ @Test
void testClosureCoercionToInterface() {
assertScript '''
-// tag::foobar_interface[]
-interface FooBar {
- int foo()
- void bar()
-}
-// end::foobar_interface[]
+ // tag::foobar_interface[]
+ interface FooBar {
+ int foo()
+ void bar()
+ }
+ // end::foobar_interface[]
-// tag::foobar2closure_coercion[]
-def impl = { println 'ok'; 123 } as FooBar
-// end::foobar2closure_coercion[]
+ // tag::foobar2closure_coercion[]
+ def impl = { println 'ok'; 123 } as FooBar
+ // end::foobar2closure_coercion[]
-// tag::foobarintf_assertions[]
-assert impl.foo() == 123
-impl.bar()
-// end::foobarintf_assertions[]
+ // tag::foobarintf_assertions[]
+ assert impl.foo() == 123
+ impl.bar()
+ // end::foobarintf_assertions[]
'''
}
+ @Test
void testClosureCoercionToClass() {
assertScript '''
-// tag::closure2foobarclass[]
-class FooBar {
- int foo() { 1 }
- void bar() { println 'bar' }
-}
+ // tag::closure2foobarclass[]
+ class FooBar {
+ int foo() { 1 }
+ void bar() { println 'bar' }
+ }
-def impl = { println 'ok'; 123 } as FooBar
+ def impl = { println 'ok'; 123 } as FooBar
-assert impl.foo() == 123
-impl.bar()
-// end::closure2foobarclass[]
-'''
+ assert impl.foo() == 123
+ impl.bar()
+ // end::closure2foobarclass[]
+ '''
}
+ @Test
void testCoerceMapToIterator() {
assertScript '''
-// tag::coerce_map_to_iterator[]
-def map
-map = [
- i: 10,
- hasNext: { map.i > 0 },
- next: { map.i-- },
-]
-def iter = map as Iterator
-// end::coerce_map_to_iterator[]
-
-// tag::use_coerced_iterator[]
-while ( iter.hasNext() )
-println iter.next()
-assert map.i==0
-// end::use_coerced_iterator[]
-'''
+ // tag::coerce_map_to_iterator[]
+ def map
+ map = [
+ i: 10,
+ hasNext: { map.i > 0 },
+ next: { map.i-- },
+ ]
+ def iter = map as Iterator
+ // end::coerce_map_to_iterator[]
+
+ // tag::use_coerced_iterator[]
+ while ( iter.hasNext() )
+ println iter.next()
+ assert map.i==0
+ // end::use_coerced_iterator[]
+ '''
+
// "remove()" is an interface default method
assertScript '''import static groovy.test.GroovyAssert.shouldFail
@@ -312,6 +323,7 @@ assert map.i==0
}
// GROOVY-10717
+ @Test
void testCoerceMapToAbstract() {
assertScript '''import static groovy.test.GroovyAssert.shouldFail
@@ -328,67 +340,69 @@ assert map.i==0
'''
}
+ @Test
void testCoerceThrowsNPE() {
assertScript '''
-// tag::define_x_interface[]
-interface X {
- void f()
- void g(int n)
- void h(String s, int n)
-}
+ // tag::define_x_interface[]
+ interface X {
+ void f()
+ void g(int n)
+ void h(String s, int n)
+ }
-x = [ f: {println "f called"} ] as X
-// end::define_x_interface[]
+ x = [ f: {println "f called"} ] as X
+ // end::define_x_interface[]
-// tag::call_existing_method[]
-x.f() // method exists
-// end::call_existing_method[]
+ // tag::call_existing_method[]
+ x.f() // method exists
+ // end::call_existing_method[]
-try {
-// tag::call_non_existing_method[]
- x.g() // MissingMethodException here
-// end::call_non_existing_method[]
-} catch (MissingMethodException e) {
- println "Caught exception"
-}
-try {
-// tag::call_notimplemented_method[]
- x.g(5) // UnsupportedOperationException here
-// end::call_notimplemented_method[]
-} catch (UnsupportedOperationException e) {
- println "Caught exception"
-}
-'''
+ try {
+ // tag::call_non_existing_method[]
+ x.g() // MissingMethodException here
+ // end::call_non_existing_method[]
+ } catch (MissingMethodException e) {
+ println "Caught exception"
+ }
+ try {
+ // tag::call_notimplemented_method[]
+ x.g(5) // UnsupportedOperationException here
+ // end::call_notimplemented_method[]
+ } catch (UnsupportedOperationException e) {
+ println "Caught exception"
+ }
+ '''
}
+ @Test
void testAsVsAsType() {
assertScript '''
-// tag::as_keyword[]
-interface Greeter {
- void greet()
-}
-def greeter = { println 'Hello, Groovy!' } as Greeter // Greeter is known
statically
-greeter.greet()
-// end::as_keyword[]
-
-/*
-// tag::clazz_greeter_header[]
-Class clazz = Class.forName('Greeter')
-// end::clazz_greeter_header[]
-
-// tag::incorrect_as_usage[]
-greeter = { println 'Hello, Groovy!' } as clazz
-// throws:
-// unable to resolve class clazz
-// @ line 9, column 40.
-// greeter = { println 'Hello, Groovy!' } as clazz
-// end::incorrect_as_usage[]
-*/
-Class clazz = Greeter
-// tag::fixed_as_usage[]
-greeter = { println 'Hello, Groovy!' }.asType(clazz)
-greeter.greet()
-// end::fixed_as_usage[]
-'''
+ // tag::as_keyword[]
+ interface Greeter {
+ void greet()
+ }
+ def greeter = { println 'Hello, Groovy!' } as Greeter // Greeter
is known statically
+ greeter.greet()
+ // end::as_keyword[]
+
+ /*
+ // tag::clazz_greeter_header[]
+ Class clazz = Class.forName('Greeter')
+ // end::clazz_greeter_header[]
+
+ // tag::incorrect_as_usage[]
+ greeter = { println 'Hello, Groovy!' } as clazz
+ // throws:
+ // unable to resolve class clazz
+ // @ line 9, column 40.
+ // greeter = { println 'Hello, Groovy!' } as clazz
+ // end::incorrect_as_usage[]
+ */
+ Class clazz = Greeter
+ // tag::fixed_as_usage[]
+ greeter = { println 'Hello, Groovy!' }.asType(clazz)
+ greeter.greet()
+ // end::fixed_as_usage[]
+ '''
}
}