Skip to content

Commit

Permalink
Allow Void expressions to be used within ForAll (#1527)
Browse files Browse the repository at this point in the history
If a ForAll expression is used within a context where its result is not needed, then it should be able to use void expressions, like in the example below. This change allows it, making the entire result of the ForAll expression a void result.

    ForAll(
        Sequence(4),
        If(
            Mod(Value, 2) = 1,
Patch( table, Index(table, Value), { IsOdd: true } ), // this returns a
record, incompatible with tables
Collect( table, { Value: Value, IsOdd: false }, { Value: Value + 1,
IsOdd: true } // this returns a table
        )
    )
  • Loading branch information
CarlosFigueiraMSFT authored May 24, 2023
1 parent 5de68e1 commit dec124e
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 5 deletions.
14 changes: 12 additions & 2 deletions src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/ForAll.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ public override bool CheckTypes(CheckTypesContext context, TexlNode[] args, DTyp
Contracts.Assert(args.Length == argTypes.Length);
Contracts.AssertValue(errors);

var fArgsValid = base.CheckTypes(context, args, argTypes, errors, out returnType, out nodeToCoercedTypeMap);
nodeToCoercedTypeMap = null;
var fArgsValid = CheckType(context, args[0], argTypes[0], ParamTypes[0], errors, ref nodeToCoercedTypeMap);

if (argTypes[1].IsRecord)
{
Expand All @@ -56,6 +57,10 @@ public override bool CheckTypes(CheckTypesContext context, TexlNode[] args, DTyp
{
returnType = DType.CreateTable(new TypedName(argTypes[1], ColumnName_Value));
}
else if (argTypes[1].IsVoid)
{
returnType = argTypes[1];
}
else
{
returnType = DType.Error;
Expand Down Expand Up @@ -104,7 +109,8 @@ public override bool CheckTypes(CheckTypesContext context, TexlNode[] args, DTyp
Contracts.Assert(args.Length == argTypes.Length);
Contracts.AssertValue(errors);

var fArgsValid = base.CheckTypes(context, args, argTypes, errors, out returnType, out nodeToCoercedTypeMap);
nodeToCoercedTypeMap = null;
var fArgsValid = CheckType(context, args[0], argTypes[0], ParamTypes[0], errors, ref nodeToCoercedTypeMap);

if (argTypes[1].IsRecord)
{
Expand All @@ -114,6 +120,10 @@ public override bool CheckTypes(CheckTypesContext context, TexlNode[] args, DTyp
{
returnType = DType.CreateTable(new TypedName(argTypes[1], ColumnName_Value));
}
else if (argTypes[1].IsVoid)
{
returnType = argTypes[1];
}
else
{
returnType = DType.Error;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2485,7 +2485,12 @@ public static async ValueTask<FormulaValue> ForAll(EvalVisitor runner, EvalVisit
if (errorRows.Any())
{
return ErrorValue.Combine(irContext, errorRows);
}
}

if (irContext.ResultType is Types.Void)
{
return new VoidValue(irContext);
}

return new InMemoryTableValue(irContext, StandardTableNodeRecords(irContext, rows.ToArray(), forceSingleColumn: false));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,12 @@ public static async ValueTask<FormulaValue> ForAll_UO(EvalVisitor runner, EvalVi
if (errorRows.Any())
{
return ErrorValue.Combine(irContext, errorRows);
}
}

if (irContext.ResultType is Types.Void)
{
return new VoidValue(irContext);
}

return new InMemoryTableValue(irContext, StandardTableNodeRecords(irContext, rows.ToArray(), forceSingleColumn: false));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,23 @@ Table({Value:true})
>> ForAll([Blank()],IsBlank(ThisRecord))
Table({Value:false})

// ************ ForAll and Void expressions ****************

>> ForAll([1,2], If(Value = 1, Value * 2, {Result: Value}))
If(true, {test:1}, "Mismatched args (result of the expression can't be used).")

>> ForAll([1,2,3] As p, Switch(p.Value, 1, {a:1}, 2, [{a:2}], 3, "Hello"))
If(true, {test:1}, "Mismatched args (result of the expression can't be used).")

>> ForAll(ParseJSON("[1,2]"), If(Value(ThisRecord) = 1, Value(ThisRecord) * 2, {Result: Value(ThisRecord)}))
If(true, {test:1}, "Mismatched args (result of the expression can't be used).")

>> ForAll(ParseJSON("[1,2,3]"), Switch(Value(ThisRecord), 1, {a:1}, 2, [{a:2}], 3, "Hello"))
If(true, {test:1}, "Mismatched args (result of the expression can't be used).")

// Errors are returned
>> ForAll([1,2], If(Value = 1, Sqrt(-Value), {Result: Value}))
Error({Kind:ErrorKind.Numeric})

>> ForAll(ParseJSON("[""1"",""a""]"), If(Text(ThisRecord) = "1", Value(ThisRecord) * 2, Value(ThisRecord)))
Error({Kind:ErrorKind.InvalidArgument})
2 changes: 1 addition & 1 deletion src/tests/Microsoft.PowerFx.Core.Tests/TexlTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -589,7 +589,7 @@ public void TexlFunctionTypeSemanticsIf()
[InlineData("Hour(If(1 < 0, [1], 2))", "n", false)]

// ForAll([1,2,3], V)
[InlineData("ForAll([1,2,3], If(1 < 0, [1], 2))", "e", false)]
[InlineData("ForAll([1,2,3], If(1 < 0, [1], 2))", "-", true)]
public void TexlFunctionTypeSemanticsIfWithArgumentCoercion(string expression, string expectedType, bool checkSuccess)
{
var symbol = new SymbolTable();
Expand Down

0 comments on commit dec124e

Please sign in to comment.