Paul,
thanks for elucidation!
Incidentally, as for the runtime — in my personal opinion the point is in that
void is void is void, i.e., whilst
void foo() { return 42 }
should be an error (I'd rather vote for compile-time, though it of course is
arguable whether not to move it to runtime),
void bar() { return (void)42 }
void baz() { return bar() }
should, in my personal opinion, be a valid an quite proper code both run- and
compile-time, for returning a void from a void function makes perfect sense.
Of course, it is not too important; it's a rare construction which normally
does not happen :)
Thanks and all the best,
OC
> On 25 Aug 2018, at 5:15 AM, Paul King <[email protected]> wrote:
>
> I think you are correct that we should do this differently. In fact, there is
> a comment along those lines in the code:
>
> https://github.com/apache/groovy/blob/master/src/main/java/org/codehaus/groovy/classgen/asm/StatementWriter.java#L601
>
> <https://github.com/apache/groovy/blob/master/src/main/java/org/codehaus/groovy/classgen/asm/StatementWriter.java#L601>
>
> You wouldn't want the check too early so that AST transforms could make
> changes, e.g.:
>
> @MakeVoidReturnSelf // some fluent api AST transform
> class Foo {
> void setBar() {...}
> void setBaz() {...}
> }
> new Foo().setBar('x').setBaz('y')
>
> Moving this to the Verifier would allow a more traditional error message to
> occur during compilation.
>
> Of course there is an argument (like you mentioned) that we should go the
> other way and not report the error which would allow scenarios like this:
>
> class Foo {
> void baz() { return 42 }
> }
>
> Foo.metaClass.baz = { throw new RuntimeException('Boom!')}
> try {
> new Foo().baz()
> println 'ERROR: Should not get here!'
> } catch(RuntimeException ex) {
> println ex.message
> }
>
> So instead of the weird "runtime" error during parsing, we could throw an
> exception at runtime if the return statement is ever reached.
>
> Cheers, Paul.
>
>
>
>
> On Sat, Aug 25, 2018 at 7:20 AM ocs@ocs <[email protected] <mailto:[email protected]>>
> wrote:
> Ladies and gentlemen,
>
> I've just bumped into the problem shown below.
>
> Whilst it is arguable whether the situation should be valid or not (myself, I
> strongly believe it should be valid and compiled without a glitch), even if
> invalid, it should not cause an uncaught exception, but simply report a
> syntax error, I believe?
>
> All the best,
> OC
>
> ===
> 941 /tmp> >e.groovy
> class foo {
> void bar() { }
> void bax() { return bar() }
> }
> 942 /tmp> groovy e
> WARNING: Using incubator modules: jdk.incubator.httpclient
> org.codehaus.groovy.control.MultipleCompilationErrorsException: startup
> failed:
> General error during class generation: Cannot use return statement with an
> expression on a method that returns void
> . At [3:16] /private/tmp/e.groovy
>
> org.codehaus.groovy.syntax.RuntimeParserException: Cannot use return
> statement with an expression on a method that returns void
> . At [3:16] /private/tmp/e.groovy
> at
> org.codehaus.groovy.classgen.AsmClassGenerator.throwException(AsmClassGenerator.java:718)
> at
> org.codehaus.groovy.classgen.asm.StatementWriter.writeReturn(StatementWriter.java:602)
> at
> org.codehaus.groovy.classgen.asm.OptimizingStatementWriter.writeReturn(OptimizingStatementWriter.java:368)
> at
> org.codehaus.groovy.classgen.AsmClassGenerator.visitReturnStatement(AsmClassGenerator.java:686)
> at
> org.codehaus.groovy.ast.stmt.ReturnStatement.visit(ReturnStatement.java:49)
> at
> org.codehaus.groovy.classgen.asm.StatementWriter.writeBlockStatement(StatementWriter.java:93)
> at
> org.codehaus.groovy.classgen.asm.OptimizingStatementWriter.writeBlockStatement(OptimizingStatementWriter.java:210)
> at
> org.codehaus.groovy.classgen.AsmClassGenerator.visitBlockStatement(AsmClassGenerator.java:636)
> at
> org.codehaus.groovy.ast.stmt.BlockStatement.visit(BlockStatement.java:71)
> at
> org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitClassCodeContainer(ClassCodeVisitorSupport.java:110)
> at
> org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitConstructorOrMethod(ClassCodeVisitorSupport.java:121)
> at
> org.codehaus.groovy.classgen.AsmClassGenerator.visitStdMethod(AsmClassGenerator.java:496)
> at
> org.codehaus.groovy.classgen.AsmClassGenerator.visitConstructorOrMethod(AsmClassGenerator.java:432)
> at
> org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitMethod(ClassCodeVisitorSupport.java:132)
> at
> org.codehaus.groovy.classgen.AsmClassGenerator.visitMethod(AsmClassGenerator.java:577)
> at org.codehaus.groovy.ast.ClassNode.visitContents(ClassNode.java:1140)
> at
> org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitClass(ClassCodeVisitorSupport.java:54)
> at
> org.codehaus.groovy.classgen.AsmClassGenerator.visitClass(AsmClassGenerator.java:270)
> at
> org.codehaus.groovy.control.CompilationUnit$18.call(CompilationUnit.java:850)
> at
> org.codehaus.groovy.control.CompilationUnit.applyToPrimaryClassNodes(CompilationUnit.java:1087)
> at
> org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:631)
> at
> org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:609)
> at
> org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:586)
> at
> groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:354)
> at groovy.lang.GroovyClassLoader.access$300(GroovyClassLoader.java:87)
> at groovy.lang.GroovyClassLoader$5.provide(GroovyClassLoader.java:323)
> at groovy.lang.GroovyClassLoader$5.provide(GroovyClassLoader.java:320)
> at
> org.codehaus.groovy.runtime.memoize.StampedCommonCache.compute(StampedCommonCache.java:162)
> at
> org.codehaus.groovy.runtime.memoize.StampedCommonCache.getAndPut(StampedCommonCache.java:153)
> at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:318)
> at groovy.lang.GroovyShell.parseClass(GroovyShell.java:547)
> at groovy.lang.GroovyShell.run(GroovyShell.java:376)
> at groovy.lang.GroovyShell.run(GroovyShell.java:366)
> at groovy.ui.GroovyMain.processOnce(GroovyMain.java:589)
> at groovy.ui.GroovyMain.run(GroovyMain.java:332)
> at groovy.ui.GroovyMain.access$1400(GroovyMain.java:69)
> at groovy.ui.GroovyMain$GroovyCommand.process(GroovyMain.java:291)
> at groovy.ui.GroovyMain.processArgs(GroovyMain.java:134)
> at groovy.ui.GroovyMain.main(GroovyMain.java:116)
> at
> java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> at
> java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
> at
> java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
> at java.base/java.lang.reflect.Method.invoke(Method.java:564)
> at
> org.codehaus.groovy.tools.GroovyStarter.rootLoader(GroovyStarter.java:114)
> at org.codehaus.groovy.tools.GroovyStarter.main(GroovyStarter.java:136)
>
> 1 error
>
> 943 /tmp> groovy -version
> WARNING: Using incubator modules: jdk.incubator.httpclient
> Groovy Version: 3.0.0-alpha-3 JVM: 10.0.1 Vendor: "Oracle Corporation" OS:
> Mac OS X
> 944 /tmp>
> ===