Since we use generic expression parser for parsing type expression
within type literal node, we consider an expression like `Type(5+5)` to
be parsevalid.
This PR
1. Adds a validator to allow only valid type expressions.
2. Simplifies `DTypeVisitor` to use `DefaultVisitor`
3. overrides exception when visiting `Type(Type(..))`
4. Adds TexlPretty for `TypeLiteralNode` to enable ToString.
Updates error to "The '.' operator cannot be used on <TypeName> values"
The error shows up in the case of
"the thing on the left of “.” is a number/string/other thing you can’t
use “.” on ever, excluding polymorphic because it's weird"
Addresses customer reported bug in pre-V1 where option set value =
Blank() resulted in an error. General remedy is to return the pre-V1
code to its original state and have a large if around V1 vs. pre-V1
code. And more tests.
The other methods in the query options classes use the datasource
associated with the target relationship to resolve relationship
metadata, where AddRelatedColumns uses the parent datasource, which
refers to the source datasource (e.g.
SourceDatasource.TargetDataSourceRelatedColumn.Name). This PR fixes
that.
Option sets coming from Dataverse that are backed by a number are not
handled correctly in Power Apps, a pre-V1 host. An error is produced for
comparisons where there was not one previously. A few checks for pre-V1
were missing:
- Concatenate function (but not the operator)
- Numerical comparisons between option sets
Updating the test suite revealed that the interpreter's implementation
of Concatenate didn't properly account for non-string option sets, which
has also been fixed.
One reason we didn't detect these problems earlier is that we use
EnumSymbol as a proxy for OptionSet, which is usually pretty good, but
in the comparison case it led tests to fail but the product to fail.
There will be a separate task to expand OptionSet to support more data
types and update the tests.
Step 4 of allowing user defined types effort.
Adds ability for users to define named types and use it in
UserDefinedFunction.
For example,
```
// Record Type
Point = Type({ x : Number, y : Number});
distance(a: Point, b: Point): Number = Sqrt(Power(b.x-a.x, 2) + Power(b.y-a.y, 2));
// Table Type
Points = Type([Point]);
Numbers = Type([Number]);
// Type Alias
Name = Type(Text);
```
`AllowParseAsTypeLiteral` can be used in the expression parser to parse
inline type definitions as `TypeLiteralNodes`
We considered UDF with parse failures in body to be parse valid UDFs
which leads to issues when binding the body of UDFs with errors.
In This PR we check if there are any new errors after parsing body and
set parseValid appropriately.
Caller is responsible Symbol tables shouldn't be mutated while they're
being read.
See #1551 for details on rule about threading.
This doesn't fix the problem, but gives us a better (and more
deterministic) exception when it happens.
Possibly related to tracking down #2136
There are 3 fixes in this PR
1. in TryGetDsInfo, if FirstNameNode is a variable, we were not
returning IExternalDataSource value. We now search in the symbol table
for the variable corresponding type to get it. There is no direct test
in this repo, this only impacts DV repo where another bug shows up (see
below)
2. in PostVisit for AsNode. In CheckAndMarkAsPageable we could set
stateful flag to true (line 1227) while reseting the flag at line 3933.
3. in IsBlankFunction, IsRowScopedServerDelegatable was not considering
DottedNameNode
1. add delegation interfaces into fx.core so that other libraries can
begin to delegate to TableValue.
2. make ConnectorTableValue implement these.
3. switch to use IReadOnlyCollection . This is a) readonly, b) has a
count . Count is important to emphasize that this is not delay execution
- because we make a network call, we need to ensure the call happens
upfront.
From a type perspective, Mod should act like / (division). The arguments
should be symmetric with a Decimal result only if both arguments are
Decimal. This is not the case, there is a bug here where the first
argument is dictating the result of the function alone. The same holds
for RandBetween which has the same problem. This PR fixes both functions
and adds many tests.
Here, the second result should be 1 with no decimal as the calculation
should be done in Float.
```
>> Mod( 3.0000000000000000000003, 2.0000000000000000000002 )
1.0000000000000000000001
>> Mod( 3.0000000000000000000003, Float(2.0000000000000000000002) )
1.0000000000000000000003
>> Mod( Float(3.0000000000000000000003), 2.0000000000000000000002 )
1
>> Mod( Float(3.0000000000000000000003), Float(2.0000000000000000000002) )
1
```
Likewise, RandBetween has the wrong answer for the second case, where
the second argument is coerced to a decimal (while losing digits).
```
>>
>> RandBetween( 12345678912345678912345678, 12345678912345678912345678 )
12345678912345678912345678
>> RandBetween( 12345678912345678912345678, Float(12345678912345678912345678) )
12345678912345697471862876
>> RandBetween( Float(12345678912345678912345678), 12345678912345678912345678 )
1.2345678912345679E+25
>> RandBetween( Float(12345678912345678912345678), Float(12345678912345678912345678) )
1.2345678912345679E+25
```
Step 3 of allowing user defined types effort .
* Introduces NamedTypes, LookupType in INameResolver.
* Remove PrimitiveTypeSymbolTable usage, and use NamedTypes from Engine
Symbols
* Require INameResolver to create UDFs.
* Removes `TypeSymbolTable`, `PrimitiveTypesSymbolTable` and
`DefinedTypeSymbolTable`
This will be followed with
1. Introduce parsing and adding user defined NamedTypes.
2. Optimize type graph to update incremental.
Fix#2241 - adds a TryGetType to lookup a variable by name (very useful
when it doesn't have a slot) and return its type.
This is particularly interesting for enums/optionsets - which don't have
slots (since they don't have per-eval storage). But
beware , #2342 - some of the FormulaTypes for enums/optionsets are not
correct.
Step 2 of allowing user defined types effort .
Retires `UserDefinitions.ProcessUserdefinitions` as it creates a tight
coupling between Parse and processing of all different kinds of
Userdefinitions.
We and our tests assume that client uses this method for processing,
hence fixing all the tests as we will not use this moving forward.
Moving `AllowAttributes` transformation to `Parse` as it is a
transformation of `ParseResult` and returns a `ParseResult` . Ideally
this could be a transformation on NamedFormula `ParseResult` .
This will be followed with
1. Introduce NamedTypes, LookupType in INameResolver but support only
Primitives. Remove PrimitiveTypeSymbolTable usage , Require
INameResolver to create UDFs.
2. Introduce parsing and adding user defined NamedTypes.
3. Optimize type graph to update incremental.
We have a string that is a fwlink redirector in our localized resources. Fwlinks should not be translated (it redirects to the user locale, based on the browser's language), so this change removes it.
Minor refactor as a part of introducing user defined types effort.
* Moved private method CreateUserDefinedFunctions from UserDefinitions
to UserDefinedFunction and exposing it to hosts. With this hosts can
create IR UserDefinedFunction from parser UDF result without being
tightly coupled with NamedFormulas or user defined types.
* This will help in introducing Userdefinedtypes . Userdefinedtypes
should be processed and resolved first before creating UDF IR as
argTypes should be known.
This will be followed by
1. Retiring `UserDefinitions.ProcessUserDefinitions` - this method
simply parses UserDefinition script and creates UDF IR and NamedFormula
ParseResult
2. Introduce NamedTypes, LookupType in INameResolver but support only
Primitives. Remove PrimitiveTypeSymbolTable usage , Require
INameResolver to create UDFs.
3. Introduce parsing and adding user defined NamedTypes.
4. Optimize type graph to update incremental.
When we enable the Decimal function in Power Apps, we will only do that for apps that select Power Fx 1.0. This makes it a compile-time error to try to use the function without it.
This fixes a nullref that's always been possible in
ErrorContainer.HaserrorsInTree Following #2284 it was more common that
errors had only a token and not a node. This wasn't handled in this
function.