diff --git a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Patch.cs b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Patch.cs index 16fcf629e0..a795bc80d5 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Patch.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Patch.cs @@ -707,22 +707,7 @@ public override bool CheckTypes(CheckTypesContext context, TexlNode[] args, DTyp continue; } - // Ensure that if the key in argument1 exists in the current record, their types match. - bool isSafeToUnion = true; - foreach (var typedName in curType.GetNames(DPath.Root)) - { - DName name = typedName.Name; - if (recordType.TryGetType(name, out DType nameType) && !nameType.Accepts(typedName.Type, exact: true, useLegacyDateTimeAccepts: false, usePowerFxV1CompatibilityRules: context.Features.PowerFxV1CompatibilityRules)) - { - errors.EnsureError(args[i], TexlStrings.ErrTypeError_Arg_Expected_Found, name, nameType.GetKindString(), typedName.Type.GetKindString()); - isValid = isSafeToUnion = false; - } - } - - if (isSafeToUnion) - { - retType = DType.Union(retType, curType, useLegacyDateTimeAccepts: false, context.Features); - } + retType = DType.Union(retType, curType, useLegacyDateTimeAccepts: false, context.Features); } returnType = retType; diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/TexlTests.cs b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/TexlTests.cs index e23bdc191f..91b2a9a03a 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/TexlTests.cs +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/TexlTests.cs @@ -4559,18 +4559,51 @@ public void TexlFunctionTypeSemanticsTable_PageableInputs(string script, string [InlineData("Abs(Type(Number))", "n")] [InlineData("If(Type(Boolean), 1, 2)", "n")] [InlineData("Concatenate(Type(Text))", "s")] - public void TestTypeLiteralsNegative(string script, string expectedSchema) - { - TestBindingErrors( - script, - TestUtils.DT(expectedSchema), - features: Features.PowerFxV1); - } - - [Theory] - - // Exact type match: all arguments directly match the data source schema *[Name:s, Value:n] - [InlineData("Patch(MyDataSource, MyRecord, { Name: \"Hello\", Value: 1 })", true)] + public void TestTypeLiteralsNegative(string script, string expectedSchema) + { + TestBindingErrors( + script, + TestUtils.DT(expectedSchema), + features: Features.PowerFxV1); + } + + [Theory] + [InlineData("Patch({a:1}, {b:2})", "![a:n, b:n]")] + [InlineData("Patch({a:1}, {b:\"test\"})", "![a:n, b:s]")] + [InlineData("Patch({a:1, b:2}, {b:\"3\", c:4})", "![a:n, b:s, c:n]")] + [InlineData("Patch({x:true}, {y:Date(2020,1,1)})", "![x:b, y:D]")] + public void TestPatchRecordFunction(string script, string expectedType) + { + Assert.True(DType.TryParse(expectedType, out var type), script); + Assert.True(type.IsValid, script); + + TestSimpleBindingSuccess(script, type); + } + + [Theory] + [InlineData("Patch(rec1, {b:2})", "![a:n, b:n]", "![a:n]", "rec1")] + [InlineData("Patch(rec2, {c:\"new\"})", "![a:n, b:s, c:s]", "![a:n, b:s]", "rec2")] + [InlineData("Patch(rec3, {b:3, c:4})", "![a:n, b:n, c:n]", "![a:n, b:n]", "rec3")] + [InlineData("Patch(rec4, {y:Date(2020,1,1)})", "![x:b, y:D]", "![x:b]", "rec4")] + [InlineData("Patch(rec5, {x:123})", "![x:$]", "![x:$]", "rec5")] + public void TestPatchRecordFunctionWithVariable(string script, string expectedType, string variableType, string variableName) + { + Assert.True(DType.TryParse(expectedType, out var type), script); + Assert.True(type.IsValid, script); + + Assert.True(DType.TryParse(variableType, out var varType), script); + Assert.True(varType.IsValid, script); + + var symbol = new SymbolTable(); + symbol.AddVariable(variableName, FormulaType.Build(varType)); + + TestSimpleBindingSuccess(script, type, symbol); + } + + [Theory] + + // Exact type match: all arguments directly match the data source schema *[Name:s, Value:n] + [InlineData("Patch(MyDataSource, MyRecord, { Name: \"Hello\", Value: 1 })", true)] // Exact type match: all arguments directly match the data source schema using display names [InlineData("Patch(MyDataSource, MyRecord, { DisplayNameForName: \"Hello\", DisplayNameForValue: 1 })", true)]