Skip to content

Commit 0c96975

Browse files
authored
Exclude outvariable assignments within the same CommandAst when inferring variables (PowerShell#25224)
1 parent c1241ed commit 0c96975

File tree

2 files changed

+20
-11
lines changed

2 files changed

+20
-11
lines changed

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

+14-11
Original file line numberDiff line numberDiff line change
@@ -2942,13 +2942,16 @@ private void SetLastAssignment(Ast ast, bool enumerate = false, bool redirection
29422942
}
29432943
}
29442944

2945-
private void SetLastAssignmentType(PSTypeName typeName, int assignmentOffset)
2945+
private void SetLastAssignmentType(PSTypeName typeName, IScriptExtent assignmentExtent)
29462946
{
2947-
if (LastAssignmentOffset < assignmentOffset)
2947+
if (LastAssignmentOffset < assignmentExtent.StartOffset && !VariableTarget.Extent.IsWithin(assignmentExtent))
29482948
{
2949+
// If the variable we are inferring the value of is inside this assignment then the assignment is invalid
2950+
// For example: $x = 1..10; Get-Random 2>variable:x -InputObject ($x.<Tab>) here the variable should be inferred based on the initial 1..10 assignment
2951+
// and not the error redirected variable.
29492952
ClearAssignmentData();
29502953
LastAssignmentType = typeName;
2951-
LastAssignmentOffset = assignmentOffset;
2954+
LastAssignmentOffset = assignmentExtent.StartOffset;
29522955
}
29532956
}
29542957

@@ -3109,17 +3112,17 @@ public override AstVisitAction VisitCommand(CommandAst commandAst)
31093112
{
31103113
case "ErrorVariable":
31113114
case "ev":
3112-
SetLastAssignmentType(new PSTypeName(typeof(List<ErrorRecord>)), commandAst.Extent.StartOffset);
3115+
SetLastAssignmentType(new PSTypeName(typeof(List<ErrorRecord>)), commandAst.Extent);
31133116
break;
31143117

31153118
case "WarningVariable":
31163119
case "wv":
3117-
SetLastAssignmentType(new PSTypeName(typeof(List<WarningRecord>)), commandAst.Extent.StartOffset);
3120+
SetLastAssignmentType(new PSTypeName(typeof(List<WarningRecord>)), commandAst.Extent);
31183121
break;
31193122

31203123
case "InformationVariable":
31213124
case "iv":
3122-
SetLastAssignmentType(new PSTypeName(typeof(List<InformationalRecord>)), commandAst.Extent.StartOffset);
3125+
SetLastAssignmentType(new PSTypeName(typeof(List<InformationalRecord>)), commandAst.Extent);
31233126
break;
31243127

31253128
case "OutVariable":
@@ -3166,23 +3169,23 @@ public override AstVisitAction VisitCommand(CommandAst commandAst)
31663169
switch (fileRedirection.FromStream)
31673170
{
31683171
case RedirectionStream.Error:
3169-
SetLastAssignmentType(new PSTypeName(typeof(ErrorRecord)), commandAst.Extent.StartOffset);
3172+
SetLastAssignmentType(new PSTypeName(typeof(ErrorRecord)), commandAst.Extent);
31703173
break;
31713174

31723175
case RedirectionStream.Warning:
3173-
SetLastAssignmentType(new PSTypeName(typeof(WarningRecord)), commandAst.Extent.StartOffset);
3176+
SetLastAssignmentType(new PSTypeName(typeof(WarningRecord)), commandAst.Extent);
31743177
break;
31753178

31763179
case RedirectionStream.Verbose:
3177-
SetLastAssignmentType(new PSTypeName(typeof(VerboseRecord)), commandAst.Extent.StartOffset);
3180+
SetLastAssignmentType(new PSTypeName(typeof(VerboseRecord)), commandAst.Extent);
31783181
break;
31793182

31803183
case RedirectionStream.Debug:
3181-
SetLastAssignmentType(new PSTypeName(typeof(DebugRecord)), commandAst.Extent.StartOffset);
3184+
SetLastAssignmentType(new PSTypeName(typeof(DebugRecord)), commandAst.Extent);
31823185
break;
31833186

31843187
case RedirectionStream.Information:
3185-
SetLastAssignmentType(new PSTypeName(typeof(InformationRecord)), commandAst.Extent.StartOffset);
3188+
SetLastAssignmentType(new PSTypeName(typeof(InformationRecord)), commandAst.Extent);
31863189
break;
31873190

31883191
default:

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

+6
Original file line numberDiff line numberDiff line change
@@ -1197,6 +1197,12 @@ Describe "Type inference Tests" -tags "CI" {
11971197
$res.Name | Should -Be System.String
11981198
}
11991199

1200+
It 'Ignores assignment when a variable is declared and used within the same commandAst' {
1201+
$variableAst = { Get-Random 2>variable:RandomError1 -InputObject ($RandomError1) }.Ast.FindAll({ param($a) $a -is [Language.VariableExpressionAst] }, $true) | select -Last 1
1202+
$res = [AstTypeInference]::InferTypeOf($variableAst)
1203+
$res.Count | Should -Be 0
1204+
}
1205+
12001206
It 'Ignores the last assignment when a variable is reused' {
12011207
$variableAst = { $x = New-Guid; $x = $x.Where{$_} }.Ast.FindAll({ param($a) $a -is [Language.VariableExpressionAst] }, $true) | select -Last 1
12021208
$res = [AstTypeInference]::InferTypeOf($variableAst)

0 commit comments

Comments
 (0)