diff --git a/src/libraries/Microsoft.PowerFx.Core/Public/Engine.cs b/src/libraries/Microsoft.PowerFx.Core/Public/Engine.cs index 480bab8594..01aba402d2 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Public/Engine.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Public/Engine.cs @@ -84,9 +84,9 @@ public Engine(PowerFxConfig powerFxConfig) public ReadOnlySymbolTable SupportedFunctions { get; protected internal set; } = _allBuiltinCoreFunctions; /// - /// Builtin Types supported by this engine. + /// Builtin Types supported by this engine for UDFs and UDTs. /// - public ReadOnlySymbolTable PrimitiveTypes { get; protected internal set; } = ReadOnlySymbolTable.PrimitiveTypesTableInstance; + public ReadOnlySymbolTable PrimitiveTypes { get; protected internal set; } // By default, we pull the core functions. // These can be overridden. diff --git a/src/libraries/Microsoft.PowerFx.Core/Public/Types/BooleanType.cs b/src/libraries/Microsoft.PowerFx.Core/Public/Types/BooleanType.cs index 31f64aa13c..b5465dcd89 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Public/Types/BooleanType.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Public/Types/BooleanType.cs @@ -3,11 +3,14 @@ using System.Text; using Microsoft.PowerFx.Core.Types; +using Microsoft.PowerFx.Core.Utils; namespace Microsoft.PowerFx.Types { public class BooleanType : FormulaType { + public override DName Name => new DName("Boolean"); + internal BooleanType() : base(DType.Boolean) { diff --git a/src/libraries/Microsoft.PowerFx.Core/Public/Types/ColorType.cs b/src/libraries/Microsoft.PowerFx.Core/Public/Types/ColorType.cs index cc4b8a687c..ba4d9c6a16 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Public/Types/ColorType.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Public/Types/ColorType.cs @@ -4,11 +4,14 @@ using System; using System.Text; using Microsoft.PowerFx.Core.Types; +using Microsoft.PowerFx.Core.Utils; namespace Microsoft.PowerFx.Types { public class ColorType : FormulaType { + public override DName Name => new DName("Color"); + internal ColorType() : base(DType.Color) { diff --git a/src/libraries/Microsoft.PowerFx.Core/Public/Types/DateTimeNoTimeZoneType.cs b/src/libraries/Microsoft.PowerFx.Core/Public/Types/DateTimeNoTimeZoneType.cs index 0902c6e77c..bc03b346a6 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Public/Types/DateTimeNoTimeZoneType.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Public/Types/DateTimeNoTimeZoneType.cs @@ -3,12 +3,15 @@ using System.Diagnostics; using Microsoft.PowerFx.Core.Types; +using Microsoft.PowerFx.Core.Utils; namespace Microsoft.PowerFx.Types { [DebuggerDisplay("{_type}:tzi")] public class DateTimeNoTimeZoneType : FormulaType { + public override DName Name => new DName("DateTimeTZInd"); + internal DateTimeNoTimeZoneType() : base(DType.DateTimeNoTimeZone) { diff --git a/src/libraries/Microsoft.PowerFx.Core/Public/Types/DateTimeType.cs b/src/libraries/Microsoft.PowerFx.Core/Public/Types/DateTimeType.cs index 89837f98f2..f9ad82d55f 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Public/Types/DateTimeType.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Public/Types/DateTimeType.cs @@ -10,6 +10,8 @@ namespace Microsoft.PowerFx.Types { public class DateTimeType : FormulaType { + public override DName Name => new DName("DateTime"); + internal DateTimeType() : base(DType.DateTime) { diff --git a/src/libraries/Microsoft.PowerFx.Core/Public/Types/DateType.cs b/src/libraries/Microsoft.PowerFx.Core/Public/Types/DateType.cs index 0ed02e46e1..5507bbf16f 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Public/Types/DateType.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Public/Types/DateType.cs @@ -9,6 +9,8 @@ namespace Microsoft.PowerFx.Types { public class DateType : FormulaType { + public override DName Name => new DName("Date"); + internal DateType() : base(DType.Date) { diff --git a/src/libraries/Microsoft.PowerFx.Core/Public/Types/DecimalType.cs b/src/libraries/Microsoft.PowerFx.Core/Public/Types/DecimalType.cs index dc3e9ea217..18b83e115f 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Public/Types/DecimalType.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Public/Types/DecimalType.cs @@ -2,12 +2,15 @@ // Licensed under the MIT license. using System.Text; -using Microsoft.PowerFx.Core.Types; +using Microsoft.PowerFx.Core.Types; +using Microsoft.PowerFx.Core.Utils; namespace Microsoft.PowerFx.Types { public class DecimalType : FormulaType - { + { + public override DName Name => new DName("Decimal"); + internal DecimalType() : base(DType.Decimal) { diff --git a/src/libraries/Microsoft.PowerFx.Core/Public/Types/FormulaType.cs b/src/libraries/Microsoft.PowerFx.Core/Public/Types/FormulaType.cs index 9ecc268047..e7f25a3797 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Public/Types/FormulaType.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Public/Types/FormulaType.cs @@ -23,7 +23,9 @@ public abstract class FormulaType #pragma warning disable SA1300 // Element should begin with upper-case letter // Uses init to allow setting from derived constructors. Otherwise, is immutable. internal DType _type { get; private protected init; } -#pragma warning restore SA1300 // Element should begin with upper-case letter +#pragma warning restore SA1300 // Element should begin with upper-case letter + + public virtual DName Name { get; } public static FormulaType Blank { get; } = new BlankType(); @@ -76,20 +78,20 @@ internal FormulaType(DType type) internal static readonly IReadOnlyDictionary PrimitiveTypes = ImmutableDictionary.CreateRange(new Dictionary() { - { new DName("Boolean"), Boolean }, - { new DName("Color"), Color }, - { new DName("Date"), Date }, - { new DName("Time"), Time }, - { new DName("DateTime"), DateTime }, - { new DName("DateTimeTZInd"), DateTimeNoTimeZone }, - { new DName("GUID"), Guid }, - { new DName("Number"), Number }, - { new DName("Decimal"), Decimal }, - { new DName("Text"), String }, - { new DName("Hyperlink"), Hyperlink }, - { new DName("None"), Blank }, - { new DName("Dynamic"), UntypedObject }, - { new DName("Void"), Void }, + { Boolean.Name, Boolean }, + { Color.Name, Color }, + { Date.Name, Date }, + { Time.Name, Time }, + { DateTime.Name, DateTime }, + { DateTimeNoTimeZone.Name, DateTimeNoTimeZone }, + { Guid.Name, Guid }, + { Number.Name, Number }, + { Decimal.Name, Decimal }, + { String.Name, String }, + { Hyperlink.Name, Hyperlink }, + { Blank.Name, Blank }, + { UntypedObject.Name, UntypedObject }, + { Void.Name, Void }, }); /// diff --git a/src/libraries/Microsoft.PowerFx.Core/Public/Types/GuidType.cs b/src/libraries/Microsoft.PowerFx.Core/Public/Types/GuidType.cs index ecfb52a3cb..9f627f0bbf 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Public/Types/GuidType.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Public/Types/GuidType.cs @@ -10,6 +10,8 @@ namespace Microsoft.PowerFx.Types { public class GuidType : FormulaType { + public override DName Name => new DName("GUID"); + internal GuidType() : base(DType.Guid) { diff --git a/src/libraries/Microsoft.PowerFx.Core/Public/Types/HyperlinkType.cs b/src/libraries/Microsoft.PowerFx.Core/Public/Types/HyperlinkType.cs index 40ea2cee8b..7887d60104 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Public/Types/HyperlinkType.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Public/Types/HyperlinkType.cs @@ -3,11 +3,14 @@ using System; using Microsoft.PowerFx.Core.Types; +using Microsoft.PowerFx.Core.Utils; namespace Microsoft.PowerFx.Types { public class HyperlinkType : FormulaType { + public override DName Name => new DName("Hyperlink"); + internal HyperlinkType() : base(DType.Hyperlink) { diff --git a/src/libraries/Microsoft.PowerFx.Core/Public/Types/NumberType.cs b/src/libraries/Microsoft.PowerFx.Core/Public/Types/NumberType.cs index 9f1f435706..22fe14d3b9 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Public/Types/NumberType.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Public/Types/NumberType.cs @@ -3,11 +3,14 @@ using System.Text; using Microsoft.PowerFx.Core.Types; +using Microsoft.PowerFx.Core.Utils; namespace Microsoft.PowerFx.Types { public class NumberType : FormulaType { + public override DName Name => new DName("Number"); + internal NumberType() : base(DType.Number) { diff --git a/src/libraries/Microsoft.PowerFx.Core/Public/Types/StringType.cs b/src/libraries/Microsoft.PowerFx.Core/Public/Types/StringType.cs index 66d38e070e..31fc0c47f4 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Public/Types/StringType.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Public/Types/StringType.cs @@ -9,6 +9,8 @@ namespace Microsoft.PowerFx.Types { public class StringType : FormulaType { + public override DName Name => new DName("Text"); + public StringType() : base(DType.String) { diff --git a/src/libraries/Microsoft.PowerFx.Core/Public/Types/TimeType.cs b/src/libraries/Microsoft.PowerFx.Core/Public/Types/TimeType.cs index 1761084269..f513f23307 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Public/Types/TimeType.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Public/Types/TimeType.cs @@ -4,11 +4,14 @@ using System; using System.Text; using Microsoft.PowerFx.Core.Types; +using Microsoft.PowerFx.Core.Utils; namespace Microsoft.PowerFx.Types { public class TimeType : FormulaType { + public override DName Name => new DName("Time"); + internal TimeType() : base(DType.Time) { diff --git a/src/libraries/Microsoft.PowerFx.Core/Public/Types/UntypedObjectType.cs b/src/libraries/Microsoft.PowerFx.Core/Public/Types/UntypedObjectType.cs index 39a55ad342..086192b7c1 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Public/Types/UntypedObjectType.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Public/Types/UntypedObjectType.cs @@ -5,11 +5,14 @@ using System.Collections.Generic; using System.Text; using Microsoft.PowerFx.Core.Types; +using Microsoft.PowerFx.Core.Utils; namespace Microsoft.PowerFx.Types { public class UntypedObjectType : FormulaType { + public override DName Name => new DName("Dynamic"); + public UntypedObjectType() : base(DType.UntypedObject) { diff --git a/src/libraries/Microsoft.PowerFx.Core/Public/Types/Void.cs b/src/libraries/Microsoft.PowerFx.Core/Public/Types/Void.cs index 0c36c932ac..3b6451da6e 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Public/Types/Void.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Public/Types/Void.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using Microsoft.PowerFx.Core.Types; +using Microsoft.PowerFx.Core.Utils; using Microsoft.PowerFx.Types; namespace Microsoft.PowerFx.Types @@ -11,6 +12,8 @@ namespace Microsoft.PowerFx.Types /// public sealed class Void : FormulaType { + public override DName Name => new DName("Void"); + internal Void() : base(DType.Void) { diff --git a/src/libraries/Microsoft.PowerFx.Core/Syntax/UserDefinitions.cs b/src/libraries/Microsoft.PowerFx.Core/Syntax/UserDefinitions.cs index 47edc98322..aa2e6a4e21 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Syntax/UserDefinitions.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Syntax/UserDefinitions.cs @@ -35,7 +35,7 @@ internal sealed class UserDefinitions /// /// Restricted return type. /// - public static readonly ISet RestrictedTypes = ImmutableHashSet.Create(DType.DateTimeNoTimeZone, DType.ObjNull, DType.Decimal); + public static readonly ISet RestrictedTypes = ImmutableHashSet.Create(DType.ObjNull); /// /// REstricted parameter type. diff --git a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/UntypedOrJSONConversionFunction.cs b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/UntypedOrJSONConversionFunction.cs index 44381bb084..cfd7243948 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/UntypedOrJSONConversionFunction.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/UntypedOrJSONConversionFunction.cs @@ -37,6 +37,10 @@ public override bool HasSuggestionsForParam(int argIndex) return argIndex == 1; } + // This list is intersected with Engine.PrimitiveTypes, with outliers generating errors before this list is checked. + // In other words, just because a type is listed here, does not mean it is supported unless it is also in Engine.PrimitiveTypes. + // Notably this list excludes ObjNull and Void, which make no sense to use in JSON or UDFs (except for UDF return type for Void). + // It also excludes Color, as we have not implemented the coversion of "Red" and other color names. We could convert # hex colors but this has not been done. internal static readonly ISet SupportedJSONTypes = new HashSet { DType.Boolean, DType.Number, DType.Decimal, DType.Date, DType.DateTime, DType.DateTimeNoTimeZone, DType.Time, DType.String, DType.Guid, DType.Hyperlink, DType.UntypedObject }; public UntypedOrJSONConversionFunction(string name, TexlStrings.StringGetter description, DType returnType, int arityMax, params DType[] paramTypes) diff --git a/src/libraries/Microsoft.PowerFx.Interpreter/RecalcEngine.cs b/src/libraries/Microsoft.PowerFx.Interpreter/RecalcEngine.cs index f85f9ad6e4..2200481bc1 100644 --- a/src/libraries/Microsoft.PowerFx.Interpreter/RecalcEngine.cs +++ b/src/libraries/Microsoft.PowerFx.Interpreter/RecalcEngine.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Globalization; using System.Linq; using System.Text; @@ -43,6 +44,23 @@ public RecalcEngine() { } + internal static readonly ReadOnlySymbolTable _recalcPrimitiveTypes = + SymbolTable.NewDefaultTypes(ImmutableDictionary.CreateRange(new Dictionary() + { + { FormulaType.Boolean.Name, FormulaType.Boolean }, + { FormulaType.Color.Name, FormulaType.Color }, + { FormulaType.Date.Name, FormulaType.Date }, + { FormulaType.Time.Name, FormulaType.Time }, + { FormulaType.DateTime.Name, FormulaType.DateTime }, + { FormulaType.Guid.Name, FormulaType.Guid }, + { FormulaType.Number.Name, FormulaType.Number }, + { FormulaType.Decimal.Name, FormulaType.Decimal }, + { FormulaType.String.Name, FormulaType.String }, // Text + { FormulaType.Hyperlink.Name, FormulaType.Hyperlink }, + { FormulaType.UntypedObject.Name, FormulaType.UntypedObject }, // Dynamic + { FormulaType.Void.Name, FormulaType.Void }, + })); + public RecalcEngine(PowerFxConfig powerFxConfig) : base(powerFxConfig) { @@ -52,6 +70,8 @@ public RecalcEngine(PowerFxConfig powerFxConfig) base.EngineSymbols = _symbolTable; + base.PrimitiveTypes = _recalcPrimitiveTypes; + // Add Builtin functions that aren't yet in the shared library. SupportedFunctions = _interpreterSupportedFunctions; } diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/AsType_UO.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/AsType_UO.txt index 8a45880cfb..a62b7ecf04 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/AsType_UO.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/AsType_UO.txt @@ -48,10 +48,10 @@ true false >> AsType(ParseJSON("""1900-12-31T00:00:00.000Z"""), DateTimeTZInd) -DateTime(1900,12,31,0,0,0,0) +Errors: Error 50-63: Name isn't valid. 'DateTimeTZInd' isn't recognized.|Error 0-64: Invalid argument 'DateTimeTZInd'. Expected valid type name or inline type expression. >> AsType(ParseJSON("""1900-12-31T00:00:00.000-08:00"""), DateTimeTZInd) -DateTime(1900,12,31,8,0,0,0) +Errors: Error 55-68: Name isn't valid. 'DateTimeTZInd' isn't recognized.|Error 0-69: Invalid argument 'DateTimeTZInd'. Expected valid type name or inline type expression. >> Value(AsType(ParseJSON("42"), Dynamic)) 42 @@ -119,10 +119,10 @@ Errors: Error 26-30: Unsupported type 'Void' in type argument. Errors: Error 0-59: Invalid number of arguments: received 3, expected 2. >> AsType(ParseJSON("true"), None) -Errors: Error 26-30: Unsupported type 'Blank' in type argument. +Errors: Error 26-30: Name isn't valid. 'None' isn't recognized.|Error 0-31: Invalid argument 'None'. Expected valid type name or inline type expression. >> AsType(ParseJSON("null"), None) -Errors: Error 26-30: Unsupported type 'Blank' in type argument. +Errors: Error 26-30: Name isn't valid. 'None' isn't recognized.|Error 0-31: Invalid argument 'None'. Expected valid type name or inline type expression. >> AsType(ParseJSON("{}"), Type({a: Text, b: [Color]})) Errors: Error 28-29: Unsupported type 'Color' in type argument. diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsType_UO.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsType_UO.txt index 744f29c50b..197badeee3 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsType_UO.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/IsType_UO.txt @@ -45,7 +45,7 @@ true true >> IsType(ParseJSON("""1900-12-31T00:00:00.000Z"""), DateTimeTZInd) -true +Errors: Error 50-63: Name isn't valid. 'DateTimeTZInd' isn't recognized.|Error 0-64: Invalid argument 'DateTimeTZInd'. Expected valid type name or inline type expression. >> IsType(ParseJSON("""true"""), Boolean) false @@ -111,7 +111,7 @@ Errors: Error 26-30: Unsupported type 'Void' in type argument. Errors: Error 0-59: Invalid number of arguments: received 3, expected 2. >> IsType(ParseJSON("true"), None) -Errors: Error 26-30: Unsupported type 'Blank' in type argument. +Errors: Error 26-30: Name isn't valid. 'None' isn't recognized.|Error 0-31: Invalid argument 'None'. Expected valid type name or inline type expression. >> IsType(ParseJSON("{}"), Type({a: Text, b: [Color]})) Errors: Error 28-29: Unsupported type 'Color' in type argument. diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/TypedParseJSON.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/TypedParseJSON.txt index 9ae205a278..d71d9e5399 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/TypedParseJSON.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/TypedParseJSON.txt @@ -48,10 +48,10 @@ true false >> ParseJSON("""1900-12-31T00:00:00.000Z""", DateTimeTZInd) -DateTime(1900,12,31,0,0,0,0) +Errors: Error 42-55: Name isn't valid. 'DateTimeTZInd' isn't recognized.|Error 0-56: Invalid argument 'DateTimeTZInd'. Expected valid type name or inline type expression. >> ParseJSON("""1900-12-31T00:00:00.000-08:00""", DateTimeTZInd) -DateTime(1900,12,31,8,0,0,0) +Errors: Error 47-60: Name isn't valid. 'DateTimeTZInd' isn't recognized.|Error 0-61: Invalid argument 'DateTimeTZInd'. Expected valid type name or inline type expression. >> Value(ParseJSON("42", Dynamic)) 42 @@ -128,10 +128,10 @@ Errors: Error 18-22: Unsupported type 'Void' in type argument. Errors: Error 0-51: Invalid number of arguments: received 3, expected 2. >> ParseJSON("true", None) -Errors: Error 18-22: Unsupported type 'Blank' in type argument. +Errors: Error 18-22: Name isn't valid. 'None' isn't recognized.|Error 0-23: Invalid argument 'None'. Expected valid type name or inline type expression. >> ParseJSON("null", None) -Errors: Error 18-22: Unsupported type 'Blank' in type argument. +Errors: Error 18-22: Name isn't valid. 'None' isn't recognized.|Error 0-23: Invalid argument 'None'. Expected valid type name or inline type expression. >> ParseJSON("{}", Type({a: Text, b: [Color]})) Errors: Error 20-21: Unsupported type 'Color' in type argument. diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/UserDefinedFunctionTests.cs b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/UserDefinedFunctionTests.cs index d30a9a14a5..b5764f2fae 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/UserDefinedFunctionTests.cs +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/UserDefinedFunctionTests.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Diagnostics.Contracts; using System.Linq; using System.Text; @@ -13,6 +14,7 @@ using Microsoft.PowerFx.Core.IR; using Microsoft.PowerFx.Core.Syntax; using Microsoft.PowerFx.Core.Texl; +using Microsoft.PowerFx.Core.Utils; using Microsoft.PowerFx.Syntax; using Microsoft.PowerFx.Types; using Xunit; @@ -435,7 +437,15 @@ public void BasicEngine() var extra = new SymbolTable(); extra.AddVariable("K1", FormulaType.Number); - var engine = new Engine(); + var engine = new Engine() + { + PrimitiveTypes = + SymbolTable.NewDefaultTypes(ImmutableDictionary.CreateRange(new Dictionary() + { + { new DName("Number"), FormulaType.Number }, + })) + }; + engine.AddUserDefinedFunction("Foo1(x: Number): Number = Abs(K1);", symbolTable: extra); var check = engine.Check("Foo1(3)"); @@ -503,10 +513,8 @@ public void TestUDF(string formula, int nfCount, int udfCount, int validUdfCount [Theory] [InlineData("Foo(x: Number): None = Abs(x);")] [InlineData("Foo(x: None): Number = Abs(x);")] - [InlineData("Foo(x: Decimal): Number = Abs(x);")] - [InlineData("Foo(x: Number): Decimal = Abs(x);")] - [InlineData("Foo(x: DateTimeTZInd): Decimal = Abs(x);")] - [InlineData("Foo(x: Number): DateTimeTZInd = Abs(x);")] + [InlineData("Foo(x: Void): Number = Abs(x);")] + [InlineData("Foo(x: Number): Void = Abs(x);")] public void TestUDFsWithRestrictedTypes(string script) { var parserOptions = new ParserOptions() @@ -518,7 +526,7 @@ public void TestUDFsWithRestrictedTypes(string script) var udfs = UserDefinedFunction.CreateFunctions(parseResult.UDFs.Where(udf => udf.IsParseValid), _primitiveTypes, out var errors); errors.AddRange(parseResult.Errors ?? Enumerable.Empty()); - Assert.Contains(errors, x => x.MessageKey == "ErrUDF_InvalidReturnType" || x.MessageKey == "ErrUDF_InvalidParamType"); + Assert.Contains(errors, x => x.MessageKey == "ErrUDF_NonImperativeVoidType" || x.MessageKey == "ErrUDF_UnknownType" || x.MessageKey == "ErrUDF_InvalidReturnType" || x.MessageKey == "ErrUDF_InvalidParamType"); } [Theory] diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/IntellisenseTests/UDFIntellisenseTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/IntellisenseTests/UDFIntellisenseTests.cs index f1befc35df..f8981dd9e0 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/IntellisenseTests/UDFIntellisenseTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/IntellisenseTests/UDFIntellisenseTests.cs @@ -3,8 +3,10 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; using System.Text; +using Microsoft.PowerFx.Core.Utils; using Microsoft.PowerFx.Intellisense; using Microsoft.PowerFx.Types; using Xunit; @@ -17,15 +19,34 @@ public class UDFIntellisenseTests [InlineData("AddNumbers(x: Number, y: Number): Number = x + y; |", "")] [InlineData("AddNumbers(x: Number, y: Number): Number = x + |", "")] [InlineData("AddNumbers(x: Number, y: Number): Number = x + Su|", "ErrorKind.InsufficientMemory,ErrorKind.NotSupported,StartOfWeek.Sunday,Sum,Substitute,TraceOptions.IgnoreUnsupportedTypes")] - [InlineData("AddNumbers(x: Number, y: Number): |", "Boolean,Color,Date,DateTime,Dynamic,GUID,Hyperlink,Number,Text,Time,Void")] - [InlineData("AddNumbers(x: Number, y: |", "Boolean,Color,Date,DateTime,Dynamic,GUID,Hyperlink,Number,Text,Time")] + [InlineData("AddNumbers(x: Number, y: Number): |", "Boolean,Color,Date,DateTime,Decimal,Dynamic,GUID,Hyperlink,Number,Text,Time,Void")] + [InlineData("AddNumbers(x: Number, y: |", "Boolean,Color,Date,DateTime,Decimal,Dynamic,GUID,Hyperlink,Number,Text,Time")] // Suggest UDF names when calling one UDF from another [InlineData("AddNumbers(x: Number, y: Number): Number = x + y; AddNumbers2(x: Number, y: Text): Number = AddNum|", "AddNumbers")] public void UDFSuggestionTest(string expression, string expected) { var config = new PowerFxConfig(); - var engine = new Engine(config); + var engine = new Engine(config) + { + PrimitiveTypes = SymbolTable.NewDefaultTypes(ImmutableDictionary.CreateRange(new Dictionary() + { + { FormulaType.Boolean.Name, FormulaType.Boolean }, + { FormulaType.Color.Name, FormulaType.Color }, + { FormulaType.Date.Name, FormulaType.Date }, + { FormulaType.Time.Name, FormulaType.Time }, + { FormulaType.DateTime.Name, FormulaType.DateTime }, + { FormulaType.DateTimeNoTimeZone.Name, FormulaType.DateTimeNoTimeZone }, + { FormulaType.Guid.Name, FormulaType.Guid }, + { FormulaType.Number.Name, FormulaType.Number }, + { FormulaType.Decimal.Name, FormulaType.Decimal }, + { FormulaType.String.Name, FormulaType.String }, + { FormulaType.Hyperlink.Name, FormulaType.Hyperlink }, + { FormulaType.Blank.Name, FormulaType.Blank }, + { FormulaType.UntypedObject.Name, FormulaType.UntypedObject }, + { FormulaType.Void.Name, FormulaType.Void }, + })) + }; var scope = engine.CreateUDFEditorScope(); // engine.AddUserDefinedFunction(expression); diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/RecalcEngineTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/RecalcEngineTests.cs index 96f4c88e2e..1f48eeb1db 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/RecalcEngineTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/RecalcEngineTests.cs @@ -1973,20 +1973,20 @@ protected override bool TryGetField(FormulaType fieldType, string fieldName, out Patients := Type([Patient]); Dummy():Number = CountRows([]);", "Dummy()", - true, + false, true, 0.0)] // Aggregate types with restricted types are not allowed in UDF [InlineData( - @"Patient := Type({DOB: DateTimeTZInd, Weight: Decimal, Dummy: None}); + @"Patient := Type({DOB: DateTimeTZInd, Weight: Void, Dummy: None}); Patients := Type([Patient]); getAnomaly(p: Patients): Patients = Filter(p, Weight < 0);", "", false)] [InlineData( - @"Patient := Type({Name: Text, Details: {h: Number, w:Decimal}}); + @"Patient := Type({Name: Text, Details: {h: Number, w:Void}}); getPatient(): Patient = {Name:""Alice"", Details: {h: 1, w: 2}};", "", false)] diff --git a/src/tests/Microsoft.PowerFx.Json.Tests.Shared/AsTypeIsTypeParseJSONTests.cs b/src/tests/Microsoft.PowerFx.Json.Tests.Shared/AsTypeIsTypeParseJSONTests.cs index a679870987..6254560944 100644 --- a/src/tests/Microsoft.PowerFx.Json.Tests.Shared/AsTypeIsTypeParseJSONTests.cs +++ b/src/tests/Microsoft.PowerFx.Json.Tests.Shared/AsTypeIsTypeParseJSONTests.cs @@ -51,7 +51,6 @@ public void PrimitivesTest() CheckIsTypeAsTypeParseJSON(engine, "\"1234.56789\"", "Decimal", 1234.56789m); CheckIsTypeAsTypeParseJSON(engine, "\"42\"", "T", 42D); CheckIsTypeAsTypeParseJSON(engine, "\"\"\"Power Fx\"\"\"", "Type(Text)", "Power Fx"); - CheckIsTypeAsTypeParseJSON(engine, "\"\"\"2000-01-01T00:00:01.100Z\"\"\"", "DateTimeTZInd", new DateTime(2000, 1, 1, 0, 0, 1, 100)); CheckIsTypeAsTypeParseJSON(engine, "\"\"\"11:59:59\"\"\"", "Time", new TimeSpan(11, 59, 59)); // Negative tests - Coercions not allowed @@ -62,7 +61,7 @@ public void PrimitivesTest() CheckIsTypeAsTypeParseJSON(engine, "\"true\"", "Number", false, false); // Negative tests - types not supported in FromJSON converter - CheckIsTypeAsTypeParseJSONCompileErrors(engine, "\"42\"", "None", TexlStrings.ErrUnsupportedTypeInTypeArgument.Key); + CheckIsTypeAsTypeParseJSONCompileErrors(engine, "\"42\"", "None", TexlStrings.ErrInvalidArgumentExpectedType.Key); CheckIsTypeAsTypeParseJSONCompileErrors(engine, "\"\"\"RED\"\"\"", "Color", TexlStrings.ErrUnsupportedTypeInTypeArgument.Key); CheckIsTypeAsTypeParseJSON(engine, "\"\"\"abcd-efgh-1234-ijkl\"\"\"", "GUID", string.Empty, false); CheckIsTypeAsTypeParseJSON(engine, "\"\"\"foo/bar/uri\"\"\"", "Hyperlink", string.Empty, false);