Revert null-safe behavior to error at runtime instead of compiletime (#65099)

This reverts a change where null-safe was enhanced to cause a compile-time error instead of a run-
time error when the target value was a primitive type. The reason for the reversion is consistency 
across def/non-def types and versions. I've added a follow up issue to fix this behavior in general 
(#65098).
This commit is contained in:
Jack Conradson 2020-11-16 10:27:03 -08:00
parent afd12fddaf
commit 0beffcd405
2 changed files with 16 additions and 4 deletions

View File

@ -2485,11 +2485,14 @@ public class DefaultSemanticAnalysisPhase extends UserTreeBaseVisitor<SemanticSc
"Field [" + index + "] does not exist for type [" + prefixValueType.getValueCanonicalTypeName() + "]."));
}
} else if (prefixValueType != null && prefixValueType.getValueType() == def.class) {
TargetType targetType = semanticScope.getDecoration(userDotNode, TargetType.class);
TargetType targetType = userDotNode.isNullSafe() ? null : semanticScope.getDecoration(userDotNode, TargetType.class);
// TODO: remove ZonedDateTime exception when JodaCompatibleDateTime is removed
valueType = targetType == null || targetType.getTargetType() == ZonedDateTime.class ||
semanticScope.getCondition(userDotNode, Explicit.class) ? def.class : targetType.getTargetType();
semanticScope.setCondition(userDotNode, DefOptimized.class);
if (write) {
semanticScope.setCondition(userDotNode, DefOptimized.class);
}
} else {
Class<?> prefixType;
String prefixCanonicalTypeName;
@ -2708,7 +2711,10 @@ public class DefaultSemanticAnalysisPhase extends UserTreeBaseVisitor<SemanticSc
// TODO: remove ZonedDateTime exception when JodaCompatibleDateTime is removed
valueType = targetType == null || targetType.getTargetType() == ZonedDateTime.class ||
semanticScope.getCondition(userBraceNode, Explicit.class) ? def.class : targetType.getTargetType();
semanticScope.setCondition(userBraceNode, DefOptimized.class);
if (write) {
semanticScope.setCondition(userBraceNode, DefOptimized.class);
}
} else if (Map.class.isAssignableFrom(prefixValueType)) {
String canonicalClassName = PainlessLookupUtility.typeToCanonicalTypeName(prefixValueType);
@ -2854,7 +2860,7 @@ public class DefaultSemanticAnalysisPhase extends UserTreeBaseVisitor<SemanticSc
}
}
TargetType targetType = semanticScope.getDecoration(userCallNode, TargetType.class);
TargetType targetType = userCallNode.isNullSafe() ? null : semanticScope.getDecoration(userCallNode, TargetType.class);
// TODO: remove ZonedDateTime exception when JodaCompatibleDateTime is removed
valueType = targetType == null || targetType.getTargetType() == ZonedDateTime.class ||
semanticScope.getCondition(userCallNode, Explicit.class) ? def.class : targetType.getTargetType();

View File

@ -840,4 +840,10 @@ public class WhenThingsGoWrongTests extends ScriptTestCase {
iae = expectScriptThrows(IllegalArgumentException.class, () -> exec("while (java.util.List) {java.util.List x = 1;}"));
assertEquals(iae.getMessage(), "value required: instead found unexpected type [java.util.List]");
}
public void testInvalidNullSafeBehavior() {
expectScriptThrows(ClassCastException.class, () ->
exec("def test = ['hostname': 'somehostname']; test?.hostname && params.host.hostname != ''"));
expectScriptThrows(NullPointerException.class, () -> exec("params?.host?.hostname && params.host?.hostname != ''"));
}
}