Paul King created GROOVY-12041:
----------------------------------

             Summary: STC: unresolvedVariable/unresolvedProperty no longer 
fires when receiver inherits getProperty(String)
                 Key: GROOVY-12041
                 URL: https://issues.apache.org/jira/browse/GROOVY-12041
             Project: Groovy
          Issue Type: Bug
            Reporter: Paul King



A {{TypeCheckingDSL}} extension that captures the receiver in 
{{unresolvedVariable}} / {{unresolvedProperty}} and later matches it by node 
identity in {{methodNotFound}} stops working in Groovy 5 when the enclosing 
class inherits {{getProperty(String)}} (e.g. extends {{Script}} or a GSP-style 
{{GroovyPage}} base). The {{unresolvedVariable}} / {{unresolvedProperty}} 
callback never fires, so the extension has no chance to record the receiver, 
and the downstream {{methodNotFound}} rejects the chained call.

h2. Observed behaviour

Reproducer extension (abridged):

{code:groovy}
newScope { dynamicProperties = [] as Set }

unresolvedVariable { VariableExpression ve ->
    if (ve.name == 'g') { currentScope.dynamicProperties << ve; return 
makeDynamic(ve) }
}

unresolvedProperty { PropertyExpression pe ->
    if (pe.propertyAsString == 'g') { currentScope.dynamicProperties << pe; 
return makeDynamic(pe) }
}

methodNotFound { receiver, name, argList, argTypes, call ->
    if (call.objectExpression != null
            && currentScope.dynamicProperties.contains(call.objectExpression)) {
        return makeDynamic(call)
    }
}
{code}

Results across versions (running {{g.message(code: 'World')}} inside the 
{{Subject}}):

||Subject shape||4.0.27||5.0.5 / 5.0.6||
|Plain class, {{g.message(...)}}|PASS ({{unresolvedVariable}} fires)|PASS 
(fires twice, but works)|
|Plain class, {{this.g.message(...)}}|PASS ({{unresolvedProperty}} fires)|PASS|
|{{extends Script}}, {{g.message(...)}}|*PASS*|*FAIL* — {{unresolvedVariable}} 
never fires|
|{{extends Base}} with {{Object getProperty(String)}}, 
{{g.message(...)}}|*PASS*|*FAIL* — same|
|{{extends Script}}, {{this.g.message(...)}}|PASS|PASS|

The Groovy 5 failure is:
{noformat}
[Static type checking] - Cannot find matching method 
java.lang.Object#message(LinkedHashMap<String,String>)
{noformat}

Diagnostic prints confirm that on the failing cases the extension is *not* 
called for {{g}} at all; {{methodNotFound}} fires with an empty 
{{dynamicProperties}} set. Where the callbacks do fire, AST node identity is 
*preserved* across callbacks on Groovy 5 — i.e. the originally reported "node 
identity changes between callbacks" hypothesis is not what is happening.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to