[ 
https://issues.apache.org/jira/browse/GROOVY-9058?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16808751#comment-16808751
 ] 

Eric Milles commented on GROOVY-9058:
-------------------------------------

In order to preserve the type checking of assignments, I think it best to make 
some kind of change after {{typeCheckAssignment}} in 
{{StaticTypeCheckingVisitor.visitBinaryExpression}}.  Here is the current code 
for handling assignments:

{code:java}
            if (!isEmptyDeclaration && isAssignment(op)) {
                if (rightExpression instanceof ConstructorCallExpression) {
                    inferDiamondType((ConstructorCallExpression) 
rightExpression, lType);
                }

                ClassNode originType = 
getOriginalDeclarationType(leftExpression);
                typeCheckAssignment(expression, leftExpression, originType, 
rightExpression, resultType);
                // if assignment succeeds but result type is not a subtype of 
original type, then we are in a special cast handling
                // and we must update the result type
                if (!implementsInterfaceOrIsSubclassOf(getWrapper(resultType), 
getWrapper(originType))) {
                    resultType = originType;
                } else if (lType.isUsingGenerics() && !lType.isEnum() && 
hasRHSIncompleteGenericTypeInfo(resultType)) {
                    // for example, LHS is List<ConcreteClass> and RHS is 
List<T> where T is a placeholder
                    resultType = lType;
                }

                // make sure we keep primitive types
                if (isPrimitiveType(originType) && 
resultType.equals(getWrapper(originType))) {
                    resultType = originType;
                }

                // if we are in an if/else branch, keep track of assignment
                if (typeCheckingContext.ifElseForWhileAssignmentTracker != null 
&& leftExpression instanceof VariableExpression
                        && !isNullConstant(rightExpression)) {
                    Variable accessedVariable = ((VariableExpression) 
leftExpression).getAccessedVariable();
                    if (accessedVariable instanceof Parameter) {
                        accessedVariable = new 
ParameterVariableExpression((Parameter) accessedVariable);
                    }
                    if (accessedVariable instanceof VariableExpression) {
                        VariableExpression var = (VariableExpression) 
accessedVariable;
                        List<ClassNode> types = 
typeCheckingContext.ifElseForWhileAssignmentTracker.get(var);
                        if (types == null) {
                            types = new LinkedList<ClassNode>();
                            ClassNode type = 
var.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
                            types.add(type);
                            
typeCheckingContext.ifElseForWhileAssignmentTracker.put(var, types);
                        }
                        types.add(resultType);
                    }
                }
                storeType(leftExpression, resultType);
{code}

To preserve the declared type of a variable, another check should be added 
after typeCheckAssignment.  Does it seem sensible that the inferred type of 
both the variable and the binary expression as a whole should both be the 
declared type (that is {{Type}} in {{Type var = value}} and not whatever 
{{value}} infers to)?  If yes, {{resultType}} needs to be set to {{originType}} 
or {{lType}} under some condition.

> each parameter type not correctly inferenced
> --------------------------------------------
>
>                 Key: GROOVY-9058
>                 URL: https://issues.apache.org/jira/browse/GROOVY-9058
>             Project: Groovy
>          Issue Type: Bug
>          Components: Static compilation
>    Affects Versions: 2.5.6
>            Reporter: Mauro Molinari
>            Priority: Major
>
> Consider this Java class:
> {code:java}
> package test51;
> import java.util.List;
> public class Foo {
>     public List<Object[]> bar() { return null; }
> }{code}
>  and this Groovy class:
> {code:java}
> package test51
> import groovy.transform.CompileStatic
> @CompileStatic
> class Test51 {
>     protected void foo() {
>         List<Object[]> foo = new Foo().bar()
>         foo.each { row ->
>             def o = row[0]
>         }
>     }
>     
>     List bar() {
>     }
> }{code}
> This produces a compiler error because {{row}} is resolved as {{Object}} 
> rather than {{Object[]}}.
> A workaround is to declare {{row}} as {{Object[] row}} in the closure 
> parameter list.



--
This message was sent by Atlassian JIRA
(v7.6.3#76005)

Reply via email to