diff --git a/src/Cli/dotnet/Commands/Run/CSharpCompilerCommand.cs b/src/Cli/dotnet/Commands/Run/CSharpCompilerCommand.cs index 84ac2b073fe0..d40970596c95 100644 --- a/src/Cli/dotnet/Commands/Run/CSharpCompilerCommand.cs +++ b/src/Cli/dotnet/Commands/Run/CSharpCompilerCommand.cs @@ -106,8 +106,9 @@ public int Execute(out bool fallbackToNormalBuild) // Process the response. var exitCode = ProcessBuildResponse(responseTask.Result, out fallbackToNormalBuild); - // Copy from obj to bin. - if (BuildResultFile != null && + // Copy from obj to bin only if the build succeeded. + if (exitCode == 0 && + BuildResultFile != null && CSharpCommandLineParser.Default.Parse(CscArguments, BaseDirectory, sdkDirectory: null) is { OutputFileName: { } outputFileName } parsedArgs) { var objFile = new FileInfo(parsedArgs.GetOutputFilePath(outputFileName)); diff --git a/test/dotnet.Tests/CommandTests/Run/RunFileTests.cs b/test/dotnet.Tests/CommandTests/Run/RunFileTests.cs index 5d7b53c65a3e..8c48225d55c9 100644 --- a/test/dotnet.Tests/CommandTests/Run/RunFileTests.cs +++ b/test/dotnet.Tests/CommandTests/Run/RunFileTests.cs @@ -3576,6 +3576,57 @@ public void CscOnly_AfterMSBuild_SpacesInPath() Build(testInstance, BuildLevel.Csc, expectedOutput: "v2 Release", programFileName: programFileName); } + /// + /// Testing optimization . + /// When compilation fails, the obj dll should not be copied to bin directory. + /// This prevents spurious errors if the dll file was not even produced by roslyn due to compilation errors. + /// + [Fact] + public void CscOnly_AfterMSBuild_CompilationFailure_NoCopyToBin() + { + var testInstance = _testAssetsManager.CreateTestDirectory(baseDirectory: OutOfTreeBaseDirectory); + + // First, create a valid program and build it successfully + var programPath = Path.Join(testInstance.Path, "Program.cs"); + var code = """ + #:property PublishAot=false + Console.WriteLine("version 1"); + """; + File.WriteAllText(programPath, code); + + var artifactsDir = VirtualProjectBuildingCommand.GetArtifactsPath(programPath); + if (Directory.Exists(artifactsDir)) Directory.Delete(artifactsDir, recursive: true); + + Build(testInstance, BuildLevel.All, expectedOutput: "version 1"); + + // Verify that the dlls were created + var objDll = Path.Join(artifactsDir, "obj", "debug", "Program.dll"); + new FileInfo(objDll).Should().Exist(); + var binDll = Path.Join(artifactsDir, "bin", "debug", "Program.dll"); + new FileInfo(binDll).Should().Exist(); + + // Delete the dlls + File.Delete(objDll); + File.Delete(binDll); + + // Write invalid code that causes compilation to fail + code = code.Replace(";", ""); + File.WriteAllText(programPath, code); + + // Try to build the invalid code + new DotnetCommand(Log, "run", "-bl", "Program.cs") + .WithWorkingDirectory(testInstance.Path) + .Execute() + .Should().Fail() + .And.HaveStdOutContaining(CliCommandStrings.NoBinaryLogBecauseRunningJustCsc) + // error CS1002: ; expected + .And.HaveStdOutContaining("error CS1002") + .And.HaveStdErrContaining(CliCommandStrings.RunCommandException); + + new FileInfo(objDll).Should().NotExist(); + new FileInfo(binDll).Should().NotExist(); + } + /// /// See . ///