Code review comment: It can accept only one argument, the output of array_generate(3) is [1,2,3]

Code before review:
public Void visitFunctionCall(FunctionCallExpr node, Scope scope) {
Type[] argumentTypes = node.getChildren().stream().map(Expr::getType).toArray(Type[]::new);
if (node.isNondeterministicBuiltinFnName()) {
ExprId exprId = analyzeState.getNextNondeterministicId();
node.setNondeterministicId(exprId);
}
Function fn;
String fnName = node.getFnName().getFunction();
if (fnName.equals(FunctionSet.COUNT) && node.getParams().isDistinct()) {
fn = Expr.getBuiltinFunction(FunctionSet.COUNT, new Type[] {argumentTypes[0]},
Function.CompareMode.IS_NONSTRICT_SUPERTYPE_OF);
} else if (fnName.equals(FunctionSet.EXCHANGE_BYTES) || fnName.equals(FunctionSet.EXCHANGE_SPEED)) {
fn = Expr.getBuiltinFunction(fnName, argumentTypes,
Function.CompareMode.IS_NONSTRICT_SUPERTYPE_OF);
fn.setArgsType(argumentTypes);
fn.setIsNullable(false);
} else if (fnName.equals(FunctionSet.TIME_SLICE) || fnName.equals(FunctionSet.DATE_SLICE)) {
if (!(node.getChild(1) instanceof IntLiteral)) {
throw new SemanticException(
fnName + " requires second parameter must be a constant interval");
}
if (((IntLiteral) node.getChild(1)).getValue() <= 0) {
throw new SemanticException(
fnName + " requires second parameter must be greater than 0");
}
fn = Expr.getBuiltinFunction(fnName, argumentTypes, Function.CompareMode.IS_NONSTRICT_SUPERTYPE_OF);
} else if (FunctionSet.decimalRoundFunctions.contains(fnName) ||
Arrays.stream(argumentTypes).anyMatch(Type::isDecimalV3)) {
if (FunctionSet.varianceFunctions.contains(fnName)) {
Type[] doubleArgTypes = Stream.of(argumentTypes).map(t -> Type.DOUBLE).toArray(Type[]::new);
fn = Expr.getBuiltinFunction(fnName, doubleArgTypes,
Function.CompareMode.IS_NONSTRICT_SUPERTYPE_OF);
} else {
fn = getDecimalV3Function(node, argumentTypes);
}
} else if (Arrays.stream(argumentTypes).anyMatch(arg -> arg.matchesType(Type.TIME))) {
fn = Expr.getBuiltinFunction(fnName, argumentTypes, Function.CompareMode.IS_NONSTRICT_SUPERTYPE_OF);
if (fn instanceof AggregateFunction) {
throw new SemanticException("Time Type can not used in %s function",
fnName);
}
} else if (FunctionSet.STR_TO_DATE.equals(fnName)) {
fn = getStrToDateFunction(node, argumentTypes);
} else if (fnName.equals(FunctionSet.ARRAY_FILTER)) {
if (node.getChildren().size() != 2) {
throw new SemanticException(fnName + " should have 2 array inputs or lambda functions.");
}
if (!node.getChild(0).getType().isArrayType() && !node.getChild(0).getType().isNull()) {
throw new SemanticException("The first input of " + fnName +
" should be an array or a lambda function.");
}
if (!node.getChild(1).getType().isArrayType() && !node.getChild(1).getType().isNull()) {
throw new SemanticException("The second input of " + fnName +
" should be an array or a lambda function.");
}
if (!Type.canCastTo(node.getChild(1).getType(), Type.ARRAY_BOOLEAN)) {
throw new SemanticException("The second input of array_filter " +
node.getChild(1).getType().toString() + "  can't cast to ARRAY<BOOL>");
}
node.setChild(1, new CastExpr(Type.ARRAY_BOOLEAN, node.getChild(1)));
argumentTypes[1] = Type.ARRAY_BOOLEAN;
fn = Expr.getBuiltinFunction(fnName, argumentTypes, Function.CompareMode.IS_NONSTRICT_SUPERTYPE_OF);
} else if (fnName.equals(FunctionSet.ARRAY_SORTBY)) {
if (node.getChildren().size() != 2) {
throw new SemanticException(fnName + " should have 2 array inputs or lambda functions.");
}
if (!node.getChild(0).getType().isArrayType() && !node.getChild(0).getType().isNull()) {
throw new SemanticException("The first input of " + fnName +
" should be an array or a lambda function.");
}
if (!node.getChild(1).getType().isArrayType() && !node.getChild(1).getType().isNull()) {
throw new SemanticException("The second input of " + fnName +
" should be an array or a lambda function.");
}
fn = Expr.getBuiltinFunction(fnName, argumentTypes, Function.CompareMode.IS_NONSTRICT_SUPERTYPE_OF);
} else if (fnName.equals(FunctionSet.ARRAY_SLICE)) {
for (int i = 1; i < argumentTypes.length; i++) {
argumentTypes[i] = Type.BIGINT;
}
fn = Expr.getBuiltinFunction(fnName, argumentTypes, Function.CompareMode.IS_SUPERTYPE_OF);
} else if (fnName.equals(FunctionSet.ARRAY_CONCAT)) {
if (node.getChildren().size() < 2) {
throw new SemanticException(fnName + " should have at least two inputs");
}
fn = Expr.getBuiltinFunction(fnName, argumentTypes, Function.CompareMode.IS_NONSTRICT_SUPERTYPE_OF);
} else if (fnName.equals("array_generate")) {
if (node.getChildren().size() < 1 || node.getChildren().size() > 3) {
throw new SemanticException(fnName + " has wrong input numbers");
}
for (Expr expr : node.getChildren()) {
if ((expr instanceof SlotRef) && node.getChildren().size() != 3) {
throw new SemanticException(fnName + " with IntColumn doesn't support default parameters");
}
if (!(expr instanceof IntLiteral) && !(expr instanceof LargeIntLiteral) &&
!(expr instanceof SlotRef) && !(expr instanceof NullLiteral)) {
throw new SemanticException(fnName + "'s parameter only support Integer");
}
}
if (node.getChildren().size() == 1) {
LiteralExpr secondParam = (LiteralExpr) node.getChild(0);
node.clearChildren();
try {
node.addChild(new IntLiteral("1", Type.TINYINT));
node.addChild(secondParam);
} catch (AnalysisException e) {
throw new SemanticException(e.getMessage());
}
}
if (node.getChildren().size() == 2) {
int idx = 0;
BigInteger[] childValues = new BigInteger[2];
for (Expr expr : node.getChildren()) {
if (expr instanceof NullLiteral) {
throw new SemanticException(fnName + "'s parameter only support Integer");
} else if (expr instanceof IntLiteral) {
childValues[idx++] = BigInteger.valueOf(((IntLiteral) expr).getValue());
} else {
childValues[idx++] = ((LargeIntLiteral) expr).getValue();
}
}
if (childValues[0].compareTo(childValues[1]) < 0) {
node.addChild(new IntLiteral(1));
} else {
node.addChild(new IntLiteral(-1));
}
}
argumentTypes = node.getChildren().stream().map(Expr::getType).toArray(Type[]::new);
fn = Expr.getBuiltinFunction(fnName, argumentTypes, Function.CompareMode.IS_SUPERTYPE_OF);
} else {
fn = Expr.getBuiltinFunction(fnName, argumentTypes, Function.CompareMode.IS_NONSTRICT_SUPERTYPE_OF);
}
if (fn == null) {
fn = AnalyzerUtils.getUdfFunction(session, node.getFnName(), argumentTypes);
}
if (fn == null) {
throw new SemanticException("No matching function with signature: %s(%s).",
fnName,
node.getParams().isStar() ? "*" : Joiner.on(", ")
.join(Arrays.stream(argumentTypes).map(Type::toSql).collect(Collectors.toList())));
}
if (fn instanceof TableFunction) {
throw unsupportedException("Table function cannot be used in expression");
}
for (int i = 0; i < fn.getNumArgs(); i++) {
if (!argumentTypes[i].matchesType(fn.getArgs()[i]) &&
!Type.canCastToAsFunctionParameter(argumentTypes[i], fn.getArgs()[i])) {
throw new SemanticException("No matching function with signature: %s(%s).", fnName,
node.getParams().isStar() ? "*" : Joiner.on(", ")
.join(Arrays.stream(argumentTypes).map(Type::toSql).collect(Collectors.toList())));
}
}
node.setFn(fn);
node.setType(fn.getReturnType());
FunctionAnalyzer.analyze(node);
return null;
}

Line under review: if (node.getChildren().size() < 1 || node.getChildren().size() > 3) {

Code after addressing the review:
public Void visitFunctionCall(FunctionCallExpr node, Scope scope) {
Type[] argumentTypes = node.getChildren().stream().map(Expr::getType).toArray(Type[]::new);
if (node.isNondeterministicBuiltinFnName()) {
ExprId exprId = analyzeState.getNextNondeterministicId();
node.setNondeterministicId(exprId);
}
Function fn;
String fnName = node.getFnName().getFunction();
checkFunction(fnName, node);
if (fnName.equals(FunctionSet.COUNT) && node.getParams().isDistinct()) {
fn = Expr.getBuiltinFunction(FunctionSet.COUNT, new Type[] {argumentTypes[0]},
Function.CompareMode.IS_NONSTRICT_SUPERTYPE_OF);
} else if (fnName.equals(FunctionSet.EXCHANGE_BYTES) || fnName.equals(FunctionSet.EXCHANGE_SPEED)) {
fn = Expr.getBuiltinFunction(fnName, argumentTypes, Function.CompareMode.IS_NONSTRICT_SUPERTYPE_OF);
fn.setArgsType(argumentTypes);
fn.setIsNullable(false);
} else if (DecimalV3FunctionAnalyzer.argumentTypeContainDecimalV3(fnName, argumentTypes)) {
fn = DecimalV3FunctionAnalyzer.getDecimalV3Function(session, node, argumentTypes);
} else if (Arrays.stream(argumentTypes).anyMatch(arg -> arg.matchesType(Type.TIME))) {
fn = Expr.getBuiltinFunction(fnName, argumentTypes, Function.CompareMode.IS_NONSTRICT_SUPERTYPE_OF);
if (fn instanceof AggregateFunction) {
throw new SemanticException("Time Type can not used in" + fnName + " function", node.getPos());
}
} else if (FunctionSet.STR_TO_DATE.equals(fnName)) {
fn = getStrToDateFunction(node, argumentTypes);
} else if (FunctionSet.ARRAY_GENERATE.equals(fnName)) {
fn = getArrayGenerateFunction(node);
argumentTypes = node.getChildren().stream().map(Expr::getType).toArray(Type[]::new);
} else {
fn = Expr.getBuiltinFunction(fnName, argumentTypes, Function.CompareMode.IS_NONSTRICT_SUPERTYPE_OF);
}
if (fn == null) {
fn = AnalyzerUtils.getUdfFunction(session, node.getFnName(), argumentTypes);
}
if (fn == null) {
String msg = String.format("No matching function with signature: %s(%s)",
fnName,
node.getParams().isStar() ? "*" : Joiner.on(", ")
.join(Arrays.stream(argumentTypes).map(Type::toSql).collect(Collectors.toList())));
throw new SemanticException(msg, node.getPos());
}
if (fn instanceof TableFunction) {
throw new SemanticException("Table function cannot be used in expression", node.getPos());
}
for (int i = 0; i < fn.getNumArgs(); i++) {
if (!argumentTypes[i].matchesType(fn.getArgs()[i]) &&
!Type.canCastToAsFunctionParameter(argumentTypes[i], fn.getArgs()[i])) {
String msg = String.format("No matching function with signature: %s(%s)", fnName,
node.getParams().isStar() ? "*" :
Arrays.stream(argumentTypes).map(Type::toSql).collect(Collectors.joining(", ")));
throw new SemanticException(msg, node.getPos());
}
}
if (fn.hasVarArgs()) {
Type varType = fn.getArgs()[fn.getNumArgs() - 1];
for (int i = fn.getNumArgs(); i < argumentTypes.length; i++) {
if (!argumentTypes[i].matchesType(varType) &&
!Type.canCastToAsFunctionParameter(argumentTypes[i], varType)) {
String msg = String.format("Variadic function %s(%s) can't support type: %s", fnName,
Arrays.stream(fn.getArgs()).map(Type::toSql).collect(Collectors.joining(", ")),
argumentTypes[i]);
throw new SemanticException(msg, node.getPos());
}
}
}
node.setFn(fn);
node.setType(fn.getReturnType());
FunctionAnalyzer.analyze(node);
return null;
}