Skip to content

Commit b5ffd04

Browse files
authored
Improve type inference of hashtable keys (#17907)
1 parent 134149e commit b5ffd04

File tree

2 files changed

+55
-19
lines changed

2 files changed

+55
-19
lines changed

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

+42-19
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,6 @@ object ICustomAstVisitor.VisitHashtable(HashtableAst hashtableAst)
540540
foreach (var kv in hashtableAst.KeyValuePairs)
541541
{
542542
string name = null;
543-
string typeName = null;
544543
if (kv.Item1 is StringConstantExpressionAst stringConstantExpressionAst)
545544
{
546545
name = stringConstantExpressionAst.Value;
@@ -554,32 +553,46 @@ object ICustomAstVisitor.VisitHashtable(HashtableAst hashtableAst)
554553
name = nameValue.ToString();
555554
}
556555

557-
if (name != null)
556+
if (name is not null)
558557
{
559-
object value = null;
560558
if (kv.Item2 is PipelineAst pipelineAst && pipelineAst.GetPureExpression() is ExpressionAst expression)
561559
{
562-
switch (expression)
560+
object value;
561+
if (expression is ConstantExpressionAst constant)
563562
{
564-
case ConstantExpressionAst constantExpression:
565-
value = constantExpression.Value;
566-
break;
567-
default:
568-
typeName = InferTypes(kv.Item2).FirstOrDefault()?.Name;
569-
if (typeName == null)
570-
{
571-
if (SafeExprEvaluator.TrySafeEval(expression, _context.ExecutionContext, out object safeValue))
572-
{
573-
value = safeValue;
574-
}
575-
}
563+
value = constant.Value;
564+
}
565+
else
566+
{
567+
_ = SafeExprEvaluator.TrySafeEval(expression, _context.ExecutionContext, out value);
568+
}
576569

577-
break;
570+
PSTypeName valueType;
571+
if (value is null)
572+
{
573+
valueType = new PSTypeName("System.Object");
578574
}
575+
else
576+
{
577+
valueType = new PSTypeName(value.GetType());
578+
}
579+
580+
properties.Add(new PSMemberNameAndType(name, valueType, value));
579581
}
582+
else
583+
{
584+
bool foundAnyTypes = false;
585+
foreach (var item in InferTypes(kv.Item2))
586+
{
587+
foundAnyTypes = true;
588+
properties.Add(new PSMemberNameAndType(name, item));
589+
}
580590

581-
var pstypeName = value != null ? new PSTypeName(value.GetType()) : new PSTypeName(typeName ?? "System.Object");
582-
properties.Add(new PSMemberNameAndType(name, pstypeName, value));
591+
if (!foundAnyTypes)
592+
{
593+
properties.Add(new PSMemberNameAndType(name, new PSTypeName("System.Object")));
594+
}
595+
}
583596
}
584597
}
585598

@@ -2257,6 +2270,16 @@ private IEnumerable<PSTypeName> InferTypeFrom(IndexExpressionAst indexExpression
22572270
bool foundAny = false;
22582271
foreach (var psType in targetTypes)
22592272
{
2273+
if (psType is PSSyntheticTypeName syntheticType)
2274+
{
2275+
foreach (var member in syntheticType.Members)
2276+
{
2277+
yield return member.PSTypeName;
2278+
}
2279+
2280+
continue;
2281+
}
2282+
22602283
var type = psType.Type;
22612284
if (type != null)
22622285
{

test/powershell/engine/Api/TypeInference.Tests.ps1

+13
Original file line numberDiff line numberDiff line change
@@ -1091,6 +1091,7 @@ Describe "Type inference Tests" -tags "CI" {
10911091
$res | Should -HaveCount 1
10921092
$res.Name | Should -Be System.Guid
10931093
}
1094+
10941095
It 'Infers type of variable $_ in array of calculated properties' {
10951096
$variableAst = { New-TimeSpan | Select-Object -Property Day,@{n="min";e={$_}} }.Ast.Find({ param($a) $a -is [System.Management.Automation.Language.VariableExpressionAst] }, $true)
10961097
$res = [AstTypeInference]::InferTypeOf($variableAst)
@@ -1353,6 +1354,18 @@ Describe "Type inference Tests" -tags "CI" {
13531354
$res.Count | Should -Be 1
13541355
$res.Name | Should -Be 'System.Management.Automation.Language.Ast'
13551356
}
1357+
1358+
It 'Infers type of hashtable key with multiple types' {
1359+
$res = [AstTypeInference]::InferTypeOf( { (@{RandomKey = Get-ChildItem $HOME}).RandomKey }.Ast)
1360+
$res.Count | Should -Be 2
1361+
$res.Name -join ' ' | Should -Be "System.IO.FileInfo System.IO.DirectoryInfo"
1362+
}
1363+
1364+
It 'Infers type of index expression on hashtable with synthetic type' {
1365+
$res = [AstTypeInference]::InferTypeOf( { (@{RandomKey = Get-ChildItem $HOME})['RandomKey'] }.Ast)
1366+
$res.Count | Should -Be 2
1367+
$res.Name -join ' ' | Should -Be "System.IO.FileInfo System.IO.DirectoryInfo"
1368+
}
13561369
}
13571370

13581371
Describe "AstTypeInference tests" -Tags CI {

0 commit comments

Comments
 (0)