Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DYN-1722 #9578

Merged
merged 10 commits into from
Mar 25, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 29 additions & 7 deletions src/Engine/ProtoCore/Lang/CallSite.cs
Original file line number Diff line number Diff line change
Expand Up @@ -822,6 +822,16 @@ private FunctionEndPoint GetLooseCompliantFEP(
return compliantTarget;
}

private Boolean IsCompatibleReplicationOption(List<ReplicationInstruction> oldOption, List<ReplicationInstruction> newOption)
{
if (oldOption.Count > 0 && newOption.Count > 0 && oldOption.Count < newOption.Count)
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’m not sure I understand this change. Why are you checking equality only for the first option?

Copy link
Contributor Author

@reddyashish reddyashish Mar 18, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For those 2 cases where it was failing, as we are checking for all the replication options(to find a match), the first match is found for "cartesian:indices=0" option. Then it finds a match for "zipped:indices=0,1" and it applies zipped replication option(as this is the final option that is tested). Previously, the first option that found a match was applied directly. After this change, it would not accept the zipped replication as the cartesian option has already found the match.
Another case is, we want to accept this new replication option, if it is of the higher rank than the previous option (old option: "cartesian:indices=0" and new option: "cartesian:indices=0, cartesian:indices=0". Similar option but checks for one extra depth level). Since all options are unique, I was checking the first element and the count for the new option to be higher than the first. Also can use, newOption.Count = oldOption.Count +1.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm definitely having a hard time understanding this one, is it possible @reddyashish you could draw a diagram or do a longer writeup of the problem here and the approach taken to fix it - I know it's kind of a tall order.

Copy link
Member

@mjkkirschner mjkkirschner Mar 22, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so - I'm trying to think of cases where this will fail -
I think naming this method or adding a summary might help - but my interpretation is that this method is used to find List<ReplicationInstruction> where the first instruction matches the previous one but is of a greater depth?

What I cannot figure out or explain yet is what case this is used to avoid or to guarantee we hit? Can you try to sum it up in the summary of the method or in the git here.

if (oldOption[0].ToString().Equals(newOption[0].ToString()))
reddyashish marked this conversation as resolved.
Show resolved Hide resolved
return true;
}
return false;
}

private void ComputeFeps(
Context context,
List<StackValue> arguments,
Expand All @@ -832,6 +842,10 @@ private void ComputeFeps(
out List<FunctionEndPoint> resolvesFeps,
reddyashish marked this conversation as resolved.
Show resolved Hide resolved
out List<ReplicationInstruction> replicationInstructions)
{
replicationInstructions = null;
resolvesFeps = null;
Boolean flag = false;
reddyashish marked this conversation as resolved.
Show resolved Hide resolved

#region Case 1: Replication guide with exact match
{
FunctionEndPoint fep = GetCompleteMatchFunctionEndPoint(context, arguments, funcGroup, instructions, stackFrame, runtimeCore);
Expand All @@ -855,13 +869,17 @@ private void ComputeFeps(
HashSet<FunctionEndPoint> lookups;
if (funcGroup.CanGetExactMatchStatics(context, reducedParams, stackFrame, runtimeCore, out lookups))
{
//Otherwise we have a cluster of FEPs that can be used to dispatch the array
resolvesFeps = new List<FunctionEndPoint>(lookups);
replicationInstructions = replicationOption;
return;
if (replicationInstructions == null || IsCompatibleReplicationOption(replicationInstructions, replicationOption))
{
//Otherwise we have a cluster of FEPs that can be used to dispatch the array
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find this comment confusing - what is the otherwise referring to - theres no comment before this and we are inside an if statement... not an else statement -

resolvesFeps = new List<FunctionEndPoint>(lookups);
replicationInstructions = replicationOption;
flag = true;
}
}
}

if (flag == true)
return;
}
#endregion

Expand All @@ -888,9 +906,11 @@ private void ComputeFeps(
{
resolvesFeps = new List<FunctionEndPoint>() { compliantTarget };
replicationInstructions = replicationOption;
return;
flag = true;
}
}
if (flag == true)
return;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@reddyashish so - what about case 5 - why do we exit the other cases late, and exit case 5 as soon as we find a match?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not understand this case and it adds an empty replication option to the previous list and finds the match. I was not able to find any examples related to this case.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will try to find when it's called.
@saintentropy any ideas?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mjkkirschner @reddyashish In general this whole function is still black magic to me. I have been able to look at indivual examples and how they flow through but it is hard to make judgment on individual PR's without holistic picture. I think we need to document examples of different data, data structures, replication settings, and functions and what the result replication instruction and function endpoint list. Not sure if we need to do that on this PR but it is hard to validate the code changes otherwise

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For a start - I've filed a followup task to cover each of the missing cases with explicit tests.

}
}

Expand Down Expand Up @@ -923,9 +943,11 @@ private void ComputeFeps(
{
resolvesFeps = new List<FunctionEndPoint>() { compliantTarget };
replicationInstructions = replicationOption;
return;
flag = true;
}
}
if (flag == true)
return;
}
#endregion

Expand Down
2 changes: 1 addition & 1 deletion test/Engine/ProtoTest/Associative/BuiltinMethodsTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1069,7 +1069,7 @@ public void TestTryGetValuesFromDictionary08()
thisTest.Verify("r", null);
}

[Test, Category("Failure")]
[Test]
public void TestTryGetValuesFromDictionary09()
{
string code = @"
Expand Down
16 changes: 0 additions & 16 deletions test/Engine/ProtoTest/Associative/MethodResolution.cs
Original file line number Diff line number Diff line change
Expand Up @@ -396,21 +396,5 @@ def qux2()
thisTest.Verify("z1", 22);
thisTest.Verify("z2", 22);
}

[Test]
public void TestEmptyNestedListsForMethodResolution()
reddyashish marked this conversation as resolved.
Show resolved Hide resolved
{
string code = @"import(""FFITarget.dll"");
pt = DummyPoint2D.ByCoordinates(0,0);
l = [[],[pt]];
px1 = DummyPoint2D.X(l);
pt = DummyPoint2D.ByCoordinates(0,0);
l2 = [[pt],[]];
px2 = DummyPoint2D.X(l2);
";
var mirror = thisTest.RunScriptSource(code);
thisTest.Verify("px1", new object[] { new object[] { }, new object[] { 0 } });
thisTest.Verify("px2", new object[] { new object[] { 0 }, new object[] { } });
}
}
}
61 changes: 60 additions & 1 deletion test/Engine/ProtoTest/TD/Associative/Replication.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4926,7 +4926,66 @@ public void TestReplicationInInlineConditional()
thisTest.RunScriptSource(code);
thisTest.Verify("r", new object[] { 2, 5, 7 });
}
}

[Test]
public void TestReplicationWithEmptyListInNestedLists()
{
string code = @"import(""FFITarget.dll"");
pt = DummyPoint2D.ByCoordinates(0,0);
l = [[],[pt]];
px1 = DummyPoint2D.X(l);
pt = DummyPoint2D.ByCoordinates(0,0);
l2 = [[pt],[]];
px2 = DummyPoint2D.X(l2);
";
var mirror = thisTest.RunScriptSource(code);
thisTest.Verify("px1", new object[] { new object[] { }, new object[] { 0 } });
thisTest.Verify("px2", new object[] { new object[] { 0 }, new object[] { } });
}

[Test]
public void TestReplicationWithNullElementInNestedLists()
{
string code = @"import(""FFITarget.dll"");
pt = DummyPoint2D.ByCoordinates(0,0);
l = [null,[pt]];
px1 = DummyPoint2D.X(l);
pt = DummyPoint2D.ByCoordinates(0,0);
l2 = [[pt],null];
px2 = DummyPoint2D.X(l2);
";

var mirror = thisTest.RunScriptSource(code);
thisTest.Verify("px1", new object[] { null, new object[] { 0 } });
thisTest.Verify("px2", new object[] { new object[] { 0 }, null });
}

[Test]
public void TestReplicationWithArraysOfDifferentRanks()
{
string code = @"import(""FFITarget.dll"");
t1 = [1, [2]];
t2 = t1 + 5;
pt = DummyPoint2D.ByCoordinates(0,0);
l1 = [[[pt]],[pt]];
px1 = DummyPoint2D.X(l1);
l2 = [[pt],[[pt]]];
px2 = DummyPoint2D.X(l2);
l3 = [[null],[[pt]]];
px3 = DummyPoint2D.X(l3);
l4 = [3.3,[pt],[[pt]]];
px4 = DummyPoint2D.X(l4);
l5 = [""test"",[[pt]],[pt]];
px5 = DummyPoint2D.X(l5);
";
var mirror = thisTest.RunScriptSource(code);
thisTest.Verify("t2", new object[] { 6, new object[] { 7 } });
thisTest.Verify("px1", new object[] { new object[] { new object[] { 0 } }, new object[] { 0 } });
thisTest.Verify("px2", new object[] { new object[] { 0 }, new object[] { new object[] { 0 } } });
thisTest.Verify("px3", new object[] { new object[] { null }, new object[] { new object[] { 0 } } });
thisTest.Verify("px4", new object[] { null, new object[] { 0 }, new object[] { new object[] { 0 } } });
thisTest.Verify("px5", new object[] { null, new object[] { new object[] { 0 } }, new object[] { 0 } });
}
}
}