From f093f538fa6a1c21e0d4b53c1b514571ad148d46 Mon Sep 17 00:00:00 2001 From: MartinGC94 <42123497+MartinGC94@users.noreply.github.com> Date: Mon, 12 Jun 2023 19:38:17 +0200 Subject: [PATCH] Fix variable type inference precedence (#18691) --- .../engine/parser/TypeInferenceVisitor.cs | 12 ++++-------- .../engine/Api/TypeInference.Tests.ps1 | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/System.Management.Automation/engine/parser/TypeInferenceVisitor.cs b/src/System.Management.Automation/engine/parser/TypeInferenceVisitor.cs index de6375bfdb..1e1ff771ac 100644 --- a/src/System.Management.Automation/engine/parser/TypeInferenceVisitor.cs +++ b/src/System.Management.Automation/engine/parser/TypeInferenceVisitor.cs @@ -2121,11 +2121,6 @@ namespace System.Management.Automation parent = parent.Parent; } - if (parent.Parent is FunctionDefinitionAst) - { - parent = parent.Parent; - } - int startOffset = variableExpressionAst.Extent.StartOffset; var targetAsts = (List)AstSearcher.FindAll( parent, @@ -2165,9 +2160,9 @@ namespace System.Management.Automation // If any of the assignments lhs use a type constraint, then we use that. // Otherwise, we use the rhs of the "nearest" assignment - foreach (var assignAst in assignAsts) + for (int i = assignAsts.Length - 1; i >= 0; i--) { - if (assignAst.Left is ConvertExpressionAst lhsConvert) + if (assignAsts[i].Left is ConvertExpressionAst lhsConvert) { inferredTypes.Add(new PSTypeName(lhsConvert.Type.TypeName)); return; @@ -2592,7 +2587,8 @@ namespace System.Management.Automation if (parameterAst != null) { return variableAstVariablePath.IsUnscopedVariable && - parameterAst.Name.VariablePath.UnqualifiedPath.Equals(variableAstVariablePath.UnqualifiedPath, StringComparison.OrdinalIgnoreCase); + parameterAst.Name.VariablePath.UnqualifiedPath.Equals(variableAstVariablePath.UnqualifiedPath, StringComparison.OrdinalIgnoreCase) && + parameterAst.Parent.Parent.Extent.EndOffset > variableAst.Extent.StartOffset; } if (ast is ForEachStatementAst foreachAst) diff --git a/test/powershell/engine/Api/TypeInference.Tests.ps1 b/test/powershell/engine/Api/TypeInference.Tests.ps1 index 14e3a3b086..69817f6290 100644 --- a/test/powershell/engine/Api/TypeInference.Tests.ps1 +++ b/test/powershell/engine/Api/TypeInference.Tests.ps1 @@ -1385,6 +1385,24 @@ Describe "Type inference Tests" -tags "CI" { $res.Name -join ' ' | Should -Be "System.IO.FileInfo System.IO.DirectoryInfo" } + It 'Infers closest variable type' { + $res = [AstTypeInference]::InferTypeOf( { [string]$TestVar = "";[hashtable]$TestVar = @{};$TestVar }.Ast) + $res.Name | Select-Object -Last 1 | Should -Be "System.Collections.Hashtable" + } + + It 'Infers closest variable type and ignores unrelated param blocks' { + $res = [AstTypeInference]::InferTypeOf( { + [hashtable]$ParameterName=@{} + function Verb-Noun { + param + ( + [string]$ParameterName + ) + } + $ParameterName }.Ast) + $res.Name | Should -Be "System.Collections.Hashtable" + } + It 'Infers type of $null after variable assignment' { $res = [AstTypeInference]::InferTypeOf( { $null = "Hello";$null }.Ast) $res.Count | Should -Be 0