diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Utility.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Utility.java index b4e2f2a553830..1430c92f47932 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Utility.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Utility.java @@ -34,5 +34,31 @@ public static char StringTochar(final String value) { return value.charAt(0); } + public static String toOrdinal(int number) { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append(number); + int hundredModule = number % 100; + int decimalModule = number % 10; + if (11 <= hundredModule && hundredModule <= 13) { + stringBuilder.append("th"); + } else { + switch (decimalModule) { + case 1: + stringBuilder.append("st"); + break; + case 2: + stringBuilder.append("nd"); + break; + case 3: + stringBuilder.append("rd"); + break; + default: + stringBuilder.append("th"); + break; + } + } + return stringBuilder.toString(); + } + private Utility() {} } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/phase/DefaultConstantFoldingOptimizationPhase.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/phase/DefaultConstantFoldingOptimizationPhase.java index 33ec5e7e5e0f9..5181041fec406 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/phase/DefaultConstantFoldingOptimizationPhase.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/phase/DefaultConstantFoldingOptimizationPhase.java @@ -10,6 +10,7 @@ import org.elasticsearch.painless.AnalyzerCaster; import org.elasticsearch.painless.Operation; +import org.elasticsearch.painless.Utility; import org.elasticsearch.painless.ir.BinaryImplNode; import org.elasticsearch.painless.ir.BinaryMathNode; import org.elasticsearch.painless.ir.BooleanNode; @@ -66,9 +67,11 @@ import org.elasticsearch.painless.symbol.IRDecorations.IRDInstanceBinding; import org.elasticsearch.painless.symbol.IRDecorations.IRDMethod; import org.elasticsearch.painless.symbol.IRDecorations.IRDOperation; +import org.elasticsearch.painless.symbol.IRDecorations.IRDName; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.Locale; import java.util.function.Consumer; /** @@ -1107,13 +1110,19 @@ private void replaceCallWithConstant( ExpressionNode argNode = irInvokeCallMemberNode.getArgumentNodes().get(i); IRDConstant constantDecoration = argNode.getDecoration(IRDConstant.class); if (constantDecoration == null) { - // TODO find a better string to output - throw irInvokeCallMemberNode.getLocation() - .createError( - new IllegalArgumentException( - "all arguments to [" + javaMethod.getName() + "] must be constant but the [" + (i + 1) + "] argument isn't" - ) - ); + // offering the symbol name in error message (CastNode was evolved from ESymbol) + String argumentName = argNode instanceof CastNode + ? ((CastNode) argNode).getChildNode().getDecoration(IRDName.class).getValue() + : ""; + throw irInvokeCallMemberNode + .getLocation() + .createError(new IllegalArgumentException(String.format( + Locale.ROOT, + "All arguments of the [%s] method must be constants, but the [%s] argument [%s] is not", + javaMethod.getName(), + Utility.toOrdinal(i+1), + argumentName + ))); } args[i] = constantDecoration.getValue(); } diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/BindingsTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/BindingsTests.java index 90c517fbdce2a..45fa49d2ace27 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/BindingsTests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/BindingsTests.java @@ -240,7 +240,7 @@ public void testClassMethodCompileTimeOnlyVariableParams() { IllegalArgumentException.class, () -> scriptEngine.compile(null, "def a = 2; classMul(2, a)", BindingsTestScript.CONTEXT, Collections.emptyMap()) ); - assertThat(e.getMessage(), equalTo("all arguments to [classMul] must be constant but the [2] argument isn't")); + assertThat(e.getMessage(), equalTo("All arguments of the [classMul] method must be constants, but the [2nd] argument [a] is not")); } public void testClassMethodCompileTimeOnlyThrows() { @@ -269,7 +269,7 @@ public void testInstanceMethodCompileTimeOnlyVariableParams() { IllegalArgumentException.class, () -> scriptEngine.compile(null, "def a = 2; instanceMul(a, 2)", BindingsTestScript.CONTEXT, Collections.emptyMap()) ); - assertThat(e.getMessage(), equalTo("all arguments to [instanceMul] must be constant but the [1] argument isn't")); + assertThat(e.getMessage(), equalTo("All arguments of the [instanceMul] method must be constants, but the [1st] argument [a] is not")); } public void testCompileTimeOnlyParameterFoldedToConstant() { diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/UtilityTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/UtilityTests.java new file mode 100644 index 0000000000000..7b73b56af3319 --- /dev/null +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/UtilityTests.java @@ -0,0 +1,53 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +package org.elasticsearch.painless; + +import org.elasticsearch.test.ESTestCase; + +import java.util.Map; + +import static java.util.Map.entry; + +public class UtilityTests extends ESTestCase { + + public static final Map ORDINALS = Map.ofEntries( + entry(0, "0th"), + entry(1, "1st"), + entry(2, "2nd"), + entry(3, "3rd"), + entry(4, "4th"), + entry(5, "5th"), + entry(10, "10th"), + entry(11, "11th"), + entry(12, "12th"), + entry(13, "13th"), + entry(14, "14th"), + entry(20, "20th"), + entry(21, "21st"), + entry(22, "22nd"), + entry(23, "23rd"), + entry(24, "24th"), + entry(100, "100th"), + entry(101, "101st"), + entry(102, "102nd"), + entry(103, "103rd"), + entry(104, "104th"), + entry(111, "111th"), + entry(112, "112th"), + entry(113, "113th"), + entry(114, "114th"), + entry(1000, "1000th") + ); + + public void testToOrdinal() { + for (Map.Entry item : ORDINALS.entrySet()) { + assertEquals(Utility.toOrdinal(item.getKey()), item.getValue()); + } + } +} diff --git a/modules/runtime-fields-common/src/yamlRestTest/resources/rest-api-spec/test/runtime_fields/250_grok.yml b/modules/runtime-fields-common/src/yamlRestTest/resources/rest-api-spec/test/runtime_fields/250_grok.yml index f089203374100..0616bff7a051c 100644 --- a/modules/runtime-fields-common/src/yamlRestTest/resources/rest-api-spec/test/runtime_fields/250_grok.yml +++ b/modules/runtime-fields-common/src/yamlRestTest/resources/rest-api-spec/test/runtime_fields/250_grok.yml @@ -80,7 +80,7 @@ fetch: --- mutable pattern: - do: - catch: /all arguments to \[grok\] must be constant but the \[1\] argument isn't/ + catch: /All arguments of the \[grok\] method must be constants, but the \[1st\] argument \[\] is not/ search: index: http_logs body: diff --git a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/runtime_fields/250_grok.yml b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/runtime_fields/250_grok.yml index 8f369c97ace8d..382e56b2ed79c 100644 --- a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/runtime_fields/250_grok.yml +++ b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/runtime_fields/250_grok.yml @@ -80,7 +80,7 @@ fetch: --- mutable pattern: - do: - catch: /all arguments to \[grok\] must be constant but the \[1\] argument isn't/ + catch: /All arguments of the \[grok\] method must be constants, but the \[1st\] argument \[\] is not/ search: index: http_logs body: