[ https://issues.apache.org/jira/browse/GROOVY-8788?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17583055#comment-17583055 ]
Eric Milles commented on GROOVY-8788: ------------------------------------- It is this excerpt of [StaticTypeCheckingVisitor#getResultType|https://github.com/apache/groovy/blob/7f6fcb2f81b58a54bc7beef33ac382cb50a79cb4/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java#L4522] that determines the type of "x = map['key']" and "map['key'] = x". Yes, it only looks for getAt... {code:java} if (isArrayOp(op)) { Expression copy = binX(leftExpression, expr.getOperation(), rightExpression); copy.setSourcePosition(expr); // do not propagate BINARY_EXP_TARGET, etc. MethodNode method = findMethodOrFail(copy, left, "getAt", rightRedirect); if (method != null && !isNumberCategory(getWrapper(rightRedirect))) { return inferReturnTypeGenerics(left, method, rightExpression); } return inferComponentType(left, right); } {code} When method selection changes, it determines Object not Type for Map<String,Type>. I can add a special case for Map left expression and String right expression. For put, type checking is done via this block in [StaticTypeCheckingVisitor#visitBinaryExpression|https://github.com/apache/groovy/blob/7f6fcb2f81b58a54bc7beef33ac382cb50a79cb4/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java#L820]: {code:java} if (isArrayOp(op)) { ... if (!lType.isArray() && enclosingBinaryExpression != null && enclosingBinaryExpression.getLeftExpression() == expression && isAssignment(enclosingBinaryExpression.getOperation().getType())) { // left hand side of a subscript assignment: map['foo'] = ... Expression enclosingExpressionRHS = enclosingBinaryExpression.getRightExpression(); if (!(enclosingExpressionRHS instanceof ClosureExpression)) { enclosingExpressionRHS.visit(this); } ClassNode[] arguments = {rType, getType(enclosingExpressionRHS)}; List<MethodNode> methods = findMethod(lType, "putAt", arguments); if (methods.size() == 1) { typeCheckMethodsWithGenericsOrFail(lType, arguments, methods.get(0), enclosingExpressionRHS); } else if (methods.isEmpty()) { addNoMatchingMethodError(lType, "putAt", arguments, enclosingBinaryExpression); } } } {code} It relies on method selection to produce "Cannot call #putAt(Map,K,V) with arguments ..." errors. Since {{putAt(Object,String,Object)}} is now selected for string keys, this block checks nothing. However, the result type allows "Cannot assign value of type X to variable of type Y" to be produced. > Inconsistency in extension method selection with @CompileStatic > --------------------------------------------------------------- > > Key: GROOVY-8788 > URL: https://issues.apache.org/jira/browse/GROOVY-8788 > Project: Groovy > Issue Type: Bug > Components: Static compilation, Static Type Checker > Affects Versions: 2.4.15, 2.5.2 > Reporter: Daniil Ovchinnikov > Assignee: Eric Milles > Priority: Major > Labels: breaking > > Given properly registered extension class: > {code:java|title=MyExtensions.java} > public class MyExtensions { > public static void foo(Object self, String s) { > System.out.println("Object#foo(String)"); > } > public static void foo(String self, Object o) { > System.out.println("String#foo(Object)"); > } > } > {code} > Run > {code:java|title=playground.groovy} > void usageExt() { > "".foo("") // prints "Object#foo(String)" which is correct > } > @groovy.transform.CompileStatic > void usageExtStatic() { > "".foo("") // prints "String#foo(Object)" which is questionable > } > usageExt() > usageExtStatic() > {code} -- This message was sent by Atlassian Jira (v8.20.10#820010)