Skip to content

Commit ad231a8

Browse files
authored
Make minor fixes in Compiler to properly handle void type expression (#5764)
1 parent 7257404 commit ad231a8

4 files changed

Lines changed: 112 additions & 4 deletions

File tree

src/System.Management.Automation/engine/parser/Compiler.cs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3039,6 +3039,12 @@ public object VisitPipeline(PipelineAst pipelineAst)
30393039
input = GetRangeEnumerator(firstCommandExpr.Expression) ??
30403040
Compile(firstCommandExpr.Expression);
30413041
}
3042+
3043+
if (input.Type == typeof(void))
3044+
{
3045+
input = Expression.Block(input, ExpressionCache.AutomationNullConstant);
3046+
}
3047+
30423048
i = 1;
30433049
commandsInPipe = pipeElements.Count - 1;
30443050
}
@@ -5525,16 +5531,21 @@ public object VisitArrayExpression(ArrayExpressionAst arrayExpressionAst)
55255531
if (values.Type == typeof(void))
55265532
{
55275533
// A dynamic site can't take void - but a void value is just an empty array.
5528-
return Expression.NewArrayInit(typeof(object));
5534+
return Expression.Block(values, Expression.NewArrayInit(typeof(object)));
55295535
}
55305536

55315537
return DynamicExpression.Dynamic(PSToObjectArrayBinder.Get(), typeof(object[]), values);
55325538
}
55335539

55345540
public object VisitArrayLiteral(ArrayLiteralAst arrayLiteralAst)
55355541
{
5536-
return Expression.NewArrayInit(typeof(object),
5537-
arrayLiteralAst.Elements.Select(elem => Compile(elem).Cast(typeof(object))));
5542+
List<Expression> elementValues = new List<Expression>(arrayLiteralAst.Elements.Count);
5543+
foreach (var element in arrayLiteralAst.Elements)
5544+
{
5545+
var eValue = Compile(element);
5546+
elementValues.Add(eValue.Type != typeof(void) ? eValue.Cast(typeof(object)) : Expression.Block(eValue, ExpressionCache.AutomationNullConstant));
5547+
}
5548+
return Expression.NewArrayInit(typeof(object), elementValues);
55385549
}
55395550

55405551
private IEnumerable<Expression> BuildHashtable(ReadOnlyCollection<KeyValuePair> keyValuePairs, ParameterExpression temp, bool ordered)

src/System.Management.Automation/engine/parser/ast.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9301,7 +9301,7 @@ public ArrayLiteralAst(IScriptExtent extent, IList<ExpressionAst> elements)
93019301
}
93029302

93039303
/// <summary>
9304-
/// The non-empty collection of asts of the elements of the array, or null if no elements were specified (e.g. <c>@()</c>).
9304+
/// The non-empty collection of asts of the elements of the array.
93059305
/// </summary>
93069306
public ReadOnlyCollection<ExpressionAst> Elements { get; private set; }
93079307

test/powershell/Language/Scripting/Array.Tests.ps1

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,71 @@ Describe "ArrayExpression Tests" -Tags "CI" {
7272
$result.Length | Should Be 1
7373
$result[0] | Should Be $null
7474
}
75+
76+
It "@([void](New-Item)) should create file" {
77+
try {
78+
$testFile = Join-Path $TestDrive (New-Guid)
79+
$result = @([void](New-Item $testFile -ItemType File))
80+
## file should be created
81+
$testFile | Should Exist
82+
## the array should be empty
83+
$result.Count | Should Be 0
84+
} finally {
85+
Remove-Item $testFile -Force -ErrorAction SilentlyContinue
86+
}
87+
}
88+
}
89+
90+
Describe "ArrayLiteral Tests" -Tags "CI" {
91+
It "'[void](New-Item),2,3' should return a 3-element array and first element is AutomationNull" {
92+
try {
93+
$testFile = Join-Path $TestDrive (New-Guid)
94+
$result = [void](New-Item $testFile -ItemType File), 2, 3
95+
## file should be created
96+
$testFile | Should Exist
97+
## the array should contain 3 items
98+
$result.Count | Should Be 3
99+
100+
## the first item should be AutomationNull
101+
$result[0] | ForEach-Object { "YES" } | Should Be $null
102+
$result | Measure-Object | ForEach-Object -MemberName Count | Should Be 2
103+
} finally{
104+
Remove-Item $testFile -Force -ErrorAction SilentlyContinue
105+
}
106+
}
107+
108+
It "'[void]1, [void](New-Item), [void]2' should return a 3-AutomationNull-element array" {
109+
try {
110+
$testFile = Join-Path $TestDrive (New-Guid)
111+
$result = [void]1, [void](New-Item $testFile -ItemType File), [void]2
112+
## file should be created
113+
$testFile | Should Exist
114+
## the array should contain 3 items
115+
$result.Count | Should Be 3
116+
117+
## all items should be AutomationNull
118+
$result | ForEach-Object { "YES" } | Should Be $null
119+
} finally {
120+
Remove-Item $testFile -Force -ErrorAction SilentlyContinue
121+
}
122+
}
123+
124+
It "'[void]`$arraylist1.Add(1), `$arraylist2.Clear()' should return a 2-AutomationNull-element array" {
125+
$arraylist1 = [System.Collections.ArrayList]::new()
126+
$arraylist2 = [System.Collections.ArrayList]::new()
127+
128+
$arraylist2.Add(2) > $null
129+
$arraylist2.Count | Should Be 1
130+
131+
## first item is a non-void method call
132+
## second item is a void method call
133+
$result = [void]$arraylist1.Add(1), $arraylist2.Clear()
134+
$result.Count | Should Be 2
135+
$result | ForEach-Object { "YES" } | Should Be $null
136+
137+
$arraylist1.Count | Should Be 1
138+
$arraylist1[0] | Should Be 1
139+
140+
$arraylist2.Count | Should Be 0
141+
}
75142
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
Describe "Scripting.Followup.Tests" -Tags "CI" {
2+
It "'[void](New-Item) | <Cmdlet>' should work and behave like passing AutomationNull to the pipe" {
3+
try {
4+
$testFile = Join-Path $TestDrive (New-Guid)
5+
[void](New-Item $testFile -ItemType File) | ForEach-Object { "YES" } | Should Be $null
6+
## file should be created
7+
$testFile | Should Exist
8+
} finally {
9+
Remove-Item $testFile -Force -ErrorAction SilentlyContinue
10+
}
11+
}
12+
13+
## cast non-void method call to [void]
14+
It "'[void]`$arraylist.Add(1) | <Cmdlet>' should work and behave like passing AutomationNull to the pipe" {
15+
$arraylist = [System.Collections.ArrayList]::new()
16+
[void]$arraylist.Add(1) | ForEach-Object { "YES" } | Should Be $null
17+
## $arraylist.Add(1) should be executed
18+
$arraylist.Count | Should Be 1
19+
$arraylist[0] | Should Be 1
20+
}
21+
22+
## void method call
23+
It "'`$arraylist2.Clear() | <Cmdlet>' should work and behave like passing AutomationNull to the pipe" {
24+
$arraylist = [System.Collections.ArrayList]::new()
25+
$arraylist.Add(1) > $null
26+
$arraylist.Clear() | ForEach-Object { "YES" } | Should Be $null
27+
## $arraylist.Clear() should be executed
28+
$arraylist.Count | Should Be 0
29+
}
30+
}

0 commit comments

Comments
 (0)