Skip to content

Commit dec124e

Browse files
Allow Void expressions to be used within ForAll (#1527)
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 ) )
1 parent 5de68e1 commit dec124e

File tree

5 files changed

+45
-5
lines changed

5 files changed

+45
-5
lines changed

src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/ForAll.cs

+12-2
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ public override bool CheckTypes(CheckTypesContext context, TexlNode[] args, DTyp
4646
Contracts.Assert(args.Length == argTypes.Length);
4747
Contracts.AssertValue(errors);
4848

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

5152
if (argTypes[1].IsRecord)
5253
{
@@ -56,6 +57,10 @@ public override bool CheckTypes(CheckTypesContext context, TexlNode[] args, DTyp
5657
{
5758
returnType = DType.CreateTable(new TypedName(argTypes[1], ColumnName_Value));
5859
}
60+
else if (argTypes[1].IsVoid)
61+
{
62+
returnType = argTypes[1];
63+
}
5964
else
6065
{
6166
returnType = DType.Error;
@@ -104,7 +109,8 @@ public override bool CheckTypes(CheckTypesContext context, TexlNode[] args, DTyp
104109
Contracts.Assert(args.Length == argTypes.Length);
105110
Contracts.AssertValue(errors);
106111

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

109115
if (argTypes[1].IsRecord)
110116
{
@@ -114,6 +120,10 @@ public override bool CheckTypes(CheckTypesContext context, TexlNode[] args, DTyp
114120
{
115121
returnType = DType.CreateTable(new TypedName(argTypes[1], ColumnName_Value));
116122
}
123+
else if (argTypes[1].IsVoid)
124+
{
125+
returnType = argTypes[1];
126+
}
117127
else
118128
{
119129
returnType = DType.Error;

src/libraries/Microsoft.PowerFx.Interpreter/Functions/Library.cs

+6-1
Original file line numberDiff line numberDiff line change
@@ -2485,7 +2485,12 @@ public static async ValueTask<FormulaValue> ForAll(EvalVisitor runner, EvalVisit
24852485
if (errorRows.Any())
24862486
{
24872487
return ErrorValue.Combine(irContext, errorRows);
2488-
}
2488+
}
2489+
2490+
if (irContext.ResultType is Types.Void)
2491+
{
2492+
return new VoidValue(irContext);
2493+
}
24892494

24902495
return new InMemoryTableValue(irContext, StandardTableNodeRecords(irContext, rows.ToArray(), forceSingleColumn: false));
24912496
}

src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryUntypedObject.cs

+6-1
Original file line numberDiff line numberDiff line change
@@ -555,7 +555,12 @@ public static async ValueTask<FormulaValue> ForAll_UO(EvalVisitor runner, EvalVi
555555
if (errorRows.Any())
556556
{
557557
return ErrorValue.Combine(irContext, errorRows);
558-
}
558+
}
559+
560+
if (irContext.ResultType is Types.Void)
561+
{
562+
return new VoidValue(irContext);
563+
}
559564

560565
return new InMemoryTableValue(irContext, StandardTableNodeRecords(irContext, rows.ToArray(), forceSingleColumn: false));
561566
}

src/tests/Microsoft.PowerFx.Core.Tests/ExpressionTestCases/ForAll.txt

+20
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,23 @@ Table({Value:true})
8989
>> ForAll([Blank()],IsBlank(ThisRecord))
9090
Table({Value:false})
9191

92+
// ************ ForAll and Void expressions ****************
93+
94+
>> ForAll([1,2], If(Value = 1, Value * 2, {Result: Value}))
95+
If(true, {test:1}, "Mismatched args (result of the expression can't be used).")
96+
97+
>> ForAll([1,2,3] As p, Switch(p.Value, 1, {a:1}, 2, [{a:2}], 3, "Hello"))
98+
If(true, {test:1}, "Mismatched args (result of the expression can't be used).")
99+
100+
>> ForAll(ParseJSON("[1,2]"), If(Value(ThisRecord) = 1, Value(ThisRecord) * 2, {Result: Value(ThisRecord)}))
101+
If(true, {test:1}, "Mismatched args (result of the expression can't be used).")
102+
103+
>> ForAll(ParseJSON("[1,2,3]"), Switch(Value(ThisRecord), 1, {a:1}, 2, [{a:2}], 3, "Hello"))
104+
If(true, {test:1}, "Mismatched args (result of the expression can't be used).")
105+
106+
// Errors are returned
107+
>> ForAll([1,2], If(Value = 1, Sqrt(-Value), {Result: Value}))
108+
Error({Kind:ErrorKind.Numeric})
109+
110+
>> ForAll(ParseJSON("[""1"",""a""]"), If(Text(ThisRecord) = "1", Value(ThisRecord) * 2, Value(ThisRecord)))
111+
Error({Kind:ErrorKind.InvalidArgument})

src/tests/Microsoft.PowerFx.Core.Tests/TexlTests.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -589,7 +589,7 @@ public void TexlFunctionTypeSemanticsIf()
589589
[InlineData("Hour(If(1 < 0, [1], 2))", "n", false)]
590590

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

0 commit comments

Comments
 (0)