Skip to content

Commit 16ff197

Browse files
authored
Fix casting single element array to generic collection (PowerShell#3170)
1 parent a557c03 commit 16ff197

2 files changed

Lines changed: 58 additions & 6 deletions

File tree

src/System.Management.Automation/engine/LanguagePrimitives.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3581,20 +3581,20 @@ internal object Convert(object valueToConvert,
35813581
TypeTable backupTable)
35823582
{
35833583
IList resultAsList = null;
3584-
int listSize = 0;
35853584
Array array = null;
35863585

35873586
try
35883587
{
3589-
// typeof(Array).IsAssignableFrom(typeof(object[])) == true
3590-
if ((IsScalar) || (!(valueToConvert is Array)))
3588+
int listSize = 0;
3589+
if (IsScalar)
35913590
{
35923591
listSize = 1;
35933592
}
35943593
else
35953594
{
3596-
array = (Array)valueToConvert;
3597-
listSize = array.Length;
3595+
// typeof(Array).IsAssignableFrom(typeof(object[])) == true
3596+
array = valueToConvert as Array;
3597+
listSize = array != null ? array.Length : 1;
35983598
}
35993599

36003600
resultAsList = ListCtorLambda(listSize);
@@ -3610,7 +3610,7 @@ internal object Convert(object valueToConvert,
36103610
{
36113611
resultAsList.Add(valueToConvert);
36123612
}
3613-
else if (listSize == 1)
3613+
else if (array == null)
36143614
{
36153615
object convertedValue = LanguagePrimitives.ConvertTo(valueToConvert, ElementType, formatProvider);
36163616
resultAsList.Add(convertedValue);

test/powershell/Language/Parser/Conversions.Tests.ps1

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,56 @@ Describe 'conversion syntax' -Tags "CI" {
2020
# This test relies on the fact that there are overloads (at least 2) for ToString method.
2121
([System.Management.Automation.ActionPreference]"Stop").ToString() | Should Be "Stop"
2222
}
23+
24+
Context "Cast object[] to more narrow generic collection" {
25+
BeforeAll {
26+
$testCases1 = @(
27+
## It's intentional to have 'Command' to be `{$result = ...}` and run it with `. $Command`.
28+
## This is because `$result = & {[List[int]]@(1,2)}` will cause the resulted List to be unraveled,
29+
## and in that case `$result` would be just an object array.
30+
## To prevent unraveling, Command needs to be `{, [List[int]]@(1,2)}`, but then the test case title
31+
## would become `, [List[int]]@(1,2)`, which is more confusing than `$result = [List[int]]@(1,2)`.
32+
## This is why the current form of `$result = [List[int]]@(1,2)` is used intentionally here.
33+
34+
@{ Command = {$result = [Collections.Generic.List[int]]@(1)}; CollectionType = 'List`1'; ElementType = "Int32"; Elements = @(1) }
35+
@{ Command = {$result = [Collections.Generic.List[int]]@(1,2)}; CollectionType = 'List`1'; ElementType = "Int32"; Elements = @(1,2) }
36+
@{ Command = {$result = [Collections.Generic.List[int]]"4"}; CollectionType = 'List`1'; ElementType = "Int32"; Elements = @(4) }
37+
@{ Command = {$result = [Collections.Generic.List[int]]@("4","5")}; CollectionType = 'List`1'; ElementType = "Int32"; Elements = @(4,5) }
38+
39+
@{ Command = {$result = [Collections.Generic.List[string]]@(1)}; CollectionType = 'List`1'; ElementType = "String"; Elements = @("1") }
40+
@{ Command = {$result = [Collections.Generic.List[string]]@(1,2)}; CollectionType = 'List`1'; ElementType = "String"; Elements = @("1","2") }
41+
@{ Command = {$result = [Collections.Generic.List[string]]1}; CollectionType = 'List`1'; ElementType = "String"; Elements = @("1") }
42+
@{ Command = {$result = [Collections.Generic.List[string]]@("4")}; CollectionType = 'List`1'; ElementType = "String"; Elements = @("4") }
43+
44+
@{ Command = {$result = [System.Collections.ObjectModel.Collection[int]]@(1)}; CollectionType = 'Collection`1'; ElementType = "Int32"; Elements = @(1) }
45+
@{ Command = {$result = [System.Collections.ObjectModel.Collection[int]]@(1,2)}; CollectionType = 'Collection`1'; ElementType = "Int32"; Elements = @(1,2) }
46+
@{ Command = {$result = [System.Collections.ObjectModel.Collection[int]]"4"}; CollectionType = 'Collection`1'; ElementType = "Int32"; Elements = @(4) }
47+
@{ Command = {$result = [System.Collections.ObjectModel.Collection[int]]@("4","5")}; CollectionType = 'Collection`1'; ElementType = "Int32"; Elements = @(4,5) }
48+
49+
@{ Command = {$result = [Collections.Generic.List[System.IO.FileInfo]]@('TestFile')};
50+
CollectionType = 'List`1'; ElementType = "FileInfo"; Elements = @('TestFile') }
51+
@{ Command = {$result = [Collections.Generic.List[System.IO.FileInfo]]@('TestFile1', 'TestFile2')};
52+
CollectionType = 'List`1'; ElementType = "FileInfo"; Elements = @('TestFile1', 'TestFile2') }
53+
@{ Command = {$result = [Collections.Generic.List[System.IO.FileInfo]]'TestFile'};
54+
CollectionType = 'List`1'; ElementType = "FileInfo"; Elements = @('TestFile') }
55+
)
56+
}
57+
58+
It "<Command>" -TestCases $testCases1 {
59+
param($Command, $CollectionType, $ElementType, $Elements)
60+
61+
$result = $null
62+
. $Command
63+
64+
$result | Should Not BeNullOrEmpty
65+
$result.GetType().Name | Should Be $CollectionType
66+
67+
$genericArgs = $result.GetType().GetGenericArguments()
68+
$genericArgs.Length | Should Be 1
69+
$genericArgs[0].Name | Should Be $ElementType
70+
71+
$result.Count | Should Be $Elements.Length
72+
$result -join ";" | Should Be ($Elements -join ";")
73+
}
74+
}
2375
}

0 commit comments

Comments
 (0)