in modules/lang-painless/src/main/java/org/elasticsearch/painless/phase/DefaultSemanticAnalysisPhase.java [3039:3190]
public void visitBrace(EBrace userBraceNode, SemanticScope semanticScope) {
boolean read = semanticScope.getCondition(userBraceNode, Read.class);
boolean write = semanticScope.getCondition(userBraceNode, Write.class);
if (read == false && write == false) {
throw userBraceNode.createError(new IllegalArgumentException("not a statement: result of brace operator not used"));
}
AExpression userPrefixNode = userBraceNode.getPrefixNode();
semanticScope.setCondition(userPrefixNode, Read.class);
checkedVisit(userPrefixNode, semanticScope);
Class<?> prefixValueType = semanticScope.getDecoration(userPrefixNode, ValueType.class).valueType();
AExpression userIndexNode = userBraceNode.getIndexNode();
Class<?> valueType;
if (prefixValueType.isArray()) {
semanticScope.setCondition(userIndexNode, Read.class);
semanticScope.putDecoration(userIndexNode, new TargetType(int.class));
checkedVisit(userIndexNode, semanticScope);
decorateWithCast(userIndexNode, semanticScope);
valueType = prefixValueType.getComponentType();
} else if (prefixValueType == def.class) {
semanticScope.setCondition(userIndexNode, Read.class);
checkedVisit(userIndexNode, semanticScope);
TargetType targetType = semanticScope.getDecoration(userBraceNode, TargetType.class);
// TODO: remove ZonedDateTime exception when JodaCompatibleDateTime is removed
valueType = targetType == null
|| targetType.targetType() == ZonedDateTime.class
|| semanticScope.getCondition(userBraceNode, Explicit.class) ? def.class : targetType.targetType();
if (write) {
semanticScope.setCondition(userBraceNode, DefOptimized.class);
}
} else if (Map.class.isAssignableFrom(prefixValueType)) {
String canonicalClassName = PainlessLookupUtility.typeToCanonicalTypeName(prefixValueType);
PainlessMethod getter = semanticScope.getScriptScope()
.getPainlessLookup()
.lookupPainlessMethod(prefixValueType, false, "get", 1);
PainlessMethod setter = semanticScope.getScriptScope()
.getPainlessLookup()
.lookupPainlessMethod(prefixValueType, false, "put", 2);
if (getter != null && (getter.returnType() == void.class || getter.typeParameters().size() != 1)) {
throw userBraceNode.createError(
new IllegalArgumentException("Illegal map get shortcut for type [" + canonicalClassName + "].")
);
}
if (setter != null && setter.typeParameters().size() != 2) {
throw userBraceNode.createError(
new IllegalArgumentException("Illegal map set shortcut for type [" + canonicalClassName + "].")
);
}
if (getter != null
&& setter != null
&& (getter.typeParameters().get(0).equals(setter.typeParameters().get(0)) == false
|| getter.returnType().equals(setter.typeParameters().get(1)) == false)) {
throw userBraceNode.createError(new IllegalArgumentException("Shortcut argument types must match."));
}
if ((read == false || getter != null) && (write == false || setter != null)) {
semanticScope.setCondition(userIndexNode, Read.class);
semanticScope.putDecoration(
userIndexNode,
new TargetType(setter != null ? setter.typeParameters().get(0) : getter.typeParameters().get(0))
);
checkedVisit(userIndexNode, semanticScope);
decorateWithCast(userIndexNode, semanticScope);
valueType = setter != null ? setter.typeParameters().get(1) : getter.returnType();
if (getter != null) {
semanticScope.putDecoration(userBraceNode, new GetterPainlessMethod(getter));
}
if (setter != null) {
semanticScope.putDecoration(userBraceNode, new SetterPainlessMethod(setter));
}
} else {
throw userBraceNode.createError(
new IllegalArgumentException("Illegal map shortcut for type [" + canonicalClassName + "].")
);
}
semanticScope.setCondition(userBraceNode, MapShortcut.class);
} else if (List.class.isAssignableFrom(prefixValueType)) {
String canonicalClassName = PainlessLookupUtility.typeToCanonicalTypeName(prefixValueType);
PainlessMethod getter = semanticScope.getScriptScope()
.getPainlessLookup()
.lookupPainlessMethod(prefixValueType, false, "get", 1);
PainlessMethod setter = semanticScope.getScriptScope()
.getPainlessLookup()
.lookupPainlessMethod(prefixValueType, false, "set", 2);
if (getter != null
&& (getter.returnType() == void.class
|| getter.typeParameters().size() != 1
|| getter.typeParameters().get(0) != int.class)) {
throw userBraceNode.createError(
new IllegalArgumentException("Illegal list get shortcut for type [" + canonicalClassName + "].")
);
}
if (setter != null && (setter.typeParameters().size() != 2 || setter.typeParameters().get(0) != int.class)) {
throw userBraceNode.createError(
new IllegalArgumentException("Illegal list set shortcut for type [" + canonicalClassName + "].")
);
}
if (getter != null
&& setter != null
&& (getter.typeParameters().get(0).equals(setter.typeParameters().get(0)) == false
|| getter.returnType().equals(setter.typeParameters().get(1)) == false)) {
throw userBraceNode.createError(new IllegalArgumentException("Shortcut argument types must match."));
}
if ((read == false || getter != null) && (write == false || setter != null)) {
semanticScope.setCondition(userIndexNode, Read.class);
semanticScope.putDecoration(userIndexNode, new TargetType(int.class));
checkedVisit(userIndexNode, semanticScope);
decorateWithCast(userIndexNode, semanticScope);
valueType = setter != null ? setter.typeParameters().get(1) : getter.returnType();
if (getter != null) {
semanticScope.putDecoration(userBraceNode, new GetterPainlessMethod(getter));
}
if (setter != null) {
semanticScope.putDecoration(userBraceNode, new SetterPainlessMethod(setter));
}
} else {
throw userBraceNode.createError(
new IllegalArgumentException("Illegal list shortcut for type [" + canonicalClassName + "].")
);
}
semanticScope.setCondition(userBraceNode, ListShortcut.class);
} else {
throw userBraceNode.createError(
new IllegalArgumentException(
"Illegal array access on type " + "[" + PainlessLookupUtility.typeToCanonicalTypeName(prefixValueType) + "]."
)
);
}
semanticScope.putDecoration(userBraceNode, new ValueType(valueType));
}