diff --git a/src/System.Management.Automation/engine/parser/Compiler.cs b/src/System.Management.Automation/engine/parser/Compiler.cs index 3fac9de74f6..91daf43821d 100644 --- a/src/System.Management.Automation/engine/parser/Compiler.cs +++ b/src/System.Management.Automation/engine/parser/Compiler.cs @@ -2278,25 +2278,26 @@ private Expression CaptureAstResults( switch (context) { case CaptureAstContext.AssignmentWithResultPreservation: - result = Expression.Call(CachedReflectionInfo.PipelineOps_PipelineResult, resultList); - - // PipelineResult might get skipped in some circumstances due to an early return or a FlowControlException thrown out, in which case - // we write to the oldPipe. This can happen in cases like: - // $(1;2;return 3) - finallyExprs.Add(Expression.Call(CachedReflectionInfo.PipelineOps_FlushPipe, oldPipe, resultList)); - break; case CaptureAstContext.AssignmentWithoutResultPreservation: result = Expression.Call(CachedReflectionInfo.PipelineOps_PipelineResult, resultList); // Clear the temporary pipe in case of exception, if we are not required to preserve the results - var catchExprs = new List + if (context == CaptureAstContext.AssignmentWithoutResultPreservation) { - Expression.Call(CachedReflectionInfo.PipelineOps_ClearPipe, resultList), - Expression.Rethrow(), - Expression.Constant(null, typeof(object)) - }; + var catchExprs = new List + { + Expression.Call(CachedReflectionInfo.PipelineOps_ClearPipe, resultList), + Expression.Rethrow(), + Expression.Constant(null, typeof(object)) + }; + + catches.Add(Expression.Catch(typeof(RuntimeException), Expression.Block(typeof(object), catchExprs))); + } - catches.Add(Expression.Catch(typeof(RuntimeException), Expression.Block(typeof(object), catchExprs))); + // PipelineResult might get skipped in some circumstances due to an early return or a FlowControlException thrown out, + // in which case we write to the oldPipe. This can happen in cases like: + // $(1;2;return 3) + finallyExprs.Add(Expression.Call(CachedReflectionInfo.PipelineOps_FlushPipe, oldPipe, resultList)); break; case CaptureAstContext.Condition: result = DynamicExpression.Dynamic(PSPipelineResultToBoolBinder.Get(), typeof(bool), resultList); diff --git a/test/powershell/Language/Scripting/Scripting.Followup.Tests.ps1 b/test/powershell/Language/Scripting/Scripting.Followup.Tests.ps1 index fff4993ffec..56bc16b2710 100644 --- a/test/powershell/Language/Scripting/Scripting.Followup.Tests.ps1 +++ b/test/powershell/Language/Scripting/Scripting.Followup.Tests.ps1 @@ -81,28 +81,6 @@ Describe "Scripting.Followup.Tests" -Tags "CI" { $result | Should -BeOfType 'System.Collections.Specialized.OrderedDictionary' } - It "Don't preserve result when no need to do so in case of flow-control exception" { - function TestFunc1([switch]$p) { - ## No need to preserve and flush the results from the IF statement to the outer - ## pipeline, because the results are supposed to be assigned to a variable. - if ($p) { - $null = if ($true) { "one"; return "two" } - } else { - $a = foreach ($a in 1) { "one"; return; } - } - } - - function TestFunc2 { - ## The results from the sub-expression need to be preserved and flushed to the outer pipeline. - $("1";return "2") - } - - TestFunc1 | Should -Be $null - TestFunc1 -p | Should -Be $null - - TestFunc2 | Should -Be @("1", "2") - } - It "'[NullString]::Value' should be treated as string type when resolving .NET method" { $testType = 'NullStringTest' -as [type] if (-not $testType) { @@ -146,4 +124,27 @@ public class NullStringTest { $result = & $powershell -noprofile -c '[System.Text.Encoding]::GetEncoding("IBM437").WebName' $result | Should -BeExactly "ibm437" } + + It 'Return statement on the right side of an assignment should write the retrun value to outer pipe' { + function TestFunc1 { + ## The return value are not assigned to the variable but should be written to the outer pipe. + $Global:mylhsvar = if ($true) { return "one" } + } + + function TestFunc2 { + ## The results from the sub-expression need to be preserved and flushed to the outer pipeline. + $("1";return "2") + } + + try { + $Global:mylhsvar = $null + TestFunc1 | Should -BeExactly "one" + TestFunc2 | Should -Be @("1", "2") + + $Global:mylhsvar | Should -Be $null + } + finally { + Remove-Variable -Name mylhsvar -Scope Global + } + } }