diff --git a/src/System.Management.Automation/engine/parser/Compiler.cs b/src/System.Management.Automation/engine/parser/Compiler.cs index fcae018bd..327001181 100644 --- a/src/System.Management.Automation/engine/parser/Compiler.cs +++ b/src/System.Management.Automation/engine/parser/Compiler.cs @@ -3200,7 +3200,7 @@ namespace System.Management.Automation.Language ExpressionCache.Constant(0))); tryBodyExprs.Add(Expression.Label(label0)); tryBodyExprs.Add(Expression.Assign(dispatchIndex, ExpressionCache.Constant(1))); - tryBodyExprs.Add(Compile(currentChain.LhsPipelineChain)); + tryBodyExprs.Add(CompilePipelineChainElement((PipelineAst)currentChain.LhsPipelineChain)); // Remainder of try statement body // L1: dispatchIndex = 2; if ($?) pipeline2; @@ -3234,7 +3234,7 @@ namespace System.Management.Automation.Language ? s_getDollarQuestion : s_notDollarQuestion; - tryBodyExprs.Add(Expression.IfThen(dollarQuestionCheck, Compile(currentChain.RhsPipeline))); + tryBodyExprs.Add(Expression.IfThen(dollarQuestionCheck, CompilePipelineChainElement(currentChain.RhsPipeline))); currentChain = currentChain.Parent as PipelineChainAst; } @@ -3277,6 +3277,24 @@ namespace System.Management.Automation.Language return fullyExpandedBlock; } + /// + /// Compile a pipeline as an element in a pipeline chain. + /// Needed since pure expressions won't set $? after them. + /// which does something similar. + /// + /// The pipeline in the pipeline chain to compile to an expression. + /// The compiled expression to execute the pipeline. + private Expression CompilePipelineChainElement(PipelineAst pipelineAst) + { + if (pipelineAst.PipelineElements.Count == 1 && pipelineAst.PipelineElements[0] is CommandExpressionAst) + { + // A single expression - must set $? after the expression. + return Expression.Block(Compile(pipelineAst), s_setDollarQuestionToTrue); + } + + return Compile(pipelineAst); + } + public object VisitPipeline(PipelineAst pipelineAst) { var temps = new List(); diff --git a/src/System.Management.Automation/engine/parser/token.cs b/src/System.Management.Automation/engine/parser/token.cs index b9dae289e..62d911baa 100644 --- a/src/System.Management.Automation/engine/parser/token.cs +++ b/src/System.Management.Automation/engine/parser/token.cs @@ -790,8 +790,8 @@ namespace System.Management.Automation.Language #region Flags for operators - /* AndAnd */ TokenFlags.BinaryOperator | TokenFlags.ParseModeInvariant, - /* OrOr */ TokenFlags.BinaryOperator | TokenFlags.ParseModeInvariant, + /* AndAnd */ TokenFlags.ParseModeInvariant, + /* OrOr */ TokenFlags.ParseModeInvariant, /* Ampersand */ TokenFlags.SpecialOperator | TokenFlags.ParseModeInvariant, /* Pipe */ TokenFlags.SpecialOperator | TokenFlags.ParseModeInvariant, /* Comma */ TokenFlags.UnaryOperator | TokenFlags.ParseModeInvariant, diff --git a/test/powershell/Language/Operators/PipelineChainOperator.Tests.ps1 b/test/powershell/Language/Operators/PipelineChainOperator.Tests.ps1 index d376161f3..2e8242a47 100644 --- a/test/powershell/Language/Operators/PipelineChainOperator.Tests.ps1 +++ b/test/powershell/Language/Operators/PipelineChainOperator.Tests.ps1 @@ -76,6 +76,8 @@ Describe "Experimental Feature: && and || operators - Feature-Enabled" -Tag CI { @{ Statement = '"hi" && testexe -returncode 1'; Output = @('hi', '1') } @{ Statement = 'testexe -returncode 1 && "Hi"'; Output = @('1') } @{ Statement = 'testexe -returncode 1 || "hi"'; Output = @('1', 'hi') } + @{ Statement = '"hello" && get-item macarena_doesnotexist || "there"; "hello" || "there"'; Output = @('hello', 'there', 'hello') } + @{ Statement = '1 + 1 && "Hi"'; Output = @(2, 'Hi') } # Pipeline and native command @{ Statement = '1,2,3 | % { $_ + 1 } && testexe -returncode 0'; Output = @('2','3','4','0') }