Skip to content

Commit

Permalink
GROOVY-11387: STC: entry before field for outside map property reference
Browse files Browse the repository at this point in the history
  • Loading branch information
eric-milles committed May 28, 2024
1 parent 6e2b947 commit 0c08d52
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1562,11 +1562,16 @@ protected boolean existsProperty(final PropertyExpression pexp, final boolean re
continue;
}

// skip property/accessor checks for "field", "this.field", "this.with { field }", etc. in declaring class of field
if (field != null && enclosingTypes.contains(current)) {
if (storeField(field, pexp, receiverType, visitor, receiver.getData(), !readMode)) {
return true;
}
if (field != null // GROOVY-11387: entry before field for indirect or non-this property expressions
&& (!receiverType.equals(field.getDeclaringClass()) || !(isThisExpression(objectExpression)
&& !(pexp.isImplicitThis() && typeCheckingContext.getEnclosingClosure() != null)))
&& (readMode || !(field.isPublic() || field.isProtected()))
&& isMapProperty(pexp, receiverType)) {
field = null;
}
// skip property/accessor checks for "field", "this.field", "this.with { field }", etc. within the declaring class of the field
else if (field != null && enclosingTypes.contains(current) && storeField(field, pexp, receiverType, visitor, receiver.getData(), !readMode)) {
return true;
}

PropertyNode property = current.getProperty(propertyName);
Expand All @@ -1584,7 +1589,7 @@ protected boolean existsProperty(final PropertyExpression pexp, final boolean re
visitor.visitMethod(getter);
}
} else if (readMode) { // GROOVY-5001, GROOVY-5491, GROOVY-8555
if (property != null) { property = null; field = null; }
if (property != null) { property = null; assert field == null; }
}

// prefer explicit getter or setter over property if receiver is not 'this'
Expand Down Expand Up @@ -1772,6 +1777,8 @@ private ClassNode getTypeForMapPropertyExpression(final ClassNode testClass, fin
};

if (!pexp.isSpreadSafe()) {
if (pexp.isImplicitThis() && isThisExpression(pexp.getObjectExpression()))
pexp.putNodeMetaData(DYNAMIC_RESOLUTION,Boolean.TRUE); // GROOVY-11387
return getCombinedBoundType(gts[1]);
} else {
// map*.property syntax acts on Entry
Expand Down
22 changes: 22 additions & 0 deletions src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -970,6 +970,28 @@ class FieldsAndPropertiesSTCTest extends StaticTypeCheckingTestCase {
'''
}

// GROOVY-11387
void testMapPropertyAccess12() {
assertScript '''
def map = new HashMap<String,String>()
@ASTTest(phase=INSTRUCTION_SELECTION, value={
assert node.getNodeMetaData(INFERRED_TYPE) == STRING_TYPE
})
def xxx = map.table
@ASTTest(phase=INSTRUCTION_SELECTION, value={
assert node.getNodeMetaData(INFERRED_TYPE) == STRING_TYPE
})
def yyy = map.with{
@ASTTest(phase=INSTRUCTION_SELECTION, value={
assert node.getNodeMetaData(INFERRED_TYPE) == STRING_TYPE
})
def zzz = table
}
assert xxx == null
assert yyy == null
'''
}

void testTypeCheckerDoesNotThinkPropertyIsReadOnly() {
assertScript '''
// a base class defining a read-only property
Expand Down

0 comments on commit 0c08d52

Please sign in to comment.