Make minor fixes in Compiler to properly handle void type expression (#5764)

This commit is contained in:
Dongbo Wang
2018-01-02 09:25:29 -08:00
committed by GitHub
parent 7257404929
commit ad231a8a7f
4 changed files with 112 additions and 4 deletions
@@ -3039,6 +3039,12 @@ namespace System.Management.Automation.Language
input = GetRangeEnumerator(firstCommandExpr.Expression) ??
Compile(firstCommandExpr.Expression);
}
if (input.Type == typeof(void))
{
input = Expression.Block(input, ExpressionCache.AutomationNullConstant);
}
i = 1;
commandsInPipe = pipeElements.Count - 1;
}
@@ -5525,7 +5531,7 @@ namespace System.Management.Automation.Language
if (values.Type == typeof(void))
{
// A dynamic site can't take void - but a void value is just an empty array.
return Expression.NewArrayInit(typeof(object));
return Expression.Block(values, Expression.NewArrayInit(typeof(object)));
}
return DynamicExpression.Dynamic(PSToObjectArrayBinder.Get(), typeof(object[]), values);
@@ -5533,8 +5539,13 @@ namespace System.Management.Automation.Language
public object VisitArrayLiteral(ArrayLiteralAst arrayLiteralAst)
{
return Expression.NewArrayInit(typeof(object),
arrayLiteralAst.Elements.Select(elem => Compile(elem).Cast(typeof(object))));
List<Expression> elementValues = new List<Expression>(arrayLiteralAst.Elements.Count);
foreach (var element in arrayLiteralAst.Elements)
{
var eValue = Compile(element);
elementValues.Add(eValue.Type != typeof(void) ? eValue.Cast(typeof(object)) : Expression.Block(eValue, ExpressionCache.AutomationNullConstant));
}
return Expression.NewArrayInit(typeof(object), elementValues);
}
private IEnumerable<Expression> BuildHashtable(ReadOnlyCollection<KeyValuePair> keyValuePairs, ParameterExpression temp, bool ordered)
@@ -9301,7 +9301,7 @@ namespace System.Management.Automation.Language
}
/// <summary>
/// The non-empty collection of asts of the elements of the array, or null if no elements were specified (e.g. <c>@()</c>).
/// The non-empty collection of asts of the elements of the array.
/// </summary>
public ReadOnlyCollection<ExpressionAst> Elements { get; private set; }
@@ -72,4 +72,71 @@ Describe "ArrayExpression Tests" -Tags "CI" {
$result.Length | Should Be 1
$result[0] | Should Be $null
}
It "@([void](New-Item)) should create file" {
try {
$testFile = Join-Path $TestDrive (New-Guid)
$result = @([void](New-Item $testFile -ItemType File))
## file should be created
$testFile | Should Exist
## the array should be empty
$result.Count | Should Be 0
} finally {
Remove-Item $testFile -Force -ErrorAction SilentlyContinue
}
}
}
Describe "ArrayLiteral Tests" -Tags "CI" {
It "'[void](New-Item),2,3' should return a 3-element array and first element is AutomationNull" {
try {
$testFile = Join-Path $TestDrive (New-Guid)
$result = [void](New-Item $testFile -ItemType File), 2, 3
## file should be created
$testFile | Should Exist
## the array should contain 3 items
$result.Count | Should Be 3
## the first item should be AutomationNull
$result[0] | ForEach-Object { "YES" } | Should Be $null
$result | Measure-Object | ForEach-Object -MemberName Count | Should Be 2
} finally{
Remove-Item $testFile -Force -ErrorAction SilentlyContinue
}
}
It "'[void]1, [void](New-Item), [void]2' should return a 3-AutomationNull-element array" {
try {
$testFile = Join-Path $TestDrive (New-Guid)
$result = [void]1, [void](New-Item $testFile -ItemType File), [void]2
## file should be created
$testFile | Should Exist
## the array should contain 3 items
$result.Count | Should Be 3
## all items should be AutomationNull
$result | ForEach-Object { "YES" } | Should Be $null
} finally {
Remove-Item $testFile -Force -ErrorAction SilentlyContinue
}
}
It "'[void]`$arraylist1.Add(1), `$arraylist2.Clear()' should return a 2-AutomationNull-element array" {
$arraylist1 = [System.Collections.ArrayList]::new()
$arraylist2 = [System.Collections.ArrayList]::new()
$arraylist2.Add(2) > $null
$arraylist2.Count | Should Be 1
## first item is a non-void method call
## second item is a void method call
$result = [void]$arraylist1.Add(1), $arraylist2.Clear()
$result.Count | Should Be 2
$result | ForEach-Object { "YES" } | Should Be $null
$arraylist1.Count | Should Be 1
$arraylist1[0] | Should Be 1
$arraylist2.Count | Should Be 0
}
}
@@ -0,0 +1,30 @@
Describe "Scripting.Followup.Tests" -Tags "CI" {
It "'[void](New-Item) | <Cmdlet>' should work and behave like passing AutomationNull to the pipe" {
try {
$testFile = Join-Path $TestDrive (New-Guid)
[void](New-Item $testFile -ItemType File) | ForEach-Object { "YES" } | Should Be $null
## file should be created
$testFile | Should Exist
} finally {
Remove-Item $testFile -Force -ErrorAction SilentlyContinue
}
}
## cast non-void method call to [void]
It "'[void]`$arraylist.Add(1) | <Cmdlet>' should work and behave like passing AutomationNull to the pipe" {
$arraylist = [System.Collections.ArrayList]::new()
[void]$arraylist.Add(1) | ForEach-Object { "YES" } | Should Be $null
## $arraylist.Add(1) should be executed
$arraylist.Count | Should Be 1
$arraylist[0] | Should Be 1
}
## void method call
It "'`$arraylist2.Clear() | <Cmdlet>' should work and behave like passing AutomationNull to the pipe" {
$arraylist = [System.Collections.ArrayList]::new()
$arraylist.Add(1) > $null
$arraylist.Clear() | ForEach-Object { "YES" } | Should Be $null
## $arraylist.Clear() should be executed
$arraylist.Count | Should Be 0
}
}