diff --git a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java index ac48070d093..f74ee46f309 100644 --- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java +++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java @@ -861,6 +861,12 @@ public void visitPropertyExpression(final PropertyExpression expression) { boolean readOnly = !typeCheckingContext.isTargetOfEnclosingAssignment(expression); if (existsProperty(expression, readOnly) || extension.handleUnresolvedProperty(expression)) { + if (readOnly) { // GROOVY-12305: record narrowed type of instanceof-guarded receiver for later use + ClassNode temporaryType = getInferredTypeFromTempInfo(expression, expression.getNodeMetaData(INFERRED_TYPE)); + if (temporaryType != null && !isObjectType(temporaryType)) { + expression.putNodeMetaData(INFERRED_TYPE, temporaryType); + } + } return; // resolved or excused } recordMissingProperty(expression); @@ -7428,7 +7434,7 @@ protected List getTemporaryTypesForExpression(final Expression expres } private ClassNode getInferredTypeFromTempInfo(final Expression expression, final ClassNode expressionType) { - if (expression instanceof VariableExpression && !isPrimitiveType(expressionType)) { + if ((expression instanceof VariableExpression || expression instanceof PropertyExpression) && !isPrimitiveType(expressionType)) { List tempTypes = getTemporaryTypesForExpression(expression); if (!tempTypes.isEmpty()) { ClassNode superclass; diff --git a/src/test/groovy/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy b/src/test/groovy/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy index 26dcbf13e61..c9c97db48e0 100644 --- a/src/test/groovy/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy +++ b/src/test/groovy/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy @@ -1321,6 +1321,30 @@ class FieldsAndPropertiesSTCTest extends StaticTypeCheckingTestCase { ''' } + // GROOVY-12305 + @Test + void testMapPropertyAccess19() { + assertScript ''' + def test(Map foo) { + foo.a instanceof Map ? foo.a.b : foo.a + } + assert test(a: [b: 'c']) == 'c' + assert test(a: 'x') == 'x' + ''' + + assertScript ''' + def test(Map foo) { + if (foo.a instanceof Map) { + foo.a.b + } else { + foo.a + } + } + assert test(a: [b: 'c']) == 'c' + assert test(a: 'x') == 'x' + ''' + } + @Test void testTypeCheckerDoesNotThinkPropertyIsReadOnly() { assertScript '''