Skip to content

Commit

Permalink
Mark UDFs and NFs Async If there's a reference to cross screen control (
Browse files Browse the repository at this point in the history
#2620)

Marks UDF and Nf async if they refer to cross screen control and a new
binding config to do that is enabled. There's no definite way to say
where binder is binding nf or udf rules so config would be used to
communicate the marking of top parse node as async upon countering those
references. We don't need to mark those async if all they refer to is
component definition but there's no definite way to also check that.
ExternalTemplate.IsComponent returns true for component defs and
instances but we need to check only for the former. However that
shouldn't matter as code gen to lazy load component defs would be no op
since component defs are loaded upfront.
  • Loading branch information
akshar2401 authored Aug 31, 2024
1 parent 923f501 commit 85e769e
Show file tree
Hide file tree
Showing 10 changed files with 376 additions and 12 deletions.
8 changes: 8 additions & 0 deletions src/libraries/Microsoft.PowerFx.Core/Binding/Binder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3071,6 +3071,14 @@ public override void Visit(FirstNameNode node)
{
_txb.ErrorContainer.EnsureError(node, TexlStrings.ErrInvalidControlReference);
}
}

if (_txb.BindingConfig.MarkAsAsyncOnLazilyLoadedControlRef &&
lookupType.IsControl &&
lookupInfo.Data is IExternalControl control &&
!control.IsAppGlobalControl)
{
_txb.FlagPathAsAsync(_txb.Top);
}

// Update _usesGlobals, _usesResources, etc.
Expand Down
9 changes: 6 additions & 3 deletions src/libraries/Microsoft.PowerFx.Core/Binding/BindingConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,17 @@ internal class BindingConfig

public bool NumberIsFloat { get; }

public bool AnalysisMode { get; }
public bool AnalysisMode { get; }

public bool MarkAsAsyncOnLazilyLoadedControlRef { get; } = false;

public BindingConfig(bool allowsSideEffects = false, bool useThisRecordForRuleScope = false, bool numberIsFloat = false, bool analysisMode = false)
public BindingConfig(bool allowsSideEffects = false, bool useThisRecordForRuleScope = false, bool numberIsFloat = false, bool analysisMode = false, bool markAsAsyncOnLazilyLoadedControlRef = false)
{
AllowsSideEffects = allowsSideEffects;
UseThisRecordForRuleScope = useThisRecordForRuleScope;
NumberIsFloat = numberIsFloat;
AnalysisMode = analysisMode;
AnalysisMode = analysisMode;
MarkAsAsyncOnLazilyLoadedControlRef = markAsAsyncOnLazilyLoadedControlRef;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

using Microsoft.PowerFx.Core.App.Controls;
using Microsoft.PowerFx.Core.Types;
using Microsoft.PowerFx.Core.Utils;

internal class ControlVirtualType : DType, IExternalControlType
{
public ControlVirtualType(TypeTree typeTree = default)
: base(typeTree)
{
foreach (var (key, value) in typeTree)
{
Template.OutputProps.Add(key, new DummyProperty() { InvariantName = new DName(key), Type = value });
}
}

public readonly DummyTemplate Template = new ();

public IExternalControlTemplate ControlTemplate => Template;

public bool IsMetaField => false;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

using Microsoft.PowerFx.Core.App.Controls;
using Microsoft.PowerFx.Core.Types;
using Microsoft.PowerFx.Core.Utils;

internal class DummyExternalControl : IExternalControl
{
public IExternalControlTemplate Template => null;

public bool IsComponentControl { get; set; } = false;

public IExternalControl TopParentOrSelf => this;

public string DisplayName { get; set; } = "DummyExternalControl";

public bool IsReplicable { get; set; } = false;

public bool IsAppInfoControl { get; set; } = false;

public DType ThisItemType { get; set; } = DType.Unknown;

public bool IsAppGlobalControl => IsAppInfoControl;

public bool IsCommandComponentInstance { get; set; } = false;

public DName EntityName => new DName(DisplayName);

public DType Type { get; set; } = DType.Unknown;

public virtual IExternalRule GetRule(string propertyInvariantName)
{
return null;
}

public virtual bool IsDescendentOf(IExternalControl controlInfo)
{
return false;
}

public virtual bool TryGetRule(string dName, out IExternalRule rule)
{
rule = GetRule(dName);
return rule != null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

using Microsoft.PowerFx.Core.App.Controls;
using Microsoft.PowerFx.Core.Functions;
using Microsoft.PowerFx.Core.Types;
using Microsoft.PowerFx.Core.Utils;

internal class DummyProperty : IExternalControlProperty
{
public bool IsImmutableOnInstance { get; set; } = false;

public bool SupportsPaging { get; set; } = false;

public bool RequiresDefaultablePropertyReferences { get; set; } = false;

public bool ShouldIncludeThisItemInFormula { get; set; } = false;

public bool IsTestCaseProperty { get; set; } = false;

public bool UseForDataQuerySelects { get; set; } = false;

public bool IsTypeInferredFromPrimaryInput { get; set; } = false;

public PropertyRuleCategory PropertyCategory { get; set; } = PropertyRuleCategory.Data;

public bool IsScopeVariable { get; set; } = false;

public string UnloadedDefault { get; set; } = string.Empty;

public IExternalControlProperty PassThroughInput => new DummyProperty();

public DName InvariantName { get; set; } = new DName("DummyProperty");

public bool IsScopedProperty { get; set; } = false;

public TexlFunction ScopeFunctionPrototype { get; set; } = null;

public DType Type { get; set; } = DType.Unknown;

public DType GetOpaqueType()
{
return Type;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

using System.Collections.Generic;
using System.Linq;
using Microsoft.PowerFx.Core.App.Components;
using Microsoft.PowerFx.Core.App.Controls;
using Microsoft.PowerFx.Core.Utils;

internal class DummyTemplate : IExternalControlTemplate
{
public readonly Dictionary<string, IExternalControlProperty> InputProps = new ();

public readonly Dictionary<string, IExternalControlProperty> OutputProps = new ();

public ComponentType ComponentType { get; set; } = ComponentType.FunctionComponent;

public bool IncludesThisItemInSpecificProperty { get; set; } = false;

public bool ReplicatesNestedControls { get; set; } = false;

public IEnumerable<DName> NestedAwareTableOutputs { get; set; } = Enumerable.Empty<DName>();

public bool IsComponent { get; set; } = false;

public bool HasExpandoProperties { get; set; } = false;

public IEnumerable<IExternalControlProperty> ExpandoProperties { get; set; } = Enumerable.Empty<IExternalControlProperty>();

public bool HasPropsInferringTypeFromPrimaryInProperty { get; set; } = false;

public IEnumerable<IExternalControlProperty> PropsInferringTypeFromPrimaryInProperty => Enumerable.Empty<IExternalControlProperty>();

public string ThisItemInputInvariantName { get; set; } = string.Empty;

public IExternalControlProperty PrimaryOutputProperty { get; set; } = new DummyProperty();

public bool IsMetaLoc { get; set; } = false;

public bool IsCommandComponent { get; set; } = false;

public bool HasOutput(DName rightName)
{
return OutputProps.ContainsKey(rightName.Value);
}

public bool HasProperty(string currentPropertyValue, PropertyRuleCategory category)
{
return TryGetProperty(currentPropertyValue, out _);
}

public bool TryGetInputProperty(string resolverCurrentProperty, out IExternalControlProperty currentProperty)
{
return InputProps.TryGetValue(resolverCurrentProperty, out currentProperty);
}

public bool TryGetOutputProperty(string name, out IExternalControlProperty externalControlProperty)
{
return OutputProps.TryGetValue(name, out externalControlProperty);
}

public bool TryGetProperty(string name, out IExternalControlProperty controlProperty)
{
return TryGetInputProperty(name, out controlProperty) || TryGetOutputProperty(name, out controlProperty);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

using Microsoft.PowerFx.Core.App.Controls;
using Microsoft.PowerFx.Core.Binding;
using Microsoft.PowerFx.Core.Functions;
using Microsoft.PowerFx.Core.Glue;

internal class MockGlue : IBinderGlue
{
public bool IsComponentDataSource(object lookupInfoData)
{
return false;
}

public bool IsDataComponentDefinition(object lookupInfoData)
{
return false;
}

public bool IsDataComponentInstance(object lookupInfoData)
{
return false;
}

public bool IsDynamicDataSourceInfo(object lookupInfoData)
{
return false;
}

bool IBinderGlue.CanControlBeUsedInComponentProperty(TexlBinding binding, IExternalControl control)
{
return true;
}

IExternalControl IBinderGlue.GetVariableScopedControlFromTexlBinding(TexlBinding txb)
{
return new DummyExternalControl();
}

bool IBinderGlue.IsComponentScopedPropertyFunction(TexlFunction infoFunction)
{
return false;
}

bool IBinderGlue.IsContextProperty(IExternalControlProperty externalControlProperty)
{
return false;
}

bool IBinderGlue.IsPrimaryCommandComponentProperty(IExternalControlProperty externalControlProperty)
{
return false;
}

bool IBinderGlue.TryGetCdsDataSourceByBind(object lhsInfoData, out IExternalControl o)
{
o = null;
return false;
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

using Microsoft.PowerFx;

using System.Collections.Generic;
using System.Linq;
using Microsoft.PowerFx;
using Microsoft.PowerFx.Core.App.Components;
using Microsoft.PowerFx.Core.App.Controls;
using Microsoft.PowerFx.Core.Binding;
using Microsoft.PowerFx.Core.Binding.BindInfo;
using Microsoft.PowerFx.Core.Functions;
using Microsoft.PowerFx.Core.Glue;
using Microsoft.PowerFx.Core.Types;
using Microsoft.PowerFx.Core.Utils;


/**
* Just a small handy mock of symbol table to be able to customize binder to compute different token types.
* Might not be 100% correct but it works and allows testing against different token types.
* Meant to be used for semantic tokens related tests.
*/
* Just a small handy mock of symbol table to be able to customize binder to compute different token types.
* Might not be 100% correct but it works and allows testing against different token types.
*/
internal class MockSymbolTable : ReadOnlySymbolTable
{
public void Add(string name, NameLookupInfo info)
Expand All @@ -36,6 +41,13 @@ public void AddControlAsControlType(string name)
var controlType = new DType(DKind.Control);
var controlInfo = new NameLookupInfo(BindKind.Control, controlType, DPath.Root, 0);
Add(name, controlInfo);
}

public void AddControl(string name, IExternalControl dummyControl = null, TypeTree typTree = default)
{
var controlType = new ControlVirtualType(typTree);
var controlInfo = new NameLookupInfo(BindKind.Control, controlType, DPath.Root, 0, dummyControl);
Add(name, controlInfo);
}

public TypedName GetLookupInfoAsTypedName(string name)
Expand All @@ -53,4 +65,4 @@ internal override bool TryLookup(DName name, out NameLookupInfo nameInfo)
{
return _variables.TryGetValue(name.Value, out nameInfo);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<Compile Include="$(MSBuildThisFileDirectory)*.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Docs\*.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Helpers\*.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Helpers\SymbolTableHelperMocks\*.cs" />
<Compile Include="$(MSBuildThisFileDirectory)IntellisenseTests\*.cs" />
<Compile Include="$(MSBuildThisFileDirectory)IRTests\*.cs" />
<Compile Include="$(MSBuildThisFileDirectory)LanguageServiceProtocol\*.cs" />
Expand Down
Loading

0 comments on commit 85e769e

Please sign in to comment.