Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Standard libraries and separate compilation #5981

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion Source/DafnyCore/Backends/CSharp/CsharpBackend.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Microsoft.Dafny.Compilers;
Expand Down Expand Up @@ -131,7 +133,10 @@ public override async Task<bool> RunTargetProgram(string dafnyProgramName, strin

foreach (var otherFileName in otherFileNames) {
if (Path.GetExtension(otherFileName) == ".dll") {
File.Copy(otherFileName, Path.Combine(dllFolder, Path.GetFileName(otherFileName)), true);
var destination = Path.Combine(dllFolder, Path.GetFileName(otherFileName));
if (Path.GetFullPath(otherFileName) != Path.GetFullPath(destination)) {
File.Copy(otherFileName, destination, true);
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion Source/DafnyCore/Backends/CSharp/CsharpCodeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ protected override void EmitHeader(Program program, ConcreteSyntaxTree wr) {
if (Options.IncludeRuntime) {
EmitRuntimeSource("DafnyRuntimeCsharp", wr, false);
}
if (Options.Get(CommonOptionBag.UseStandardLibraries)) {
if (Options.Get(CommonOptionBag.UseStandardLibraries) && Options.Get(CommonOptionBag.TranslateStandardLibrary)) {
EmitRuntimeSource("DafnyStandardLibraries_cs", wr, false);
}

Expand Down
2 changes: 1 addition & 1 deletion Source/DafnyCore/Backends/GoLang/GoCodeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ protected override void EmitHeader(Program program, ConcreteSyntaxTree wr) {
}
ImportsNotFromDafnyModules.Add(new Import { Name = "_dafny", Path = $"{path}dafny" });

if (Options.Get(CommonOptionBag.UseStandardLibraries)) {
if (Options.Get(CommonOptionBag.UseStandardLibraries) && Options.Get(CommonOptionBag.TranslateStandardLibrary)) {
EmitRuntimeSource("DafnyStandardLibraries_go", wr);
}

Expand Down
2 changes: 1 addition & 1 deletion Source/DafnyCore/Backends/Java/JavaCodeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ protected override void EmitHeader(Program program, ConcreteSyntaxTree wr) {
if (Options.IncludeRuntime) {
EmitRuntimeSource("DafnyRuntimeJava", wr);
}
if (Options.Get(CommonOptionBag.UseStandardLibraries)) {
if (Options.Get(CommonOptionBag.UseStandardLibraries) && Options.Get(CommonOptionBag.TranslateStandardLibrary)) {
EmitRuntimeSource("DafnyStandardLibraries_java", wr);
}
wr.WriteLine($"// Dafny program {program.Name} compiled into Java");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ protected override void EmitHeader(Program program, ConcreteSyntaxTree wr) {
if (Options.IncludeRuntime) {
EmitRuntimeSource("DafnyRuntimeJs", wr, false);
}
if (Options.Get(CommonOptionBag.UseStandardLibraries)) {
if (Options.Get(CommonOptionBag.UseStandardLibraries) && Options.Get(CommonOptionBag.TranslateStandardLibrary)) {
EmitRuntimeSource("DafnyStandardLibraries_js", wr, false);
}
}
Expand Down
2 changes: 1 addition & 1 deletion Source/DafnyCore/Backends/Python/PythonCodeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ protected override void EmitHeader(Program program, ConcreteSyntaxTree wr) {
if (Options.IncludeRuntime) {
EmitRuntimeSource("DafnyRuntimePython", wr);
}
if (Options.Get(CommonOptionBag.UseStandardLibraries)) {
if (Options.Get(CommonOptionBag.UseStandardLibraries) && Options.Get(CommonOptionBag.TranslateStandardLibrary)) {
EmitRuntimeSource("DafnyStandardLibraries_py", wr);
}

Expand Down
7 changes: 7 additions & 0 deletions Source/DafnyCore/Options/CommonOptionBag.cs
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,12 @@ public enum DefaultFunctionOpacityOptions {
`opaque` means functions are always opaque so the opaque keyword is not needed, and functions must be revealed everywhere needed for a proof.".TrimStart()) {
};

public static readonly Option<bool> TranslateStandardLibrary = new("--translate-standard-library", () => true,
@"Currently Dafny does not prevent separately built Dafny projects from each including the standard library,
leading to conflicts. When combining such projects, please ensure that only one of them has --translate-standard-library set to true.
Comment on lines +370 to +371
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The first sentence feels overly defensive to me, but it might be because we see the current state differently. I don't think it's inherently wrong to merge doo files personally, building larger aggregate libraries, as long as you don't use them incorrectly.

When building a Dafny library (.doo file), this option will automatically be set to false.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels like it's going to be confusing and hard to debug, especially since it's a change in behavior. Wouldn't it be better to fail instead, and make users set --translate-standard-library:false explicitly?

");

public static readonly Option<bool> UseStandardLibraries = new("--standard-libraries", () => false,
@"
Allow Dafny code to depend on the standard libraries included with the Dafny distribution.
Expand Down Expand Up @@ -610,6 +616,7 @@ void ParsePrintMode(Option<PrintModes> option, Boogie.CommandLineParseState ps,
OptionRegistry.RegisterGlobalOption(AllowDeprecation, OptionCompatibility.OptionLibraryImpliesLocalWarning);
OptionRegistry.RegisterGlobalOption(WarnShadowing, OptionCompatibility.OptionLibraryImpliesLocalWarning);
OptionRegistry.RegisterGlobalOption(UseStandardLibraries, OptionCompatibility.OptionLibraryImpliesLocalError);
OptionRegistry.RegisterOption(TranslateStandardLibrary, OptionScope.Cli);
OptionRegistry.RegisterOption(WarnAsErrors, OptionScope.Cli);
OptionRegistry.RegisterOption(ProgressOption, OptionScope.Cli);
OptionRegistry.RegisterOption(LogLocation, OptionScope.Cli);
Expand Down
1 change: 1 addition & 0 deletions Source/DafnyCore/Options/DafnyCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ static DafnyCommands() {
CommonOptionBag.NewTypeInferenceDebug,
Method.ReadsClausesOnMethods,
CommonOptionBag.UseStandardLibraries,
CommonOptionBag.TranslateStandardLibrary,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't it be a translation option? It doesn't make sense to pass this to resolve or verify

CommonOptionBag.LogLevelOption,
CommonOptionBag.LogLocation
});
Expand Down
8 changes: 7 additions & 1 deletion Source/DafnyCore/Pipeline/Compilation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.CommandLine;
using System.IO;
using System.Linq;
using System.Reactive;
using System.Reactive.Subjects;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Boogie;
using Microsoft.Dafny.Compilers;
using Microsoft.Extensions.Logging;
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
using VC;
Expand Down Expand Up @@ -176,9 +178,13 @@ private async Task<IReadOnlyList<DafnyFile>> DetermineRootFiles() {
}

if (Options.Get(CommonOptionBag.UseStandardLibraries)) {
if (Options.Backend is LibraryBackend) {
Options.Set(CommonOptionBag.TranslateStandardLibrary, false);
}

// For now the standard libraries are still translated from scratch.
// This breaks separate compilation and will be addressed in https://github.com/dafny-lang/dafny/pull/4877
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto

var asLibrary = false;
var asLibrary = !Options.Get(CommonOptionBag.TranslateStandardLibrary);

if (Options.CompilerName is null or "cs" or "java" or "go" or "py" or "js") {
var targetName = Options.CompilerName ?? "notarget";
Expand Down
6 changes: 5 additions & 1 deletion Source/DafnyDriver/Legacy/SynchronousCliCompilation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,13 @@ public static async Task<int> Run(DafnyOptions options) {
// only because if they are added first, one might be used as the program name,
// which is not handled well.
if (options.Get(CommonOptionBag.UseStandardLibraries)) {
if (options.Backend is LibraryBackend) {
options.Set(CommonOptionBag.TranslateStandardLibrary, false);
}

// For now the standard libraries are still translated from scratch.
// This breaks separate compilation and will be addressed in https://github.com/dafny-lang/dafny/pull/4877
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you're addressing "this breaks separate compilation" with this change so just that part of the comment can be removed, although I think the rest still applies (although I think we might publish the libraries separately rather than embed them in the runtimes)

var asLibrary = false;
var asLibrary = !options.Get(CommonOptionBag.TranslateStandardLibrary);

var reporter = new ConsoleErrorReporter(options);
if (options.CompilerName is null or "cs" or "java" or "go" or "py" or "js") {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module UsesWrappers {

import opened Std.Wrappers

function SafeDiv(a: int, b: int): Option<int> {
if b == 0 then None else Some(a/b)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// NONUNIFORM: Test is too complex for the uniform back-end testing mechanism
// RUN: %build --target=lib "%S/Inputs/library.dfy" --standard-libraries=true --output %S/Outputs > %t
// RUN: %run --standard-libraries=true %s --input "%S/Outputs.doo" >> %t
//
// Let's pretend we're vending a Dafny library outside of Dafny, and we want to include the std-lib with the library,
// since the external user won't include it
// RUN: %build "%S/Inputs/library.dfy" --standard-libraries=true --output %S/Outputs >> %t
// RUN: %run --standard-libraries=true %s --library "%S/Outputs.doo" --input "%S/Outputs.dll" --translate-standard-library=false >> %t
// RUN: %diff "%s.expect" "%t"

import opened UsesWrappers

method Main() {
print SafeDiv(4, 2), "\n";
print SafeDiv(7, 0), "\n";
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

Dafny program verifier finished with 1 verified, 0 errors

Dafny program verifier finished with 0 verified, 0 errors
Wrappers.Option.Some(2)
Wrappers.Option.None

Dafny program verifier finished with 1 verified, 0 errors

Dafny program verifier finished with 0 verified, 0 errors
Wrappers.Option.Some(2)
Wrappers.Option.None
Loading