daniellansun commented on PR #3259:
URL: https://github.com/apache/groovy/pull/3259#issuecomment-6781911494

   (3) The example I answered last time really was two locals, and 
`VariableScopeVisitor` rejects that with or without the bridge. What you meant 
is a field or a property and a local of the same name. That does compile, and 
the bridge does not treat them as one name.
   
   The lowered query is spliced into the method, `VariableScopeVisitor` links 
each reference to the declaration in scope, and the original call is put back. 
A `FieldNode` or a `PropertyNode` is not copied. It is read when the closure 
runs. A local or a closure parameter declared inside the query is a different 
declaration, and that is the one the references in that scope use. A 
`DynamicVariable` is not copied either. At conversion that is what an import 
alias still is, including a lower-case alias such as `import 
java.util.concurrent.TimeUnit as threshold`, and the alias then resolves to the 
class.
   
   I ran that shape under `@CompileStatic`. A field `threshold` of 10 is set to 
4 after the `GQ` expression and before `toList()`. The `where` clause sees 4. A 
closure parameter `threshold` of 5 in the same query's `select` stays 5. A 
getter/setter property behaves the same way: the getter runs at the terminal, 
not when the expression is built. `@TypeChecked` does this too. `GQL` still 
materializes at the expression, so a later write of the field is not observed. 
A closure parameter of the same name as the field wins over the field. Two 
locals of the same name are still rejected. `STRATEGY.md` now says this 
explicitly. There is still no name walk in the bridge.
   
   (5) You are right that I answered a different question. The problem is not 
that the GINQ operators are dynamic. `DYNAMIC_RESOLUTION = Boolean.TRUE` is set 
on the lowered query closure, and `StaticTypesClosureWriter` compiles that 
whole closure with the dynamic writer. Every expression in it is dynamic, 
including a call written in `where` or `select`. A target another transform 
already chose for that call is not what is emitted. The call is dispatched at 
runtime.
   
   A concrete case: an extension's `onMethodSelection` forces 
`choose(CharSequence)` when the argument is a `String`. In the enclosing 
`@CompileStatic` method that is the method that runs. The same call inside 
`select` hits `choose(String)`, because the runtime type wins. The same is true 
of any other call in the clause whose static target differs from the runtime 
dispatch.
   
   I tried not to mark the closure. Clause parameters stayed dynamic, so a map 
row is not inferred as a bean. A call the checker could resolve kept its 
target, and only an operator whose target was a stand-in became a dynamic call. 
The read-only snapshot was passed into the result lambda as a parameter, 
because a static lambda still cannot capture a local of an enclosing closure: 
the bytecode loads the outer class and casts it to `GroovyObject`. `orderby n 
in desc` and the join tests in the static suite still passed, and the 
`choose(CharSequence)` target was honoured inside the query.
   
   The rest of the dynamic query did not. On the groovy-ginq suite, 71 tests 
failed. `where note(n)`, `note` being a method of the enclosing class, was 
emitted as `invokevirtual` of `Object.note()`, which does not exist. A join 
alias was resolved against `QueryableCollection`. A parallel join that returns 
rows dynamically returned an empty list. Group, window, aggregate, and 
hash-join scripts failed in the same way. Parallel `submit` also cannot take 
the snapshot as an extra parameter, because that lambda is a `Supplier`.
   
   So the closure stays dynamic. The enclosing method does not. I have written 
that limitation into `STRATEGY.md` and the CompileStatic section of the user 
guide, including the `choose(CharSequence)` example. I would rather the clause 
bodies stayed on the static writer. I do not have a way to do that which still 
runs the queries that pass today.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to