From 492fd82d58690d88906420a97777b75a6b8b3b57 Mon Sep 17 00:00:00 2001 From: Fabio Madge <fmadge@amazon.com> Date: Fri, 4 Aug 2023 08:45:22 +0200 Subject: [PATCH 01/19] fix: Return `BigInteger` when computing the `multiset` cardinality in C# (#4370) Fixes #4125. We could also apply this to the other collection types, but the benefit would only lie in the simpler code generation. --------- Co-authored-by: Remy Willems <rwillems@amazon.com> --- .../Compilers/CSharp/Compiler-Csharp.cs | 9 +++++++-- Source/DafnyCore/DafnyGeneratedFromDafny.sh | 2 +- Source/DafnyRuntime/DafnyRuntime.cs | 20 +++++++++++-------- Test/git-issues/git-issue-4012.dfy | 8 ++++---- Test/git-issues/git-issue-4012.dfy.cs.check | 2 -- 5 files changed, 24 insertions(+), 17 deletions(-) delete mode 100644 Test/git-issues/git-issue-4012.dfy.cs.check diff --git a/Source/DafnyCore/Compilers/CSharp/Compiler-Csharp.cs b/Source/DafnyCore/Compilers/CSharp/Compiler-Csharp.cs index 797b927247e..a264ee708f8 100644 --- a/Source/DafnyCore/Compilers/CSharp/Compiler-Csharp.cs +++ b/Source/DafnyCore/Compilers/CSharp/Compiler-Csharp.cs @@ -2933,8 +2933,13 @@ protected override void EmitUnaryExpr(ResolvedUnaryOp op, Expression expr, bool TrParenExpr("~", expr, wr, inLetExprBody, wStmts); break; case ResolvedUnaryOp.Cardinality: - TrParenExpr("new BigInteger(", expr, wr, inLetExprBody, wStmts); - wr.Write(".Count)"); + if (expr.Type.AsCollectionType is MultiSetType) { + TrParenExpr(expr, wr, inLetExprBody, wStmts); + wr.Write(".ElementCount"); + } else { + TrParenExpr("new BigInteger(", expr, wr, inLetExprBody, wStmts); + wr.Write(".Count)"); + } break; default: Contract.Assert(false); throw new cce.UnreachableException(); // unexpected unary expression diff --git a/Source/DafnyCore/DafnyGeneratedFromDafny.sh b/Source/DafnyCore/DafnyGeneratedFromDafny.sh index b6b8bce572e..95f6bcf3872 100644 --- a/Source/DafnyCore/DafnyGeneratedFromDafny.sh +++ b/Source/DafnyCore/DafnyGeneratedFromDafny.sh @@ -21,7 +21,7 @@ fi ../../Scripts/dafny translate cs --output $output.cs AST/Formatting.dfy ../../Scripts/dafny translate cs --output "${output}Rust.cs" Compilers/Rust/Dafny-compiler-rust.dfy -python -c " +python3 -c " import re with open ('$output.cs', 'r' ) as f: content = f.read() diff --git a/Source/DafnyRuntime/DafnyRuntime.cs b/Source/DafnyRuntime/DafnyRuntime.cs index 8b60cb18ea3..c4ad7ccd81b 100755 --- a/Source/DafnyRuntime/DafnyRuntime.cs +++ b/Source/DafnyRuntime/DafnyRuntime.cs @@ -374,6 +374,7 @@ public interface IMultiSet<out T> { bool IsEmpty { get; } int Count { get; } long LongCount { get; } + BigInteger ElementCount { get; } IEnumerable<T> Elements { get; } IEnumerable<T> UniqueElements { get; } bool Contains<G>(G t); @@ -652,18 +653,21 @@ public static IMultiSet<T> Difference(IMultiSet<T> th, IMultiSet<T> other) { // public bool IsEmpty { get { return occurrencesOfNull == 0 && dict.IsEmpty; } } public int Count { - get { return (int)ElementCount(); } + get { return (int)ElementCount; } } public long LongCount { - get { return (long)ElementCount(); } + get { return (long)ElementCount; } } - private BigInteger ElementCount() { - // This is inefficient - var c = occurrencesOfNull; - foreach (var item in dict) { - c += item.Value; + + public BigInteger ElementCount { + get { + // This is inefficient + var c = occurrencesOfNull; + foreach (var item in dict) { + c += item.Value; + } + return c; } - return c; } public IEnumerable<T> Elements { diff --git a/Test/git-issues/git-issue-4012.dfy b/Test/git-issues/git-issue-4012.dfy index 5360c0e935b..14b6d550fb7 100644 --- a/Test/git-issues/git-issue-4012.dfy +++ b/Test/git-issues/git-issue-4012.dfy @@ -1,7 +1,7 @@ -// RUN: %testDafnyForEachCompiler "%s" -- --relax-definite-assignment +// RUN: %testDafnyForEachCompiler "%s" method Main() { - var x: multiset<int> := multiset{}; - x := x[1 := 18446744073709551616]; - print |x|, "\n"; + var m: multiset<()> := multiset{}; + m := m[() := 18446744073709551616]; + print |m|, "\n"; } diff --git a/Test/git-issues/git-issue-4012.dfy.cs.check b/Test/git-issues/git-issue-4012.dfy.cs.check deleted file mode 100644 index 42f034cb8ed..00000000000 --- a/Test/git-issues/git-issue-4012.dfy.cs.check +++ /dev/null @@ -1,2 +0,0 @@ -// https://github.com/dafny-lang/dafny/issues/4125 -// CHECK-L: Unhandled exception. System.OverflowException: Value was either too large or too small for an Int32. From c6d73ef657e4bd724af1e3aa7b7811e8d994c530 Mon Sep 17 00:00:00 2001 From: Fabio Madge <fmadge@amazon.com> Date: Fri, 4 Aug 2023 12:19:49 +0200 Subject: [PATCH 02/19] fix: Type name for `array`s in JavaScript (#4386) Fixes #3873. --- Source/DafnyCore/Compilers/JavaScript/Compiler-js.cs | 6 +----- Test/git-issues/git-issue-3873.dfy | 8 ++++++++ Test/git-issues/git-issue-3873.dfy.expect | 1 + 3 files changed, 10 insertions(+), 5 deletions(-) create mode 100644 Test/git-issues/git-issue-3873.dfy create mode 100644 Test/git-issues/git-issue-3873.dfy.expect diff --git a/Source/DafnyCore/Compilers/JavaScript/Compiler-js.cs b/Source/DafnyCore/Compilers/JavaScript/Compiler-js.cs index 37199e303a6..d8acadc7ba1 100644 --- a/Source/DafnyCore/Compilers/JavaScript/Compiler-js.cs +++ b/Source/DafnyCore/Compilers/JavaScript/Compiler-js.cs @@ -900,11 +900,7 @@ internal override string TypeName(Type type, ConcreteSyntaxTree wr, IToken tok, } else if (xType.IsObjectQ) { return "object"; } else if (xType.IsArrayType) { - ArrayClassDecl at = xType.AsArrayType; - Contract.Assert(at != null); // follows from type.IsArrayType - Type elType = UserDefinedType.ArrayElementType(xType); - TypeName_SplitArrayName(elType, wr, tok, out var typeNameSansBrackets, out var brackets); - return typeNameSansBrackets + TypeNameArrayBrackets(at.Dims) + brackets; + return "Array"; } else if (xType is UserDefinedType udt) { var s = FullTypeName(udt, member); return TypeName_UDT(s, udt, wr, udt.tok); diff --git a/Test/git-issues/git-issue-3873.dfy b/Test/git-issues/git-issue-3873.dfy new file mode 100644 index 00000000000..064fc77ad3e --- /dev/null +++ b/Test/git-issues/git-issue-3873.dfy @@ -0,0 +1,8 @@ +// RUN: %testDafnyForEachCompiler "%s" + +method Main() { + var a := new ()[1]; + var m: map<array<()>, ()> := map[a := ()]; + var v :| v in m; + print v[0], "\n"; +} diff --git a/Test/git-issues/git-issue-3873.dfy.expect b/Test/git-issues/git-issue-3873.dfy.expect new file mode 100644 index 00000000000..6a452c185a8 --- /dev/null +++ b/Test/git-issues/git-issue-3873.dfy.expect @@ -0,0 +1 @@ +() From 41e05f208c4d9947de84e6ccd1ded461c1c5e73c Mon Sep 17 00:00:00 2001 From: Remy Willems <rwillems@amazon.com> Date: Fri, 4 Aug 2023 13:11:11 +0200 Subject: [PATCH 03/19] Remove logging noise (#4376) Remove logging noise by filtering out the two framework exceptions that we can't prevent <small>By submitting this pull request, I confirm that my contribution is made under the terms of the [MIT license](https://github.com/dafny-lang/dafny/blob/master/LICENSE.txt).</small> --- .../DafnyLanguageServerTestBase.cs | 20 ++++++++----------- .../Workspace/IdeStateObserver.cs | 2 +- .../Workspace/LanguageServerFilesystem.cs | 2 +- .../Workspace/VerificationProgressReporter.cs | 4 ++-- 4 files changed, 12 insertions(+), 16 deletions(-) diff --git a/Source/DafnyLanguageServer.Test/DafnyLanguageServerTestBase.cs b/Source/DafnyLanguageServer.Test/DafnyLanguageServerTestBase.cs index b1da3915301..9e2a8ffa12b 100644 --- a/Source/DafnyLanguageServer.Test/DafnyLanguageServerTestBase.cs +++ b/Source/DafnyLanguageServer.Test/DafnyLanguageServerTestBase.cs @@ -54,8 +54,13 @@ ensures true public IProjectDatabase Projects => Server.GetRequiredService<IProjectDatabase>(); - public DafnyLanguageServerTestBase(ITestOutputHelper output) : base(new JsonRpcTestOptions(LoggerFactory.Create( - builder => builder.AddConsole().SetMinimumLevel(LogLevel.Warning)))) { + protected DafnyLanguageServerTestBase(ITestOutputHelper output) : base(new JsonRpcTestOptions(LoggerFactory.Create( + builder => { + builder.AddFilter("OmniSharp.Extensions.JsonRpc", LogLevel.None); + builder.AddFilter("OmniSharp", LogLevel.Warning); + builder.AddFilter("Microsoft.Dafny", LogLevel.Information); + builder.AddConsole(); + }))) { this.output = new WriterFromOutputHelper(output); } @@ -92,7 +97,6 @@ private Action<LanguageServerOptions> GetServerOptionsAction(Action<DafnyOptions ServerCommand.ConfigureDafnyOptionsForServer(dafnyOptions); ApplyDefaultOptionValues(dafnyOptions); return options => { - options.ConfigureLogging(SetupTestLogging); options.WithDafnyLanguageServer(() => { }); options.Services.AddSingleton(dafnyOptions); options.Services.AddSingleton<IProgramVerifier>(serviceProvider => new SlowVerifier( @@ -120,14 +124,6 @@ private static void ApplyDefaultOptionValues(DafnyOptions dafnyOptions) { } } - private static void SetupTestLogging(ILoggingBuilder builder) { - builder - .AddFilter("OmniSharp", LogLevel.Warning) - .AddFilter("Microsoft.Dafny", LogLevel.Information) - .SetMinimumLevel(LogLevel.Debug) - .AddConsole(); - } - protected static TextDocumentItem CreateTestDocument(string source, string filePath = null, int version = 1) { if (filePath == null) { filePath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName(), $"testFile{fileIndex++}.dfy"); @@ -164,4 +160,4 @@ public static string PrintEnumerable(IEnumerable<object> items) { return "[" + string.Join(", ", items.Select(o => o.ToString())) + "]"; } } -} +} \ No newline at end of file diff --git a/Source/DafnyLanguageServer/Workspace/IdeStateObserver.cs b/Source/DafnyLanguageServer/Workspace/IdeStateObserver.cs index e6239d91f53..810a3360d2f 100644 --- a/Source/DafnyLanguageServer/Workspace/IdeStateObserver.cs +++ b/Source/DafnyLanguageServer/Workspace/IdeStateObserver.cs @@ -44,7 +44,7 @@ public void OnCompleted() { public void OnError(Exception exception) { if (exception is OperationCanceledException) { - logger.LogInformation("document processing cancelled."); + logger.LogDebug("document processing cancelled."); return; } diff --git a/Source/DafnyLanguageServer/Workspace/LanguageServerFilesystem.cs b/Source/DafnyLanguageServer/Workspace/LanguageServerFilesystem.cs index 5381677d9c3..366a810f823 100644 --- a/Source/DafnyLanguageServer/Workspace/LanguageServerFilesystem.cs +++ b/Source/DafnyLanguageServer/Workspace/LanguageServerFilesystem.cs @@ -78,7 +78,7 @@ public void UpdateDocument(DidChangeTextDocumentParams documentChange) { public void CloseDocument(TextDocumentIdentifier document) { var uri = document.Uri.ToUri(); - logger.LogInformation($"Closing document {document.Uri}"); + logger.LogDebug($"Closing document {document.Uri}"); if (!openFiles.TryRemove(uri, out _)) { logger.LogError($"Could not close file {uri} because it was not open."); } diff --git a/Source/DafnyLanguageServer/Workspace/VerificationProgressReporter.cs b/Source/DafnyLanguageServer/Workspace/VerificationProgressReporter.cs index 455e29c749c..f565f3a3f92 100644 --- a/Source/DafnyLanguageServer/Workspace/VerificationProgressReporter.cs +++ b/Source/DafnyLanguageServer/Workspace/VerificationProgressReporter.cs @@ -297,9 +297,9 @@ private void NoMethodNodeAtLogging(string methodName, CompilationAfterTranslatio var availableMethodNodes = string.Join(",", compilation.VerificationTree!.Children.Select(vt => $"{vt.Kind} {vt.DisplayName} at {vt.Filename}:{vt.Position.Line}")); logger.LogError( - $"For {methodName}, in document {compilation.Uri} and filename {compilation.VerificationTree.Filename}, " + + $"No method found in {methodName}, in document {compilation.Uri} and filename {compilation.VerificationTree.Filename}, " + $"no method node at {implementation.tok.filename}:{position.Line}:{position.Character}.\n" + - $"Available:" + availableMethodNodes); + $"Available nodes: " + availableMethodNodes); } /// <summary> From df505adb6dbf893e9a546ae7dadda803bb16ba13 Mon Sep 17 00:00:00 2001 From: Remy Willems <rwillems@amazon.com> Date: Fri, 4 Aug 2023 14:49:26 +0200 Subject: [PATCH 04/19] Fix project file override (#4357) ### Changes Allow function-syntax and other options with a custom default to be overridden in `dfyconfig.toml` ### Testing Add a test for the above bug <small>By submitting this pull request, I confirm that my contribution is made under the terms of the [MIT license](https://github.com/dafny-lang/dafny/blob/master/LICENSE.txt).</small> --- Source/DafnyDriver/Commands/CommandRegistry.cs | 2 +- Test/cli/projectFile/projectFile.dfy | 3 +++ Test/cli/projectFile/projectFile.dfy.expect | 2 ++ Test/cli/projectFile/src/input.dfy | 6 +++++- docs/dev/news/4357.fix | 1 + 5 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 docs/dev/news/4357.fix diff --git a/Source/DafnyDriver/Commands/CommandRegistry.cs b/Source/DafnyDriver/Commands/CommandRegistry.cs index 1c8cd3ef8e5..7d428f6fa71 100644 --- a/Source/DafnyDriver/Commands/CommandRegistry.cs +++ b/Source/DafnyDriver/Commands/CommandRegistry.cs @@ -171,7 +171,7 @@ async Task CommandHandler(InvocationContext context) { object value; if (option.Arity.MaximumNumberOfValues <= 1) { // If multiple values aren't allowed, CLI options take precedence over project file options - value = result == null && hasProjectFileValue + value = (result == null || Equals(result.Token, null)) && hasProjectFileValue ? projectFileValue : GetValueForOption(context.ParseResult, option); } else { diff --git a/Test/cli/projectFile/projectFile.dfy b/Test/cli/projectFile/projectFile.dfy index 317f57b480d..d9d6eeb077e 100644 --- a/Test/cli/projectFile/projectFile.dfy +++ b/Test/cli/projectFile/projectFile.dfy @@ -7,6 +7,9 @@ // Test option override behavior // RUN: %baredafny resolve --show-snippets:false --use-basename-for-filename "%S/dfyconfig.toml" --warn-shadowing=false >> "%t" +// Test option with default override behavior +// RUN: ! %baredafny resolve --show-snippets:false --use-basename-for-filename "%S/dfyconfig.toml" --function-syntax=3 >> "%t" + // Multiple project files are not allowed // RUN: ! %baredafny resolve --show-snippets:false --use-basename-for-filename "%S/dfyconfig.toml" "%S/broken/dfyconfig.toml" diff --git a/Test/cli/projectFile/projectFile.dfy.expect b/Test/cli/projectFile/projectFile.dfy.expect index 1712d455ead..82778703cd4 100644 --- a/Test/cli/projectFile/projectFile.dfy.expect +++ b/Test/cli/projectFile/projectFile.dfy.expect @@ -3,6 +3,8 @@ input.dfy(6,8): Warning: Shadowed local-variable name: x Dafny program verifier did not attempt verification Dafny program verifier did not attempt verification +input.dfy(10,0): Error: a function cannot be declared 'ghost' (it is 'ghost' by default when using --function-syntax:3) +1 parse errors detected in input.dfy Warning: only Dafny project files named dfyconfig.toml are recognised by the Dafny IDE. Warning: option 'does-not-exist' that was specified in the project file, is not a valid Dafny option. diff --git a/Test/cli/projectFile/src/input.dfy b/Test/cli/projectFile/src/input.dfy index 3aff32ba633..b490f1a3cd7 100644 --- a/Test/cli/projectFile/src/input.dfy +++ b/Test/cli/projectFile/src/input.dfy @@ -5,4 +5,8 @@ method Foo() { if (true) { var x := 4; } -} \ No newline at end of file +} + +ghost function Bar(): int { + 3 +} \ No newline at end of file diff --git a/docs/dev/news/4357.fix b/docs/dev/news/4357.fix new file mode 100644 index 00000000000..6aea8c19cb9 --- /dev/null +++ b/docs/dev/news/4357.fix @@ -0,0 +1 @@ +Allow function-syntax and other options with a custom default to be overridden in `dfyconfig.toml` \ No newline at end of file From 8498dcee6f283ab55afe358d69e5cb0b3f5f97ae Mon Sep 17 00:00:00 2001 From: Shadaj Laddad <shadaj@users.noreply.github.com> Date: Fri, 4 Aug 2023 11:23:42 -0400 Subject: [PATCH 05/19] Initial support for traits in the Rust backend (#4361) Initial support for traits in the Rust backend Don't support fields yet (we don't even support them in classes), but basic method calls work. <small>By submitting this pull request, I confirm that my contribution is made under the terms of the [MIT license](https://github.com/dafny-lang/dafny/blob/master/LICENSE.txt).</small> --- Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/dafny-lang/dafny/pull/4361). * #4382 * #4369 * #4368 * #4363 * __->__ #4361 --- Source/DafnyCore/Compilers/Dafny/AST.dfy | 14 +- .../DafnyCore/Compilers/Dafny/ASTBuilder.cs | 93 +- .../Compilers/Dafny/Compiler-dafny.cs | 105 +- .../Compilers/Rust/Dafny-compiler-rust.dfy | 254 +- .../DafnyCore/Compilers/SinglePassCompiler.cs | 54 +- Source/DafnyCore/GeneratedFromDafnyRust.cs | 2730 ++++++++++------- docs/DafnyRef/Features.md | 2 +- 7 files changed, 2058 insertions(+), 1194 deletions(-) diff --git a/Source/DafnyCore/Compilers/Dafny/AST.dfy b/Source/DafnyCore/Compilers/Dafny/AST.dfy index d21bf964cb0..7a3577f4f9b 100644 --- a/Source/DafnyCore/Compilers/Dafny/AST.dfy +++ b/Source/DafnyCore/Compilers/Dafny/AST.dfy @@ -1,7 +1,7 @@ module {:extern "DAST"} DAST { datatype Module = Module(name: string, body: seq<ModuleItem>) - datatype ModuleItem = Module(Module) | Class(Class) | Newtype(Newtype) | Datatype(Datatype) + datatype ModuleItem = Module(Module) | Class(Class) | Trait(Trait) | Newtype(Newtype) | Datatype(Datatype) datatype Newtype = Newtype(name: string, base: Type) @@ -9,11 +9,13 @@ module {:extern "DAST"} DAST { datatype Primitive = String | Bool | Char - datatype ResolvedType = Datatype(path: seq<Ident>) | Newtype + datatype ResolvedType = Datatype(path: seq<Ident>) | Trait(path: seq<Ident>) | Newtype datatype Ident = Ident(id: string) - datatype Class = Class(name: string, body: seq<ClassItem>) + datatype Class = Class(name: string, superClasses: seq<Type>, body: seq<ClassItem>) + + datatype Trait = Trait(name: string, typeParams: seq<Type>, body: seq<ClassItem>) datatype Datatype = Datatype(name: string, enclosingModule: Ident, typeParams: seq<Type>, ctors: seq<DatatypeCtor>, body: seq<ClassItem>, isCo: bool) @@ -23,7 +25,7 @@ module {:extern "DAST"} DAST { datatype Formal = Formal(name: string, typ: Type) - datatype Method = Method(isStatic: bool, name: string, typeParams: seq<Type>, params: seq<Formal>, body: seq<Statement>, outTypes: seq<Type>, outVars: Optional<seq<Ident>>) + datatype Method = Method(isStatic: bool, hasBody: bool, overridingPath: Optional<seq<Ident>>, name: string, typeParams: seq<Type>, params: seq<Formal>, body: seq<Statement>, outTypes: seq<Type>, outVars: Optional<seq<Ident>>) datatype Optional<T> = Some(T) | None @@ -35,6 +37,7 @@ module {:extern "DAST"} DAST { Call(on: Expression, name: string, typeArgs: seq<Type>, args: seq<Expression>, outs: Optional<seq<Ident>>) | Return(expr: Expression) | EarlyReturn() | + Halt() | Print(Expression) datatype Expression = @@ -46,6 +49,7 @@ module {:extern "DAST"} DAST { DatatypeValue(path: seq<Ident>, variant: string, isCo: bool, contents: seq<(string, Expression)>) | This() | Ite(cond: Expression, thn: Expression, els: Expression) | + UnOp(unOp: UnaryOp, expr: Expression) | BinOp(op: string, left: Expression, right: Expression) | Select(expr: Expression, field: string, onDatatype: bool) | TupleSelect(expr: Expression, index: nat) | @@ -53,5 +57,7 @@ module {:extern "DAST"} DAST { TypeTest(on: Expression, dType: seq<Ident>, variant: string) | InitializationValue(typ: Type) + datatype UnaryOp = Not | BitwiseNot | Cardinality + datatype Literal = BoolLiteral(bool) | IntLiteral(int) | DecLiteral(string) | StringLiteral(string) } diff --git a/Source/DafnyCore/Compilers/Dafny/ASTBuilder.cs b/Source/DafnyCore/Compilers/Dafny/ASTBuilder.cs index 309207fa531..08ebb2b6ecd 100644 --- a/Source/DafnyCore/Compilers/Dafny/ASTBuilder.cs +++ b/Source/DafnyCore/Compilers/Dafny/ASTBuilder.cs @@ -25,7 +25,7 @@ public ModuleBuilder Module(string name) { } } - class ModuleBuilder : ClassContainer, NewtypeContainer, DatatypeContainer { + class ModuleBuilder : ClassContainer, TraitContainer, NewtypeContainer, DatatypeContainer { readonly ModuleContainer parent; readonly string name; readonly List<ModuleItem> body = new(); @@ -43,6 +43,10 @@ public void AddClass(Class item) { body.Add((ModuleItem)ModuleItem.create_Class(item)); } + public void AddTrait(Trait item) { + body.Add((ModuleItem)ModuleItem.create_Trait(item)); + } + public void AddNewtype(Newtype item) { body.Add((ModuleItem)ModuleItem.create_Newtype(item)); } @@ -60,19 +64,21 @@ public object Finish() { interface ClassContainer { void AddClass(Class item); - public ClassBuilder Class(string name) { - return new ClassBuilder(this, name); + public ClassBuilder Class(string name, List<DAST.Type> superClasses) { + return new ClassBuilder(this, name, superClasses); } } class ClassBuilder : ClassLike { readonly ClassContainer parent; readonly string name; + readonly List<DAST.Type> superClasses; readonly List<ClassItem> body = new(); - public ClassBuilder(ClassContainer parent, string name) { + public ClassBuilder(ClassContainer parent, string name, List<DAST.Type> superClasses) { this.parent = parent; this.name = name; + this.superClasses = superClasses; } public void AddMethod(DAST.Method item) { @@ -84,7 +90,57 @@ public void AddField(DAST.Formal item) { } public object Finish() { - parent.AddClass((Class)Class.create(Sequence<Rune>.UnicodeFromString(this.name), Sequence<ClassItem>.FromArray(body.ToArray()))); + parent.AddClass((Class)Class.create( + Sequence<Rune>.UnicodeFromString(this.name), + Sequence<DAST.Type>.FromArray(this.superClasses.ToArray()), + Sequence<ClassItem>.FromArray(body.ToArray()) + )); + return parent; + } + } + + interface TraitContainer { + void AddTrait(Trait item); + + public TraitBuilder Trait(string name, List<DAST.Type> typeParams) { + return new TraitBuilder(this, name, typeParams); + } + } + + class TraitBuilder : ClassLike { + readonly TraitContainer parent; + readonly string name; + readonly List<DAST.Type> typeParams; + readonly List<ClassItem> body = new(); + + public TraitBuilder(TraitContainer parent, string name, List<DAST.Type> typeParams) { + this.parent = parent; + this.name = name; + this.typeParams = typeParams; + } + + public void AddMethod(DAST.Method item) { + // remove existing method with the same name, because we're going to define an implementation + for (int i = 0; i < body.Count; i++) { + if (body[i].is_Method && body[i].dtor_Method_a0.dtor_name.Equals(item.dtor_name)) { + body.RemoveAt(i); + break; + } + } + + body.Add((ClassItem)ClassItem.create_Method(item)); + } + + public void AddField(DAST.Formal item) { + throw new NotImplementedException(); + } + + public object Finish() { + parent.AddTrait((Trait)Trait.create( + Sequence<Rune>.UnicodeFromString(this.name), + Sequence<DAST.Type>.FromArray(typeParams.ToArray()), + Sequence<ClassItem>.FromArray(body.ToArray())) + ); return parent; } } @@ -174,8 +230,15 @@ interface ClassLike { void AddField(DAST.Formal item); - public MethodBuilder Method(bool isStatic, string name, List<DAST.Type> typeArgs, List<DAST.Formal> params_, List<DAST.Type> outTypes, List<ISequence<Rune>> outVars) { - return new MethodBuilder(this, isStatic, name, typeArgs, params_, outTypes, outVars); + public MethodBuilder Method( + bool isStatic, bool hasBody, + ISequence<ISequence<Rune>> overridingPath, + string name, + List<DAST.Type> typeArgs, + List<DAST.Formal> params_, + List<DAST.Type> outTypes, List<ISequence<Rune>> outVars + ) { + return new MethodBuilder(this, isStatic, hasBody, overridingPath, name, typeArgs, params_, outTypes, outVars); } public object Finish(); @@ -185,15 +248,27 @@ class MethodBuilder : StatementContainer { readonly ClassLike parent; readonly string name; readonly bool isStatic; + readonly bool hasBody; + readonly ISequence<ISequence<Rune>> overridingPath; readonly List<DAST.Type> typeArgs; readonly List<DAST.Formal> params_; readonly List<DAST.Type> outTypes; readonly List<ISequence<Rune>> outVars; readonly List<object> body = new(); - public MethodBuilder(ClassLike parent, bool isStatic, string name, List<DAST.Type> typeArgs, List<DAST.Formal> params_, List<DAST.Type> outTypes, List<ISequence<Rune>> outVars) { + public MethodBuilder( + ClassLike parent, + bool isStatic, bool hasBody, + ISequence<ISequence<Rune>> overridingPath, + string name, + List<DAST.Type> typeArgs, + List<DAST.Formal> params_, + List<DAST.Type> outTypes, List<ISequence<Rune>> outVars + ) { this.parent = parent; this.isStatic = isStatic; + this.hasBody = hasBody; + this.overridingPath = overridingPath; this.name = name; this.typeArgs = typeArgs; this.params_ = params_; @@ -221,6 +296,8 @@ public DAST.Method Build() { return (DAST.Method)DAST.Method.create( isStatic, + hasBody, + overridingPath != null ? Optional<ISequence<ISequence<Rune>>>.create_Some(overridingPath) : Optional<ISequence<ISequence<Rune>>>.create_None(), Sequence<Rune>.UnicodeFromString(this.name), Sequence<DAST.Type>.FromArray(typeArgs.ToArray()), Sequence<DAST.Formal>.FromArray(params_.ToArray()), diff --git a/Source/DafnyCore/Compilers/Dafny/Compiler-dafny.cs b/Source/DafnyCore/Compilers/Dafny/Compiler-dafny.cs index 5cb2e6791ce..00a11ecb354 100644 --- a/Source/DafnyCore/Compilers/Dafny/Compiler-dafny.cs +++ b/Source/DafnyCore/Compilers/Dafny/Compiler-dafny.cs @@ -69,7 +69,6 @@ public DafnyCompiler(DafnyOptions options, ErrorReporter reporter) : base(option Feature.RuntimeTypeDescriptors, Feature.MultiDimensionalArrays, Feature.MapComprehensions, - Feature.Traits, Feature.LetSuchThatExpressions, Feature.NonNativeNewtypes, Feature.MethodSynthesis, @@ -143,7 +142,7 @@ private static string MangleName(string name) { protected override IClassWriter CreateClass(string moduleName, string name, bool isExtern, string fullPrintName, List<TypeParameter> typeParameters, TopLevelDecl cls, List<Type> superClasses, IToken tok, ConcreteSyntaxTree wr) { if (currentBuilder is ClassContainer builder) { - return new ClassWriter(this, builder.Class(name)); + return new ClassWriter(this, builder.Class(name, superClasses.Select(t => GenType(t)).ToList())); } else { throw new InvalidOperationException(); } @@ -151,7 +150,16 @@ protected override IClassWriter CreateClass(string moduleName, string name, bool protected override IClassWriter CreateTrait(string name, bool isExtern, List<TypeParameter> typeParameters, TraitDecl trait, List<Type> superClasses, IToken tok, ConcreteSyntaxTree wr) { - throw new UnsupportedFeatureException(Token.NoToken, Feature.Traits); + if (currentBuilder is TraitContainer builder) { + List<DAST.Type> typeParams = new(); + foreach (var tp in trait.TypeArgs) { + typeParams.Add((DAST.Type)DAST.Type.create_TypeArg(Sequence<Rune>.UnicodeFromString(IdProtect(tp.GetCompileName(Options))))); + } + + return new ClassWriter(this, builder.Trait(name, typeParams)); + } else { + throw new InvalidOperationException(); + } } protected override ConcreteSyntaxTree CreateIterator(IteratorDecl iter, ConcreteSyntaxTree wr) { @@ -279,9 +287,22 @@ public ConcreteSyntaxTree CreateMethod(Method m, List<TypeArgumentInstantiation> } } - var builder = this.builder.Method(m.IsStatic, m.GetCompileName(compiler.Options), astTypeArgs, params_, outTypes, outVars); + var overridingTrait = m.OverriddenMethod?.EnclosingClass; + var builder = this.builder.Method( + m.IsStatic, createBody, + overridingTrait != null ? compiler.PathFromTopLevel(overridingTrait) : null, + m.GetCompileName(compiler.Options), + astTypeArgs, params_, + outTypes, outVars + ); methods.Add(builder); - return new BuilderSyntaxTree<StatementContainer>(builder); + + if (createBody) { + return new BuilderSyntaxTree<StatementContainer>(builder); + } else { + // TODO(shadaj): actually create a trait + return null; + } } public ConcreteSyntaxTree SynthesizeMethod(Method m, List<TypeArgumentInstantiation> typeArgs, bool createBody, bool forBodyInheritance, bool lookasideBody) { @@ -303,11 +324,24 @@ public ConcreteSyntaxTree CreateFunction(string name, List<TypeArgumentInstantia } } - var builder = this.builder.Method(isStatic, name, astTypeArgs, params_, new() { - compiler.GenType(resultType) - }, null); + var overridingTrait = member.OverriddenMember?.EnclosingClass; + + var builder = this.builder.Method( + isStatic, createBody, + overridingTrait != null ? compiler.PathFromTopLevel(overridingTrait) : null, + name, + astTypeArgs, params_, + new() { + compiler.GenType(resultType) + }, null + ); methods.Add(builder); - return new BuilderSyntaxTree<StatementContainer>(builder); + + if (createBody) { + return new BuilderSyntaxTree<StatementContainer>(builder); + } else { + return null; + } } public ConcreteSyntaxTree CreateGetter(string name, TopLevelDecl enclosingDecl, Type resultType, IToken tok, @@ -542,6 +576,19 @@ protected override void TrCallStmt(CallStmt s, string receiverReplacement, Concr } } + protected override void EmitCallToInheritedMethod(Method method, [CanBeNull] TopLevelDeclWithMembers heir, ConcreteSyntaxTree wr, ConcreteSyntaxTree wStmts, ConcreteSyntaxTree wStmtsAfterCall) { + if (wr is BuilderSyntaxTree<StatementContainer> stmtContainer) { + var callBuilder = stmtContainer.Builder.Call(); + base.EmitCallToInheritedMethod(method, heir, new BuilderSyntaxTree<ExprContainer>(callBuilder), wStmts, wStmtsAfterCall); + } else { + throw new InvalidOperationException("Cannot call statement in this context: " + currentBuilder); + } + } + + protected override void EmitMultiReturnTuple(List<Formal> outs, List<Type> outTypes, List<string> outTmps, IToken methodToken, ConcreteSyntaxTree wr) { + // nothing to do, we auto-emit a return for the method + } + protected override void CompileFunctionCallExpr(FunctionCallExpr e, ConcreteSyntaxTree wr, bool inLetExprBody, ConcreteSyntaxTree wStmts, FCE_Arg_Translator tr) { if (wr is BuilderSyntaxTree<ExprContainer> builder) { @@ -653,7 +700,11 @@ protected override void EmitAbsurd(string message, ConcreteSyntaxTree wr) { } protected override void EmitHalt(IToken tok, Expression messageExpr, ConcreteSyntaxTree wr) { - throw new NotImplementedException(); + if (wr is BuilderSyntaxTree<StatementContainer> container) { + container.Builder.AddStatement((DAST.Statement)DAST.Statement.create_Halt()); + } else { + throw new InvalidOperationException(); + } } private readonly Stack<ElseBuilder> elseBuilderStack = new(); @@ -885,8 +936,7 @@ private DAST.Type TypeNameASTFromTopLevel(TopLevelDecl topLevel, List<Type> type if (topLevel is NewtypeDecl) { resolvedType = (DAST.ResolvedType)DAST.ResolvedType.create_Newtype(); } else if (topLevel is TraitDecl) { - // TODO(shadaj): have a separate type when we properly support traits - resolvedType = (DAST.ResolvedType)DAST.ResolvedType.create_Newtype(); + resolvedType = (DAST.ResolvedType)DAST.ResolvedType.create_Trait(path); } else if (topLevel is DatatypeDecl) { resolvedType = (DAST.ResolvedType)DAST.ResolvedType.create_Datatype(path); } else if (topLevel is ClassDecl) { @@ -1148,7 +1198,36 @@ protected override ConcreteSyntaxTree CreateIIFE1(int source, Type resultType, I protected override void EmitUnaryExpr(ResolvedUnaryOp op, Expression expr, bool inLetExprBody, ConcreteSyntaxTree wr, ConcreteSyntaxTree wStmts) { - throw new NotImplementedException("Unary expression: " + op); + if (wr is BuilderSyntaxTree<ExprContainer> container) { + var buf = new ExprBuffer(null); + EmitExpr(expr, inLetExprBody, new BuilderSyntaxTree<ExprContainer>(buf), null); + + switch (op) { + case ResolvedUnaryOp.BoolNot: { + container.Builder.AddExpr((DAST.Expression)DAST.Expression.create_UnOp( + UnaryOp.create_Not(), + buf.Finish() + )); + break; + } + case ResolvedUnaryOp.BitwiseNot: { + container.Builder.AddExpr((DAST.Expression)DAST.Expression.create_UnOp( + UnaryOp.create_BitwiseNot(), + buf.Finish() + )); + break; + } + case ResolvedUnaryOp.Cardinality: { + container.Builder.AddExpr((DAST.Expression)DAST.Expression.create_UnOp( + UnaryOp.create_Cardinality(), + buf.Finish() + )); + break; + } + } + } else { + throw new InvalidOperationException(); + } } protected override void CompileBinOp(BinaryExpr.ResolvedOpcode op, diff --git a/Source/DafnyCore/Compilers/Rust/Dafny-compiler-rust.dfy b/Source/DafnyCore/Compilers/Rust/Dafny-compiler-rust.dfy index 2ec6014d8f7..b1cf6a7f5f5 100644 --- a/Source/DafnyCore/Compilers/Rust/Dafny-compiler-rust.dfy +++ b/Source/DafnyCore/Compilers/Rust/Dafny-compiler-rust.dfy @@ -17,19 +17,20 @@ module {:extern "DCOMP"} DCOMP { } class COMP { - static method GenModule(mod: Module) returns (s: string) { - var body := GenModuleBody(mod.body); + static method GenModule(mod: Module, containingPath: seq<Ident>) returns (s: string) { + var body := GenModuleBody(mod.body, containingPath + [Ident.Ident(mod.name)]); s := "mod r#" + mod.name + " {\n" + body + "\n}"; } - static method GenModuleBody(body: seq<ModuleItem>) returns (s: string) { + static method GenModuleBody(body: seq<ModuleItem>, containingPath: seq<Ident>) returns (s: string) { s := ""; var i := 0; while i < |body| { var generated: string; match body[i] { - case Module(m) => generated := GenModule(m); - case Class(c) => generated := GenClass(c); + case Module(m) => generated := GenModule(m, containingPath); + case Class(c) => generated := GenClass(c, containingPath + [Ident.Ident(c.name)]); + case Trait(t) => generated := GenTrait(t, containingPath); case Newtype(n) => generated := GenNewtype(n); case Datatype(d) => generated := GenDatatype(d); } @@ -43,15 +44,56 @@ module {:extern "DCOMP"} DCOMP { } } - static method GenClass(c: Class) returns (s: string) { - var selfPath := [Ident.Ident(c.name)]; - var implBody := GenClassImplBody(c.body, Type.Path([], [], ResolvedType.Datatype(selfPath)), {}); + static method GenClass(c: Class, path: seq<Ident>) returns (s: string) { + var implBody, traitBodies := GenClassImplBody(c.body, false, Type.Path(path, [], ResolvedType.Datatype(path)), {}); implBody := "pub fn new() -> Self {\n" + "r#" + c.name + " {\n" + "" + "\n}\n}\n" + implBody; s := "pub struct r#" + c.name + " {\n" + "" + "\n}" + "\n" + "impl r#" + c.name + " {\n" + implBody + "\n}"; + if (|c.superClasses| > 0) { + var i := 0; + while i < |c.superClasses| { + var superClass := c.superClasses[i]; + match superClass { + case Path(traitPath, typeArgs, Trait(_)) => { + var pathStr := GenPath(traitPath); + var typeArgs := GenTypeArgs(typeArgs, false); + var body := ""; + if traitPath in traitBodies { + body := traitBodies[traitPath]; + } + + var genSelfPath := GenPath(path); + s := s + "\nimpl " + pathStr + typeArgs + " for ::std::rc::Rc<" + genSelfPath + "> {\n" + body + "\n}"; + } + case _ => {} + } + i := i + 1; + } + } + } + + static method GenTrait(t: Trait, containingPath: seq<Ident>) returns (s: string) { + var typeParamsSet := {}; + var typeParams := ""; + var tpI := 0; + if |t.typeParams| > 0 { + typeParams := "<"; + while tpI < |t.typeParams| { + var tp := t.typeParams[tpI]; + typeParamsSet := typeParamsSet + {tp}; + var genTp := GenType(tp, false); + typeParams := typeParams + "r#" + genTp + ", "; + tpI := tpI + 1; + } + typeParams := typeParams + ">"; + } + + var fullPath := containingPath + [Ident.Ident(t.name)]; + var implBody, _ := GenClassImplBody(t.body, true, Type.Path(fullPath, [], ResolvedType.Trait(fullPath)), typeParamsSet); + s := "pub trait r#" + t.name + typeParams + " {\n" + implBody + "\n}"; } static method GenNewtype(c: Newtype) returns (s: string) { - var underlyingType := GenType(c.base); + var underlyingType := GenType(c.base, false); s := "pub type r#" + c.name + " =" + underlyingType + ";\n"; } @@ -64,7 +106,7 @@ module {:extern "DCOMP"} DCOMP { while tpI < |c.typeParams| { var tp := c.typeParams[tpI]; typeParamsSet := typeParamsSet + {tp}; - var genTp := GenType(tp); + var genTp := GenType(tp, false); typeParams := typeParams + "r#" + genTp + ", "; tpI := tpI + 1; } @@ -79,7 +121,7 @@ module {:extern "DCOMP"} DCOMP { var j := 0; while j < |ctor.args| { var formal := ctor.args[j]; - var formalType := GenType(formal.typ); + var formalType := GenType(formal.typ, false); if c.isCo { ctorBody := ctorBody + "r#" + formal.name + ": ::dafny_runtime::LazyFieldWrapper<" + formalType + ">, "; } else { @@ -95,7 +137,7 @@ module {:extern "DCOMP"} DCOMP { } var selfPath := [Ident.Ident(c.name)]; - var implBody := GenClassImplBody(c.body, Type.Path([], [], ResolvedType.Datatype(selfPath)), typeParamsSet); + var implBody, traitBodies := GenClassImplBody(c.body, false, Type.Path([], [], ResolvedType.Datatype(selfPath)), typeParamsSet); i := 0; var emittedFields: set<string> := {}; while i < |c.ctors| { @@ -109,7 +151,7 @@ module {:extern "DCOMP"} DCOMP { if !(formal.name in emittedFields) { emittedFields := emittedFields + {formal.name}; - var formalType := GenType(formal.typ); + var formalType := GenType(formal.typ, false); var methodBody := "match self {\n"; var k := 0; while k < |c.ctors| { @@ -159,7 +201,7 @@ module {:extern "DCOMP"} DCOMP { } var tp := c.typeParams[tpI]; - var genTp := GenType(tp); + var genTp := GenType(tp, false); constrainedTypeParams := constrainedTypeParams + "r#" + genTp + ": Clone + ::std::cmp::PartialEq + ::dafny_runtime::DafnyPrint + ::std::default::Default + 'static"; tpI := tpI + 1; } @@ -239,30 +281,44 @@ module {:extern "DCOMP"} DCOMP { } } - static method GenType(c: Type) returns (s: string) { + static method GenTypeArgs(args: seq<Type>, inBinding: bool) returns (s: string) { + s := ""; + if |args| > 0 { + s := s + "<"; + var i := 0; + while i < |args| { + if i > 0 { + s := s + ", "; + } + + var genTp := GenType(args[i], inBinding); + s := s + genTp; + i := i + 1; + } + s := s + ">"; + } + } + + static method GenType(c: Type, inBinding: bool) returns (s: string) { match c { case Path(p, args, resolved) => { s := GenPath(p); - if |args| > 0 { - s := s + "<"; - var i := 0; - while i < |args| { - if i > 0 { - s := s + ", "; - } - - var genTp := GenType(args[i]); - s := s + genTp; - i := i + 1; - } - s := s + ">"; - } + var typeArgs := GenTypeArgs(args, inBinding); + s := s + typeArgs; match resolved { case Datatype(_) => { s := "::std::rc::Rc<" + s + ">"; } + case Trait(_) => { + if inBinding { + // impl trait in bindings is not stable + s := "_"; + } else { + s := "impl " + s + ""; + } + } case Primitive => {} } } @@ -274,7 +330,7 @@ module {:extern "DCOMP"} DCOMP { s := s + " "; } - var generated := GenType(types[i]); + var generated := GenType(types[i], inBinding); s := s + generated + ","; i := i + 1; } @@ -293,21 +349,43 @@ module {:extern "DCOMP"} DCOMP { } } - static method GenClassImplBody(body: seq<ClassItem>, enclosingType: Type, enclosingTypeParams: set<Type>) returns (s: string) { + static method GenClassImplBody(body: seq<ClassItem>, forTrait: bool, enclosingType: Type, enclosingTypeParams: set<Type>) returns (s: string, traitBodies: map<seq<Ident>, string>) { s := ""; + traitBodies := map[]; + var i := 0; while i < |body| { - var generated: string; match body[i] { - case Method(m) => generated := GenMethod(m, enclosingType, enclosingTypeParams); - case Field(f) => generated := "TODO"; + case Method(m) => { + match m.overridingPath { + case Some(p) => { + var existing := ""; + if p in traitBodies { + existing := traitBodies[p]; + } + + if |existing| > 0 { + existing := existing + "\n"; + } + + var genMethod := GenMethod(m, true, enclosingType, enclosingTypeParams); + existing := existing + genMethod; + + traitBodies := traitBodies + map[p := existing]; + } + case None => { + var generated := GenMethod(m, forTrait, enclosingType, enclosingTypeParams); + s := s + generated; + } + } + } + case Field(f) => { /* TODO */ } } - if i > 0 { + if |s| > 0 { s := s + "\n"; } - s := s + generated; i := i + 1; } } @@ -317,7 +395,7 @@ module {:extern "DCOMP"} DCOMP { var i := 0; while i < |params| { var param := params[i]; - var paramType := GenType(param.typ); + var paramType := GenType(param.typ, false); s := s + "r#" + param.name + ": &" + paramType; if i < |params| - 1 { @@ -328,7 +406,7 @@ module {:extern "DCOMP"} DCOMP { } } - static method GenMethod(m: Method, enclosingType: Type, enclosingTypeParams: set<Type>) returns (s: string) { + static method GenMethod(m: Method, forTrait: bool, enclosingType: Type, enclosingTypeParams: set<Type>) returns (s: string) { var params := GenParams(m.params); var paramNames := []; var paramI := 0; @@ -338,8 +416,12 @@ module {:extern "DCOMP"} DCOMP { } if (!m.isStatic) { - var enclosingTypeString := GenType(enclosingType); - params := "self: &" + enclosingTypeString + ", " + params; + if (forTrait) { + params := "&self" + ", " + params; + } else { + var enclosingTypeString := GenType(enclosingType, false); + params := "self: &" + enclosingTypeString + ", " + params; + } } var retType := if |m.outTypes| != 1 then "(" else ""; @@ -350,7 +432,7 @@ module {:extern "DCOMP"} DCOMP { retType := retType + ", "; } - var typeString := GenType(m.outTypes[typeI]); + var typeString := GenType(m.outTypes[typeI], false); retType := retType + typeString; typeI := typeI + 1; @@ -360,7 +442,11 @@ module {:extern "DCOMP"} DCOMP { retType := retType + ")"; } - s := "pub fn r#" + m.name; + if forTrait { + s := "fn r#" + m.name; + } else { + s := "pub fn r#" + m.name; + } var typeParamsFiltered := []; var typeParamI := 0; @@ -382,7 +468,7 @@ module {:extern "DCOMP"} DCOMP { s := s + ", "; } - var typeString := GenType(typeParamsFiltered[i]); + var typeString := GenType(typeParamsFiltered[i], false); s := s + typeString + ": Clone + ::std::cmp::PartialEq + ::dafny_runtime::DafnyPrint + ::std::default::Default + 'static"; i := i + 1; @@ -391,35 +477,41 @@ module {:extern "DCOMP"} DCOMP { s := s + ">"; } - var earlyReturn := "return;"; - match m.outVars { - case Some(outVars) => { - earlyReturn := "return ("; - var outI := 0; - while outI < |outVars| { - if outI > 0 { - earlyReturn := earlyReturn + ", "; - } + s := s + "(" + params + ") -> " + retType; + + if m.hasBody { + var earlyReturn := "return;"; + match m.outVars { + case Some(outVars) => { + earlyReturn := "return ("; + var outI := 0; + while outI < |outVars| { + if outI > 0 { + earlyReturn := earlyReturn + ", "; + } - var outVar := outVars[outI]; - earlyReturn := earlyReturn + "r#" + outVar.id; + var outVar := outVars[outI]; + earlyReturn := earlyReturn + "r#" + outVar.id; - outI := outI + 1; + outI := outI + 1; + } + earlyReturn := earlyReturn + ");"; } - earlyReturn := earlyReturn + ");"; + case None => {} } - case None => {} - } - var body := GenStmts(m.body, paramNames, earlyReturn); - match m.outVars { - case Some(outVars) => { - body := body + "\n" + earlyReturn; + var body := GenStmts(m.body, paramNames, earlyReturn); + match m.outVars { + case Some(outVars) => { + body := body + "\n" + earlyReturn; + } + case None => {} } - case None => {} - } - s := s + "(" + params + ") -> " + retType + " {\n" + body + "\n}\n"; + s := s + " {\n" + body + "\n}\n"; + } else { + s := s + ";\n"; + } } static method GenStmts(stmts: seq<Statement>, params: seq<string>, earlyReturn: string) returns (generated: string) { @@ -442,11 +534,11 @@ module {:extern "DCOMP"} DCOMP { match stmt { case DeclareVar(name, typ, Some(expression)) => { var expr, _, _ := GenExpr(expression, params, true); - var typeString := GenType(typ); + var typeString := GenType(typ, true); generated := "let mut r#" + name + ": " + typeString + " = " + expr + ";"; } case DeclareVar(name, typ, None) => { - var typeString := GenType(typ); + var typeString := GenType(typ, true); generated := "let mut r#" + name + ": " + typeString + ";"; } case Assign(name, expression) => { @@ -474,7 +566,7 @@ module {:extern "DCOMP"} DCOMP { typeArgString := typeArgString + ", "; } - var typeString := GenType(typeArgs[typeI]); + var typeString := GenType(typeArgs[typeI], false); typeArgString := typeArgString + typeString; typeI := typeI + 1; @@ -540,6 +632,9 @@ module {:extern "DCOMP"} DCOMP { case EarlyReturn() => { generated := earlyReturn; } + case Halt() => { + generated := "panic!(\"Halt\");"; + } case Print(e) => { var printedExpr, isOwned, _ := GenExpr(e, params, false); generated := "print!(\"{}\", ::dafny_runtime::DafnyPrintWrapper(" + (if isOwned then "&" else "") + printedExpr + "));"; @@ -665,7 +760,6 @@ module {:extern "DCOMP"} DCOMP { if isCo { var recursiveGen, _, recIdents := GenExpr(value, [], true); readIdents := readIdents + recIdents; - var allReadCloned := ""; while recIdents != {} decreases recIdents { var next: string :| next in recIdents; @@ -703,6 +797,24 @@ module {:extern "DCOMP"} DCOMP { isOwned := fOwned; readIdents := recIdentsCond + recIdentsT + recIdentsF; } + case UnOp(Not, e) => { + var recursiveGen, _, recIdents := GenExpr(e, params, true); + s := "!(" + recursiveGen + ")"; + isOwned := true; + readIdents := recIdents; + } + case UnOp(BitwiseNot, e) => { + var recursiveGen, _, recIdents := GenExpr(e, params, true); + s := "~(" + recursiveGen + ")"; + isOwned := true; + readIdents := recIdents; + } + case UnOp(Cardinality, e) => { + var recursiveGen, _, recIdents := GenExpr(e, params, false); + s := "(" + recursiveGen + ").len()"; + isOwned := true; + readIdents := recIdents; + } case BinOp(op, l, r) => { var left, _, recIdentsL := GenExpr(l, params, true); var right, _, recIdentsR := GenExpr(r, params, true); @@ -757,7 +869,7 @@ module {:extern "DCOMP"} DCOMP { typeArgString := typeArgString + ", "; } - var typeString := GenType(typeArgs[typeI]); + var typeString := GenType(typeArgs[typeI], false); typeArgString := typeArgString + typeString; typeI := typeI + 1; @@ -810,7 +922,7 @@ module {:extern "DCOMP"} DCOMP { var i := 0; while i < |p| { var generated: string; - generated := GenModule(p[i]); + generated := GenModule(p[i], []); if i > 0 { s := s + "\n"; diff --git a/Source/DafnyCore/Compilers/SinglePassCompiler.cs b/Source/DafnyCore/Compilers/SinglePassCompiler.cs index 5a6f661d521..d6e874309b1 100644 --- a/Source/DafnyCore/Compilers/SinglePassCompiler.cs +++ b/Source/DafnyCore/Compilers/SinglePassCompiler.cs @@ -1469,7 +1469,7 @@ public void Compile(Program program, ConcreteSyntaxTree wrx) { // writing the trait var w = CreateTrait(trait.GetCompileName(Options), trait.IsExtern(Options, out _, out _), trait.TypeArgs, trait, trait.ParentTypeInformation.UniqueParentTraits(), trait.tok, wr); CompileClassMembers(program, trait, w); - + w.Finish(); } else if (d is DefaultClassDecl defaultClassDecl) { Contract.Assert(defaultClassDecl.InheritedMembers.Count == 0); Predicate<MemberDecl> compilationMaterial = x => @@ -1972,7 +1972,10 @@ void CompileClassMembers(Program program, TopLevelDeclWithMembers c, IClassWrite if (!Attributes.Contains(method.Attributes, "extern")) { Contract.Assert(method.Body != null); var w = classWriter.CreateMethod(method, CombineAllTypeArguments(member), true, true, false); - EmitCallToInheritedMethod(method, null, w); + var wBefore = w.Fork(); + var wCall = w.Fork(); + var wAfter = w; + EmitCallToInheritedMethod(method, null, wCall, wBefore, wAfter); } } else { Contract.Assert(false); // unexpected member @@ -2137,7 +2140,10 @@ void CompileClassMembers(Program program, TopLevelDeclWithMembers c, IClassWrite } else if (c is NewtypeDecl && m != m.Original) { CompileMethod(program, m, classWriter, false); var w = classWriter.CreateMethod(m, CombineAllTypeArguments(member), true, true, false); - EmitCallToInheritedMethod(m, c, w); + var wBefore = w.Fork(); + var wCall = w.Fork(); + var wAfter = w; + EmitCallToInheritedMethod(m, c, wCall, wBefore, wAfter); } else { CompileMethod(program, m, classWriter, false); } @@ -2270,11 +2276,26 @@ protected virtual void EmitCallReturnOuts(List<string> outTmps, ConcreteSyntaxTr wr.Write("{0} = ", Util.Comma(outTmps)); } + protected virtual void EmitMultiReturnTuple(List<Formal> outs, List<Type> outTypes, List<string> outTmps, IToken methodToken, ConcreteSyntaxTree wr) { + var wrReturn = EmitReturnExpr(wr); + var sep = ""; + for (int j = 0, l = 0; j < outs.Count; j++) { + var p = outs[j]; + if (!p.IsGhost) { + wrReturn.Write(sep); + var w = EmitCoercionIfNecessary(outs[j].Type, outTypes[l], methodToken, wrReturn); + w.Write(outTmps[l]); + sep = ", "; + l++; + } + } + } + /// <summary> /// "heir" is the type declaration that inherits the method. Or, it can be "null" to indicate that the method is declared in /// the type itself, in which case the "call to inherited" is actually a call from the dynamically dispatched method to its implementation. /// </summary> - protected void EmitCallToInheritedMethod(Method method, [CanBeNull] TopLevelDeclWithMembers heir, ConcreteSyntaxTree wr) { + protected virtual void EmitCallToInheritedMethod(Method method, [CanBeNull] TopLevelDeclWithMembers heir, ConcreteSyntaxTree wr, ConcreteSyntaxTree wStmts, ConcreteSyntaxTree wStmtsAfterCall) { Contract.Requires(method != null); Contract.Requires(!method.IsStatic); Contract.Requires(method.EnclosingClass is TraitDecl); @@ -2296,7 +2317,7 @@ protected void EmitCallToInheritedMethod(Method method, [CanBeNull] TopLevelDecl var target = returnStyleOutCollector != null ? IdName(p) : ProtectedFreshId("_out"); outTmps.Add(target); outTypes.Add(p.Type); - DeclareLocalVar(target, p.Type, p.tok, false, null, wr); + DeclareLocalVar(target, p.Type, p.tok, false, null, wStmts); } } Contract.Assert(outTmps.Count == nonGhostOutParameterCount && outTypes.Count == nonGhostOutParameterCount); @@ -2309,7 +2330,7 @@ protected void EmitCallToInheritedMethod(Method method, [CanBeNull] TopLevelDecl var companionName = CompanionMemberIdName(method); var calleeReceiverType = UserDefinedType.FromTopLevelDecl(method.tok, method.EnclosingClass).Subst(thisContext.ParentFormalTypeParametersToActuals); - wr.Write(TypeName_Companion(calleeReceiverType, wr, method.tok, method)); + EmitTypeName_Companion(calleeReceiverType, wr, wr, method.tok, method); wr.Write(ClassAccessor); var typeArgs = CombineAllTypeArguments(method, thisContext); @@ -2328,7 +2349,7 @@ protected void EmitCallToInheritedMethod(Method method, [CanBeNull] TopLevelDecl if (!p.IsGhost) { wr.Write(sep); w = EmitCoercionIfNecessary(method.Original.Ins[j].Type, method.Ins[j].Type, method.tok, wr); - w.Write(IdName(p)); + EmitIdentifier(IdName(p), w); sep = ", "; l++; } @@ -2345,29 +2366,18 @@ protected void EmitCallToInheritedMethod(Method method, [CanBeNull] TopLevelDecl EndStmt(wr); if (returnStyleOutCollector != null) { - EmitCastOutParameterSplits(returnStyleOutCollector, outTmps, wr, outTypes, outTypes, method.tok); - EmitReturn(method.Outs, wr); + EmitCastOutParameterSplits(returnStyleOutCollector, outTmps, wStmtsAfterCall, outTypes, outTypes, method.tok); + EmitReturn(method.Outs, wStmtsAfterCall); } else if (!returnStyleOuts) { for (int j = 0, l = 0; j < method.Outs.Count; j++) { var p = method.Outs[j]; if (!p.IsGhost) { - EmitAssignment(IdName(p), method.Outs[j].Type, outTmps[l], outTypes[l], wr); + EmitAssignment(IdName(p), method.Outs[j].Type, outTmps[l], outTypes[l], wStmtsAfterCall); l++; } } } else { - var wrReturn = EmitReturnExpr(wr); - sep = ""; - for (int j = 0, l = 0; j < method.Outs.Count; j++) { - var p = method.Outs[j]; - if (!p.IsGhost) { - wrReturn.Write(sep); - w = EmitCoercionIfNecessary(method.Outs[j].Type, outTypes[l], method.tok, wrReturn); - w.Write(outTmps[l]); - sep = ", "; - l++; - } - } + EmitMultiReturnTuple(method.Outs, outTypes, outTmps, method.tok, wStmtsAfterCall); } } diff --git a/Source/DafnyCore/GeneratedFromDafnyRust.cs b/Source/DafnyCore/GeneratedFromDafnyRust.cs index 41b1eff6627..8769d8ef841 100644 --- a/Source/DafnyCore/GeneratedFromDafnyRust.cs +++ b/Source/DafnyCore/GeneratedFromDafnyRust.cs @@ -78,10 +78,12 @@ public Dafny.ISequence<DAST._IModuleItem> dtor_body { public interface _IModuleItem { bool is_Module { get; } bool is_Class { get; } + bool is_Trait { get; } bool is_Newtype { get; } bool is_Datatype { get; } DAST._IModule dtor_Module_a0 { get; } DAST._IClass dtor_Class_a0 { get; } + DAST._ITrait dtor_Trait_a0 { get; } DAST._INewtype dtor_Newtype_a0 { get; } DAST._IDatatype dtor_Datatype_a0 { get; } _IModuleItem DowncastClone(); @@ -103,6 +105,9 @@ public static _IModuleItem create_Module(DAST._IModule _a0) { public static _IModuleItem create_Class(DAST._IClass _a0) { return new ModuleItem_Class(_a0); } + public static _IModuleItem create_Trait(DAST._ITrait _a0) { + return new ModuleItem_Trait(_a0); + } public static _IModuleItem create_Newtype(DAST._INewtype _a0) { return new ModuleItem_Newtype(_a0); } @@ -111,6 +116,7 @@ public static _IModuleItem create_Datatype(DAST._IDatatype _a0) { } public bool is_Module { get { return this is ModuleItem_Module; } } public bool is_Class { get { return this is ModuleItem_Class; } } + public bool is_Trait { get { return this is ModuleItem_Trait; } } public bool is_Newtype { get { return this is ModuleItem_Newtype; } } public bool is_Datatype { get { return this is ModuleItem_Datatype; } } public DAST._IModule dtor_Module_a0 { @@ -125,6 +131,12 @@ public DAST._IClass dtor_Class_a0 { return ((ModuleItem_Class)d)._a0; } } + public DAST._ITrait dtor_Trait_a0 { + get { + var d = this; + return ((ModuleItem_Trait)d)._a0; + } + } public DAST._INewtype dtor_Newtype_a0 { get { var d = this; @@ -193,6 +205,33 @@ public override string ToString() { return s; } } + public class ModuleItem_Trait : ModuleItem { + public readonly DAST._ITrait _a0; + public ModuleItem_Trait(DAST._ITrait _a0) : base() { + this._a0 = _a0; + } + public override _IModuleItem DowncastClone() { + if (this is _IModuleItem dt) { return dt; } + return new ModuleItem_Trait(_a0); + } + public override bool Equals(object other) { + var oth = other as DAST.ModuleItem_Trait; + return oth != null && object.Equals(this._a0, oth._a0); + } + public override int GetHashCode() { + ulong hash = 5381; + hash = ((hash << 5) + hash) + 2; + hash = ((hash << 5) + hash) + ((ulong)Dafny.Helpers.GetHashCode(this._a0)); + return (int)hash; + } + public override string ToString() { + string s = "DAST.ModuleItem.Trait"; + s += "("; + s += Dafny.Helpers.ToString(this._a0); + s += ")"; + return s; + } + } public class ModuleItem_Newtype : ModuleItem { public readonly DAST._INewtype _a0; public ModuleItem_Newtype(DAST._INewtype _a0) : base() { @@ -208,7 +247,7 @@ public override bool Equals(object other) { } public override int GetHashCode() { ulong hash = 5381; - hash = ((hash << 5) + hash) + 2; + hash = ((hash << 5) + hash) + 3; hash = ((hash << 5) + hash) + ((ulong)Dafny.Helpers.GetHashCode(this._a0)); return (int)hash; } @@ -235,7 +274,7 @@ public override bool Equals(object other) { } public override int GetHashCode() { ulong hash = 5381; - hash = ((hash << 5) + hash) + 3; + hash = ((hash << 5) + hash) + 4; hash = ((hash << 5) + hash) + ((ulong)Dafny.Helpers.GetHashCode(this._a0)); return (int)hash; } @@ -652,6 +691,7 @@ public override string ToString() { public interface _IResolvedType { bool is_Datatype { get; } + bool is_Trait { get; } bool is_Newtype { get; } Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> dtor_path { get; } _IResolvedType DowncastClone(); @@ -670,15 +710,20 @@ public static DAST._IResolvedType Default() { public static _IResolvedType create_Datatype(Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> path) { return new ResolvedType_Datatype(path); } + public static _IResolvedType create_Trait(Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> path) { + return new ResolvedType_Trait(path); + } public static _IResolvedType create_Newtype() { return new ResolvedType_Newtype(); } public bool is_Datatype { get { return this is ResolvedType_Datatype; } } + public bool is_Trait { get { return this is ResolvedType_Trait; } } public bool is_Newtype { get { return this is ResolvedType_Newtype; } } public Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> dtor_path { get { var d = this; - return ((ResolvedType_Datatype)d)._path; + if (d is ResolvedType_Datatype) { return ((ResolvedType_Datatype)d)._path; } + return ((ResolvedType_Trait)d)._path; } } public abstract _IResolvedType DowncastClone(); @@ -710,6 +755,33 @@ public override string ToString() { return s; } } + public class ResolvedType_Trait : ResolvedType { + public readonly Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _path; + public ResolvedType_Trait(Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> path) : base() { + this._path = path; + } + public override _IResolvedType DowncastClone() { + if (this is _IResolvedType dt) { return dt; } + return new ResolvedType_Trait(_path); + } + public override bool Equals(object other) { + var oth = other as DAST.ResolvedType_Trait; + return oth != null && object.Equals(this._path, oth._path); + } + public override int GetHashCode() { + ulong hash = 5381; + hash = ((hash << 5) + hash) + 1; + hash = ((hash << 5) + hash) + ((ulong)Dafny.Helpers.GetHashCode(this._path)); + return (int)hash; + } + public override string ToString() { + string s = "DAST.ResolvedType.Trait"; + s += "("; + s += Dafny.Helpers.ToString(this._path); + s += ")"; + return s; + } + } public class ResolvedType_Newtype : ResolvedType { public ResolvedType_Newtype() : base() { } @@ -723,7 +795,7 @@ public override bool Equals(object other) { } public override int GetHashCode() { ulong hash = 5381; - hash = ((hash << 5) + hash) + 1; + hash = ((hash << 5) + hash) + 2; return (int)hash; } public override string ToString() { @@ -786,28 +858,32 @@ public Dafny.ISequence<Dafny.Rune> dtor_id { public interface _IClass { bool is_Class { get; } Dafny.ISequence<Dafny.Rune> dtor_name { get; } + Dafny.ISequence<DAST._IType> dtor_superClasses { get; } Dafny.ISequence<DAST._IClassItem> dtor_body { get; } _IClass DowncastClone(); } public class Class : _IClass { public readonly Dafny.ISequence<Dafny.Rune> _name; + public readonly Dafny.ISequence<DAST._IType> _superClasses; public readonly Dafny.ISequence<DAST._IClassItem> _body; - public Class(Dafny.ISequence<Dafny.Rune> name, Dafny.ISequence<DAST._IClassItem> body) { + public Class(Dafny.ISequence<Dafny.Rune> name, Dafny.ISequence<DAST._IType> superClasses, Dafny.ISequence<DAST._IClassItem> body) { this._name = name; + this._superClasses = superClasses; this._body = body; } public _IClass DowncastClone() { if (this is _IClass dt) { return dt; } - return new Class(_name, _body); + return new Class(_name, _superClasses, _body); } public override bool Equals(object other) { var oth = other as DAST.Class; - return oth != null && object.Equals(this._name, oth._name) && object.Equals(this._body, oth._body); + return oth != null && object.Equals(this._name, oth._name) && object.Equals(this._superClasses, oth._superClasses) && object.Equals(this._body, oth._body); } public override int GetHashCode() { ulong hash = 5381; hash = ((hash << 5) + hash) + 0; hash = ((hash << 5) + hash) + ((ulong)Dafny.Helpers.GetHashCode(this._name)); + hash = ((hash << 5) + hash) + ((ulong)Dafny.Helpers.GetHashCode(this._superClasses)); hash = ((hash << 5) + hash) + ((ulong)Dafny.Helpers.GetHashCode(this._body)); return (int)hash; } @@ -816,11 +892,13 @@ public override string ToString() { s += "("; s += this._name.ToVerbatimString(true); s += ", "; + s += Dafny.Helpers.ToString(this._superClasses); + s += ", "; s += Dafny.Helpers.ToString(this._body); s += ")"; return s; } - private static readonly DAST._IClass theDefault = create(Dafny.Sequence<Dafny.Rune>.Empty, Dafny.Sequence<DAST._IClassItem>.Empty); + private static readonly DAST._IClass theDefault = create(Dafny.Sequence<Dafny.Rune>.Empty, Dafny.Sequence<DAST._IType>.Empty, Dafny.Sequence<DAST._IClassItem>.Empty); public static DAST._IClass Default() { return theDefault; } @@ -828,11 +906,11 @@ public static DAST._IClass Default() { public static Dafny.TypeDescriptor<DAST._IClass> _TypeDescriptor() { return _TYPE; } - public static _IClass create(Dafny.ISequence<Dafny.Rune> name, Dafny.ISequence<DAST._IClassItem> body) { - return new Class(name, body); + public static _IClass create(Dafny.ISequence<Dafny.Rune> name, Dafny.ISequence<DAST._IType> superClasses, Dafny.ISequence<DAST._IClassItem> body) { + return new Class(name, superClasses, body); } - public static _IClass create_Class(Dafny.ISequence<Dafny.Rune> name, Dafny.ISequence<DAST._IClassItem> body) { - return create(name, body); + public static _IClass create_Class(Dafny.ISequence<Dafny.Rune> name, Dafny.ISequence<DAST._IType> superClasses, Dafny.ISequence<DAST._IClassItem> body) { + return create(name, superClasses, body); } public bool is_Class { get { return true; } } public Dafny.ISequence<Dafny.Rune> dtor_name { @@ -840,6 +918,86 @@ public Dafny.ISequence<Dafny.Rune> dtor_name { return this._name; } } + public Dafny.ISequence<DAST._IType> dtor_superClasses { + get { + return this._superClasses; + } + } + public Dafny.ISequence<DAST._IClassItem> dtor_body { + get { + return this._body; + } + } + } + + public interface _ITrait { + bool is_Trait { get; } + Dafny.ISequence<Dafny.Rune> dtor_name { get; } + Dafny.ISequence<DAST._IType> dtor_typeParams { get; } + Dafny.ISequence<DAST._IClassItem> dtor_body { get; } + _ITrait DowncastClone(); + } + public class Trait : _ITrait { + public readonly Dafny.ISequence<Dafny.Rune> _name; + public readonly Dafny.ISequence<DAST._IType> _typeParams; + public readonly Dafny.ISequence<DAST._IClassItem> _body; + public Trait(Dafny.ISequence<Dafny.Rune> name, Dafny.ISequence<DAST._IType> typeParams, Dafny.ISequence<DAST._IClassItem> body) { + this._name = name; + this._typeParams = typeParams; + this._body = body; + } + public _ITrait DowncastClone() { + if (this is _ITrait dt) { return dt; } + return new Trait(_name, _typeParams, _body); + } + public override bool Equals(object other) { + var oth = other as DAST.Trait; + return oth != null && object.Equals(this._name, oth._name) && object.Equals(this._typeParams, oth._typeParams) && object.Equals(this._body, oth._body); + } + public override int GetHashCode() { + ulong hash = 5381; + hash = ((hash << 5) + hash) + 0; + hash = ((hash << 5) + hash) + ((ulong)Dafny.Helpers.GetHashCode(this._name)); + hash = ((hash << 5) + hash) + ((ulong)Dafny.Helpers.GetHashCode(this._typeParams)); + hash = ((hash << 5) + hash) + ((ulong)Dafny.Helpers.GetHashCode(this._body)); + return (int)hash; + } + public override string ToString() { + string s = "DAST.Trait.Trait"; + s += "("; + s += this._name.ToVerbatimString(true); + s += ", "; + s += Dafny.Helpers.ToString(this._typeParams); + s += ", "; + s += Dafny.Helpers.ToString(this._body); + s += ")"; + return s; + } + private static readonly DAST._ITrait theDefault = create(Dafny.Sequence<Dafny.Rune>.Empty, Dafny.Sequence<DAST._IType>.Empty, Dafny.Sequence<DAST._IClassItem>.Empty); + public static DAST._ITrait Default() { + return theDefault; + } + private static readonly Dafny.TypeDescriptor<DAST._ITrait> _TYPE = new Dafny.TypeDescriptor<DAST._ITrait>(DAST.Trait.Default()); + public static Dafny.TypeDescriptor<DAST._ITrait> _TypeDescriptor() { + return _TYPE; + } + public static _ITrait create(Dafny.ISequence<Dafny.Rune> name, Dafny.ISequence<DAST._IType> typeParams, Dafny.ISequence<DAST._IClassItem> body) { + return new Trait(name, typeParams, body); + } + public static _ITrait create_Trait(Dafny.ISequence<Dafny.Rune> name, Dafny.ISequence<DAST._IType> typeParams, Dafny.ISequence<DAST._IClassItem> body) { + return create(name, typeParams, body); + } + public bool is_Trait { get { return true; } } + public Dafny.ISequence<Dafny.Rune> dtor_name { + get { + return this._name; + } + } + public Dafny.ISequence<DAST._IType> dtor_typeParams { + get { + return this._typeParams; + } + } public Dafny.ISequence<DAST._IClassItem> dtor_body { get { return this._body; @@ -1192,6 +1350,8 @@ public DAST._IType dtor_typ { public interface _IMethod { bool is_Method { get; } bool dtor_isStatic { get; } + bool dtor_hasBody { get; } + DAST._IOptional<Dafny.ISequence<Dafny.ISequence<Dafny.Rune>>> dtor_overridingPath { get; } Dafny.ISequence<Dafny.Rune> dtor_name { get; } Dafny.ISequence<DAST._IType> dtor_typeParams { get; } Dafny.ISequence<DAST._IFormal> dtor_params { get; } @@ -1202,14 +1362,18 @@ public interface _IMethod { } public class Method : _IMethod { public readonly bool _isStatic; + public readonly bool _hasBody; + public readonly DAST._IOptional<Dafny.ISequence<Dafny.ISequence<Dafny.Rune>>> _overridingPath; public readonly Dafny.ISequence<Dafny.Rune> _name; public readonly Dafny.ISequence<DAST._IType> _typeParams; public readonly Dafny.ISequence<DAST._IFormal> _params; public readonly Dafny.ISequence<DAST._IStatement> _body; public readonly Dafny.ISequence<DAST._IType> _outTypes; public readonly DAST._IOptional<Dafny.ISequence<Dafny.ISequence<Dafny.Rune>>> _outVars; - public Method(bool isStatic, Dafny.ISequence<Dafny.Rune> name, Dafny.ISequence<DAST._IType> typeParams, Dafny.ISequence<DAST._IFormal> @params, Dafny.ISequence<DAST._IStatement> body, Dafny.ISequence<DAST._IType> outTypes, DAST._IOptional<Dafny.ISequence<Dafny.ISequence<Dafny.Rune>>> outVars) { + public Method(bool isStatic, bool hasBody, DAST._IOptional<Dafny.ISequence<Dafny.ISequence<Dafny.Rune>>> overridingPath, Dafny.ISequence<Dafny.Rune> name, Dafny.ISequence<DAST._IType> typeParams, Dafny.ISequence<DAST._IFormal> @params, Dafny.ISequence<DAST._IStatement> body, Dafny.ISequence<DAST._IType> outTypes, DAST._IOptional<Dafny.ISequence<Dafny.ISequence<Dafny.Rune>>> outVars) { this._isStatic = isStatic; + this._hasBody = hasBody; + this._overridingPath = overridingPath; this._name = name; this._typeParams = typeParams; this._params = @params; @@ -1219,16 +1383,18 @@ public Method(bool isStatic, Dafny.ISequence<Dafny.Rune> name, Dafny.ISequence<D } public _IMethod DowncastClone() { if (this is _IMethod dt) { return dt; } - return new Method(_isStatic, _name, _typeParams, _params, _body, _outTypes, _outVars); + return new Method(_isStatic, _hasBody, _overridingPath, _name, _typeParams, _params, _body, _outTypes, _outVars); } public override bool Equals(object other) { var oth = other as DAST.Method; - return oth != null && this._isStatic == oth._isStatic && object.Equals(this._name, oth._name) && object.Equals(this._typeParams, oth._typeParams) && object.Equals(this._params, oth._params) && object.Equals(this._body, oth._body) && object.Equals(this._outTypes, oth._outTypes) && object.Equals(this._outVars, oth._outVars); + return oth != null && this._isStatic == oth._isStatic && this._hasBody == oth._hasBody && object.Equals(this._overridingPath, oth._overridingPath) && object.Equals(this._name, oth._name) && object.Equals(this._typeParams, oth._typeParams) && object.Equals(this._params, oth._params) && object.Equals(this._body, oth._body) && object.Equals(this._outTypes, oth._outTypes) && object.Equals(this._outVars, oth._outVars); } public override int GetHashCode() { ulong hash = 5381; hash = ((hash << 5) + hash) + 0; hash = ((hash << 5) + hash) + ((ulong)Dafny.Helpers.GetHashCode(this._isStatic)); + hash = ((hash << 5) + hash) + ((ulong)Dafny.Helpers.GetHashCode(this._hasBody)); + hash = ((hash << 5) + hash) + ((ulong)Dafny.Helpers.GetHashCode(this._overridingPath)); hash = ((hash << 5) + hash) + ((ulong)Dafny.Helpers.GetHashCode(this._name)); hash = ((hash << 5) + hash) + ((ulong)Dafny.Helpers.GetHashCode(this._typeParams)); hash = ((hash << 5) + hash) + ((ulong)Dafny.Helpers.GetHashCode(this._params)); @@ -1242,6 +1408,10 @@ public override string ToString() { s += "("; s += Dafny.Helpers.ToString(this._isStatic); s += ", "; + s += Dafny.Helpers.ToString(this._hasBody); + s += ", "; + s += Dafny.Helpers.ToString(this._overridingPath); + s += ", "; s += this._name.ToVerbatimString(true); s += ", "; s += Dafny.Helpers.ToString(this._typeParams); @@ -1256,7 +1426,7 @@ public override string ToString() { s += ")"; return s; } - private static readonly DAST._IMethod theDefault = create(false, Dafny.Sequence<Dafny.Rune>.Empty, Dafny.Sequence<DAST._IType>.Empty, Dafny.Sequence<DAST._IFormal>.Empty, Dafny.Sequence<DAST._IStatement>.Empty, Dafny.Sequence<DAST._IType>.Empty, DAST.Optional<Dafny.ISequence<Dafny.ISequence<Dafny.Rune>>>.Default()); + private static readonly DAST._IMethod theDefault = create(false, false, DAST.Optional<Dafny.ISequence<Dafny.ISequence<Dafny.Rune>>>.Default(), Dafny.Sequence<Dafny.Rune>.Empty, Dafny.Sequence<DAST._IType>.Empty, Dafny.Sequence<DAST._IFormal>.Empty, Dafny.Sequence<DAST._IStatement>.Empty, Dafny.Sequence<DAST._IType>.Empty, DAST.Optional<Dafny.ISequence<Dafny.ISequence<Dafny.Rune>>>.Default()); public static DAST._IMethod Default() { return theDefault; } @@ -1264,11 +1434,11 @@ public static DAST._IMethod Default() { public static Dafny.TypeDescriptor<DAST._IMethod> _TypeDescriptor() { return _TYPE; } - public static _IMethod create(bool isStatic, Dafny.ISequence<Dafny.Rune> name, Dafny.ISequence<DAST._IType> typeParams, Dafny.ISequence<DAST._IFormal> @params, Dafny.ISequence<DAST._IStatement> body, Dafny.ISequence<DAST._IType> outTypes, DAST._IOptional<Dafny.ISequence<Dafny.ISequence<Dafny.Rune>>> outVars) { - return new Method(isStatic, name, typeParams, @params, body, outTypes, outVars); + public static _IMethod create(bool isStatic, bool hasBody, DAST._IOptional<Dafny.ISequence<Dafny.ISequence<Dafny.Rune>>> overridingPath, Dafny.ISequence<Dafny.Rune> name, Dafny.ISequence<DAST._IType> typeParams, Dafny.ISequence<DAST._IFormal> @params, Dafny.ISequence<DAST._IStatement> body, Dafny.ISequence<DAST._IType> outTypes, DAST._IOptional<Dafny.ISequence<Dafny.ISequence<Dafny.Rune>>> outVars) { + return new Method(isStatic, hasBody, overridingPath, name, typeParams, @params, body, outTypes, outVars); } - public static _IMethod create_Method(bool isStatic, Dafny.ISequence<Dafny.Rune> name, Dafny.ISequence<DAST._IType> typeParams, Dafny.ISequence<DAST._IFormal> @params, Dafny.ISequence<DAST._IStatement> body, Dafny.ISequence<DAST._IType> outTypes, DAST._IOptional<Dafny.ISequence<Dafny.ISequence<Dafny.Rune>>> outVars) { - return create(isStatic, name, typeParams, @params, body, outTypes, outVars); + public static _IMethod create_Method(bool isStatic, bool hasBody, DAST._IOptional<Dafny.ISequence<Dafny.ISequence<Dafny.Rune>>> overridingPath, Dafny.ISequence<Dafny.Rune> name, Dafny.ISequence<DAST._IType> typeParams, Dafny.ISequence<DAST._IFormal> @params, Dafny.ISequence<DAST._IStatement> body, Dafny.ISequence<DAST._IType> outTypes, DAST._IOptional<Dafny.ISequence<Dafny.ISequence<Dafny.Rune>>> outVars) { + return create(isStatic, hasBody, overridingPath, name, typeParams, @params, body, outTypes, outVars); } public bool is_Method { get { return true; } } public bool dtor_isStatic { @@ -1276,6 +1446,16 @@ public bool dtor_isStatic { return this._isStatic; } } + public bool dtor_hasBody { + get { + return this._hasBody; + } + } + public DAST._IOptional<Dafny.ISequence<Dafny.ISequence<Dafny.Rune>>> dtor_overridingPath { + get { + return this._overridingPath; + } + } public Dafny.ISequence<Dafny.Rune> dtor_name { get { return this._name; @@ -1396,6 +1576,7 @@ public interface _IStatement { bool is_Call { get; } bool is_Return { get; } bool is_EarlyReturn { get; } + bool is_Halt { get; } bool is_Print { get; } Dafny.ISequence<Dafny.Rune> dtor_name { get; } DAST._IType dtor_typ { get; } @@ -1445,6 +1626,9 @@ public static _IStatement create_Return(DAST._IExpression expr) { public static _IStatement create_EarlyReturn() { return new Statement_EarlyReturn(); } + public static _IStatement create_Halt() { + return new Statement_Halt(); + } public static _IStatement create_Print(DAST._IExpression _a0) { return new Statement_Print(_a0); } @@ -1455,6 +1639,7 @@ public static _IStatement create_Print(DAST._IExpression _a0) { public bool is_Call { get { return this is Statement_Call; } } public bool is_Return { get { return this is Statement_Return; } } public bool is_EarlyReturn { get { return this is Statement_EarlyReturn; } } + public bool is_Halt { get { return this is Statement_Halt; } } public bool is_Print { get { return this is Statement_Print; } } public Dafny.ISequence<Dafny.Rune> dtor_name { get { @@ -1778,6 +1963,27 @@ public override string ToString() { return s; } } + public class Statement_Halt : Statement { + public Statement_Halt() : base() { + } + public override _IStatement DowncastClone() { + if (this is _IStatement dt) { return dt; } + return new Statement_Halt(); + } + public override bool Equals(object other) { + var oth = other as DAST.Statement_Halt; + return oth != null; + } + public override int GetHashCode() { + ulong hash = 5381; + hash = ((hash << 5) + hash) + 7; + return (int)hash; + } + public override string ToString() { + string s = "DAST.Statement.Halt"; + return s; + } + } public class Statement_Print : Statement { public readonly DAST._IExpression _a0; public Statement_Print(DAST._IExpression _a0) : base() { @@ -1793,7 +1999,7 @@ public override bool Equals(object other) { } public override int GetHashCode() { ulong hash = 5381; - hash = ((hash << 5) + hash) + 7; + hash = ((hash << 5) + hash) + 8; hash = ((hash << 5) + hash) + ((ulong)Dafny.Helpers.GetHashCode(this._a0)); return (int)hash; } @@ -1815,6 +2021,7 @@ public interface _IExpression { bool is_DatatypeValue { get; } bool is_This { get; } bool is_Ite { get; } + bool is_UnOp { get; } bool is_BinOp { get; } bool is_Select { get; } bool is_TupleSelect { get; } @@ -1833,10 +2040,11 @@ public interface _IExpression { DAST._IExpression dtor_cond { get; } DAST._IExpression dtor_thn { get; } DAST._IExpression dtor_els { get; } + DAST._IUnaryOp dtor_unOp { get; } + DAST._IExpression dtor_expr { get; } Dafny.ISequence<Dafny.Rune> dtor_op { get; } DAST._IExpression dtor_left { get; } DAST._IExpression dtor_right { get; } - DAST._IExpression dtor_expr { get; } Dafny.ISequence<Dafny.Rune> dtor_field { get; } bool dtor_onDatatype { get; } BigInteger dtor_index { get; } @@ -1882,6 +2090,9 @@ public static _IExpression create_This() { public static _IExpression create_Ite(DAST._IExpression cond, DAST._IExpression thn, DAST._IExpression els) { return new Expression_Ite(cond, thn, els); } + public static _IExpression create_UnOp(DAST._IUnaryOp unOp, DAST._IExpression expr) { + return new Expression_UnOp(unOp, expr); + } public static _IExpression create_BinOp(Dafny.ISequence<Dafny.Rune> op, DAST._IExpression left, DAST._IExpression right) { return new Expression_BinOp(op, left, right); } @@ -1908,6 +2119,7 @@ public static _IExpression create_InitializationValue(DAST._IType typ) { public bool is_DatatypeValue { get { return this is Expression_DatatypeValue; } } public bool is_This { get { return this is Expression_This; } } public bool is_Ite { get { return this is Expression_Ite; } } + public bool is_UnOp { get { return this is Expression_UnOp; } } public bool is_BinOp { get { return this is Expression_BinOp; } } public bool is_Select { get { return this is Expression_Select; } } public bool is_TupleSelect { get { return this is Expression_TupleSelect; } } @@ -1989,6 +2201,20 @@ public DAST._IExpression dtor_els { return ((Expression_Ite)d)._els; } } + public DAST._IUnaryOp dtor_unOp { + get { + var d = this; + return ((Expression_UnOp)d)._unOp; + } + } + public DAST._IExpression dtor_expr { + get { + var d = this; + if (d is Expression_UnOp) { return ((Expression_UnOp)d)._expr; } + if (d is Expression_Select) { return ((Expression_Select)d)._expr; } + return ((Expression_TupleSelect)d)._expr; + } + } public Dafny.ISequence<Dafny.Rune> dtor_op { get { var d = this; @@ -2007,13 +2233,6 @@ public DAST._IExpression dtor_right { return ((Expression_BinOp)d)._right; } } - public DAST._IExpression dtor_expr { - get { - var d = this; - if (d is Expression_Select) { return ((Expression_Select)d)._expr; } - return ((Expression_TupleSelect)d)._expr; - } - } public Dafny.ISequence<Dafny.Rune> dtor_field { get { var d = this; @@ -2305,6 +2524,38 @@ public override string ToString() { return s; } } + public class Expression_UnOp : Expression { + public readonly DAST._IUnaryOp _unOp; + public readonly DAST._IExpression _expr; + public Expression_UnOp(DAST._IUnaryOp unOp, DAST._IExpression expr) : base() { + this._unOp = unOp; + this._expr = expr; + } + public override _IExpression DowncastClone() { + if (this is _IExpression dt) { return dt; } + return new Expression_UnOp(_unOp, _expr); + } + public override bool Equals(object other) { + var oth = other as DAST.Expression_UnOp; + return oth != null && object.Equals(this._unOp, oth._unOp) && object.Equals(this._expr, oth._expr); + } + public override int GetHashCode() { + ulong hash = 5381; + hash = ((hash << 5) + hash) + 8; + hash = ((hash << 5) + hash) + ((ulong)Dafny.Helpers.GetHashCode(this._unOp)); + hash = ((hash << 5) + hash) + ((ulong)Dafny.Helpers.GetHashCode(this._expr)); + return (int)hash; + } + public override string ToString() { + string s = "DAST.Expression.UnOp"; + s += "("; + s += Dafny.Helpers.ToString(this._unOp); + s += ", "; + s += Dafny.Helpers.ToString(this._expr); + s += ")"; + return s; + } + } public class Expression_BinOp : Expression { public readonly Dafny.ISequence<Dafny.Rune> _op; public readonly DAST._IExpression _left; @@ -2324,7 +2575,7 @@ public override bool Equals(object other) { } public override int GetHashCode() { ulong hash = 5381; - hash = ((hash << 5) + hash) + 8; + hash = ((hash << 5) + hash) + 9; hash = ((hash << 5) + hash) + ((ulong)Dafny.Helpers.GetHashCode(this._op)); hash = ((hash << 5) + hash) + ((ulong)Dafny.Helpers.GetHashCode(this._left)); hash = ((hash << 5) + hash) + ((ulong)Dafny.Helpers.GetHashCode(this._right)); @@ -2361,7 +2612,7 @@ public override bool Equals(object other) { } public override int GetHashCode() { ulong hash = 5381; - hash = ((hash << 5) + hash) + 9; + hash = ((hash << 5) + hash) + 10; hash = ((hash << 5) + hash) + ((ulong)Dafny.Helpers.GetHashCode(this._expr)); hash = ((hash << 5) + hash) + ((ulong)Dafny.Helpers.GetHashCode(this._field)); hash = ((hash << 5) + hash) + ((ulong)Dafny.Helpers.GetHashCode(this._onDatatype)); @@ -2396,7 +2647,7 @@ public override bool Equals(object other) { } public override int GetHashCode() { ulong hash = 5381; - hash = ((hash << 5) + hash) + 10; + hash = ((hash << 5) + hash) + 11; hash = ((hash << 5) + hash) + ((ulong)Dafny.Helpers.GetHashCode(this._expr)); hash = ((hash << 5) + hash) + ((ulong)Dafny.Helpers.GetHashCode(this._index)); return (int)hash; @@ -2432,7 +2683,7 @@ public override bool Equals(object other) { } public override int GetHashCode() { ulong hash = 5381; - hash = ((hash << 5) + hash) + 11; + hash = ((hash << 5) + hash) + 12; hash = ((hash << 5) + hash) + ((ulong)Dafny.Helpers.GetHashCode(this._on)); hash = ((hash << 5) + hash) + ((ulong)Dafny.Helpers.GetHashCode(this._name)); hash = ((hash << 5) + hash) + ((ulong)Dafny.Helpers.GetHashCode(this._typeArgs)); @@ -2472,7 +2723,7 @@ public override bool Equals(object other) { } public override int GetHashCode() { ulong hash = 5381; - hash = ((hash << 5) + hash) + 12; + hash = ((hash << 5) + hash) + 13; hash = ((hash << 5) + hash) + ((ulong)Dafny.Helpers.GetHashCode(this._on)); hash = ((hash << 5) + hash) + ((ulong)Dafny.Helpers.GetHashCode(this._dType)); hash = ((hash << 5) + hash) + ((ulong)Dafny.Helpers.GetHashCode(this._variant)); @@ -2505,7 +2756,7 @@ public override bool Equals(object other) { } public override int GetHashCode() { ulong hash = 5381; - hash = ((hash << 5) + hash) + 13; + hash = ((hash << 5) + hash) + 14; hash = ((hash << 5) + hash) + ((ulong)Dafny.Helpers.GetHashCode(this._typ)); return (int)hash; } @@ -2518,6 +2769,108 @@ public override string ToString() { } } + public interface _IUnaryOp { + bool is_Not { get; } + bool is_BitwiseNot { get; } + bool is_Cardinality { get; } + _IUnaryOp DowncastClone(); + } + public abstract class UnaryOp : _IUnaryOp { + public UnaryOp() { + } + private static readonly DAST._IUnaryOp theDefault = create_Not(); + public static DAST._IUnaryOp Default() { + return theDefault; + } + private static readonly Dafny.TypeDescriptor<DAST._IUnaryOp> _TYPE = new Dafny.TypeDescriptor<DAST._IUnaryOp>(DAST.UnaryOp.Default()); + public static Dafny.TypeDescriptor<DAST._IUnaryOp> _TypeDescriptor() { + return _TYPE; + } + public static _IUnaryOp create_Not() { + return new UnaryOp_Not(); + } + public static _IUnaryOp create_BitwiseNot() { + return new UnaryOp_BitwiseNot(); + } + public static _IUnaryOp create_Cardinality() { + return new UnaryOp_Cardinality(); + } + public bool is_Not { get { return this is UnaryOp_Not; } } + public bool is_BitwiseNot { get { return this is UnaryOp_BitwiseNot; } } + public bool is_Cardinality { get { return this is UnaryOp_Cardinality; } } + public static System.Collections.Generic.IEnumerable<_IUnaryOp> AllSingletonConstructors { + get { + yield return UnaryOp.create_Not(); + yield return UnaryOp.create_BitwiseNot(); + yield return UnaryOp.create_Cardinality(); + } + } + public abstract _IUnaryOp DowncastClone(); + } + public class UnaryOp_Not : UnaryOp { + public UnaryOp_Not() : base() { + } + public override _IUnaryOp DowncastClone() { + if (this is _IUnaryOp dt) { return dt; } + return new UnaryOp_Not(); + } + public override bool Equals(object other) { + var oth = other as DAST.UnaryOp_Not; + return oth != null; + } + public override int GetHashCode() { + ulong hash = 5381; + hash = ((hash << 5) + hash) + 0; + return (int)hash; + } + public override string ToString() { + string s = "DAST.UnaryOp.Not"; + return s; + } + } + public class UnaryOp_BitwiseNot : UnaryOp { + public UnaryOp_BitwiseNot() : base() { + } + public override _IUnaryOp DowncastClone() { + if (this is _IUnaryOp dt) { return dt; } + return new UnaryOp_BitwiseNot(); + } + public override bool Equals(object other) { + var oth = other as DAST.UnaryOp_BitwiseNot; + return oth != null; + } + public override int GetHashCode() { + ulong hash = 5381; + hash = ((hash << 5) + hash) + 1; + return (int)hash; + } + public override string ToString() { + string s = "DAST.UnaryOp.BitwiseNot"; + return s; + } + } + public class UnaryOp_Cardinality : UnaryOp { + public UnaryOp_Cardinality() : base() { + } + public override _IUnaryOp DowncastClone() { + if (this is _IUnaryOp dt) { return dt; } + return new UnaryOp_Cardinality(); + } + public override bool Equals(object other) { + var oth = other as DAST.UnaryOp_Cardinality; + return oth != null; + } + public override int GetHashCode() { + ulong hash = 5381; + hash = ((hash << 5) + hash) + 2; + return (int)hash; + } + public override string ToString() { + string s = "DAST.UnaryOp.Cardinality"; + return s; + } + } + public interface _ILiteral { bool is_BoolLiteral { get; } bool is_IntLiteral { get; } @@ -2735,16 +3088,16 @@ public partial class stringNat { public partial class COMP { public COMP() { } - public static Dafny.ISequence<Dafny.Rune> GenModule(DAST._IModule mod) { + public static Dafny.ISequence<Dafny.Rune> GenModule(DAST._IModule mod, Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> containingPath) { Dafny.ISequence<Dafny.Rune> s = Dafny.Sequence<Dafny.Rune>.Empty; Dafny.ISequence<Dafny.Rune> body; Dafny.ISequence<Dafny.Rune> _out0; - _out0 = DCOMP.COMP.GenModuleBody((mod).dtor_body); + _out0 = DCOMP.COMP.GenModuleBody((mod).dtor_body, Dafny.Sequence<Dafny.ISequence<Dafny.Rune>>.Concat(containingPath, Dafny.Sequence<Dafny.ISequence<Dafny.Rune>>.FromElements((mod).dtor_name))); body = _out0; s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("mod r#"), (mod).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" {\n")), body), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n}")); return s; } - public static Dafny.ISequence<Dafny.Rune> GenModuleBody(Dafny.ISequence<DAST._IModuleItem> body) { + public static Dafny.ISequence<Dafny.Rune> GenModuleBody(Dafny.ISequence<DAST._IModuleItem> body, Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> containingPath) { Dafny.ISequence<Dafny.Rune> s = Dafny.Sequence<Dafny.Rune>.Empty; s = Dafny.Sequence<Dafny.Rune>.UnicodeFromString(""); BigInteger i; @@ -2756,26 +3109,32 @@ public COMP() { DAST._IModule __mcc_h0 = _source0.dtor_Module_a0; DAST._IModule m = __mcc_h0; Dafny.ISequence<Dafny.Rune> _out1; - _out1 = DCOMP.COMP.GenModule(m); + _out1 = DCOMP.COMP.GenModule(m, containingPath); generated = _out1; } else if (_source0.is_Class) { DAST._IClass __mcc_h1 = _source0.dtor_Class_a0; DAST._IClass c = __mcc_h1; Dafny.ISequence<Dafny.Rune> _out2; - _out2 = DCOMP.COMP.GenClass(c); + _out2 = DCOMP.COMP.GenClass(c, Dafny.Sequence<Dafny.ISequence<Dafny.Rune>>.Concat(containingPath, Dafny.Sequence<Dafny.ISequence<Dafny.Rune>>.FromElements((c).dtor_name))); generated = _out2; - } else if (_source0.is_Newtype) { - DAST._INewtype __mcc_h2 = _source0.dtor_Newtype_a0; - DAST._INewtype n = __mcc_h2; + } else if (_source0.is_Trait) { + DAST._ITrait __mcc_h2 = _source0.dtor_Trait_a0; + DAST._ITrait t = __mcc_h2; Dafny.ISequence<Dafny.Rune> _out3; - _out3 = DCOMP.COMP.GenNewtype(n); + _out3 = DCOMP.COMP.GenTrait(t, containingPath); generated = _out3; - } else { - DAST._IDatatype __mcc_h3 = _source0.dtor_Datatype_a0; - DAST._IDatatype _10_d = __mcc_h3; + } else if (_source0.is_Newtype) { + DAST._INewtype __mcc_h3 = _source0.dtor_Newtype_a0; + DAST._INewtype _10_n = __mcc_h3; Dafny.ISequence<Dafny.Rune> _out4; - _out4 = DCOMP.COMP.GenDatatype(_10_d); + _out4 = DCOMP.COMP.GenNewtype(_10_n); generated = _out4; + } else { + DAST._IDatatype _11___mcc_h4 = _source0.dtor_Datatype_a0; + DAST._IDatatype _12_d = _11___mcc_h4; + Dafny.ISequence<Dafny.Rune> _out5; + _out5 = DCOMP.COMP.GenDatatype(_12_d); + generated = _out5; } if ((i).Sign == 1) { s = Dafny.Sequence<Dafny.Rune>.Concat(s, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n")); @@ -2785,212 +3144,303 @@ public COMP() { } return s; } - public static Dafny.ISequence<Dafny.Rune> GenClass(DAST._IClass c) { + public static Dafny.ISequence<Dafny.Rune> GenClass(DAST._IClass c, Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> path) { + Dafny.ISequence<Dafny.Rune> s = Dafny.Sequence<Dafny.Rune>.Empty; + Dafny.ISequence<Dafny.Rune> _13_implBody; + Dafny.IMap<Dafny.ISequence<Dafny.ISequence<Dafny.Rune>>, Dafny.ISequence<Dafny.Rune>> _14_traitBodies; + Dafny.ISequence<Dafny.Rune> _out6; + Dafny.IMap<Dafny.ISequence<Dafny.ISequence<Dafny.Rune>>, Dafny.ISequence<Dafny.Rune>> _out7; + DCOMP.COMP.GenClassImplBody((c).dtor_body, false, DAST.Type.create_Path(path, Dafny.Sequence<DAST._IType>.FromElements(), DAST.ResolvedType.create_Datatype(path)), Dafny.Set<DAST._IType>.FromElements(), out _out6, out _out7); + _13_implBody = _out6; + _14_traitBodies = _out7; + _13_implBody = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("pub fn new() -> Self {\n"), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#")), (c).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" {\n")), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("")), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n}\n}\n")), _13_implBody); + s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("pub struct r#"), (c).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" {\n")), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("")), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n}")), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n")), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("impl r#")), (c).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" {\n")), _13_implBody), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n}")); + if ((new BigInteger(((c).dtor_superClasses).Count)).Sign == 1) { + BigInteger _15_i; + _15_i = BigInteger.Zero; + while ((_15_i) < (new BigInteger(((c).dtor_superClasses).Count))) { + DAST._IType _16_superClass; + _16_superClass = ((c).dtor_superClasses).Select(_15_i); + DAST._IType _source1 = _16_superClass; + if (_source1.is_Path) { + Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _17___mcc_h0 = _source1.dtor_Path_a0; + Dafny.ISequence<DAST._IType> _18___mcc_h1 = _source1.dtor_typeArgs; + DAST._IResolvedType _19___mcc_h2 = _source1.dtor_resolved; + DAST._IResolvedType _source2 = _19___mcc_h2; + if (_source2.is_Datatype) { + Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _20___mcc_h6 = _source2.dtor_path; + } else if (_source2.is_Trait) { + Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _21___mcc_h8 = _source2.dtor_path; + Dafny.ISequence<DAST._IType> _22_typeArgs = _18___mcc_h1; + Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _23_traitPath = _17___mcc_h0; + { + Dafny.ISequence<Dafny.Rune> _24_pathStr; + Dafny.ISequence<Dafny.Rune> _out8; + _out8 = DCOMP.COMP.GenPath(_23_traitPath); + _24_pathStr = _out8; + Dafny.ISequence<Dafny.Rune> _25_typeArgs; + Dafny.ISequence<Dafny.Rune> _out9; + _out9 = DCOMP.COMP.GenTypeArgs(_22_typeArgs, false); + _25_typeArgs = _out9; + Dafny.ISequence<Dafny.Rune> _26_body; + _26_body = Dafny.Sequence<Dafny.Rune>.UnicodeFromString(""); + if ((_14_traitBodies).Contains(_23_traitPath)) { + _26_body = Dafny.Map<Dafny.ISequence<Dafny.ISequence<Dafny.Rune>>, Dafny.ISequence<Dafny.Rune>>.Select(_14_traitBodies, _23_traitPath); + } + Dafny.ISequence<Dafny.Rune> _27_genSelfPath; + Dafny.ISequence<Dafny.Rune> _out10; + _out10 = DCOMP.COMP.GenPath(path); + _27_genSelfPath = _out10; + s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(s, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\nimpl ")), _24_pathStr), _25_typeArgs), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" for ::std::rc::Rc<")), _27_genSelfPath), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("> {\n")), _26_body), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n}")); + } + } else { + } + } else if (_source1.is_Tuple) { + Dafny.ISequence<DAST._IType> _28___mcc_h10 = _source1.dtor_Tuple_a0; + } else if (_source1.is_Primitive) { + DAST._IPrimitive _29___mcc_h12 = _source1.dtor_Primitive_a0; + } else if (_source1.is_Passthrough) { + Dafny.ISequence<Dafny.Rune> _30___mcc_h14 = _source1.dtor_Passthrough_a0; + } else { + Dafny.ISequence<Dafny.Rune> _31___mcc_h16 = _source1.dtor_TypeArg_a0; + } + _15_i = (_15_i) + (BigInteger.One); + } + } + return s; + } + public static Dafny.ISequence<Dafny.Rune> GenTrait(DAST._ITrait t, Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> containingPath) { Dafny.ISequence<Dafny.Rune> s = Dafny.Sequence<Dafny.Rune>.Empty; - Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _11_selfPath; - _11_selfPath = Dafny.Sequence<Dafny.ISequence<Dafny.Rune>>.FromElements((c).dtor_name); - Dafny.ISequence<Dafny.Rune> _12_implBody; - Dafny.ISequence<Dafny.Rune> _out5; - _out5 = DCOMP.COMP.GenClassImplBody((c).dtor_body, DAST.Type.create_Path(Dafny.Sequence<Dafny.ISequence<Dafny.Rune>>.FromElements(), Dafny.Sequence<DAST._IType>.FromElements(), DAST.ResolvedType.create_Datatype(_11_selfPath)), Dafny.Set<DAST._IType>.FromElements()); - _12_implBody = _out5; - _12_implBody = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("pub fn new() -> Self {\n"), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#")), (c).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" {\n")), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("")), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n}\n}\n")), _12_implBody); - s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("pub struct r#"), (c).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" {\n")), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("")), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n}")), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n")), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("impl r#")), (c).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" {\n")), _12_implBody), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n}")); + Dafny.ISet<DAST._IType> _32_typeParamsSet; + _32_typeParamsSet = Dafny.Set<DAST._IType>.FromElements(); + Dafny.ISequence<Dafny.Rune> _33_typeParams; + _33_typeParams = Dafny.Sequence<Dafny.Rune>.UnicodeFromString(""); + BigInteger _34_tpI; + _34_tpI = BigInteger.Zero; + if ((new BigInteger(((t).dtor_typeParams).Count)).Sign == 1) { + _33_typeParams = Dafny.Sequence<Dafny.Rune>.UnicodeFromString("<"); + while ((_34_tpI) < (new BigInteger(((t).dtor_typeParams).Count))) { + DAST._IType _35_tp; + _35_tp = ((t).dtor_typeParams).Select(_34_tpI); + _32_typeParamsSet = Dafny.Set<DAST._IType>.Union(_32_typeParamsSet, Dafny.Set<DAST._IType>.FromElements(_35_tp)); + Dafny.ISequence<Dafny.Rune> _36_genTp; + Dafny.ISequence<Dafny.Rune> _out11; + _out11 = DCOMP.COMP.GenType(_35_tp, false); + _36_genTp = _out11; + _33_typeParams = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(_33_typeParams, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#")), _36_genTp), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(", ")); + _34_tpI = (_34_tpI) + (BigInteger.One); + } + _33_typeParams = Dafny.Sequence<Dafny.Rune>.Concat(_33_typeParams, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(">")); + } + Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _37_fullPath; + _37_fullPath = Dafny.Sequence<Dafny.ISequence<Dafny.Rune>>.Concat(containingPath, Dafny.Sequence<Dafny.ISequence<Dafny.Rune>>.FromElements((t).dtor_name)); + Dafny.ISequence<Dafny.Rune> _38_implBody; + Dafny.IMap<Dafny.ISequence<Dafny.ISequence<Dafny.Rune>>, Dafny.ISequence<Dafny.Rune>> _39___v3; + Dafny.ISequence<Dafny.Rune> _out12; + Dafny.IMap<Dafny.ISequence<Dafny.ISequence<Dafny.Rune>>, Dafny.ISequence<Dafny.Rune>> _out13; + DCOMP.COMP.GenClassImplBody((t).dtor_body, true, DAST.Type.create_Path(_37_fullPath, Dafny.Sequence<DAST._IType>.FromElements(), DAST.ResolvedType.create_Trait(_37_fullPath)), _32_typeParamsSet, out _out12, out _out13); + _38_implBody = _out12; + _39___v3 = _out13; + s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("pub trait r#"), (t).dtor_name), _33_typeParams), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" {\n")), _38_implBody), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n}")); return s; } public static Dafny.ISequence<Dafny.Rune> GenNewtype(DAST._INewtype c) { Dafny.ISequence<Dafny.Rune> s = Dafny.Sequence<Dafny.Rune>.Empty; - Dafny.ISequence<Dafny.Rune> _13_underlyingType; - Dafny.ISequence<Dafny.Rune> _out6; - _out6 = DCOMP.COMP.GenType((c).dtor_base); - _13_underlyingType = _out6; - s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("pub type r#"), (c).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" =")), _13_underlyingType), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(";\n")); + Dafny.ISequence<Dafny.Rune> _40_underlyingType; + Dafny.ISequence<Dafny.Rune> _out14; + _out14 = DCOMP.COMP.GenType((c).dtor_base, false); + _40_underlyingType = _out14; + s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("pub type r#"), (c).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" =")), _40_underlyingType), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(";\n")); return s; } public static Dafny.ISequence<Dafny.Rune> GenDatatype(DAST._IDatatype c) { Dafny.ISequence<Dafny.Rune> s = Dafny.Sequence<Dafny.Rune>.Empty; - Dafny.ISet<DAST._IType> _14_typeParamsSet; - _14_typeParamsSet = Dafny.Set<DAST._IType>.FromElements(); - Dafny.ISequence<Dafny.Rune> _15_typeParams; - _15_typeParams = Dafny.Sequence<Dafny.Rune>.UnicodeFromString(""); - BigInteger _16_tpI; - _16_tpI = BigInteger.Zero; + Dafny.ISet<DAST._IType> _41_typeParamsSet; + _41_typeParamsSet = Dafny.Set<DAST._IType>.FromElements(); + Dafny.ISequence<Dafny.Rune> _42_typeParams; + _42_typeParams = Dafny.Sequence<Dafny.Rune>.UnicodeFromString(""); + BigInteger _43_tpI; + _43_tpI = BigInteger.Zero; if ((new BigInteger(((c).dtor_typeParams).Count)).Sign == 1) { - _15_typeParams = Dafny.Sequence<Dafny.Rune>.UnicodeFromString("<"); - while ((_16_tpI) < (new BigInteger(((c).dtor_typeParams).Count))) { - DAST._IType _17_tp; - _17_tp = ((c).dtor_typeParams).Select(_16_tpI); - _14_typeParamsSet = Dafny.Set<DAST._IType>.Union(_14_typeParamsSet, Dafny.Set<DAST._IType>.FromElements(_17_tp)); - Dafny.ISequence<Dafny.Rune> _18_genTp; - Dafny.ISequence<Dafny.Rune> _out7; - _out7 = DCOMP.COMP.GenType(_17_tp); - _18_genTp = _out7; - _15_typeParams = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(_15_typeParams, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#")), _18_genTp), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(", ")); - _16_tpI = (_16_tpI) + (BigInteger.One); + _42_typeParams = Dafny.Sequence<Dafny.Rune>.UnicodeFromString("<"); + while ((_43_tpI) < (new BigInteger(((c).dtor_typeParams).Count))) { + DAST._IType _44_tp; + _44_tp = ((c).dtor_typeParams).Select(_43_tpI); + _41_typeParamsSet = Dafny.Set<DAST._IType>.Union(_41_typeParamsSet, Dafny.Set<DAST._IType>.FromElements(_44_tp)); + Dafny.ISequence<Dafny.Rune> _45_genTp; + Dafny.ISequence<Dafny.Rune> _out15; + _out15 = DCOMP.COMP.GenType(_44_tp, false); + _45_genTp = _out15; + _42_typeParams = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(_42_typeParams, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#")), _45_genTp), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(", ")); + _43_tpI = (_43_tpI) + (BigInteger.One); } - _15_typeParams = Dafny.Sequence<Dafny.Rune>.Concat(_15_typeParams, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(">")); + _42_typeParams = Dafny.Sequence<Dafny.Rune>.Concat(_42_typeParams, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(">")); } - Dafny.ISequence<Dafny.Rune> _19_ctors; - _19_ctors = Dafny.Sequence<Dafny.Rune>.UnicodeFromString(""); - BigInteger _20_i; - _20_i = BigInteger.Zero; - while ((_20_i) < (new BigInteger(((c).dtor_ctors).Count))) { - DAST._IDatatypeCtor _21_ctor; - _21_ctor = ((c).dtor_ctors).Select(_20_i); - Dafny.ISequence<Dafny.Rune> _22_ctorBody; - _22_ctorBody = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#"), (_21_ctor).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" { ")); - BigInteger _23_j; - _23_j = BigInteger.Zero; - while ((_23_j) < (new BigInteger(((_21_ctor).dtor_args).Count))) { - DAST._IFormal _24_formal; - _24_formal = ((_21_ctor).dtor_args).Select(_23_j); - Dafny.ISequence<Dafny.Rune> _25_formalType; - Dafny.ISequence<Dafny.Rune> _out8; - _out8 = DCOMP.COMP.GenType((_24_formal).dtor_typ); - _25_formalType = _out8; + Dafny.ISequence<Dafny.Rune> _46_ctors; + _46_ctors = Dafny.Sequence<Dafny.Rune>.UnicodeFromString(""); + BigInteger _47_i; + _47_i = BigInteger.Zero; + while ((_47_i) < (new BigInteger(((c).dtor_ctors).Count))) { + DAST._IDatatypeCtor _48_ctor; + _48_ctor = ((c).dtor_ctors).Select(_47_i); + Dafny.ISequence<Dafny.Rune> _49_ctorBody; + _49_ctorBody = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#"), (_48_ctor).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" { ")); + BigInteger _50_j; + _50_j = BigInteger.Zero; + while ((_50_j) < (new BigInteger(((_48_ctor).dtor_args).Count))) { + DAST._IFormal _51_formal; + _51_formal = ((_48_ctor).dtor_args).Select(_50_j); + Dafny.ISequence<Dafny.Rune> _52_formalType; + Dafny.ISequence<Dafny.Rune> _out16; + _out16 = DCOMP.COMP.GenType((_51_formal).dtor_typ, false); + _52_formalType = _out16; if ((c).dtor_isCo) { - _22_ctorBody = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(_22_ctorBody, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#")), (_24_formal).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(": ::dafny_runtime::LazyFieldWrapper<")), _25_formalType), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(">, ")); + _49_ctorBody = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(_49_ctorBody, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#")), (_51_formal).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(": ::dafny_runtime::LazyFieldWrapper<")), _52_formalType), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(">, ")); } else { - _22_ctorBody = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(_22_ctorBody, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#")), (_24_formal).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(": ")), _25_formalType), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(", ")); + _49_ctorBody = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(_49_ctorBody, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#")), (_51_formal).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(": ")), _52_formalType), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(", ")); } - _23_j = (_23_j) + (BigInteger.One); + _50_j = (_50_j) + (BigInteger.One); } - _22_ctorBody = Dafny.Sequence<Dafny.Rune>.Concat(_22_ctorBody, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("}")); - _19_ctors = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(_19_ctors, _22_ctorBody), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(",\n")); - _20_i = (_20_i) + (BigInteger.One); + _49_ctorBody = Dafny.Sequence<Dafny.Rune>.Concat(_49_ctorBody, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("}")); + _46_ctors = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(_46_ctors, _49_ctorBody), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(",\n")); + _47_i = (_47_i) + (BigInteger.One); } - Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _26_selfPath; - _26_selfPath = Dafny.Sequence<Dafny.ISequence<Dafny.Rune>>.FromElements((c).dtor_name); - Dafny.ISequence<Dafny.Rune> _27_implBody; - Dafny.ISequence<Dafny.Rune> _out9; - _out9 = DCOMP.COMP.GenClassImplBody((c).dtor_body, DAST.Type.create_Path(Dafny.Sequence<Dafny.ISequence<Dafny.Rune>>.FromElements(), Dafny.Sequence<DAST._IType>.FromElements(), DAST.ResolvedType.create_Datatype(_26_selfPath)), _14_typeParamsSet); - _27_implBody = _out9; - _20_i = BigInteger.Zero; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _28_emittedFields; - _28_emittedFields = Dafny.Set<Dafny.ISequence<Dafny.Rune>>.FromElements(); - while ((_20_i) < (new BigInteger(((c).dtor_ctors).Count))) { - DAST._IDatatypeCtor _29_ctor; - _29_ctor = ((c).dtor_ctors).Select(_20_i); - BigInteger _30_j; - _30_j = BigInteger.Zero; - while ((_30_j) < (new BigInteger(((_29_ctor).dtor_args).Count))) { - DAST._IFormal _31_formal; - _31_formal = ((_29_ctor).dtor_args).Select(_30_j); - if (!((_28_emittedFields).Contains((_31_formal).dtor_name))) { - _28_emittedFields = Dafny.Set<Dafny.ISequence<Dafny.Rune>>.Union(_28_emittedFields, Dafny.Set<Dafny.ISequence<Dafny.Rune>>.FromElements((_31_formal).dtor_name)); - Dafny.ISequence<Dafny.Rune> _32_formalType; - Dafny.ISequence<Dafny.Rune> _out10; - _out10 = DCOMP.COMP.GenType((_31_formal).dtor_typ); - _32_formalType = _out10; - Dafny.ISequence<Dafny.Rune> _33_methodBody; - _33_methodBody = Dafny.Sequence<Dafny.Rune>.UnicodeFromString("match self {\n"); - BigInteger _34_k; - _34_k = BigInteger.Zero; - while ((_34_k) < (new BigInteger(((c).dtor_ctors).Count))) { - DAST._IDatatypeCtor _35_ctor2; - _35_ctor2 = ((c).dtor_ctors).Select(_34_k); - Dafny.ISequence<Dafny.Rune> _36_ctorMatch; - _36_ctorMatch = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#"), (c).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("::")), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#")), (_35_ctor2).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" { ")); - BigInteger _37_l; - _37_l = BigInteger.Zero; - bool _38_hasMatchingField; - _38_hasMatchingField = false; - while ((_37_l) < (new BigInteger(((_35_ctor2).dtor_args).Count))) { - DAST._IFormal _39_formal2; - _39_formal2 = ((_35_ctor2).dtor_args).Select(_37_l); - if (((_31_formal).dtor_name).Equals((_39_formal2).dtor_name)) { - _38_hasMatchingField = true; + Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _53_selfPath; + _53_selfPath = Dafny.Sequence<Dafny.ISequence<Dafny.Rune>>.FromElements((c).dtor_name); + Dafny.ISequence<Dafny.Rune> _54_implBody; + Dafny.IMap<Dafny.ISequence<Dafny.ISequence<Dafny.Rune>>, Dafny.ISequence<Dafny.Rune>> _55_traitBodies; + Dafny.ISequence<Dafny.Rune> _out17; + Dafny.IMap<Dafny.ISequence<Dafny.ISequence<Dafny.Rune>>, Dafny.ISequence<Dafny.Rune>> _out18; + DCOMP.COMP.GenClassImplBody((c).dtor_body, false, DAST.Type.create_Path(Dafny.Sequence<Dafny.ISequence<Dafny.Rune>>.FromElements(), Dafny.Sequence<DAST._IType>.FromElements(), DAST.ResolvedType.create_Datatype(_53_selfPath)), _41_typeParamsSet, out _out17, out _out18); + _54_implBody = _out17; + _55_traitBodies = _out18; + _47_i = BigInteger.Zero; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _56_emittedFields; + _56_emittedFields = Dafny.Set<Dafny.ISequence<Dafny.Rune>>.FromElements(); + while ((_47_i) < (new BigInteger(((c).dtor_ctors).Count))) { + DAST._IDatatypeCtor _57_ctor; + _57_ctor = ((c).dtor_ctors).Select(_47_i); + BigInteger _58_j; + _58_j = BigInteger.Zero; + while ((_58_j) < (new BigInteger(((_57_ctor).dtor_args).Count))) { + DAST._IFormal _59_formal; + _59_formal = ((_57_ctor).dtor_args).Select(_58_j); + if (!((_56_emittedFields).Contains((_59_formal).dtor_name))) { + _56_emittedFields = Dafny.Set<Dafny.ISequence<Dafny.Rune>>.Union(_56_emittedFields, Dafny.Set<Dafny.ISequence<Dafny.Rune>>.FromElements((_59_formal).dtor_name)); + Dafny.ISequence<Dafny.Rune> _60_formalType; + Dafny.ISequence<Dafny.Rune> _out19; + _out19 = DCOMP.COMP.GenType((_59_formal).dtor_typ, false); + _60_formalType = _out19; + Dafny.ISequence<Dafny.Rune> _61_methodBody; + _61_methodBody = Dafny.Sequence<Dafny.Rune>.UnicodeFromString("match self {\n"); + BigInteger _62_k; + _62_k = BigInteger.Zero; + while ((_62_k) < (new BigInteger(((c).dtor_ctors).Count))) { + DAST._IDatatypeCtor _63_ctor2; + _63_ctor2 = ((c).dtor_ctors).Select(_62_k); + Dafny.ISequence<Dafny.Rune> _64_ctorMatch; + _64_ctorMatch = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#"), (c).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("::")), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#")), (_63_ctor2).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" { ")); + BigInteger _65_l; + _65_l = BigInteger.Zero; + bool _66_hasMatchingField; + _66_hasMatchingField = false; + while ((_65_l) < (new BigInteger(((_63_ctor2).dtor_args).Count))) { + DAST._IFormal _67_formal2; + _67_formal2 = ((_63_ctor2).dtor_args).Select(_65_l); + if (((_59_formal).dtor_name).Equals((_67_formal2).dtor_name)) { + _66_hasMatchingField = true; } - _36_ctorMatch = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(_36_ctorMatch, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#")), (_39_formal2).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(", ")); - _37_l = (_37_l) + (BigInteger.One); + _64_ctorMatch = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(_64_ctorMatch, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#")), (_67_formal2).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(", ")); + _65_l = (_65_l) + (BigInteger.One); } - if (_38_hasMatchingField) { + if (_66_hasMatchingField) { if ((c).dtor_isCo) { - _36_ctorMatch = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(_36_ctorMatch, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("} => ::std::ops::Deref::deref(&")), (_31_formal).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(".0),\n")); + _64_ctorMatch = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(_64_ctorMatch, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("} => ::std::ops::Deref::deref(&")), (_59_formal).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(".0),\n")); } else { - _36_ctorMatch = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(_36_ctorMatch, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("} => ")), (_31_formal).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(",\n")); + _64_ctorMatch = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(_64_ctorMatch, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("} => ")), (_59_formal).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(",\n")); } } else { - _36_ctorMatch = Dafny.Sequence<Dafny.Rune>.Concat(_36_ctorMatch, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("} => panic!(\"field does not exist on this variant\"),\n")); + _64_ctorMatch = Dafny.Sequence<Dafny.Rune>.Concat(_64_ctorMatch, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("} => panic!(\"field does not exist on this variant\"),\n")); } - _33_methodBody = Dafny.Sequence<Dafny.Rune>.Concat(_33_methodBody, _36_ctorMatch); - _34_k = (_34_k) + (BigInteger.One); + _61_methodBody = Dafny.Sequence<Dafny.Rune>.Concat(_61_methodBody, _64_ctorMatch); + _62_k = (_62_k) + (BigInteger.One); } - _33_methodBody = Dafny.Sequence<Dafny.Rune>.Concat(_33_methodBody, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("}\n")); - _27_implBody = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(_27_implBody, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("pub fn r#")), (_31_formal).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("(&self) -> &")), _32_formalType), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" {\n")), _33_methodBody), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("}\n")); + _61_methodBody = Dafny.Sequence<Dafny.Rune>.Concat(_61_methodBody, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("}\n")); + _54_implBody = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(_54_implBody, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("pub fn r#")), (_59_formal).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("(&self) -> &")), _60_formalType), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" {\n")), _61_methodBody), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("}\n")); } - _30_j = (_30_j) + (BigInteger.One); + _58_j = (_58_j) + (BigInteger.One); } - _20_i = (_20_i) + (BigInteger.One); + _47_i = (_47_i) + (BigInteger.One); } - Dafny.ISequence<Dafny.Rune> _40_constrainedTypeParams; - _40_constrainedTypeParams = Dafny.Sequence<Dafny.Rune>.UnicodeFromString(""); + Dafny.ISequence<Dafny.Rune> _68_constrainedTypeParams; + _68_constrainedTypeParams = Dafny.Sequence<Dafny.Rune>.UnicodeFromString(""); if ((new BigInteger(((c).dtor_typeParams).Count)).Sign == 1) { - _16_tpI = BigInteger.Zero; - _40_constrainedTypeParams = Dafny.Sequence<Dafny.Rune>.UnicodeFromString("<"); - while ((_16_tpI) < (new BigInteger(((c).dtor_typeParams).Count))) { - if ((_16_tpI).Sign == 1) { - _40_constrainedTypeParams = Dafny.Sequence<Dafny.Rune>.Concat(_40_constrainedTypeParams, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(", ")); + _43_tpI = BigInteger.Zero; + _68_constrainedTypeParams = Dafny.Sequence<Dafny.Rune>.UnicodeFromString("<"); + while ((_43_tpI) < (new BigInteger(((c).dtor_typeParams).Count))) { + if ((_43_tpI).Sign == 1) { + _68_constrainedTypeParams = Dafny.Sequence<Dafny.Rune>.Concat(_68_constrainedTypeParams, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(", ")); } - DAST._IType _41_tp; - _41_tp = ((c).dtor_typeParams).Select(_16_tpI); - Dafny.ISequence<Dafny.Rune> _42_genTp; - Dafny.ISequence<Dafny.Rune> _out11; - _out11 = DCOMP.COMP.GenType(_41_tp); - _42_genTp = _out11; - _40_constrainedTypeParams = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(_40_constrainedTypeParams, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#")), _42_genTp), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(": Clone + ::std::cmp::PartialEq + ::dafny_runtime::DafnyPrint + ::std::default::Default + 'static")); - _16_tpI = (_16_tpI) + (BigInteger.One); + DAST._IType _69_tp; + _69_tp = ((c).dtor_typeParams).Select(_43_tpI); + Dafny.ISequence<Dafny.Rune> _70_genTp; + Dafny.ISequence<Dafny.Rune> _out20; + _out20 = DCOMP.COMP.GenType(_69_tp, false); + _70_genTp = _out20; + _68_constrainedTypeParams = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(_68_constrainedTypeParams, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#")), _70_genTp), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(": Clone + ::std::cmp::PartialEq + ::dafny_runtime::DafnyPrint + ::std::default::Default + 'static")); + _43_tpI = (_43_tpI) + (BigInteger.One); } - _40_constrainedTypeParams = Dafny.Sequence<Dafny.Rune>.Concat(_40_constrainedTypeParams, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(">")); + _68_constrainedTypeParams = Dafny.Sequence<Dafny.Rune>.Concat(_68_constrainedTypeParams, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(">")); } - Dafny.ISequence<Dafny.Rune> _43_enumBody; - _43_enumBody = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("#[derive(PartialEq)]\npub enum r#"), (c).dtor_name), _15_typeParams), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" {\n")), _19_ctors), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n}")), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n")), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("impl ")), _40_constrainedTypeParams), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" r#")), (c).dtor_name), _15_typeParams), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" {\n")), _27_implBody), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n}")); - Dafny.ISequence<Dafny.Rune> _44_printImpl; - _44_printImpl = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("impl "), _40_constrainedTypeParams), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" ::dafny_runtime::DafnyPrint for r#")), (c).dtor_name), _15_typeParams), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" {\n")), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("fn fmt_print(&self, f: &mut ::std::fmt::Formatter) -> std::fmt::Result {\n")), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("match self {\n")); - _20_i = BigInteger.Zero; - while ((_20_i) < (new BigInteger(((c).dtor_ctors).Count))) { - DAST._IDatatypeCtor _45_ctor; - _45_ctor = ((c).dtor_ctors).Select(_20_i); - Dafny.ISequence<Dafny.Rune> _46_ctorMatch; - _46_ctorMatch = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#"), (_45_ctor).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" { ")); - Dafny.ISequence<Dafny.Rune> _47_modulePrefix; - _47_modulePrefix = (((((c).dtor_enclosingModule)).Equals(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("_module"))) ? (Dafny.Sequence<Dafny.Rune>.UnicodeFromString("")) : (Dafny.Sequence<Dafny.Rune>.Concat(((c).dtor_enclosingModule), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(".")))); - Dafny.ISequence<Dafny.Rune> _48_printRhs; - _48_printRhs = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("write!(f, \""), _47_modulePrefix), (c).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(".")), (_45_ctor).dtor_name), (((_45_ctor).dtor_hasAnyArgs) ? (Dafny.Sequence<Dafny.Rune>.UnicodeFromString("(\")?;")) : (Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\")?;")))); - BigInteger _49_j; - _49_j = BigInteger.Zero; - while ((_49_j) < (new BigInteger(((_45_ctor).dtor_args).Count))) { - DAST._IFormal _50_formal; - _50_formal = ((_45_ctor).dtor_args).Select(_49_j); - _46_ctorMatch = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(_46_ctorMatch, (_50_formal).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(", ")); - if ((_49_j).Sign == 1) { - _48_printRhs = Dafny.Sequence<Dafny.Rune>.Concat(_48_printRhs, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\nwrite!(f, \", \")?;")); + Dafny.ISequence<Dafny.Rune> _71_enumBody; + _71_enumBody = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("#[derive(PartialEq)]\npub enum r#"), (c).dtor_name), _42_typeParams), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" {\n")), _46_ctors), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n}")), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n")), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("impl ")), _68_constrainedTypeParams), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" r#")), (c).dtor_name), _42_typeParams), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" {\n")), _54_implBody), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n}")); + Dafny.ISequence<Dafny.Rune> _72_printImpl; + _72_printImpl = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("impl "), _68_constrainedTypeParams), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" ::dafny_runtime::DafnyPrint for r#")), (c).dtor_name), _42_typeParams), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" {\n")), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("fn fmt_print(&self, f: &mut ::std::fmt::Formatter) -> std::fmt::Result {\n")), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("match self {\n")); + _47_i = BigInteger.Zero; + while ((_47_i) < (new BigInteger(((c).dtor_ctors).Count))) { + DAST._IDatatypeCtor _73_ctor; + _73_ctor = ((c).dtor_ctors).Select(_47_i); + Dafny.ISequence<Dafny.Rune> _74_ctorMatch; + _74_ctorMatch = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#"), (_73_ctor).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" { ")); + Dafny.ISequence<Dafny.Rune> _75_modulePrefix; + _75_modulePrefix = (((((c).dtor_enclosingModule)).Equals(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("_module"))) ? (Dafny.Sequence<Dafny.Rune>.UnicodeFromString("")) : (Dafny.Sequence<Dafny.Rune>.Concat(((c).dtor_enclosingModule), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(".")))); + Dafny.ISequence<Dafny.Rune> _76_printRhs; + _76_printRhs = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("write!(f, \""), _75_modulePrefix), (c).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(".")), (_73_ctor).dtor_name), (((_73_ctor).dtor_hasAnyArgs) ? (Dafny.Sequence<Dafny.Rune>.UnicodeFromString("(\")?;")) : (Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\")?;")))); + BigInteger _77_j; + _77_j = BigInteger.Zero; + while ((_77_j) < (new BigInteger(((_73_ctor).dtor_args).Count))) { + DAST._IFormal _78_formal; + _78_formal = ((_73_ctor).dtor_args).Select(_77_j); + _74_ctorMatch = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(_74_ctorMatch, (_78_formal).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(", ")); + if ((_77_j).Sign == 1) { + _76_printRhs = Dafny.Sequence<Dafny.Rune>.Concat(_76_printRhs, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\nwrite!(f, \", \")?;")); } - _48_printRhs = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(_48_printRhs, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n::dafny_runtime::DafnyPrint::fmt_print(")), (_50_formal).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(", f)?;")); - _49_j = (_49_j) + (BigInteger.One); + _76_printRhs = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(_76_printRhs, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n::dafny_runtime::DafnyPrint::fmt_print(")), (_78_formal).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(", f)?;")); + _77_j = (_77_j) + (BigInteger.One); } - _46_ctorMatch = Dafny.Sequence<Dafny.Rune>.Concat(_46_ctorMatch, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("}")); - if ((_45_ctor).dtor_hasAnyArgs) { - _48_printRhs = Dafny.Sequence<Dafny.Rune>.Concat(_48_printRhs, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\nwrite!(f, \")\")?;")); + _74_ctorMatch = Dafny.Sequence<Dafny.Rune>.Concat(_74_ctorMatch, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("}")); + if ((_73_ctor).dtor_hasAnyArgs) { + _76_printRhs = Dafny.Sequence<Dafny.Rune>.Concat(_76_printRhs, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\nwrite!(f, \")\")?;")); } - _48_printRhs = Dafny.Sequence<Dafny.Rune>.Concat(_48_printRhs, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\nOk(())")); - _44_printImpl = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(_44_printImpl, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#")), (c).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("::")), _46_ctorMatch), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" => {\n")), _48_printRhs), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n}\n")); - _20_i = (_20_i) + (BigInteger.One); + _76_printRhs = Dafny.Sequence<Dafny.Rune>.Concat(_76_printRhs, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\nOk(())")); + _72_printImpl = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(_72_printImpl, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#")), (c).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("::")), _74_ctorMatch), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" => {\n")), _76_printRhs), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n}\n")); + _47_i = (_47_i) + (BigInteger.One); } - _44_printImpl = Dafny.Sequence<Dafny.Rune>.Concat(_44_printImpl, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("}\n}\n}\n")); - Dafny.ISequence<Dafny.Rune> _51_defaultImpl; - _51_defaultImpl = Dafny.Sequence<Dafny.Rune>.UnicodeFromString(""); + _72_printImpl = Dafny.Sequence<Dafny.Rune>.Concat(_72_printImpl, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("}\n}\n}\n")); + Dafny.ISequence<Dafny.Rune> _79_defaultImpl; + _79_defaultImpl = Dafny.Sequence<Dafny.Rune>.UnicodeFromString(""); if ((new BigInteger(((c).dtor_ctors).Count)).Sign == 1) { - _51_defaultImpl = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("impl "), _40_constrainedTypeParams), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" ::std::default::Default for r#")), (c).dtor_name), _15_typeParams), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" {\n")), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("fn default() -> Self {\n")), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#")), (c).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("::r#")), (((c).dtor_ctors).Select(BigInteger.Zero)).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" {\n")); - _20_i = BigInteger.Zero; - while ((_20_i) < (new BigInteger(((((c).dtor_ctors).Select(BigInteger.Zero)).dtor_args).Count))) { - DAST._IFormal _52_formal; - _52_formal = ((((c).dtor_ctors).Select(BigInteger.Zero)).dtor_args).Select(_20_i); - _51_defaultImpl = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(_51_defaultImpl, (_52_formal).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(": std::default::Default::default(),\n")); - _20_i = (_20_i) + (BigInteger.One); + _79_defaultImpl = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("impl "), _68_constrainedTypeParams), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" ::std::default::Default for r#")), (c).dtor_name), _42_typeParams), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" {\n")), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("fn default() -> Self {\n")), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#")), (c).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("::r#")), (((c).dtor_ctors).Select(BigInteger.Zero)).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" {\n")); + _47_i = BigInteger.Zero; + while ((_47_i) < (new BigInteger(((((c).dtor_ctors).Select(BigInteger.Zero)).dtor_args).Count))) { + DAST._IFormal _80_formal; + _80_formal = ((((c).dtor_ctors).Select(BigInteger.Zero)).dtor_args).Select(_47_i); + _79_defaultImpl = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(_79_defaultImpl, (_80_formal).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(": std::default::Default::default(),\n")); + _47_i = (_47_i) + (BigInteger.One); } - _51_defaultImpl = Dafny.Sequence<Dafny.Rune>.Concat(_51_defaultImpl, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("}\n}\n}\n")); + _79_defaultImpl = Dafny.Sequence<Dafny.Rune>.Concat(_79_defaultImpl, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("}\n}\n}\n")); } - s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(_43_enumBody, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n")), _44_printImpl), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n")), _51_defaultImpl); + s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(_71_enumBody, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n")), _72_printImpl), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n")), _79_defaultImpl); return s; } public static Dafny.ISequence<Dafny.Rune> GenPath(Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> p) { @@ -3000,602 +3450,670 @@ public COMP() { return s; } else { s = Dafny.Sequence<Dafny.Rune>.UnicodeFromString("super::"); - BigInteger _53_i; - _53_i = BigInteger.Zero; - while ((_53_i) < (new BigInteger((p).Count))) { - if ((_53_i).Sign == 1) { + BigInteger _81_i; + _81_i = BigInteger.Zero; + while ((_81_i) < (new BigInteger((p).Count))) { + if ((_81_i).Sign == 1) { s = Dafny.Sequence<Dafny.Rune>.Concat(s, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("::")); } - s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(s, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#")), ((p).Select(_53_i))); - _53_i = (_53_i) + (BigInteger.One); + s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(s, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#")), ((p).Select(_81_i))); + _81_i = (_81_i) + (BigInteger.One); } } return s; } - public static Dafny.ISequence<Dafny.Rune> GenType(DAST._IType c) { + public static Dafny.ISequence<Dafny.Rune> GenTypeArgs(Dafny.ISequence<DAST._IType> args, bool inBinding) { Dafny.ISequence<Dafny.Rune> s = Dafny.Sequence<Dafny.Rune>.Empty; - DAST._IType _source1 = c; - if (_source1.is_Path) { - Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _54___mcc_h0 = _source1.dtor_Path_a0; - Dafny.ISequence<DAST._IType> _55___mcc_h1 = _source1.dtor_typeArgs; - DAST._IResolvedType _56___mcc_h2 = _source1.dtor_resolved; - DAST._IResolvedType _57_resolved = _56___mcc_h2; - Dafny.ISequence<DAST._IType> _58_args = _55___mcc_h1; - Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _59_p = _54___mcc_h0; - { - Dafny.ISequence<Dafny.Rune> _out12; - _out12 = DCOMP.COMP.GenPath(_59_p); - s = _out12; - if ((new BigInteger((_58_args).Count)).Sign == 1) { - s = Dafny.Sequence<Dafny.Rune>.Concat(s, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("<")); - BigInteger _60_i; - _60_i = BigInteger.Zero; - while ((_60_i) < (new BigInteger((_58_args).Count))) { - if ((_60_i).Sign == 1) { - s = Dafny.Sequence<Dafny.Rune>.Concat(s, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(", ")); - } - Dafny.ISequence<Dafny.Rune> _61_genTp; - Dafny.ISequence<Dafny.Rune> _out13; - _out13 = DCOMP.COMP.GenType((_58_args).Select(_60_i)); - _61_genTp = _out13; - s = Dafny.Sequence<Dafny.Rune>.Concat(s, _61_genTp); - _60_i = (_60_i) + (BigInteger.One); - } - s = Dafny.Sequence<Dafny.Rune>.Concat(s, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(">")); + s = Dafny.Sequence<Dafny.Rune>.UnicodeFromString(""); + if ((new BigInteger((args).Count)).Sign == 1) { + s = Dafny.Sequence<Dafny.Rune>.Concat(s, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("<")); + BigInteger _82_i; + _82_i = BigInteger.Zero; + while ((_82_i) < (new BigInteger((args).Count))) { + if ((_82_i).Sign == 1) { + s = Dafny.Sequence<Dafny.Rune>.Concat(s, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(", ")); } - DAST._IResolvedType _source2 = _57_resolved; - if (_source2.is_Datatype) { - Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _62___mcc_h8 = _source2.dtor_path; + Dafny.ISequence<Dafny.Rune> _83_genTp; + Dafny.ISequence<Dafny.Rune> _out21; + _out21 = DCOMP.COMP.GenType((args).Select(_82_i), inBinding); + _83_genTp = _out21; + s = Dafny.Sequence<Dafny.Rune>.Concat(s, _83_genTp); + _82_i = (_82_i) + (BigInteger.One); + } + s = Dafny.Sequence<Dafny.Rune>.Concat(s, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(">")); + } + return s; + } + public static Dafny.ISequence<Dafny.Rune> GenType(DAST._IType c, bool inBinding) { + Dafny.ISequence<Dafny.Rune> s = Dafny.Sequence<Dafny.Rune>.Empty; + DAST._IType _source3 = c; + if (_source3.is_Path) { + Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _84___mcc_h0 = _source3.dtor_Path_a0; + Dafny.ISequence<DAST._IType> _85___mcc_h1 = _source3.dtor_typeArgs; + DAST._IResolvedType _86___mcc_h2 = _source3.dtor_resolved; + DAST._IResolvedType _87_resolved = _86___mcc_h2; + Dafny.ISequence<DAST._IType> _88_args = _85___mcc_h1; + Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _89_p = _84___mcc_h0; + { + Dafny.ISequence<Dafny.Rune> _out22; + _out22 = DCOMP.COMP.GenPath(_89_p); + s = _out22; + Dafny.ISequence<Dafny.Rune> _90_typeArgs; + Dafny.ISequence<Dafny.Rune> _out23; + _out23 = DCOMP.COMP.GenTypeArgs(_88_args, inBinding); + _90_typeArgs = _out23; + s = Dafny.Sequence<Dafny.Rune>.Concat(s, _90_typeArgs); + DAST._IResolvedType _source4 = _87_resolved; + if (_source4.is_Datatype) { + Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _91___mcc_h8 = _source4.dtor_path; { s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("::std::rc::Rc<"), s), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(">")); } + } else if (_source4.is_Trait) { + Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _92___mcc_h10 = _source4.dtor_path; + { + if (inBinding) { + s = Dafny.Sequence<Dafny.Rune>.UnicodeFromString("_"); + } else { + s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("impl "), s), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("")); + } + } } else { - DAST._IResolvedType _63_Primitive = _57_resolved; + DAST._IResolvedType _93_Primitive = _87_resolved; } } - } else if (_source1.is_Tuple) { - Dafny.ISequence<DAST._IType> _64___mcc_h3 = _source1.dtor_Tuple_a0; - Dafny.ISequence<DAST._IType> _65_types = _64___mcc_h3; + } else if (_source3.is_Tuple) { + Dafny.ISequence<DAST._IType> _94___mcc_h3 = _source3.dtor_Tuple_a0; + Dafny.ISequence<DAST._IType> _95_types = _94___mcc_h3; { s = Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("); - BigInteger _66_i; - _66_i = BigInteger.Zero; - while ((_66_i) < (new BigInteger((_65_types).Count))) { - if ((_66_i).Sign == 1) { + BigInteger _96_i; + _96_i = BigInteger.Zero; + while ((_96_i) < (new BigInteger((_95_types).Count))) { + if ((_96_i).Sign == 1) { s = Dafny.Sequence<Dafny.Rune>.Concat(s, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" ")); } - Dafny.ISequence<Dafny.Rune> _67_generated; - Dafny.ISequence<Dafny.Rune> _out14; - _out14 = DCOMP.COMP.GenType((_65_types).Select(_66_i)); - _67_generated = _out14; - s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(s, _67_generated), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(",")); - _66_i = (_66_i) + (BigInteger.One); + Dafny.ISequence<Dafny.Rune> _97_generated; + Dafny.ISequence<Dafny.Rune> _out24; + _out24 = DCOMP.COMP.GenType((_95_types).Select(_96_i), inBinding); + _97_generated = _out24; + s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(s, _97_generated), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(",")); + _96_i = (_96_i) + (BigInteger.One); } s = Dafny.Sequence<Dafny.Rune>.Concat(s, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(")")); } - } else if (_source1.is_Primitive) { - DAST._IPrimitive _68___mcc_h4 = _source1.dtor_Primitive_a0; - DAST._IPrimitive _69_p = _68___mcc_h4; + } else if (_source3.is_Primitive) { + DAST._IPrimitive _98___mcc_h4 = _source3.dtor_Primitive_a0; + DAST._IPrimitive _99_p = _98___mcc_h4; { - DAST._IPrimitive _source3 = _69_p; - if (_source3.is_String) { + DAST._IPrimitive _source5 = _99_p; + if (_source5.is_String) { s = Dafny.Sequence<Dafny.Rune>.UnicodeFromString("String"); - } else if (_source3.is_Bool) { + } else if (_source5.is_Bool) { s = Dafny.Sequence<Dafny.Rune>.UnicodeFromString("bool"); } else { s = Dafny.Sequence<Dafny.Rune>.UnicodeFromString("char"); } } - } else if (_source1.is_Passthrough) { - Dafny.ISequence<Dafny.Rune> _70___mcc_h5 = _source1.dtor_Passthrough_a0; - Dafny.ISequence<Dafny.Rune> _71_v = _70___mcc_h5; - s = _71_v; + } else if (_source3.is_Passthrough) { + Dafny.ISequence<Dafny.Rune> _100___mcc_h5 = _source3.dtor_Passthrough_a0; + Dafny.ISequence<Dafny.Rune> _101_v = _100___mcc_h5; + s = _101_v; } else { - Dafny.ISequence<Dafny.Rune> _72___mcc_h6 = _source1.dtor_TypeArg_a0; - Dafny.ISequence<Dafny.Rune> _source4 = _72___mcc_h6; - Dafny.ISequence<Dafny.Rune> _73___mcc_h7 = _source4; - Dafny.ISequence<Dafny.Rune> _74_name = _73___mcc_h7; - s = _74_name; + Dafny.ISequence<Dafny.Rune> _102___mcc_h6 = _source3.dtor_TypeArg_a0; + Dafny.ISequence<Dafny.Rune> _source6 = _102___mcc_h6; + Dafny.ISequence<Dafny.Rune> _103___mcc_h7 = _source6; + Dafny.ISequence<Dafny.Rune> _104_name = _103___mcc_h7; + s = _104_name; } return s; } - public static Dafny.ISequence<Dafny.Rune> GenClassImplBody(Dafny.ISequence<DAST._IClassItem> body, DAST._IType enclosingType, Dafny.ISet<DAST._IType> enclosingTypeParams) { - Dafny.ISequence<Dafny.Rune> s = Dafny.Sequence<Dafny.Rune>.Empty; + public static void GenClassImplBody(Dafny.ISequence<DAST._IClassItem> body, bool forTrait, DAST._IType enclosingType, Dafny.ISet<DAST._IType> enclosingTypeParams, out Dafny.ISequence<Dafny.Rune> s, out Dafny.IMap<Dafny.ISequence<Dafny.ISequence<Dafny.Rune>>, Dafny.ISequence<Dafny.Rune>> traitBodies) { + s = Dafny.Sequence<Dafny.Rune>.Empty; + traitBodies = Dafny.Map<Dafny.ISequence<Dafny.ISequence<Dafny.Rune>>, Dafny.ISequence<Dafny.Rune>>.Empty; s = Dafny.Sequence<Dafny.Rune>.UnicodeFromString(""); - BigInteger _75_i; - _75_i = BigInteger.Zero; - while ((_75_i) < (new BigInteger((body).Count))) { - Dafny.ISequence<Dafny.Rune> _76_generated = Dafny.Sequence<Dafny.Rune>.Empty; - DAST._IClassItem _source5 = (body).Select(_75_i); - if (_source5.is_Method) { - DAST._IMethod _77___mcc_h0 = _source5.dtor_Method_a0; - DAST._IMethod _78_m = _77___mcc_h0; - Dafny.ISequence<Dafny.Rune> _out15; - _out15 = DCOMP.COMP.GenMethod(_78_m, enclosingType, enclosingTypeParams); - _76_generated = _out15; + traitBodies = Dafny.Map<Dafny.ISequence<Dafny.ISequence<Dafny.Rune>>, Dafny.ISequence<Dafny.Rune>>.FromElements(); + BigInteger _105_i; + _105_i = BigInteger.Zero; + while ((_105_i) < (new BigInteger((body).Count))) { + DAST._IClassItem _source7 = (body).Select(_105_i); + if (_source7.is_Method) { + DAST._IMethod _106___mcc_h0 = _source7.dtor_Method_a0; + DAST._IMethod _107_m = _106___mcc_h0; + { + DAST._IOptional<Dafny.ISequence<Dafny.ISequence<Dafny.Rune>>> _source8 = (_107_m).dtor_overridingPath; + if (_source8.is_Some) { + Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _108___mcc_h2 = _source8.dtor_Some_a0; + Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _109_p = _108___mcc_h2; + { + Dafny.ISequence<Dafny.Rune> _110_existing; + _110_existing = Dafny.Sequence<Dafny.Rune>.UnicodeFromString(""); + if ((traitBodies).Contains(_109_p)) { + _110_existing = Dafny.Map<Dafny.ISequence<Dafny.ISequence<Dafny.Rune>>, Dafny.ISequence<Dafny.Rune>>.Select(traitBodies, _109_p); + } + if ((new BigInteger((_110_existing).Count)).Sign == 1) { + _110_existing = Dafny.Sequence<Dafny.Rune>.Concat(_110_existing, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n")); + } + Dafny.ISequence<Dafny.Rune> _111_genMethod; + Dafny.ISequence<Dafny.Rune> _out25; + _out25 = DCOMP.COMP.GenMethod(_107_m, true, enclosingType, enclosingTypeParams); + _111_genMethod = _out25; + _110_existing = Dafny.Sequence<Dafny.Rune>.Concat(_110_existing, _111_genMethod); + traitBodies = Dafny.Map<Dafny.ISequence<Dafny.ISequence<Dafny.Rune>>, Dafny.ISequence<Dafny.Rune>>.Merge(traitBodies, Dafny.Map<Dafny.ISequence<Dafny.ISequence<Dafny.Rune>>, Dafny.ISequence<Dafny.Rune>>.FromElements(new Dafny.Pair<Dafny.ISequence<Dafny.ISequence<Dafny.Rune>>, Dafny.ISequence<Dafny.Rune>>(_109_p, _110_existing))); + } + } else { + { + Dafny.ISequence<Dafny.Rune> _112_generated; + Dafny.ISequence<Dafny.Rune> _out26; + _out26 = DCOMP.COMP.GenMethod(_107_m, forTrait, enclosingType, enclosingTypeParams); + _112_generated = _out26; + s = Dafny.Sequence<Dafny.Rune>.Concat(s, _112_generated); + } + } + } } else { - DAST._IFormal _79___mcc_h1 = _source5.dtor_Field_a0; - DAST._IFormal _80_f = _79___mcc_h1; - _76_generated = Dafny.Sequence<Dafny.Rune>.UnicodeFromString("TODO"); + DAST._IFormal _113___mcc_h1 = _source7.dtor_Field_a0; + DAST._IFormal _114_f = _113___mcc_h1; } - if ((_75_i).Sign == 1) { + if ((new BigInteger((s).Count)).Sign == 1) { s = Dafny.Sequence<Dafny.Rune>.Concat(s, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n")); } - s = Dafny.Sequence<Dafny.Rune>.Concat(s, _76_generated); - _75_i = (_75_i) + (BigInteger.One); + _105_i = (_105_i) + (BigInteger.One); } - return s; } public static Dafny.ISequence<Dafny.Rune> GenParams(Dafny.ISequence<DAST._IFormal> @params) { Dafny.ISequence<Dafny.Rune> s = Dafny.Sequence<Dafny.Rune>.Empty; s = Dafny.Sequence<Dafny.Rune>.UnicodeFromString(""); - BigInteger _81_i; - _81_i = BigInteger.Zero; - while ((_81_i) < (new BigInteger((@params).Count))) { - DAST._IFormal _82_param; - _82_param = (@params).Select(_81_i); - Dafny.ISequence<Dafny.Rune> _83_paramType; - Dafny.ISequence<Dafny.Rune> _out16; - _out16 = DCOMP.COMP.GenType((_82_param).dtor_typ); - _83_paramType = _out16; - s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(s, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#")), (_82_param).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(": &")), _83_paramType); - if ((_81_i) < ((new BigInteger((@params).Count)) - (BigInteger.One))) { + BigInteger _115_i; + _115_i = BigInteger.Zero; + while ((_115_i) < (new BigInteger((@params).Count))) { + DAST._IFormal _116_param; + _116_param = (@params).Select(_115_i); + Dafny.ISequence<Dafny.Rune> _117_paramType; + Dafny.ISequence<Dafny.Rune> _out27; + _out27 = DCOMP.COMP.GenType((_116_param).dtor_typ, false); + _117_paramType = _out27; + s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(s, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#")), (_116_param).dtor_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(": &")), _117_paramType); + if ((_115_i) < ((new BigInteger((@params).Count)) - (BigInteger.One))) { s = Dafny.Sequence<Dafny.Rune>.Concat(s, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(", ")); } - _81_i = (_81_i) + (BigInteger.One); + _115_i = (_115_i) + (BigInteger.One); } return s; } - public static Dafny.ISequence<Dafny.Rune> GenMethod(DAST._IMethod m, DAST._IType enclosingType, Dafny.ISet<DAST._IType> enclosingTypeParams) { + public static Dafny.ISequence<Dafny.Rune> GenMethod(DAST._IMethod m, bool forTrait, DAST._IType enclosingType, Dafny.ISet<DAST._IType> enclosingTypeParams) { Dafny.ISequence<Dafny.Rune> s = Dafny.Sequence<Dafny.Rune>.Empty; - Dafny.ISequence<Dafny.Rune> _84_params; - Dafny.ISequence<Dafny.Rune> _out17; - _out17 = DCOMP.COMP.GenParams((m).dtor_params); - _84_params = _out17; - Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _85_paramNames; - _85_paramNames = Dafny.Sequence<Dafny.ISequence<Dafny.Rune>>.FromElements(); - BigInteger _86_paramI; - _86_paramI = BigInteger.Zero; - while ((_86_paramI) < (new BigInteger(((m).dtor_params).Count))) { - _85_paramNames = Dafny.Sequence<Dafny.ISequence<Dafny.Rune>>.Concat(_85_paramNames, Dafny.Sequence<Dafny.ISequence<Dafny.Rune>>.FromElements((((m).dtor_params).Select(_86_paramI)).dtor_name)); - _86_paramI = (_86_paramI) + (BigInteger.One); + Dafny.ISequence<Dafny.Rune> _118_params; + Dafny.ISequence<Dafny.Rune> _out28; + _out28 = DCOMP.COMP.GenParams((m).dtor_params); + _118_params = _out28; + Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _119_paramNames; + _119_paramNames = Dafny.Sequence<Dafny.ISequence<Dafny.Rune>>.FromElements(); + BigInteger _120_paramI; + _120_paramI = BigInteger.Zero; + while ((_120_paramI) < (new BigInteger(((m).dtor_params).Count))) { + _119_paramNames = Dafny.Sequence<Dafny.ISequence<Dafny.Rune>>.Concat(_119_paramNames, Dafny.Sequence<Dafny.ISequence<Dafny.Rune>>.FromElements((((m).dtor_params).Select(_120_paramI)).dtor_name)); + _120_paramI = (_120_paramI) + (BigInteger.One); } if (!((m).dtor_isStatic)) { - Dafny.ISequence<Dafny.Rune> _87_enclosingTypeString; - Dafny.ISequence<Dafny.Rune> _out18; - _out18 = DCOMP.COMP.GenType(enclosingType); - _87_enclosingTypeString = _out18; - _84_params = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("self: &"), _87_enclosingTypeString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(", ")), _84_params); + if (forTrait) { + _118_params = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("&self"), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(", ")), _118_params); + } else { + Dafny.ISequence<Dafny.Rune> _121_enclosingTypeString; + Dafny.ISequence<Dafny.Rune> _out29; + _out29 = DCOMP.COMP.GenType(enclosingType, false); + _121_enclosingTypeString = _out29; + _118_params = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("self: &"), _121_enclosingTypeString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(", ")), _118_params); + } } - Dafny.ISequence<Dafny.Rune> _88_retType; - _88_retType = (((new BigInteger(((m).dtor_outTypes).Count)) != (BigInteger.One)) ? (Dafny.Sequence<Dafny.Rune>.UnicodeFromString("(")) : (Dafny.Sequence<Dafny.Rune>.UnicodeFromString(""))); - BigInteger _89_typeI; - _89_typeI = BigInteger.Zero; - while ((_89_typeI) < (new BigInteger(((m).dtor_outTypes).Count))) { - if ((_89_typeI).Sign == 1) { - _88_retType = Dafny.Sequence<Dafny.Rune>.Concat(_88_retType, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(", ")); + Dafny.ISequence<Dafny.Rune> _122_retType; + _122_retType = (((new BigInteger(((m).dtor_outTypes).Count)) != (BigInteger.One)) ? (Dafny.Sequence<Dafny.Rune>.UnicodeFromString("(")) : (Dafny.Sequence<Dafny.Rune>.UnicodeFromString(""))); + BigInteger _123_typeI; + _123_typeI = BigInteger.Zero; + while ((_123_typeI) < (new BigInteger(((m).dtor_outTypes).Count))) { + if ((_123_typeI).Sign == 1) { + _122_retType = Dafny.Sequence<Dafny.Rune>.Concat(_122_retType, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(", ")); } - Dafny.ISequence<Dafny.Rune> _90_typeString; - Dafny.ISequence<Dafny.Rune> _out19; - _out19 = DCOMP.COMP.GenType(((m).dtor_outTypes).Select(_89_typeI)); - _90_typeString = _out19; - _88_retType = Dafny.Sequence<Dafny.Rune>.Concat(_88_retType, _90_typeString); - _89_typeI = (_89_typeI) + (BigInteger.One); + Dafny.ISequence<Dafny.Rune> _124_typeString; + Dafny.ISequence<Dafny.Rune> _out30; + _out30 = DCOMP.COMP.GenType(((m).dtor_outTypes).Select(_123_typeI), false); + _124_typeString = _out30; + _122_retType = Dafny.Sequence<Dafny.Rune>.Concat(_122_retType, _124_typeString); + _123_typeI = (_123_typeI) + (BigInteger.One); } if ((new BigInteger(((m).dtor_outTypes).Count)) != (BigInteger.One)) { - _88_retType = Dafny.Sequence<Dafny.Rune>.Concat(_88_retType, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(")")); + _122_retType = Dafny.Sequence<Dafny.Rune>.Concat(_122_retType, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(")")); + } + if (forTrait) { + s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("fn r#"), (m).dtor_name); + } else { + s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("pub fn r#"), (m).dtor_name); } - s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("pub fn r#"), (m).dtor_name); - Dafny.ISequence<DAST._IType> _91_typeParamsFiltered; - _91_typeParamsFiltered = Dafny.Sequence<DAST._IType>.FromElements(); - BigInteger _92_typeParamI; - _92_typeParamI = BigInteger.Zero; - while ((_92_typeParamI) < (new BigInteger(((m).dtor_typeParams).Count))) { - DAST._IType _93_typeParam; - _93_typeParam = ((m).dtor_typeParams).Select(_92_typeParamI); - if (!((enclosingTypeParams).Contains(_93_typeParam))) { - _91_typeParamsFiltered = Dafny.Sequence<DAST._IType>.Concat(_91_typeParamsFiltered, Dafny.Sequence<DAST._IType>.FromElements(_93_typeParam)); + Dafny.ISequence<DAST._IType> _125_typeParamsFiltered; + _125_typeParamsFiltered = Dafny.Sequence<DAST._IType>.FromElements(); + BigInteger _126_typeParamI; + _126_typeParamI = BigInteger.Zero; + while ((_126_typeParamI) < (new BigInteger(((m).dtor_typeParams).Count))) { + DAST._IType _127_typeParam; + _127_typeParam = ((m).dtor_typeParams).Select(_126_typeParamI); + if (!((enclosingTypeParams).Contains(_127_typeParam))) { + _125_typeParamsFiltered = Dafny.Sequence<DAST._IType>.Concat(_125_typeParamsFiltered, Dafny.Sequence<DAST._IType>.FromElements(_127_typeParam)); } - _92_typeParamI = (_92_typeParamI) + (BigInteger.One); + _126_typeParamI = (_126_typeParamI) + (BigInteger.One); } - if ((new BigInteger((_91_typeParamsFiltered).Count)).Sign == 1) { + if ((new BigInteger((_125_typeParamsFiltered).Count)).Sign == 1) { s = Dafny.Sequence<Dafny.Rune>.Concat(s, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("<")); - BigInteger _94_i; - _94_i = BigInteger.Zero; - while ((_94_i) < (new BigInteger((_91_typeParamsFiltered).Count))) { - if ((_94_i).Sign == 1) { + BigInteger _128_i; + _128_i = BigInteger.Zero; + while ((_128_i) < (new BigInteger((_125_typeParamsFiltered).Count))) { + if ((_128_i).Sign == 1) { s = Dafny.Sequence<Dafny.Rune>.Concat(s, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(", ")); } - Dafny.ISequence<Dafny.Rune> _95_typeString; - Dafny.ISequence<Dafny.Rune> _out20; - _out20 = DCOMP.COMP.GenType((_91_typeParamsFiltered).Select(_94_i)); - _95_typeString = _out20; - s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(s, _95_typeString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(": Clone + ::std::cmp::PartialEq + ::dafny_runtime::DafnyPrint + ::std::default::Default + 'static")); - _94_i = (_94_i) + (BigInteger.One); + Dafny.ISequence<Dafny.Rune> _129_typeString; + Dafny.ISequence<Dafny.Rune> _out31; + _out31 = DCOMP.COMP.GenType((_125_typeParamsFiltered).Select(_128_i), false); + _129_typeString = _out31; + s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(s, _129_typeString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(": Clone + ::std::cmp::PartialEq + ::dafny_runtime::DafnyPrint + ::std::default::Default + 'static")); + _128_i = (_128_i) + (BigInteger.One); } s = Dafny.Sequence<Dafny.Rune>.Concat(s, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(">")); } - Dafny.ISequence<Dafny.Rune> _96_earlyReturn; - _96_earlyReturn = Dafny.Sequence<Dafny.Rune>.UnicodeFromString("return;"); - DAST._IOptional<Dafny.ISequence<Dafny.ISequence<Dafny.Rune>>> _source6 = (m).dtor_outVars; - if (_source6.is_Some) { - Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _97___mcc_h0 = _source6.dtor_Some_a0; - Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _98_outVars = _97___mcc_h0; - { - _96_earlyReturn = Dafny.Sequence<Dafny.Rune>.UnicodeFromString("return ("); - BigInteger _99_outI; - _99_outI = BigInteger.Zero; - while ((_99_outI) < (new BigInteger((_98_outVars).Count))) { - if ((_99_outI).Sign == 1) { - _96_earlyReturn = Dafny.Sequence<Dafny.Rune>.Concat(_96_earlyReturn, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(", ")); + s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(s, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("(")), _118_params), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(") -> ")), _122_retType); + if ((m).dtor_hasBody) { + Dafny.ISequence<Dafny.Rune> _130_earlyReturn; + _130_earlyReturn = Dafny.Sequence<Dafny.Rune>.UnicodeFromString("return;"); + DAST._IOptional<Dafny.ISequence<Dafny.ISequence<Dafny.Rune>>> _source9 = (m).dtor_outVars; + if (_source9.is_Some) { + Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _131___mcc_h0 = _source9.dtor_Some_a0; + Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _132_outVars = _131___mcc_h0; + { + _130_earlyReturn = Dafny.Sequence<Dafny.Rune>.UnicodeFromString("return ("); + BigInteger _133_outI; + _133_outI = BigInteger.Zero; + while ((_133_outI) < (new BigInteger((_132_outVars).Count))) { + if ((_133_outI).Sign == 1) { + _130_earlyReturn = Dafny.Sequence<Dafny.Rune>.Concat(_130_earlyReturn, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(", ")); + } + Dafny.ISequence<Dafny.Rune> _134_outVar; + _134_outVar = (_132_outVars).Select(_133_outI); + _130_earlyReturn = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(_130_earlyReturn, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#")), (_134_outVar)); + _133_outI = (_133_outI) + (BigInteger.One); } - Dafny.ISequence<Dafny.Rune> _100_outVar; - _100_outVar = (_98_outVars).Select(_99_outI); - _96_earlyReturn = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(_96_earlyReturn, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#")), (_100_outVar)); - _99_outI = (_99_outI) + (BigInteger.One); + _130_earlyReturn = Dafny.Sequence<Dafny.Rune>.Concat(_130_earlyReturn, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(");")); } - _96_earlyReturn = Dafny.Sequence<Dafny.Rune>.Concat(_96_earlyReturn, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(");")); + } else { } - } else { - } - Dafny.ISequence<Dafny.Rune> _101_body; - Dafny.ISequence<Dafny.Rune> _out21; - _out21 = DCOMP.COMP.GenStmts((m).dtor_body, _85_paramNames, _96_earlyReturn); - _101_body = _out21; - DAST._IOptional<Dafny.ISequence<Dafny.ISequence<Dafny.Rune>>> _source7 = (m).dtor_outVars; - if (_source7.is_Some) { - Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _102___mcc_h1 = _source7.dtor_Some_a0; - Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _103_outVars = _102___mcc_h1; - { - _101_body = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(_101_body, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n")), _96_earlyReturn); + Dafny.ISequence<Dafny.Rune> _135_body; + Dafny.ISequence<Dafny.Rune> _out32; + _out32 = DCOMP.COMP.GenStmts((m).dtor_body, _119_paramNames, _130_earlyReturn); + _135_body = _out32; + DAST._IOptional<Dafny.ISequence<Dafny.ISequence<Dafny.Rune>>> _source10 = (m).dtor_outVars; + if (_source10.is_Some) { + Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _136___mcc_h1 = _source10.dtor_Some_a0; + Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _137_outVars = _136___mcc_h1; + { + _135_body = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(_135_body, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n")), _130_earlyReturn); + } + } else { } + s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(s, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" {\n")), _135_body), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n}\n")); } else { + s = Dafny.Sequence<Dafny.Rune>.Concat(s, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(";\n")); } - s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(s, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("(")), _84_params), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(") -> ")), _88_retType), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" {\n")), _101_body), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n}\n")); return s; } public static Dafny.ISequence<Dafny.Rune> GenStmts(Dafny.ISequence<DAST._IStatement> stmts, Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> @params, Dafny.ISequence<Dafny.Rune> earlyReturn) { Dafny.ISequence<Dafny.Rune> generated = Dafny.Sequence<Dafny.Rune>.Empty; generated = Dafny.Sequence<Dafny.Rune>.UnicodeFromString(""); - BigInteger _104_i; - _104_i = BigInteger.Zero; - while ((_104_i) < (new BigInteger((stmts).Count))) { - DAST._IStatement _105_stmt; - _105_stmt = (stmts).Select(_104_i); - Dafny.ISequence<Dafny.Rune> _106_stmtString; - Dafny.ISequence<Dafny.Rune> _out22; - _out22 = DCOMP.COMP.GenStmt(_105_stmt, @params, earlyReturn); - _106_stmtString = _out22; - if ((_104_i).Sign == 1) { + BigInteger _138_i; + _138_i = BigInteger.Zero; + while ((_138_i) < (new BigInteger((stmts).Count))) { + DAST._IStatement _139_stmt; + _139_stmt = (stmts).Select(_138_i); + Dafny.ISequence<Dafny.Rune> _140_stmtString; + Dafny.ISequence<Dafny.Rune> _out33; + _out33 = DCOMP.COMP.GenStmt(_139_stmt, @params, earlyReturn); + _140_stmtString = _out33; + if ((_138_i).Sign == 1) { generated = Dafny.Sequence<Dafny.Rune>.Concat(generated, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n")); } - generated = Dafny.Sequence<Dafny.Rune>.Concat(generated, _106_stmtString); - _104_i = (_104_i) + (BigInteger.One); + generated = Dafny.Sequence<Dafny.Rune>.Concat(generated, _140_stmtString); + _138_i = (_138_i) + (BigInteger.One); } return generated; } public static Dafny.ISequence<Dafny.Rune> GenStmt(DAST._IStatement stmt, Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> @params, Dafny.ISequence<Dafny.Rune> earlyReturn) { Dafny.ISequence<Dafny.Rune> generated = Dafny.Sequence<Dafny.Rune>.Empty; - DAST._IStatement _source8 = stmt; - if (_source8.is_DeclareVar) { - Dafny.ISequence<Dafny.Rune> _107___mcc_h0 = _source8.dtor_name; - DAST._IType _108___mcc_h1 = _source8.dtor_typ; - DAST._IOptional<DAST._IExpression> _109___mcc_h2 = _source8.dtor_maybeValue; - DAST._IOptional<DAST._IExpression> _source9 = _109___mcc_h2; - if (_source9.is_Some) { - DAST._IExpression _110___mcc_h3 = _source9.dtor_Some_a0; - DAST._IExpression _111_expression = _110___mcc_h3; - DAST._IType _112_typ = _108___mcc_h1; - Dafny.ISequence<Dafny.Rune> _113_name = _107___mcc_h0; + DAST._IStatement _source11 = stmt; + if (_source11.is_DeclareVar) { + Dafny.ISequence<Dafny.Rune> _141___mcc_h0 = _source11.dtor_name; + DAST._IType _142___mcc_h1 = _source11.dtor_typ; + DAST._IOptional<DAST._IExpression> _143___mcc_h2 = _source11.dtor_maybeValue; + DAST._IOptional<DAST._IExpression> _source12 = _143___mcc_h2; + if (_source12.is_Some) { + DAST._IExpression _144___mcc_h3 = _source12.dtor_Some_a0; + DAST._IExpression _145_expression = _144___mcc_h3; + DAST._IType _146_typ = _142___mcc_h1; + Dafny.ISequence<Dafny.Rune> _147_name = _141___mcc_h0; { - Dafny.ISequence<Dafny.Rune> _114_expr; - bool _115___v2; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _116___v3; - Dafny.ISequence<Dafny.Rune> _out23; - bool _out24; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out25; - DCOMP.COMP.GenExpr(_111_expression, @params, true, out _out23, out _out24, out _out25); - _114_expr = _out23; - _115___v2 = _out24; - _116___v3 = _out25; - Dafny.ISequence<Dafny.Rune> _117_typeString; - Dafny.ISequence<Dafny.Rune> _out26; - _out26 = DCOMP.COMP.GenType(_112_typ); - _117_typeString = _out26; - generated = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("let mut r#"), _113_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(": ")), _117_typeString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" = ")), _114_expr), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(";")); + Dafny.ISequence<Dafny.Rune> _148_expr; + bool _149___v6; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _150___v7; + Dafny.ISequence<Dafny.Rune> _out34; + bool _out35; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out36; + DCOMP.COMP.GenExpr(_145_expression, @params, true, out _out34, out _out35, out _out36); + _148_expr = _out34; + _149___v6 = _out35; + _150___v7 = _out36; + Dafny.ISequence<Dafny.Rune> _151_typeString; + Dafny.ISequence<Dafny.Rune> _out37; + _out37 = DCOMP.COMP.GenType(_146_typ, true); + _151_typeString = _out37; + generated = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("let mut r#"), _147_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(": ")), _151_typeString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" = ")), _148_expr), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(";")); } } else { - DAST._IType _118_typ = _108___mcc_h1; - Dafny.ISequence<Dafny.Rune> _119_name = _107___mcc_h0; + DAST._IType _152_typ = _142___mcc_h1; + Dafny.ISequence<Dafny.Rune> _153_name = _141___mcc_h0; { - Dafny.ISequence<Dafny.Rune> _120_typeString; - Dafny.ISequence<Dafny.Rune> _out27; - _out27 = DCOMP.COMP.GenType(_118_typ); - _120_typeString = _out27; - generated = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("let mut r#"), _119_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(": ")), _120_typeString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(";")); + Dafny.ISequence<Dafny.Rune> _154_typeString; + Dafny.ISequence<Dafny.Rune> _out38; + _out38 = DCOMP.COMP.GenType(_152_typ, true); + _154_typeString = _out38; + generated = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("let mut r#"), _153_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(": ")), _154_typeString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(";")); } } - } else if (_source8.is_Assign) { - Dafny.ISequence<Dafny.Rune> _121___mcc_h4 = _source8.dtor_name; - DAST._IExpression _122___mcc_h5 = _source8.dtor_value; - DAST._IExpression _123_expression = _122___mcc_h5; - Dafny.ISequence<Dafny.Rune> _124_name = _121___mcc_h4; + } else if (_source11.is_Assign) { + Dafny.ISequence<Dafny.Rune> _155___mcc_h4 = _source11.dtor_name; + DAST._IExpression _156___mcc_h5 = _source11.dtor_value; + DAST._IExpression _157_expression = _156___mcc_h5; + Dafny.ISequence<Dafny.Rune> _158_name = _155___mcc_h4; { - Dafny.ISequence<Dafny.Rune> _125_expr; - bool _126___v4; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _127___v5; - Dafny.ISequence<Dafny.Rune> _out28; - bool _out29; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out30; - DCOMP.COMP.GenExpr(_123_expression, @params, true, out _out28, out _out29, out _out30); - _125_expr = _out28; - _126___v4 = _out29; - _127___v5 = _out30; - generated = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#"), _124_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" = ")), _125_expr), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(";")); + Dafny.ISequence<Dafny.Rune> _159_expr; + bool _160___v8; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _161___v9; + Dafny.ISequence<Dafny.Rune> _out39; + bool _out40; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out41; + DCOMP.COMP.GenExpr(_157_expression, @params, true, out _out39, out _out40, out _out41); + _159_expr = _out39; + _160___v8 = _out40; + _161___v9 = _out41; + generated = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#"), _158_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" = ")), _159_expr), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(";")); } - } else if (_source8.is_If) { - DAST._IExpression _128___mcc_h6 = _source8.dtor_cond; - Dafny.ISequence<DAST._IStatement> _129___mcc_h7 = _source8.dtor_thn; - Dafny.ISequence<DAST._IStatement> _130___mcc_h8 = _source8.dtor_els; - Dafny.ISequence<DAST._IStatement> _131_els = _130___mcc_h8; - Dafny.ISequence<DAST._IStatement> _132_thn = _129___mcc_h7; - DAST._IExpression _133_cond = _128___mcc_h6; + } else if (_source11.is_If) { + DAST._IExpression _162___mcc_h6 = _source11.dtor_cond; + Dafny.ISequence<DAST._IStatement> _163___mcc_h7 = _source11.dtor_thn; + Dafny.ISequence<DAST._IStatement> _164___mcc_h8 = _source11.dtor_els; + Dafny.ISequence<DAST._IStatement> _165_els = _164___mcc_h8; + Dafny.ISequence<DAST._IStatement> _166_thn = _163___mcc_h7; + DAST._IExpression _167_cond = _162___mcc_h6; { - Dafny.ISequence<Dafny.Rune> _134_condString; - bool _135___v6; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _136___v7; - Dafny.ISequence<Dafny.Rune> _out31; - bool _out32; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out33; - DCOMP.COMP.GenExpr(_133_cond, @params, true, out _out31, out _out32, out _out33); - _134_condString = _out31; - _135___v6 = _out32; - _136___v7 = _out33; - Dafny.ISequence<Dafny.Rune> _137_thnString; - Dafny.ISequence<Dafny.Rune> _out34; - _out34 = DCOMP.COMP.GenStmts(_132_thn, @params, earlyReturn); - _137_thnString = _out34; - Dafny.ISequence<Dafny.Rune> _138_elsString; - Dafny.ISequence<Dafny.Rune> _out35; - _out35 = DCOMP.COMP.GenStmts(_131_els, @params, earlyReturn); - _138_elsString = _out35; - generated = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("if "), _134_condString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" {\n")), _137_thnString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n} else {\n")), _138_elsString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n}")); + Dafny.ISequence<Dafny.Rune> _168_condString; + bool _169___v10; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _170___v11; + Dafny.ISequence<Dafny.Rune> _out42; + bool _out43; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out44; + DCOMP.COMP.GenExpr(_167_cond, @params, true, out _out42, out _out43, out _out44); + _168_condString = _out42; + _169___v10 = _out43; + _170___v11 = _out44; + Dafny.ISequence<Dafny.Rune> _171_thnString; + Dafny.ISequence<Dafny.Rune> _out45; + _out45 = DCOMP.COMP.GenStmts(_166_thn, @params, earlyReturn); + _171_thnString = _out45; + Dafny.ISequence<Dafny.Rune> _172_elsString; + Dafny.ISequence<Dafny.Rune> _out46; + _out46 = DCOMP.COMP.GenStmts(_165_els, @params, earlyReturn); + _172_elsString = _out46; + generated = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("if "), _168_condString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" {\n")), _171_thnString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n} else {\n")), _172_elsString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n}")); } - } else if (_source8.is_While) { - DAST._IExpression _139___mcc_h9 = _source8.dtor_cond; - Dafny.ISequence<DAST._IStatement> _140___mcc_h10 = _source8.dtor_body; - Dafny.ISequence<DAST._IStatement> _141_body = _140___mcc_h10; - DAST._IExpression _142_cond = _139___mcc_h9; + } else if (_source11.is_While) { + DAST._IExpression _173___mcc_h9 = _source11.dtor_cond; + Dafny.ISequence<DAST._IStatement> _174___mcc_h10 = _source11.dtor_body; + Dafny.ISequence<DAST._IStatement> _175_body = _174___mcc_h10; + DAST._IExpression _176_cond = _173___mcc_h9; { - Dafny.ISequence<Dafny.Rune> _143_condString; - bool _144___v8; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _145___v9; - Dafny.ISequence<Dafny.Rune> _out36; - bool _out37; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out38; - DCOMP.COMP.GenExpr(_142_cond, @params, true, out _out36, out _out37, out _out38); - _143_condString = _out36; - _144___v8 = _out37; - _145___v9 = _out38; - Dafny.ISequence<Dafny.Rune> _146_bodyString; - Dafny.ISequence<Dafny.Rune> _out39; - _out39 = DCOMP.COMP.GenStmts(_141_body, @params, earlyReturn); - _146_bodyString = _out39; - generated = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("while "), _143_condString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" {\n")), _146_bodyString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n}")); + Dafny.ISequence<Dafny.Rune> _177_condString; + bool _178___v12; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _179___v13; + Dafny.ISequence<Dafny.Rune> _out47; + bool _out48; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out49; + DCOMP.COMP.GenExpr(_176_cond, @params, true, out _out47, out _out48, out _out49); + _177_condString = _out47; + _178___v12 = _out48; + _179___v13 = _out49; + Dafny.ISequence<Dafny.Rune> _180_bodyString; + Dafny.ISequence<Dafny.Rune> _out50; + _out50 = DCOMP.COMP.GenStmts(_175_body, @params, earlyReturn); + _180_bodyString = _out50; + generated = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("while "), _177_condString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" {\n")), _180_bodyString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n}")); } - } else if (_source8.is_Call) { - DAST._IExpression _147___mcc_h11 = _source8.dtor_on; - Dafny.ISequence<Dafny.Rune> _148___mcc_h12 = _source8.dtor_name; - Dafny.ISequence<DAST._IType> _149___mcc_h13 = _source8.dtor_typeArgs; - Dafny.ISequence<DAST._IExpression> _150___mcc_h14 = _source8.dtor_args; - DAST._IOptional<Dafny.ISequence<Dafny.ISequence<Dafny.Rune>>> _151___mcc_h15 = _source8.dtor_outs; - DAST._IOptional<Dafny.ISequence<Dafny.ISequence<Dafny.Rune>>> _152_maybeOutVars = _151___mcc_h15; - Dafny.ISequence<DAST._IExpression> _153_args = _150___mcc_h14; - Dafny.ISequence<DAST._IType> _154_typeArgs = _149___mcc_h13; - Dafny.ISequence<Dafny.Rune> _155_name = _148___mcc_h12; - DAST._IExpression _156_on = _147___mcc_h11; + } else if (_source11.is_Call) { + DAST._IExpression _181___mcc_h11 = _source11.dtor_on; + Dafny.ISequence<Dafny.Rune> _182___mcc_h12 = _source11.dtor_name; + Dafny.ISequence<DAST._IType> _183___mcc_h13 = _source11.dtor_typeArgs; + Dafny.ISequence<DAST._IExpression> _184___mcc_h14 = _source11.dtor_args; + DAST._IOptional<Dafny.ISequence<Dafny.ISequence<Dafny.Rune>>> _185___mcc_h15 = _source11.dtor_outs; + DAST._IOptional<Dafny.ISequence<Dafny.ISequence<Dafny.Rune>>> _186_maybeOutVars = _185___mcc_h15; + Dafny.ISequence<DAST._IExpression> _187_args = _184___mcc_h14; + Dafny.ISequence<DAST._IType> _188_typeArgs = _183___mcc_h13; + Dafny.ISequence<Dafny.Rune> _189_name = _182___mcc_h12; + DAST._IExpression _190_on = _181___mcc_h11; { - Dafny.ISequence<Dafny.Rune> _157_typeArgString; - _157_typeArgString = Dafny.Sequence<Dafny.Rune>.UnicodeFromString(""); - if ((new BigInteger((_154_typeArgs).Count)) >= (BigInteger.One)) { - BigInteger _158_typeI; - _158_typeI = BigInteger.Zero; - _157_typeArgString = Dafny.Sequence<Dafny.Rune>.UnicodeFromString("::<"); - while ((_158_typeI) < (new BigInteger((_154_typeArgs).Count))) { - if ((_158_typeI).Sign == 1) { - _157_typeArgString = Dafny.Sequence<Dafny.Rune>.Concat(_157_typeArgString, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(", ")); + Dafny.ISequence<Dafny.Rune> _191_typeArgString; + _191_typeArgString = Dafny.Sequence<Dafny.Rune>.UnicodeFromString(""); + if ((new BigInteger((_188_typeArgs).Count)) >= (BigInteger.One)) { + BigInteger _192_typeI; + _192_typeI = BigInteger.Zero; + _191_typeArgString = Dafny.Sequence<Dafny.Rune>.UnicodeFromString("::<"); + while ((_192_typeI) < (new BigInteger((_188_typeArgs).Count))) { + if ((_192_typeI).Sign == 1) { + _191_typeArgString = Dafny.Sequence<Dafny.Rune>.Concat(_191_typeArgString, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(", ")); } - Dafny.ISequence<Dafny.Rune> _159_typeString; - Dafny.ISequence<Dafny.Rune> _out40; - _out40 = DCOMP.COMP.GenType((_154_typeArgs).Select(_158_typeI)); - _159_typeString = _out40; - _157_typeArgString = Dafny.Sequence<Dafny.Rune>.Concat(_157_typeArgString, _159_typeString); - _158_typeI = (_158_typeI) + (BigInteger.One); + Dafny.ISequence<Dafny.Rune> _193_typeString; + Dafny.ISequence<Dafny.Rune> _out51; + _out51 = DCOMP.COMP.GenType((_188_typeArgs).Select(_192_typeI), false); + _193_typeString = _out51; + _191_typeArgString = Dafny.Sequence<Dafny.Rune>.Concat(_191_typeArgString, _193_typeString); + _192_typeI = (_192_typeI) + (BigInteger.One); } - _157_typeArgString = Dafny.Sequence<Dafny.Rune>.Concat(_157_typeArgString, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(">")); + _191_typeArgString = Dafny.Sequence<Dafny.Rune>.Concat(_191_typeArgString, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(">")); } - Dafny.ISequence<Dafny.Rune> _160_argString; - _160_argString = Dafny.Sequence<Dafny.Rune>.UnicodeFromString(""); - BigInteger _161_i; - _161_i = BigInteger.Zero; - while ((_161_i) < (new BigInteger((_153_args).Count))) { - if ((_161_i).Sign == 1) { - _160_argString = Dafny.Sequence<Dafny.Rune>.Concat(_160_argString, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(", ")); + Dafny.ISequence<Dafny.Rune> _194_argString; + _194_argString = Dafny.Sequence<Dafny.Rune>.UnicodeFromString(""); + BigInteger _195_i; + _195_i = BigInteger.Zero; + while ((_195_i) < (new BigInteger((_187_args).Count))) { + if ((_195_i).Sign == 1) { + _194_argString = Dafny.Sequence<Dafny.Rune>.Concat(_194_argString, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(", ")); } - Dafny.ISequence<Dafny.Rune> _162_argExpr; - bool _163_isOwned; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _164___v10; - Dafny.ISequence<Dafny.Rune> _out41; - bool _out42; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out43; - DCOMP.COMP.GenExpr((_153_args).Select(_161_i), @params, false, out _out41, out _out42, out _out43); - _162_argExpr = _out41; - _163_isOwned = _out42; - _164___v10 = _out43; - _160_argString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(_160_argString, ((_163_isOwned) ? (Dafny.Sequence<Dafny.Rune>.UnicodeFromString("&")) : (Dafny.Sequence<Dafny.Rune>.UnicodeFromString("")))), _162_argExpr); - _161_i = (_161_i) + (BigInteger.One); + Dafny.ISequence<Dafny.Rune> _196_argExpr; + bool _197_isOwned; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _198___v14; + Dafny.ISequence<Dafny.Rune> _out52; + bool _out53; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out54; + DCOMP.COMP.GenExpr((_187_args).Select(_195_i), @params, false, out _out52, out _out53, out _out54); + _196_argExpr = _out52; + _197_isOwned = _out53; + _198___v14 = _out54; + _194_argString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(_194_argString, ((_197_isOwned) ? (Dafny.Sequence<Dafny.Rune>.UnicodeFromString("&")) : (Dafny.Sequence<Dafny.Rune>.UnicodeFromString("")))), _196_argExpr); + _195_i = (_195_i) + (BigInteger.One); } - Dafny.ISequence<Dafny.Rune> _165_enclosingString; - bool _166___v11; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _167___v12; - Dafny.ISequence<Dafny.Rune> _out44; - bool _out45; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out46; - DCOMP.COMP.GenExpr(_156_on, @params, true, out _out44, out _out45, out _out46); - _165_enclosingString = _out44; - _166___v11 = _out45; - _167___v12 = _out46; - DAST._IExpression _source10 = _156_on; - if (_source10.is_Literal) { - DAST._ILiteral _168___mcc_h18 = _source10.dtor_Literal_a0; + Dafny.ISequence<Dafny.Rune> _199_enclosingString; + bool _200___v15; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _201___v16; + Dafny.ISequence<Dafny.Rune> _out55; + bool _out56; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out57; + DCOMP.COMP.GenExpr(_190_on, @params, true, out _out55, out _out56, out _out57); + _199_enclosingString = _out55; + _200___v15 = _out56; + _201___v16 = _out57; + DAST._IExpression _source13 = _190_on; + if (_source13.is_Literal) { + DAST._ILiteral _202___mcc_h18 = _source13.dtor_Literal_a0; { - _165_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _165_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); + _199_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _199_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); } - } else if (_source10.is_Ident) { - Dafny.ISequence<Dafny.Rune> _169___mcc_h20 = _source10.dtor_Ident_a0; + } else if (_source13.is_Ident) { + Dafny.ISequence<Dafny.Rune> _203___mcc_h20 = _source13.dtor_Ident_a0; { - _165_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _165_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); + _199_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _199_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); } - } else if (_source10.is_Companion) { - Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _170___mcc_h22 = _source10.dtor_Companion_a0; + } else if (_source13.is_Companion) { + Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _204___mcc_h22 = _source13.dtor_Companion_a0; { - _165_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(_165_enclosingString, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("::")); + _199_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(_199_enclosingString, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("::")); } - } else if (_source10.is_Tuple) { - Dafny.ISequence<DAST._IExpression> _171___mcc_h24 = _source10.dtor_Tuple_a0; + } else if (_source13.is_Tuple) { + Dafny.ISequence<DAST._IExpression> _205___mcc_h24 = _source13.dtor_Tuple_a0; { - _165_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _165_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); + _199_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _199_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); } - } else if (_source10.is_New) { - Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _172___mcc_h26 = _source10.dtor_path; - Dafny.ISequence<DAST._IExpression> _173___mcc_h27 = _source10.dtor_args; + } else if (_source13.is_New) { + Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _206___mcc_h26 = _source13.dtor_path; + Dafny.ISequence<DAST._IExpression> _207___mcc_h27 = _source13.dtor_args; { - _165_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _165_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); + _199_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _199_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); } - } else if (_source10.is_DatatypeValue) { - Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _174___mcc_h30 = _source10.dtor_path; - Dafny.ISequence<Dafny.Rune> _175___mcc_h31 = _source10.dtor_variant; - bool _176___mcc_h32 = _source10.dtor_isCo; - Dafny.ISequence<_System._ITuple2<Dafny.ISequence<Dafny.Rune>, DAST._IExpression>> _177___mcc_h33 = _source10.dtor_contents; + } else if (_source13.is_DatatypeValue) { + Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _208___mcc_h30 = _source13.dtor_path; + Dafny.ISequence<Dafny.Rune> _209___mcc_h31 = _source13.dtor_variant; + bool _210___mcc_h32 = _source13.dtor_isCo; + Dafny.ISequence<_System._ITuple2<Dafny.ISequence<Dafny.Rune>, DAST._IExpression>> _211___mcc_h33 = _source13.dtor_contents; { - _165_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _165_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); + _199_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _199_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); } - } else if (_source10.is_This) { + } else if (_source13.is_This) { { - _165_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _165_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); + _199_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _199_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); } - } else if (_source10.is_Ite) { - DAST._IExpression _178___mcc_h38 = _source10.dtor_cond; - DAST._IExpression _179___mcc_h39 = _source10.dtor_thn; - DAST._IExpression _180___mcc_h40 = _source10.dtor_els; + } else if (_source13.is_Ite) { + DAST._IExpression _212___mcc_h38 = _source13.dtor_cond; + DAST._IExpression _213___mcc_h39 = _source13.dtor_thn; + DAST._IExpression _214___mcc_h40 = _source13.dtor_els; { - _165_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _165_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); + _199_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _199_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); } - } else if (_source10.is_BinOp) { - Dafny.ISequence<Dafny.Rune> _181___mcc_h44 = _source10.dtor_op; - DAST._IExpression _182___mcc_h45 = _source10.dtor_left; - DAST._IExpression _183___mcc_h46 = _source10.dtor_right; + } else if (_source13.is_UnOp) { + DAST._IUnaryOp _215___mcc_h44 = _source13.dtor_unOp; + DAST._IExpression _216___mcc_h45 = _source13.dtor_expr; { - _165_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _165_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); + _199_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _199_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); } - } else if (_source10.is_Select) { - DAST._IExpression _184___mcc_h50 = _source10.dtor_expr; - Dafny.ISequence<Dafny.Rune> _185___mcc_h51 = _source10.dtor_field; - bool _186___mcc_h52 = _source10.dtor_onDatatype; + } else if (_source13.is_BinOp) { + Dafny.ISequence<Dafny.Rune> _217___mcc_h48 = _source13.dtor_op; + DAST._IExpression _218___mcc_h49 = _source13.dtor_left; + DAST._IExpression _219___mcc_h50 = _source13.dtor_right; { - _165_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _165_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); + _199_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _199_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); } - } else if (_source10.is_TupleSelect) { - DAST._IExpression _187___mcc_h56 = _source10.dtor_expr; - BigInteger _188___mcc_h57 = _source10.dtor_index; + } else if (_source13.is_Select) { + DAST._IExpression _220___mcc_h54 = _source13.dtor_expr; + Dafny.ISequence<Dafny.Rune> _221___mcc_h55 = _source13.dtor_field; + bool _222___mcc_h56 = _source13.dtor_onDatatype; { - _165_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _165_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); + _199_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _199_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); } - } else if (_source10.is_Call) { - DAST._IExpression _189___mcc_h60 = _source10.dtor_on; - Dafny.ISequence<Dafny.Rune> _190___mcc_h61 = _source10.dtor_name; - Dafny.ISequence<DAST._IType> _191___mcc_h62 = _source10.dtor_typeArgs; - Dafny.ISequence<DAST._IExpression> _192___mcc_h63 = _source10.dtor_args; + } else if (_source13.is_TupleSelect) { + DAST._IExpression _223___mcc_h60 = _source13.dtor_expr; + BigInteger _224___mcc_h61 = _source13.dtor_index; { - _165_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _165_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); + _199_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _199_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); } - } else if (_source10.is_TypeTest) { - DAST._IExpression _193___mcc_h68 = _source10.dtor_on; - Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _194___mcc_h69 = _source10.dtor_dType; - Dafny.ISequence<Dafny.Rune> _195___mcc_h70 = _source10.dtor_variant; + } else if (_source13.is_Call) { + DAST._IExpression _225___mcc_h64 = _source13.dtor_on; + Dafny.ISequence<Dafny.Rune> _226___mcc_h65 = _source13.dtor_name; + Dafny.ISequence<DAST._IType> _227___mcc_h66 = _source13.dtor_typeArgs; + Dafny.ISequence<DAST._IExpression> _228___mcc_h67 = _source13.dtor_args; { - _165_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _165_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); + _199_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _199_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); + } + } else if (_source13.is_TypeTest) { + DAST._IExpression _229___mcc_h72 = _source13.dtor_on; + Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _230___mcc_h73 = _source13.dtor_dType; + Dafny.ISequence<Dafny.Rune> _231___mcc_h74 = _source13.dtor_variant; + { + _199_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _199_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); } } else { - DAST._IType _196___mcc_h74 = _source10.dtor_typ; + DAST._IType _232___mcc_h78 = _source13.dtor_typ; { - _165_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _165_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); + _199_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _199_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); } } - Dafny.ISequence<Dafny.Rune> _197_receiver; - _197_receiver = Dafny.Sequence<Dafny.Rune>.UnicodeFromString(""); - DAST._IOptional<Dafny.ISequence<Dafny.ISequence<Dafny.Rune>>> _source11 = _152_maybeOutVars; - if (_source11.is_Some) { - Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _198___mcc_h76 = _source11.dtor_Some_a0; - Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _199_outVars = _198___mcc_h76; + Dafny.ISequence<Dafny.Rune> _233_receiver; + _233_receiver = Dafny.Sequence<Dafny.Rune>.UnicodeFromString(""); + DAST._IOptional<Dafny.ISequence<Dafny.ISequence<Dafny.Rune>>> _source14 = _186_maybeOutVars; + if (_source14.is_Some) { + Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _234___mcc_h80 = _source14.dtor_Some_a0; + Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _235_outVars = _234___mcc_h80; { - if ((new BigInteger((_199_outVars).Count)) > (BigInteger.One)) { - _197_receiver = Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("); + if ((new BigInteger((_235_outVars).Count)) > (BigInteger.One)) { + _233_receiver = Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("); } - BigInteger _200_outI; - _200_outI = BigInteger.Zero; - while ((_200_outI) < (new BigInteger((_199_outVars).Count))) { - if ((_200_outI).Sign == 1) { - _197_receiver = Dafny.Sequence<Dafny.Rune>.Concat(_197_receiver, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(", ")); + BigInteger _236_outI; + _236_outI = BigInteger.Zero; + while ((_236_outI) < (new BigInteger((_235_outVars).Count))) { + if ((_236_outI).Sign == 1) { + _233_receiver = Dafny.Sequence<Dafny.Rune>.Concat(_233_receiver, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(", ")); } - Dafny.ISequence<Dafny.Rune> _201_outVar; - _201_outVar = (_199_outVars).Select(_200_outI); - _197_receiver = Dafny.Sequence<Dafny.Rune>.Concat(_197_receiver, (_201_outVar)); - _200_outI = (_200_outI) + (BigInteger.One); + Dafny.ISequence<Dafny.Rune> _237_outVar; + _237_outVar = (_235_outVars).Select(_236_outI); + _233_receiver = Dafny.Sequence<Dafny.Rune>.Concat(_233_receiver, (_237_outVar)); + _236_outI = (_236_outI) + (BigInteger.One); } - if ((new BigInteger((_199_outVars).Count)) > (BigInteger.One)) { - _197_receiver = Dafny.Sequence<Dafny.Rune>.Concat(_197_receiver, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(")")); + if ((new BigInteger((_235_outVars).Count)) > (BigInteger.One)) { + _233_receiver = Dafny.Sequence<Dafny.Rune>.Concat(_233_receiver, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(")")); } } } else { } - generated = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(((!(_197_receiver).Equals(Dafny.Sequence<Dafny.Rune>.UnicodeFromString(""))) ? (Dafny.Sequence<Dafny.Rune>.Concat(_197_receiver, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" = "))) : (Dafny.Sequence<Dafny.Rune>.UnicodeFromString(""))), _165_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#")), _155_name), _157_typeArgString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("(")), _160_argString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(");")); + generated = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(((!(_233_receiver).Equals(Dafny.Sequence<Dafny.Rune>.UnicodeFromString(""))) ? (Dafny.Sequence<Dafny.Rune>.Concat(_233_receiver, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" = "))) : (Dafny.Sequence<Dafny.Rune>.UnicodeFromString(""))), _199_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#")), _189_name), _191_typeArgString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("(")), _194_argString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(");")); } - } else if (_source8.is_Return) { - DAST._IExpression _202___mcc_h16 = _source8.dtor_expr; - DAST._IExpression _203_expr = _202___mcc_h16; + } else if (_source11.is_Return) { + DAST._IExpression _238___mcc_h16 = _source11.dtor_expr; + DAST._IExpression _239_expr = _238___mcc_h16; { - Dafny.ISequence<Dafny.Rune> _204_exprString; - bool _205___v15; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _206___v16; - Dafny.ISequence<Dafny.Rune> _out47; - bool _out48; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out49; - DCOMP.COMP.GenExpr(_203_expr, @params, true, out _out47, out _out48, out _out49); - _204_exprString = _out47; - _205___v15 = _out48; - _206___v16 = _out49; - generated = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("return "), _204_exprString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(";")); + Dafny.ISequence<Dafny.Rune> _240_exprString; + bool _241___v19; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _242___v20; + Dafny.ISequence<Dafny.Rune> _out58; + bool _out59; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out60; + DCOMP.COMP.GenExpr(_239_expr, @params, true, out _out58, out _out59, out _out60); + _240_exprString = _out58; + _241___v19 = _out59; + _242___v20 = _out60; + generated = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("return "), _240_exprString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(";")); } - } else if (_source8.is_EarlyReturn) { + } else if (_source11.is_EarlyReturn) { { generated = earlyReturn; } + } else if (_source11.is_Halt) { + { + generated = Dafny.Sequence<Dafny.Rune>.UnicodeFromString("panic!(\"Halt\");"); + } } else { - DAST._IExpression _207___mcc_h17 = _source8.dtor_Print_a0; - DAST._IExpression _208_e = _207___mcc_h17; + DAST._IExpression _243___mcc_h17 = _source11.dtor_Print_a0; + DAST._IExpression _244_e = _243___mcc_h17; { - Dafny.ISequence<Dafny.Rune> _209_printedExpr; - bool _210_isOwned; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _211___v17; - Dafny.ISequence<Dafny.Rune> _out50; - bool _out51; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out52; - DCOMP.COMP.GenExpr(_208_e, @params, false, out _out50, out _out51, out _out52); - _209_printedExpr = _out50; - _210_isOwned = _out51; - _211___v17 = _out52; - generated = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("print!(\"{}\", ::dafny_runtime::DafnyPrintWrapper("), ((_210_isOwned) ? (Dafny.Sequence<Dafny.Rune>.UnicodeFromString("&")) : (Dafny.Sequence<Dafny.Rune>.UnicodeFromString("")))), _209_printedExpr), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("));")); + Dafny.ISequence<Dafny.Rune> _245_printedExpr; + bool _246_isOwned; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _247___v21; + Dafny.ISequence<Dafny.Rune> _out61; + bool _out62; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out63; + DCOMP.COMP.GenExpr(_244_e, @params, false, out _out61, out _out62, out _out63); + _245_printedExpr = _out61; + _246_isOwned = _out62; + _247___v21 = _out63; + generated = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("print!(\"{}\", ::dafny_runtime::DafnyPrintWrapper("), ((_246_isOwned) ? (Dafny.Sequence<Dafny.Rune>.UnicodeFromString("&")) : (Dafny.Sequence<Dafny.Rune>.UnicodeFromString("")))), _245_printedExpr), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("));")); } } return generated; @@ -3604,13 +4122,13 @@ public static void GenExpr(DAST._IExpression e, Dafny.ISequence<Dafny.ISequence< s = Dafny.Sequence<Dafny.Rune>.Empty; isOwned = false; readIdents = Dafny.Set<Dafny.ISequence<Dafny.Rune>>.Empty; - DAST._IExpression _source12 = e; - if (_source12.is_Literal) { - DAST._ILiteral _212___mcc_h0 = _source12.dtor_Literal_a0; - DAST._ILiteral _source13 = _212___mcc_h0; - if (_source13.is_BoolLiteral) { - bool _213___mcc_h1 = _source13.dtor_BoolLiteral_a0; - if ((_213___mcc_h1) == (false)) { + DAST._IExpression _source15 = e; + if (_source15.is_Literal) { + DAST._ILiteral _248___mcc_h0 = _source15.dtor_Literal_a0; + DAST._ILiteral _source16 = _248___mcc_h0; + if (_source16.is_BoolLiteral) { + bool _249___mcc_h1 = _source16.dtor_BoolLiteral_a0; + if ((_249___mcc_h1) == (false)) { { s = Dafny.Sequence<Dafny.Rune>.UnicodeFromString("false"); isOwned = true; @@ -3623,41 +4141,41 @@ public static void GenExpr(DAST._IExpression e, Dafny.ISequence<Dafny.ISequence< readIdents = Dafny.Set<Dafny.ISequence<Dafny.Rune>>.FromElements(); } } - } else if (_source13.is_IntLiteral) { - BigInteger _214___mcc_h2 = _source13.dtor_IntLiteral_a0; - BigInteger _215_i = _214___mcc_h2; + } else if (_source16.is_IntLiteral) { + BigInteger _250___mcc_h2 = _source16.dtor_IntLiteral_a0; + BigInteger _251_i = _250___mcc_h2; { - if ((_215_i).Sign == -1) { - s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("-"), DCOMP.__default.natToString((BigInteger.Zero) - (_215_i))); + if ((_251_i).Sign == -1) { + s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("-"), DCOMP.__default.natToString((BigInteger.Zero) - (_251_i))); } else { - s = DCOMP.__default.natToString(_215_i); + s = DCOMP.__default.natToString(_251_i); } isOwned = true; readIdents = Dafny.Set<Dafny.ISequence<Dafny.Rune>>.FromElements(); } - } else if (_source13.is_DecLiteral) { - Dafny.ISequence<Dafny.Rune> _216___mcc_h3 = _source13.dtor_DecLiteral_a0; - Dafny.ISequence<Dafny.Rune> _217_l = _216___mcc_h3; + } else if (_source16.is_DecLiteral) { + Dafny.ISequence<Dafny.Rune> _252___mcc_h3 = _source16.dtor_DecLiteral_a0; + Dafny.ISequence<Dafny.Rune> _253_l = _252___mcc_h3; { - s = _217_l; + s = _253_l; isOwned = true; readIdents = Dafny.Set<Dafny.ISequence<Dafny.Rune>>.FromElements(); } } else { - Dafny.ISequence<Dafny.Rune> _218___mcc_h4 = _source13.dtor_StringLiteral_a0; - Dafny.ISequence<Dafny.Rune> _219_l = _218___mcc_h4; + Dafny.ISequence<Dafny.Rune> _254___mcc_h4 = _source16.dtor_StringLiteral_a0; + Dafny.ISequence<Dafny.Rune> _255_l = _254___mcc_h4; { - s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\""), _219_l), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\".to_string()")); + s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\""), _255_l), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\".to_string()")); isOwned = true; readIdents = Dafny.Set<Dafny.ISequence<Dafny.Rune>>.FromElements(); } } - } else if (_source12.is_Ident) { - Dafny.ISequence<Dafny.Rune> _220___mcc_h5 = _source12.dtor_Ident_a0; - Dafny.ISequence<Dafny.Rune> _221_name = _220___mcc_h5; + } else if (_source15.is_Ident) { + Dafny.ISequence<Dafny.Rune> _256___mcc_h5 = _source15.dtor_Ident_a0; + Dafny.ISequence<Dafny.Rune> _257_name = _256___mcc_h5; { - s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#"), _221_name); - if ((@params).Contains(_221_name)) { + s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#"), _257_name); + if ((@params).Contains(_257_name)) { if (mustOwn) { s = Dafny.Sequence<Dafny.Rune>.Concat(s, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(".clone()")); isOwned = true; @@ -3673,156 +4191,156 @@ public static void GenExpr(DAST._IExpression e, Dafny.ISequence<Dafny.ISequence< isOwned = false; } } - readIdents = Dafny.Set<Dafny.ISequence<Dafny.Rune>>.FromElements(_221_name); + readIdents = Dafny.Set<Dafny.ISequence<Dafny.Rune>>.FromElements(_257_name); } - } else if (_source12.is_Companion) { - Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _222___mcc_h6 = _source12.dtor_Companion_a0; - Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _223_path = _222___mcc_h6; + } else if (_source15.is_Companion) { + Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _258___mcc_h6 = _source15.dtor_Companion_a0; + Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _259_path = _258___mcc_h6; { - Dafny.ISequence<Dafny.Rune> _out53; - _out53 = DCOMP.COMP.GenPath(_223_path); - s = _out53; + Dafny.ISequence<Dafny.Rune> _out64; + _out64 = DCOMP.COMP.GenPath(_259_path); + s = _out64; isOwned = true; readIdents = Dafny.Set<Dafny.ISequence<Dafny.Rune>>.FromElements(); } - } else if (_source12.is_Tuple) { - Dafny.ISequence<DAST._IExpression> _224___mcc_h7 = _source12.dtor_Tuple_a0; - Dafny.ISequence<DAST._IExpression> _225_values = _224___mcc_h7; + } else if (_source15.is_Tuple) { + Dafny.ISequence<DAST._IExpression> _260___mcc_h7 = _source15.dtor_Tuple_a0; + Dafny.ISequence<DAST._IExpression> _261_values = _260___mcc_h7; { s = Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("); readIdents = Dafny.Set<Dafny.ISequence<Dafny.Rune>>.FromElements(); - BigInteger _226_i; - _226_i = BigInteger.Zero; - while ((_226_i) < (new BigInteger((_225_values).Count))) { - if ((_226_i).Sign == 1) { + BigInteger _262_i; + _262_i = BigInteger.Zero; + while ((_262_i) < (new BigInteger((_261_values).Count))) { + if ((_262_i).Sign == 1) { s = Dafny.Sequence<Dafny.Rune>.Concat(s, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" ")); } - Dafny.ISequence<Dafny.Rune> _227_recursiveGen; - bool _228___v18; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _229_recIdents; - Dafny.ISequence<Dafny.Rune> _out54; - bool _out55; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out56; - DCOMP.COMP.GenExpr((_225_values).Select(_226_i), @params, true, out _out54, out _out55, out _out56); - _227_recursiveGen = _out54; - _228___v18 = _out55; - _229_recIdents = _out56; - s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(s, _227_recursiveGen), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(",")); - readIdents = Dafny.Set<Dafny.ISequence<Dafny.Rune>>.Union(readIdents, _229_recIdents); - _226_i = (_226_i) + (BigInteger.One); + Dafny.ISequence<Dafny.Rune> _263_recursiveGen; + bool _264___v22; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _265_recIdents; + Dafny.ISequence<Dafny.Rune> _out65; + bool _out66; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out67; + DCOMP.COMP.GenExpr((_261_values).Select(_262_i), @params, true, out _out65, out _out66, out _out67); + _263_recursiveGen = _out65; + _264___v22 = _out66; + _265_recIdents = _out67; + s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(s, _263_recursiveGen), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(",")); + readIdents = Dafny.Set<Dafny.ISequence<Dafny.Rune>>.Union(readIdents, _265_recIdents); + _262_i = (_262_i) + (BigInteger.One); } s = Dafny.Sequence<Dafny.Rune>.Concat(s, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(")")); isOwned = true; } - } else if (_source12.is_New) { - Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _230___mcc_h8 = _source12.dtor_path; - Dafny.ISequence<DAST._IExpression> _231___mcc_h9 = _source12.dtor_args; - Dafny.ISequence<DAST._IExpression> _232_args = _231___mcc_h9; - Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _233_path = _230___mcc_h8; + } else if (_source15.is_New) { + Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _266___mcc_h8 = _source15.dtor_path; + Dafny.ISequence<DAST._IExpression> _267___mcc_h9 = _source15.dtor_args; + Dafny.ISequence<DAST._IExpression> _268_args = _267___mcc_h9; + Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _269_path = _266___mcc_h8; { - Dafny.ISequence<Dafny.Rune> _234_path; - Dafny.ISequence<Dafny.Rune> _out57; - _out57 = DCOMP.COMP.GenPath(_233_path); - _234_path = _out57; - s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("::std::rc::Rc::new("), _234_path), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("::new(")); + Dafny.ISequence<Dafny.Rune> _270_path; + Dafny.ISequence<Dafny.Rune> _out68; + _out68 = DCOMP.COMP.GenPath(_269_path); + _270_path = _out68; + s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("::std::rc::Rc::new("), _270_path), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("::new(")); readIdents = Dafny.Set<Dafny.ISequence<Dafny.Rune>>.FromElements(); - BigInteger _235_i; - _235_i = BigInteger.Zero; - while ((_235_i) < (new BigInteger((_232_args).Count))) { - if ((_235_i).Sign == 1) { + BigInteger _271_i; + _271_i = BigInteger.Zero; + while ((_271_i) < (new BigInteger((_268_args).Count))) { + if ((_271_i).Sign == 1) { s = Dafny.Sequence<Dafny.Rune>.Concat(s, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(", ")); } - Dafny.ISequence<Dafny.Rune> _236_recursiveGen; - bool _237___v19; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _238_recIdents; - Dafny.ISequence<Dafny.Rune> _out58; - bool _out59; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out60; - DCOMP.COMP.GenExpr((_232_args).Select(_235_i), @params, true, out _out58, out _out59, out _out60); - _236_recursiveGen = _out58; - _237___v19 = _out59; - _238_recIdents = _out60; - s = Dafny.Sequence<Dafny.Rune>.Concat(s, _236_recursiveGen); - readIdents = Dafny.Set<Dafny.ISequence<Dafny.Rune>>.Union(readIdents, _238_recIdents); - _235_i = (_235_i) + (BigInteger.One); + Dafny.ISequence<Dafny.Rune> _272_recursiveGen; + bool _273___v23; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _274_recIdents; + Dafny.ISequence<Dafny.Rune> _out69; + bool _out70; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out71; + DCOMP.COMP.GenExpr((_268_args).Select(_271_i), @params, true, out _out69, out _out70, out _out71); + _272_recursiveGen = _out69; + _273___v23 = _out70; + _274_recIdents = _out71; + s = Dafny.Sequence<Dafny.Rune>.Concat(s, _272_recursiveGen); + readIdents = Dafny.Set<Dafny.ISequence<Dafny.Rune>>.Union(readIdents, _274_recIdents); + _271_i = (_271_i) + (BigInteger.One); } s = Dafny.Sequence<Dafny.Rune>.Concat(s, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("))")); isOwned = true; } - } else if (_source12.is_DatatypeValue) { - Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _239___mcc_h10 = _source12.dtor_path; - Dafny.ISequence<Dafny.Rune> _240___mcc_h11 = _source12.dtor_variant; - bool _241___mcc_h12 = _source12.dtor_isCo; - Dafny.ISequence<_System._ITuple2<Dafny.ISequence<Dafny.Rune>, DAST._IExpression>> _242___mcc_h13 = _source12.dtor_contents; - Dafny.ISequence<_System._ITuple2<Dafny.ISequence<Dafny.Rune>, DAST._IExpression>> _243_values = _242___mcc_h13; - bool _244_isCo = _241___mcc_h12; - Dafny.ISequence<Dafny.Rune> _245_variant = _240___mcc_h11; - Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _246_path = _239___mcc_h10; + } else if (_source15.is_DatatypeValue) { + Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _275___mcc_h10 = _source15.dtor_path; + Dafny.ISequence<Dafny.Rune> _276___mcc_h11 = _source15.dtor_variant; + bool _277___mcc_h12 = _source15.dtor_isCo; + Dafny.ISequence<_System._ITuple2<Dafny.ISequence<Dafny.Rune>, DAST._IExpression>> _278___mcc_h13 = _source15.dtor_contents; + Dafny.ISequence<_System._ITuple2<Dafny.ISequence<Dafny.Rune>, DAST._IExpression>> _279_values = _278___mcc_h13; + bool _280_isCo = _277___mcc_h12; + Dafny.ISequence<Dafny.Rune> _281_variant = _276___mcc_h11; + Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _282_path = _275___mcc_h10; { - Dafny.ISequence<Dafny.Rune> _247_path; - Dafny.ISequence<Dafny.Rune> _out61; - _out61 = DCOMP.COMP.GenPath(_246_path); - _247_path = _out61; - s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("::std::rc::Rc::new("), _247_path), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("::r#")), _245_variant); + Dafny.ISequence<Dafny.Rune> _283_path; + Dafny.ISequence<Dafny.Rune> _out72; + _out72 = DCOMP.COMP.GenPath(_282_path); + _283_path = _out72; + s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("::std::rc::Rc::new("), _283_path), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("::r#")), _281_variant); readIdents = Dafny.Set<Dafny.ISequence<Dafny.Rune>>.FromElements(); - BigInteger _248_i; - _248_i = BigInteger.Zero; + BigInteger _284_i; + _284_i = BigInteger.Zero; s = Dafny.Sequence<Dafny.Rune>.Concat(s, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" {")); - while ((_248_i) < (new BigInteger((_243_values).Count))) { - _System._ITuple2<Dafny.ISequence<Dafny.Rune>, DAST._IExpression> _let_tmp_rhs0 = (_243_values).Select(_248_i); - Dafny.ISequence<Dafny.Rune> _249_name = _let_tmp_rhs0.dtor__0; - DAST._IExpression _250_value = _let_tmp_rhs0.dtor__1; - if ((_248_i).Sign == 1) { + while ((_284_i) < (new BigInteger((_279_values).Count))) { + _System._ITuple2<Dafny.ISequence<Dafny.Rune>, DAST._IExpression> _let_tmp_rhs0 = (_279_values).Select(_284_i); + Dafny.ISequence<Dafny.Rune> _285_name = _let_tmp_rhs0.dtor__0; + DAST._IExpression _286_value = _let_tmp_rhs0.dtor__1; + if ((_284_i).Sign == 1) { s = Dafny.Sequence<Dafny.Rune>.Concat(s, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(", ")); } - if (_244_isCo) { - Dafny.ISequence<Dafny.Rune> _251_recursiveGen; - bool _252___v20; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _253_recIdents; - Dafny.ISequence<Dafny.Rune> _out62; - bool _out63; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out64; - DCOMP.COMP.GenExpr(_250_value, Dafny.Sequence<Dafny.ISequence<Dafny.Rune>>.FromElements(), true, out _out62, out _out63, out _out64); - _251_recursiveGen = _out62; - _252___v20 = _out63; - _253_recIdents = _out64; - readIdents = Dafny.Set<Dafny.ISequence<Dafny.Rune>>.Union(readIdents, _253_recIdents); - Dafny.ISequence<Dafny.Rune> _254_allReadCloned; - _254_allReadCloned = Dafny.Sequence<Dafny.Rune>.UnicodeFromString(""); - while (!(_253_recIdents).Equals(Dafny.Set<Dafny.ISequence<Dafny.Rune>>.FromElements())) { - Dafny.ISequence<Dafny.Rune> _255_next; - foreach (Dafny.ISequence<Dafny.Rune> _assign_such_that_0 in (_253_recIdents).Elements) { - _255_next = (Dafny.ISequence<Dafny.Rune>)_assign_such_that_0; - if ((_253_recIdents).Contains(_255_next)) { + if (_280_isCo) { + Dafny.ISequence<Dafny.Rune> _287_recursiveGen; + bool _288___v24; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _289_recIdents; + Dafny.ISequence<Dafny.Rune> _out73; + bool _out74; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out75; + DCOMP.COMP.GenExpr(_286_value, Dafny.Sequence<Dafny.ISequence<Dafny.Rune>>.FromElements(), true, out _out73, out _out74, out _out75); + _287_recursiveGen = _out73; + _288___v24 = _out74; + _289_recIdents = _out75; + readIdents = Dafny.Set<Dafny.ISequence<Dafny.Rune>>.Union(readIdents, _289_recIdents); + Dafny.ISequence<Dafny.Rune> _290_allReadCloned; + _290_allReadCloned = Dafny.Sequence<Dafny.Rune>.UnicodeFromString(""); + while (!(_289_recIdents).Equals(Dafny.Set<Dafny.ISequence<Dafny.Rune>>.FromElements())) { + Dafny.ISequence<Dafny.Rune> _291_next; + foreach (Dafny.ISequence<Dafny.Rune> _assign_such_that_0 in (_289_recIdents).Elements) { + _291_next = (Dafny.ISequence<Dafny.Rune>)_assign_such_that_0; + if ((_289_recIdents).Contains(_291_next)) { goto after__ASSIGN_SUCH_THAT_0; } } - throw new System.Exception("assign-such-that search produced no value (line 671)"); + throw new System.Exception("assign-such-that search produced no value (line 765)"); after__ASSIGN_SUCH_THAT_0:; - _254_allReadCloned = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(_254_allReadCloned, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("let r#")), _255_next), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" = r#")), _255_next), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(".clone();\n")); - _253_recIdents = Dafny.Set<Dafny.ISequence<Dafny.Rune>>.Difference(_253_recIdents, Dafny.Set<Dafny.ISequence<Dafny.Rune>>.FromElements(_255_next)); + _290_allReadCloned = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(_290_allReadCloned, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("let r#")), _291_next), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" = r#")), _291_next), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(".clone();\n")); + _289_recIdents = Dafny.Set<Dafny.ISequence<Dafny.Rune>>.Difference(_289_recIdents, Dafny.Set<Dafny.ISequence<Dafny.Rune>>.FromElements(_291_next)); } - s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(s, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#")), _249_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(": ::dafny_runtime::LazyFieldWrapper(::dafny_runtime::Lazy::new(Box::new({\n")), _254_allReadCloned), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("move || (")), _251_recursiveGen), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(")})))")); + s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(s, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#")), _285_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(": ::dafny_runtime::LazyFieldWrapper(::dafny_runtime::Lazy::new(Box::new({\n")), _290_allReadCloned), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("move || (")), _287_recursiveGen), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(")})))")); } else { - Dafny.ISequence<Dafny.Rune> _256_recursiveGen; - bool _257___v21; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _258_recIdents; - Dafny.ISequence<Dafny.Rune> _out65; - bool _out66; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out67; - DCOMP.COMP.GenExpr(_250_value, @params, true, out _out65, out _out66, out _out67); - _256_recursiveGen = _out65; - _257___v21 = _out66; - _258_recIdents = _out67; - s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(s, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#")), _249_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(": ")), _256_recursiveGen); - readIdents = Dafny.Set<Dafny.ISequence<Dafny.Rune>>.Union(readIdents, _258_recIdents); + Dafny.ISequence<Dafny.Rune> _292_recursiveGen; + bool _293___v25; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _294_recIdents; + Dafny.ISequence<Dafny.Rune> _out76; + bool _out77; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out78; + DCOMP.COMP.GenExpr(_286_value, @params, true, out _out76, out _out77, out _out78); + _292_recursiveGen = _out76; + _293___v25 = _out77; + _294_recIdents = _out78; + s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(s, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#")), _285_name), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(": ")), _292_recursiveGen); + readIdents = Dafny.Set<Dafny.ISequence<Dafny.Rune>>.Union(readIdents, _294_recIdents); } - _248_i = (_248_i) + (BigInteger.One); + _284_i = (_284_i) + (BigInteger.One); } s = Dafny.Sequence<Dafny.Rune>.Concat(s, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" })")); isOwned = true; } - } else if (_source12.is_This) { + } else if (_source15.is_This) { { if (mustOwn) { s = Dafny.Sequence<Dafny.Rune>.UnicodeFromString("self.clone()"); @@ -3833,110 +4351,166 @@ public static void GenExpr(DAST._IExpression e, Dafny.ISequence<Dafny.ISequence< } readIdents = Dafny.Set<Dafny.ISequence<Dafny.Rune>>.FromElements(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("self")); } - } else if (_source12.is_Ite) { - DAST._IExpression _259___mcc_h14 = _source12.dtor_cond; - DAST._IExpression _260___mcc_h15 = _source12.dtor_thn; - DAST._IExpression _261___mcc_h16 = _source12.dtor_els; - DAST._IExpression _262_f = _261___mcc_h16; - DAST._IExpression _263_t = _260___mcc_h15; - DAST._IExpression _264_cond = _259___mcc_h14; + } else if (_source15.is_Ite) { + DAST._IExpression _295___mcc_h14 = _source15.dtor_cond; + DAST._IExpression _296___mcc_h15 = _source15.dtor_thn; + DAST._IExpression _297___mcc_h16 = _source15.dtor_els; + DAST._IExpression _298_f = _297___mcc_h16; + DAST._IExpression _299_t = _296___mcc_h15; + DAST._IExpression _300_cond = _295___mcc_h14; { - Dafny.ISequence<Dafny.Rune> _265_condString; - bool _266___v22; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _267_recIdentsCond; - Dafny.ISequence<Dafny.Rune> _out68; - bool _out69; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out70; - DCOMP.COMP.GenExpr(_264_cond, @params, true, out _out68, out _out69, out _out70); - _265_condString = _out68; - _266___v22 = _out69; - _267_recIdentsCond = _out70; - Dafny.ISequence<Dafny.Rune> _268___v23; - bool _269_tHasToBeOwned; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _270___v24; - Dafny.ISequence<Dafny.Rune> _out71; - bool _out72; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out73; - DCOMP.COMP.GenExpr(_263_t, @params, mustOwn, out _out71, out _out72, out _out73); - _268___v23 = _out71; - _269_tHasToBeOwned = _out72; - _270___v24 = _out73; - Dafny.ISequence<Dafny.Rune> _271_fString; - bool _272_fOwned; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _273_recIdentsF; - Dafny.ISequence<Dafny.Rune> _out74; - bool _out75; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out76; - DCOMP.COMP.GenExpr(_262_f, @params, _269_tHasToBeOwned, out _out74, out _out75, out _out76); - _271_fString = _out74; - _272_fOwned = _out75; - _273_recIdentsF = _out76; - Dafny.ISequence<Dafny.Rune> _274_tString; - bool _275___v25; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _276_recIdentsT; - Dafny.ISequence<Dafny.Rune> _out77; - bool _out78; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out79; - DCOMP.COMP.GenExpr(_263_t, @params, _272_fOwned, out _out77, out _out78, out _out79); - _274_tString = _out77; - _275___v25 = _out78; - _276_recIdentsT = _out79; - s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("(if "), _265_condString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" {\n")), _274_tString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n} else {\n")), _271_fString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n})")); - isOwned = _272_fOwned; - readIdents = Dafny.Set<Dafny.ISequence<Dafny.Rune>>.Union(Dafny.Set<Dafny.ISequence<Dafny.Rune>>.Union(_267_recIdentsCond, _276_recIdentsT), _273_recIdentsF); + Dafny.ISequence<Dafny.Rune> _301_condString; + bool _302___v26; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _303_recIdentsCond; + Dafny.ISequence<Dafny.Rune> _out79; + bool _out80; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out81; + DCOMP.COMP.GenExpr(_300_cond, @params, true, out _out79, out _out80, out _out81); + _301_condString = _out79; + _302___v26 = _out80; + _303_recIdentsCond = _out81; + Dafny.ISequence<Dafny.Rune> _304___v27; + bool _305_tHasToBeOwned; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _306___v28; + Dafny.ISequence<Dafny.Rune> _out82; + bool _out83; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out84; + DCOMP.COMP.GenExpr(_299_t, @params, mustOwn, out _out82, out _out83, out _out84); + _304___v27 = _out82; + _305_tHasToBeOwned = _out83; + _306___v28 = _out84; + Dafny.ISequence<Dafny.Rune> _307_fString; + bool _308_fOwned; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _309_recIdentsF; + Dafny.ISequence<Dafny.Rune> _out85; + bool _out86; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out87; + DCOMP.COMP.GenExpr(_298_f, @params, _305_tHasToBeOwned, out _out85, out _out86, out _out87); + _307_fString = _out85; + _308_fOwned = _out86; + _309_recIdentsF = _out87; + Dafny.ISequence<Dafny.Rune> _310_tString; + bool _311___v29; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _312_recIdentsT; + Dafny.ISequence<Dafny.Rune> _out88; + bool _out89; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out90; + DCOMP.COMP.GenExpr(_299_t, @params, _308_fOwned, out _out88, out _out89, out _out90); + _310_tString = _out88; + _311___v29 = _out89; + _312_recIdentsT = _out90; + s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("(if "), _301_condString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" {\n")), _310_tString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n} else {\n")), _307_fString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n})")); + isOwned = _308_fOwned; + readIdents = Dafny.Set<Dafny.ISequence<Dafny.Rune>>.Union(Dafny.Set<Dafny.ISequence<Dafny.Rune>>.Union(_303_recIdentsCond, _312_recIdentsT), _309_recIdentsF); + } + } else if (_source15.is_UnOp) { + DAST._IUnaryOp _313___mcc_h17 = _source15.dtor_unOp; + DAST._IExpression _314___mcc_h18 = _source15.dtor_expr; + DAST._IUnaryOp _source17 = _313___mcc_h17; + if (_source17.is_Not) { + DAST._IExpression _315_e = _314___mcc_h18; + { + Dafny.ISequence<Dafny.Rune> _316_recursiveGen; + bool _317___v30; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _318_recIdents; + Dafny.ISequence<Dafny.Rune> _out91; + bool _out92; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out93; + DCOMP.COMP.GenExpr(_315_e, @params, true, out _out91, out _out92, out _out93); + _316_recursiveGen = _out91; + _317___v30 = _out92; + _318_recIdents = _out93; + s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("!("), _316_recursiveGen), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(")")); + isOwned = true; + readIdents = _318_recIdents; + } + } else if (_source17.is_BitwiseNot) { + DAST._IExpression _319_e = _314___mcc_h18; + { + Dafny.ISequence<Dafny.Rune> _320_recursiveGen; + bool _321___v31; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _322_recIdents; + Dafny.ISequence<Dafny.Rune> _out94; + bool _out95; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out96; + DCOMP.COMP.GenExpr(_319_e, @params, true, out _out94, out _out95, out _out96); + _320_recursiveGen = _out94; + _321___v31 = _out95; + _322_recIdents = _out96; + s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("~("), _320_recursiveGen), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(")")); + isOwned = true; + readIdents = _322_recIdents; + } + } else { + DAST._IExpression _323_e = _314___mcc_h18; + { + Dafny.ISequence<Dafny.Rune> _324_recursiveGen; + bool _325___v32; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _326_recIdents; + Dafny.ISequence<Dafny.Rune> _out97; + bool _out98; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out99; + DCOMP.COMP.GenExpr(_323_e, @params, false, out _out97, out _out98, out _out99); + _324_recursiveGen = _out97; + _325___v32 = _out98; + _326_recIdents = _out99; + s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _324_recursiveGen), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").len()")); + isOwned = true; + readIdents = _326_recIdents; + } } - } else if (_source12.is_BinOp) { - Dafny.ISequence<Dafny.Rune> _277___mcc_h17 = _source12.dtor_op; - DAST._IExpression _278___mcc_h18 = _source12.dtor_left; - DAST._IExpression _279___mcc_h19 = _source12.dtor_right; - DAST._IExpression _280_r = _279___mcc_h19; - DAST._IExpression _281_l = _278___mcc_h18; - Dafny.ISequence<Dafny.Rune> _282_op = _277___mcc_h17; + } else if (_source15.is_BinOp) { + Dafny.ISequence<Dafny.Rune> _327___mcc_h19 = _source15.dtor_op; + DAST._IExpression _328___mcc_h20 = _source15.dtor_left; + DAST._IExpression _329___mcc_h21 = _source15.dtor_right; + DAST._IExpression _330_r = _329___mcc_h21; + DAST._IExpression _331_l = _328___mcc_h20; + Dafny.ISequence<Dafny.Rune> _332_op = _327___mcc_h19; { - Dafny.ISequence<Dafny.Rune> _283_left; - bool _284___v26; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _285_recIdentsL; - Dafny.ISequence<Dafny.Rune> _out80; - bool _out81; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out82; - DCOMP.COMP.GenExpr(_281_l, @params, true, out _out80, out _out81, out _out82); - _283_left = _out80; - _284___v26 = _out81; - _285_recIdentsL = _out82; - Dafny.ISequence<Dafny.Rune> _286_right; - bool _287___v27; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _288_recIdentsR; - Dafny.ISequence<Dafny.Rune> _out83; - bool _out84; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out85; - DCOMP.COMP.GenExpr(_280_r, @params, true, out _out83, out _out84, out _out85); - _286_right = _out83; - _287___v27 = _out84; - _288_recIdentsR = _out85; - s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _283_left), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" ")), _282_op), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" ")), _286_right), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(")")); + Dafny.ISequence<Dafny.Rune> _333_left; + bool _334___v33; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _335_recIdentsL; + Dafny.ISequence<Dafny.Rune> _out100; + bool _out101; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out102; + DCOMP.COMP.GenExpr(_331_l, @params, true, out _out100, out _out101, out _out102); + _333_left = _out100; + _334___v33 = _out101; + _335_recIdentsL = _out102; + Dafny.ISequence<Dafny.Rune> _336_right; + bool _337___v34; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _338_recIdentsR; + Dafny.ISequence<Dafny.Rune> _out103; + bool _out104; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out105; + DCOMP.COMP.GenExpr(_330_r, @params, true, out _out103, out _out104, out _out105); + _336_right = _out103; + _337___v34 = _out104; + _338_recIdentsR = _out105; + s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _333_left), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" ")), _332_op), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(" ")), _336_right), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(")")); isOwned = true; - readIdents = Dafny.Set<Dafny.ISequence<Dafny.Rune>>.Union(_285_recIdentsL, _288_recIdentsR); + readIdents = Dafny.Set<Dafny.ISequence<Dafny.Rune>>.Union(_335_recIdentsL, _338_recIdentsR); } - } else if (_source12.is_Select) { - DAST._IExpression _289___mcc_h20 = _source12.dtor_expr; - Dafny.ISequence<Dafny.Rune> _290___mcc_h21 = _source12.dtor_field; - bool _291___mcc_h22 = _source12.dtor_onDatatype; - bool _292_isDatatype = _291___mcc_h22; - Dafny.ISequence<Dafny.Rune> _293_field = _290___mcc_h21; - DAST._IExpression _294_on = _289___mcc_h20; + } else if (_source15.is_Select) { + DAST._IExpression _339___mcc_h22 = _source15.dtor_expr; + Dafny.ISequence<Dafny.Rune> _340___mcc_h23 = _source15.dtor_field; + bool _341___mcc_h24 = _source15.dtor_onDatatype; + bool _342_isDatatype = _341___mcc_h24; + Dafny.ISequence<Dafny.Rune> _343_field = _340___mcc_h23; + DAST._IExpression _344_on = _339___mcc_h22; { - Dafny.ISequence<Dafny.Rune> _295_onString; - bool _296___v28; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _297_recIdents; - Dafny.ISequence<Dafny.Rune> _out86; - bool _out87; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out88; - DCOMP.COMP.GenExpr(_294_on, @params, false, out _out86, out _out87, out _out88); - _295_onString = _out86; - _296___v28 = _out87; - _297_recIdents = _out88; - if (_292_isDatatype) { - s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _295_onString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(")")), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(".r#")), _293_field), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("()")); + Dafny.ISequence<Dafny.Rune> _345_onString; + bool _346___v35; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _347_recIdents; + Dafny.ISequence<Dafny.Rune> _out106; + bool _out107; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out108; + DCOMP.COMP.GenExpr(_344_on, @params, false, out _out106, out _out107, out _out108); + _345_onString = _out106; + _346___v35 = _out107; + _347_recIdents = _out108; + if (_342_isDatatype) { + s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _345_onString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(")")), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(".r#")), _343_field), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("()")); if (mustOwn) { s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), s), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").clone()")); isOwned = true; @@ -3944,7 +4518,7 @@ public static void GenExpr(DAST._IExpression e, Dafny.ISequence<Dafny.ISequence< isOwned = false; } } else { - s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _295_onString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(")")), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(".r#")), _293_field); + s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _345_onString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(")")), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(".r#")), _343_field); if (mustOwn) { s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), s), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").clone()")); isOwned = true; @@ -3952,25 +4526,25 @@ public static void GenExpr(DAST._IExpression e, Dafny.ISequence<Dafny.ISequence< isOwned = false; } } - readIdents = _297_recIdents; + readIdents = _347_recIdents; } - } else if (_source12.is_TupleSelect) { - DAST._IExpression _298___mcc_h23 = _source12.dtor_expr; - BigInteger _299___mcc_h24 = _source12.dtor_index; - BigInteger _300_idx = _299___mcc_h24; - DAST._IExpression _301_on = _298___mcc_h23; + } else if (_source15.is_TupleSelect) { + DAST._IExpression _348___mcc_h25 = _source15.dtor_expr; + BigInteger _349___mcc_h26 = _source15.dtor_index; + BigInteger _350_idx = _349___mcc_h26; + DAST._IExpression _351_on = _348___mcc_h25; { - Dafny.ISequence<Dafny.Rune> _302_onString; - bool _303___v29; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _304_recIdents; - Dafny.ISequence<Dafny.Rune> _out89; - bool _out90; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out91; - DCOMP.COMP.GenExpr(_301_on, @params, false, out _out89, out _out90, out _out91); - _302_onString = _out89; - _303___v29 = _out90; - _304_recIdents = _out91; - s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _302_onString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")), DCOMP.__default.natToString(_300_idx)); + Dafny.ISequence<Dafny.Rune> _352_onString; + bool _353___v36; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _354_recIdents; + Dafny.ISequence<Dafny.Rune> _out109; + bool _out110; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out111; + DCOMP.COMP.GenExpr(_351_on, @params, false, out _out109, out _out110, out _out111); + _352_onString = _out109; + _353___v36 = _out110; + _354_recIdents = _out111; + s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _352_onString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")), DCOMP.__default.natToString(_350_idx)); if (mustOwn) { s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), s), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(")")), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(".clone()")); isOwned = true; @@ -3978,190 +4552,196 @@ public static void GenExpr(DAST._IExpression e, Dafny.ISequence<Dafny.ISequence< s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("&"), s); isOwned = false; } - readIdents = _304_recIdents; + readIdents = _354_recIdents; } - } else if (_source12.is_Call) { - DAST._IExpression _305___mcc_h25 = _source12.dtor_on; - Dafny.ISequence<Dafny.Rune> _306___mcc_h26 = _source12.dtor_name; - Dafny.ISequence<DAST._IType> _307___mcc_h27 = _source12.dtor_typeArgs; - Dafny.ISequence<DAST._IExpression> _308___mcc_h28 = _source12.dtor_args; - Dafny.ISequence<DAST._IExpression> _309_args = _308___mcc_h28; - Dafny.ISequence<DAST._IType> _310_typeArgs = _307___mcc_h27; - Dafny.ISequence<Dafny.Rune> _311_name = _306___mcc_h26; - DAST._IExpression _312_on = _305___mcc_h25; + } else if (_source15.is_Call) { + DAST._IExpression _355___mcc_h27 = _source15.dtor_on; + Dafny.ISequence<Dafny.Rune> _356___mcc_h28 = _source15.dtor_name; + Dafny.ISequence<DAST._IType> _357___mcc_h29 = _source15.dtor_typeArgs; + Dafny.ISequence<DAST._IExpression> _358___mcc_h30 = _source15.dtor_args; + Dafny.ISequence<DAST._IExpression> _359_args = _358___mcc_h30; + Dafny.ISequence<DAST._IType> _360_typeArgs = _357___mcc_h29; + Dafny.ISequence<Dafny.Rune> _361_name = _356___mcc_h28; + DAST._IExpression _362_on = _355___mcc_h27; { readIdents = Dafny.Set<Dafny.ISequence<Dafny.Rune>>.FromElements(); - Dafny.ISequence<Dafny.Rune> _313_typeArgString; - _313_typeArgString = Dafny.Sequence<Dafny.Rune>.UnicodeFromString(""); - if ((new BigInteger((_310_typeArgs).Count)) >= (BigInteger.One)) { - BigInteger _314_typeI; - _314_typeI = BigInteger.Zero; - _313_typeArgString = Dafny.Sequence<Dafny.Rune>.UnicodeFromString("::<"); - while ((_314_typeI) < (new BigInteger((_310_typeArgs).Count))) { - if ((_314_typeI).Sign == 1) { - _313_typeArgString = Dafny.Sequence<Dafny.Rune>.Concat(_313_typeArgString, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(", ")); + Dafny.ISequence<Dafny.Rune> _363_typeArgString; + _363_typeArgString = Dafny.Sequence<Dafny.Rune>.UnicodeFromString(""); + if ((new BigInteger((_360_typeArgs).Count)) >= (BigInteger.One)) { + BigInteger _364_typeI; + _364_typeI = BigInteger.Zero; + _363_typeArgString = Dafny.Sequence<Dafny.Rune>.UnicodeFromString("::<"); + while ((_364_typeI) < (new BigInteger((_360_typeArgs).Count))) { + if ((_364_typeI).Sign == 1) { + _363_typeArgString = Dafny.Sequence<Dafny.Rune>.Concat(_363_typeArgString, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(", ")); } - Dafny.ISequence<Dafny.Rune> _315_typeString; - Dafny.ISequence<Dafny.Rune> _out92; - _out92 = DCOMP.COMP.GenType((_310_typeArgs).Select(_314_typeI)); - _315_typeString = _out92; - _313_typeArgString = Dafny.Sequence<Dafny.Rune>.Concat(_313_typeArgString, _315_typeString); - _314_typeI = (_314_typeI) + (BigInteger.One); + Dafny.ISequence<Dafny.Rune> _365_typeString; + Dafny.ISequence<Dafny.Rune> _out112; + _out112 = DCOMP.COMP.GenType((_360_typeArgs).Select(_364_typeI), false); + _365_typeString = _out112; + _363_typeArgString = Dafny.Sequence<Dafny.Rune>.Concat(_363_typeArgString, _365_typeString); + _364_typeI = (_364_typeI) + (BigInteger.One); } - _313_typeArgString = Dafny.Sequence<Dafny.Rune>.Concat(_313_typeArgString, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(">")); + _363_typeArgString = Dafny.Sequence<Dafny.Rune>.Concat(_363_typeArgString, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(">")); } - Dafny.ISequence<Dafny.Rune> _316_argString; - _316_argString = Dafny.Sequence<Dafny.Rune>.UnicodeFromString(""); - BigInteger _317_i; - _317_i = BigInteger.Zero; - while ((_317_i) < (new BigInteger((_309_args).Count))) { - if ((_317_i).Sign == 1) { - _316_argString = Dafny.Sequence<Dafny.Rune>.Concat(_316_argString, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(", ")); + Dafny.ISequence<Dafny.Rune> _366_argString; + _366_argString = Dafny.Sequence<Dafny.Rune>.UnicodeFromString(""); + BigInteger _367_i; + _367_i = BigInteger.Zero; + while ((_367_i) < (new BigInteger((_359_args).Count))) { + if ((_367_i).Sign == 1) { + _366_argString = Dafny.Sequence<Dafny.Rune>.Concat(_366_argString, Dafny.Sequence<Dafny.Rune>.UnicodeFromString(", ")); } - Dafny.ISequence<Dafny.Rune> _318_argExpr; - bool _319_isOwned; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _320_recIdents; - Dafny.ISequence<Dafny.Rune> _out93; - bool _out94; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out95; - DCOMP.COMP.GenExpr((_309_args).Select(_317_i), @params, false, out _out93, out _out94, out _out95); - _318_argExpr = _out93; - _319_isOwned = _out94; - _320_recIdents = _out95; - readIdents = Dafny.Set<Dafny.ISequence<Dafny.Rune>>.Union(readIdents, _320_recIdents); - _316_argString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(_316_argString, ((_319_isOwned) ? (Dafny.Sequence<Dafny.Rune>.UnicodeFromString("&")) : (Dafny.Sequence<Dafny.Rune>.UnicodeFromString("")))), _318_argExpr); - _317_i = (_317_i) + (BigInteger.One); + Dafny.ISequence<Dafny.Rune> _368_argExpr; + bool _369_isOwned; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _370_recIdents; + Dafny.ISequence<Dafny.Rune> _out113; + bool _out114; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out115; + DCOMP.COMP.GenExpr((_359_args).Select(_367_i), @params, false, out _out113, out _out114, out _out115); + _368_argExpr = _out113; + _369_isOwned = _out114; + _370_recIdents = _out115; + readIdents = Dafny.Set<Dafny.ISequence<Dafny.Rune>>.Union(readIdents, _370_recIdents); + _366_argString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(_366_argString, ((_369_isOwned) ? (Dafny.Sequence<Dafny.Rune>.UnicodeFromString("&")) : (Dafny.Sequence<Dafny.Rune>.UnicodeFromString("")))), _368_argExpr); + _367_i = (_367_i) + (BigInteger.One); } - Dafny.ISequence<Dafny.Rune> _321_enclosingString; - bool _322___v30; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _323_recIdents; - Dafny.ISequence<Dafny.Rune> _out96; - bool _out97; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out98; - DCOMP.COMP.GenExpr(_312_on, @params, false, out _out96, out _out97, out _out98); - _321_enclosingString = _out96; - _322___v30 = _out97; - _323_recIdents = _out98; - readIdents = Dafny.Set<Dafny.ISequence<Dafny.Rune>>.Union(readIdents, _323_recIdents); - DAST._IExpression _source14 = _312_on; - if (_source14.is_Literal) { - DAST._ILiteral _324___mcc_h33 = _source14.dtor_Literal_a0; + Dafny.ISequence<Dafny.Rune> _371_enclosingString; + bool _372___v37; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _373_recIdents; + Dafny.ISequence<Dafny.Rune> _out116; + bool _out117; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out118; + DCOMP.COMP.GenExpr(_362_on, @params, false, out _out116, out _out117, out _out118); + _371_enclosingString = _out116; + _372___v37 = _out117; + _373_recIdents = _out118; + readIdents = Dafny.Set<Dafny.ISequence<Dafny.Rune>>.Union(readIdents, _373_recIdents); + DAST._IExpression _source18 = _362_on; + if (_source18.is_Literal) { + DAST._ILiteral _374___mcc_h35 = _source18.dtor_Literal_a0; + { + _371_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _371_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); + } + } else if (_source18.is_Ident) { + Dafny.ISequence<Dafny.Rune> _375___mcc_h37 = _source18.dtor_Ident_a0; { - _321_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _321_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); + _371_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _371_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); } - } else if (_source14.is_Ident) { - Dafny.ISequence<Dafny.Rune> _325___mcc_h35 = _source14.dtor_Ident_a0; + } else if (_source18.is_Companion) { + Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _376___mcc_h39 = _source18.dtor_Companion_a0; { - _321_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _321_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); + _371_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(_371_enclosingString, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("::")); } - } else if (_source14.is_Companion) { - Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _326___mcc_h37 = _source14.dtor_Companion_a0; + } else if (_source18.is_Tuple) { + Dafny.ISequence<DAST._IExpression> _377___mcc_h41 = _source18.dtor_Tuple_a0; { - _321_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(_321_enclosingString, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("::")); + _371_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _371_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); } - } else if (_source14.is_Tuple) { - Dafny.ISequence<DAST._IExpression> _327___mcc_h39 = _source14.dtor_Tuple_a0; + } else if (_source18.is_New) { + Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _378___mcc_h43 = _source18.dtor_path; + Dafny.ISequence<DAST._IExpression> _379___mcc_h44 = _source18.dtor_args; { - _321_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _321_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); + _371_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _371_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); } - } else if (_source14.is_New) { - Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _328___mcc_h41 = _source14.dtor_path; - Dafny.ISequence<DAST._IExpression> _329___mcc_h42 = _source14.dtor_args; + } else if (_source18.is_DatatypeValue) { + Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _380___mcc_h47 = _source18.dtor_path; + Dafny.ISequence<Dafny.Rune> _381___mcc_h48 = _source18.dtor_variant; + bool _382___mcc_h49 = _source18.dtor_isCo; + Dafny.ISequence<_System._ITuple2<Dafny.ISequence<Dafny.Rune>, DAST._IExpression>> _383___mcc_h50 = _source18.dtor_contents; { - _321_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _321_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); + _371_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _371_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); } - } else if (_source14.is_DatatypeValue) { - Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _330___mcc_h45 = _source14.dtor_path; - Dafny.ISequence<Dafny.Rune> _331___mcc_h46 = _source14.dtor_variant; - bool _332___mcc_h47 = _source14.dtor_isCo; - Dafny.ISequence<_System._ITuple2<Dafny.ISequence<Dafny.Rune>, DAST._IExpression>> _333___mcc_h48 = _source14.dtor_contents; + } else if (_source18.is_This) { { - _321_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _321_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); + _371_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _371_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); } - } else if (_source14.is_This) { + } else if (_source18.is_Ite) { + DAST._IExpression _384___mcc_h55 = _source18.dtor_cond; + DAST._IExpression _385___mcc_h56 = _source18.dtor_thn; + DAST._IExpression _386___mcc_h57 = _source18.dtor_els; { - _321_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _321_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); + _371_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _371_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); } - } else if (_source14.is_Ite) { - DAST._IExpression _334___mcc_h53 = _source14.dtor_cond; - DAST._IExpression _335___mcc_h54 = _source14.dtor_thn; - DAST._IExpression _336___mcc_h55 = _source14.dtor_els; + } else if (_source18.is_UnOp) { + DAST._IUnaryOp _387___mcc_h61 = _source18.dtor_unOp; + DAST._IExpression _388___mcc_h62 = _source18.dtor_expr; { - _321_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _321_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); + _371_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _371_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); } - } else if (_source14.is_BinOp) { - Dafny.ISequence<Dafny.Rune> _337___mcc_h59 = _source14.dtor_op; - DAST._IExpression _338___mcc_h60 = _source14.dtor_left; - DAST._IExpression _339___mcc_h61 = _source14.dtor_right; + } else if (_source18.is_BinOp) { + Dafny.ISequence<Dafny.Rune> _389___mcc_h65 = _source18.dtor_op; + DAST._IExpression _390___mcc_h66 = _source18.dtor_left; + DAST._IExpression _391___mcc_h67 = _source18.dtor_right; { - _321_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _321_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); + _371_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _371_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); } - } else if (_source14.is_Select) { - DAST._IExpression _340___mcc_h65 = _source14.dtor_expr; - Dafny.ISequence<Dafny.Rune> _341___mcc_h66 = _source14.dtor_field; - bool _342___mcc_h67 = _source14.dtor_onDatatype; + } else if (_source18.is_Select) { + DAST._IExpression _392___mcc_h71 = _source18.dtor_expr; + Dafny.ISequence<Dafny.Rune> _393___mcc_h72 = _source18.dtor_field; + bool _394___mcc_h73 = _source18.dtor_onDatatype; { - _321_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _321_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); + _371_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _371_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); } - } else if (_source14.is_TupleSelect) { - DAST._IExpression _343___mcc_h71 = _source14.dtor_expr; - BigInteger _344___mcc_h72 = _source14.dtor_index; + } else if (_source18.is_TupleSelect) { + DAST._IExpression _395___mcc_h77 = _source18.dtor_expr; + BigInteger _396___mcc_h78 = _source18.dtor_index; { - _321_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _321_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); + _371_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _371_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); } - } else if (_source14.is_Call) { - DAST._IExpression _345___mcc_h75 = _source14.dtor_on; - Dafny.ISequence<Dafny.Rune> _346___mcc_h76 = _source14.dtor_name; - Dafny.ISequence<DAST._IType> _347___mcc_h77 = _source14.dtor_typeArgs; - Dafny.ISequence<DAST._IExpression> _348___mcc_h78 = _source14.dtor_args; + } else if (_source18.is_Call) { + DAST._IExpression _397___mcc_h81 = _source18.dtor_on; + Dafny.ISequence<Dafny.Rune> _398___mcc_h82 = _source18.dtor_name; + Dafny.ISequence<DAST._IType> _399___mcc_h83 = _source18.dtor_typeArgs; + Dafny.ISequence<DAST._IExpression> _400___mcc_h84 = _source18.dtor_args; { - _321_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _321_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); + _371_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _371_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); } - } else if (_source14.is_TypeTest) { - DAST._IExpression _349___mcc_h83 = _source14.dtor_on; - Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _350___mcc_h84 = _source14.dtor_dType; - Dafny.ISequence<Dafny.Rune> _351___mcc_h85 = _source14.dtor_variant; + } else if (_source18.is_TypeTest) { + DAST._IExpression _401___mcc_h89 = _source18.dtor_on; + Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _402___mcc_h90 = _source18.dtor_dType; + Dafny.ISequence<Dafny.Rune> _403___mcc_h91 = _source18.dtor_variant; { - _321_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _321_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); + _371_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _371_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); } } else { - DAST._IType _352___mcc_h89 = _source14.dtor_typ; + DAST._IType _404___mcc_h95 = _source18.dtor_typ; { - _321_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _321_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); + _371_enclosingString = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("("), _371_enclosingString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(").")); } } - s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(_321_enclosingString, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#")), _311_name), _313_typeArgString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("(")), _316_argString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(")")); + s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(_371_enclosingString, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("r#")), _361_name), _363_typeArgString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("(")), _366_argString), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(")")); isOwned = true; } - } else if (_source12.is_TypeTest) { - DAST._IExpression _353___mcc_h29 = _source12.dtor_on; - Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _354___mcc_h30 = _source12.dtor_dType; - Dafny.ISequence<Dafny.Rune> _355___mcc_h31 = _source12.dtor_variant; - Dafny.ISequence<Dafny.Rune> _356_variant = _355___mcc_h31; - Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _357_dType = _354___mcc_h30; - DAST._IExpression _358_on = _353___mcc_h29; + } else if (_source15.is_TypeTest) { + DAST._IExpression _405___mcc_h31 = _source15.dtor_on; + Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _406___mcc_h32 = _source15.dtor_dType; + Dafny.ISequence<Dafny.Rune> _407___mcc_h33 = _source15.dtor_variant; + Dafny.ISequence<Dafny.Rune> _408_variant = _407___mcc_h33; + Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> _409_dType = _406___mcc_h32; + DAST._IExpression _410_on = _405___mcc_h31; { - Dafny.ISequence<Dafny.Rune> _359_exprGen; - bool _360___v33; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _361_recIdents; - Dafny.ISequence<Dafny.Rune> _out99; - bool _out100; - Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out101; - DCOMP.COMP.GenExpr(_358_on, @params, false, out _out99, out _out100, out _out101); - _359_exprGen = _out99; - _360___v33 = _out100; - _361_recIdents = _out101; - Dafny.ISequence<Dafny.Rune> _362_dTypePath; - Dafny.ISequence<Dafny.Rune> _out102; - _out102 = DCOMP.COMP.GenPath(_357_dType); - _362_dTypePath = _out102; - s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("matches!("), _359_exprGen), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(".as_ref(), ")), _362_dTypePath), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("::r#")), _356_variant), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("{ .. })")); + Dafny.ISequence<Dafny.Rune> _411_exprGen; + bool _412___v40; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _413_recIdents; + Dafny.ISequence<Dafny.Rune> _out119; + bool _out120; + Dafny.ISet<Dafny.ISequence<Dafny.Rune>> _out121; + DCOMP.COMP.GenExpr(_410_on, @params, false, out _out119, out _out120, out _out121); + _411_exprGen = _out119; + _412___v40 = _out120; + _413_recIdents = _out121; + Dafny.ISequence<Dafny.Rune> _414_dTypePath; + Dafny.ISequence<Dafny.Rune> _out122; + _out122 = DCOMP.COMP.GenPath(_409_dType); + _414_dTypePath = _out122; + s = Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.Concat(Dafny.Sequence<Dafny.Rune>.UnicodeFromString("matches!("), _411_exprGen), Dafny.Sequence<Dafny.Rune>.UnicodeFromString(".as_ref(), ")), _414_dTypePath), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("::r#")), _408_variant), Dafny.Sequence<Dafny.Rune>.UnicodeFromString("{ .. })")); isOwned = true; - readIdents = _361_recIdents; + readIdents = _413_recIdents; } } else { - DAST._IType _363___mcc_h32 = _source12.dtor_typ; - DAST._IType _364_typ = _363___mcc_h32; + DAST._IType _415___mcc_h34 = _source15.dtor_typ; + DAST._IType _416_typ = _415___mcc_h34; { s = Dafny.Sequence<Dafny.Rune>.UnicodeFromString("std::default::Default::default()"); isOwned = true; @@ -4173,32 +4753,32 @@ public static void GenExpr(DAST._IExpression e, Dafny.ISequence<Dafny.ISequence< Dafny.ISequence<Dafny.Rune> s = Dafny.Sequence<Dafny.Rune>.Empty; s = Dafny.Sequence<Dafny.Rune>.UnicodeFromString("#![allow(warnings, unconditional_panic)]\n"); s = Dafny.Sequence<Dafny.Rune>.Concat(s, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("extern crate dafny_runtime;\n")); - BigInteger _365_i; - _365_i = BigInteger.Zero; - while ((_365_i) < (new BigInteger((p).Count))) { - Dafny.ISequence<Dafny.Rune> _366_generated = Dafny.Sequence<Dafny.Rune>.Empty; - Dafny.ISequence<Dafny.Rune> _out103; - _out103 = DCOMP.COMP.GenModule((p).Select(_365_i)); - _366_generated = _out103; - if ((_365_i).Sign == 1) { + BigInteger _417_i; + _417_i = BigInteger.Zero; + while ((_417_i) < (new BigInteger((p).Count))) { + Dafny.ISequence<Dafny.Rune> _418_generated = Dafny.Sequence<Dafny.Rune>.Empty; + Dafny.ISequence<Dafny.Rune> _out123; + _out123 = DCOMP.COMP.GenModule((p).Select(_417_i), Dafny.Sequence<Dafny.ISequence<Dafny.Rune>>.FromElements()); + _418_generated = _out123; + if ((_417_i).Sign == 1) { s = Dafny.Sequence<Dafny.Rune>.Concat(s, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\n")); } - s = Dafny.Sequence<Dafny.Rune>.Concat(s, _366_generated); - _365_i = (_365_i) + (BigInteger.One); + s = Dafny.Sequence<Dafny.Rune>.Concat(s, _418_generated); + _417_i = (_417_i) + (BigInteger.One); } return s; } public static Dafny.ISequence<Dafny.Rune> EmitCallToMain(Dafny.ISequence<Dafny.ISequence<Dafny.Rune>> fullName) { Dafny.ISequence<Dafny.Rune> s = Dafny.Sequence<Dafny.Rune>.Empty; s = Dafny.Sequence<Dafny.Rune>.UnicodeFromString("\nfn main() {\n"); - BigInteger _367_i; - _367_i = BigInteger.Zero; - while ((_367_i) < (new BigInteger((fullName).Count))) { - if ((_367_i).Sign == 1) { + BigInteger _419_i; + _419_i = BigInteger.Zero; + while ((_419_i) < (new BigInteger((fullName).Count))) { + if ((_419_i).Sign == 1) { s = Dafny.Sequence<Dafny.Rune>.Concat(s, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("::")); } - s = Dafny.Sequence<Dafny.Rune>.Concat(s, (fullName).Select(_367_i)); - _367_i = (_367_i) + (BigInteger.One); + s = Dafny.Sequence<Dafny.Rune>.Concat(s, (fullName).Select(_419_i)); + _419_i = (_419_i) + (BigInteger.One); } s = Dafny.Sequence<Dafny.Rune>.Concat(s, Dafny.Sequence<Dafny.Rune>.UnicodeFromString("();\n}")); return s; diff --git a/docs/DafnyRef/Features.md b/docs/DafnyRef/Features.md index 77b178f109c..f76d8fd9b2e 100644 --- a/docs/DafnyRef/Features.md +++ b/docs/DafnyRef/Features.md @@ -12,7 +12,7 @@ | [Runtime type descriptors](#) | X | X | X | X | X | | X | | | [Multi-dimensional arrays](#sec-multi-dimensional-arrays) | X | X | X | X | X | | X | | | [Map comprehensions](#sec-map-comprehension-expression) | X | X | X | X | X | | X | | -| [Traits](#sec-trait-types) | X | X | X | X | X | | X | | +| [Traits](#sec-trait-types) | X | X | X | X | X | | X | X | | [Let-such-that expressions](#sec-let-expression) | X | X | X | X | X | | X | | | [Non-native numeric newtypes](#sec-newtypes) | X | X | X | X | X | | X | | | [Method synthesis](#sec-synthesize-attr) | X | | | | | | X | | From 1639857597d15e5bad3532362998e718252eaa3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=C3=ABl=20Mayer?= <MikaelMayer@users.noreply.github.com> Date: Fri, 4 Aug 2023 11:58:16 -0500 Subject: [PATCH 06/19] Fix: Gutter icons more robust (#4288) This PR fixes #4287 The computation of the number of lines was done improperly for empty files and wasn't migrated properly for non-empty files, which resulted in gutter icons to never expand as before. I modified the tests so that it's now possible to fully simulate a variable number of line and more general insertions, which helped me first reproduce the issue and then ensure that the fix was correct. Also, I renamed "Next" to "Replace" in the tests so that it better reflects what the edit is supposed to do: replace the entire line. I added the variant "Insert" and described https://github.com/dafny-lang/dafny/pull/4288/files#diff-81426824e7dbbe14c1b83ee3acd4998ddd7b565b09c355e835c7e101b930f4c5R184 what the variants mean I made it possible also for the tests to perform several changes at once, so that I can simulate not just removing a comment like "//Insert:", but also replacing \n by newlines and \\ by single backslashes. <small>By submitting this pull request, I confirm that my contribution is made under the terms of the [MIT license](https://github.com/dafny-lang/dafny/blob/master/LICENSE.txt).</small> --------- Co-authored-by: Remy Willems <rwillems@amazon.com> --- Source/DafnyCore/AST/DafnyAst.cs | 0 Source/DafnyCore/AST/Grammar/ProgramParser.cs | 2 +- ...hedLinearVerificationGutterStatusTester.cs | 6 +- ...entLinearVerificationGutterStatusTester.cs | 2 +- .../LinearVerificationGutterStatusTester.cs | 104 +++++++++++++----- ...eorderingVerificationGutterStatusTester.cs | 30 ++--- ...pleLinearVerificationGutterStatusTester.cs | 35 +++--- .../ProjectManagerDatabaseTest.cs | 3 +- .../Util/ClientBasedLanguageServerTest.cs | 20 ++++ .../Workspace/ChangeProcessors/Relocator.cs | 26 +++-- .../VerificationDiagnosticsParams.cs | 14 +-- docs/dev/news/4287.fix | 1 + 12 files changed, 157 insertions(+), 86 deletions(-) create mode 100644 Source/DafnyCore/AST/DafnyAst.cs create mode 100644 docs/dev/news/4287.fix diff --git a/Source/DafnyCore/AST/DafnyAst.cs b/Source/DafnyCore/AST/DafnyAst.cs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/Source/DafnyCore/AST/Grammar/ProgramParser.cs b/Source/DafnyCore/AST/Grammar/ProgramParser.cs index 3febc26f388..aae46d87328 100644 --- a/Source/DafnyCore/AST/Grammar/ProgramParser.cs +++ b/Source/DafnyCore/AST/Grammar/ProgramParser.cs @@ -125,7 +125,7 @@ private void ShowWarningsForIncludeCycles(Program program) { } } - public static void AddParseResultToProgram(DfyParseResult parseResult, Program program) { + private static void AddParseResultToProgram(DfyParseResult parseResult, Program program) { var defaultModule = program.DefaultModuleDef; var fileModule = parseResult.Module; program.Files.Add(fileModule); diff --git a/Source/DafnyLanguageServer.Test/GutterStatus/CachedLinearVerificationGutterStatusTester.cs b/Source/DafnyLanguageServer.Test/GutterStatus/CachedLinearVerificationGutterStatusTester.cs index e93a39c4ece..5ca91644ac8 100644 --- a/Source/DafnyLanguageServer.Test/GutterStatus/CachedLinearVerificationGutterStatusTester.cs +++ b/Source/DafnyLanguageServer.Test/GutterStatus/CachedLinearVerificationGutterStatusTester.cs @@ -13,7 +13,7 @@ public class CachedLinearVerificationGutterStatusTester : LinearVerificationGutt // To add a new test, just call VerifyTrace on a given program, // the test will fail and give the correct output that can be use for the test - // Add '//Next<n>:' to edit a line multiple times + // Add '//Replace<n>:' to edit a line multiple times [Fact(Timeout = MaxTestExecutionTimeMs)] public async Task EnsureCachingDoesNotMakeSquigglyLinesToRemain() { @@ -24,7 +24,7 @@ await SetUp(options => { await VerifyTrace(@" . S S | I $ | :method test() { . S | | I $ | : assert true; - . S S | I $ | : //Next: + . S S | I $ | : //Replace: . S S | I $ | :}", true); } @@ -38,7 +38,7 @@ await VerifyTrace(@" . S [S][ ][I][S][S][ ]:method test() { . S [O][O][o][Q][O][O]: assert true; . S [=][=][-][~][=][=]: assert false; - . S [S][ ][I][S][S][ ]: //Next: + . S [S][ ][I][S][S][ ]: //Replace: . S [S][ ][I][S][S][ ]:}", false, "ensureCachingDoesNotHideErrors.dfy"); } diff --git a/Source/DafnyLanguageServer.Test/GutterStatus/ConcurrentLinearVerificationGutterStatusTester.cs b/Source/DafnyLanguageServer.Test/GutterStatus/ConcurrentLinearVerificationGutterStatusTester.cs index 24d0b89d029..6703b19569b 100644 --- a/Source/DafnyLanguageServer.Test/GutterStatus/ConcurrentLinearVerificationGutterStatusTester.cs +++ b/Source/DafnyLanguageServer.Test/GutterStatus/ConcurrentLinearVerificationGutterStatusTester.cs @@ -50,7 +50,7 @@ public async Task EnsuresManyDocumentsCanBeVerifiedAtOnce() { | | | I | | : . S [S][ ][I][S][ ]:method H() . S [=][=][-][~][O]: ensures F(1) - . S [=][=][-][~][=]:{//Next: { assert false; + . S [=][=][-][~][=]:{//Replace: { assert false; . S [S][ ][I][S][ ]:}", false, $"testfile{i}.dfy", true, true, verificationStatusGutterReceivers[i])); } diff --git a/Source/DafnyLanguageServer.Test/GutterStatus/LinearVerificationGutterStatusTester.cs b/Source/DafnyLanguageServer.Test/GutterStatus/LinearVerificationGutterStatusTester.cs index 58f87924d77..41248ae4751 100644 --- a/Source/DafnyLanguageServer.Test/GutterStatus/LinearVerificationGutterStatusTester.cs +++ b/Source/DafnyLanguageServer.Test/GutterStatus/LinearVerificationGutterStatusTester.cs @@ -68,21 +68,37 @@ private static bool IsNotIndicatingProgress(LineVerificationStatus status) { status != LineVerificationStatus.AssertionVerifiedInErrorContextObsolete && status != LineVerificationStatus.AssertionVerifiedInErrorContextVerifying; } - public static string RenderTrace(List<LineVerificationStatus[]> statusesTrace, string code) { + public static string RenderTrace(List<LineVerificationStatus[]> statusesTrace, List<string> codes) { + var code = codes[0]; var codeLines = new Regex("\r?\n").Split(code); + var maxLines = codeLines.Length; + foreach (var trace in statusesTrace) { + if (maxLines < trace.Length) { + maxLines = trace.Length; + } + } + foreach (var intermediateCode in codes) { + var intermediateCodeLines = new Regex("\r?\n").Split(intermediateCode).Length; + if (maxLines < intermediateCodeLines) { + maxLines = intermediateCodeLines; + } + } var renderedCode = ""; - for (var line = 0; line < codeLines.Length; line++) { + for (var line = 0; line < maxLines; line++) { if (line != 0) { renderedCode += "\n"; } foreach (var statusTrace in statusesTrace) { - renderedCode += LineVerificationStatusToString[statusTrace[line]]; + if (line >= statusTrace.Length) { + renderedCode += "###"; + } else { + renderedCode += LineVerificationStatusToString[statusTrace[line]]; + } } renderedCode += ":"; - renderedCode += codeLines[line]; + renderedCode += line < codeLines.Length ? codeLines[line] : ""; } - Assert.All(statusesTrace, trace => Assert.Equal(codeLines.Length, trace.Length)); return renderedCode; } @@ -166,26 +182,30 @@ private static bool NoMoreNotificationsToAwaitFrom(VerificationStatusGutter veri /// <summary> /// Given some code, will emit the edit like this: /// ``` - /// sentence //Next1:sentence2 //Next2:sentence3 - /// ^^^^^^^^^^^^^^^^^ remove + /// sentence //Replace1:This is a \nsentence2 //Replace2:sentence3 with \\n character + /// ^^^remove^^^^^^^^^^^ ^^ replace with newline ^^ replace with \ /// ``` /// ``` - /// sentence //Next1:\nsentence2 //Next2:sentence3 - /// ^^^^^^^^^^^^^^^^^^^ replace with newline + /// sentence //Insert1:This is a \nsentence2 //Replace2:sentence3 with \\n character + /// ^^^remove^ ^^ replace with newline ^^ replace with \ /// ``` /// ``` - /// sentence //Remove1:sentence2 //Next2:sentence3 - /// ^^^^^^^^^^^^^^^^^^^ remove, including the newline before sentence if any + /// sentence //Remove1:sentence2 //Replace2:sentence3 + /// ^^^^^^^^^^^^^^^^^^^ Same as Replace, but will remove also the newline before /// ``` /// </summary> - /// <param name="code">The original code with the //Next: comments or //NextN:</param> + /// <param name="code">The original code with the //Replace: comments or //ReplaceN:</param> /// <returns></returns> - public (string code, List<(Range changeRange, string changeValue)> changes) ExtractCodeAndChanges(string code) { + public (string code, List<string> codes, List<List<Change>> changes) ExtractCodeAndChanges(string code) { var lineMatcher = new Regex(@"\r?\n"); - var matcher = new Regex(@"(?<previousNewline>^|\r?\n)(?<toRemove>.*?//(?<newtOrRemove>Next|Remove)(?<id>\d*):(?<newline>\\n)?)"); + var newLineOrDoubleBackslashMatcher = new Regex(@"\\\\|\\n"); + var matcher = new Regex(@"(?<previousNewline>^|\r?\n)(?<toRemove>.*?(?<commentStart>//)(?<keyword>Replace|Remove|Insert)(?<id>\d*):)(?<toInsert>.*)"); + code = code.Trim(); + var codes = new List<string>(); + codes.Add(code); var originalCode = code; var matches = matcher.Matches(code); - var changes = new List<(Range, string)>(); + var changes = new List<List<Change>>(); while (matches.Count > 0) { var firstChange = 0; Match firstChangeMatch = null; @@ -206,12 +226,20 @@ private static bool NoMoreNotificationsToAwaitFrom(VerificationStatusGutter veri break; } - var startRemove = - firstChangeMatch.Groups["newtOrRemove"].Value == "Next" ? - firstChangeMatch.Groups["toRemove"].Index : - firstChangeMatch.Groups["previousNewline"].Index; + var keyword = firstChangeMatch.Groups["keyword"].Value; + var startRemove = keyword switch { + "Replace" => firstChangeMatch.Groups["toRemove"].Index, + "Remove" => firstChangeMatch.Groups["previousNewline"].Index, + "Insert" => firstChangeMatch.Groups["commentStart"].Index, + _ => throw new Exception("Unexpected keyword: " + keyword + ", expected Replace, Remove or Insert") + }; var endRemove = firstChangeMatch.Groups["toRemove"].Index + firstChangeMatch.Groups["toRemove"].Value.Length; + var toInsert = firstChangeMatch.Groups["toInsert"].Value; + var toInsertIndex = firstChangeMatch.Groups["toInsert"].Index; + var allNewlinesOrDoubleBackslashes = newLineOrDoubleBackslashMatcher.Matches(toInsert); + + Position IndexToPosition(int index) { var before = code.Substring(0, index); var newlines = lineMatcher.Matches(before); @@ -225,15 +253,31 @@ Position IndexToPosition(int index) { return new Position(line, character); } - var optionalNewLine = firstChangeMatch.Groups["newline"].Success ? "\n" : ""; - // For now, simple: Remove the line - changes.Add(new( - new Range(IndexToPosition(startRemove), IndexToPosition(endRemove)), optionalNewLine)); - code = code.Substring(0, startRemove) + optionalNewLine + code.Substring(endRemove); + // If there are \n characters in the comments, we replace them by newlines + // If there are \\ characters in the comments, we replace them by single slashes + var resultingChange = new List<Change>(); + for (var i = allNewlinesOrDoubleBackslashes.Count - 1; i >= 0; i--) { + var newlineOrDoubleBackslash = allNewlinesOrDoubleBackslashes[i]; + var isNewline = newlineOrDoubleBackslash.Value == @"\n"; + var index = newlineOrDoubleBackslash.Index; + var absoluteIndex = toInsertIndex + index; + var absoluteIndexEnd = absoluteIndex + newlineOrDoubleBackslash.Value.Length; + var replacement = isNewline ? "\n" : @"\"; + resultingChange.Add(new( + new Range(IndexToPosition(absoluteIndex), IndexToPosition(absoluteIndexEnd)), replacement + )); + code = code.Substring(0, absoluteIndex) + replacement + code.Substring(absoluteIndexEnd); + } + + resultingChange.Add(new( + new Range(IndexToPosition(startRemove), IndexToPosition(endRemove)), "")); + code = code.Substring(0, startRemove) + code.Substring(endRemove); matches = matcher.Matches(code); + changes.Add(resultingChange); + codes.Add(code); } - return (originalCode, changes); + return (originalCode, codes, changes); } // If testTrace is false, codeAndTree should not contain a trace to test. @@ -246,23 +290,23 @@ public async Task VerifyTrace(string codeAndTrace, bool explicitProject, string codeAndTrace.Substring(0, 2) == "\r\n" ? codeAndTrace.Substring(2) : codeAndTrace; var codeAndChanges = testTrace ? ExtractCode(codeAndTrace) : codeAndTrace; - var (code, changes) = ExtractCodeAndChanges(codeAndChanges); + var (code, codes, changesList) = ExtractCodeAndChanges(codeAndChanges); - var documentItem = CreateTestDocument(code, fileName, 1); + var documentItem = CreateTestDocument(code.Trim(), fileName, 1); if (explicitProject) { await CreateAndOpenTestDocument("", Path.Combine(Path.GetDirectoryName(documentItem.Uri.GetFileSystemPath())!, DafnyProject.FileName)); } client.OpenDocument(documentItem); var traces = new List<LineVerificationStatus[]>(); traces.AddRange(await GetAllLineVerificationStatuses(documentItem, verificationStatusGutterReceiver, intermediates: intermediates)); - foreach (var (range, inserted) in changes) { - ApplyChange(ref documentItem, range, inserted); + foreach (var changes in changesList) { + ApplyChanges(ref documentItem, changes); traces.AddRange(await GetAllLineVerificationStatuses(documentItem, verificationStatusGutterReceiver, intermediates: intermediates)); await Projects.GetLastDocumentAsync(documentItem); } if (testTrace) { - var traceObtained = RenderTrace(traces, code); + var traceObtained = RenderTrace(traces, codes); var ignoreQuestionMarks = AcceptQuestionMarks(traceObtained, codeAndTrace); var expected = "\n" + codeAndTrace + "\n"; var actual = "\n" + ignoreQuestionMarks + "\n"; diff --git a/Source/DafnyLanguageServer.Test/GutterStatus/ReorderingVerificationGutterStatusTester.cs b/Source/DafnyLanguageServer.Test/GutterStatus/ReorderingVerificationGutterStatusTester.cs index 613350151a3..c193882d7cd 100644 --- a/Source/DafnyLanguageServer.Test/GutterStatus/ReorderingVerificationGutterStatusTester.cs +++ b/Source/DafnyLanguageServer.Test/GutterStatus/ReorderingVerificationGutterStatusTester.cs @@ -26,10 +26,10 @@ public class ReorderingVerificationGutterStatusTester : LinearVerificationGutter public async Task EnsuresPriorityDependsOnEditing() { await TestPriorities(@" method m1() { - assert false;//Next2: assert true; + assert false;//Replace2: assert true; } method m2() { - assert false;//Next1: assert true; + assert false;//Replace1: assert true; } ", "m1 m2\n" + @@ -42,19 +42,19 @@ method m2() { public async Task EnsuresPriorityDependsOnEditingWhileEditingSameMethod() { await TestPriorities(@" method m1() { - assert false;//Next7: assert true;//Next8: assert false; + assert false;//Replace7: assert true;//Replace8: assert false; } method m2() { - assert false;//Next5: assert true; + assert false;//Replace5: assert true; } method m3() { - assert false;//Next2: assert true;//Next9: assert false; + assert false;//Replace2: assert true;//Replace9: assert false; } method m4() { - assert false;//Next3: assert true;//Next4: assert false; + assert false;//Replace3: assert true;//Replace4: assert false; } method m5() { - assert false;//Next1: assert true;//Next6: assert false;//Next10: assert true; + assert false;//Replace1: assert true;//Replace6: assert false;//Replace10: assert true; } ", "m1 m2 m3 m4 m5\n" + "m5 m1 m2 m3 m4\n" + @@ -76,10 +76,10 @@ await TestPriorities(@" method m1() { assert false; } method m2() { assert false; } method m3() { - assert false;//Next1: assert true; + assert false;//Replace1: assert true; } method m4() { - assert false;//Next2: assert true; + assert false;//Replace2: assert true; } method m5() { assert false; } //Remove3: ", @@ -94,13 +94,13 @@ public async Task EnsuresPriorityWorksEvenIfRemovingMethodsWhileTypo() { await TestPriorities(@" method m1() { assert false; } method m2() { - assert false;//Next3: typo//Next5: assert true; + assert false;//Replace3: typo//Replace5: assert true; } method m3() { - assert false;//Next1: assert true; + assert false;//Replace1: assert true; } method m4() { - assert false;//Next2: assert true; + assert false;//Replace2: assert true; } method m5() { assert false; } //Remove4: ", @@ -123,7 +123,7 @@ await SetUp(options => { }); var symbols = ExtractSymbols(symbolsString); - var (code, changes) = ExtractCodeAndChanges(codeAndChanges.TrimStart()); + var (code, codes, changesList) = ExtractCodeAndChanges(codeAndChanges.TrimStart()); var documentItem = CreateTestDocument(code); client.OpenDocument(documentItem); @@ -147,9 +147,9 @@ async Task CompareWithExpectation(List<string> expectedSymbols) { } await CompareWithExpectation(symbols.First()); - foreach (var (change, expectedSymbols) in changes.Zip(symbols.Skip(1))) { + foreach (var (changes, expectedSymbols) in changesList.Zip(symbols.Skip(1))) { index++; - ApplyChange(ref documentItem, change.changeRange, change.changeValue); + ApplyChanges(ref documentItem, changes); if (expectedSymbols != null) { var migrated = expectedSymbols.Count == 0; if (migrated) { diff --git a/Source/DafnyLanguageServer.Test/GutterStatus/SimpleLinearVerificationGutterStatusTester.cs b/Source/DafnyLanguageServer.Test/GutterStatus/SimpleLinearVerificationGutterStatusTester.cs index fd0030caf37..1292105a906 100644 --- a/Source/DafnyLanguageServer.Test/GutterStatus/SimpleLinearVerificationGutterStatusTester.cs +++ b/Source/DafnyLanguageServer.Test/GutterStatus/SimpleLinearVerificationGutterStatusTester.cs @@ -11,7 +11,15 @@ public class SimpleLinearVerificationGutterStatusTester : LinearVerificationGutt // To add a new test, just call VerifyTrace on a given program, // the test will fail and give the correct output that can be use for the test - // Add '//Next<n>:' to edit a line multiple times + // Add '//Replace<n>:' to edit a line multiple times + + [Fact] + public async Task GitIssue4287GutterHighlightingBroken() { + await VerifyTrace(@" + | | [ ]://Insert1:method Test() {//Insert2:\\n assert false;\n} +### | [=]: +######[ ]:", false, intermediates: false); + } [Fact] public async Task GitIssue3821GutterIgnoredProblem() { @@ -61,7 +69,7 @@ await VerifyTrace(@" . S [S][ ][I][I][S] | : if x { . S [S][ ][I][I][S] | : i := 2; . S [=][=][-][-][~] | : } else { - . S [S][ ]/!\[I][S] | : i := 1; //Next1: i := /; //Next2: i := 2; + . S [S][ ]/!\[I][S] | : i := 1; //Replace1: i := /; //Replace2: i := 2; . S [S][ ][I][I][S] | : } . S [S][ ][I][I][S] | :} | | | I I | | : @@ -72,7 +80,7 @@ await VerifyTrace(@" [Fact(Timeout = MaxTestExecutionTimeMs)] public async Task EnsuresItWorksForSubsetTypes() { await VerifyTrace(@" - | | | I I | | | I I | | | : + | | | I I | | | I I | | | :// The maximum Id . | | | I I | | | I I | | | :ghost const maxId := 200; | | | I I | | | I I | | | : . | | | I I | | | I I | | | :ghost predicate isIssueIdValid(issueId: int) { @@ -80,7 +88,7 @@ await VerifyTrace(@" . | | | I I | | | I I | | | :} | | | I I | | | I I | | | : . S S | I . S S [=] I . S S | :type IssueId = i : int | isIssueIdValid(i) - . S | | I . S | [=] I . S | | : witness 101 //Next1: witness 99 //Next2: witness 101 ", false, "EnsuresItWorksForSubsetTypes.dfy"); + . S | | I . S | [=] I . S | | : witness 101 //Replace1: witness 99 //Replace2: witness 101 ", false, "EnsuresItWorksForSubsetTypes.dfy"); } [Fact(Timeout = MaxTestExecutionTimeMs)] @@ -103,9 +111,9 @@ await VerifyTrace(@" . | | | I | :predicate P(x: int) | | | I | : . S [S][ ][I] | :method Main() { - . S [=][=][I] | : ghost var x :| P(x); //Next: ghost var x := 1; + . S [=][=][I] | : ghost var x :| P(x); //Replace: ghost var x := 1; . S [S][ ][I] | :} - | :", false, $"EnsureNoAssertShowsVerified{i}.dfy"); + | :// Comment to not trim this line", false, $"EnsureNoAssertShowsVerified{i}.dfy"); } } @@ -114,7 +122,7 @@ public async Task EnsureEmptyDocumentIsVerified() { await VerifyTrace(@" | :class A { | :} - | :", true); + | :// Comment so test does not trim this line", true); } @@ -122,8 +130,7 @@ await VerifyTrace(@" public async Task EnsuresEmptyDocumentWithParseErrorShowsError() { await VerifyTrace(@" /!\:class A {/ - :} - :", false); + :}", false); } [Fact/*(Timeout = MaxTestExecutionTimeMs)*/] @@ -145,10 +152,10 @@ await VerifyTrace(@" public async Task EnsuresAddingNewlinesMigratesPositions() { await VerifyTrace(@" . S [S][ ][I][S][ ][I][S][ ]:method f(x: int) { - . S [S][ ][I][S][ ][I][S][ ]: //Next1:\n //Next2:\n + . S [S][ ][I][S][ ][I][S][ ]: //Replace1:\n //Replace2:\\n . S [=][=][I][S][ ][I][S][ ]: assert x == 2; } - [-][~][=][I][S][ ]: - [-][~][=]:", true, "EnsuresAddingNewlinesMigratesPositions.dfy"); +############[-][~][=][I][S][ ]: +#####################[-][~][=]:", true, "EnsuresAddingNewlinesMigratesPositions.dfy"); } [Fact/*(Timeout = MaxTestExecutionTimeMs)*/] @@ -158,12 +165,12 @@ await VerifyTrace(@" . S [S][ ][I][S][S][ ]:method f(x: int) returns (y: int) . S [S][ ][I][S][S][ ]:ensures . S [=][=][-][~][=][=]: x > 3 { y := x; - . S [S][ ][I][S][S][ ]: //Next1:\n + . S [S][ ][I][S][S][ ]: //Replace1:\n . S [=][=][-][~][=][ ]: while(y <= 1) invariant y >= 2 { . S [S][ ][-][~][~][=]: y := y + 1; . S [S][ ][I][S][S][ ]: } . S [S][ ][I][S][S][ ]:} - [I][S][S][ ]:", false); +############[I][S][S][ ]:", false); } [Fact] diff --git a/Source/DafnyLanguageServer.Test/Synchronization/ProjectManagerDatabaseTest.cs b/Source/DafnyLanguageServer.Test/Synchronization/ProjectManagerDatabaseTest.cs index d14a90fa7a6..69a33446b84 100644 --- a/Source/DafnyLanguageServer.Test/Synchronization/ProjectManagerDatabaseTest.cs +++ b/Source/DafnyLanguageServer.Test/Synchronization/ProjectManagerDatabaseTest.cs @@ -70,8 +70,7 @@ public async Task OpenAndCloseConcurrentlySameProject() { var project = CreateTestDocument("", Path.Combine(directory, DafnyProject.FileName)); client.OpenDocument(project); for (int i = 0; i < documentsToLoadConcurrently; i++) { - var documentItem = CreateTestDocument(source, Path.Combine(directory, $"pmdtest3_{i}.dfy")); - client.OpenDocument(documentItem); + var documentItem = await CreateAndOpenTestDocument(source, Path.Combine(directory, $"pmdtest3_{i}.dfy")); loadingDocuments.Add(documentItem); } diff --git a/Source/DafnyLanguageServer.Test/Util/ClientBasedLanguageServerTest.cs b/Source/DafnyLanguageServer.Test/Util/ClientBasedLanguageServerTest.cs index 6bf0d0807c3..958062b2a61 100644 --- a/Source/DafnyLanguageServer.Test/Util/ClientBasedLanguageServerTest.cs +++ b/Source/DafnyLanguageServer.Test/Util/ClientBasedLanguageServerTest.cs @@ -194,6 +194,10 @@ protected virtual void InitialiseClientHandler(LanguageClientOptions options) { NotificationHandler.For<FileVerificationStatus>(verificationStatusReceiver.NotificationReceived)); } + public record Change(Range range, String inserted); + + public record Changes(List<Change> changes); + protected void ApplyChange(ref TextDocumentItem documentItem, Range range, string text) { documentItem = documentItem with { Version = documentItem.Version + 1 }; client.DidChangeTextDocument(new DidChangeTextDocumentParams { @@ -210,6 +214,22 @@ protected void ApplyChange(ref TextDocumentItem documentItem, Range range, strin }); } + protected void ApplyChanges(ref TextDocumentItem documentItem, List<Change> changes) { + documentItem = documentItem with { Version = documentItem.Version + 1 }; + client.DidChangeTextDocument(new DidChangeTextDocumentParams { + TextDocument = new OptionalVersionedTextDocumentIdentifier { + Uri = documentItem.Uri, + Version = documentItem.Version + }, + ContentChanges = + changes.Select(change => + new TextDocumentContentChangeEvent { + Range = change.range, + Text = change.inserted + }).ToArray() + }); + } + public async Task AssertNoVerificationStatusIsComing(TextDocumentItem documentItem, CancellationToken cancellationToken) { foreach (var entry in Projects.Managers) { try { diff --git a/Source/DafnyLanguageServer/Workspace/ChangeProcessors/Relocator.cs b/Source/DafnyLanguageServer/Workspace/ChangeProcessors/Relocator.cs index f8260b4ea79..aebc6891e6b 100644 --- a/Source/DafnyLanguageServer/Workspace/ChangeProcessors/Relocator.cs +++ b/Source/DafnyLanguageServer/Workspace/ChangeProcessors/Relocator.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using System.Text.RegularExpressions; using System.Threading; using Microsoft.Dafny.LanguageServer.Workspace.Notifications; @@ -44,8 +45,10 @@ public VerificationTree RelocateVerificationTree(VerificationTree originalVerifi DidChangeTextDocumentParams changes, CancellationToken cancellationToken) { var changeProcessor = new ChangeProcessor(logger, loggerSymbolTable, changes, cancellationToken); var migratedChildren = changeProcessor.MigrateVerificationTrees(originalVerificationTree.Children); + var migratedRange = changeProcessor.MigrateRange(originalVerificationTree.Range, true); return originalVerificationTree with { Children = migratedChildren.ToList(), + Range = migratedRange!, StatusCurrent = CurrentStatus.Obsolete }; } @@ -87,9 +90,9 @@ public Position MigratePosition(Position position) { }); } - public Range? MigrateRange(Range range) { + public Range? MigrateRange(Range range, bool isFullRange = false) { return changeParams.ContentChanges.Aggregate<TextDocumentContentChangeEvent, Range?>(range, - (intermediateRange, change) => intermediateRange == null ? null : MigrateRange(intermediateRange, change)); + (intermediateRange, change) => intermediateRange == null ? null : MigrateRange(intermediateRange, change, isFullRange)); } public IReadOnlyList<Diagnostic> MigrateDiagnostics(IReadOnlyList<Diagnostic> originalDiagnostics) { @@ -226,9 +229,9 @@ Position Compute() { /// <param name="text">The text to get the LSP end of.</param> /// <param name="cancellationToken">A token to cancel the resolution before its completion.</param> /// <returns>The LSP position at the end of the text.</returns> - /// <exception cref="ArgumentException">Thrown if the specified position does not belong to the given text.</exception> - /// <exception cref="OperationCanceledException">Thrown when the cancellation was requested before completion.</exception> - /// <exception cref="ObjectDisposedException">Thrown if the cancellation token was disposed before the completion.</exception> + /// <exception cref="System.ArgumentException">Thrown if the specified position does not belong to the given text.</exception> + /// <exception cref="System.OperationCanceledException">Thrown when the cancellation was requested before completion.</exception> + /// <exception cref="System.ObjectDisposedException">Thrown if the cancellation token was disposed before the completion.</exception> private static Position GetEofPosition(string text, CancellationToken cancellationToken = default) { int line = 0; int character = 0; @@ -257,9 +260,18 @@ private static bool IsEndOfLine(string text, int absolutePosition) { }; } - public Range? MigrateRange(Range rangeToMigrate, TextDocumentContentChangeEvent change) { - if (!rangeToMigrate.Contains(change.Range!) && rangeToMigrate.Intersects(change.Range!)) { + public Range? MigrateRange(Range rangeToMigrate, TextDocumentContentChangeEvent change, bool isFullRange = false) { + if (change.Range == null || (!rangeToMigrate.Contains(change.Range!) && rangeToMigrate.Intersects(change.Range!))) { // Do not migrate ranges that partially overlap with the change + if (change.Range == null && isFullRange) { + var newLineRegex = new Regex("\n(?<LastColumn>.*)"); + var matches = newLineRegex.Matches(change.Text); + var line = matches.Count; + var col = matches.Count == 0 ? change.Text.Length : matches[^1].Groups["LastColumn"].Value.Length; + + var endPosition = (line, col); + return new Range((0, 0), endPosition); + } return null; } diff --git a/Source/DafnyLanguageServer/Workspace/Notifications/VerificationDiagnosticsParams.cs b/Source/DafnyLanguageServer/Workspace/Notifications/VerificationDiagnosticsParams.cs index e324d2abccf..9d9c97c3f6f 100644 --- a/Source/DafnyLanguageServer/Workspace/Notifications/VerificationDiagnosticsParams.cs +++ b/Source/DafnyLanguageServer/Workspace/Notifications/VerificationDiagnosticsParams.cs @@ -368,14 +368,9 @@ public record DocumentVerificationTree( INode Program, Uri Uri) : VerificationTree("Document", Uri.ToString(), Uri.ToString(), Uri.ToString(), Uri, ComputeRange(Program, Uri), new Position(0, 0)) { - private static Range ComputeRange(INode program, Uri uri) { - var fileNode = FindFileNode(program, uri); - if (fileNode == null) { - return new Range(0, 0, 0, 0); - } + var end = ((Program)program).Files.FirstOrDefault(f => f.RangeToken.Uri == uri)?.EndToken ?? Token.NoToken; - var end = fileNode!.RangeToken.EndToken; while (end.Next != null) { end = end.Next; } @@ -386,13 +381,6 @@ private static Range ComputeRange(INode program, Uri uri) { endPosition.Character + endTriviaLines[^1].Length); return new Range(new Position(0, 0), endPosition); - INode? FindFileNode(INode node, Uri uri) { - if (node.Tok.Uri == uri) { - return node; - } - - return node.Children.Select(child => FindFileNode(child, uri)).FirstOrDefault(x => x != null); - } } } diff --git a/docs/dev/news/4287.fix b/docs/dev/news/4287.fix new file mode 100644 index 00000000000..d2e0b16b991 --- /dev/null +++ b/docs/dev/news/4287.fix @@ -0,0 +1 @@ +Gutter icons more robust \ No newline at end of file From 22550f81409d302acf8ff1784455d4beb3e7b385 Mon Sep 17 00:00:00 2001 From: John Tristan <trjohnb@amazon.com> Date: Fri, 4 Aug 2023 16:57:25 -0400 Subject: [PATCH 07/19] Fixing some of the know logical inconsistencies (#4348) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes # <!-- Is this a user-visible change? Remember to update RELEASE_NOTES.md --> <!-- Is this a bug fix? Remember to include a test in Test/git-issues/ --> <!-- Is this a bug fix for an issue introduced in the latest release? Mention this in the PR details and ensure a patch release is considered --> <!-- Does this PR need tests? Add them to `Test/` or to `Source/*.Test/…` and run them with `dotnet test` --> <!-- Are you moving a large amount of code? Read CONTRIBUTING.md to learn how to do that while maintaining git history --> <small>By submitting this pull request, I confirm that my contribution is made under the terms of the [MIT license](https://github.com/dafny-lang/dafny/blob/master/LICENSE.txt).</small> --- .../HigherOrderHeapAllocationChecker.cs | 89 +++++++++++++++ ...erOrderHeapAllocationCheckerConstructor.cs | 104 ++++++++++++++++++ Source/DafnyCore/Resolver/ModuleResolver.cs | 8 ++ Test/Landin/Knot1.dfy | 14 +++ Test/Landin/Knot1.dfy.expect | 2 + Test/Landin/Knot10.dfy | 16 +++ Test/Landin/Knot10.dfy.expect | 3 + Test/Landin/Knot11.dfy | 16 +++ Test/Landin/Knot11.dfy.expect | 2 + Test/Landin/Knot12.dfy | 17 +++ Test/Landin/Knot12.dfy.expect | 3 + Test/Landin/Knot13.dfy | 20 ++++ Test/Landin/Knot13.dfy.expect | 2 + Test/Landin/Knot2.dfy | 23 ++++ Test/Landin/Knot2.dfy.expect | 3 + Test/Landin/Knot3.dfy | 37 +++++++ Test/Landin/Knot3.dfy.expect | 2 + Test/Landin/Knot4.dfy | 19 ++++ Test/Landin/Knot4.dfy.expect | 2 + Test/Landin/Knot5.dfy | 21 ++++ Test/Landin/Knot5.dfy.expect | 2 + Test/Landin/Knot6.dfy | 31 ++++++ Test/Landin/Knot6.dfy.expect | 3 + Test/Landin/Knot7.dfy | 22 ++++ Test/Landin/Knot7.dfy.expect | 2 + Test/Landin/Knot8.dfy | 15 +++ Test/Landin/Knot8.dfy.expect | 2 + Test/Landin/Knot9.dfy | 22 ++++ Test/Landin/Knot9.dfy.expect | 2 + Test/hofs/FnRef.dfy | 70 ------------ Test/hofs/FnRef.dfy.expect | 6 - 31 files changed, 504 insertions(+), 76 deletions(-) create mode 100644 Source/DafnyCore/Resolver/HigherOrderHeapAllocationChecker.cs create mode 100644 Source/DafnyCore/Resolver/HigherOrderHeapAllocationCheckerConstructor.cs create mode 100644 Test/Landin/Knot1.dfy create mode 100644 Test/Landin/Knot1.dfy.expect create mode 100644 Test/Landin/Knot10.dfy create mode 100644 Test/Landin/Knot10.dfy.expect create mode 100644 Test/Landin/Knot11.dfy create mode 100644 Test/Landin/Knot11.dfy.expect create mode 100644 Test/Landin/Knot12.dfy create mode 100644 Test/Landin/Knot12.dfy.expect create mode 100644 Test/Landin/Knot13.dfy create mode 100644 Test/Landin/Knot13.dfy.expect create mode 100644 Test/Landin/Knot2.dfy create mode 100644 Test/Landin/Knot2.dfy.expect create mode 100644 Test/Landin/Knot3.dfy create mode 100644 Test/Landin/Knot3.dfy.expect create mode 100644 Test/Landin/Knot4.dfy create mode 100644 Test/Landin/Knot4.dfy.expect create mode 100644 Test/Landin/Knot5.dfy create mode 100644 Test/Landin/Knot5.dfy.expect create mode 100644 Test/Landin/Knot6.dfy create mode 100644 Test/Landin/Knot6.dfy.expect create mode 100644 Test/Landin/Knot7.dfy create mode 100644 Test/Landin/Knot7.dfy.expect create mode 100644 Test/Landin/Knot8.dfy create mode 100644 Test/Landin/Knot8.dfy.expect create mode 100644 Test/Landin/Knot9.dfy create mode 100644 Test/Landin/Knot9.dfy.expect delete mode 100644 Test/hofs/FnRef.dfy delete mode 100644 Test/hofs/FnRef.dfy.expect diff --git a/Source/DafnyCore/Resolver/HigherOrderHeapAllocationChecker.cs b/Source/DafnyCore/Resolver/HigherOrderHeapAllocationChecker.cs new file mode 100644 index 00000000000..137aeafb291 --- /dev/null +++ b/Source/DafnyCore/Resolver/HigherOrderHeapAllocationChecker.cs @@ -0,0 +1,89 @@ +//----------------------------------------------------------------------------- +// +// Copyright by the contributors to the Dafny Project +// SPDX-License-Identifier: MIT +// +//----------------------------------------------------------------------------- + +namespace Microsoft.Dafny; + +/// <summary> +/// This checker prevents the definition of non-terminating functions +/// by storing functions in memory (aka Landin's knots) +/// Thanks to frame information, we need not reject all assignments of +/// functions to memory, but only the ones that are know to have a +/// read frame. +/// </summary> +class HigherOrderHeapAllocationChecker : ASTVisitor<IASTVisitorContext> { + private readonly ErrorReporter reporter; + + public HigherOrderHeapAllocationChecker(ErrorReporter reporter) { + this.reporter = reporter; + } + + public override IASTVisitorContext GetContext(IASTVisitorContext astVisitorContext, bool inFunctionPostcondition) { + return astVisitorContext; + } + + /// <summary> + /// ContainsRead is a pure function that visits a type to test + /// for the presence of a memory-reading arrow type ( ~> ). + /// </summary> + private bool ContainsRead(Type rhs) { + + Type type = rhs.NormalizeExpandKeepConstraints(); + + if (type is BasicType) { + return false; + } else if (type is MapType) { + var t = (MapType)type; + return ContainsRead(t.Domain) || ContainsRead(t.Range); + } else if (type is CollectionType) { + var t = (CollectionType)type; + return ContainsRead(t.Arg); + } else { + var t = (UserDefinedType)type; + if (t.IsArrowType && !t.IsArrowTypeWithoutReadEffects) { + return true; + } + return t.TypeArgs.Exists(ContainsRead); + } + + } + + /// <summary> + /// VisitOneStatement checks that we do not store in memory a function of + /// type . ~> . + /// </summary> + protected override bool VisitOneStatement(Statement stmt, IASTVisitorContext context) { + + // Since all updates and variable declarations are eventually broken down into + // assignments, we need only consider an AssignStmt. + if (stmt is AssignStmt { Lhs: { } lhs, Rhs: { } rhs }) { + + // Memory can be updated either by writing to a sequence-like collection + // or by writing to an object's field. + if (lhs is MemberSelectExpr or SeqSelectExpr) { + + // The only case of interest is when the right hand side of the assignment + // is an expression. The case where it is a type expression (new) is handled + // by a different check. + if (rhs is ExprRhs { Expr: { Type: { } type } }) { + + // If the assignment contains a function with read effects, it must be rejected. + // It would not be enough to check that the RHS is of type . ~> . because + // one can hide such a function deep into another type. + // It is plausible that using write frame information, we could relax this check + // by ensuring that the read frame of the function and the write frame of the context + // are disjoint, but this would require an inter-procedural analysis. + if (ContainsRead(type)) { + reporter.Error(MessageSource.Resolver, stmt, + "To prevent the creation of non-terminating functions, storing functions with read effects into memory is disallowed"); + } + } + } + } + + return base.VisitOneStatement(stmt, context); + } +} \ No newline at end of file diff --git a/Source/DafnyCore/Resolver/HigherOrderHeapAllocationCheckerConstructor.cs b/Source/DafnyCore/Resolver/HigherOrderHeapAllocationCheckerConstructor.cs new file mode 100644 index 00000000000..1d67484bd3e --- /dev/null +++ b/Source/DafnyCore/Resolver/HigherOrderHeapAllocationCheckerConstructor.cs @@ -0,0 +1,104 @@ +//----------------------------------------------------------------------------- +// +// Copyright by the contributors to the Dafny Project +// SPDX-License-Identifier: MIT +// +//----------------------------------------------------------------------------- + +namespace Microsoft.Dafny; + +/// <summary> +/// This checker prevents the definition of non-terminating functions +/// by storing functions in memory (aka Landin's knots) during the +/// creation of an object. This could also be prevented by doing +/// a cardinality check on the type of class (similar to what is done +/// for algebraic datatypes) but at a fundamental level, the issue is +/// the creation of a Landin's knot, and it is easier and safer to catch +/// this way because of type parameters and traits. +/// Thanks to frame information, we need not reject all assignments of +/// functions to memory, but only the ones that are know to have a +/// read frame. +/// To understand this checker, it is recommended to first look at +/// HigherOrderHeapAllocationChecker. +/// </summary> +class HigherOrderHeapAllocationCheckerConstructor : ASTVisitor<IASTVisitorContext> { + private readonly ErrorReporter reporter; + + public HigherOrderHeapAllocationCheckerConstructor(ErrorReporter reporter) { + this.reporter = reporter; + } + + public override IASTVisitorContext GetContext(IASTVisitorContext astVisitorContext, bool inFunctionPostcondition) { + return astVisitorContext; + } + + /// <summary> + /// Occurs is a pure function that visits a type (rhs) to test + /// for the presence of an heap-allocated type (Obj) left of + /// an arrow. + /// This check could be relaxed but we keep it simple until + /// we encounter a good use case for the more general check. + /// Recall that a cycle can only be created using a function, + /// which is why the test is different than a traditional + /// cardinality test. + /// </summary> + private bool Occurs(Type obj, Type rhs, bool left) { + Type type = rhs.NormalizeExpandKeepConstraints(); + if (type is BasicType) { + return false; + } else if (type is MapType) { + var t = (MapType)type; + return Occurs(obj, t.Domain, left) || Occurs(obj, t.Range, left); + } else if (type is SetType) { + var t = (SetType)type; + return Occurs(obj, t.Arg, left); + } else if (type is CollectionType) { + var t = (CollectionType)type; + return Occurs(obj, t.Arg, left); + } else { + var t = (UserDefinedType)type; + if (left && Type.Equal_Improved(obj, t)) { + return true; + } + var b = false; + if (t.IsArrowType) { + var arrow = type.AsArrowType; + b = b || arrow.TypeArgs.Exists(typeArg => Occurs(obj, typeArg, true)); + } + return b || t.TypeArgs.Exists(typeArg => Occurs(obj, typeArg, left)); + } + } + + protected override bool VisitOneStatement(Statement stmt, IASTVisitorContext context) { + + // Assigments to constant fields in constructors boil down to an assignment. + if (stmt is AssignStmt assign) { + + var lhs = assign.Lhs; + Type lhsType; + + // We need to make sure that if a function is written to a field + // it does not refer to the type of the object being assigned to. + // Note that the function may not be of type . ~> . because + // functions of type . ~> . can be assigned to constant fields + // of type . -> . during the object's construction. + if (lhs is MemberSelectExpr mseLhs) { + + lhsType = mseLhs.Obj.Type.NormalizeExpandKeepConstraints(); + + var rhs = assign.Rhs; + if (rhs is ExprRhs eRhs) { + var exp = eRhs.Expr; + var type = exp.Type; + + if (Occurs(lhsType, type, false)) { + reporter.Error(MessageSource.Resolver, stmt, + "To prevent the creation of non-terminating functions, storing functions into an object's fields that reads the object is disallowed"); + } + } + } + } + + return base.VisitOneStatement(stmt, context); + } +} \ No newline at end of file diff --git a/Source/DafnyCore/Resolver/ModuleResolver.cs b/Source/DafnyCore/Resolver/ModuleResolver.cs index 757b3e98bcb..a3245ff9974 100644 --- a/Source/DafnyCore/Resolver/ModuleResolver.cs +++ b/Source/DafnyCore/Resolver/ModuleResolver.cs @@ -1499,6 +1499,14 @@ public void ResolveTopLevelDecls_Core(List<TopLevelDecl> declarations, } } + if (reporter.Count(ErrorLevel.Error) == prevErrorCount) { + new HigherOrderHeapAllocationChecker(reporter).VisitDeclarations(declarations); + } + + if (reporter.Count(ErrorLevel.Error) == prevErrorCount) { + new HigherOrderHeapAllocationCheckerConstructor(reporter).VisitDeclarations(declarations); + } + if (reporter.Count(ErrorLevel.Error) == prevErrorCount) { // Check that usage of "this" is restricted before "new;" in constructor bodies, // and that a class without any constructor only has fields with known initializers. diff --git a/Test/Landin/Knot1.dfy b/Test/Landin/Knot1.dfy new file mode 100644 index 00000000000..393bafc4423 --- /dev/null +++ b/Test/Landin/Knot1.dfy @@ -0,0 +1,14 @@ +// RUN: %exits-with 2 %dafny /compile:0 "%s" > "%t" +// RUN: %diff "%s.expect" "%t" + +class Ref { + ghost var hogp: () ~> int +} + +method Main() + ensures false +{ + var r := new Ref; + // error: r.hogp calls itself without decreasing + r.hogp := () reads r, r.hogp.reads() => if r.hogp.requires() then 1 + r.hogp() else 0; +} \ No newline at end of file diff --git a/Test/Landin/Knot1.dfy.expect b/Test/Landin/Knot1.dfy.expect new file mode 100644 index 00000000000..fe747f06712 --- /dev/null +++ b/Test/Landin/Knot1.dfy.expect @@ -0,0 +1,2 @@ +Knot1.dfy(13,9): Error: To prevent the creation of non-terminating functions, storing functions with read effects into memory is disallowed +1 resolution/type errors detected in Knot1.dfy diff --git a/Test/Landin/Knot10.dfy b/Test/Landin/Knot10.dfy new file mode 100644 index 00000000000..fa86b6e6b63 --- /dev/null +++ b/Test/Landin/Knot10.dfy @@ -0,0 +1,16 @@ +// RUN: %exits-with 2 %dafny /compile:0 "%s" > "%t" +// RUN: %diff "%s.expect" "%t" + +datatype Pack<T> = Pack(ghost c: T) + +method M() + ensures false +{ + var r := new Pack<() ~> bool>[1]; + r[0] := Pack(() => false); + var tf := Pack(() reads r, r[0].c.reads => + if r[0].c.requires() then !r[0].c() else false + ); + // error: r[0] calls itself without decreasing + r[0] := tf; +} \ No newline at end of file diff --git a/Test/Landin/Knot10.dfy.expect b/Test/Landin/Knot10.dfy.expect new file mode 100644 index 00000000000..f9708d94c12 --- /dev/null +++ b/Test/Landin/Knot10.dfy.expect @@ -0,0 +1,3 @@ +Knot10.dfy(10,7): Error: To prevent the creation of non-terminating functions, storing functions with read effects into memory is disallowed +Knot10.dfy(15,7): Error: To prevent the creation of non-terminating functions, storing functions with read effects into memory is disallowed +2 resolution/type errors detected in Knot10.dfy diff --git a/Test/Landin/Knot11.dfy b/Test/Landin/Knot11.dfy new file mode 100644 index 00000000000..d1c22198347 --- /dev/null +++ b/Test/Landin/Knot11.dfy @@ -0,0 +1,16 @@ +// RUN: %exits-with 2 %dafny /compile:0 "%s" > "%t" +// RUN: %diff "%s.expect" "%t" + +datatype Pack<T> = Pack(ghost c: T) + +class Ref { + ghost var hogp: Pack<() ~> int> +} + +method Main() + ensures false +{ + var r := new Ref; + // error: r.hogp calls itself without decreasing + r.hogp := Pack(() reads r, r.hogp.c.reads() => if r.hogp.c.requires() then 1 + r.hogp.c() else 0); +} \ No newline at end of file diff --git a/Test/Landin/Knot11.dfy.expect b/Test/Landin/Knot11.dfy.expect new file mode 100644 index 00000000000..e5c0b661b4d --- /dev/null +++ b/Test/Landin/Knot11.dfy.expect @@ -0,0 +1,2 @@ +Knot11.dfy(15,9): Error: To prevent the creation of non-terminating functions, storing functions with read effects into memory is disallowed +1 resolution/type errors detected in Knot11.dfy diff --git a/Test/Landin/Knot12.dfy b/Test/Landin/Knot12.dfy new file mode 100644 index 00000000000..d32ba0817de --- /dev/null +++ b/Test/Landin/Knot12.dfy @@ -0,0 +1,17 @@ +// RUN: %exits-with 2 %dafny /compile:0 "%s" > "%t" +// RUN: %diff "%s.expect" "%t" + +datatype Pack<T> = Pack(ghost c: T) + +method M() + ensures false +{ + var r := new array<Pack<() ~> bool>>[1]; + r[0] := new Pack<() ~> bool>[1]; + r[0][0] := Pack(() => false); + var tf := Pack(() reads r, r[0], r[0][0].c.reads => + if r[0][0].c.requires() then !r[0][0].c() else false + ); + // error: r[0][0].c calls itself without decreasing + r[0][0] := tf; +} \ No newline at end of file diff --git a/Test/Landin/Knot12.dfy.expect b/Test/Landin/Knot12.dfy.expect new file mode 100644 index 00000000000..0efe5ead486 --- /dev/null +++ b/Test/Landin/Knot12.dfy.expect @@ -0,0 +1,3 @@ +Knot12.dfy(11,10): Error: To prevent the creation of non-terminating functions, storing functions with read effects into memory is disallowed +Knot12.dfy(16,10): Error: To prevent the creation of non-terminating functions, storing functions with read effects into memory is disallowed +2 resolution/type errors detected in Knot12.dfy diff --git a/Test/Landin/Knot13.dfy b/Test/Landin/Knot13.dfy new file mode 100644 index 00000000000..8f1b7fdd82a --- /dev/null +++ b/Test/Landin/Knot13.dfy @@ -0,0 +1,20 @@ +// RUN: %exits-with 2 %dafny /compile:0 "%s" > "%t" +// RUN: %diff "%s.expect" "%t" + +class Ref1 { + ghost var hogp: () ~> int +} + +class Ref2 { + ghost var r: Ref1 + constructor() +} + +method Main() + ensures false +{ + var r := new Ref2(); + r.r := new Ref1; + // error: r.r.hogp calls itself without decreasing + r.r.hogp := () reads r, r.r, r.r.hogp.reads() => if r.r.hogp.requires() then 1 + r.r.hogp() else 0; +} \ No newline at end of file diff --git a/Test/Landin/Knot13.dfy.expect b/Test/Landin/Knot13.dfy.expect new file mode 100644 index 00000000000..146c4d5ddb3 --- /dev/null +++ b/Test/Landin/Knot13.dfy.expect @@ -0,0 +1,2 @@ +Knot13.dfy(19,11): Error: To prevent the creation of non-terminating functions, storing functions with read effects into memory is disallowed +1 resolution/type errors detected in Knot13.dfy diff --git a/Test/Landin/Knot2.dfy b/Test/Landin/Knot2.dfy new file mode 100644 index 00000000000..424a585a0a0 --- /dev/null +++ b/Test/Landin/Knot2.dfy @@ -0,0 +1,23 @@ +// RUN: %exits-with 2 %dafny /compile:0 "%s" > "%t" +// RUN: %diff "%s.expect" "%t" + +class Ref { + ghost var hogp: () ~> int +} + +method LogicKnot(r1: Ref,r2: Ref) + modifies r1, r2 + ensures false +{ + // error: r1.hogp and r2.hogp call each others without decreasing + r1.hogp := () reads r2, r2.hogp.reads() => if r2.hogp.requires() then 1 + r2.hogp() else 0; + r2.hogp := () reads r1, r1.hogp.reads() => if r1.hogp.requires() then 1 + r1.hogp() else 0; +} + +method Main() + ensures false +{ + var r1 := new Ref; + var r2 := new Ref; + LogicKnot(r1,r2); +} \ No newline at end of file diff --git a/Test/Landin/Knot2.dfy.expect b/Test/Landin/Knot2.dfy.expect new file mode 100644 index 00000000000..5c60fa4bb18 --- /dev/null +++ b/Test/Landin/Knot2.dfy.expect @@ -0,0 +1,3 @@ +Knot2.dfy(13,10): Error: To prevent the creation of non-terminating functions, storing functions with read effects into memory is disallowed +Knot2.dfy(14,10): Error: To prevent the creation of non-terminating functions, storing functions with read effects into memory is disallowed +2 resolution/type errors detected in Knot2.dfy diff --git a/Test/Landin/Knot3.dfy b/Test/Landin/Knot3.dfy new file mode 100644 index 00000000000..615dadcf526 --- /dev/null +++ b/Test/Landin/Knot3.dfy @@ -0,0 +1,37 @@ +// RUN: %exits-with 2 %dafny /compile:0 "%s" > "%t" +// RUN: %diff "%s.expect" "%t" + +class C { + + var f: () ~> bool + + constructor() + ensures Invariant() + { + f := () requires true => true; + } + + ghost predicate Invariant() + reads this, f.reads() + { + f.requires() + } + +} + +method update(t: C) + modifies t + requires t.Invariant() + ensures false +{ + // error: t.f calls itself without decreasing + t.f := () reads t, t.f.reads() requires t.f.requires() => !t.f(); + assert t.f.requires() == old(t.f).requires(); + var b := t.f(); +} + +method Main() +{ + var t := new C(); + update(t); +} \ No newline at end of file diff --git a/Test/Landin/Knot3.dfy.expect b/Test/Landin/Knot3.dfy.expect new file mode 100644 index 00000000000..96dbb2d515b --- /dev/null +++ b/Test/Landin/Knot3.dfy.expect @@ -0,0 +1,2 @@ +Knot3.dfy(28,6): Error: To prevent the creation of non-terminating functions, storing functions with read effects into memory is disallowed +1 resolution/type errors detected in Knot3.dfy diff --git a/Test/Landin/Knot4.dfy b/Test/Landin/Knot4.dfy new file mode 100644 index 00000000000..0578e062c87 --- /dev/null +++ b/Test/Landin/Knot4.dfy @@ -0,0 +1,19 @@ +// RUN: %exits-with 2 %dafny /compile:0 "%s" > "%t" +// RUN: %diff "%s.expect" "%t" + +class Y { + const f: Y -> nat // Type error here? because since Y can be accessed, -> should be ~> + constructor(f: Y -> nat) + ensures this.f == f + { + this.f := f; + } +} + +method Main() + ensures false +{ + // error: knot.f calls itself without decreasing + var knot := new Y((x: Y) => 1 + x.f(x)); // Why doesn't it have a reads clause? Because f can pretend that it does not + var a := knot.f(knot); +} \ No newline at end of file diff --git a/Test/Landin/Knot4.dfy.expect b/Test/Landin/Knot4.dfy.expect new file mode 100644 index 00000000000..df63cf4c882 --- /dev/null +++ b/Test/Landin/Knot4.dfy.expect @@ -0,0 +1,2 @@ +Knot4.dfy(9,11): Error: To prevent the creation of non-terminating functions, storing functions into an object's fields that reads the object is disallowed +1 resolution/type errors detected in Knot4.dfy diff --git a/Test/Landin/Knot5.dfy b/Test/Landin/Knot5.dfy new file mode 100644 index 00000000000..f0c7e1956a2 --- /dev/null +++ b/Test/Landin/Knot5.dfy @@ -0,0 +1,21 @@ +// RUN: %exits-with 2 %dafny /compile:0 "%s" > "%t" +// RUN: %diff "%s.expect" "%t" + +datatype Pack<T> = Pack(ghost c: T) + +class Y { + const f: Pack<Y -> nat> + constructor(f: Pack<Y -> nat>) + ensures this.f == f + { + this.f := f; + } +} + +method Main() + ensures false +{ + // error: x.f.c calls itself without decreasing + var knot := new Y(Pack((x: Y) => 1 + x.f.c(x))); + var a := knot.f.c(knot); +} \ No newline at end of file diff --git a/Test/Landin/Knot5.dfy.expect b/Test/Landin/Knot5.dfy.expect new file mode 100644 index 00000000000..e3bbc4541e7 --- /dev/null +++ b/Test/Landin/Knot5.dfy.expect @@ -0,0 +1,2 @@ +Knot5.dfy(11,11): Error: To prevent the creation of non-terminating functions, storing functions into an object's fields that reads the object is disallowed +1 resolution/type errors detected in Knot5.dfy diff --git a/Test/Landin/Knot6.dfy b/Test/Landin/Knot6.dfy new file mode 100644 index 00000000000..bf50f64ad96 --- /dev/null +++ b/Test/Landin/Knot6.dfy @@ -0,0 +1,31 @@ +// RUN: %exits-with 2 %dafny /compile:0 "%s" > "%t" +// RUN: %diff "%s.expect" "%t" + +class Ref { + ghost var hogp: () ~> int +} + +method LogicKnot1(r1: Ref,r2: Ref) + modifies r1 + ensures r1.hogp == (() reads r2, r2.hogp.reads() => if r2.hogp.requires() then 1 + r2.hogp() else 0) +{ + // error: r1.hogp calls itself through r2.hogp without decreasing + r1.hogp := () reads r2, r2.hogp.reads() => if r2.hogp.requires() then 1 + r2.hogp() else 0; +} + +method LogicKnot2(r1: Ref,r2: Ref) + modifies r2 + ensures r2.hogp == (() reads r1, r1.hogp.reads() => if r1.hogp.requires() then 1 + r1.hogp() else 0) +{ + // error: r1.hogp calls itself through r1.hogp without decreasing + r2.hogp := () reads r1, r1.hogp.reads() => if r1.hogp.requires() then 1 + r1.hogp() else 0; +} + +method Main() + ensures false +{ + var r1 := new Ref; + var r2 := new Ref; + LogicKnot1(r1,r2); + LogicKnot2(r1,r2); +} diff --git a/Test/Landin/Knot6.dfy.expect b/Test/Landin/Knot6.dfy.expect new file mode 100644 index 00000000000..7e6e271ae68 --- /dev/null +++ b/Test/Landin/Knot6.dfy.expect @@ -0,0 +1,3 @@ +Knot6.dfy(13,10): Error: To prevent the creation of non-terminating functions, storing functions with read effects into memory is disallowed +Knot6.dfy(21,10): Error: To prevent the creation of non-terminating functions, storing functions with read effects into memory is disallowed +2 resolution/type errors detected in Knot6.dfy diff --git a/Test/Landin/Knot7.dfy b/Test/Landin/Knot7.dfy new file mode 100644 index 00000000000..a8859414526 --- /dev/null +++ b/Test/Landin/Knot7.dfy @@ -0,0 +1,22 @@ +// RUN: %exits-with 2 %dafny /compile:0 "%s" > "%t" +// RUN: %diff "%s.expect" "%t" + +class Ref { + ghost var hogp: Ref ~> int +} + +ghost function F(r: Ref): int + reads r, r.hogp.reads(r) +{ + if r.hogp.requires(r) then 1 + r.hogp(r) else 0 +} + + +method Main() + ensures false +{ + var r := new Ref; + r.hogp := F; + // error: r.hogp calls itself without decreasing + var f := r.hogp(r); +} \ No newline at end of file diff --git a/Test/Landin/Knot7.dfy.expect b/Test/Landin/Knot7.dfy.expect new file mode 100644 index 00000000000..ca643337033 --- /dev/null +++ b/Test/Landin/Knot7.dfy.expect @@ -0,0 +1,2 @@ +Knot7.dfy(19,9): Error: To prevent the creation of non-terminating functions, storing functions with read effects into memory is disallowed +1 resolution/type errors detected in Knot7.dfy diff --git a/Test/Landin/Knot8.dfy b/Test/Landin/Knot8.dfy new file mode 100644 index 00000000000..a084e565619 --- /dev/null +++ b/Test/Landin/Knot8.dfy @@ -0,0 +1,15 @@ +// RUN: %exits-with 2 %dafny /compile:0 "%s" > "%t" +// RUN: %diff "%s.expect" "%t" + +class Ref<T> { + ghost var hogp: T + constructor() +} + +method Main() + ensures false +{ + var r := new Ref<() ~> int>(); + // error: r.hogp calls itself without decreasing + r.hogp := () reads r, r.hogp.reads() => if r.hogp.requires() then 1 + r.hogp() else 0; +} \ No newline at end of file diff --git a/Test/Landin/Knot8.dfy.expect b/Test/Landin/Knot8.dfy.expect new file mode 100644 index 00000000000..a0d24196f0a --- /dev/null +++ b/Test/Landin/Knot8.dfy.expect @@ -0,0 +1,2 @@ +Knot8.dfy(14,9): Error: To prevent the creation of non-terminating functions, storing functions with read effects into memory is disallowed +1 resolution/type errors detected in Knot8.dfy diff --git a/Test/Landin/Knot9.dfy b/Test/Landin/Knot9.dfy new file mode 100644 index 00000000000..68db757c202 --- /dev/null +++ b/Test/Landin/Knot9.dfy @@ -0,0 +1,22 @@ +// RUN: %exits-with 2 %dafny /compile:0 "%s" > "%t" +// RUN: %diff "%s.expect" "%t" + +trait T<U> { + const f: U -> nat // Type error here? because since Y can be accessed, -> should be ~> +} + +class Y extends T<Y> { + constructor(f: Y -> nat) + ensures this.f == f + { + this.f := f; + } +} + +method Main() + ensures false +{ + // error: x.f calls itself without decreasing + var knot := new Y((x: Y) => 1 + x.f(x)); // Why doesn't it have a reads clause? Because f can pretend that it does not + var a := knot.f(knot); +} \ No newline at end of file diff --git a/Test/Landin/Knot9.dfy.expect b/Test/Landin/Knot9.dfy.expect new file mode 100644 index 00000000000..4ea30a7cfdb --- /dev/null +++ b/Test/Landin/Knot9.dfy.expect @@ -0,0 +1,2 @@ +Knot9.dfy(12,11): Error: To prevent the creation of non-terminating functions, storing functions into an object's fields that reads the object is disallowed +1 resolution/type errors detected in Knot9.dfy diff --git a/Test/hofs/FnRef.dfy b/Test/hofs/FnRef.dfy deleted file mode 100644 index f7bb3ccfce9..00000000000 --- a/Test/hofs/FnRef.dfy +++ /dev/null @@ -1,70 +0,0 @@ -// RUN: %exits-with 4 %dafny /print:"%t.print" "%s" > "%t" -// RUN: %diff "%s.expect" "%t" - - -class Ref<A(0)> { - var val: A -} - -method Nope() { - var f : Ref<int ~> bool>; - var g : int ~> bool; - - f := new Ref<int ~> bool>; - - f.val := x => true; - - g := x reads f reads f.val.reads(x) => !f.val(x); -} - -method M() { - var f : Ref<int ~> bool>; - var g : int ~> bool; - - f := new Ref<int ~> bool>; - - f.val := x => true; - - g := x reads f reads f.val.reads(x) requires f.val.requires(x) => !f.val(x); - - f.val := g; - - if (!g(0)) { - assert !g(0); - } else { - assert g(0); - } -} - - -method L() { - var f : Ref<() ~> bool>; - f := new Ref<() ~> bool>; - f.val := () reads f reads f.val.reads() requires !f.val.requires() => true; - - if (f.val.requires()) { - assert !f.val.requires(); - } else { - assert f.val.requires(); - } -} - -method LRead() { - var o : object?; - var f : Ref<() ~> bool>; - f := new Ref<() ~> bool>; - f.val := () reads f - reads f.val.reads() - reads if o in f.val.reads() then {} else {o} - => true; - - assume o != null; - assert o != f; - - if (o in f.val.reads()) { - assert o !in f.val.reads(); - } else { - assert o in f.val.reads(); - } -} - diff --git a/Test/hofs/FnRef.dfy.expect b/Test/hofs/FnRef.dfy.expect deleted file mode 100644 index a302444c941..00000000000 --- a/Test/hofs/FnRef.dfy.expect +++ /dev/null @@ -1,6 +0,0 @@ -FnRef.dfy(17,44): Error: function precondition could not be proved -FnRef.dfy(32,7): Error: function precondition could not be proved -FnRef.dfy(46,11): Error: assertion might not hold -FnRef.dfy(65,13): Error: assertion might not hold - -Dafny program verifier finished with 0 verified, 4 errors From 2a37f3783d3305cd7eb8c4c42d39929cf7a9cc39 Mon Sep 17 00:00:00 2001 From: Rustan Leino <leino@amazon.com> Date: Fri, 4 Aug 2023 15:42:15 -0700 Subject: [PATCH 08/19] Add new type inference, under /typeSystemRefresh:1 (#4323) This PR contains the bulk of the long-awaited changes of the Dafny's new type system. Most of the changes are to implement a new type inference. This was necessary, because the previous implementation was very complicated and difficult to understand and modify. The new type inference is more straightforward (see, e.g., the description in https://github.com/dafny-lang/dafny/pull/4134). Unlike the previous type system, the new one supports traits over datatypes and lays the groundwork for some other type-system changes we planning in the months ahead. The changes in this PR are under the option `--type-system-refresh` (legacy `/typeSystemRefresh:1`), except for some minor improvements (e.g., a better error source location for modify statements). (Also, to use traits over datatypes, it is also necessary to use `--general-traits` / `/generalTraits:1`.) While this PR contains the core parts of the new type system, these changes are not final. However, **it makes sense to get these changes into the master branch at this time**, to more easily keep other changes in synch. For this reason, I don't know at what level of detail this PR ought to be reviewed. Because the changes are isolated to the `--type-system-refresh` option and because we should do a comprehensive review of the the system before we switch to making it the default in Dafny, there will be another chance to review anything that is more shallowly or leniently reviewed at this time. From a functionality standpoint, the biggest thing missing from this PR is inference of subset types. For example, for a class `C`, this PR may infer the type `C?` rather than the non-null type `C`. In some cases, this will just make the verifier work harder, but in other cases (e.g., when a local variable has such a type and the local variable is modified inside a loop), the new type inference in this PR may generate an error. The additional precision that comes from considering subset types will be added in a separate PR. One actual _change_ in the type system is worth highlighting: Consider a `trait Tr` and a `class Cl extends Tr`. In the type system of Dafny today, `Tr` is assignable to `Cl` without an explicit cast. But in the new type system, this require an explicit cast. (Note, what I just said applies to traits, not subset types. So, for example, there is no change in how an `int` can be assigned to a `nat`.) ## Basic approach The basic approach (see also the description of https://github.com/dafny-lang/dafny/pull/4134, whose changes are included in this PR) is to * First, infer _pre-types_. These are the parts of types that don't depend on theorem proving. In other words, they are what you get if you replace subset types with their base types. * Then, make the types more precise by considering subset types. (This step is not included in this PR.) ## Additional notes In the implementation, some of the resolver's fields had to be made more accessible (e.g., changing method `FreeVariables` to be `public`). Error messages generated by the new type inference include the string `PRE-TYPE:`. This continues to be useful in debugging, but will be removed by the time we start recommending the new type system. The PR disables CI coverage tests for the new code, because the test suite has not yet been changed to use the new type system. The code contains some TODO's that will be filled in by later PRs. This is not standard practice, but I don't want to lose track of these TODO's and the code surrounding them is need to make everything compile and run. <small>By submitting this pull request, I confirm that my contribution is made under the terms of the [MIT license](https://github.com/dafny-lang/dafny/blob/master/LICENSE.txt).</small> --- .../AST/Expressions/DefaultValueExpression.cs | 24 + .../AST/Expressions/Variables/CasePattern.cs | 22 + Source/DafnyCore/Dafny.atg | 2 +- Source/DafnyCore/Resolver/ModuleResolver.cs | 38 +- .../CheckTypeInferenceVisitor.cs | 10 +- .../NameResolutionAndTypeInference.cs | 16 - .../Resolver/ObjectConstructorChecker.cs | 36 + .../Resolver/PreType/PreTypeAdvice.cs | 2 +- .../Resolver/PreType/PreTypeConstraints.cs | 122 +- .../PreTypeResolve.ActualParameters.cs | 186 ++ .../PreType/PreTypeResolve.Expressions.cs | 2180 +++++++++++++++++ .../PreType/PreTypeResolve.Statements.cs | 1385 +++++++++++ .../Resolver/PreType/PreTypeResolve.cs | 1115 ++++++++- .../Resolver/PreType/PreTypeResolver.Match.cs | 208 ++ .../Resolver/PreType/PreTypeToType.cs | 93 +- Source/DafnyCore/Resolver/ProgramResolver.cs | 10 + Test/dafny0/Datatypes.dfy | 18 +- .../ForbidNondeterminismCompile.dfy.expect | 2 +- .../GhostAllocations-Resolution.dfy.expect | 10 +- Test/dafny0/GhostAllocations.dfy.expect | 4 +- Test/dafny0/IteratorResolution.dfy | 32 +- Test/dafny0/IteratorResolution.dfy.expect | 7 +- Test/dafny0/ModifyStmt.dfy.expect | 16 +- Test/dafny0/ModuleExport.dfy | 12 +- Test/dafny0/ModuleExport.dfy.expect | 23 +- Test/dafny0/Modules0.dfy | 20 +- Test/dafny0/Modules0.dfy.expect | 3 +- Test/dafny0/OnDemandResolutionCycle.dfy | 24 + .../dafny0/OnDemandResolutionCycle.dfy.expect | 12 + Test/dafny0/OnDemandResolutionOrdering.dfy | 161 ++ .../OnDemandResolutionOrdering.dfy.expect | 6 + Test/dafny0/ParallelResolveErrors.dfy.expect | 8 +- Test/dafny0/Refinement.dfy.expect | 2 +- Test/dafny0/ResolutionErrors.dfy | 80 +- Test/dafny0/ResolutionErrors.dfy.expect | 1172 ++++----- Test/dafny0/TypeInferenceRefresh.dfy | 1061 ++++++++ Test/dafny0/TypeInferenceRefresh.dfy.expect | 15 + Test/dafny0/TypeInferenceRefreshErrors.dfy | 225 ++ .../TypeInferenceRefreshErrors.dfy.expect | 17 + .../ClassRefinement.dfy.verifier.expect | 2 +- Test/exports/ExportResolve.dfy | 23 +- Test/exports/ExportResolve.dfy.expect | 10 +- Test/git-issues/git-issue-1252.dfy.expect | 2 +- Test/git-issues/git-issue-4272.dfy | 17 + Test/git-issues/git-issue-4272.dfy.expect | 2 + Test/traits/GeneralTraits.dfy | 150 ++ Test/traits/GeneralTraits.dfy.expect | 26 + Test/traits/GeneralTraitsCompile.dfy | 442 ++++ Test/traits/GeneralTraitsCompile.dfy.expect | 66 + Test/traits/GeneralTraitsVerify.dfy | 471 ++++ Test/traits/GeneralTraitsVerify.dfy.expect | 9 + Test/traits/TraitResolution1.dfy.expect | 9 +- Test/traits/TraitResolution2.dfy.expect | 9 +- 53 files changed, 8787 insertions(+), 830 deletions(-) create mode 100644 Source/DafnyCore/Resolver/ObjectConstructorChecker.cs create mode 100644 Source/DafnyCore/Resolver/PreType/PreTypeResolve.ActualParameters.cs create mode 100644 Source/DafnyCore/Resolver/PreType/PreTypeResolve.Expressions.cs create mode 100644 Source/DafnyCore/Resolver/PreType/PreTypeResolve.Statements.cs create mode 100644 Source/DafnyCore/Resolver/PreType/PreTypeResolver.Match.cs create mode 100644 Test/dafny0/OnDemandResolutionCycle.dfy create mode 100644 Test/dafny0/OnDemandResolutionCycle.dfy.expect create mode 100644 Test/dafny0/OnDemandResolutionOrdering.dfy create mode 100644 Test/dafny0/OnDemandResolutionOrdering.dfy.expect create mode 100644 Test/dafny0/TypeInferenceRefresh.dfy create mode 100644 Test/dafny0/TypeInferenceRefresh.dfy.expect create mode 100644 Test/dafny0/TypeInferenceRefreshErrors.dfy create mode 100644 Test/dafny0/TypeInferenceRefreshErrors.dfy.expect create mode 100644 Test/git-issues/git-issue-4272.dfy create mode 100644 Test/git-issues/git-issue-4272.dfy.expect create mode 100644 Test/traits/GeneralTraits.dfy create mode 100644 Test/traits/GeneralTraits.dfy.expect create mode 100644 Test/traits/GeneralTraitsCompile.dfy create mode 100644 Test/traits/GeneralTraitsCompile.dfy.expect create mode 100644 Test/traits/GeneralTraitsVerify.dfy create mode 100644 Test/traits/GeneralTraitsVerify.dfy.expect diff --git a/Source/DafnyCore/AST/Expressions/DefaultValueExpression.cs b/Source/DafnyCore/AST/Expressions/DefaultValueExpression.cs index ab62da5cf29..5df4f73ee03 100644 --- a/Source/DafnyCore/AST/Expressions/DefaultValueExpression.cs +++ b/Source/DafnyCore/AST/Expressions/DefaultValueExpression.cs @@ -57,4 +57,28 @@ public DefaultValueExpression(Cloner cloner, DefaultValueExpression original) : public DefaultValueExpression Clone(Cloner cloner) { return new DefaultValueExpression(cloner, this); } +} + +/// TODO: This class is a bit sketchy. It should probably be used to replace DefaultValueExpression in some way. +/// </summary> +public class DefaultValueExpressionPreType : ConcreteSyntaxExpression { + public readonly Formal Formal; + public readonly Expression Receiver; + public readonly Dictionary<IVariable, Expression> SubstMap; + public readonly Dictionary<TypeParameter, PreType> PreTypeMap; + + public DefaultValueExpressionPreType(IToken tok, Formal formal, + Expression/*?*/ receiver, Dictionary<IVariable, Expression> substMap, Dictionary<TypeParameter, PreType> preTypeMap) + : base(tok) { + Contract.Requires(tok != null); + Contract.Requires(formal != null); + Contract.Requires(formal.DefaultValue != null); + Contract.Requires(substMap != null); + Contract.Requires(preTypeMap != null); + Formal = formal; + Receiver = receiver; + SubstMap = substMap; + PreTypeMap = preTypeMap; + PreType = formal.PreType.Substitute(preTypeMap); + } } \ No newline at end of file diff --git a/Source/DafnyCore/AST/Expressions/Variables/CasePattern.cs b/Source/DafnyCore/AST/Expressions/Variables/CasePattern.cs index ff876ce9ae0..7dca93bd5e1 100644 --- a/Source/DafnyCore/AST/Expressions/Variables/CasePattern.cs +++ b/Source/DafnyCore/AST/Expressions/Variables/CasePattern.cs @@ -86,6 +86,28 @@ public void AssembleExpr(List<Type> dtvTypeArgs) { } } + /// <summary> + /// Sets the Expr field. Assumes the CasePattern and its arguments to have been successfully resolved, except for assigning + /// to Expr. + /// </summary> + public void AssembleExprPreType(List<PreType> dtvPreTypeArgs) { + Contract.Requires(Var != null || dtvPreTypeArgs != null); + if (Var != null) { + Contract.Assert(this.Id == this.Var.Name); + this.Expr = new IdentifierExpr(this.tok, this.Var) { + PreType = this.Var.PreType + }; + } else { + var dtValue = new DatatypeValue(this.tok, this.Ctor.EnclosingDatatype.Name, this.Id, + this.Arguments == null ? new List<Expression>() : this.Arguments.ConvertAll(arg => arg.Expr)) { + Ctor = this.Ctor, + PreType = new DPreType(this.Ctor.EnclosingDatatype, dtvPreTypeArgs) + }; + dtValue.InferredPreTypeArgs.AddRange(dtvPreTypeArgs); // resolve here + this.Expr = dtValue; + } + } + public IEnumerable<VT> Vars { get { if (Var != null) { diff --git a/Source/DafnyCore/Dafny.atg b/Source/DafnyCore/Dafny.atg index f791cbe2ee7..bdcc8a8877d 100644 --- a/Source/DafnyCore/Dafny.atg +++ b/Source/DafnyCore/Dafny.atg @@ -3784,7 +3784,7 @@ ModifyStmt<out Statement s> .) ) ( BlockStmt<out body, out bodyStart, out endTok> - (. errors.Deprecated(ErrorId.p_deprecated_modify_statement_with_block, t, "the modify statement with a block statement is deprecated"); + (. errors.Deprecated(ErrorId.p_deprecated_modify_statement_with_block, bodyStart, "the modify statement with a block statement is deprecated"); .) | SYNC ";" (. endTok = t; .) ) diff --git a/Source/DafnyCore/Resolver/ModuleResolver.cs b/Source/DafnyCore/Resolver/ModuleResolver.cs index a3245ff9974..9667c23be32 100644 --- a/Source/DafnyCore/Resolver/ModuleResolver.cs +++ b/Source/DafnyCore/Resolver/ModuleResolver.cs @@ -47,7 +47,7 @@ private bool RevealedInScope(Declaration d) { return d.IsRevealedInScope(moduleInfo.VisibilityScope); } - private bool VisibleInScope(Declaration d) { + internal bool VisibleInScope(Declaration d) { Contract.Requires(d != null); Contract.Requires(moduleInfo != null); Contract.Requires(moduleInfo.VisibilityScope != null); @@ -1069,8 +1069,7 @@ public void ResolveTopLevelDecls_Core(List<TopLevelDecl> declarations, if (Options.Get(CommonOptionBag.TypeSystemRefresh)) { // Resolve all names and infer types. - var preTypeResolver = new PreTypeResolver(this); - preTypeResolver.ResolveDeclarations(declarations); + PreTypeResolver.ResolveDeclarations(declarations, this); if (reporter.Count(ErrorLevel.Error) == prevErrorCount) { var u = new UnderspecificationDetector(this); @@ -1078,17 +1077,9 @@ public void ResolveTopLevelDecls_Core(List<TopLevelDecl> declarations, } if (reporter.Count(ErrorLevel.Error) == prevErrorCount) { - var u = new UnderspecificationDetector(this); - u.Check(declarations); - } - - if (reporter.Count(ErrorLevel.Error) == prevErrorCount) { - var u = new UnderspecificationDetector(this); - u.Check(declarations); - } - - if (reporter.Count(ErrorLevel.Error) == prevErrorCount) { - new PreTypeToTypeVisitor().VisitDeclarations(declarations); + var preType2TypeVisitor = new PreTypeToTypeVisitor(); + preType2TypeVisitor.VisitConstantsAndRedirectingTypes(declarations); + preType2TypeVisitor.VisitDeclarations(declarations); } } else { @@ -1499,6 +1490,11 @@ public void ResolveTopLevelDecls_Core(List<TopLevelDecl> declarations, } } + if (reporter.Count(ErrorLevel.Error) == prevErrorCount) { + // Check that class constructors are called when required. + new ObjectConstructorChecker(reporter).VisitDeclarations(declarations); + } + if (reporter.Count(ErrorLevel.Error) == prevErrorCount) { new HigherOrderHeapAllocationChecker(reporter).VisitDeclarations(declarations); } @@ -2871,7 +2867,7 @@ bool InferRequiredEqualitySupport(TypeParameter tp, Type type) { } private TopLevelDeclWithMembers currentClass; - public readonly Scope<TypeParameter>/*!*/ allTypeParameters; + public Scope<TypeParameter>/*!*/ allTypeParameters; public readonly Scope<IVariable>/*!*/ scope; /// <summary> @@ -3755,7 +3751,7 @@ public ResolveTypeOption(TypeParameter.ParentType parent) { /// Callers are expected to provide "arg" as an already resolved type. (Note, a proxy type is resolved-- /// only types that contain identifiers stand the possibility of not being resolved.) /// </summary> - Type ResolvedArrayType(IToken tok, int dims, Type arg, ResolutionContext resolutionContext, bool useClassNameType) { + internal Type ResolvedArrayType(IToken tok, int dims, Type arg, ResolutionContext resolutionContext, bool useClassNameType) { Contract.Requires(tok != null); Contract.Requires(1 <= dims); Contract.Requires(arg != null); @@ -3940,16 +3936,16 @@ public static UserDefinedType GetReceiverType(IToken tok, MemberDecl member) { return GetThisType(tok, (TopLevelDeclWithMembers)member.EnclosingClass); } - private Expression VarDotFunction(IToken tok, string varname, string functionname) { + internal Expression VarDotFunction(IToken tok, string varname, string functionname) { return new ApplySuffix(tok, null, new ExprDotName(tok, new IdentifierExpr(tok, varname), functionname, null), new List<ActualBinding>(), tok); } // TODO search for occurrences of "new LetExpr" which could benefit from this helper - private LetExpr LetPatIn(IToken tok, CasePattern<BoundVar> lhs, Expression rhs, Expression body) { + internal LetExpr LetPatIn(IToken tok, CasePattern<BoundVar> lhs, Expression rhs, Expression body) { return new LetExpr(tok, new List<CasePattern<BoundVar>>() { lhs }, new List<Expression>() { rhs }, body, true); } - private LetExpr LetVarIn(IToken tok, string name, Type tp, Expression rhs, Expression body) { + internal LetExpr LetVarIn(IToken tok, string name, Type tp, Expression rhs, Expression body) { var lhs = new CasePattern<BoundVar>(tok, new BoundVar(tok, name, tp)); return LetPatIn(tok, lhs, rhs, body); } @@ -4238,7 +4234,7 @@ public static string GhostPrefix(bool isGhost) { return isGhost ? "ghost " : ""; } - private static ModuleSignature GetSignatureExt(ModuleSignature sig) { + internal static ModuleSignature GetSignatureExt(ModuleSignature sig) { Contract.Requires(sig != null); Contract.Ensures(Contract.Result<ModuleSignature>() != null); return sig; @@ -4286,7 +4282,7 @@ public static Expression GetImpliedTypeConstraint(Expression e, Type ty) { /// Requires "expr" to be successfully resolved. /// Ensures that the set returned has no aliases. /// </summary> - static ISet<IVariable> FreeVariables(Expression expr) { + public static ISet<IVariable> FreeVariables(Expression expr) { Contract.Requires(expr != null); Contract.Ensures(expr.Type != null); diff --git a/Source/DafnyCore/Resolver/NameResolutionAndTypeInference/CheckTypeInferenceVisitor.cs b/Source/DafnyCore/Resolver/NameResolutionAndTypeInference/CheckTypeInferenceVisitor.cs index 0ff8f8a163d..25083acdf6e 100644 --- a/Source/DafnyCore/Resolver/NameResolutionAndTypeInference/CheckTypeInferenceVisitor.cs +++ b/Source/DafnyCore/Resolver/NameResolutionAndTypeInference/CheckTypeInferenceVisitor.cs @@ -1,3 +1,10 @@ +//----------------------------------------------------------------------------- +// +// Copyright by the contributors to the Dafny Project +// SPDX-License-Identifier: MIT +// +//----------------------------------------------------------------------------- + using System.Collections.Generic; using System.Diagnostics.Contracts; using System.Linq; @@ -8,7 +15,6 @@ namespace Microsoft.Dafny; class CheckTypeInferenceVisitor : ASTVisitor<TypeInferenceCheckingContext> { private readonly ModuleResolver resolver; - private ErrorReporter reporter => resolver.reporter; public CheckTypeInferenceVisitor(ModuleResolver resolver) { this.resolver = resolver; @@ -375,7 +381,7 @@ public bool CheckTypeIsDetermined(IToken tok, Type t, string what) { Contract.Requires(tok != null); Contract.Requires(t != null); Contract.Requires(what != null); - t = t.NormalizeExpandKeepConstraints(); + t = t.Normalize(); // note, this keeps type synonyms, by design if (t is TypeProxy) { var proxy = (TypeProxy)t; diff --git a/Source/DafnyCore/Resolver/NameResolutionAndTypeInference/NameResolutionAndTypeInference.cs b/Source/DafnyCore/Resolver/NameResolutionAndTypeInference/NameResolutionAndTypeInference.cs index 8bdc5d83f15..58488bc30ab 100644 --- a/Source/DafnyCore/Resolver/NameResolutionAndTypeInference/NameResolutionAndTypeInference.cs +++ b/Source/DafnyCore/Resolver/NameResolutionAndTypeInference/NameResolutionAndTypeInference.cs @@ -4485,7 +4485,6 @@ public Type ResolveTypeRhs(TypeRhs rr, Statement stmt, ResolutionContext resolut } } } else { - bool callsConstructor = false; if (rr.Bindings == null) { ResolveType(stmt.Tok, rr.EType, resolutionContext, ResolveTypeOptionEnum.InferTypeProxies, null); var cl = (rr.EType as UserDefinedType)?.ResolvedClass as NonNullTypeDecl; @@ -4533,27 +4532,12 @@ public Type ResolveTypeRhs(TypeRhs rr, Statement stmt, ResolutionContext resolut if (methodSel.Member is Method) { rr.InitCall = new CallStmt(stmt.RangeToken, new List<Expression>(), methodSel, rr.Bindings.ArgumentBindings, initCallTok); ResolveCallStmt(rr.InitCall, resolutionContext, rr.EType); - if (rr.InitCall.Method is Constructor) { - callsConstructor = true; - } } else { reporter.Error(MessageSource.Resolver, initCallTok, "object initialization must denote an initializing method or constructor ({0})", initCallName); } } } } - if (rr.EType.IsRefType) { - var udt = rr.EType.NormalizeExpand() as UserDefinedType; - if (udt != null) { - var cl = (ClassLikeDecl)udt.ResolvedClass; // cast is guaranteed by the call to rr.EType.IsRefType above, together with the "rr.EType is UserDefinedType" test - if (!callsConstructor && !cl.IsObjectTrait && !udt.IsArrayType && - (cl is ClassDecl { HasConstructor: true } || cl.EnclosingModuleDefinition != currentClass.EnclosingModuleDefinition)) { - reporter.Error(MessageSource.Resolver, stmt, - "when allocating an object of {1}type '{0}', one of its constructor methods must be called", cl.Name, - cl is ClassDecl { HasConstructor: true } ? "" : "imported "); - } - } - } rr.Type = rr.EType; } } diff --git a/Source/DafnyCore/Resolver/ObjectConstructorChecker.cs b/Source/DafnyCore/Resolver/ObjectConstructorChecker.cs new file mode 100644 index 00000000000..88076014d36 --- /dev/null +++ b/Source/DafnyCore/Resolver/ObjectConstructorChecker.cs @@ -0,0 +1,36 @@ +//----------------------------------------------------------------------------- +// +// Copyright by the contributors to the Dafny Project +// SPDX-License-Identifier: MIT +// +//----------------------------------------------------------------------------- + +namespace Microsoft.Dafny; + +class ObjectConstructorChecker : ASTVisitor<IASTVisitorContext> { + private readonly ErrorReporter reporter; + + public ObjectConstructorChecker(ErrorReporter reporter) { + this.reporter = reporter; + } + + public override IASTVisitorContext GetContext(IASTVisitorContext astVisitorContext, bool inFunctionPostcondition) { + return astVisitorContext; + } + + protected override bool VisitOneStatement(Statement stmt, IASTVisitorContext context) { + if (stmt is AssignStmt { Rhs: TypeRhs rr } && rr.ArrayDimensions == null && (rr.Bindings == null || rr.InitCall.Method is not Constructor)) { + // this is an AssignStmt that allocates one object and does not call a constructor + var udt = (UserDefinedType)rr.EType.NormalizeExpand(); + var cl = (ClassLikeDecl)udt.ResolvedClass; + if (!cl.IsObjectTrait && !udt.IsArrayType) { + var classHasConstructor = cl is ClassDecl { HasConstructor: true }; + if (classHasConstructor || cl.EnclosingModuleDefinition != context.EnclosingModule) { + reporter.Error(MessageSource.Resolver, stmt, + $"when allocating an object of {(classHasConstructor ? "" : "imported ")}type '{cl.Name}', one of its constructor methods must be called"); + } + } + } + return base.VisitOneStatement(stmt, context); + } +} diff --git a/Source/DafnyCore/Resolver/PreType/PreTypeAdvice.cs b/Source/DafnyCore/Resolver/PreType/PreTypeAdvice.cs index 6ad15c991e6..e08506d20ba 100644 --- a/Source/DafnyCore/Resolver/PreType/PreTypeAdvice.cs +++ b/Source/DafnyCore/Resolver/PreType/PreTypeAdvice.cs @@ -12,7 +12,7 @@ using Microsoft.Boogie; namespace Microsoft.Dafny { - class Advice { + public class Advice { public enum Target { Bool, Char, diff --git a/Source/DafnyCore/Resolver/PreType/PreTypeConstraints.cs b/Source/DafnyCore/Resolver/PreType/PreTypeConstraints.cs index 6b7083432c1..1cba12556c5 100644 --- a/Source/DafnyCore/Resolver/PreType/PreTypeConstraints.cs +++ b/Source/DafnyCore/Resolver/PreType/PreTypeConstraints.cs @@ -38,38 +38,36 @@ public PreTypeConstraints(PreTypeResolver preTypeResolver) { /// Returns "true" if anything changed (that is, if any of the constraints in the type-inference state /// caused a change some pre-type proxy). /// </summary> - void PartiallySolveTypeConstraints(string printableContext = null, bool makeDecisions = false) { + public void PartiallySolveTypeConstraints(string printableContext = null, bool makeDecisions = false) { if (printableContext != null) { PrintTypeInferenceState("(partial) " + printableContext); } bool anythingChanged; do { - if (makeDecisions) { - if (TryResolveTypeProxiesUsingKnownBounds(true)) { - // something changed, so do another round of Apply... calls below - } else if (TryResolveTypeProxiesUsingKnownBounds(false)) { - // something changed, so do another round of Apply... calls below - } else { - return; - } - } - anythingChanged = false; + anythingChanged = makeDecisions && TryMakeDecisions(); anythingChanged |= ApplySubtypeConstraints(); anythingChanged |= ApplyEqualityConstraints(); anythingChanged |= ApplyGuardedConstraints(); } while (anythingChanged); } - void SolveAllTypeConstraints(string printableContext) { + private bool TryMakeDecisions() { + if (TryResolveTypeProxiesUsingKnownBounds(true)) { + return true; + } else if (TryResolveTypeProxiesUsingKnownBounds(false)) { + return true; + } else if (TryApplyDefaultAdvice()) { + return true; + } + return false; + } + + public void SolveAllTypeConstraints(string printableContext) { PrintTypeInferenceState(printableContext); PartiallySolveTypeConstraints(null); PartiallySolveTypeConstraints(null, true); - if (TryApplyDefaultAdvice()) { - PartiallySolveTypeConstraints(null, true); - } - PrintLegend(); ConfirmTypeConstraints(); ClearState(); @@ -262,7 +260,7 @@ int Height(TopLevelDecl d) { } } - IEnumerable<DPreType> AllSubBounds(PreTypeProxy proxy, ISet<PreTypeProxy> visited) { + public IEnumerable<DPreType> AllSubBounds(PreTypeProxy proxy, ISet<PreTypeProxy> visited) { Contract.Requires(proxy.PT == null); if (visited.Contains(proxy)) { yield break; @@ -282,7 +280,7 @@ IEnumerable<DPreType> AllSubBounds(PreTypeProxy proxy, ISet<PreTypeProxy> visite } } - IEnumerable<DPreType> AllSuperBounds(PreTypeProxy proxy, ISet<PreTypeProxy> visited) { + public IEnumerable<DPreType> AllSuperBounds(PreTypeProxy proxy, ISet<PreTypeProxy> visited) { Contract.Requires(proxy.PT == null); if (visited.Contains(proxy)) { yield break; @@ -313,7 +311,7 @@ public IEnumerable<PreType> DirectionalBounds(PreTypeProxy tproxy, int direction } } - void AddGuardedConstraint(Func<bool> predicate) { + public void AddGuardedConstraint(Func<bool> predicate) { guardedConstraints.Add(predicate); } @@ -335,7 +333,7 @@ bool ApplyGuardedConstraints() { return anythingChanged; } - void AddDefaultAdvice(PreType preType, Advice.Target advice) { + public void AddDefaultAdvice(PreType preType, Advice.Target advice) { defaultAdvice.Add(new Advice(preType, advice)); } @@ -347,7 +345,7 @@ bool TryApplyDefaultAdvice() { return anythingChanged; } - void AddConfirmation(string check, PreType preType, IToken tok, string errorFormatString) { + public void AddConfirmation(CommonConfirmationBag check, PreType preType, IToken tok, string errorFormatString) { confirmations.Add(() => { if (!ConfirmConstraint(check, preType, null)) { PreTypeResolver.ReportError(tok, errorFormatString, preType); @@ -355,7 +353,7 @@ void AddConfirmation(string check, PreType preType, IToken tok, string errorForm }); } - void AddConfirmation(string check, PreType preType, Type toType, IToken tok, string errorFormatString) { + public void AddConfirmation(CommonConfirmationBag check, PreType preType, Type toType, IToken tok, string errorFormatString) { Contract.Requires(toType is NonProxyType); var toPreType = (DPreType)PreTypeResolver.Type2PreType(toType); confirmations.Add(() => { @@ -365,7 +363,7 @@ void AddConfirmation(string check, PreType preType, Type toType, IToken tok, str }); } - void AddConfirmation(System.Action confirm) { + public void AddConfirmation(System.Action confirm) { confirmations.Add(confirm); } @@ -375,7 +373,33 @@ void ConfirmTypeConstraints() { } } - private bool ConfirmConstraint(string check, PreType preType, DPreType auxPreType) { + public enum CommonConfirmationBag { + InIntFamily, + InRealFamily, + InBoolFamily, + InCharFamily, + InSeqFamily, + IsNullableRefType, + IsBitvector, + IntLikeOrBitvector, + NumericOrBitvector, + NumericOrBitvectorOrCharOrORDINALOrSuchTrait, + BooleanBits, + IntOrORDINAL, + IntOrBitvectorOrORDINAL, + Plussable, + Mullable, + Disjointable, + OrderableLess, + OrderableGreater, + RankOrderable, + RankOrderableOrTypeParameter, + Sizeable, + Freshable, + IsCoDatatype, + }; + + private bool ConfirmConstraint(CommonConfirmationBag check, PreType preType, DPreType auxPreType) { preType = preType.Normalize(); if (preType is PreTypeProxy) { return false; @@ -386,36 +410,36 @@ private bool ConfirmConstraint(string check, PreType preType, DPreType auxPreTyp var ancestorDecl = ancestorPt.Decl; var familyDeclName = ancestorDecl.Name; switch (check) { - case "InIntFamily": + case CommonConfirmationBag.InIntFamily: return familyDeclName == "int"; - case "InRealFamily": + case CommonConfirmationBag.InRealFamily: return familyDeclName == "real"; - case "InBoolFamily": + case CommonConfirmationBag.InBoolFamily: return familyDeclName == "bool"; - case "InCharFamily": + case CommonConfirmationBag.InCharFamily: return familyDeclName == "char"; - case "InSeqFamily": + case CommonConfirmationBag.InSeqFamily: return familyDeclName == "seq"; - case "IsNullableRefType": + case CommonConfirmationBag.IsNullableRefType: return DPreType.IsReferenceTypeDecl(pt.Decl); - case "IsBitvector": + case CommonConfirmationBag.IsBitvector: return PreTypeResolver.IsBitvectorName(familyDeclName); - case "IntLikeOrBitvector": + case CommonConfirmationBag.IntLikeOrBitvector: return familyDeclName == "int" || PreTypeResolver.IsBitvectorName(familyDeclName); - case "NumericOrBitvector": + case CommonConfirmationBag.NumericOrBitvector: return familyDeclName is "int" or "real" || PreTypeResolver.IsBitvectorName(familyDeclName); - case "NumericOrBitvectorOrCharOrORDINALOrSuchTrait": + case CommonConfirmationBag.NumericOrBitvectorOrCharOrORDINALOrSuchTrait: if (familyDeclName is "int" or "real" or "char" or "ORDINAL" || PreTypeResolver.IsBitvectorName(familyDeclName)) { return true; } return PreTypeResolver.IsSuperPreTypeOf(pt, auxPreType); - case "BooleanBits": + case CommonConfirmationBag.BooleanBits: return familyDeclName == "bool" || PreTypeResolver.IsBitvectorName(familyDeclName); - case "IntOrORDINAL": + case CommonConfirmationBag.IntOrORDINAL: return familyDeclName == "int" || familyDeclName == "ORDINAL"; - case "IntOrBitvectorOrORDINAL": + case CommonConfirmationBag.IntOrBitvectorOrORDINAL: return familyDeclName == "int" || PreTypeResolver.IsBitvectorName(familyDeclName) || familyDeclName == "ORDINAL"; - case "Plussable": + case CommonConfirmationBag.Plussable: switch (familyDeclName) { case "int": case "real": @@ -431,7 +455,7 @@ private bool ConfirmConstraint(string check, PreType preType, DPreType auxPreTyp default: return PreTypeResolver.IsBitvectorName(familyDeclName); } - case "Mullable": + case CommonConfirmationBag.Mullable: switch (familyDeclName) { case "int": case "real": @@ -442,10 +466,10 @@ private bool ConfirmConstraint(string check, PreType preType, DPreType auxPreTyp default: return PreTypeResolver.IsBitvectorName(familyDeclName); } - case "Disjointable": + case CommonConfirmationBag.Disjointable: return familyDeclName == "set" || familyDeclName == "iset" || familyDeclName == "multiset"; - case "Orderable_Lt": - case "Orderable_Gt": + case CommonConfirmationBag.OrderableLess: + case CommonConfirmationBag.OrderableGreater: switch (familyDeclName) { case "int": case "real": @@ -456,15 +480,15 @@ private bool ConfirmConstraint(string check, PreType preType, DPreType auxPreTyp case "multiset": return true; case "seq": - return check == "Orderable_Lt"; + return check == CommonConfirmationBag.OrderableLess; default: return PreTypeResolver.IsBitvectorName(familyDeclName); } - case "RankOrderable": + case CommonConfirmationBag.RankOrderable: return ancestorDecl is IndDatatypeDecl; - case "RankOrderableOrTypeParameter": + case CommonConfirmationBag.RankOrderableOrTypeParameter: return ancestorDecl is IndDatatypeDecl || ancestorDecl is TypeParameter; - case "Sizeable": + case CommonConfirmationBag.Sizeable: switch (familyDeclName) { case "set": // but not "iset" case "multiset": @@ -474,13 +498,13 @@ private bool ConfirmConstraint(string check, PreType preType, DPreType auxPreTyp default: return false; } - case "Freshable": { + case CommonConfirmationBag.Freshable: { var t = familyDeclName == "set" || familyDeclName == "iset" || familyDeclName == "seq" ? ancestorPt.Arguments[0].Normalize() as DPreType : ancestorPt; return t != null && DPreType.IsReferenceTypeDecl(t.Decl); } - case "IsCoDatatype": + case CommonConfirmationBag.IsCoDatatype: return ancestorDecl is CoDatatypeDecl; default: @@ -538,7 +562,7 @@ string Pad(string s, int minWidth) { public void DebugPrint(string format, params object[] args) { if (options.Get(CommonOptionBag.NewTypeInferenceDebug)) { - Console.WriteLine(format, args); + options.OutputWriter.WriteLine(format, args); } } diff --git a/Source/DafnyCore/Resolver/PreType/PreTypeResolve.ActualParameters.cs b/Source/DafnyCore/Resolver/PreType/PreTypeResolve.ActualParameters.cs new file mode 100644 index 00000000000..bc44e127e64 --- /dev/null +++ b/Source/DafnyCore/Resolver/PreType/PreTypeResolve.ActualParameters.cs @@ -0,0 +1,186 @@ +//----------------------------------------------------------------------------- +// +// Copyright by the contributors to the Dafny Project +// SPDX-License-Identifier: MIT +// +//----------------------------------------------------------------------------- + +using System.Collections.Generic; +using System.Linq; +using System.Diagnostics.Contracts; +using Microsoft.Boogie; +using ResolutionContext = Microsoft.Dafny.ResolutionContext; + +namespace Microsoft.Dafny { + public partial class PreTypeResolver { + /// <summary> + /// Resolve the actual arguments given in "bindings". Then, check that there is exactly one + /// actual for each formal, and impose assignable constraints. + /// "typeMap" is applied to the type of each formal. + /// This method should be called only once. That is, bindings.arguments is required to be null on entry to this method. + /// </summary> + void ResolveActualParameters(ActualBindings bindings, List<Formal> formals, IToken callTok, object context, ResolutionContext opts, + Dictionary<TypeParameter, PreType> typeMap, Expression/*?*/ receiver) { + Contract.Requires(bindings != null); + Contract.Requires(formals != null); + Contract.Requires(callTok != null); + Contract.Requires(context is Method || context is Function || context is DatatypeCtor || context is ArrowType); + Contract.Requires(typeMap != null); + + string whatKind; + string name; + if (context is Method cMethod) { + whatKind = cMethod.WhatKind; + name = $"{whatKind} '{cMethod.Name}'"; + } else if (context is Function cFunction) { + whatKind = cFunction.WhatKind; + name = $"{whatKind} '{cFunction.Name}'"; + } else if (context is DatatypeCtor cCtor) { + whatKind = "datatype constructor"; + name = $"{whatKind} '{cCtor.Name}'"; + } else { + var arrowPreType = (DPreType)context; + Contract.Assert(DPreType.IsArrowType(arrowPreType.Decl)); + whatKind = "function application"; + name = $"function type '{arrowPreType}'"; + } + + // If all arguments are passed positionally, use simple error messages that talk about the count of arguments. + var onlyPositionalArguments = bindings.ArgumentBindings.TrueForAll(binding => binding.FormalParameterName == null); + var simpleErrorReported = false; + if (onlyPositionalArguments) { + var requiredParametersCount = formals.Count(f => f.DefaultValue == null); + var actualsCounts = bindings.ArgumentBindings.Count; + if (requiredParametersCount <= actualsCounts && actualsCounts <= formals.Count) { + // the situation is plausible + } else if (requiredParametersCount == formals.Count) { + // this is the common, classical case of no default parameter values; generate a straightforward error message + ReportError(callTok, $"wrong number of arguments ({name} expects {formals.Count}, got {actualsCounts})"); + simpleErrorReported = true; + } else if (actualsCounts < requiredParametersCount) { + ReportError(callTok, $"wrong number of arguments ({name} expects at least {requiredParametersCount}, got {actualsCounts})"); + simpleErrorReported = true; + } else { + ReportError(callTok, $"wrong number of arguments ({name} expects at most {formals.Count}, got {actualsCounts})"); + simpleErrorReported = true; + } + } + + // resolve given arguments and populate the "namesToActuals" map + var namesToActuals = new Dictionary<string, ActualBinding>(); + formals.ForEach(f => namesToActuals.Add(f.Name, null)); // a name mapping to "null" says it hasn't been filled in yet + var stillAcceptingPositionalArguments = true; + var bindingIndex = 0; + foreach (var binding in bindings.ArgumentBindings) { + var arg = binding.Actual; + // insert the actual into "namesToActuals" under an appropriate name, unless there is an error + if (binding.FormalParameterName != null) { + var pname = binding.FormalParameterName.val; + stillAcceptingPositionalArguments = false; + if (!namesToActuals.TryGetValue(pname, out var b)) { + ReportError(binding.FormalParameterName, $"the binding named '{pname}' does not correspond to any formal parameter"); + } else if (b == null) { + // all is good + namesToActuals[pname] = binding; + } else if (b.FormalParameterName == null) { + ReportError(binding.FormalParameterName, $"the parameter named '{pname}' is already given positionally"); + } else { + ReportError(binding.FormalParameterName, $"duplicate binding for parameter name '{pname}'"); + } + } else if (!stillAcceptingPositionalArguments) { + ReportError(arg.tok, "a positional argument is not allowed to follow named arguments"); + } else if (bindingIndex < formals.Count) { + // use the name of formal corresponding to this positional argument, unless the parameter is name-only + var formal = formals[bindingIndex]; + var pname = formal.Name; + if (formal.IsNameOnly) { + ReportError(arg.tok, $"nameonly parameter '{pname}' must be passed using a name binding; it cannot be passed positionally"); + } + Contract.Assert(namesToActuals[pname] == null); // we expect this, since we've only filled parameters positionally so far + namesToActuals[pname] = binding; + } else { + // too many positional arguments + if (onlyPositionalArguments) { + // error was reported before the "foreach" loop + Contract.Assert(simpleErrorReported); + } else if (formals.Count < bindingIndex) { + // error was reported on a previous iteration of this "foreach" loop + } else { + ReportError(callTok, $"wrong number of arguments ({name} expects {formals.Count}, got {bindings.ArgumentBindings.Count})"); + } + } + + // resolve argument + ResolveExpression(arg, opts); + bindingIndex++; + } + + var actuals = new List<Expression>(); + var formalIndex = 0; + var substMap = new Dictionary<IVariable, Expression>(); + foreach (var formal in formals) { + formal.PreType = Type2PreType(formal.Type); + var b = namesToActuals[formal.Name]; + if (b != null) { + actuals.Add(b.Actual); + substMap.Add(formal, b.Actual); + var what = GetLocationInformation(formal, + bindings.ArgumentBindings.Count, bindings.ArgumentBindings.IndexOf(b), + whatKind + (context is Method ? " in-parameter" : " parameter")); + + Constraints.AddSubtypeConstraint( + formal.PreType.Substitute(typeMap), b.Actual.PreType, callTok, + $"incorrect argument type {what} (expected {{0}}, found {{1}})"); + } else if (formal.DefaultValue != null) { + // Note, in the following line, "substMap" is passed in, but it hasn't been fully filled in until the + // end of this foreach loop. Still, that's soon enough, because DefaultValueExpression won't use it + // until FillInDefaultValueExpressions at the end of Pass 1 of the Resolver. + var n = new DefaultValueExpressionPreType(callTok, formal, receiver, substMap, typeMap); +#if SOON + resolver.allDefaultValueExpressions.Add(n); +#endif + actuals.Add(n); + substMap.Add(formal, n); + } else { + // parameter has no value + if (onlyPositionalArguments) { + // a simple error message has already been reported + Contract.Assert(simpleErrorReported); + } else { + var formalDescription = whatKind + (context is Method ? " in-parameter" : " parameter"); + var nameWithIndex = formal.HasName && formal is not ImplicitFormal ? "'" + formal.Name + "'" : ""; + if (formals.Count > 1 || nameWithIndex == "") { + nameWithIndex += nameWithIndex == "" ? "" : " "; + nameWithIndex += $"at index {formalIndex}"; + } + var message = $"{formalDescription} {nameWithIndex} requires an argument of type {formal.Type}"; + ReportError(callTok, message); + } + } + formalIndex++; + } + + bindings.AcceptArgumentExpressionsAsExactParameterList(actuals); + } + + private static string GetLocationInformation(Formal parameter, int bindingCount, int bindingIndex, string formalDescription) { + Contract.Requires(parameter != null); + Contract.Requires(0 <= bindingIndex); + Contract.Requires(bindingIndex < bindingCount); + Contract.Requires(formalDescription != null); + + var description = ""; + if (bindingCount > 1) { + description += $"at index {bindingIndex} "; + } + + description += $"for {formalDescription}"; + + if (parameter.HasName && parameter is not ImplicitFormal) { + description += $" '{parameter.Name}'"; + } + + return description; + } + } +} diff --git a/Source/DafnyCore/Resolver/PreType/PreTypeResolve.Expressions.cs b/Source/DafnyCore/Resolver/PreType/PreTypeResolve.Expressions.cs new file mode 100644 index 00000000000..13509a417bb --- /dev/null +++ b/Source/DafnyCore/Resolver/PreType/PreTypeResolve.Expressions.cs @@ -0,0 +1,2180 @@ +//----------------------------------------------------------------------------- +// +// Copyright by the contributors to the Dafny Project +// SPDX-License-Identifier: MIT +// +//----------------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Diagnostics.Contracts; +using Microsoft.Boogie; +using ResolutionContext = Microsoft.Dafny.ResolutionContext; + +namespace Microsoft.Dafny { + public partial class PreTypeResolver { + // ---------------------------------------- Expressions ---------------------------------------- + + void ResolveExpression(Expression expr, ResolutionContext resolutionContext) { + Contract.Requires(expr != null); + Contract.Requires(resolutionContext != null); + + if (expr.PreType != null) { + // expression has already been pre-resolved + return; + } + + if (expr is ParensExpression) { + var e = (ParensExpression)expr; + ResolveExpression(e.E, resolutionContext); + e.ResolvedExpression = e.E; + e.PreType = e.E.PreType; + + } else if (expr is ChainingExpression) { + var e = (ChainingExpression)expr; + ResolveExpression(e.E, resolutionContext); + e.ResolvedExpression = e.E; + e.PreType = e.E.PreType; + + } else if (expr is NegationExpression) { + var e = (NegationExpression)expr; + ResolveExpression(e.E, resolutionContext); + e.PreType = e.E.PreType; + AddConfirmation(PreTypeConstraints.CommonConfirmationBag.NumericOrBitvector, e.E.PreType, e.E.tok, "type of unary - must be of a numeric or bitvector type (instead got {0})"); + // Note, e.ResolvedExpression will be filled in during CheckTypeInference, at which time e.PreType has been determined + + } else if (expr is LiteralExpr) { + var e = (LiteralExpr)expr; + + if (e is StaticReceiverExpr eStatic) { + resolver.ResolveType(eStatic.tok, eStatic.UnresolvedType, resolutionContext, ResolveTypeOptionEnum.InferTypeProxies, null); + eStatic.PreType = Type2PreType(eStatic.UnresolvedType, "static receiver type"); + } else { + if (e.Value == null) { + e.PreType = CreatePreTypeProxy("literal 'null'"); + Constraints.AddDefaultAdvice(e.PreType, Advice.Target.Object); + AddConfirmation(PreTypeConstraints.CommonConfirmationBag.IsNullableRefType, e.PreType, e.tok, "type of 'null' is a reference type, but it is used as {0}"); + } else if (e.Value is BigInteger) { + e.PreType = CreatePreTypeProxy($"integer literal '{e.Value}'"); + Constraints.AddDefaultAdvice(e.PreType, Advice.Target.Int); + AddConfirmation(PreTypeConstraints.CommonConfirmationBag.IntOrBitvectorOrORDINAL, e.PreType, e.tok, "integer literal used as if it had type {0}"); + } else if (e.Value is BaseTypes.BigDec) { + e.PreType = CreatePreTypeProxy($"real literal '{e.Value}'"); + Constraints.AddDefaultAdvice(e.PreType, Advice.Target.Real); + AddConfirmation(PreTypeConstraints.CommonConfirmationBag.InRealFamily, e.PreType, e.tok, "type of real literal is used as {0}"); // TODO: make this error message have the same form as the one for integers above + } else if (e.Value is bool) { + e.PreType = CreatePreTypeProxy($"boolean literal '{e.Value.ToString().ToLower()}'"); + Constraints.AddDefaultAdvice(e.PreType, Advice.Target.Bool); + AddConfirmation(PreTypeConstraints.CommonConfirmationBag.InBoolFamily, e.PreType, e.tok, "boolean literal used as if it had type {0}"); + } else if (e is CharLiteralExpr) { + e.PreType = CreatePreTypeProxy($"character literal '{e.Value}'"); + Constraints.AddDefaultAdvice(e.PreType, Advice.Target.Char); + AddConfirmation(PreTypeConstraints.CommonConfirmationBag.InCharFamily, e.PreType, e.tok, "character literal used as if it had type {0}"); + } else if (e is StringLiteralExpr) { + e.PreType = CreatePreTypeProxy($"string literal \"{e.Value}\""); + Constraints.AddDefaultAdvice(e.PreType, Advice.Target.String); + AddConfirmation(PreTypeConstraints.CommonConfirmationBag.InSeqFamily, e.PreType, e.tok, "string literal used as if it had type {0}"); + } else { + Contract.Assert(false); throw new cce.UnreachableException(); // unexpected literal type + } + } + + } else if (expr is ThisExpr) { + if (!scope.AllowInstance) { + ReportError(expr, "'this' is not allowed in a 'static' context"); + } + if (currentClass is DefaultClassDecl) { + // there's no type + } else if (currentClass == null) { + Contract.Assert(resolver.reporter.HasErrors); + } else { + var ty = ModuleResolver.GetThisType(expr.tok, currentClass); // do this regardless of scope.AllowInstance, for better error reporting + expr.PreType = Type2PreType(ty, "type of 'this'"); + } + + } else if (expr is IdentifierExpr) { + var e = (IdentifierExpr)expr; + e.Var = scope.Find(e.Name); + if (e.Var != null) { + expr.PreType = e.Var.PreType; + } else { + ReportError(expr, "Identifier does not denote a local variable, parameter, or bound variable: {0}", e.Name); + } + + } else if (expr is DatatypeValue) { + var dtv = (DatatypeValue)expr; + if (!resolver.moduleInfo.TopLevels.TryGetValue(dtv.DatatypeName, out var decl)) { + ReportError(expr.tok, "Undeclared datatype: {0}", dtv.DatatypeName); + } else if (decl is AmbiguousTopLevelDecl) { + var ad = (AmbiguousTopLevelDecl)decl; + ReportError(expr.tok, + "The name {0} ambiguously refers to a type in one of the modules {1} (try qualifying the type name with the module name)", + dtv.DatatypeName, ad.ModuleNames()); + } else if (decl is DatatypeDecl dtd) { + ResolveDatatypeValue(resolutionContext, dtv, dtd, null); + } else { + ReportError(expr.tok, "Expected datatype: {0}", dtv.DatatypeName); + } + + } else if (expr is DisplayExpression) { + var e = (DisplayExpression)expr; + var elementPreType = CreatePreTypeProxy("display expression element type"); + foreach (var ee in e.Elements) { + ResolveExpression(ee, resolutionContext); + AddSubtypeConstraint(elementPreType, ee.PreType, ee.tok, + "All elements of display must have some common supertype (got {1}, but needed type or type of previous elements is {0})"); + } + var argTypes = new List<PreType>() { elementPreType }; + if (expr is SetDisplayExpr setDisplayExpr) { + expr.PreType = new DPreType(BuiltInTypeDecl(setDisplayExpr.Finite ? "set" : "iset"), argTypes); + } else if (expr is MultiSetDisplayExpr) { + expr.PreType = new DPreType(BuiltInTypeDecl("multiset"), argTypes); + } else { + expr.PreType = new DPreType(BuiltInTypeDecl("seq"), argTypes); + } + + } else if (expr is MapDisplayExpr) { + var e = (MapDisplayExpr)expr; + var domainPreType = CreatePreTypeProxy("map display expression domain type"); + var rangePreType = CreatePreTypeProxy("map display expression range type"); + foreach (ExpressionPair p in e.Elements) { + ResolveExpression(p.A, resolutionContext); + AddSubtypeConstraint(domainPreType, p.A.PreType, p.A.tok, + "All elements of display must have some common supertype (got {1}, but needed type or type of previous elements is {0})"); + ResolveExpression(p.B, resolutionContext); + AddSubtypeConstraint(rangePreType, p.B.PreType, p.B.tok, + "All elements of display must have some common supertype (got {1}, but needed type or type of previous elements is {0})"); + } + var argTypes = new List<PreType>() { domainPreType, rangePreType }; + expr.PreType = new DPreType(BuiltInTypeDecl(e.Finite ? "map" : "imap"), argTypes); + + } else if (expr is NameSegment) { + var e = (NameSegment)expr; + ResolveNameSegment(e, true, null, resolutionContext, false); + + if (e.PreType is PreTypePlaceholderModule) { + ReportError(e.tok, "name of module ({0}) is used as a variable", e.Name); + e.ResetTypeAssignment(); // the rest of type checking assumes actual types + } else if (e.PreType is PreTypePlaceholderType) { + ReportError(e.tok, "name of type ({0}) is used as a variable", e.Name); + e.ResetTypeAssignment(); // the rest of type checking assumes actual types + } + + } else if (expr is ExprDotName) { + var e = (ExprDotName)expr; + ResolveDotSuffix(e, true, null, resolutionContext, false); + if (e.PreType is PreTypePlaceholderModule) { + ReportError(e.tok, "name of module ({0}) is used as a variable", e.SuffixName); + e.ResetTypeAssignment(); // the rest of type checking assumes actual types + } else if (e.PreType is PreTypePlaceholderType) { + ReportError(e.tok, "name of type ({0}) is used as a variable", e.SuffixName); + e.ResetTypeAssignment(); // the rest of type checking assumes actual types + } + + } else if (expr is ApplySuffix applySuffix) { + ResolveApplySuffix(applySuffix, resolutionContext, false); + + } else if (expr is MemberSelectExpr) { + var e = (MemberSelectExpr)expr; + Contract.Assert(false); // this case is always handled by ResolveExprDotCall +#if PROBABLY_NEVER + ResolveExpression(e.Obj, resolutionContext); + var (member, tentativeReceiverType) = FindMember(expr.tok, e.Obj.PreType, e.MemberName); + if (member == null) { + // error has already been reported by FindMember + } else if (member is Function fn) { + e.Member = fn; + if (fn is TwoStateFunction && !resolutionContext.twoState) { + ReportError(e.tok, "a two-state function can be used only in a two-state resolutionContext"); + } + // build the type substitution map + e.TypeApplication_AtEnclosingClass = tentativeReceiverType.TypeArgs; + e.TypeApplication_JustMember = new List<Type>(); + Dictionary<TypeParameter, Type> subst; + var ctype = tentativeReceiverType as UserDefinedType; + if (ctype == null) { + subst = new Dictionary<TypeParameter, Type>(); + } else { + subst = TypeSubstitutionMap(ctype.ResolvedClass.TypeArgs, ctype.TypeArgs); + } + foreach (var tp in fn.TypeArgs) { + Type prox = new InferredTypeProxy(); + subst[tp] = prox; + e.TypeApplication_JustMember.Add(prox); + } + subst = BuildTypeArgumentSubstitute(subst); + e.Type = SelectAppropriateArrowType(fn.tok, fn.Formals.ConvertAll(f => SubstType(f.Type, subst)), SubstType(fn.ResultType, subst), + fn.Reads.Count != 0, fn.Req.Count != 0); + AddCallGraphEdge(resolutionContext, fn, e, false); + } else if (member is Field field) { + e.Member = field; + e.TypeApplication_AtEnclosingClass = tentativeReceiverType.TypeArgs; + e.TypeApplication_JustMember = new List<Type>(); + if (e.Obj is StaticReceiverExpr && !field.IsStatic) { + ReportError(expr, "a field must be selected via an object, not just a class name"); + } + var ctype = tentativeReceiverType as UserDefinedType; + if (ctype == null) { + e.Type = field.Type; + } else { + Contract.Assert(ctype.ResolvedClass != null); // follows from postcondition of ResolveMember + // build the type substitution map + var subst = TypeSubstitutionMap(ctype.ResolvedClass.TypeArgs, ctype.TypeArgs); + e.Type = SubstType(field.Type, subst); + } + AddCallGraphEdgeForField(resolutionContext, field, e); + } else { + ReportError(expr, "member {0} in type {1} does not refer to a field or a function", e.MemberName, tentativeReceiverType); + } +#endif + + } else if (expr is SeqSelectExpr) { + var e = (SeqSelectExpr)expr; + + ResolveExpression(e.Seq, resolutionContext); + if (e.E0 != null) { + ResolveExpression(e.E0, resolutionContext); + } + if (e.E1 != null) { + ResolveExpression(e.E1, resolutionContext); + } + + if (e.SelectOne) { + Contract.Assert(e.E0 != null); + Contract.Assert(e.E1 == null); + e.PreType = ResolveSingleSelectionExpr(e.tok, e.Seq.PreType, e.E0); + } else { + e.PreType = ResolveRangeSelectionExpr(e.tok, e.Seq.PreType, e.E0, e.E1); + } + + } else if (expr is MultiSelectExpr) { + var e = (MultiSelectExpr)expr; + + ResolveExpression(e.Array, resolutionContext); + var elementPreType = CreatePreTypeProxy("multi-dim array select"); + var arrayPreType = BuiltInArrayType(e.Indices.Count, elementPreType); + AddSubtypeConstraint(arrayPreType, e.Array.PreType, e.Array.tok, "array selection requires an {0} (got {1})"); + int i = 0; + foreach (var indexExpression in e.Indices) { + ResolveExpression(indexExpression, resolutionContext); + ConstrainToIntFamily(indexExpression.PreType, indexExpression.tok, + "array selection requires integer- or bitvector-based numeric indices (got {0} for index " + i + ")"); + i++; + } + e.PreType = elementPreType; + + } else if (expr is SeqUpdateExpr) { + var e = (SeqUpdateExpr)expr; + ResolveExpression(e.Seq, resolutionContext); + ResolveExpression(e.Index, resolutionContext); + ResolveExpression(e.Value, resolutionContext); + Constraints.AddGuardedConstraint(() => { + var sourcePreType = e.Seq.PreType.Normalize() as DPreType; + var ancestorDecl = AncestorDecl(sourcePreType.Decl); + var familyDeclName = AncestorName(sourcePreType); + if (familyDeclName == "seq") { + var elementPreType = sourcePreType.Arguments[0]; + ConstrainToIntFamily(e.Index.PreType, e.Index.tok, "sequence update requires integer- or bitvector-based index (got {0})"); + AddSubtypeConstraint(elementPreType, e.Value.PreType, e.Value.tok, + "sequence update requires the value to have the element type of the sequence (got {0})"); + return true; + } else if (familyDeclName == "map" || familyDeclName == "imap") { + var domainPreType = sourcePreType.Arguments[0]; + var rangePreType = sourcePreType.Arguments[1]; + AddSubtypeConstraint(domainPreType, e.Index.PreType, e.Index.tok, + familyDeclName + " update requires domain element to be of type {0} (got {1})"); + AddSubtypeConstraint(rangePreType, e.Value.PreType, e.Value.tok, + familyDeclName + " update requires the value to have the range type {0} (got {1})"); + return true; + } else if (familyDeclName == "multiset") { + var elementPreType = sourcePreType.Arguments[0]; + AddSubtypeConstraint(elementPreType, e.Index.PreType, e.Index.tok, + "multiset update requires domain element to be of type {0} (got {1})"); + ConstrainToIntFamily(e.Value.PreType, e.Value.tok, "multiset update requires integer-based numeric value (got {0})"); + return true; + } else if (familyDeclName != null) { + ReportError(expr.tok, "update requires a sequence, map, or multiset (got {0})", e.Seq.PreType); + return true; + } + return false; + }); + expr.PreType = e.Seq.PreType; + + } else if (expr is DatatypeUpdateExpr) { + var e = (DatatypeUpdateExpr)expr; + ResolveExpression(e.Root, resolutionContext); + expr.PreType = CreatePreTypeProxy("datatype update"); + Constraints.AddGuardedConstraint(() => { + var (_, memberName, _) = e.Updates[0]; + var (_, tentativeRootPreType) = FindMember(expr.tok, e.Root.PreType, memberName); + if (tentativeRootPreType != null) { + if (tentativeRootPreType.Decl is DatatypeDecl datatypeDecl) { + var (ghostLet, compiledLet) = ResolveDatatypeUpdate(expr.tok, tentativeRootPreType, e.Root, datatypeDecl, e.Updates, + resolutionContext, out var members, out var legalSourceConstructors); + // if 'let' returns as 'null', an error has already been reported + if (ghostLet != null) { + e.ResolvedExpression = ghostLet; + e.ResolvedCompiledExpression = compiledLet; + e.Members = members; + e.LegalSourceConstructors = legalSourceConstructors; + Constraints.AddEqualityConstraint(expr.PreType, ghostLet.PreType, expr.tok, + "result of datatype update expression of type '{1}' is used as if it were of type '{0}'"); + } + } else { + ReportError(expr, "datatype update expression requires a root expression of a datatype (got {0})", tentativeRootPreType); + } + return true; + } + return false; + }); + + } else if (expr is FunctionCallExpr) { + var e = (FunctionCallExpr)expr; + Contract.Assert(false); // this case is always handled by ResolveExprDotCall +#if PROBABLY_NEVER + ResolveFunctionCallExpr(e, resolutionContext); +#endif + + } else if (expr is ApplyExpr) { + var e = (ApplyExpr)expr; + ResolveExpression(e.Function, resolutionContext); + foreach (var arg in e.Args) { + ResolveExpression(arg, resolutionContext); + } + expr.PreType = CreatePreTypeProxy("apply expression result"); + + Constraints.AddGuardedConstraint(() => { + if (e.Function.PreType.Normalize() is DPreType dp) { + if (!DPreType.IsArrowType(dp.Decl)) { + ReportError(e.tok, "non-function expression (of type {0}) is called with parameters", e.Function.PreType); + } else { + var arity = dp.Decl.TypeArgs.Count - 1; + if (arity != e.Args.Count) { + ReportError(e.tok, + "wrong number of arguments to function application (function type '{0}' expects {1}, got {2})", e.Function.PreType, + arity, e.Args.Count); + } else { + for (var i = 0; i < arity; i++) { + AddSubtypeConstraint(dp.Arguments[i], e.Args[i].PreType, e.Args[i].tok, + "type mismatch for argument" + (arity == 1 ? "" : " " + i) + " (function expects {0}, got {1})"); + } + AddSubtypeConstraint(expr.PreType, dp.Arguments[arity], expr.tok, "function result '{1}' used as if it had type '{0}'"); + } + } + return true; + } + return false; + }); + + } else if (expr is SeqConstructionExpr) { + var e = (SeqConstructionExpr)expr; + var elementType = e.ExplicitElementType ?? new InferredTypeProxy(); + resolver.ResolveType(e.tok, elementType, resolutionContext, ResolveTypeOptionEnum.InferTypeProxies, null); + var elementPreType = Type2PreType(elementType); + ResolveExpression(e.N, resolutionContext); + ConstrainToIntFamily(e.N.PreType, e.N.tok, "sequence construction must use an integer-based expression for the sequence size (got {0})"); + ResolveExpression(e.Initializer, resolutionContext); + var intPreType = Type2PreType(resolver.SystemModuleManager.Nat()); + var arrowPreType = new DPreType(BuiltInArrowTypeDecl(1), new List<PreType>() { intPreType, elementPreType }); + var resultPreType = new DPreType(BuiltInTypeDecl("seq"), new List<PreType>() { elementPreType }); + Constraints.AddSubtypeConstraint(arrowPreType, e.Initializer.PreType, e.Initializer.tok, + () => { + var strFormat = "sequence-construction initializer expression expected to have type '{0}' (instead got '{1}')"; + if (PreType.Same(elementPreType, e.Initializer.PreType)) { + var hintString = " (perhaps write '_ =>' in front of the expression you gave in order to make it an arrow type)"; + strFormat += hintString; + } + return strFormat; + }); + expr.PreType = resultPreType; + + } else if (expr is MultiSetFormingExpr) { + var e = (MultiSetFormingExpr)expr; + ResolveExpression(e.E, resolutionContext); + var targetElementPreType = CreatePreTypeProxy("multiset conversion element type"); + Constraints.AddGuardedConstraint(() => { + if (e.E.PreType.Normalize() is DPreType dp) { + if (dp.Decl.Name == "set" || dp.Decl.Name == "seq") { + Contract.Assert(dp.Arguments.Count == 1); + var sourceElementPreType = dp.Arguments[0]; + AddSubtypeConstraint(targetElementPreType, sourceElementPreType, e.E.tok, "expecting element type {0} (got {1})"); + } else { + ReportError(e.E.tok, "can only form a multiset from a seq or set (got {0})", e.E.PreType); + } + return true; + } + return false; + }); + expr.PreType = new DPreType(BuiltInTypeDecl("multiset"), new List<PreType>() { targetElementPreType }); + + } else if (expr is OldExpr) { + var e = (OldExpr)expr; + e.AtLabel = ResolveDominatingLabelInExpr(expr.tok, e.At, "old", resolutionContext); + ResolveExpression(e.E, new ResolutionContext(resolutionContext.CodeContext, false) with { InOld = true }); + expr.PreType = e.E.PreType; + + } else if (expr is UnchangedExpr) { + var e = (UnchangedExpr)expr; + e.AtLabel = ResolveDominatingLabelInExpr(expr.tok, e.At, "unchanged", resolutionContext); + foreach (var fe in e.Frame) { + ResolveFrameExpression(fe, FrameExpressionUse.Unchanged, resolutionContext.CodeContext); + } + ConstrainTypeExprBool(e, "result of 'unchanged' is boolean, but is used as if it had type {0}"); + + } else if (expr is FreshExpr) { + var e = (FreshExpr)expr; + ResolveExpression(e.E, resolutionContext); + e.AtLabel = ResolveDominatingLabelInExpr(expr.tok, e.At, "fresh", resolutionContext); + // the type of e.E must be either an object or a set/seq of objects + AddConfirmation(PreTypeConstraints.CommonConfirmationBag.Freshable, e.E.PreType, e.E.tok, "the argument of a fresh expression must denote an object or a set or sequence of objects (instead got {0})"); + ConstrainTypeExprBool(e, "result of 'fresh' is boolean, but is used as if it had type {0}"); + + } else if (expr is UnaryOpExpr) { + var e = (UnaryOpExpr)expr; + ResolveExpression(e.E, resolutionContext); + switch (e.Op) { + case UnaryOpExpr.Opcode.Not: + AddConfirmation(PreTypeConstraints.CommonConfirmationBag.BooleanBits, e.E.PreType, expr.tok, "logical/bitwise negation expects a boolean or bitvector argument (instead got {0})"); + expr.PreType = e.E.PreType; + break; + case UnaryOpExpr.Opcode.Cardinality: + AddConfirmation(PreTypeConstraints.CommonConfirmationBag.Sizeable, e.E.PreType, expr.tok, "size operator expects a collection argument (instead got {0})"); + expr.PreType = CreatePreTypeProxy("cardinality"); + ConstrainToIntFamily(expr.PreType, expr.tok, "integer literal used as if it had type {0}"); + break; + case UnaryOpExpr.Opcode.Allocated: + // the argument is allowed to have any type at all + expr.PreType = ConstrainResultToBoolFamily(expr.tok, "allocated", "boolean literal used as if it had type {0}"); + if ((resolutionContext.CodeContext is Function && !resolutionContext.InOld) || + resolutionContext.CodeContext is ConstantField || + CodeContextWrapper.Unwrap(resolutionContext.CodeContext) is RedirectingTypeDecl) { + var declKind = CodeContextWrapper.Unwrap(resolutionContext.CodeContext) is RedirectingTypeDecl redir + ? redir.WhatKind + : ((MemberDecl)resolutionContext.CodeContext).WhatKind; + ReportError(expr, "a {0} definition is not allowed to depend on the set of allocated references", declKind); + } + break; + default: + Contract.Assert(false); throw new cce.UnreachableException(); // unexpected unary operator + } + + } else if (expr is ConversionExpr) { + var e = (ConversionExpr)expr; + ResolveExpression(e.E, resolutionContext); + var prevErrorCount = ErrorCount; + resolver.ResolveType(e.tok, e.ToType, resolutionContext, new ModuleResolver.ResolveTypeOption(ResolveTypeOptionEnum.InferTypeProxies), null); + if (ErrorCount == prevErrorCount) { + var toPreType = (DPreType)Type2PreType(e.ToType); + var ancestorDecl = AncestorDecl(toPreType.Decl); + var familyDeclName = ancestorDecl.Name; + if (familyDeclName == "int") { + Constraints.AddConfirmation(PreTypeConstraints.CommonConfirmationBag.NumericOrBitvectorOrCharOrORDINALOrSuchTrait, e.E.PreType, e.ToType, expr.tok, + "type conversion to an int-based type is allowed only from numeric and bitvector types, char, and ORDINAL (got {0})"); + } else if (familyDeclName == "real") { + Constraints.AddConfirmation(PreTypeConstraints.CommonConfirmationBag.NumericOrBitvectorOrCharOrORDINALOrSuchTrait, e.E.PreType, e.ToType, expr.tok, + "type conversion to a real-based type is allowed only from numeric and bitvector types, char, and ORDINAL (got {0})"); + } else if (IsBitvectorName(familyDeclName)) { + Constraints.AddConfirmation(PreTypeConstraints.CommonConfirmationBag.NumericOrBitvectorOrCharOrORDINALOrSuchTrait, e.E.PreType, e.ToType, expr.tok, + "type conversion to a bitvector-based type is allowed only from numeric and bitvector types, char, and ORDINAL (got {0})"); + } else if (familyDeclName == "char") { + Constraints.AddConfirmation(PreTypeConstraints.CommonConfirmationBag.NumericOrBitvectorOrCharOrORDINALOrSuchTrait, e.E.PreType, e.ToType, expr.tok, + "type conversion to a char type is allowed only from numeric and bitvector types, char, and ORDINAL (got {0})"); + } else if (familyDeclName == "ORDINAL") { + Constraints.AddConfirmation(PreTypeConstraints.CommonConfirmationBag.NumericOrBitvectorOrCharOrORDINALOrSuchTrait, e.E.PreType, e.ToType, expr.tok, + "type conversion to an ORDINAL type is allowed only from numeric and bitvector types, char, and ORDINAL (got {0})"); + } else if (DPreType.IsReferenceTypeDecl(ancestorDecl)) { + AddComparableConstraint(toPreType, e.E.PreType, expr.tok, + "type cast to reference type '{0}' must be from an expression assignable to it (got '{1}')"); + } else if (ancestorDecl is TraitDecl) { + AddComparableConstraint(toPreType, e.E.PreType, expr.tok, + "type cast to trait type '{0}' must be from an expression assignable to it (got '{1}')"); + } else { + AddComparableConstraint(toPreType, e.E.PreType, expr.tok, + "type cast to type '{0}' must be from an expression assignable to it (got '{1}')"); + } + e.PreType = toPreType; + } else { + e.PreType = CreatePreTypeProxy("'as' target type"); + } + + } else if (expr is TypeTestExpr) { + var e = (TypeTestExpr)expr; + ResolveExpression(e.E, resolutionContext); + expr.PreType = ConstrainResultToBoolFamilyOperator(expr.tok, "is"); + resolver.ResolveType(e.tok, e.ToType, resolutionContext, new ModuleResolver.ResolveTypeOption(ResolveTypeOptionEnum.InferTypeProxies), null); + var toPreType = Type2PreType(e.ToType); + AddComparableConstraint(toPreType, e.E.PreType, expr.tok, "type test for type '{0}' must be from an expression assignable to it (got '{1}')"); + Constraints.AddConfirmation(() => { + // TODO: all of these tests should be revisited (they don't seem right in the presence of newtype's) + var fromPT = e.E.PreType.Normalize() as DPreType; + var toPT = toPreType.Normalize() as DPreType; + if (fromPT != null && toPT != null && IsSuperPreTypeOf(toPT, fromPT)) { + // This test is allowed and it always returns true + } else if (fromPT == null || toPT == null || !IsSuperPreTypeOf(fromPT, toPT)) { + // TODO: I think this line can never be reached, since we get here only if we get past the guarded Comparable constraint + ReportError(e.tok, "a type test to '{0}' must be from a compatible type (got '{1}')", toPreType, e.E.PreType); + } + }); + + } else if (expr is BinaryExpr) { + var e = (BinaryExpr)expr; + ResolveExpression(e.E0, resolutionContext); + ResolveExpression(e.E1, resolutionContext); + expr.PreType = ResolveBinaryExpr(e.tok, e.Op, e.E0, e.E1, resolutionContext); + + } else if (expr is TernaryExpr) { + var e = (TernaryExpr)expr; + ResolveExpression(e.E0, resolutionContext); + ResolveExpression(e.E1, resolutionContext); + ResolveExpression(e.E2, resolutionContext); + switch (e.Op) { + case TernaryExpr.Opcode.PrefixEqOp: + case TernaryExpr.Opcode.PrefixNeqOp: + expr.PreType = ConstrainResultToBoolFamily(expr.tok, "ternary op", "boolean literal used as if it had type {0}"); + AddConfirmation(PreTypeConstraints.CommonConfirmationBag.IntOrORDINAL, e.E0.PreType, expr.tok, "prefix-equality limit argument must be an ORDINAL or integer expression (got {0})"); + AddComparableConstraint(e.E1.PreType, e.E2.PreType, expr.tok, "arguments must have the same type (got {0} and {1})"); + AddConfirmation(PreTypeConstraints.CommonConfirmationBag.IsCoDatatype, e.E1.PreType, expr.tok, "arguments to prefix equality must be codatatypes (instead of {0})"); + break; + default: + Contract.Assert(false); // unexpected ternary operator + break; + } + + } else if (expr is LetExpr) { + var e = (LetExpr)expr; + if (e.Exact) { + foreach (var bv in e.BoundVars) { + int prevErrorCount = ErrorCount; + resolver.ResolveType(bv.Tok, bv.Type, resolutionContext, ResolveTypeOptionEnum.InferTypeProxies, null); + bv.PreType = Type2PreType(bv.Type); + } + foreach (var rhs in e.RHSs) { + ResolveExpression(rhs, resolutionContext); + } + scope.PushMarker(); + if (e.LHSs.Count != e.RHSs.Count) { + ReportError(expr, "let expression must have same number of LHSs (found {0}) as RHSs (found {1})", e.LHSs.Count, e.RHSs.Count); + } + var i = 0; + foreach (var lhs in e.LHSs) { + var rhsPreType = i < e.RHSs.Count ? e.RHSs[i].PreType : CreatePreTypeProxy("let RHS"); + ResolveCasePattern(lhs, rhsPreType, resolutionContext); + // Check for duplicate names now, because not until after resolving the case pattern do we know if identifiers inside it refer to bound variables or nullary constructors + var c = 0; + foreach (var v in lhs.Vars) { + ScopePushAndReport(v, "let-variable", false); // .PreType's already assigned by ResolveCasePattern + c++; + } + if (c == 0) { + // Every identifier-looking thing in the pattern resolved to a constructor; that is, this LHS is a constant literal + ReportError(lhs.tok, "LHS is a constant literal; to be legal, it must introduce at least one bound variable"); + } + i++; + } + } else { + // let-such-that expression + if (e.RHSs.Count != 1) { + ReportError(expr, "let-such-that expression must have just one RHS (found {0})", e.RHSs.Count); + } + // the bound variables are in scope in the RHS of a let-such-that expression + scope.PushMarker(); + foreach (var lhs in e.LHSs) { + Contract.Assert(lhs.Var != null); // the parser already checked that every LHS is a BoundVar, not a general pattern + var v = lhs.Var; + resolver.ResolveType(v.tok, v.Type, resolutionContext, ResolveTypeOptionEnum.InferTypeProxies, null); + v.PreType = Type2PreType(v.Type); + ScopePushAndReport(v, "let-variable", false); + lhs.AssembleExprPreType(null); +#if SOON + resolver.AddTypeDependencyEdges(resolutionContext, v.Type); +#endif + } + foreach (var rhs in e.RHSs) { + ResolveExpression(rhs, resolutionContext); + rhs.PreType = ConstrainResultToBoolFamily(rhs.tok, "such-that constraint", "type of RHS of let-such-that expression must be boolean (got {0})"); + } + } + ResolveExpression(e.Body, resolutionContext); + ResolveAttributes(e, resolutionContext, false); + scope.PopMarker(); + expr.PreType = e.Body.PreType; + + } else if (expr is LetOrFailExpr) { + var e = (LetOrFailExpr)expr; + e.ResolvedExpression = DesugarElephantExpr(e, resolutionContext); + e.PreType = e.ResolvedExpression.PreType; + Constraints.AddGuardedConstraint(() => { + if (e.Rhs.PreType.Normalize() is DPreType receiverPreType) { + bool expectExtract = e.Lhs != null; + EnsureSupportsErrorHandling(e.tok, receiverPreType, expectExtract); + return true; + } + return false; + }); + + } else if (expr is QuantifierExpr) { + var e = (QuantifierExpr)expr; + if (resolutionContext.CodeContext is Function enclosingFunction) { + enclosingFunction.ContainsQuantifier = true; + } + Contract.Assert(e.SplitQuantifier == null); // No split quantifiers during resolution + scope.PushMarker(); + foreach (var v in e.BoundVars) { + resolver.ResolveType(v.tok, v.Type, resolutionContext, ResolveTypeOptionEnum.InferTypeProxies, null); + ScopePushAndReport(v, "bound-variable", true); + } + if (e.Range != null) { + ResolveExpression(e.Range, resolutionContext); + ConstrainTypeExprBool(e.Range, "range of quantifier must be of type bool (instead got {0})"); + } + ResolveExpression(e.Term, resolutionContext); + ConstrainTypeExprBool(e.Term, "body of quantifier must be of type bool (instead got {0})"); + // Since the body is more likely to infer the types of the bound variables, resolve it + // first (above) and only then resolve the attributes (below). + ResolveAttributes(e, resolutionContext, false); + scope.PopMarker(); + expr.PreType = ConstrainResultToBoolFamilyOperator(expr.tok, e.WhatKind); + + } else if (expr is SetComprehension) { + var e = (SetComprehension)expr; + scope.PushMarker(); + foreach (var v in e.BoundVars) { + resolver.ResolveType(v.tok, v.Type, resolutionContext, ResolveTypeOptionEnum.InferTypeProxies, null); + ScopePushAndReport(v, "bound-variable", true); + } + ResolveExpression(e.Range, resolutionContext); + ConstrainTypeExprBool(e.Range, "range of comprehension must be of type bool (instead got {0})"); + ResolveExpression(e.Term, resolutionContext); + + ResolveAttributes(e, resolutionContext, false); + scope.PopMarker(); + expr.PreType = new DPreType(BuiltInTypeDecl(e.Finite ? "set" : "iset"), new List<PreType>() { e.Term.PreType }); + + } else if (expr is MapComprehension) { + var e = (MapComprehension)expr; + scope.PushMarker(); + Contract.Assert(e.BoundVars.Count == 1 || (1 < e.BoundVars.Count && e.TermLeft != null)); + foreach (BoundVar v in e.BoundVars) { + resolver.ResolveType(v.tok, v.Type, resolutionContext, ResolveTypeOptionEnum.InferTypeProxies, null); + ScopePushAndReport(v, "bound-variable", true); + if (v.Type is InferredTypeProxy inferredProxy) { + Contract.Assert(!inferredProxy.KeepConstraints); // in general, this proxy is inferred to be a base type + } + } + ResolveExpression(e.Range, resolutionContext); + ConstrainTypeExprBool(e.Range, "range of comprehension must be of type bool (instead got {0})"); + if (e.TermLeft != null) { + ResolveExpression(e.TermLeft, resolutionContext); + } + ResolveExpression(e.Term, resolutionContext); + + ResolveAttributes(e, resolutionContext, false); + scope.PopMarker(); + expr.PreType = new DPreType(BuiltInTypeDecl(e.Finite ? "map" : "imap"), + new List<PreType>() { e.TermLeft != null ? e.TermLeft.PreType : e.BoundVars[0].PreType, e.Term.PreType }); + + } else if (expr is LambdaExpr) { + var e = (LambdaExpr)expr; + scope.PushMarker(); + foreach (var v in e.BoundVars) { + resolver.ResolveType(v.tok, v.Type, resolutionContext, ResolveTypeOptionEnum.InferTypeProxies, null); + ScopePushAndReport(v, "bound-variable", true); + } + + if (e.Range != null) { + ResolveExpression(e.Range, resolutionContext); + ConstrainTypeExprBool(e.Range, "precondition must be boolean (got {0})"); + } + foreach (var read in e.Reads) { + ResolveFrameExpression(read, FrameExpressionUse.Reads, resolutionContext.CodeContext); + } + ResolveExpression(e.Term, resolutionContext); + scope.PopMarker(); + expr.PreType = BuiltInArrowType(e.BoundVars.ConvertAll(v => v.PreType), e.Body.PreType); + + } else if (expr is WildcardExpr) { + var obj = new DPreType(BuiltInTypeDecl("object?"), new List<PreType>() { }); + expr.PreType = new DPreType(BuiltInTypeDecl("set"), new List<PreType>() { obj }); + + } else if (expr is StmtExpr) { + var e = (StmtExpr)expr; + int prevErrorCount = ErrorCount; + ResolveStatement(e.S, resolutionContext); + if (ErrorCount == prevErrorCount) { + if (e.S is UpdateStmt updateStmt && updateStmt.ResolvedStatements.Count == 1) { + var call = (CallStmt)updateStmt.ResolvedStatements[0]; + if (call.Method is TwoStateLemma && !resolutionContext.IsTwoState) { + ReportError(call, "two-state lemmas can only be used in two-state contexts"); + } + } + } + ResolveExpression(e.E, resolutionContext); + expr.PreType = e.E.PreType; + + } else if (expr is ITEExpr) { + var e = (ITEExpr)expr; + ResolveExpression(e.Test, resolutionContext); + ResolveExpression(e.Thn, resolutionContext); + ResolveExpression(e.Els, resolutionContext); + e.Test.PreType = ConstrainResultToBoolFamily(e.Test.tok, "if-then-else test", "guard condition in if-then-else expression must be a boolean (instead got {0})"); + expr.PreType = CreatePreTypeProxy("if-then-else branches"); + AddSubtypeConstraint(expr.PreType, e.Thn.PreType, expr.tok, "the two branches of an if-then-else expression must have the same type (got {0} and {1})"); + AddSubtypeConstraint(expr.PreType, e.Els.PreType, expr.tok, "the two branches of an if-then-else expression must have the same type (got {0} and {1})"); + +#if SOON + } else if (expr is MatchExpr) { + ResolveMatchExpr((MatchExpr)expr, resolutionContext); +#endif + + } else if (expr is NestedMatchExpr) { + var e = (NestedMatchExpr)expr; + ResolveNestedMatchExpr(e, resolutionContext); + + } else { + Contract.Assert(false); throw new cce.UnreachableException(); // unexpected expression + } + + if (expr.PreType == null) { + // some resolution error occurred + expr.PreType = CreatePreTypeProxy("ResolveExpression didn't compute this pre-type"); + } + } + + private PreType ResolveBinaryExpr(IToken tok, BinaryExpr.Opcode opcode, Expression e0, Expression e1, ResolutionContext resolutionContext) { + var opString = BinaryExpr.OpcodeString(opcode); + PreType resultPreType; + switch (opcode) { + case BinaryExpr.Opcode.Iff: + case BinaryExpr.Opcode.Imp: + case BinaryExpr.Opcode.Exp: + case BinaryExpr.Opcode.And: + case BinaryExpr.Opcode.Or: { + resultPreType = ConstrainResultToBoolFamilyOperator(tok, opString); + ConstrainOperandTypes(tok, opString, e0, e1, resultPreType); + break; + } + + case BinaryExpr.Opcode.Eq: + case BinaryExpr.Opcode.Neq: + resultPreType = ConstrainResultToBoolFamilyOperator(tok, opString); + AddComparableConstraint(e0.PreType, e1.PreType, tok, "arguments must have comparable types (got {0} and {1})"); + break; + + case BinaryExpr.Opcode.Disjoint: + resultPreType = ConstrainResultToBoolFamilyOperator(tok, opString); + ConstrainToCommonSupertype(tok, opString, e0.PreType, e1.PreType, null); + AddConfirmation(PreTypeConstraints.CommonConfirmationBag.Disjointable, e0.PreType, tok, "arguments must be of a set or multiset type (got {0})"); + break; + + case BinaryExpr.Opcode.Lt: + resultPreType = ConstrainResultToBoolFamilyOperator(tok, opString); + Constraints.AddGuardedConstraint(() => { + var left = e0.PreType.Normalize() as DPreType; + var right = e1.PreType.Normalize() as DPreType; + if (left != null && (left.Decl is IndDatatypeDecl || left.Decl is TypeParameter)) { + AddConfirmation(PreTypeConstraints.CommonConfirmationBag.RankOrderable, e1.PreType, tok, + $"arguments to rank comparison must be datatypes (got {e0.PreType} and {{0}})"); + return true; + } else if (right != null && right.Decl is IndDatatypeDecl) { + AddConfirmation(PreTypeConstraints.CommonConfirmationBag.RankOrderableOrTypeParameter, e0.PreType, tok, + $"arguments to rank comparison must be datatypes (got {{0}} and {e1.PreType})"); + return true; + } else if (left != null || right != null) { + var commonSupertype = CreatePreTypeProxy("common supertype of < operands"); + ConstrainToCommonSupertype(tok, opString, e0.PreType, e1.PreType, commonSupertype); + AddConfirmation(PreTypeConstraints.CommonConfirmationBag.OrderableLess, e0.PreType, tok, + "arguments to " + opString + + " must be of a numeric type, bitvector type, ORDINAL, char, a sequence type, or a set-like type (instead got {0})"); + return true; + } + return false; + }); + break; + + case BinaryExpr.Opcode.Le: + resultPreType = ConstrainResultToBoolFamilyOperator(tok, opString); + ConstrainToCommonSupertype(tok, opString, e0.PreType, e1.PreType, null); + AddConfirmation(PreTypeConstraints.CommonConfirmationBag.OrderableLess, e0.PreType, tok, + "arguments to " + opString + + " must be of a numeric type, bitvector type, ORDINAL, char, a sequence type, or a set-like type (instead got {0})"); + break; + + case BinaryExpr.Opcode.Gt: + resultPreType = ConstrainResultToBoolFamilyOperator(tok, opString); + Constraints.AddGuardedConstraint(() => { + var left = e0.PreType.Normalize() as DPreType; + var right = e1.PreType.Normalize() as DPreType; + if (left != null && left.Decl is IndDatatypeDecl) { + AddConfirmation(PreTypeConstraints.CommonConfirmationBag.RankOrderableOrTypeParameter, e1.PreType, tok, + $"arguments to rank comparison must be datatypes (got {e0.PreType} and {{0}})"); + return true; + } else if (right != null && (right.Decl is IndDatatypeDecl || right.Decl is TypeParameter)) { + AddConfirmation(PreTypeConstraints.CommonConfirmationBag.RankOrderable, e0.PreType, tok, + $"arguments to rank comparison must be datatypes (got {{0}} and {e1.PreType})"); + return true; + } else if (left != null || right != null) { + var commonSupertype = CreatePreTypeProxy("common supertype of < operands"); + ConstrainToCommonSupertype(tok, opString, e0.PreType, e1.PreType, commonSupertype); + AddConfirmation(PreTypeConstraints.CommonConfirmationBag.OrderableGreater, e0.PreType, tok, + "arguments to " + opString + " must be of a numeric type, bitvector type, ORDINAL, char, or a set-like type (instead got {0})"); + return true; + } + return false; + }); + break; + + case BinaryExpr.Opcode.Ge: + resultPreType = ConstrainResultToBoolFamilyOperator(tok, opString); + ConstrainToCommonSupertype(tok, opString, e0.PreType, e1.PreType, null); + AddConfirmation(PreTypeConstraints.CommonConfirmationBag.OrderableGreater, e0.PreType, tok, + "arguments to " + opString + " must be of a numeric type, bitvector type, ORDINAL, char, or a set-like type (instead got {0} and {1})"); + break; + + case BinaryExpr.Opcode.Add: + resultPreType = CreatePreTypeProxy("result of +"); + AddConfirmation(PreTypeConstraints.CommonConfirmationBag.Plussable, resultPreType, tok, + "type of + must be of a numeric type, a bitvector type, ORDINAL, char, a sequence type, or a set-like or map-like type (instead got {0})"); + ConstrainOperandTypes(tok, opString, e0, e1, resultPreType); + break; + + case BinaryExpr.Opcode.Sub: + resultPreType = CreatePreTypeProxy("result of -"); + Constraints.AddGuardedConstraint(() => { + // The following cases are allowed: + // Uniform cases: + // - int int + // - real real + // - bv bv + // - ORDINAL ORDINAL + // - char char + // - set<T> set<V> + // - iset<T> iset<V> + // - multiset<T> multiset<T> + // Non-uniform cases: + // - map<T, U> set<V> + // - imap<T, U> set<V> + // + // The tests below distinguish between the uniform and non-uniform cases, but otherwise may allow some cases + // that are not included above. The after the enclosing call to AddGuardedConstraint will arrange to confirm + // that only the expected types are allowed. + var a0 = e0.PreType; + var a1 = e1.PreType; + var left = a0.Normalize() as DPreType; + var right = a1.Normalize() as DPreType; + var familyDeclNameLeft = AncestorName(a0); + var familyDeclNameRight = AncestorName(a1); + if (familyDeclNameLeft == "map" || familyDeclNameLeft == "imap") { + Contract.Assert(left.Arguments.Count == 2); + var st = new DPreType(BuiltInTypeDecl("set"), new List<PreType>() { left.Arguments[0] }); + Constraints.DebugPrint($" DEBUG: guard applies: Minusable {a0} {a1}, converting to {st} :> {a1}"); + AddSubtypeConstraint(st, a1, tok, + "map subtraction expects right-hand operand to have type {0} (instead got {1})"); + return true; + } else if (familyDeclNameLeft != null || (familyDeclNameRight != null && familyDeclNameRight != "set")) { + Constraints.DebugPrint($" DEBUG: guard applies: Minusable {a0} {a1}, converting to {a0} :> {a1}"); + AddSubtypeConstraint(a0, a1, tok, + "type of right argument to - ({0}) must agree with the result type ({1})"); + return true; + } + return false; + }); + ConstrainOperandTypes(tok, opString, e0, null, resultPreType); + break; + + case BinaryExpr.Opcode.Mul: + resultPreType = CreatePreTypeProxy("result of *"); + AddConfirmation(PreTypeConstraints.CommonConfirmationBag.Mullable, resultPreType, tok, + "type of * must be of a numeric type, bitvector type, or a set-like type (instead got {0})"); + ConstrainOperandTypes(tok, opString, e0, e1, resultPreType); + break; + + case BinaryExpr.Opcode.In: + case BinaryExpr.Opcode.NotIn: + resultPreType = ConstrainResultToBoolFamilyOperator(tok, "'" + opString + "'"); + Constraints.AddGuardedConstraint(() => { + // For "Innable x s", if s is known, then: + // if s == c<a> or s == c<a, b> where c is a collection type, then a :> x, else error. + var a0 = e0.PreType.Normalize(); + var a1 = e1.PreType.Normalize(); + var coll = a1.UrAncestor(this).AsCollectionPreType(); + if (coll != null) { + Constraints.DebugPrint($" DEBUG: guard applies: Innable {a0} {a1}"); + AddSubtypeConstraint(coll.Arguments[0], a0, tok, "expecting element type to be assignable to {0} (got {1})"); + return true; + } else if (a1 is DPreType) { + // type head is determined and it isn't a collection type + ReportError(tok, + $"second argument to '{opString}' must be a set, a multiset, " + + $"a sequence with elements of type {e0.PreType}, or a map with domain {e0.PreType} (instead got {e1.PreType})"); + return true; + } + return false; + }); + break; + + case BinaryExpr.Opcode.Div: + resultPreType = CreatePreTypeProxy("result of / operation"); + Constraints.AddDefaultAdvice(resultPreType, Advice.Target.Int); + AddConfirmation(PreTypeConstraints.CommonConfirmationBag.NumericOrBitvector, resultPreType, tok, "arguments to " + opString + " must be numeric or bitvector types (got {0})"); + ConstrainOperandTypes(tok, opString, e0, e1, resultPreType); + break; + + case BinaryExpr.Opcode.Mod: + resultPreType = CreatePreTypeProxy("result of % operation"); + Constraints.AddDefaultAdvice(resultPreType, Advice.Target.Int); + AddConfirmation(PreTypeConstraints.CommonConfirmationBag.IntLikeOrBitvector, resultPreType, tok, "type of " + opString + " must be integer-numeric or bitvector types (got {0})"); + ConstrainOperandTypes(tok, opString, e0, e1, resultPreType); + break; + + case BinaryExpr.Opcode.BitwiseAnd: + case BinaryExpr.Opcode.BitwiseOr: + case BinaryExpr.Opcode.BitwiseXor: + resultPreType = CreatePreTypeProxy("result of " + opString + " operation"); + AddConfirmation(PreTypeConstraints.CommonConfirmationBag.IsBitvector, resultPreType, tok, "type of " + opString + " must be of a bitvector type (instead got {0})"); + ConstrainOperandTypes(tok, opString, e0, e1, resultPreType); + break; + + case BinaryExpr.Opcode.LeftShift: + case BinaryExpr.Opcode.RightShift: { + resultPreType = CreatePreTypeProxy("result of " + opString + " operation"); + AddConfirmation(PreTypeConstraints.CommonConfirmationBag.IsBitvector, resultPreType, tok, "type of " + opString + " must be of a bitvector type (instead got {0})"); + ConstrainOperandTypes(tok, opString, e0, null, resultPreType); + AddConfirmation(PreTypeConstraints.CommonConfirmationBag.IntLikeOrBitvector, e1.PreType, tok, + "type of right argument to " + opString + " ({0}) must be an integer-numeric or bitvector type"); + break; + } + + default: + Contract.Assert(false); + throw new cce.UnreachableException(); // unexpected operator + } + // We should also fill in e.ResolvedOp, but we may not have enough information for that yet. So, instead, delay + // setting e.ResolvedOp until inside CheckTypeInference. + return resultPreType; + } + + private void ConstrainTypeExprBool(Expression e, string msgFormat) { + Contract.Requires(e != null); + Contract.Requires(msgFormat != null); // may have a {0} part + e.PreType = ConstrainResultToBoolFamily(e.tok, "<unspecified use>", msgFormat); + } + + private void ConstrainTypeExprBool(Expression e, string proxyDescription, string msgFormat) { + Contract.Requires(e != null); + Contract.Requires(proxyDescription != null); + Contract.Requires(msgFormat != null); // may have a {0} part + e.PreType = ConstrainResultToBoolFamily(e.tok, proxyDescription, msgFormat); + } + + private PreType ConstrainResultToBoolFamilyOperator(IToken tok, string opString) { + var proxyDescription = $"result of {opString} operation"; + return ConstrainResultToBoolFamily(tok, proxyDescription, "type of " + opString + " must be a boolean (got {0})"); + } + + private PreType ConstrainResultToBoolFamily(IToken tok, string proxyDescription, string errorFormat) { + var pt = CreatePreTypeProxy(proxyDescription); + Constraints.AddDefaultAdvice(pt, Advice.Target.Bool); + AddConfirmation(PreTypeConstraints.CommonConfirmationBag.InBoolFamily, pt, tok, errorFormat); + return pt; + } + + private void ConstrainToIntFamily(PreType preType, IToken tok, string errorFormat) { + Constraints.AddDefaultAdvice(preType, Advice.Target.Int); + AddConfirmation(PreTypeConstraints.CommonConfirmationBag.InIntFamily, preType, tok, errorFormat); + } + + private void ConstrainToCommonSupertype(IToken tok, string opString, PreType a, PreType b, PreType commonSupertype) { + if (commonSupertype == null) { + commonSupertype = CreatePreTypeProxy($"element type of common {opString} supertype"); + } + var errorFormat = $"arguments to {opString} must have a common supertype (got {{0}} and {{1}})"; + AddSubtypeConstraint(commonSupertype, a, tok, errorFormat); + AddSubtypeConstraint(commonSupertype, b, tok, errorFormat); + } + + private void ConstrainOperandTypes(IToken tok, string opString, Expression e0, Expression e1, PreType resultPreType) { + if (e0 != null) { + AddSubtypeConstraint(resultPreType, e0.PreType, tok, + $"type of left argument to {opString} ({{1}}) must agree with the result type ({{0}})"); + } + if (e1 != null) { + AddSubtypeConstraint(resultPreType, e1.PreType, tok, + $"type of right argument to {opString} ({{1}}) must agree with the result type ({{0}})"); + } + } + + /// <summary> + /// Resolve "memberName" in what currently is known as "receiverPreType". If "receiverPreType" is an unresolved + /// proxy type, try to solve enough type constraints and use heuristics to figure out which type contains + /// "memberName" and return that enclosing type as "tentativeReceiverType". However, try not to make + /// type-inference decisions about "receiverPreType"; instead, lay down the further constraints that need to + /// be satisfied in order for "tentativeReceiverType" to be where "memberName" is found. + /// Consequently, if "memberName" is found and returned as a "MemberDecl", it may still be the case that + /// "receiverPreType" is an unresolved proxy type and that, after solving more type constraints, "receiverPreType" + /// eventually gets set to a type more specific than "tentativeReceiverType". + /// </summary> + (MemberDecl/*?*/, DPreType/*?*/) FindMember(IToken tok, PreType receiverPreType, string memberName) { + Contract.Requires(tok != null); + Contract.Requires(receiverPreType != null); + Contract.Requires(memberName != null); + + Constraints.PartiallySolveTypeConstraints(); + receiverPreType = receiverPreType.Normalize(); + DPreType dReceiver = null; + if (receiverPreType is PreTypeProxy proxy) { + // If there is a subtype constraint "proxy :> sub<X>", then (if the program is legal at all, then) "sub" must have the member "memberName". + foreach (var sub in Constraints.AllSubBounds(proxy, new HashSet<PreTypeProxy>())) { + dReceiver = sub; + break; + } + if (dReceiver == null) { + // If there is a subtype constraint "super<X> :> proxy" where "super" has a member "memberName", then that is the correct member. + foreach (var super in Constraints.AllSuperBounds(proxy, new HashSet<PreTypeProxy>())) { + if (super.Decl is TopLevelDeclWithMembers md && resolver.GetClassMembers(md).ContainsKey(memberName)) { + dReceiver = super; + break; + } + } + } + if (dReceiver == null) { + ReportError(tok, "type of the receiver is not fully determined at this program point"); + return (null, null); + } + } else { + dReceiver = (DPreType)receiverPreType; + } + Contract.Assert(dReceiver != null); + + var receiverDecl = dReceiver.Decl; + if (receiverDecl is TopLevelDeclWithMembers receiverDeclWithMembers) { + // TODO: does this case need to do something like this? var cd = ctype?.AsTopLevelTypeWithMembersBypassInternalSynonym; + + if (!resolver.GetClassMembers(receiverDeclWithMembers).TryGetValue(memberName, out var member)) { + if (memberName == "_ctor") { + ReportError(tok, $"{receiverDecl.WhatKind} '{receiverDecl.Name}' does not have an anonymous constructor"); + } else { + ReportError(tok, $"member '{memberName}' does not exist in {receiverDecl.WhatKind} '{receiverDecl.Name}'"); + } + return (null, null); + } else if (resolver.VisibleInScope(member)) { + // TODO: We should return the original "member", not an overridden member. Alternatively, we can just return "member" so that the + // caller can figure out the types, and then a later pass can figure out which particular "member" is intended. + return (member, dReceiver); + } + } + ReportError(tok, $"member '{memberName}' does not exist in {receiverDecl.WhatKind} '{receiverDecl.Name}'"); + return (null, null); + } + + /// <summary> + /// Expecting that "preType" is a type that does not involve traits, return that type, if possible. + /// </summary> + DPreType/*?*/ FindDefinedPreType(PreType preType) { + Contract.Requires(preType != null); + + Constraints.PartiallySolveTypeConstraints(); + preType = preType.Normalize(); + if (preType is PreTypeProxy proxy) { + // We're looking a type with concerns for traits, so if the proxy has any sub- or super-type, then (if the + // program is legal at all, then) that sub- or super-type must be the type we're looking for. + foreach (var sub in Constraints.AllSubBounds(proxy, new HashSet<PreTypeProxy>())) { + return sub; + } + foreach (var super in Constraints.AllSuperBounds(proxy, new HashSet<PreTypeProxy>())) { + return super; + } + return null; + } + + return preType as DPreType; + } + + /// <summary> + /// Look up expr.Name in the following order: + /// 0. Local variable, parameter, or bound variable. + /// (Language design note: If this clashes with something of interest, one can always rename the local variable locally.) + /// 1. Member of enclosing class (an implicit "this" is inserted, if needed) + /// 2. If isLastNameSegment: + /// Unambiguous constructor name of a datatype in the enclosing module (if two constructors have the same name, an error message is produced here) + /// (Language design note: If the constructor name is ambiguous or if one of the steps above takes priority, one can qualify the constructor + /// name with the name of the datatype.) + /// 3. Member of the enclosing module (type name or the name of a module) + /// 4. Static function or method in the enclosing module or its imports + /// 5. If !isLastNameSegment: + /// Unambiguous constructor name of a datatype in the enclosing module + /// + /// </summary> + /// <param name="expr"></param> + /// <param name="isLastNameSegment">Indicates that the NameSegment is not directly enclosed in another NameSegment or ExprDotName expression.</param> + /// <param name="args">If the NameSegment is enclosed in an ApplySuffix, then these are the arguments. The method returns null to indicate + /// that these arguments, if any, were not used. If args is non-null and the method does use them, the method returns the resolved expression + /// that incorporates these arguments.</param> + /// <param name="resolutionContext"></param> + /// <param name="allowMethodCall">If false, generates an error if the name denotes a method. If true and the name denotes a method, returns + /// a MemberSelectExpr whose .Member is a Method.</param> + /// <param name="complain"></param> + Expression ResolveNameSegment(NameSegment expr, bool isLastNameSegment, List<ActualBinding> args, + ResolutionContext resolutionContext, bool allowMethodCall, bool complain = true) { + Contract.Requires(expr != null); + Contract.Requires(!expr.WasResolved()); + Contract.Requires(resolutionContext != null); + Contract.Ensures(Contract.Result<Expression>() == null || args != null); + + if (expr.OptTypeArguments != null) { + foreach (var ty in expr.OptTypeArguments) { + resolver.ResolveType(expr.tok, ty, resolutionContext, ResolveTypeOptionEnum.InferTypeProxies, null); + } + } + + Expression r = null; // the resolved expression, if successful + Expression rWithArgs = null; // the resolved expression after incorporating "args" + + // For 1 and 4: + MemberDecl member = null; + // For 2 and 5: + Tuple<DatatypeCtor, bool> pair; + + var name = resolutionContext.InReveal ? "reveal_" + expr.Name : expr.Name; + var v = scope.Find(name); + if (v != null) { + // ----- 0. local variable, parameter, or bound variable + if (expr.OptTypeArguments != null) { + if (complain) { + ReportError(expr.tok, "variable '{0}' does not take any type parameters", name); + } else { + expr.ResolvedExpression = null; + return null; + } + } +#if NO_LONGER_NEEDED + if (v.PreType == null) { + v.PreType = Type2PreType(v.Type, $"type of identifier '{name}'"); + } +#endif + r = new IdentifierExpr(expr.tok, v) { + PreType = v.PreType + }; + } else if (currentClass != null && resolver.GetClassMembers(currentClass) is { } members && + members.TryGetValue(name, out member)) { + // ----- 1. member of the enclosing class + Expression receiver; + if (member.IsStatic) { + receiver = new StaticReceiverExpr(expr.tok, UserDefinedType.FromTopLevelDecl(expr.tok, currentClass, currentClass.TypeArgs), + (TopLevelDeclWithMembers)member.EnclosingClass, true); + receiver.PreType = Type2PreType(receiver.Type); + } else { + if (!scope.AllowInstance) { + if (complain) { + ReportError(expr.tok, "'this' is not allowed in a 'static' resolutionContext"); //TODO: Rephrase this + } else { + expr.ResolvedExpression = null; + return null; + } + // nevertheless, set "receiver" to a value so we can continue resolution + } + receiver = new ImplicitThisExpr(expr.tok); + receiver.Type = ModuleResolver.GetThisType(expr.tok, currentClass); + receiver.PreType = Type2PreType(receiver.Type); + } + r = ResolveExprDotCall(expr.tok, receiver, null, member, args, expr.OptTypeArguments, resolutionContext, allowMethodCall); + + } else if (isLastNameSegment && resolver.moduleInfo.Ctors.TryGetValue(name, out pair)) { + // ----- 2. datatype constructor + if (ResolveDatatypeConstructor(expr, args, resolutionContext, complain, pair, name, ref r, ref rWithArgs)) { + return null; + } + + } else if (resolver.moduleInfo.TopLevels.TryGetValue(name, out var decl)) { + // ----- 3. Member of the enclosing module + if (decl is AmbiguousTopLevelDecl ambiguousTopLevelDecl) { + if (complain) { + ReportError(expr.tok, + "The name {0} ambiguously refers to a type in one of the modules {1} (try qualifying the type name with the module name)", + expr.Name, ambiguousTopLevelDecl.ModuleNames()); + } else { + expr.ResolvedExpression = null; + return null; + } + } else { + // We have found a module name or a type name, neither of which is an expression. However, the NameSegment we're + // looking at may be followed by a further suffix that makes this into an expression. We postpone the rest of the + // resolution to any such suffix. For now, we create a temporary expression that will never be seen by the compiler + // or verifier, just to have a placeholder where we can recorded what we have found. + if (!isLastNameSegment) { + if (decl is ClassLikeDecl cd && cd.NonNullTypeDecl != null && name != cd.NonNullTypeDecl.Name) { + // A possibly-null type C? was mentioned. But it does not have any further members. The program should have used + // the name of the class, C. Report an error and continue. + if (complain) { + ReportError(expr.tok, "To access members of {0} '{1}', write '{1}', not '{2}'", decl.WhatKind, decl.Name, name); + } else { + expr.ResolvedExpression = null; + return null; + } + } + } + r = CreateResolver_IdentifierExpr(expr.tok, name, expr.OptTypeArguments, decl); + } + + } else if (resolver.moduleInfo.StaticMembers.TryGetValue(name, out member)) { + // ----- 4. static member of the enclosing module + Contract.Assert(member.IsStatic); // moduleInfo.StaticMembers is supposed to contain only static members of the module's implicit class _default + if (member is AmbiguousMemberDecl ambiguousMember) { + if (complain) { + ReportError(expr.tok, "The name {0} ambiguously refers to a static member in one of the modules {1} (try qualifying the member name with the module name)", expr.Name, ambiguousMember.ModuleNames()); + } else { + expr.ResolvedExpression = null; + return null; + } + } else { + var receiver = new StaticReceiverExpr(expr.tok, (TopLevelDeclWithMembers)member.EnclosingClass, true); + receiver.PreType = Type2PreType(receiver.Type); + r = ResolveExprDotCall(expr.tok, receiver, null, member, args, expr.OptTypeArguments, resolutionContext, allowMethodCall); + } + + } else if (!isLastNameSegment && resolver.moduleInfo.Ctors.TryGetValue(name, out pair)) { + // ----- 5. datatype constructor + if (ResolveDatatypeConstructor(expr, args, resolutionContext, complain, pair, name, ref r, ref rWithArgs)) { + return null; + } + + } else { + // ----- None of the above + if (complain) { + ReportError(expr.tok, "unresolved identifier: {0}", name); + } else { + expr.ResolvedExpression = null; + return null; + } + } + + if (r == null) { + // an error has been reported above; we won't fill in .ResolvedExpression, but we still must fill in .PreType + expr.PreType = CreatePreTypeProxy(); + } else { + expr.ResolvedExpression = r; + if (r.Type != null) { + // The following may be needed to meet some .WasResolved() expectations + expr.Type = r.Type.UseInternalSynonym(); + } + expr.PreType = r.PreType; + } + return rWithArgs; + } + + private Resolver_IdentifierExpr CreateResolver_IdentifierExpr(IToken tok, string name, List<Type> optTypeArguments, TopLevelDecl decl) { + Contract.Requires(tok != null); + Contract.Requires(name != null); + Contract.Requires(decl != null); + Contract.Ensures(Contract.Result<Resolver_IdentifierExpr>() != null); + + if (!resolver.moduleInfo.IsAbstract) { + if (decl is ModuleDecl md && md.Signature.IsAbstract) { + ReportError(tok, $"a compiled module is not allowed to use an abstract module ({decl.Name})"); + } + } + var n = optTypeArguments == null ? 0 : optTypeArguments.Count; + if (optTypeArguments != null) { + // type arguments were supplied; they must be equal in number to those expected + if (n != decl.TypeArgs.Count) { + ReportError(tok, $"Wrong number of type arguments ({n} instead of {decl.TypeArgs.Count}) passed to {decl.WhatKind}: {name}"); + } + } + var typeArguments = new List<Type>(); + for (var i = 0; i < decl.TypeArgs.Count; i++) { + typeArguments.Add(i < n ? optTypeArguments[i] : new InferredTypeProxy()); + } + return new Resolver_IdentifierExpr(tok, decl, typeArguments); + } + + private bool ResolveDatatypeConstructor(NameSegment expr, List<ActualBinding>/*?*/ args, ResolutionContext resolutionContext, bool complain, + Tuple<DatatypeCtor, bool> pair, string name, ref Expression r, ref Expression rWithArgs) { + Contract.Requires(expr != null); + Contract.Requires(resolutionContext != null); + + var datatypeDecl = pair.Item1.EnclosingDatatype; + if (pair.Item2) { + // there is more than one constructor with this name + if (complain) { + ReportError(expr.tok, + "the name '{0}' denotes a datatype constructor, but does not do so uniquely; add an explicit qualification (for example, '{1}.{0}')", + expr.Name, datatypeDecl.Name); + return false; + } else { + expr.ResolvedExpression = null; + return true; + } + } + + if (expr.OptTypeArguments != null) { + if (complain) { + var errorMsg = $"datatype constructor does not take any type parameters ('{name}')"; + if (datatypeDecl.TypeArgs.Count != 0) { + // Perhaps the user intended to put the type arguments on the constructor, but didn't know the right syntax. + // Let's give a hint (whether or not expr.OptTypeArguments.Count == datatypeDecl.TypeArgs.Count). + var givenTypeArguments = Util.Comma(expr.OptTypeArguments, targ => targ.ToString()); + errorMsg = $"{errorMsg}; did you perhaps mean to write '{datatypeDecl.Name}<{givenTypeArguments}>.{name}'?"; + } + ReportError(expr.tok, errorMsg); + return false; + } else { + expr.ResolvedExpression = null; + return true; + } + } + + var rr = new DatatypeValue(expr.tok, datatypeDecl.Name, name, args ?? new List<ActualBinding>()); + var ok = ResolveDatatypeValue(resolutionContext, rr, datatypeDecl, null, complain); + if (!ok) { + expr.ResolvedExpression = null; + return true; + } + if (args == null) { + r = rr; + } else { + r = rr; // this doesn't really matter, since we're returning an "rWithArgs" (but if would have been proper to have returned the ctor as a lambda) + rWithArgs = rr; + } + return false; + } + + /// <summary> + /// To resolve "id" in expression "E . id", do: + /// * If E denotes a module name M: + /// 0. If isLastNameSegment: + /// Unambiguous constructor name of a datatype in module M (if two constructors have the same name, an error message is produced here) + /// (Language design note: If the constructor name is ambiguous or if one of the steps above takes priority, one can qualify the constructor name with the name of the datatype) + /// 1. Member of module M: sub-module (including submodules of imports), class, datatype, etc. + /// (if two imported types have the same name, an error message is produced here) + /// 2. Static function or method of M._default + /// (Note that in contrast to ResolveNameSegment, imported modules, etc. are ignored) + /// * If E denotes a type: + /// 3. Look up id as a member of that type + /// * If E denotes an expression: + /// 4. Let T be the type of E. Look up id in T. + /// </summary> + /// <param name="expr"></param> + /// <param name="isLastNameSegment">Indicates that the ExprDotName is not directly enclosed in another ExprDotName expression.</param> + /// <param name="args">If the ExprDotName is enclosed in an ApplySuffix, then these are the arguments. The method returns null to indicate + /// that these arguments, if any, were not used. If args is non-null and the method does use them, the method returns the resolved expression + /// that incorporates these arguments.</param> + /// <param name="resolutionContext"></param> + /// <param name="allowMethodCall">If false, generates an error if the name denotes a method. If true and the name denotes a method, returns + /// a Resolver_MethodCall.</param> + Expression ResolveDotSuffix(ExprDotName expr, bool isLastNameSegment, List<ActualBinding> args, ResolutionContext resolutionContext, bool allowMethodCall) { + Contract.Requires(expr != null); + Contract.Requires(!expr.WasResolved()); + Contract.Requires(resolutionContext != null); + Contract.Ensures(Contract.Result<Expression>() == null || args != null); + + // resolve the LHS expression + // LHS should not be reveal lemma + ResolutionContext nonRevealOpts = resolutionContext with { InReveal = false }; + if (expr.Lhs is NameSegment) { + ResolveNameSegment((NameSegment)expr.Lhs, false, null, nonRevealOpts, false); + } else if (expr.Lhs is ExprDotName) { + ResolveDotSuffix((ExprDotName)expr.Lhs, false, null, nonRevealOpts, false); + } else { + ResolveExpression(expr.Lhs, nonRevealOpts); + } + + if (expr.OptTypeArguments != null) { + foreach (var ty in expr.OptTypeArguments) { + resolver.ResolveType(expr.tok, ty, resolutionContext, ResolveTypeOptionEnum.InferTypeProxies, null); + } + } + + Expression r = null; // the resolved expression, if successful + Expression rWithArgs = null; // the resolved expression after incorporating "args" + + var name = resolutionContext.InReveal ? "reveal_" + expr.SuffixName : expr.SuffixName; + var lhs = expr.Lhs.Resolved; + if (lhs != null && lhs.PreType is PreTypePlaceholderModule) { + var ri = (Resolver_IdentifierExpr)lhs; + var sig = ((ModuleDecl)ri.Decl).AccessibleSignature(false); + sig = ModuleResolver.GetSignatureExt(sig); + + if (isLastNameSegment && sig.Ctors.TryGetValue(name, out var pair)) { + // ----- 0. datatype constructor + if (pair.Item2) { + // there is more than one constructor with this name + ReportError(expr.tok, "the name '{0}' denotes a datatype constructor in module {2}, but does not do so uniquely; add an explicit qualification (for example, '{1}.{0}')", name, pair.Item1.EnclosingDatatype.Name, ((ModuleDecl)ri.Decl).Name); + } else { + if (expr.OptTypeArguments != null) { + ReportError(expr.tok, "datatype constructor does not take any type parameters ('{0}')", name); + } + var rr = new DatatypeValue(expr.tok, pair.Item1.EnclosingDatatype.Name, name, args ?? new List<ActualBinding>()); + ResolveDatatypeValue(resolutionContext, rr, pair.Item1.EnclosingDatatype, null); + + if (args == null) { + r = rr; + } else { + r = rr; // this doesn't really matter, since we're returning an "rWithArgs" (but if would have been proper to have returned the ctor as a lambda) + rWithArgs = rr; + } + } + } else if (sig.TopLevels.TryGetValue(name, out var decl)) { + // ----- 1. Member of the specified module + if (decl is AmbiguousTopLevelDecl) { + var ad = (AmbiguousTopLevelDecl)decl; + ReportError(expr.tok, "The name {0} ambiguously refers to a type in one of the modules {1} (try qualifying the type name with the module name)", expr.SuffixName, ad.ModuleNames()); + } else { + // We have found a module name or a type name, neither of which is an expression. However, the ExprDotName we're + // looking at may be followed by a further suffix that makes this into an expression. We postpone the rest of the + // resolution to any such suffix. For now, we create a temporary expression that will never be seen by the compiler + // or verifier, just to have a placeholder where we can recorded what we have found. + if (!isLastNameSegment) { + if (decl is ClassLikeDecl cd && cd.NonNullTypeDecl != null && name != cd.NonNullTypeDecl.Name) { + // A possibly-null type C? was mentioned. But it does not have any further members. The program should have used + // the name of the class, C. Report an error and continue. + ReportError(expr.tok, "To access members of {0} '{1}', write '{1}', not '{2}'", decl.WhatKind, decl.Name, name); + } + } + r = resolver.CreateResolver_IdentifierExpr(expr.tok, name, expr.OptTypeArguments, decl); + } + } else if (sig.StaticMembers.TryGetValue(name, out var member)) { + // ----- 2. static member of the specified module + Contract.Assert(member.IsStatic); // moduleInfo.StaticMembers is supposed to contain only static members of the module's implicit class _default + if (member is AmbiguousMemberDecl) { + var ambiguousMember = (AmbiguousMemberDecl)member; + ReportError(expr.tok, "The name {0} ambiguously refers to a static member in one of the modules {1} (try qualifying the member name with the module name)", expr.SuffixName, ambiguousMember.ModuleNames()); + } else { + var receiver = new StaticReceiverExpr(expr.tok, (TopLevelDeclWithMembers)member.EnclosingClass, true); + receiver.PreType = Type2PreType(receiver.Type); + r = ResolveExprDotCall(expr.tok, receiver, null, member, args, expr.OptTypeArguments, resolutionContext, allowMethodCall); + } + } else { + ReportError(expr.tok, "unresolved identifier: {0}", name); + } + + } else if (lhs != null && lhs.PreType is PreTypePlaceholderType) { + var ri = (Resolver_IdentifierExpr)lhs; + // ----- 3. Look up name in type + // expand any synonyms + var ty = new UserDefinedType(expr.tok, ri.Decl.Name, ri.Decl, ri.TypeArgs).NormalizeExpand(); + if (ty.IsDatatype) { + // ----- LHS is a datatype + var dt = ty.AsDatatype; + if (dt.ConstructorsByName != null && dt.ConstructorsByName.TryGetValue(name, out var ctor)) { + if (expr.OptTypeArguments != null) { + ReportError(expr.tok, $"datatype constructor does not take any type parameters ('{name}')"); + } + var rr = new DatatypeValue(expr.tok, ctor.EnclosingDatatype.Name, name, args ?? new List<ActualBinding>()); + ResolveDatatypeValue(resolutionContext, rr, ctor.EnclosingDatatype, (DPreType)Type2PreType(ty)); + if (args == null) { + r = rr; + } else { + r = rr; // this doesn't really matter, since we're returning an "rWithArgs" (but if would have been proper to have returned the ctor as a lambda) + rWithArgs = rr; + } + } + } + var cd = r == null ? ty.AsTopLevelTypeWithMembersBypassInternalSynonym : null; + if (cd != null) { + // ----- LHS is a type with members + if (resolver.GetClassMembers(cd) is { } members && members.TryGetValue(name, out var member)) { + if (!resolver.VisibleInScope(member)) { + ReportError(expr.tok, $"member '{name}' has not been imported in this scope and cannot be accessed here"); + } + if (!member.IsStatic) { + ReportError(expr.tok, $"accessing member '{name}' requires an instance expression"); //TODO Unify with similar error messages + // nevertheless, continue creating an expression that approximates a correct one + } + var receiver = new StaticReceiverExpr(expr.Lhs.tok, (UserDefinedType)ty.NormalizeExpand(), (TopLevelDeclWithMembers)member.EnclosingClass, false); + receiver.PreType = Type2PreType(receiver.Type); + r = ResolveExprDotCall(expr.tok, receiver, null, member, args, expr.OptTypeArguments, resolutionContext, allowMethodCall); + } + } + if (r == null) { + ReportError(expr.tok, $"member '{name}' does not exist in {ri.Decl.WhatKind} '{ri.Decl.Name}'"); + } + + } else if (lhs != null) { + // ----- 4. Look up name in the type of the Lhs + var (member, tentativeReceiverType) = FindMember(expr.tok, expr.Lhs.PreType, name); + if (member != null) { + if (!member.IsStatic) { + var receiver = expr.Lhs; + AddSubtypeConstraint(tentativeReceiverType, receiver.PreType, expr.tok, $"receiver type ({{1}}) does not have a member named '{name}'"); + r = ResolveExprDotCall(expr.tok, receiver, tentativeReceiverType, member, args, expr.OptTypeArguments, resolutionContext, allowMethodCall); + } else { + var receiver = new StaticReceiverExpr(expr.tok, (TopLevelDeclWithMembers)tentativeReceiverType.Decl, true, lhs); + receiver.PreType = Type2PreType(receiver.Type); + r = ResolveExprDotCall(expr.tok, receiver, null, member, args, expr.OptTypeArguments, resolutionContext, allowMethodCall); + } + } + } + + if (r == null) { + // an error has been reported above; we won't fill in .ResolvedExpression, but we still must fill in .PreType + expr.PreType = CreatePreTypeProxy("ExprDotName error, so using proxy instead"); + } else { + expr.ResolvedExpression = r; + // TODO: do we need something analogous to this for pre-types? expr.Type = r.Type.UseInternalSynonym(); + expr.PreType = r.PreType; + } + return rWithArgs; + } + + Expression ResolveExprDotCall(IToken tok, Expression receiver, DPreType receiverPreTypeBound/*?*/, + MemberDecl member, List<ActualBinding> args, List<Type> optTypeArguments, ResolutionContext resolutionContext, bool allowMethodCall) { + Contract.Requires(tok != null); + Contract.Requires(receiver != null); + Contract.Requires(receiver.PreType.Normalize() is DPreType); + Contract.Requires(member != null); + Contract.Requires(resolutionContext != null && resolutionContext != null); + + ResolvePreTypeSignature(member); + + receiverPreTypeBound ??= (DPreType)receiver.PreType.Normalize(); + + var rr = new MemberSelectExpr(tok, receiver, member.Name); + rr.Member = member; + + // Now, fill in rr.PreType. This requires taking into consideration the type parameters passed to the receiver's type as well as any type + // parameters used in this NameSegment/ExprDotName. + // Add to "subst" the type parameters given to the member's class/datatype + rr.PreTypeApplication_AtEnclosingClass = new List<PreType>(); + rr.PreTypeApplication_JustMember = new List<PreType>(); + var rType = receiverPreTypeBound; + var subst = PreType.PreTypeSubstMap(rType.Decl.TypeArgs, rType.Arguments); + if (member.EnclosingClass == null) { + // this can happen for some special members, like real.Floor + } else { + rr.PreTypeApplication_AtEnclosingClass.AddRange(rType.AsParentType(member.EnclosingClass, this).Arguments); + } + + if (member is Field field) { + if (optTypeArguments != null) { + ReportError(tok, "a field ({0}) does not take any type arguments (got {1})", field.Name, optTypeArguments.Count); + } + subst = BuildPreTypeArgumentSubstitute(subst, receiverPreTypeBound); + rr.PreType = field.PreType.Substitute(subst); +#if SOON + resolver.AddCallGraphEdgeForField(resolutionContext, field, rr); +#endif + } else if (member is Function function) { + if (function is TwoStateFunction && !resolutionContext.IsTwoState) { + ReportError(tok, "two-state function ('{0}') can only be called in a two-state resolutionContext", member.Name); + } + int suppliedTypeArguments = optTypeArguments == null ? 0 : optTypeArguments.Count; + if (optTypeArguments != null && suppliedTypeArguments != function.TypeArgs.Count) { + ReportError(tok, "function '{0}' expects {1} type argument{2} (got {3})", + member.Name, function.TypeArgs.Count, Util.Plural(function.TypeArgs.Count), suppliedTypeArguments); + } + for (int i = 0; i < function.TypeArgs.Count; i++) { + var ta = i < suppliedTypeArguments ? Type2PreType(optTypeArguments[i]) : + CreatePreTypeProxy($"function call to {function.Name}, type argument {i}"); + rr.PreTypeApplication_JustMember.Add(ta); + subst.Add(function.TypeArgs[i], ta); + } + subst = BuildPreTypeArgumentSubstitute(subst, receiverPreTypeBound); + var inParamTypes = function.Formals.ConvertAll(f => f.PreType.Substitute(subst)); + var resultType = Type2PreType(function.ResultType).Substitute(subst); + rr.PreType = BuiltInArrowType(inParamTypes, resultType); +#if SOON + AddCallGraphEdge(resolutionContext, function, rr, IsFunctionReturnValue(function, args, resolutionContext)); +#endif + } else { + // the member is a method + var method = (Method)member; + if (!allowMethodCall) { + // it's a method and method calls are not allowed in the given resolutionContext + ReportError(tok, "expression is not allowed to invoke a {0} ({1})", member.WhatKind, member.Name); + } + int suppliedTypeArguments = optTypeArguments == null ? 0 : optTypeArguments.Count; + if (optTypeArguments != null && suppliedTypeArguments != method.TypeArgs.Count) { + ReportError(tok, "method '{0}' expects {1} type argument{2} (got {3})", + member.Name, method.TypeArgs.Count, Util.Plural(method.TypeArgs.Count), suppliedTypeArguments); + } + for (int i = 0; i < method.TypeArgs.Count; i++) { + var ta = i < suppliedTypeArguments ? Type2PreType(optTypeArguments[i]) : + CreatePreTypeProxy($"method call to {method.Name}, type argument {i}"); + rr.PreTypeApplication_JustMember.Add(ta); + subst.Add(method.TypeArgs[i], ta); + } + subst = BuildPreTypeArgumentSubstitute(subst, receiverPreTypeBound); +#if SOON + rr.ResolvedOutparameterTypes = method.Outs.ConvertAll(f => f.PreType.Substitute(subst)); +#endif + rr.PreType = new UnusedPreType($"call to {method.WhatKind} {method.Name}"); // fill in this field, in order to make "rr" resolved + } + return rr; + } + + ModuleResolver.MethodCallInformation ResolveApplySuffix(ApplySuffix e, ResolutionContext resolutionContext, bool allowMethodCall) { + Contract.Requires(e != null); + Contract.Requires(resolutionContext != null); + Contract.Ensures(Contract.Result<ModuleResolver.MethodCallInformation>() == null || allowMethodCall); + + Expression r = null; // upon success, the expression to which the ApplySuffix resolves + var errorCount = ErrorCount; + if (e.Lhs is NameSegment) { + r = ResolveNameSegment((NameSegment)e.Lhs, true, e.Bindings.ArgumentBindings, resolutionContext, allowMethodCall); + // note, if r is non-null, then e.Args have been resolved and r is a resolved expression that incorporates e.Args + } else if (e.Lhs is ExprDotName) { + r = ResolveDotSuffix((ExprDotName)e.Lhs, true, e.Bindings.ArgumentBindings, resolutionContext, allowMethodCall); + // note, if r is non-null, then e.Args have been resolved and r is a resolved expression that incorporates e.Args + } else { + ResolveExpression(e.Lhs, resolutionContext); + } + if (e.Lhs.PreType == null) { + // some error had been detected during the attempted resolution of e.Lhs + e.Lhs.PreType = CreatePreTypeProxy("unresolved ApplySuffix LHS"); + } + Label atLabel = null; + if (e.AtTok != null) { + atLabel = dominatingStatementLabels.Find(e.AtTok.val); + if (atLabel == null) { + ReportError(e.AtTok, "no label '{0}' in scope at this time", e.AtTok.val); + } + } + if (r == null) { + // e.Lhs denotes a function value, or at least it's used as if it were + var dp = FindDefinedPreType(e.Lhs.PreType); + if (dp != null && DPreType.IsArrowType(dp.Decl)) { + // e.Lhs does denote a function value + // In the general case, we'll resolve this as an ApplyExpr, but in the more common case of the Lhs + // naming a function directly, we resolve this as a FunctionCallExpr. + var mse = e.Lhs is NameSegment || e.Lhs is ExprDotName ? e.Lhs.Resolved as MemberSelectExpr : null; + var callee = mse?.Member as Function; + if (atLabel != null && !(callee is TwoStateFunction)) { + ReportError(e.AtTok, "an @-label can only be applied to a two-state function"); + atLabel = null; + } + if (callee != null) { + // resolve as a FunctionCallExpr instead of as an ApplyExpr(MemberSelectExpr) + var rr = new FunctionCallExpr(e.Lhs.tok, callee.Name, mse.Obj, e.tok, e.CloseParen, e.Bindings, atLabel) { + Function = callee, + PreTypeApplication_AtEnclosingClass = mse.PreTypeApplication_AtEnclosingClass, + PreTypeApplication_JustFunction = mse.PreTypeApplication_JustMember + }; + var typeMap = mse.PreTypeArgumentSubstitutionsAtMemberDeclaration(); + var preTypeMap = BuildPreTypeArgumentSubstitute( + typeMap.Keys.ToDictionary(tp => tp, tp => typeMap[tp])); + ResolveActualParameters(rr.Bindings, callee.Formals, e.tok, callee, resolutionContext, preTypeMap, callee.IsStatic ? null : mse.Obj); + rr.PreType = Type2PreType(callee.ResultType).Substitute(preTypeMap); + if (errorCount == ErrorCount) { + Contract.Assert(!(mse.Obj is StaticReceiverExpr) || callee.IsStatic); // this should have been checked already + Contract.Assert(callee.Formals.Count == rr.Args.Count); // this should have been checked already + } + // further bookkeeping + if (callee is ExtremePredicate) { + ((ExtremePredicate)callee).Uses.Add(rr); + } + r = rr; + ResolveExpression(r, resolutionContext); + } else { + // resolve as an ApplyExpr + var formals = new List<Formal>(); + for (var i = 0; i < dp.Arguments.Count - 1; i++) { + var argType = dp.Arguments[i]; + var formal = new ImplicitFormal(e.tok, "_#p" + i, new InferredTypeProxy(), true, false); + formal.PreType = argType; + formals.Add(formal); + } + ResolveActualParameters(e.Bindings, formals, e.tok, dp, resolutionContext, new Dictionary<TypeParameter, PreType>(), null); + r = new ApplyExpr(e.Lhs.tok, e.Lhs, e.Args, e.CloseParen); + ResolveExpression(r, resolutionContext); + r.PreType = dp.Arguments.Last(); + } + } else { + // e.Lhs is used as if it were a function value, but it isn't + var lhs = e.Lhs.Resolved; + if (lhs != null && lhs.PreType is PreTypePlaceholderModule) { + ReportError(e.tok, "name of module ({0}) is used as a function", ((Resolver_IdentifierExpr)lhs).Decl.Name); + } else if (lhs != null && lhs.PreType is PreTypePlaceholderType) { + var ri = (Resolver_IdentifierExpr)lhs; + ReportError(e.tok, "name of {0} ({1}) is used as a function", ri.Decl.WhatKind, ri.Decl.Name); + } else { + if (lhs is MemberSelectExpr mse && mse.Member is Method) { + if (atLabel != null) { + Contract.Assert(mse != null); // assured by the parser + if (mse.Member is TwoStateLemma) { + mse.AtLabel = atLabel; + } else { + ReportError(e.AtTok, "an @-label can only be applied to a two-state lemma"); + } + } + if (allowMethodCall) { + return new ModuleResolver.MethodCallInformation(e.RangeToken, mse, e.Bindings.ArgumentBindings); + } else { + ReportError(e.tok, "{0} call is not allowed to be used in an expression resolutionContext ({1})", mse.Member.WhatKind, mse.Member.Name); + } + } else if (lhs != null) { // if e.Lhs.Resolved is null, then e.Lhs was not successfully resolved and an error has already been reported + ReportError(e.tok, "non-function expression (of type {0}) is called with parameters", e.Lhs.PreType); + } + } + // resolve the arguments, even in the presence of the errors above + foreach (var binding in e.Bindings.ArgumentBindings) { + ResolveExpression(binding.Actual, resolutionContext); + } + } + } + if (r == null) { + // an error has been reported above; we won't fill in .ResolvedExpression, but we still must fill in .PreType + e.PreType = CreatePreTypeProxy("unresolved ApplySuffix"); + } else { + e.ResolvedExpression = r; + e.PreType = r.PreType; + } + return null; // not a method call + } + + /// <summary> + /// Attempt to rewrite a datatype update into more primitive operations, after doing the appropriate resolution checks. + /// Upon success, return that rewritten expression and set "legalSourceConstructors". + /// Upon some resolution error, report an error and return null (caller should not use "legalSourceConstructors"). + /// Note, "root.PreType" is allowed to be different from "rootPreType"; in particular, "root.PreType" may still be a proxy. + /// + /// Actually, the method returns two expressions (or returns "(null, null)"). The first expression is the desugaring to be + /// used when the DatatypeUpdateExpr is used in a ghost context. The second is to be used for a compiled context. In either + /// case, "legalSourceConstructors" contains both ghost and compiled constructors. + /// + /// The reason for computing both desugarings here is that it's too early to tell if the DatatypeUpdateExpr is being used in + /// a ghost or compiled context. This is a consequence of doing the deguaring so early. But it's also convenient to do the + /// desugaring during resolution, because then the desugaring can be constructed as a non-resolved expression on which ResolveExpression + /// is called--this is easier than constructing an already-resolved expression. + /// </summary> + (Expression, Expression) ResolveDatatypeUpdate(IToken tok, DPreType rootPreType, Expression root, DatatypeDecl dt, + List<Tuple<IToken, string, Expression>> memberUpdates, + ResolutionContext resolutionContext, out List<MemberDecl> members, out List<DatatypeCtor> legalSourceConstructors) { + Contract.Requires(tok != null); + Contract.Requires(root != null); + Contract.Requires(rootPreType != null); + Contract.Requires(dt != null); + Contract.Requires(memberUpdates != null); + Contract.Requires(resolutionContext != null); + + legalSourceConstructors = null; + members = new List<MemberDecl>(); + Contract.Assert(rootPreType.Decl == dt); + Contract.Assert(rootPreType.Arguments.Count == dt.TypeArgs.Count); + + // First, compute the list of candidate result constructors, that is, the constructors + // that have all of the mentioned destructors. Issue errors for duplicated names and for + // names that are not destructors in the datatype. + var candidateResultCtors = dt.Ctors; // list of constructors that have all the so-far-mentioned destructors + var memberNames = new HashSet<string>(); + var rhsBindings = new Dictionary<string, Tuple<BoundVar/*let variable*/, IdentifierExpr/*id expr for let variable*/, Expression /*RHS in given syntax*/>>(); + foreach (var (updateToken, updateName, updateValue) in memberUpdates) { + if (memberNames.Contains(updateName)) { + ReportError(updateToken, $"duplicate update member '{updateName}'"); + } else { + memberNames.Add(updateName); + if (!resolver.GetClassMembers(dt).TryGetValue(updateName, out var member)) { + ReportError(updateToken, "member '{0}' does not exist in datatype '{1}'", updateName, dt.Name); + } else if (member is not DatatypeDestructor) { + ReportError(updateToken, "member '{0}' is not a destructor in datatype '{1}'", updateName, dt.Name); + } else { + members.Add(member); + var destructor = (DatatypeDestructor)member; + var intersection = new List<DatatypeCtor>(candidateResultCtors.Intersect(destructor.EnclosingCtors)); + if (intersection.Count == 0) { + ReportError(updateToken, + "updated datatype members must belong to the same constructor (unlike the previously mentioned destructors, '{0}' does not belong to {1})", + updateName, DatatypeDestructor.PrintableCtorNameList(candidateResultCtors, "or")); + } else { + candidateResultCtors = intersection; + if (destructor.IsGhost) { + rhsBindings.Add(updateName, new Tuple<BoundVar, IdentifierExpr, Expression>(null, null, updateValue)); + } else { + var xName = resolver.FreshTempVarName($"dt_update#{updateName}#", resolutionContext.CodeContext); + var xVar = new BoundVar(new AutoGeneratedToken(tok), xName, new InferredTypeProxy()); + var x = new IdentifierExpr(new AutoGeneratedToken(tok), xVar); + rhsBindings.Add(updateName, new Tuple<BoundVar, IdentifierExpr, Expression>(xVar, x, updateValue)); + } + } + } + } + } + if (candidateResultCtors.Count == 0) { + return (null, null); + } + + // Check that every candidate result constructor has given a name to all of its parameters. + var hasError = false; + foreach (var ctor in candidateResultCtors) { + if (ctor.Formals.Exists(f => !f.HasName)) { + ReportError(tok, $"candidate result constructor '{ctor.Name}' has an anonymous parameter" + + " (to use in datatype update expression, name all the parameters of the candidate result constructors)"); + hasError = true; + } + } + if (hasError) { + return (null, null); + } + + // The legal source constructors are the candidate result constructors. (Yep, two names for the same thing.) + legalSourceConstructors = candidateResultCtors; + Contract.Assert(1 <= legalSourceConstructors.Count); + + var desugaringForGhostContext = DesugarDatatypeUpdate(tok, root, rootPreType, candidateResultCtors, rhsBindings, resolutionContext); + var nonGhostConstructors = candidateResultCtors.Where(ctor => !ctor.IsGhost).ToList(); + if (nonGhostConstructors.Count == candidateResultCtors.Count) { + return (desugaringForGhostContext, desugaringForGhostContext); + } + var desugaringForCompiledContext = DesugarDatatypeUpdate(tok, root, rootPreType, nonGhostConstructors, rhsBindings, resolutionContext); + return (desugaringForGhostContext, desugaringForCompiledContext); + } + + /// <summary> + /// Rewrite the datatype update root.(x := X, y := Y, ...) into a resolved expression: + /// var d := root; + /// var x := X; // EXCEPT: don't do this for ghost fields (see below) + /// var y := Y; + /// ... + /// if d.CandidateResultConstructor0 then + /// CandidateResultConstructor0(x, y, ..., d.f0, d.f1, ...) // for a ghost field x, use the expression X directly + /// else if d.CandidateResultConstructor1 then + /// CandidateResultConstructor0(x, y, ..., d.g0, d.g1, ...) + /// ... + /// else + /// CandidateResultConstructorN(x, y, ..., d.k0, d.k1, ...) + /// + /// </summary> + private Expression DesugarDatatypeUpdate(IToken tok, Expression root, DPreType rootPreType, + List<DatatypeCtor> candidateResultCtors, Dictionary<string, Tuple<BoundVar, IdentifierExpr, Expression>> rhsBindings, + ResolutionContext resolutionContext) { + Contract.Requires(1 <= candidateResultCtors.Count); + + // Create a unique name for d', the variable we introduce in the let expression + var dName = resolver.FreshTempVarName("dt_update_tmp#", resolutionContext.CodeContext); + var dVar = new BoundVar(new AutoGeneratedToken(tok), dName, new InferredTypeProxy()); + dVar.PreType = rootPreType; + var d = new IdentifierExpr(new AutoGeneratedToken(tok), dVar); + Expression body = null; + candidateResultCtors.Reverse(); + foreach (var crc in candidateResultCtors) { + // Build the arguments to the datatype constructor, using the updated value in the appropriate slot + var actualBindings = new List<ActualBinding>(); + foreach (var f in crc.Formals) { + Expression ctorArg; + if (rhsBindings.TryGetValue(f.Name, out var info)) { + ctorArg = info.Item2 ?? info.Item3; + } else { + ctorArg = new ExprDotName(tok, d, f.Name, null); + } + var bindingName = new Token(tok.line, tok.col) { + Uri = tok.Uri, + val = f.Name + }; + actualBindings.Add(new ActualBinding(bindingName, ctorArg)); + } + var ctorCall = new DatatypeValue(tok, crc.EnclosingDatatype.Name, crc.Name, actualBindings); + if (body == null) { + body = ctorCall; + } else { + // body := if d.crc? then ctor_call else body + var guard = new ExprDotName(tok, d, crc.QueryField.Name, null); + body = new ITEExpr(tok, false, guard, ctorCall, body); + } + } + Contract.Assert(body != null); // because there was at least one element in candidateResultCtors + + // Wrap the let bindings around body + var rewrite = body; + foreach (var entry in rhsBindings) { + if (entry.Value.Item1 != null) { + var lhs = new CasePattern<BoundVar>(tok, entry.Value.Item1); + rewrite = new LetExpr(tok, new List<CasePattern<BoundVar>>() { lhs }, new List<Expression>() { entry.Value.Item3 }, rewrite, true); + } + } + var dVarPat = new CasePattern<BoundVar>(tok, dVar); + rewrite = new LetExpr(tok, new List<CasePattern<BoundVar>>() { dVarPat }, new List<Expression>() { root }, rewrite, true); + Contract.Assert(rewrite != null); + ResolveExpression(rewrite, resolutionContext); + return rewrite; + } + + /// <summary> + /// Resolves the case pattern "pat", figuring out if it denotes a variable or a constructor (or is in error). + /// The caller is expected to have filled in the .type and .PreType fields of any variable occurring in "pat". + /// </summary> + void ResolveCasePattern<VT>(CasePattern<VT> pat, PreType sourcePreType, ResolutionContext resolutionContext) where VT : class, IVariable { + Contract.Requires(pat != null); + Contract.Requires(sourcePreType != null); + Contract.Requires(resolutionContext != null); + + var dtd = (sourcePreType.Normalize() as DPreType)?.Decl as DatatypeDecl; + List<PreType> sourceTypeArguments = null; + // Find the constructor in the given datatype + // If what was parsed was just an identifier, we will interpret it as a datatype constructor, if possible + DatatypeCtor ctor = null; + if (dtd != null) { + sourceTypeArguments = ((DPreType)sourcePreType.Normalize()).Arguments; + if (pat.Var == null || (pat.Var != null && pat.Var.Type is TypeProxy)) { + if (dtd.ConstructorsByName.TryGetValue(pat.Id, out ctor)) { + if (pat.Arguments == null) { + if (ctor.Formals.Count != 0) { + // Leave this as a variable + } else { + // Convert to a constructor + pat.MakeAConstructor(); + pat.Ctor = ctor; + pat.Var = default(VT); + } + } else { + pat.Ctor = ctor; + pat.Var = default(VT); + } + } + } + } + + if (pat.Var != null) { + // this is a simple resolution + var v = pat.Var; + if (resolutionContext.IsGhost) { + v.MakeGhost(); + } + Contract.Assert(v.PreType != null); +#if SOON + AddTypeDependencyEdges(resolutionContext, v.Type); +#endif + // Note, the following type constraint checks that the RHS type can be assigned to the new variable on the left. In particular, it + // does not check that the entire RHS can be assigned to something of the type of the pattern on the left. For example, consider + // a type declared as "datatype Atom<T> = MakeAtom(T)", where T is a non-variant type argument. Suppose the RHS has type Atom<nat> + // and that the LHS is the pattern MakeAtom(x: int). This is okay, despite the fact that Atom<nat> is not assignable to Atom<int>. + // The reason is that the purpose of the pattern on the left is really just to provide a skeleton to introduce bound variables in. +#if SOON + EagerAddAssignableConstraint(v.Tok, v.Type, sourcePreType, "type of corresponding source/RHS ({1}) does not match type of bound variable ({0})"); +#else + AddSubtypeConstraint(v.PreType, sourcePreType, v.Tok, + "type of corresponding source/RHS ({1}) does not match type of bound variable ({0})"); +#endif + pat.AssembleExprPreType(null); + return; + } + + if (dtd == null) { + // look up the name of the pattern's constructor + if (resolver.moduleInfo.Ctors.TryGetValue(pat.Id, out var pair) && !pair.Item2) { + ctor = pair.Item1; + pat.Ctor = ctor; + dtd = ctor.EnclosingDatatype; + sourceTypeArguments = dtd.TypeArgs.ConvertAll(tp => (PreType)CreatePreTypeProxy($"type parameter '{tp.Name}'")); + var lhsPreType = new DPreType(dtd, sourceTypeArguments); + AddSubtypeConstraint(lhsPreType, sourcePreType, pat.tok, $"type of RHS ({{0}}) does not match type of bound variable '{pat.Id}' ({{1}})"); + } + } + if (dtd == null) { + Contract.Assert(ctor == null); + ReportError(pat.tok, "to use a pattern, the type of the source/RHS expression must be a datatype (instead found {0})", sourcePreType); + } else if (ctor == null) { + ReportError(pat.tok, "constructor {0} does not exist in datatype {1}", pat.Id, dtd.Name); + } else { + if (pat.Arguments == null) { + if (ctor.Formals.Count == 0) { + // The Id matches a constructor of the correct type and 0 arguments, + // so make it a nullary constructor, not a variable + pat.MakeAConstructor(); + } + } else { + if (ctor.Formals.Count != pat.Arguments.Count) { + ReportError(pat.tok, "pattern for constructor {0} has wrong number of formals (found {1}, expected {2})", pat.Id, pat.Arguments.Count, ctor.Formals.Count); + } + } + // build the type-parameter substitution map for this use of the datatype + Contract.Assert(dtd.TypeArgs.Count == sourceTypeArguments.Count); // follows from the type previously having been successfully resolved + var subst = PreType.PreTypeSubstMap(dtd.TypeArgs, sourceTypeArguments); + // recursively call ResolveCasePattern on each of the arguments + var j = 0; + if (pat.Arguments != null) { + foreach (var arg in pat.Arguments) { + if (j < ctor.Formals.Count) { + var formal = ctor.Formals[j]; + var st = formal.PreType.Substitute(subst); + ResolveCasePattern(arg, st, resolutionContext.WithGhost(resolutionContext.IsGhost || formal.IsGhost)); + } + j++; + } + } + if (j == ctor.Formals.Count) { + pat.AssembleExprPreType(sourceTypeArguments); + } + } + } + + /// <summary> + /// The return value is false iff there is an error in resolving the datatype value. + /// If there is an error, then an error message is emitted iff complain is true. + /// </summary> + private bool ResolveDatatypeValue(ResolutionContext resolutionContext, DatatypeValue dtv, DatatypeDecl datatypeDecl, DPreType ty, bool complain = true) { + Contract.Requires(resolutionContext != null); + Contract.Requires(dtv != null); + Contract.Requires(datatypeDecl != null); + Contract.Requires(ty == null || (ty.Decl == datatypeDecl && ty.Arguments.Count == datatypeDecl.TypeArgs.Count)); + + var ok = true; + List<PreType> gt; + if (ty == null) { + gt = datatypeDecl.TypeArgs.ConvertAll(tp => CreatePreTypeProxy($"datatype type parameter '{tp.Name}'")); + } else { + gt = ty.Arguments; + } + dtv.InferredPreTypeArgs.AddRange(gt); + // Construct a resolved type directly, since we know the declaration is datatypeDecl. + dtv.PreType = new DPreType(datatypeDecl, gt); + + if (!datatypeDecl.ConstructorsByName.TryGetValue(dtv.MemberName, out var ctor)) { + ok = false; + if (complain) { + ReportError(dtv.tok, "undeclared constructor {0} in datatype {1}", dtv.MemberName, dtv.DatatypeName); + } + } else { + Contract.Assert(ctor != null); // follows from postcondition of TryGetValue + dtv.Ctor = ctor; + } + if (complain && ctor != null) { + var subst = PreType.PreTypeSubstMap(datatypeDecl.TypeArgs, gt); + ResolveActualParameters(dtv.Bindings, ctor.Formals, dtv.tok, ctor, resolutionContext, subst, null); + } else { + // still resolve the expressions + foreach (var binding in dtv.Bindings.ArgumentBindings) { + ResolveExpression(binding.Actual, resolutionContext); + } + dtv.Bindings.AcceptArgumentExpressionsAsExactParameterList(); + } + + if (CodeContextWrapper.Unwrap(resolutionContext.CodeContext) is ICallable caller && caller.EnclosingModule == datatypeDecl.EnclosingModuleDefinition) { + caller.EnclosingModule.CallGraph.AddEdge(caller, datatypeDecl); + } + return ok && ctor.Formals.Count == dtv.Arguments.Count; + } + + PreType ResolveSingleSelectionExpr(IToken tok, PreType collectionPreType, Expression index) { + var resultPreType = CreatePreTypeProxy("seq selection"); + Constraints.AddGuardedConstraint(() => { + var sourcePreType = collectionPreType.Normalize() as DPreType; + if (sourcePreType != null) { + var familyDeclName = AncestorName(sourcePreType); + switch (familyDeclName) { + case "array": + case "seq": + AddConfirmation(PreTypeConstraints.CommonConfirmationBag.IntLikeOrBitvector, index.PreType, index.tok, "index expression must have an integer type (got {0})"); + AddSubtypeConstraint(resultPreType, sourcePreType.Arguments[0], tok, "type does not agree with element type {1} (got {0})"); + break; + case "multiset": + AddSubtypeConstraint(sourcePreType.Arguments[0], index.PreType, index.tok, "type does not agree with element type {0} (got {1})"); + ConstrainToIntFamily(resultPreType, tok, "multiset multiplicity must have an integer type (got {0})"); + break; + case "map": + case "imap": + AddSubtypeConstraint(sourcePreType.Arguments[0], index.PreType, index.tok, "type does not agree with domain type {0} (got {1})"); + AddSubtypeConstraint(resultPreType, sourcePreType.Arguments[1], tok, "type does not agree with value type of {1} (got {0})"); + break; + default: + ReportError(tok, "element selection requires a sequence, array, multiset, or map (got {0})", sourcePreType); + break; + } + return true; + } + return false; + }); + return resultPreType; + } + + PreType ResolveRangeSelectionExpr(IToken tok, PreType collectionPreType, Expression e0, Expression e1) { + var resultElementPreType = CreatePreTypeProxy("multi-index selection"); + var resultPreType = new DPreType(BuiltInTypeDecl("seq"), new List<PreType>() { resultElementPreType }); + if (e0 != null) { + AddConfirmation(PreTypeConstraints.CommonConfirmationBag.IntLikeOrBitvector, e0.PreType, e0.tok, + "multi-element selection position expression must have an integer type (got {0})"); + } + if (e1 != null) { + AddConfirmation(PreTypeConstraints.CommonConfirmationBag.IntLikeOrBitvector, e1.PreType, e1.tok, + "multi-element selection position expression must have an integer type (got {0})"); + } + Constraints.AddGuardedConstraint(() => { + var sourcePreType = collectionPreType.Normalize() as DPreType; + if (sourcePreType != null) { + var familyDeclName = AncestorName(sourcePreType); + switch (familyDeclName) { + case "seq": + case "array": + AddSubtypeConstraint(resultElementPreType, sourcePreType.Arguments[0], tok, "type does not agree with element type {1} (got {0})"); + break; + default: + ReportError(tok, "multi-selection of elements requires a sequence or array (got {0})", collectionPreType); + break; + } + return true; + } + return false; + }); + return resultPreType; + } + + /// <summary> + /// Desugar the elphant-operator expression + /// var x: T :- E; Body + /// into + /// var burrito := E; + /// if button.IsFailure() then + /// burrito.PropagateFailure() + /// else + /// var x: T := burrito.Extract(); + /// Body + /// and desugar the elephant-operator expression + /// :- E; Body + /// into + /// var burrito := E; + /// if button.IsFailure() then + /// burrito.PropagateFailure() + /// else + /// Body + /// </summary> + public Expression DesugarElephantExpr(LetOrFailExpr expr, ResolutionContext resolutionContext) { + // Using the famous monad/burrito analogy, the following variable denotes the burrito + var burrito = resolver.FreshTempVarName("valueOrError", resolutionContext.CodeContext); + var burritoType = new InferredTypeProxy(); + // "var burrito := E;" + return resolver.LetVarIn(expr.tok, burrito, burritoType, expr.Rhs, + // "if burrito.IsFailure()" + new ITEExpr(expr.tok, false, resolver.VarDotFunction(expr.tok, burrito, "IsFailure"), + // "then burrito.PropagateFailure()" + resolver.VarDotFunction(expr.tok, burrito, "PropagateFailure"), + // "else" + expr.Lhs == null + // "Body" + ? expr.Body + // "var x: T := burrito.Extract(); Body" + : resolver.LetPatIn(expr.tok, expr.Lhs, resolver.VarDotFunction(expr.tok, burrito, "Extract"), expr.Body))); + } + + private void EnsureSupportsErrorHandling(IToken tok, DPreType burritoPreType, bool expectExtract, string keyword = null) { + Contract.Requires(tok != null); + Contract.Requires(burritoPreType != null); + + var (memberIsFailure, _) = FindMember(tok, burritoPreType, "IsFailure"); + var (memberPropagate, _) = FindMember(tok, burritoPreType, "PropagateFailure"); + var (memberExtract, _) = FindMember(tok, burritoPreType, "Extract"); + + if (keyword != null) { + if (memberIsFailure == null || (memberExtract != null) != expectExtract) { + // more details regarding which methods are missing have already been reported by regular resolution + var requiredMembers = expectExtract ? "members IsFailure() and Extract()" : "member IsFailure(), but not Extract()"; + ReportError(tok, $"right-hand side of ':- {keyword}', which is of type '{burritoPreType}', must have {requiredMembers}"); + } + } else { + if (memberIsFailure == null || memberPropagate == null || (memberExtract != null) != expectExtract) { + // more details regarding which methods are missing have already been reported by regular resolution + var requiredMembers = expectExtract ? "IsFailure(), PropagateFailure(), and Extract()" : "IsFailure() and PropagateFailure(), but not Extract()"; + ReportError(tok, $"right-hand side of :- operator, which is of type '{burritoPreType}', must have members {requiredMembers}"); + } + } + + // The following checks are not necessary, because the ghost mismatch is caught later. + // However, the error messages here are much clearer. + if (memberIsFailure != null && memberIsFailure.IsGhost) { + ReportError(tok, $"the IsFailure() member must not be ghost (type {burritoPreType} used in RHS of :- operator)"); + } + if (keyword == null && memberPropagate != null && memberPropagate.IsGhost) { + ReportError(tok, $"the PropagateFailure() member must not be ghost (type {burritoPreType} used in RHS of :- operator)"); + } + } + + } +} diff --git a/Source/DafnyCore/Resolver/PreType/PreTypeResolve.Statements.cs b/Source/DafnyCore/Resolver/PreType/PreTypeResolve.Statements.cs new file mode 100644 index 00000000000..4755f9e3ec8 --- /dev/null +++ b/Source/DafnyCore/Resolver/PreType/PreTypeResolve.Statements.cs @@ -0,0 +1,1385 @@ +//----------------------------------------------------------------------------- +// +// Copyright by the contributors to the Dafny Project +// SPDX-License-Identifier: MIT +// +//----------------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Numerics; +using System.Diagnostics.Contracts; +using System.Runtime.Intrinsics.X86; +using JetBrains.Annotations; +using Microsoft.Boogie; +using Bpl = Microsoft.Boogie; +using ResolutionContext = Microsoft.Dafny.ResolutionContext; + +namespace Microsoft.Dafny { + public partial class PreTypeResolver { + private Scope<Statement> enclosingStatementLabels; + private readonly Scope<Label> dominatingStatementLabels; + private List<Statement> loopStack = new(); // the enclosing loops (from which it is possible to break out) + bool inBodyInitContext; // "true" only if "currentMethod is Constructor" + + void ResolveBlockStatement(BlockStmt blockStmt, ResolutionContext resolutionContext) { + Contract.Requires(blockStmt != null); + Contract.Requires(resolutionContext != null); + + if (blockStmt is DividedBlockStmt div) { + Contract.Assert(currentMethod is Constructor); // divided bodies occur only in class constructors + Contract.Assert(!inBodyInitContext); // divided bodies are never nested + inBodyInitContext = true; + foreach (Statement ss in div.BodyInit) { + ResolveStatementWithLabels(ss, resolutionContext); + } + Contract.Assert(inBodyInitContext); + inBodyInitContext = false; + foreach (Statement ss in div.BodyProper) { + ResolveStatementWithLabels(ss, resolutionContext); + } + } else { + foreach (Statement ss in blockStmt.Body) { + ResolveStatementWithLabels(ss, resolutionContext); + } + } + } + + void ResolveStatementWithLabels(Statement stmt, ResolutionContext resolutionContext) { + Contract.Requires(stmt != null); + Contract.Requires(resolutionContext != null); + + enclosingStatementLabels.PushMarker(); + // push labels + for (var l = stmt.Labels; l != null; l = l.Next) { + var lnode = l.Data; + Contract.Assert(lnode.Name != null); // LabelNode's with .Label==null are added only during resolution of the break statements with 'stmt' as their target, which hasn't happened yet + var prev = enclosingStatementLabels.Find(lnode.Name); + if (prev == stmt) { + ReportError(lnode.Tok, "duplicate label"); + } else if (prev != null) { + ReportError(lnode.Tok, "label shadows an enclosing label"); + } else { + var r = enclosingStatementLabels.Push(lnode.Name, stmt); + Contract.Assert(r == Scope<Statement>.PushResult.Success); // since we just checked for duplicates, we expect the Push to succeed + if (dominatingStatementLabels.Find(lnode.Name) != null) { + ReportError(lnode.Tok, "label shadows a dominating label"); + } else { + var rr = dominatingStatementLabels.Push(lnode.Name, lnode); + Contract.Assert(rr == Scope<Label>.PushResult.Success); // since we just checked for duplicates, we expect the Push to succeed + } + } + } + ResolveStatement(stmt, resolutionContext); + enclosingStatementLabels.PopMarker(); + } + + Label/*?*/ ResolveDominatingLabelInExpr(IToken tok, string/*?*/ labelName, string expressionDescription, ResolutionContext resolutionContext) { + Contract.Requires(tok != null); + Contract.Requires(expressionDescription != null); + Contract.Requires(resolutionContext != null); + + Label label = null; + if (!resolutionContext.IsTwoState) { + ReportError(tok, $"{expressionDescription} expressions are not allowed in this context"); + } else if (labelName != null) { + label = dominatingStatementLabels.Find(labelName); + if (label == null) { + ReportError(tok, $"no label '{labelName}' in scope at this time"); + } + } + return label; + } + + public void ResolveStatement(Statement stmt, ResolutionContext resolutionContext) { + Contract.Requires(stmt != null); + Contract.Requires(resolutionContext != null); + + if (!(stmt is ForallStmt || stmt is ForLoopStmt)) { // "forall" and "for" statements do their own attribute resolution below + ResolveAttributes(stmt, resolutionContext, false); + } + if (stmt is PredicateStmt) { + var s = (PredicateStmt)stmt; + var assertStmt = stmt as AssertStmt; + if (assertStmt != null && assertStmt.Label != null) { + if (dominatingStatementLabels.Find(assertStmt.Label.Name) != null) { + ReportError(assertStmt.Label.Tok, "assert label shadows a dominating label"); + } else { + var rr = dominatingStatementLabels.Push(assertStmt.Label.Name, assertStmt.Label); + Contract.Assert(rr == Scope<Label>.PushResult.Success); // since we just checked for duplicates, we expect the Push to succeed + } + } + ResolveExpression(s.Expr, resolutionContext); + ConstrainTypeExprBool(s.Expr, "condition is expected to be of type bool, but is {0}"); + if (assertStmt != null && assertStmt.Proof != null) { + // clear the labels for the duration of checking the proof body, because break statements are not allowed to leave a the proof body + var prevLblStmts = enclosingStatementLabels; + var prevLoopStack = loopStack; + enclosingStatementLabels = new Scope<Statement>(resolver.Options); + loopStack = new List<Statement>(); + ResolveStatement(assertStmt.Proof, resolutionContext); + enclosingStatementLabels = prevLblStmts; + loopStack = prevLoopStack; + } + if (stmt is ExpectStmt expectStmt) { + if (expectStmt.Message == null) { + expectStmt.Message = new StringLiteralExpr(s.Tok, "expectation violation", false); + } + ResolveExpression(expectStmt.Message, resolutionContext); + } + + } else if (stmt is PrintStmt) { + var s = (PrintStmt)stmt; + foreach (var e in s.Args) { + ResolveExpression(e, resolutionContext); + } + + } else if (stmt is RevealStmt) { + var s = (RevealStmt)stmt; + foreach (var expr in s.Exprs) { + var name = RevealStmt.SingleName(expr); + var labeledAssert = name == null ? null : dominatingStatementLabels.Find(name) as AssertLabel; + if (labeledAssert != null) { + s.LabeledAsserts.Add(labeledAssert); + } else { + var revealResolutionContext = resolutionContext with { InReveal = true }; + if (expr is ApplySuffix applySuffix) { + var methodCallInfo = ResolveApplySuffix(applySuffix, revealResolutionContext, true); + if (methodCallInfo == null) { + ReportError(expr.tok, "expression has no reveal lemma"); + } else if (methodCallInfo.Callee.Member is TwoStateLemma && !revealResolutionContext.IsTwoState) { + ReportError(methodCallInfo.Tok, "a two-state function can only be revealed in a two-state context"); + } else if (methodCallInfo.Callee.AtLabel != null) { + Contract.Assert(methodCallInfo.Callee.Member is TwoStateLemma); + ReportError(methodCallInfo.Tok, "to reveal a two-state function, do not list any parameters or @-labels"); + } else { + var call = new CallStmt(s.RangeToken, new List<Expression>(), methodCallInfo.Callee, methodCallInfo.ActualParameters); + s.ResolvedStatements.Add(call); + } + } else { + ResolveExpression(expr, revealResolutionContext); + } + } + } + foreach (var a in s.ResolvedStatements) { + ResolveStatement(a, resolutionContext); + } + + } else if (stmt is BreakStmt) { + var s = (BreakStmt)stmt; + if (s.TargetLabel != null) { + Statement target = enclosingStatementLabels.Find(s.TargetLabel.val); + if (target == null) { + ReportError(s.TargetLabel, $"{s.Kind} label is undefined or not in scope: {s.TargetLabel.val}"); + } else if (s.IsContinue && !(target is LoopStmt)) { + ReportError(s.TargetLabel, $"continue label must designate a loop: {s.TargetLabel.val}"); + } else { + s.TargetStmt = target; + } + } else { + Contract.Assert(1 <= s.BreakAndContinueCount); // follows from BreakStmt class invariant and the guard for this "else" branch + var jumpStmt = s.BreakAndContinueCount == 1 ? + $"a non-labeled '{s.Kind}' statement" : + $"a '{Util.Repeat(s.BreakAndContinueCount - 1, "break ")}{s.Kind}' statement"; + if (loopStack.Count == 0) { + ReportError(s, $"{jumpStmt} is allowed only in loops"); + } else if (loopStack.Count < s.BreakAndContinueCount) { + ReportError(s, + $"{jumpStmt} is allowed only in contexts with {s.BreakAndContinueCount} enclosing loops, but the current context only has {loopStack.Count}"); + } else { + Statement target = loopStack[loopStack.Count - s.BreakAndContinueCount]; + if (target.Labels == null) { + // make sure there is a label, because the compiler and translator will want to see a unique ID + target.Labels = new LList<Label>(new Label(target.Tok, null), null); + } + s.TargetStmt = target; + } + } + + } else if (stmt is ProduceStmt) { + var kind = stmt is YieldStmt ? "yield" : "return"; + if (stmt is YieldStmt && !(resolutionContext.CodeContext is IteratorDecl)) { + ReportError(stmt, "yield statement is allowed only in iterators"); + } else if (stmt is ReturnStmt && !(resolutionContext.CodeContext is Method)) { + ReportError(stmt, "return statement is allowed only in method"); + } else if (inBodyInitContext) { + ReportError(stmt, "return statement is not allowed before 'new;' in a constructor"); + } + var s = (ProduceStmt)stmt; + if (s.Rhss == null) { + // this is a regular return/yield statement. + s.HiddenUpdate = null; + } else { + var cmc = resolutionContext.AsMethodCodeContext; + if (cmc == null) { + // an error has already been reported above + } else if (cmc.Outs.Count != s.Rhss.Count) { + ReportError(s, "number of {2} parameters does not match declaration (found {0}, expected {1})", s.Rhss.Count, cmc.Outs.Count, kind); + } else { + Contract.Assert(s.Rhss.Count > 0); + // Create a hidden update statement using the out-parameter formals, resolve the RHS, and check that the RHS is good. + List<Expression> formals = new List<Expression>(); + foreach (Formal f in cmc.Outs) { + Expression produceLhs; + if (stmt is ReturnStmt) { + var ident = new IdentifierExpr(f.tok, f.Name); + // resolve it here to avoid capture into more closely declared local variables + Contract.Assert(f.Type != null); + ident.Var = f; + ident.PreType = Type2PreType(ident.Var.Type); + produceLhs = ident; + } else { + var yieldIdent = new MemberSelectExpr(f.tok, new ImplicitThisExpr(f.tok), f.Name); + ResolveExpression(yieldIdent, resolutionContext); + produceLhs = yieldIdent; + } + formals.Add(produceLhs); + } + s.HiddenUpdate = new UpdateStmt(s.RangeToken, formals, s.Rhss, true); + // resolving the update statement will check for return/yield statement specifics. + ResolveStatement(s.HiddenUpdate, resolutionContext); + } + } + + } else if (stmt is ConcreteUpdateStatement concreteUpdateStatement) { + ResolveConcreteUpdateStmt(concreteUpdateStatement, null, resolutionContext); + + } else if (stmt is VarDeclStmt varDeclStmt) { + ResolveConcreteUpdateStmt(varDeclStmt.Update, varDeclStmt.Locals, resolutionContext); + + } else if (stmt is VarDeclPattern) { + var s = (VarDeclPattern)stmt; + foreach (var local in s.LocalVars) { + int prevErrorCount = ErrorCount; + resolver.ResolveType(local.Tok, local.OptionalType, resolutionContext, ResolveTypeOptionEnum.InferTypeProxies, null); + local.type = ErrorCount == prevErrorCount ? local.type = local.OptionalType : new InferredTypeProxy(); + local.PreType = Type2PreType(local.type); + } + ResolveExpression(s.RHS, resolutionContext); + ResolveCasePattern(s.LHS, s.RHS.PreType, resolutionContext); + // Check for duplicate names now, because not until after resolving the case pattern do we know if identifiers inside it refer to bound variables or nullary constructors + var c = 0; + foreach (var bv in s.LHS.Vars) { + ScopePushAndReport(scope, bv.Name, bv, bv.Tok, "local variable"); + c++; + } + if (c == 0) { + // Every identifier-looking thing in the pattern resolved to a constructor; that is, this LHS is a constant literal + ReportError(s.LHS.tok, "LHS is a constant literal; to be legal, it must introduce at least one bound variable"); + } + + } else if (stmt is AssignStmt) { + var s = (AssignStmt)stmt; + int prevErrorCount = ErrorCount; + ResolveExpression(s.Lhs, resolutionContext); // allow ghosts for now, tightened up below + bool lhsResolvedSuccessfully = ErrorCount == prevErrorCount; + // check that LHS denotes a mutable variable or a field + var lhs = s.Lhs.Resolved; + if (lhs is IdentifierExpr) { + IVariable var = ((IdentifierExpr)lhs).Var; + if (var == null) { + // the LHS didn't resolve correctly; some error would already have been reported + } else { + CheckIsLvalue(lhs, resolutionContext); + } + } else if (lhs is MemberSelectExpr mseLhs) { + if (mseLhs.Member != null) { // otherwise, an error was reported above + CheckIsLvalue(mseLhs, resolutionContext); + } + } else if (lhs is SeqSelectExpr sseLhs) { + // LHS is fine, provided the "sequence" is really an array + if (lhsResolvedSuccessfully) { + CheckIsLvalue(sseLhs, resolutionContext); + } + } else { + CheckIsLvalue(lhs, resolutionContext); + } + var lhsPreType = s.Lhs.PreType; + if (s.Rhs is ExprRhs) { + var rr = (ExprRhs)s.Rhs; + ResolveExpression(rr.Expr, resolutionContext); + AddSubtypeConstraint(lhsPreType, rr.Expr.PreType, stmt.Tok, "RHS (of type {1}) not assignable to LHS (of type {0})"); + } else if (s.Rhs is TypeRhs) { + var rr = (TypeRhs)s.Rhs; + ResolveTypeRhs(rr, stmt, resolutionContext); + AddSubtypeConstraint(lhsPreType, rr.PreType, stmt.Tok, "type {1} is not assignable to LHS (of type {0})"); + } else if (s.Rhs is HavocRhs) { + // nothing else to do + } else { + Contract.Assert(false); throw new cce.UnreachableException(); // unexpected RHS + } + + } else if (stmt is CallStmt callStmt) { + ResolveCallStmt(callStmt, resolutionContext, null); + + } else if (stmt is BlockStmt blockStmt) { + scope.PushMarker(); + ResolveBlockStatement(blockStmt, resolutionContext); + scope.PopMarker(); + + } else if (stmt is IfStmt) { + var s = (IfStmt)stmt; + if (s.Guard != null) { + ResolveExpression(s.Guard, resolutionContext); + ConstrainTypeExprBool(s.Guard, "if statement", "condition is expected to be of type bool, but is {0}"); + } + + scope.PushMarker(); + if (s.IsBindingGuard) { + var exists = (ExistsExpr)s.Guard; + foreach (var v in exists.BoundVars) { + ScopePushAndReport(v, "bound-variable", false); + } + } + dominatingStatementLabels.PushMarker(); + ResolveBlockStatement(s.Thn, resolutionContext); + dominatingStatementLabels.PopMarker(); + scope.PopMarker(); + + if (s.Els != null) { + dominatingStatementLabels.PushMarker(); + ResolveStatement(s.Els, resolutionContext); + dominatingStatementLabels.PopMarker(); + } + + } else if (stmt is AlternativeStmt) { + var s = (AlternativeStmt)stmt; + ResolveAlternatives(s.Alternatives, null, resolutionContext); + + } else if (stmt is OneBodyLoopStmt oneBodyLoopStmt) { + ResolveOneBodyLoopStmt(oneBodyLoopStmt, resolutionContext); + + } else if (stmt is AlternativeLoopStmt) { + var s = (AlternativeLoopStmt)stmt; + ResolveAlternatives(s.Alternatives, s, resolutionContext); + ResolveLoopSpecificationComponents(s.Invariants, s.Decreases, s.Mod, resolutionContext); + + } else if (stmt is ForallStmt) { + var s = (ForallStmt)stmt; + + int prevErrorCount = ErrorCount; + scope.PushMarker(); + foreach (BoundVar v in s.BoundVars) { + resolver.ResolveType(v.tok, v.Type, resolutionContext, ResolveTypeOptionEnum.InferTypeProxies, null); + ScopePushAndReport(v, "local-variable"); + } + ResolveExpression(s.Range, resolutionContext); + ConstrainTypeExprBool(s.Range, "range restriction in forall statement must be of type bool (instead got {0})"); + foreach (var ens in s.Ens) { + ResolveExpression(ens.E, resolutionContext); + ConstrainTypeExprBool(ens.E, "ensures condition is expected to be of type bool, but is {0}"); + } + // Since the range and postconditions are more likely to infer the types of the bound variables, resolve them + // first (above) and only then resolve the attributes (below). + ResolveAttributes(s, resolutionContext, false); + + if (s.Body != null) { + // clear the labels for the duration of checking the body, because break statements are not allowed to leave a forall statement + var prevLblStmts = enclosingStatementLabels; + var prevLoopStack = loopStack; + enclosingStatementLabels = new Scope<Statement>(resolver.Options); + loopStack = new List<Statement>(); + ResolveStatement(s.Body, resolutionContext); + enclosingStatementLabels = prevLblStmts; + loopStack = prevLoopStack; + } else { + ReportWarning(s.Tok, "note, this forall statement has no body"); + } + scope.PopMarker(); + + if (prevErrorCount == ErrorCount) { + // determine the Kind and run some additional checks on the body + if (s.Ens.Count != 0) { + // The only supported kind with ensures clauses is Proof. + s.Kind = ForallStmt.BodyKind.Proof; + } else { + // There are three special cases: + // * Assign, which is the only kind of the forall statement that allows a heap update. + // * Call, which is a single call statement with no side effects or output parameters. + // * A single calc statement, which is a special case of Proof where the postcondition can be inferred. + // The effect of Assign and the postcondition of Call will be seen outside the forall + // statement. + Statement s0 = s.S0; + if (s0 is AssignStmt) { + s.Kind = ForallStmt.BodyKind.Assign; + + var rhs = ((AssignStmt)s0).Rhs; + if (rhs is TypeRhs) { + ReportError(rhs.Tok, "new allocation not supported in aggregate assignments"); + } + + } else if (s0 is CallStmt) { + s.Kind = ForallStmt.BodyKind.Call; + var call = (CallStmt)s.S0; + var method = call.Method; + // if the called method is not in the same module as the ForallCall stmt + // don't convert it to ForallExpression since the inlined called method's + // ensure clause might not be resolved correctly(test\dafny3\GenericSort.dfy) + if (method.EnclosingClass.EnclosingModuleDefinition != resolutionContext.CodeContext.EnclosingModule) { + s.CanConvert = false; + } + // Additional information (namely, the postcondition of the call) will be reported later. But it cannot be + // done yet, because the specification of the callee may not have been resolved yet. + } else if (s0 is CalcStmt) { + s.Kind = ForallStmt.BodyKind.Proof; + // add the conclusion of the calc as a free postcondition + var result = ((CalcStmt)s0).Result; + s.Ens.Add(new AttributedExpression(result)); + ReportInfo(s.Tok, "ensures " + Printer.ExprToString(resolver.Options, result)); + } else { + s.Kind = ForallStmt.BodyKind.Proof; + if (s.Body is BlockStmt && ((BlockStmt)s.Body).Body.Count == 0) { + // an empty statement, so don't produce any warning + } else { + ReportWarning(s.Tok, "the conclusion of the body of this forall statement will not be known outside the forall statement; consider using an 'ensures' clause"); + } + } + } + + if (s.ForallExpressions != null) { + foreach (Expression expr in s.ForallExpressions) { + ResolveExpression(expr, resolutionContext); + } + } + } + + } else if (stmt is ModifyStmt modifyStmt) { + ResolveAttributes(modifyStmt.Mod, resolutionContext, false); + foreach (FrameExpression fe in modifyStmt.Mod.Expressions) { + ResolveFrameExpression(fe, FrameExpressionUse.Modifies, resolutionContext.CodeContext); + } + if (modifyStmt.Body != null) { + ResolveBlockStatement(modifyStmt.Body, resolutionContext); + } + + } else if (stmt is CalcStmt calcStmt) { + ResolveCalc(calcStmt, resolutionContext); + + } else if (stmt is MatchStmt matchStmt) { + Contract.Assert(false); // a plain MatchStmt isn't introduced until post-resolution + + } else if (stmt is NestedMatchStmt nestedMatchStmt) { + ResolveNestedMatchStmt(nestedMatchStmt, resolutionContext); + + } else if (stmt is SkeletonStatement skeletonStatement) { + ReportError(stmt.Tok, "skeleton statements are allowed only in refining methods"); + // nevertheless, resolve the underlying statement; hey, why not + if (skeletonStatement.S != null) { + ResolveStatement(skeletonStatement.S, resolutionContext); + } + + } else { + Contract.Assert(false); throw new cce.UnreachableException(); + } + } + + private void ResolveOneBodyLoopStmt(OneBodyLoopStmt s, ResolutionContext resolutionContext) { + Contract.Requires(s != null); + Contract.Requires(resolutionContext != null); + + if (s is WhileStmt whileS && whileS.Guard != null) { + ResolveExpression(whileS.Guard, resolutionContext); + ConstrainTypeExprBool(whileS.Guard, "condition is expected to be of type bool, but is {0}"); + + } else if (s is ForLoopStmt forS) { + var loopIndex = forS.LoopIndex; + resolver.ResolveType(loopIndex.tok, loopIndex.Type, resolutionContext, ResolveTypeOptionEnum.InferTypeProxies, null); + loopIndex.PreType = Type2PreType(loopIndex.Type); + AddConfirmation(PreTypeConstraints.CommonConfirmationBag.InIntFamily, loopIndex.PreType, loopIndex.tok, "index variable is expected to be of an integer type (got {0})"); + + ResolveExpression(forS.Start, resolutionContext); + AddSubtypeConstraint(loopIndex.PreType, forS.Start.PreType, forS.Start.tok, + "lower bound (of type {1}) not assignable to index variable (of type {0})"); + if (forS.End != null) { + ResolveExpression(forS.End, resolutionContext); + AddSubtypeConstraint(loopIndex.PreType, forS.End.PreType, forS.End.tok, + "upper bound (of type {1}) not assignable to index variable (of type {0})"); + if (forS.Decreases.Expressions.Count != 0) { + ReportError(forS.Decreases.Expressions[0].tok, + "a 'for' loop is allowed an explicit 'decreases' clause only if the end-expression is '*'"); + } + } else if (forS.Decreases.Expressions.Count == 0 && !resolutionContext.CodeContext.AllowsNontermination) { + // note, the following error message is also emitted elsewhere (if the loop bears a "decreases *") + ReportError(forS.Tok, + "a possibly infinite loop is allowed only if the enclosing method is declared (with 'decreases *') to be possibly non-terminating" + + " (or you can add a 'decreases' clause to this 'for' loop if you want to prove that it does indeed terminate)"); + } + + // Create a new scope, add the local to the scope, and resolve the attributes + scope.PushMarker(); + ScopePushAndReport(loopIndex, "index-variable", false); + ResolveAttributes(s, resolutionContext, false); + } + + ResolveLoopSpecificationComponents(s.Invariants, s.Decreases, s.Mod, resolutionContext); + + if (s.Body != null) { + loopStack.Add(s); // push + dominatingStatementLabels.PushMarker(); + ResolveStatement(s.Body, resolutionContext); + dominatingStatementLabels.PopMarker(); + loopStack.RemoveAt(loopStack.Count - 1); // pop + } + + if (s is ForLoopStmt) { + scope.PopMarker(); + } + } + + private void ResolveCalc(CalcStmt s, ResolutionContext resolutionContext) { + var prevErrorCount = ErrorCount; + // figure out s.Op + Contract.Assert(s.Op == null); // it hasn't been set yet + if (s.UserSuppliedOp != null) { + s.Op = s.UserSuppliedOp; + } else { + s.Op = s.GetInferredDefaultOp() ?? CalcStmt.DefaultOp; + ReportInfo(s.Tok, s.Op.ToString()); + } + + if (s.Lines.Count > 0) { + PreType linePreType = CreatePreTypeProxy("calc line"); + var e0 = s.Lines.First(); + ResolveExpression(e0, resolutionContext); + AddSubtypeConstraint(linePreType, e0.PreType, e0.tok, "all lines in a calculation must have the same type (got {1} after {0})"); + for (var i = 1; i < s.Lines.Count; i++) { + var e1 = s.Lines[i]; + ResolveExpression(e1, resolutionContext); +#if SOON + // reuse the error object if we're on the dummy line; this prevents a duplicate error message +#endif + AddSubtypeConstraint(linePreType, e1.PreType, e1.tok, "all lines in a calculation must have the same type (got {1} after {0})"); + var step = (s.StepOps[i - 1] ?? s.Op).StepExpr(e0, e1); // Use custom line operator + ResolveExpression(step, resolutionContext); + s.Steps.Add(step); + e0 = e1; + } + + // clear the labels for the duration of checking the hints, because break statements are not allowed to leave a forall statement + var prevLblStmts = enclosingStatementLabels; + var prevLoopStack = loopStack; + enclosingStatementLabels = new Scope<Statement>(resolver.Options); + loopStack = new List<Statement>(); + foreach (var h in s.Hints) { + foreach (var oneHint in h.Body) { + dominatingStatementLabels.PushMarker(); + ResolveStatement(oneHint, resolutionContext); + dominatingStatementLabels.PopMarker(); + } + } + enclosingStatementLabels = prevLblStmts; + loopStack = prevLoopStack; + } + if (prevErrorCount == ErrorCount && s.Lines.Count > 0) { + // do not build Result from the lines if there were errors, as it might be ill-typed and produce unnecessary resolution errors + var resultOp = s.StepOps.Aggregate(s.Op, (op0, op1) => op1 == null ? op0 : op0.ResultOp(op1)); + s.Result = resultOp.StepExpr(s.Lines.First(), s.Lines.Last()); + } else { + s.Result = CalcStmt.DefaultOp.StepExpr(Expression.CreateIntLiteral(s.Tok, 0), Expression.CreateIntLiteral(s.Tok, 0)); + } + ResolveExpression(s.Result, resolutionContext); + Contract.Assert(s.Result != null); + Contract.Assert(prevErrorCount != ErrorCount || s.Steps.Count == s.Hints.Count); + } + + private void ResolveConcreteUpdateStmt(ConcreteUpdateStatement update, List<LocalVariable> locals, ResolutionContext resolutionContext) { + Contract.Requires(update != null || locals != null); + // We have four cases. + Contract.Assert(update == null || update is AssignSuchThatStmt || update is UpdateStmt || update is AssignOrReturnStmt); + // 0. There is no update. This is easy, we will just resolve the locals. + // 1. The update is an AssignSuchThatStmt. This is also straightforward: first + // resolve the locals, which adds them to the scope, and then resolve the update. + // 2. The update is an UpdateStmt, which, resolved, means either a CallStmt or a bunch + // of simultaneous AssignStmt's. Here, the right-hand sides should be resolved before + // the local variables have been added to the scope, but the left-hand sides should + // resolve to the newly introduced variables. + // 3. The update is a ":-" statement, for which resolution does two steps: + // First, desugar, then run the regular resolution on the desugared AST. + + var errorCountBeforeCheckingStmt = ErrorCount; + + // For UpdateStmt and AssignOrReturnStmt, resolve the RHSs before adding the LHSs to the scope + if (update is UpdateStmt updateStatement) { + foreach (var rhs in updateStatement.Rhss) { + ResolveAssignmentRhs(rhs, updateStatement, resolutionContext); + } + } else if (update is AssignOrReturnStmt elephantStmt) { + ResolveAssignmentRhs(elephantStmt.Rhs, elephantStmt, resolutionContext); + if (elephantStmt.Rhss != null) { + foreach (var rhs in elephantStmt.Rhss) { + ResolveAssignmentRhs(rhs, elephantStmt, resolutionContext); + } + } + } + + if (locals != null) { + // Add the locals to the scope + foreach (var local in locals) { + int prevErrorCount = ErrorCount; + resolver.ResolveType(local.Tok, local.OptionalType, resolutionContext, ResolveTypeOptionEnum.InferTypeProxies, null); + local.type = ErrorCount == prevErrorCount ? local.OptionalType : new InferredTypeProxy(); + ScopePushAndReport(local, "local-variable", true); + } + // With the new locals in scope, it's now time to resolve the attributes on all the locals + foreach (var local in locals) { + ResolveAttributes(local, resolutionContext, false); + } + } + + // Resolve the LHSs + if (update != null) { + foreach (var lhs in update.Lhss) { + ResolveExpression(lhs, resolutionContext); + } + } + + if (update is AssignSuchThatStmt assignSuchThatStmt) { + ResolveAssignSuchThatStmt(assignSuchThatStmt, resolutionContext); + } else if (update is UpdateStmt updateStmt) { + ResolveUpdateStmt(updateStmt, resolutionContext, errorCountBeforeCheckingStmt); + } else if (update is AssignOrReturnStmt assignOrReturnStmt) { + ResolveAssignOrReturnStmt(assignOrReturnStmt, resolutionContext); + } else { + Contract.Assert(update == null); + } + } + + void ResolveAssignmentRhs(AssignmentRhs rhs, Statement enclosingStmt, ResolutionContext resolutionContext) { + Contract.Requires(rhs != null); + Contract.Requires(enclosingStmt != null); + Contract.Requires(resolutionContext != null); + + if (rhs is TypeRhs tr) { + ResolveTypeRhs(tr, enclosingStmt, resolutionContext); + } else if (rhs is ExprRhs er) { + if (er.Expr is ApplySuffix applySuffix) { + ResolveApplySuffix(applySuffix, resolutionContext, true); + } else { + ResolveExpression(er.Expr, resolutionContext); + } + } else { + Contract.Assert(rhs is HavocRhs); + } + } + + /// <summary> + /// Assumes that LHSs and RHSs have already been resolved. + /// Resolve the entire UpdateStmt. + /// errorCountBeforeCheckingStmt is passed in so that this method can determine if any resolution errors were found during + /// LHS or RHS checking, because only if no errors were found is update.ResolvedStmt changed. + /// </summary> + private void ResolveUpdateStmt(UpdateStmt update, ResolutionContext resolutionContext, int errorCountBeforeCheckingStmt) { + Contract.Requires(update != null); + Contract.Requires(resolutionContext != null); + IToken firstEffectfulRhs = null; + ModuleResolver.MethodCallInformation methodCallInfo = null; + update.ResolvedStatements = new(); + foreach (var rhs in update.Rhss) { + bool isEffectful; + if (rhs is TypeRhs tr) { + isEffectful = tr.InitCall != null; + } else if (rhs is HavocRhs) { + isEffectful = false; + } else { + var er = (ExprRhs)rhs; + if (er.Expr is ApplySuffix applySuffix) { + var cRhs = ResolveApplySuffix(applySuffix, resolutionContext, true); // TODO: don't re-resolve the RHS, only obtain the cRhs return value + isEffectful = cRhs != null; + methodCallInfo = methodCallInfo ?? cRhs; + } else { + isEffectful = false; + } + } + if (isEffectful && firstEffectfulRhs == null) { + firstEffectfulRhs = rhs.Tok; + } + + ResolveAttributes(rhs, resolutionContext, false); + } + + // figure out what kind of UpdateStmt this is + if (firstEffectfulRhs == null) { + if (update.Lhss.Count == 0) { + Contract.Assert(update.Rhss.Count == 1); // guaranteed by the parser + ReportError(update, "expected method call, found expression"); + } else if (update.Lhss.Count != update.Rhss.Count) { + ReportError(update, "the number of left-hand sides ({0}) and right-hand sides ({1}) must match for a multi-assignment", + update.Lhss.Count, update.Rhss.Count); + } else if (ErrorCount == errorCountBeforeCheckingStmt) { + // add the statements here in a sequence, but don't use that sequence later for translation (instead, should translate properly as multi-assignment) + for (var i = 0; i < update.Lhss.Count; i++) { + var a = new AssignStmt(update.RangeToken, update.Lhss[i].Resolved, update.Rhss[i]); + update.ResolvedStatements.Add(a); + } + } + + } else if (update.CanMutateKnownState) { + if (1 < update.Rhss.Count) { + ReportError(firstEffectfulRhs, "cannot have effectful parameter in multi-return statement."); + } else { // it might be ok, if it is a TypeRhs + Contract.Assert(update.Rhss.Count == 1); + if (methodCallInfo != null) { + ReportError(methodCallInfo.Tok, "cannot have method call in return statement."); + } else { + // we have a TypeRhs + var tr = (TypeRhs)update.Rhss[0]; + Contract.Assert(tr.InitCall != null); // there were effects, so this must have been a call. + if (tr.CanAffectPreviouslyKnownExpressions) { + ReportError(tr.Tok, "can only have initialization methods which modify at most 'this'."); + } else if (ErrorCount == errorCountBeforeCheckingStmt) { + var a = new AssignStmt(update.RangeToken, update.Lhss[0].Resolved, tr); + update.ResolvedStatements.Add(a); + } + } + } + + } else { + // if there was an effectful RHS, that must be the only RHS + if (update.Rhss.Count != 1) { + ReportError(firstEffectfulRhs, "an update statement is allowed an effectful RHS only if there is just one RHS"); + } else if (methodCallInfo == null) { + // must be a single TypeRhs + if (update.Lhss.Count != 1) { + Contract.Assert(2 <= update.Lhss.Count); // the parser allows 0 Lhss only if the whole statement looks like an expression (not a TypeRhs) + ReportError(update.Lhss[1].tok, "the number of left-hand sides ({0}) and right-hand sides ({1}) must match for a multi-assignment", + update.Lhss.Count, update.Rhss.Count); + } else if (ErrorCount == errorCountBeforeCheckingStmt) { + var a = new AssignStmt(update.RangeToken, update.Lhss[0].Resolved, update.Rhss[0]); + update.ResolvedStatements.Add(a); + } + } else if (ErrorCount == errorCountBeforeCheckingStmt) { + // a call statement + var resolvedLhss = update.Lhss.ConvertAll(ll => ll.Resolved); + var a = new CallStmt(update.RangeToken, resolvedLhss, methodCallInfo.Callee, methodCallInfo.ActualParameters); + a.OriginalInitialLhs = update.OriginalInitialLhs; + update.ResolvedStatements.Add(a); + } + } + + foreach (var a in update.ResolvedStatements) { + ResolveStatement(a, resolutionContext); + } + } + + /// <summary> + /// Resolve an assign-such-that statement. It is assumed that the LHSs have already been resolved, + /// but not the RHSs. + /// </summary> + private void ResolveAssignSuchThatStmt(AssignSuchThatStmt s, ResolutionContext resolutionContext) { + Contract.Requires(s != null); + Contract.Requires(resolutionContext != null); + + var lhsSimpleVariables = new HashSet<IVariable>(); + foreach (var lhs in s.Lhss) { + CheckIsLvalue(lhs.Resolved, resolutionContext); + if (lhs.Resolved is IdentifierExpr ide) { + if (lhsSimpleVariables.Contains(ide.Var)) { + // syntactically forbid duplicate simple-variables on the LHS + ReportError(lhs, $"variable '{ide.Var.Name}' occurs more than once as left-hand side of :|"); + } else { + lhsSimpleVariables.Add(ide.Var); + } + } + // to ease in the verification of the existence check, only allow local variables as LHSs + if (s.AssumeToken == null && !(lhs.Resolved is IdentifierExpr)) { + ReportError(lhs, "an assign-such-that statement (without an 'assume' clause) currently supports only local-variable LHSs"); + } + } + + ResolveExpression(s.Expr, resolutionContext); + ConstrainTypeExprBool(s.Expr, "type of RHS of assign-such-that statement must be boolean (got {0})"); + } + + private void ResolveLoopSpecificationComponents(List<AttributedExpression> invariants, + Specification<Expression> decreases, Specification<FrameExpression> modifies, + ResolutionContext resolutionContext) { + Contract.Requires(invariants != null); + Contract.Requires(decreases != null); + Contract.Requires(modifies != null); + Contract.Requires(resolutionContext != null); + + foreach (AttributedExpression inv in invariants) { + ResolveAttributes(inv, resolutionContext, false); + ResolveExpression(inv.E, resolutionContext); + ConstrainTypeExprBool(inv.E, "invariant is expected to be of type bool, but is {0}"); + } + + ResolveAttributes(decreases, resolutionContext, false); + foreach (Expression e in decreases.Expressions) { + ResolveExpression(e, resolutionContext); + if (e is WildcardExpr && !resolutionContext.CodeContext.AllowsNontermination) { + ReportError(e, "a possibly infinite loop is allowed only if the enclosing method is declared (with 'decreases *') to be possibly non-terminating"); + } + // any type is fine + } + + ResolveAttributes(modifies, resolutionContext, false); + if (modifies.Expressions != null) { + foreach (var fe in modifies.Expressions) { + ResolveFrameExpression(fe, FrameExpressionUse.Modifies, resolutionContext.CodeContext); + } + } + } + + /// <summary> + /// Resolves the given call statement. + /// Assumes all LHSs have already been resolved (and checked for mutability). + /// </summary> + void ResolveCallStmt(CallStmt s, ResolutionContext resolutionContext, Type receiverType) { + Contract.Requires(s != null); + Contract.Requires(resolutionContext != null); + bool isInitCall = receiverType != null; + + var callee = s.Method; + Contract.Assert(callee != null); // follows from the invariant of CallStmt + if (!isInitCall && callee is Constructor) { + ReportError(s, "a constructor is allowed to be called only when an object is being allocated"); + } + + // resolve left-hand sides (the right-hand sides are resolved below) + foreach (var lhs in s.Lhs) { + Contract.Assume(lhs.PreType != null); // a sanity check that LHSs have already been resolved + } + + bool tryToResolve = false; + if (callee.Outs.Count != s.Lhs.Count) { + if (isInitCall) { + ReportError(s, "a method called as an initialization method must not have any result arguments"); + } else { + ReportError(s, "wrong number of method result arguments (got {0}, expected {1})", s.Lhs.Count, callee.Outs.Count); + tryToResolve = true; + } + } else { + if (isInitCall) { + if (callee.IsStatic) { + ReportError(s.Tok, "a method called as an initialization method must not be 'static'"); + } else { + tryToResolve = true; + } + } else if (!callee.IsStatic) { + if (!scope.AllowInstance && s.Receiver is ThisExpr) { + // The call really needs an instance, but that instance is given as 'this', which is not + // available in this context. For more details, see comment in the resolution of a + // FunctionCallExpr. + ReportError(s.Receiver, "'this' is not allowed in a 'static' context"); + } else if (s.Receiver is StaticReceiverExpr) { + ReportError(s.Receiver, "call to instance method requires an instance"); + } else { + tryToResolve = true; + } + } else { + tryToResolve = true; + } + } + + if (tryToResolve) { + var typeMap = s.MethodSelect.PreTypeArgumentSubstitutionsAtMemberDeclaration(); + // resolve arguments + ResolveActualParameters(s.Bindings, callee.Ins, s.Tok, callee, resolutionContext, typeMap, + callee.IsStatic ? null : s.Receiver); + // type check the out-parameter arguments (in-parameters were type checked as part of ResolveActualParameters) + for (var i = 0; i < callee.Outs.Count && i < s.Lhs.Count; i++) { + var outFormal = callee.Outs[i]; + var st = outFormal.PreType.Substitute(typeMap); + var lhs = s.Lhs[i]; + var what = GetLocationInformation(outFormal, callee.Outs.Count, i, "method out-parameter"); + + AddSubtypeConstraint(lhs.PreType, st, s.Tok, $"incorrect return type {what} (expected {{1}}, got {{0}})"); + } + for (int i = 0; i < s.Lhs.Count; i++) { + var lhs = s.Lhs[i]; + // LHS must denote a mutable field. + CheckIsLvalue(lhs.Resolved, resolutionContext); + } + +#if SOON + // Resolution termination check + ModuleDefinition callerModule = resolutionContext.EnclosingModule; + ModuleDefinition calleeModule = ((ICodeContext)callee).EnclosingModule; + if (callerModule == calleeModule) { + // intra-module call; add edge in module's call graph + var caller = CodeContextWrapper.Unwrap(resolutionContext) as ICallable; + if (caller == null) { + // don't add anything to the call graph after all + } else if (caller is IteratorDecl) { + callerModule.CallGraph.AddEdge(((IteratorDecl)caller).Member_MoveNext, callee); + } else { + callerModule.CallGraph.AddEdge(caller, callee); + if (caller == callee) { + callee.IsRecursive = true; // self recursion (mutual recursion is determined elsewhere) + } + } + } +#endif + } + if (Contract.Exists(callee.Decreases.Expressions, e => e is WildcardExpr) && !resolutionContext.CodeContext.AllowsNontermination) { + ReportError(s.Tok, "a call to a possibly non-terminating method is allowed only if the calling method is also declared (with 'decreases *') to be possibly non-terminating"); + } + } + + /// <summary> + /// Desugars "y, ... :- MethodOrExpression" into + /// var temp; + /// temp, ... := MethodOrExpression; + /// if temp.IsFailure() { return temp.PropagateFailure(); } + /// y := temp.Extract(); + /// + /// If the type of MethodExpression does not have an Extract, then the desugaring is + /// var temp; + /// temp, y, ... := MethodOrExpression; + /// if temp.IsFailure() { return temp.PropagateFailure(); } + /// + /// If there are multiple RHSs then "y, ... :- Expression, ..." becomes + /// var temp; + /// temp, ... := Expression, ...; + /// if temp.IsFailure() { return temp.PropagateFailure(); } + /// y := temp.Extract(); + /// OR + /// var temp; + /// temp, y, ... := Expression, ...; + /// if temp.IsFailure() { return temp.PropagateFailure(); } + /// + /// and "y, ... :- expect MethodOrExpression, ..." into + /// var temp, [y, ] ... := MethodOrExpression, ...; + /// expect !temp.IsFailure(), temp.PropagateFailure(); + /// [y := temp.Extract();] + /// + /// and saves the result into s.ResolvedStatements. + /// This is also known as the "elephant operator" + /// </summary> + private void ResolveAssignOrReturnStmt(AssignOrReturnStmt s, ResolutionContext resolutionContext) { + // We need to figure out whether we are using a status type that has Extract or not, + // as that determines how the AssignOrReturnStmt is desugared. Thus if the RHS is a + // method call, then we need to know which one (to inspect its first output); if RHS is a + // list of expressions, we need to know the type of the first one. For all of this we have + // to do some partial type resolution. + + bool expectExtract = s.Lhss.Count != 0; // default value if we cannot determine and inspect the type + PreType firstPreType = null; + Method callee = null; + Contract.Assert(s.Rhss != null); + if (s.Rhss.Count == 0 && s.Rhs.Expr is ApplySuffix asx) { + var methodCallInfo = ResolveApplySuffix(asx, resolutionContext, true); + callee = methodCallInfo?.Callee.Member as Method; + if (callee != null) { + // We're looking at a method call + if (callee.Outs.Count != 0) { + var typeMap = PreType.PreTypeSubstMap(callee.TypeArgs, methodCallInfo.Callee.PreTypeApplication_JustMember); + firstPreType = callee.Outs[0].PreType.Substitute(typeMap); + } else { + ReportError(s.Rhs.tok, $"Expected '{callee.Name}' to have a success/failure output value, but the method returns nothing."); + } + } else { + // We're looking at a call to a function. Treat it like any other expression. + firstPreType = asx.PreType; + } + } else { + ResolveExpression(s.Rhs.Expr, resolutionContext); + firstPreType = s.Rhs.Expr.PreType; + } + + var enclosingMethod = (Method)resolutionContext.CodeContext; + if (enclosingMethod.Outs.Count == 0 && s.KeywordToken == null) { + ReportError(s.Tok, $"A method containing a :- statement must have an out-parameter ({enclosingMethod.Name})"); + return; + } + TopLevelDeclWithMembers failureSupportingType = null; + if (firstPreType != null) { + Constraints.PartiallySolveTypeConstraints(); + failureSupportingType = (firstPreType.Normalize() as DPreType)?.Decl as TopLevelDeclWithMembers; + if (failureSupportingType != null) { + if (failureSupportingType.Members.Find(x => x.Name == "IsFailure") == null) { + ReportError(s.Tok, $"member IsFailure does not exist in {firstPreType}, in :- statement"); + return; + } + expectExtract = failureSupportingType.Members.Find(x => x.Name == "Extract") != null; + if (expectExtract && callee == null && s.Lhss.Count != 1 + s.Rhss.Count) { + ReportError(s.Tok, + "number of lhs ({0}) must match number of rhs ({1}) for a rhs type ({2}) with member Extract", + s.Lhss.Count, 1 + s.Rhss.Count, firstPreType); + return; + } else if (expectExtract && callee != null && s.Lhss.Count != callee.Outs.Count) { + ReportError(s.Tok, + "wrong number of method result arguments (got {0}, expected {1}) for a rhs type ({2}) with member Extract", + s.Lhss.Count, callee.Outs.Count, firstPreType); + return; + } else if (!expectExtract && callee == null && s.Lhss.Count != s.Rhss.Count) { + ReportError(s.Tok, "number of lhs ({0}) must be one less than number of rhs ({1}) for a rhs type ({2}) without member Extract", + s.Lhss.Count, 1 + s.Rhss.Count, firstPreType); + return; + } else if (!expectExtract && callee != null && s.Lhss.Count != callee.Outs.Count - 1) { + ReportError(s.Tok, "wrong number of method result arguments (got {0}, expected {1}) for a rhs type ({2}) without member Extract", + s.Lhss.Count, callee.Outs.Count - 1, firstPreType); + return; + } + } else { + ReportError(s.Tok, + $"The type of the first expression to the right of ':-' could not be determined to be a failure type (got '{firstPreType}')"); + return; + } + } else { + ReportError(s.Tok, "Internal Error: Unknown failure type in :- statement"); + return; + } + + Expression lhsExtract = null; + if (expectExtract) { + if (enclosingMethod.Outs.Count == 0 && s.KeywordToken == null) { + ReportError(s.Rhs.tok, $"Expected {enclosingMethod.Name} to have a Success/Failure output value"); + return; + } + + lhsExtract = s.Lhss[0]; + var lhsResolved = lhsExtract.Resolved; + // Make a new unresolved expression + if (lhsResolved is MemberSelectExpr lexr) { + Expression id = Expression.AsThis(lexr.Obj) != null ? lexr.Obj : resolver.makeTemp("recv", s, resolutionContext, lexr.Obj); + var lex = lhsExtract as ExprDotName; // might be just a NameSegment + lhsExtract = new ExprDotName(lexr.tok, id, lexr.MemberName, lex?.OptTypeArguments); + } else if (lhsResolved is SeqSelectExpr lseq) { + if (!lseq.SelectOne || lseq.E0 == null) { + ReportError(s.Tok, "Element ranges not allowed as l-values"); + return; + } + Expression id = resolver.makeTemp("recv", s, resolutionContext, lseq.Seq); + Expression id0 = id0 = resolver.makeTemp("idx", s, resolutionContext, lseq.E0); + lhsExtract = new SeqSelectExpr(lseq.tok, lseq.SelectOne, id, id0, null, lseq.CloseParen); + lhsExtract.Type = lseq.Type; + } else if (lhsResolved is MultiSelectExpr lmulti) { + Expression id = resolver.makeTemp("recv", s, resolutionContext, lmulti.Array); + var idxs = new List<Expression>(); + foreach (var i in lmulti.Indices) { + Expression idx = resolver.makeTemp("idx", s, resolutionContext, i); + idxs.Add(idx); + } + lhsExtract = new MultiSelectExpr(lmulti.tok, id, idxs); + lhsExtract.Type = lmulti.Type; + } else if (lhsResolved is IdentifierExpr) { + // do nothing + } else if (lhsResolved == null) { + // LHS failed to resolve. Abort trying to resolve assign or return stmt + return; + } else { + throw new InvalidOperationException("Internal error: unexpected option in AssignOrReturnStmt.Resolve"); + } + } + var temp = resolver.FreshTempVarName("valueOrError", resolutionContext.CodeContext); + var lhss = new List<LocalVariable>() { new LocalVariable(s.RangeToken, temp, new InferredTypeProxy(), false) }; + // "var temp ;" + s.ResolvedStatements.Add(new VarDeclStmt(s.RangeToken, lhss, null)); + var lhss2 = new List<Expression>() { new IdentifierExpr(s.Tok, temp) }; + for (int k = (expectExtract ? 1 : 0); k < s.Lhss.Count; ++k) { + lhss2.Add(s.Lhss[k]); + } + List<AssignmentRhs> rhss2 = new List<AssignmentRhs>() { s.Rhs }; + rhss2.AddRange(s.Rhss); + if (s.Rhss.Count > 0) { + if (lhss2.Count != rhss2.Count) { + ReportError(s.Tok, "Mismatch in expected number of LHSs and RHSs"); + if (lhss2.Count < rhss2.Count) { + rhss2.RemoveRange(lhss2.Count, rhss2.Count - lhss2.Count); + } else { + lhss2.RemoveRange(rhss2.Count, lhss2.Count - rhss2.Count); + } + } + } + // " temp, ... := MethodOrExpression, ...;" + UpdateStmt up = new UpdateStmt(s.RangeToken, lhss2, rhss2); + if (expectExtract) { + up.OriginalInitialLhs = s.Lhss.Count == 0 ? null : s.Lhss[0]; + } + s.ResolvedStatements.Add(up); + + if (s.KeywordToken != null) { + var notFailureExpr = new UnaryOpExpr(s.Tok, UnaryOpExpr.Opcode.Not, resolver.VarDotMethod(s.Tok, temp, "IsFailure")); + Statement ss = null; + if (s.KeywordToken.Token.val == "expect") { + // "expect !temp.IsFailure(), temp" + ss = new ExpectStmt(new RangeToken(s.Tok, s.EndToken), notFailureExpr, new IdentifierExpr(s.Tok, temp), s.KeywordToken.Attrs); + } else if (s.KeywordToken.Token.val == "assume") { + ss = new AssumeStmt(new RangeToken(s.Tok, s.EndToken), notFailureExpr, s.KeywordToken.Attrs); + } else if (s.KeywordToken.Token.val == "assert") { + ss = new AssertStmt(new RangeToken(s.Tok, s.EndToken), notFailureExpr, null, null, s.KeywordToken.Attrs); + } else { + Contract.Assert(false, $"Invalid token in :- statement: {s.KeywordToken.Token.val}"); + } + s.ResolvedStatements.Add(ss); + } else { + var enclosingOutParameter = ((Method)resolutionContext.CodeContext).Outs[0]; + var ident = new IdentifierExpr(s.Tok, enclosingOutParameter.Name) { + // resolve it here to avoid capture into more closely declared local variables + Var = enclosingOutParameter, + Type = enclosingOutParameter.Type, + PreType = enclosingOutParameter.PreType + }; + + s.ResolvedStatements.Add( + // "if temp.IsFailure()" + new IfStmt(s.RangeToken, false, resolver.VarDotMethod(s.Tok, temp, "IsFailure"), + // THEN: { out := temp.PropagateFailure(); return; } + new BlockStmt(s.RangeToken, new List<Statement>() { + new UpdateStmt(s.RangeToken, + new List<Expression>() { ident }, + new List<AssignmentRhs>() {new ExprRhs(resolver.VarDotMethod(s.Tok, temp, "PropagateFailure"))} + ), + new ReturnStmt(s.RangeToken, null), + }), + // ELSE: no else block + null + )); + } + + if (expectExtract) { + // "y := temp.Extract();" + var lhs = s.Lhss[0]; + s.ResolvedStatements.Add( + new UpdateStmt(s.RangeToken, + new List<Expression>() { lhsExtract }, + new List<AssignmentRhs>() { new ExprRhs(resolver.VarDotMethod(s.Tok, temp, "Extract")) } + )); + } + + s.ResolvedStatements.ForEach(a => ResolveStatement(a, resolutionContext)); + EnsureSupportsErrorHandling(s.Tok, failureSupportingType, expectExtract, s.KeywordToken != null); + } + + private void EnsureSupportsErrorHandling(IToken tok, TopLevelDeclWithMembers failureSupportingType, bool expectExtract, bool hasKeywordToken) { + + var isFailure = failureSupportingType.Members.Find(x => x.Name == "IsFailure"); + var propagateFailure = failureSupportingType.Members.Find(x => x.Name == "PropagateFailure"); + var extract = failureSupportingType.Members.Find(x => x.Name == "Extract"); + + if (hasKeywordToken) { + if (isFailure == null || (extract != null) != expectExtract) { + // more details regarding which methods are missing have already been reported by regular resolution + ReportError(tok, + "The right-hand side of ':-', which is of type '{0}', with a keyword token must have function{1}", failureSupportingType, + expectExtract ? "s 'IsFailure()' and 'Extract()'" : " 'IsFailure()', but not 'Extract()'"); + } + } else { + if (isFailure == null || propagateFailure == null || (extract != null) != expectExtract) { + // more details regarding which methods are missing have already been reported by regular resolution + ReportError(tok, + "The right-hand side of ':-', which is of type '{0}', must have function{1}", failureSupportingType, + expectExtract + ? "s 'IsFailure()', 'PropagateFailure()', and 'Extract()'" + : "s 'IsFailure()' and 'PropagateFailure()', but not 'Extract()'"); + } + } + + void checkIsFunction([CanBeNull] MemberDecl memberDecl, bool allowMethod) { + if (memberDecl == null || memberDecl is Function) { + // fine + } else if (allowMethod && memberDecl is Method) { + // give a deprecation warning, so we will remove this language feature around the Dafny 4 time frame + resolver.reporter.Deprecated(MessageSource.Resolver, ResolutionErrors.ErrorId.r_failure_methods_deprecated, tok, + $"Support for member '{memberDecl.Name}' in type '{failureSupportingType}' (used indirectly via a :- statement) being a method is deprecated;" + + " declare it to be a function instead"); + } else { + // not allowed + resolver.reporter.Error(MessageSource.Resolver, tok, + $"Member '{memberDecl.Name}' in type '{failureSupportingType}' (used indirectly via a :- statement) is expected to be a function"); + } + } + + checkIsFunction(isFailure, false); + if (!hasKeywordToken) { + checkIsFunction(propagateFailure, true); + } + if (expectExtract) { + checkIsFunction(extract, true); + } + } + + void ResolveTypeRhs(TypeRhs rr, Statement stmt, ResolutionContext resolutionContext) { + Contract.Requires(rr != null); + Contract.Requires(stmt != null); + Contract.Requires(resolutionContext != null); + Contract.Ensures(Contract.Result<Type>() != null); + + if (rr.PreType != null) { + // the job's already been done + return; + } + + if (rr.ArrayDimensions != null) { + // ---------- new T[EE] OR new T[EE] (elementInit) + var dims = rr.ArrayDimensions.Count; + Contract.Assert(rr.Bindings == null && rr.Path == null && rr.InitCall == null); + resolver.ResolveType(stmt.Tok, rr.EType, resolutionContext, ResolveTypeOptionEnum.InferTypeProxies, null); + int i = 0; + foreach (var dim in rr.ArrayDimensions) { + ResolveExpression(dim, resolutionContext); + var indexHint = dims == 1 ? "" : " for index " + i; + AddConfirmation(PreTypeConstraints.CommonConfirmationBag.InIntFamily, dim.PreType, dim.tok, + $"new must use an integer-based expression for the array size (got {{0}}{indexHint})"); + i++; + } + rr.PreType = BuiltInArrayType(dims, Type2PreType(rr.EType)); + if (rr.ElementInit != null) { + ResolveExpression(rr.ElementInit, resolutionContext); + // Check (the pre-type version of) + // nat^N -> rr.EType :> rr.ElementInit.Type + resolver.SystemModuleManager.CreateArrowTypeDecl(dims); // TODO: should this be done already in the parser? + var indexPreTypes = Enumerable.Repeat(Type2PreType(resolver.SystemModuleManager.Nat()), dims).ToList(); + var arrowPreType = BuiltInArrowType(indexPreTypes, Type2PreType(rr.EType)); + Constraints.AddSubtypeConstraint(arrowPreType, rr.ElementInit.PreType, rr.ElementInit.tok, () => { + var hintString = !PreType.Same(arrowPreType, rr.ElementInit.PreType) ? "" : + string.Format(" (perhaps write '{0} =>' in front of the expression you gave in order to make it an arrow type)", + dims == 1 ? "_" : "(" + Util.Comma(dims, x => "_") + ")"); + return $"array-allocation initialization expression expected to have type '{{0}}' (instead got '{{1}}'){hintString}"; + }); + } else if (rr.InitDisplay != null) { + foreach (var v in rr.InitDisplay) { + ResolveExpression(v, resolutionContext); + AddSubtypeConstraint(Type2PreType(rr.EType), v.PreType, v.tok, "initial value must be assignable to array's elements (expected '{0}', got '{1}')"); + } + } + } else { + if (rr.Bindings == null) { + resolver.ResolveType(stmt.Tok, rr.EType, resolutionContext, ResolveTypeOptionEnum.InferTypeProxies, null); + var cl = (rr.EType as UserDefinedType)?.ResolvedClass as NonNullTypeDecl; + if (cl != null && !(rr.EType.IsTraitType && !rr.EType.NormalizeExpand().IsObjectQ)) { + // life is good + } else { + ReportError(stmt, "new can be applied only to class types (got {0})", rr.EType); + } + } else { + string initCallName = null; + IToken initCallTok = null; + // Resolve rr.Path and do one of three things: + // * If rr.Path denotes a type, then set EType,initCallName to rr.Path,"_ctor", which sets up a call to the anonymous constructor. + // * If the all-but-last components of rr.Path denote a type, then do EType,initCallName := allButLast(EType),last(EType) + // * Otherwise, report an error + var ret = resolver.ResolveTypeLenient(rr.Tok, rr.Path, resolutionContext, + new ModuleResolver.ResolveTypeOption(ResolveTypeOptionEnum.InferTypeProxies), null, true); + if (ret != null) { + // The all-but-last components of rr.Path denote a type (namely, ret.ReplacementType). + rr.EType = ret.ReplacementType; + initCallName = ret.LastComponent.SuffixName; + initCallTok = ret.LastComponent.tok; + } else { + // Either rr.Path resolved correctly as a type or there was no way to drop a last component to make it into something that looked + // like a type. In either case, set EType,initCallName to Path,"_ctor" and continue. + rr.EType = rr.Path; + initCallName = "_ctor"; + initCallTok = rr.Tok; + } + var cl = (rr.EType as UserDefinedType)?.ResolvedClass as NonNullTypeDecl; + if (cl == null || rr.EType.IsTraitType) { + ReportError(rr.tok, "new can be applied only to class types (got {0})", rr.EType); + } else { + // ---------- new C.Init(EE) + Contract.Assert(initCallName != null); + var prevErrorCount = ErrorCount; + + // We want to create a MemberSelectExpr for the initializing method. To do that, we create a throw-away receiver of the appropriate + // type, create a dot-suffix expression around this receiver, and then resolve it in the usual way for dot-suffix expressions. + // It is important that this throw-away receiver have its .PreType filled in, because the call to ResolveDotSuffix will recursive + // down to resolve this "lhs"; that's a no-op if the .PreType is already filled in, whereas it could cause a "'this' not allowed in + // static context" error if the code tried to resolve this "this" against the enclosing environment. + rr.PreType = Type2PreType(rr.EType); + var lhs = new ImplicitThisExpr_ConstructorCall(initCallTok) { + Type = rr.EType, + PreType = rr.PreType + }; + var callLhs = new ExprDotName(((UserDefinedType)rr.EType).tok, lhs, initCallName, ret?.LastComponent.OptTypeArguments); + ResolveDotSuffix(callLhs, true, rr.Bindings.ArgumentBindings, resolutionContext, true); + if (prevErrorCount == ErrorCount) { + Contract.Assert(callLhs.ResolvedExpression is MemberSelectExpr); // since ResolveApplySuffix succeeded and call.Lhs denotes an expression (not a module or a type) + var methodSel = (MemberSelectExpr)callLhs.ResolvedExpression; + if (methodSel.Member is Method) { + rr.InitCall = new CallStmt(stmt.RangeToken, new List<Expression>(), methodSel, rr.Bindings.ArgumentBindings, initCallTok); + ResolveCallStmt(rr.InitCall, resolutionContext, rr.EType); + } else { + ReportError(initCallTok, "object initialization must denote an initializing method or constructor ({0})", initCallName); + } + } + } + } + // set rr.PreType, unless it was already set above + if (rr.PreType == null) { + rr.PreType = Type2PreType(rr.EType); + } + } + } + + /// <summary> + /// Checks if lhs, which is expected to be a successfully resolved expression, denotes something + /// that can be assigned to. In particular, this means that lhs denotes a mutable variable, field, + /// or array element. If a violation is detected, an error is reported. + /// </summary> + void CheckIsLvalue(Expression lhs, ResolutionContext resolutionContext) { + Contract.Requires(lhs != null); + Contract.Requires(resolutionContext != null); + if (lhs is IdentifierExpr) { + var ll = (IdentifierExpr)lhs; + if (!ll.Var.IsMutable) { + ReportError(lhs, "LHS of assignment must denote a mutable variable"); + } + } else if (lhs is MemberSelectExpr) { + var ll = (MemberSelectExpr)lhs; + var field = ll.Member as Field; + if (field == null || !field.IsUserMutable) { + var cf = field as ConstantField; + if (inBodyInitContext && cf != null && !cf.IsStatic && cf.Rhs == null) { + if (Expression.AsThis(ll.Obj) != null) { + // it's cool; this field can be assigned to here + } else { + ReportError(lhs, "LHS of assignment must denote a mutable field of 'this'"); + } + } else { + ReportError(lhs, "LHS of assignment must denote a mutable field"); + } + } + } else if (lhs is SeqSelectExpr) { + var ll = (SeqSelectExpr)lhs; + var arrayType = resolver.ResolvedArrayType(ll.Seq.tok, 1, new InferredTypeProxy(), resolutionContext, true); + AddSubtypeConstraint(Type2PreType(arrayType), ll.Seq.PreType, ll.Seq.tok, "LHS of array assignment must denote an array element (found {1})"); + if (!ll.SelectOne) { + ReportError(ll.Seq, "cannot assign to a range of array elements (try the 'forall' statement)"); + } + } else if (lhs is MultiSelectExpr) { + // nothing to check; this can only denote an array element + } else { + ReportError(lhs, "LHS of assignment must denote a mutable variable or field"); + } + } + + void ResolveAlternatives(List<GuardedAlternative> alternatives, AlternativeLoopStmt loopToCatchBreaks, ResolutionContext resolutionContext) { + Contract.Requires(alternatives != null); + Contract.Requires(resolutionContext != null); + + // first, resolve the guards + foreach (var alternative in alternatives) { + ResolveExpression(alternative.Guard, resolutionContext); + alternative.Guard.PreType = ConstrainResultToBoolFamily(alternative.Guard.tok, "if/while case", "condition is expected to be of type bool, but is {0}"); + } + + if (loopToCatchBreaks != null) { + loopStack.Add(loopToCatchBreaks); // push + } + foreach (var alternative in alternatives) { + scope.PushMarker(); + dominatingStatementLabels.PushMarker(); + if (alternative.IsBindingGuard) { + var exists = (ExistsExpr)alternative.Guard; + foreach (var v in exists.BoundVars) { + ScopePushAndReport(v, "bound-variable", false); + } + } + ResolveAttributes(alternative, resolutionContext, false); + foreach (Statement ss in alternative.Body) { + ResolveStatementWithLabels(ss, resolutionContext); + } + dominatingStatementLabels.PopMarker(); + scope.PopMarker(); + } + if (loopToCatchBreaks != null) { + loopStack.RemoveAt(loopStack.Count - 1); // pop + } + } + } +} diff --git a/Source/DafnyCore/Resolver/PreType/PreTypeResolve.cs b/Source/DafnyCore/Resolver/PreType/PreTypeResolve.cs index b28e5a0954e..e08d312455e 100644 --- a/Source/DafnyCore/Resolver/PreType/PreTypeResolve.cs +++ b/Source/DafnyCore/Resolver/PreType/PreTypeResolve.cs @@ -64,13 +64,18 @@ protected void ReportInfo(IToken tok, string msg, params object[] args) { } } - public class PreTypeResolver : ResolverPass { + public partial class PreTypeResolver : ResolverPass { + private readonly Scope<IVariable> scope; + + TopLevelDeclWithMembers currentClass; + Method currentMethod; + private readonly Dictionary<string, TopLevelDecl> preTypeBuiltins = new(); public readonly PreTypeConstraints Constraints; TopLevelDecl BuiltInTypeDecl(string name) { Contract.Requires(name != null); - if (preTypeBuiltins.TryGetValue(name, out var decl)) { + if (preTypeInferenceModuleState.PreTypeBuiltins.TryGetValue(name, out var decl)) { return decl; } if (IsArrayName(name, out var dims)) { @@ -81,11 +86,15 @@ TopLevelDecl BuiltInTypeDecl(string name) { } else if (IsBitvectorName(name, out var width)) { var bvDecl = new ValuetypeDecl(name, resolver.SystemModuleManager.SystemModule, t => t.IsBitVectorType, typeArgs => new BitvectorType(resolver.Options, width)); - preTypeBuiltins.Add(name, bvDecl); + preTypeInferenceModuleState.PreTypeBuiltins.Add(name, bvDecl); AddRotateMember(bvDecl, "RotateLeft", width); AddRotateMember(bvDecl, "RotateRight", width); + resolver.SystemModuleManager.SystemModule.SourceDecls.Add(bvDecl); + var memberDictionary = bvDecl.Members.ToDictionary(member => member.Name, member => member); + resolver.ProgramResolver.AddSystemClass(bvDecl, memberDictionary); return bvDecl; } else { + decl = null; foreach (var valueTypeDecl in resolver.ProgramResolver.SystemModuleManager.valuetypeDecls) { if (valueTypeDecl.Name == name) { // bool, int, real, ORDINAL, map, imap @@ -100,12 +109,14 @@ TopLevelDecl BuiltInTypeDecl(string name) { } else if (name == "iset") { var variances = new List<TypeParameter.TPVarianceSyntax>() { TypeParameter.TPVarianceSyntax.Covariant_Permissive }; decl = new ValuetypeDecl(name, resolver.SystemModuleManager.SystemModule, variances, _ => false, null); + } else if (name == "object?") { + decl = resolver.SystemModuleManager.ObjectDecl; } else { decl = new ValuetypeDecl(name, resolver.SystemModuleManager.SystemModule, _ => false, null); } } } - preTypeBuiltins.Add(name, decl); + preTypeInferenceModuleState.PreTypeBuiltins.Add(name, decl); return decl; } @@ -131,10 +142,10 @@ public void AddRotateMember(ValuetypeDecl bitvectorTypeDecl, string name, int wi TopLevelDecl BuiltInArrowTypeDecl(int arity) { Contract.Requires(0 <= arity); var name = ArrowType.ArrowTypeName(arity); - if (!preTypeBuiltins.TryGetValue(name, out var decl)) { + if (!preTypeInferenceModuleState.PreTypeBuiltins.TryGetValue(name, out var decl)) { // the arrow type declaration should already have been created by the parser decl = resolver.SystemModuleManager.ArrowTypeDecls[arity]; - preTypeBuiltins.Add(name, decl); + preTypeInferenceModuleState.PreTypeBuiltins.Add(name, decl); } return decl; } @@ -164,26 +175,51 @@ public enum Type2PreTypeOption { GoodForInference, GoodForPrinting, GoodForBoth public PreType Type2PreType(Type type, string description = null, Type2PreTypeOption option = Type2PreTypeOption.GoodForBoth) { Contract.Requires(type != null); - type = type.Normalize(); - var expandedType = type.NormalizeExpand(); - if (expandedType is TypeProxy) { - return CreatePreTypeProxy(description ?? $"from type proxy {type}"); - } + type = type.Normalize(); // keep type synonyms + if (type.AsTypeSynonym is { } typeSynonymDecl and not SubsetTypeDecl && option != Type2PreTypeOption.GoodForInference) { + // Compute a pre-type for the non-instantiated ("raw") RHS type (that is, for the RHS of the type-synonym declaration with the + // formal type parameters of the type-synonym declaration). + var rawRhsType = UserDefinedType.FromTopLevelDecl(typeSynonymDecl.tok, typeSynonymDecl); + var preTypeArguments = type.TypeArgs.ConvertAll(ty => Type2PreType(ty, null, Type2PreTypeOption.GoodForBoth)); + + // The printable pre-type is the original type synonym, but with preTypeArguments as arguments + var printablePreType = new DPreType(typeSynonymDecl, preTypeArguments); - DPreType printablePreType = null; - if (option != Type2PreTypeOption.GoodForInference) { - var printableDecl = Type2Decl(type); - var printableArguments = type.TypeArgs.ConvertAll(ty => Type2PreType(ty, null, Type2PreTypeOption.GoodForPrinting)); - printablePreType = new DPreType(printableDecl, printableArguments, null); - if (option == Type2PreTypeOption.GoodForPrinting) { - return printablePreType; + // The expanded pre-type is the raw RHS pre-type, but substituting in preTypeArguments for the type parameters + var rawRhsPreTypeForInference = Type2PreType(rawRhsType, null, Type2PreTypeOption.GoodForInference); + var preType = rawRhsPreTypeForInference.Substitute(PreType.PreTypeSubstMap(typeSynonymDecl.TypeArgs, preTypeArguments)); + + // Typically, preType is a DPreType. However, it could be that the RHS of the type synonym fizzles out to just one of the type + // parameters of the type synonym, and if that type synonym started off a proxy, then "preType" will be a proxy. + if (preType is DPreType dPreType) { + return new DPreType(dPreType.Decl, dPreType.Arguments, printablePreType); + } else { + // TODO: it would be nice to have a place to include "printablePreType" as part of what's returned, but currently only DPreType allows that + return preType; } } - type = expandedType; + type = type.NormalizeExpandKeepConstraints(); // blow past proxies and type synonyms + if (type.AsSubsetType is { } subsetType) { + ResolvePreTypeSignature(subsetType); + Contract.Assert(subsetType.Var.PreType != null); + var typeArguments = type.TypeArgs.ConvertAll(ty => Type2PreType(ty, null, option)); + var preTypeMap = PreType.PreTypeSubstMap(subsetType.TypeArgs, typeArguments); + return subsetType.Var.PreType.Substitute(preTypeMap); + } else if (type is UserDefinedType { ResolvedClass: NewtypeDecl newtypeDecl }) { + // Make sure the newtype declaration itself has been pre-type resolved + ResolvePreTypeSignature(newtypeDecl); + Contract.Assert(newtypeDecl.Var == null || newtypeDecl.Var.PreType != null); + Contract.Assert(newtypeDecl.BaseType != null); + } + + if (type is TypeProxy) { + return CreatePreTypeProxy(description ?? $"from type proxy {type}"); + } + var decl = Type2Decl(type); - var arguments = type.TypeArgs.ConvertAll(ty => Type2PreType(ty, null, Type2PreTypeOption.GoodForInference)); - return new DPreType(decl, arguments, printablePreType); + var arguments = type.TypeArgs.ConvertAll(ty => Type2PreType(ty, null, option)); + return new DPreType(decl, arguments); } TopLevelDecl Type2Decl(Type type) { @@ -293,7 +329,7 @@ public void ComputeAncestors(TopLevelDecl decl, ISet<TopLevelDecl> ancestors) { if (decl is TopLevelDeclWithMembers topLevelDeclWithMembers) { topLevelDeclWithMembers.ParentTraitHeads.ForEach(parent => ComputeAncestors(parent, ancestors)); } - if (decl is ClassDecl { IsObjectTrait: true }) { + if (decl is TraitDecl { IsObjectTrait: true }) { // we're done } else if (DPreType.IsReferenceTypeDecl(decl)) { // object is also a parent type @@ -363,18 +399,1045 @@ public static bool IsArrayName(string name, out int dimensions) { return false; } - public PreTypeResolver(ModuleResolver resolver) + private class PreTypeInferenceModuleState { + public readonly ISet<Declaration> StillNeedsPreTypeSignature; + public readonly Stack<Declaration> InFirstPhase = new Stack<Declaration>(); + public readonly Dictionary<string, TopLevelDecl> PreTypeBuiltins = new(); + + public PreTypeInferenceModuleState(List<Declaration> declarations) { + StillNeedsPreTypeSignature = new HashSet<Declaration>(declarations); + } + } + + private readonly PreTypeInferenceModuleState preTypeInferenceModuleState; + + private PreTypeResolver(ModuleResolver resolver, PreTypeInferenceModuleState preTypeInferenceModuleState) : base(resolver) { - Contract.Requires(resolver != null); + this.preTypeInferenceModuleState = preTypeInferenceModuleState; + + scope = new Scope<IVariable>(resolver.Options); + enclosingStatementLabels = new Scope<Statement>(resolver.Options); + dominatingStatementLabels = new Scope<Label>(resolver.Options); Constraints = new PreTypeConstraints(this); } + void ScopePushAndReport(IVariable v, string kind, bool assignPreType = true) { + Contract.Requires(scope != null); + Contract.Requires(v != null); + Contract.Requires(kind != null); + if (assignPreType) { + Contract.Assert(v.PreType == null); + v.PreType = Type2PreType(v.Type, $"type of identifier '{v.Name}'"); + Contract.Assert(v.PreType is not DPreType dp || dp.Decl != null); // sanity check that the .Decl field was set + } else { + Contract.Assert(v.PreType != null); + } + ScopePushAndReport(scope, v.Name, v, v.Tok, kind); + } + + void ScopePushExpectSuccess(IVariable v, string kind, bool assignPreType = true) { + Contract.Requires(scope != null); + Contract.Requires(v != null); + Contract.Requires(kind != null); + if (assignPreType) { + Contract.Assert(v.PreType == null); + v.PreType = Type2PreType(v.Type, $"type of identifier '{v.Name}'"); + } else { + Contract.Assert(v.PreType != null); + } + var r = ScopePushAndReport(scope, v.Name, v, v.Tok, kind); + Contract.Assert(r == Scope<IVariable>.PushResult.Success); + } + + private Scope<Thing>.PushResult ScopePushAndReport<Thing>(Scope<Thing> scope, string name, Thing thing, IToken tok, string kind) where Thing : class { + Contract.Requires(scope != null); + Contract.Requires(name != null); + Contract.Requires(thing != null); + Contract.Requires(tok != null); + Contract.Requires(kind != null); + var r = scope.Push(name, thing); + switch (r) { + case Scope<Thing>.PushResult.Success: + break; + case Scope<Thing>.PushResult.Duplicate: + ReportError(tok, "Duplicate {0} name: {1}", kind, name); + break; + case Scope<Thing>.PushResult.Shadow: + ReportWarning(tok, "Shadowed {0} name: {1}", kind, name); + break; + } + return r; + } + +#if THIS_COMES_LATER + public void PostResolveChecks(List<TopLevelDecl> declarations) { + Contract.Requires(declarations != null); + foreach (TopLevelDecl topd in declarations) { + TopLevelDecl d = topd is ClassLikeDecl ? ((ClassLikeDecl)topd).NonNullTypeDecl : topd; + + if (ErrorCount == prevErrorCount) { + // Check type inference, which also discovers bounds, in newtype/subset-type constraints and const declarations + foreach (TopLevelDecl topd in declarations) { + TopLevelDecl d = topd is ClassLikeDecl ? ((ClassLikeDecl)topd).NonNullTypeDecl : topd; + if (topd is TopLevelDeclWithMembers cl) { + foreach (var member in cl.Members) { + if (member is ConstantField field && field.Rhs != null) { + // make sure initialization only refers to constant field or literal expression + if (CheckIsConstantExpr(field, field.Rhs)) { + AddAssignableConstraint(field.tok, field.Type, field.Rhs.Type, + "type for constant '" + field.Name + "' is '{0}', but its initialization value type is '{1}'"); + } + + } + } + } + } + } + + } + } +#endif + + void AddSubtypeConstraint(PreType super, PreType sub, IToken tok, string errorFormatString) { + Constraints.AddSubtypeConstraint(super, sub, tok, errorFormatString); + } + + void AddConfirmation(PreTypeConstraints.CommonConfirmationBag check, PreType preType, IToken tok, string errorFormatString) { + Constraints.AddConfirmation(check, preType, tok, errorFormatString); + } + + void AddComparableConstraint(PreType a, PreType b, IToken tok, string errorFormatString) { + Contract.Requires(a != null); + Contract.Requires(b != null); + Contract.Requires(tok != null); + Contract.Requires(errorFormatString != null); + Constraints.AddGuardedConstraint(() => ApplyComparableConstraints(a, b, tok, errorFormatString)); + } + + bool ApplyComparableConstraints(PreType a, PreType b, IToken tok, string errorFormatString) { + // The meaning of a comparable constraint + // A ~~ B + // is the disjunction + // A :> B or B :> A + // To decide between these two possibilities, enough information must be available about A and/or B. + var ptA = a.Normalize() as DPreType; + var ptB = b.Normalize() as DPreType; + if (ptA != null && ptB != null && + Constraints.GetTypeArgumentsForSuperType(ptB.Decl, ptA.Decl, ptA.Arguments) == null && + Constraints.GetTypeArgumentsForSuperType(ptA.Decl, ptB.Decl, ptB.Arguments) == null) { + // neither A :> B nor B :> A is possible + ReportError(tok, errorFormatString, a, b); + return true; + } else if ((ptA != null && ptA.IsLeafType()) || (ptB != null && ptB.IsRootType())) { + // use B :> A + Constraints.DebugPrint($" DEBUG: turning ~~ into {b} :> {a}"); + Constraints.AddSubtypeConstraint(b, a, tok, errorFormatString); + return true; + } else if ((ptA != null && ptA.IsRootType()) || (ptB != null && ptB.IsLeafType())) { + // use A :> B + Constraints.DebugPrint($" DEBUG: turning ~~ into {a} :> {b}"); + Constraints.AddSubtypeConstraint(a, b, tok, errorFormatString); + return true; + } else { + // not enough information to determine + return false; + } + } + /// <summary> /// For every declaration in "declarations", resolve names and determine pre-types. /// </summary> - public void ResolveDeclarations(List<TopLevelDecl> declarations) { - // under construction... (the CLI option --type-system-refresh has informed the user that this mode is not yet ready) + public static void ResolveDeclarations(List<TopLevelDecl> declarations, ModuleResolver resolver, bool firstPhaseOnly = false) { + // Each (top-level or member) declaration is done in two phases. + // + // The goal of the first phase is to fill in the pre-types in the declaration's signature. For many declarations, + // this is as easy as calling PreType2Type on each type that appears in the declaration's signature. + // Since the base type of a newtype or subset type and the type of a const may be omitted in the program text, + // obtaining the pre-type for these 3 declarations requires doing resolution. It is not clear a-priori which + // order to process the (first phase of the) declarations in, so that the necessary pre-type information is + // available when the first phase of a declaration needs it. Therefore, the order is determined lazily. + // + // In more detail, for this first phase, the declarations are processed in the given order. When such processing + // is started for a declaration, the declaration is pushed onto a stack, and when the processing of the first + // phase is completed, the declaration is popped off the stack and added to a set of first-phase-finished + // declarations. If the processing requires pre-type information for a declaration whose processing has not + // yet started, processing continues recursively with it. If the processing for the other declaration is ongoing, + // then a cyclic-dependency error is reported. + // + // When the first-phase processing is finished for all the declarations, the second-phase processing is done + // for each declaration, in the order given. + + var allDeclarations = AllTopLevelOrMemberDeclarations(declarations).ToList(); + var preTypeInferenceModuleState = new PreTypeInferenceModuleState(allDeclarations); + foreach (var d in allDeclarations) { + Contract.Assert(resolver.VisibleInScope(d)); + ResolvePreTypeSignature(d, preTypeInferenceModuleState, resolver); + } + + if (!firstPhaseOnly) { + var basicPreTypeResolver = new PreTypeResolver(resolver, preTypeInferenceModuleState); + foreach (var d in allDeclarations) { + basicPreTypeResolver.ResolveDeclarationBody(d); + } + } + } + + void ResolvePreTypeSignature(Declaration d) { + ResolvePreTypeSignature(d, preTypeInferenceModuleState, resolver); + } + + private static void ResolvePreTypeSignature(Declaration d, PreTypeInferenceModuleState preTypeInferenceModuleState, ModuleResolver resolver) { + var preTypeResolver = new PreTypeResolver(resolver, preTypeInferenceModuleState); + + // The "allTypeParameters" scope is stored in "resolver", and there's only one such "resolver". Since + // "ResolvePreTypeSignature" is recursive, a simple "PushMarker()" would still leave previous type parameters + // in the scope. Instead, we create a whole new "Scope<TypeParameter>" here. (This makes the "PushMarker()" + // and "PopMarker()" unnecessary, but they're included here for good style.) + var oldAllTypeParameters = resolver.allTypeParameters; + resolver.allTypeParameters = new Scope<TypeParameter>(resolver.Options); + resolver.allTypeParameters.PushMarker(); + + if (d is TopLevelDecl topLevelDecl) { + preTypeResolver.ResolveTypeParameters(topLevelDecl.TypeArgs, false, topLevelDecl); + } else { + var memberDecl = (MemberDecl)d; + preTypeResolver.ResolveTypeParameters(memberDecl.EnclosingClass.TypeArgs, false, memberDecl.EnclosingClass); + if (memberDecl is Method method) { + preTypeResolver.ResolveTypeParameters(method.TypeArgs, false, method); + } else if (memberDecl is Function function) { + preTypeResolver.ResolveTypeParameters(function.TypeArgs, false, function); + } + } + + preTypeResolver.ResolveDeclarationSignature(d); + + resolver.allTypeParameters.PopMarker(); + resolver.allTypeParameters = oldAllTypeParameters; + } + + static IEnumerable<Declaration> AllTopLevelOrMemberDeclarations(List<TopLevelDecl> declarations) { + foreach (var d in declarations) { + yield return d; + /* + if (d is ClassLikeDecl { NonNullTypeDecl: { } nonNullTypeDecl }) { + yield return nonNullTypeDecl; + } + */ + if (d is TopLevelDeclWithMembers cl) { + foreach (var member in cl.Members) { + yield return member; + } + } + } + } + + /// <summary> + /// Assumes that the type parameters in scope for "d" have been pushed. + /// </summary> + /// <param name="d"></param> + public void ResolveDeclarationSignature(Declaration d) { + Contract.Requires(d is TopLevelDecl or MemberDecl); + + if (!preTypeInferenceModuleState.StillNeedsPreTypeSignature.Contains(d)) { + // already processed + return; + } + + if (preTypeInferenceModuleState.InFirstPhase.Contains(d)) { + var cycle = Util.Comma(" -> ", preTypeInferenceModuleState.InFirstPhase, d => d.ToString()); + ReportError(d, $"Cyclic dependency among declarations: {d} -> {cycle}"); + } else { + preTypeInferenceModuleState.InFirstPhase.Push(d); + FillInPreTypesInSignature(d); + preTypeInferenceModuleState.InFirstPhase.Pop(); + } + + preTypeInferenceModuleState.StillNeedsPreTypeSignature.Remove(d); + } + + /// <summary> + /// Assumes the type parameters in scope for "declaration" have been pushed. + /// </summary> + public void FillInPreTypesInSignature(Declaration declaration) { + void ComputePreType(Formal formal) { + Contract.Assume(formal.PreType == null); // precondition + formal.PreType = Type2PreType(formal.Type); + } + + void ComputePreTypeField(Field field) { + Contract.Assume(field.PreType == null); // precondition + field.PreType = CreatePreTypeProxy("temporary proxy until after cyclicity tests have completed"); + field.PreType = Type2PreType(field.Type); + if (field is ConstantField cfield) { + var parent = (TopLevelDeclWithMembers)cfield.EnclosingClass; + Contract.Assert(currentClass == null); + currentClass = parent; + + ResolveConstRHS(cfield, true); + + Contract.Assert(currentClass == parent); + currentClass = null; + } + } + + void ComputePreTypeFunction(Function function) { + function.Formals.ForEach(ComputePreType); + if (function.Result != null) { + function.Result.PreType = Type2PreType(function.Result.Type); + } else if (function.ByMethodDecl != null) { + // The by-method out-parameter is not the same as the one given in the function declaration, since the + // function declaration didn't give one. + function.ByMethodDecl.Outs.ForEach(ComputePreType); + } + function.ResultPreType = Type2PreType(function.ResultType); + } + + void ComputePreTypeMethod(Method method) { + method.Ins.ForEach(ComputePreType); + method.Outs.ForEach(ComputePreType); + } + + if (declaration is SubsetTypeDecl std) { + std.Var.PreType = Type2PreType(std.Var.Type); + ResolveConstraintAndWitness(std, true); + } else if (declaration is NewtypeDecl nd) { + nd.BasePreType = Type2PreType(nd.BaseType); + if (nd.Var != null) { + Contract.Assert(object.ReferenceEquals(nd.BaseType, nd.Var.Type)); + nd.Var.PreType = nd.BasePreType; + } + ResolveConstraintAndWitness(nd, true); + } else if (declaration is IteratorDecl iter) { + // Note, iter.Ins are reused with the parameters of the iterator's automatically generated _ctor, and + // the iter.OutsFields are shared with the automatically generated fields of the iterator class. To avoid + // computing their pre-types twice, we omit their pre-type computations here and instead do them in + // the _ctor Method and for each Field of the iterator class. + iter.Outs.ForEach(ComputePreType); + } else if (declaration is DatatypeDecl dtd) { + foreach (var ctor in dtd.Ctors) { + ctor.Formals.ForEach(ComputePreType); + ComputePreTypeField(ctor.QueryField); + foreach (var dtor in ctor.Destructors) { + // The following "if" condition makes sure ComputePreTypeField is called just once (since a destructor + // can be shared among several constructors). + if (dtor.EnclosingCtors[0] == ctor) { + ComputePreTypeField(dtor); + } + } + } + } else if (declaration is TopLevelDeclWithMembers or ValuetypeDecl or TypeSynonymDecl or ModuleDecl) { + // nothing to do + } else if (declaration is Field field) { + ComputePreTypeField(field); + } else if (declaration is Function function) { + if (function.ResultType is SelfType) { + // This is a special case that, with the legacy type inference, handled the .Rotate{Left, Right} method of + // bitvector types. That's now handled in a different way, which does not use SelfType. + } else { + ComputePreTypeFunction(function); + if (function is ExtremePredicate extremePredicate) { + ComputePreTypeFunction(extremePredicate.PrefixPredicate); + } + } + } else if (declaration is Method method) { + ComputePreTypeMethod(method); + if (method is ExtremeLemma extremeLemma) { + ComputePreTypeMethod(extremeLemma.PrefixLemma); + } + } else { + Contract.Assert(false); // unexpected declaration + } + } + + public void ResolveDeclarationBody(Declaration d) { + Contract.Requires(d is TopLevelDecl or MemberDecl); + + resolver.allTypeParameters.PushMarker(); + + if (d is TopLevelDecl topLevelDecl) { + ResolveTypeParameters(topLevelDecl.TypeArgs, false, topLevelDecl); + ResolveTopLevelDeclaration(topLevelDecl); + } else { + var member = (MemberDecl)d; + var parent = (TopLevelDeclWithMembers)member.EnclosingClass; + ResolveTypeParameters(parent.TypeArgs, false, parent); + Contract.Assert(currentClass == null); + currentClass = parent; + ResolveMember(member); + Contract.Assert(currentClass == parent); + currentClass = null; + } + + resolver.allTypeParameters.PopMarker(); + } + + /// <summary> + /// Resolve declaration "d". + /// + /// This method assumes type parameters have been pushed. + /// </summary> + private void ResolveTopLevelDeclaration(TopLevelDecl d) { + if (d is not IteratorDecl) { + // Note, attributes of iterators are resolved by ResolveIterator, after registering any names in the iterator signature + ResolveAttributes(d, new ResolutionContext(new NoContext(d.EnclosingModuleDefinition), false), true); + } + + if (d is NewtypeDecl newtypeDecl) { + ResolveConstraintAndWitness(newtypeDecl, false); + } else if (d is SubsetTypeDecl subsetTypeDecl) { + ResolveConstraintAndWitness(subsetTypeDecl, false); + } else if (d is IteratorDecl iter) { + // Note, attributes of iterators are resolved by ResolveIterator, after registering any names in the iterator signature. + // The following method generates the iterator's members, which in turn are resolved below. + ResolveIterator(iter); + } else if (d is DatatypeDecl dt) { + // resolve any default parameters + foreach (var ctor in dt.Ctors) { + scope.PushMarker(); + scope.AllowInstance = false; + ctor.Formals.ForEach(p => ScopePushAndReport(p, "destructor", false)); + ResolveAttributes(ctor, new ResolutionContext(new NoContext(d.EnclosingModuleDefinition), false), true); + ResolveParameterDefaultValues(ctor.Formals, dt); + scope.PopMarker(); + } + } + } + + void ResolveTypeParameters(List<TypeParameter> tparams, bool emitErrors, TypeParameter.ParentType parent) { + Contract.Requires(tparams != null); + Contract.Requires(parent != null); + // push non-duplicated type parameter names + int index = 0; + foreach (TypeParameter tp in tparams) { + if (emitErrors) { + // we're seeing this TypeParameter for the first time + tp.Parent = parent; + tp.PositionalIndex = index; + } + var r = resolver.allTypeParameters.Push(tp.Name, tp); + if (emitErrors) { + if (r == Scope<TypeParameter>.PushResult.Duplicate) { + ReportError(tp, "Duplicate type-parameter name: {0}", tp.Name); + } else if (r == Scope<TypeParameter>.PushResult.Shadow) { + ReportWarning(tp.tok, "Shadowed type-parameter name: {0}", tp.Name); + } + } + } + } + + void ResolveAttributes(IAttributeBearingDeclaration attributeHost, ResolutionContext opts, bool solveConstraints) { + Contract.Requires(attributeHost != null); + Contract.Requires(opts != null); + + // order does not matter much for resolution, so resolve them in reverse order + foreach (var attr in attributeHost.Attributes.AsEnumerable()) { + if (attributeHost != null && attr is UserSuppliedAttributes usa) { +#if TODO + usa.Recognized = resolver.IsRecognizedAttribute(usa, attributeHost); // TODO: this could be done in a later resolution pass +#endif + } + if (attr.Args != null) { + attr.Args.ForEach(arg => ResolveExpression(arg, opts)); + if (solveConstraints) { + Constraints.SolveAllTypeConstraints($"attribute of {attributeHost.ToString()}"); + } + } + } + } + + void ResolveConstraintAndWitness(RedirectingTypeDecl dd, bool initialResolutionPass) { + Contract.Requires(dd != null); + Contract.Requires(dd.Constraint != null); + + if (dd.Var != null) { + if (initialResolutionPass == dd.Var.Type is TypeProxy) { + scope.PushMarker(); + ScopePushExpectSuccess(dd.Var, dd.WhatKind + " variable", false); + ResolveExpression(dd.Constraint, new ResolutionContext(new CodeContextWrapper(dd, true), false)); + ConstrainTypeExprBool(dd.Constraint, dd.WhatKind + " constraint must be of type bool (instead got {0})"); + scope.PopMarker(); + Constraints.SolveAllTypeConstraints($"{dd.WhatKind} '{dd.Name}' constraint"); + } + } + + if (!initialResolutionPass && dd.Witness != null) { + var codeContext = new CodeContextWrapper(dd, dd.WitnessKind == SubsetTypeDecl.WKind.Ghost); + ResolveExpression(dd.Witness, new ResolutionContext(codeContext, false)); + AddSubtypeConstraint(dd.Var.PreType, dd.Witness.PreType, dd.Witness.tok, "witness expression must have type '{0}' (got '{1}')"); + Constraints.SolveAllTypeConstraints($"{dd.WhatKind} '{dd.Name}' witness"); + } + } + + /// <summary> + /// Assumes the type parameters in scope for "cfield" have been pushed. + /// Assumes that "currentClass" has been set to the parent of "cfield". + /// </summary> + void ResolveConstRHS(ConstantField cfield, bool initialResolutionPass) { + if (cfield.Rhs != null && initialResolutionPass == cfield.Type is TypeProxy) { + var opts = new ResolutionContext(cfield, false); + ResolveExpression(cfield.Rhs, opts); + AddSubtypeConstraint(cfield.PreType, cfield.Rhs.PreType, cfield.Tok, "RHS (of type {1}) not assignable to LHS (of type {0})"); + Constraints.SolveAllTypeConstraints($"{cfield.WhatKind} '{cfield.Name}' constraint"); + } + } + + void ResolveParameterDefaultValues(List<Formal> formals, ICodeContext codeContext) { + Contract.Requires(formals != null); + Contract.Requires(codeContext != null); + + var dependencies = new Graph<IVariable>(); + var allowMoreRequiredParameters = true; + var allowNamelessParameters = true; + foreach (var formal in formals) { + var d = formal.DefaultValue; + if (d != null) { + allowMoreRequiredParameters = false; + ResolveExpression(d, new ResolutionContext(codeContext, codeContext is TwoStateFunction || codeContext is TwoStateLemma)); + AddSubtypeConstraint(Type2PreType(formal.Type), d.PreType, d.tok, "default-value expression (of type '{1}') is not assignable to formal (of type '{0}')"); + foreach (var v in ModuleResolver.FreeVariables(d)) { + dependencies.AddEdge(formal, v); + } + } else if (!allowMoreRequiredParameters) { + ReportError(formal.tok, "a required parameter must precede all optional parameters"); + } + if (!allowNamelessParameters && !formal.HasName) { + ReportError(formal.tok, "a nameless parameter must precede all nameonly parameters"); + } + if (formal.IsNameOnly) { + allowNamelessParameters = false; + } + } + Constraints.SolveAllTypeConstraints($"parameter default values of {codeContext.FullSanitizedName}"); + + foreach (var cycle in dependencies.AllCycles()) { + var cy = Util.Comma(" -> ", cycle, v => v.Name) + " -> " + cycle[0].Name; + ReportError(cycle[0].Tok, $"default-value expressions for parameters contain a cycle: {cy}"); + } + } + + /// <summary> + /// Resolve declaration "member", assuming that the member's pre-type signature has already been resolved. + /// + /// Type constraints are solved here. + /// + /// This method assumes type parameters of the enclosing type have been pushed. + /// Also assumes that "currentClass" has been set to the parent of "member". + /// </summary> + void ResolveMember(MemberDecl member) { + Contract.Requires(member != null); + Contract.Requires(currentClass != null); + + ResolveAttributes(member, new ResolutionContext(new NoContext(currentClass.EnclosingModuleDefinition), false), true); + + if (member is ConstantField cfield) { + ResolveConstRHS(cfield, false); + + } else if (member is Field) { + // nothing else to do + + } else if (member is Function f) { + var ec = ErrorCount; + resolver.allTypeParameters.PushMarker(); + ResolveTypeParameters(f.TypeArgs, false, f); + ResolveFunction(f); + resolver.allTypeParameters.PopMarker(); + + if (f is ExtremePredicate extremePredicate && extremePredicate.PrefixPredicate != null && ec == ErrorCount) { + var ff = extremePredicate.PrefixPredicate; + resolver.allTypeParameters.PushMarker(); + ResolveTypeParameters(ff.TypeArgs, false, ff); + ResolveFunction(ff); + resolver.allTypeParameters.PopMarker(); + } + + } else if (member is Method m) { + var ec = ErrorCount; + resolver.allTypeParameters.PushMarker(); + ResolveTypeParameters(m.TypeArgs, false, m); + ResolveMethod(m); + resolver.allTypeParameters.PopMarker(); + + if (m is ExtremeLemma em && em.PrefixLemma != null && ec == ErrorCount) { + var mm = em.PrefixLemma; + resolver.allTypeParameters.PushMarker(); + ResolveTypeParameters(mm.TypeArgs, false, mm); + ResolveMethod(mm); + resolver.allTypeParameters.PopMarker(); + } + + } else { + Contract.Assert(false); throw new cce.UnreachableException(); // unexpected member type + } + } + + /// <summary> + /// Assumes type parameters have already been pushed + /// </summary> + void ResolveIterator(IteratorDecl iter) { + Contract.Requires(iter != null); + Contract.Requires(currentClass != null); + Contract.Ensures(currentClass == null); + + var initialErrorCount = ErrorCount; + + // Add in-parameters to the scope, but don't care about any duplication errors, since they have already been reported + scope.PushMarker(); + scope.AllowInstance = false; // disallow 'this' from use, which means that the special fields and methods added are not accessible in the syntactically given spec + iter.Ins.ForEach(p => ScopePushAndReport(p, "in-parameter", false)); + ResolveParameterDefaultValues(iter.Ins, iter); + + // Start resolving specification... + // we start with the decreases clause, because the _decreases<n> fields were only given type proxies before; we'll know + // the types only after resolving the decreases clause (and it may be that some of resolution has already seen uses of + // these fields; so, with no further ado, here we go + Contract.Assert(iter.Decreases.Expressions.Count == iter.DecreasesFields.Count); + ResolveAttributes(iter.Decreases, new ResolutionContext(iter, false), false); + for (int i = 0; i < iter.Decreases.Expressions.Count; i++) { + var e = iter.Decreases.Expressions[i]; + ResolveExpression(e, new ResolutionContext(iter, false)); + // any type is fine, but associate this type with the corresponding _decreases<n> field + var d = iter.DecreasesFields[i]; + // If the following type constraint does not hold, then: Bummer, there was a use--and a bad use--of the field before, so this won't be the best of error messages + AddSubtypeConstraint(d.PreType, e.PreType, e.tok, "type of field '" + d.Name + "' is {1}, but has been constrained elsewhere to be of type {0}"); + } + foreach (FrameExpression fe in iter.Reads.Expressions) { + ResolveFrameExpression(fe, FrameExpressionUse.Reads, iter); + } + ResolveAttributes(iter.Modifies, new ResolutionContext(iter, false), false); + foreach (FrameExpression fe in iter.Modifies.Expressions) { + ResolveFrameExpression(fe, FrameExpressionUse.Modifies, iter); + } + foreach (AttributedExpression e in iter.Requires) { + ResolveAttributes(e, new ResolutionContext(iter, false), false); + ResolveExpression(e.E, new ResolutionContext(iter, false)); + ConstrainTypeExprBool(e.E, "Precondition must be a boolean (got {0})"); + } + + scope.PopMarker(); // for the in-parameters + + // We resolve the rest of the specification in an instance context. So mentions of the in- or yield-parameters + // get resolved as field dereferences (with an implicit "this") + scope.PushMarker(); + currentClass = iter; + Contract.Assert(scope.AllowInstance); + + foreach (AttributedExpression e in iter.YieldRequires) { + ResolveAttributes(e, new ResolutionContext(iter, false), false); + ResolveExpression(e.E, new ResolutionContext(iter, false)); + ConstrainTypeExprBool(e.E, "Yield precondition must be a boolean (got {0})"); + } + foreach (AttributedExpression e in iter.YieldEnsures) { + ResolveAttributes(e, new ResolutionContext(iter, true), false); + ResolveExpression(e.E, new ResolutionContext(iter, true)); + ConstrainTypeExprBool(e.E, "Yield postcondition must be a boolean (got {0})"); + } + foreach (AttributedExpression e in iter.Ensures) { + ResolveAttributes(e, new ResolutionContext(iter, true), false); + ResolveExpression(e.E, new ResolutionContext(iter, true)); + ConstrainTypeExprBool(e.E, "Postcondition must be a boolean (got {0})"); + } + Constraints.SolveAllTypeConstraints($"specification of iterator '{iter.Name}'"); + + ResolveAttributes(iter, new ResolutionContext(iter, false), true); + + var postSpecErrorCount = ErrorCount; + + // Resolve body + if (iter.Body != null) { + dominatingStatementLabels.PushMarker(); + foreach (var req in iter.Requires) { + if (req.Label != null) { + if (dominatingStatementLabels.Find(req.Label.Name) != null) { + ReportError(req.Label.Tok, "assert label shadows a dominating label"); + } else { + var rr = dominatingStatementLabels.Push(req.Label.Name, req.Label); + Contract.Assert(rr == Scope<Label>.PushResult.Success); // since we just checked for duplicates, we expect the Push to succeed + } + } + } + ResolveBlockStatement(iter.Body, ResolutionContext.FromCodeContext(iter)); + dominatingStatementLabels.PopMarker(); + Constraints.SolveAllTypeConstraints($"body of iterator '{iter.Name}'"); + } + + currentClass = null; + scope.PopMarker(); // pop off the AllowInstance setting + + if (postSpecErrorCount == initialErrorCount) { + iter.CreateIteratorMethodSpecs(resolver); + } + } + + /// <summary> + /// Assumes type parameters have already been pushed. + /// Also assumes that "currentClass" has been set to the parent of "f". + /// </summary> + void ResolveFunction(Function f) { + Contract.Requires(f != null); + + bool warnShadowingOption = resolver.Options.WarnShadowing; // save the original warnShadowing value + bool warnShadowing = false; + + scope.PushMarker(); + if (f.IsStatic) { + scope.AllowInstance = false; + } + + if (f.IsGhost) { + // TODO: the following could be done in a different resolver pass + foreach (TypeParameter p in f.TypeArgs) { + if (p.SupportsEquality) { + ReportWarning(p.tok, + $"type parameter {p.Name} of ghost {f.WhatKind} {f.Name} is declared (==), which is unnecessary because the {f.WhatKind} doesn't contain any compiled code"); + } + } + } + + foreach (Formal p in f.Formals) { + ScopePushAndReport(p, "parameter", false); + } + ResolveAttributes(f, new ResolutionContext(f, false), true); + // take care of the warnShadowing attribute + if (Attributes.ContainsBool(f.Attributes, "warnShadowing", ref warnShadowing)) { + resolver.Options.WarnShadowing = warnShadowing; // set the value according to the attribute + } + ResolveParameterDefaultValues(f.Formals, f); + foreach (AttributedExpression e in f.Req) { + ResolveAttributes(e, new ResolutionContext(f, f is TwoStateFunction), false); + Expression r = e.E; + ResolveExpression(r, new ResolutionContext(f, f is TwoStateFunction)); + ConstrainTypeExprBool(r, "Precondition must be a boolean (got {0})"); + } + foreach (FrameExpression fr in f.Reads) { + ResolveFrameExpression(fr, FrameExpressionUse.Reads, f); + } + foreach (AttributedExpression e in f.Ens) { + ResolveAttributes(e, new ResolutionContext(f, f is TwoStateFunction), false); + Expression r = e.E; + if (f.Result != null) { + scope.PushMarker(); + ScopePushAndReport(f.Result, "function result", false); // function return only visible in post-conditions + } + ResolveExpression(r, new ResolutionContext(f, f is TwoStateFunction) with { InFunctionPostcondition = true }); + ConstrainTypeExprBool(r, "Postcondition must be a boolean (got {0})"); + if (f.Result != null) { + scope.PopMarker(); + } + } + ResolveAttributes(f.Decreases, new ResolutionContext(f, f is TwoStateFunction), false); + foreach (Expression r in f.Decreases.Expressions) { + ResolveExpression(r, new ResolutionContext(f, f is TwoStateFunction)); + // any type is fine + } + Constraints.SolveAllTypeConstraints($"specification of {f.WhatKind} '{f.Name}'"); + + if (f.ByMethodBody != null) { + // The following conditions are assured by the parser and other callers of the Function constructor + Contract.Assert(f.Body != null); + Contract.Assert(!f.IsGhost); + } + if (f.Body != null) { + var prevErrorCount = ErrorCount; + ResolveExpression(f.Body, new ResolutionContext(f, f is TwoStateFunction)); + AddSubtypeConstraint(Type2PreType(f.ResultType), f.Body.PreType, f.tok, "Function body type mismatch (expected {0}, got {1})"); + Constraints.SolveAllTypeConstraints($"body of {f.WhatKind} '{f.Name}'"); + } + + scope.PopMarker(); + + if (f.ByMethodBody != null) { + var method = f.ByMethodDecl; + Contract.Assert(method != null); // this should have been filled in by now + ResolveMethod(method); + } + + resolver.Options.WarnShadowing = warnShadowingOption; // restore the original warnShadowing value } + /// <summary> + /// Assumes type parameters have already been pushed. + /// Also assumes that "currentClass" has been set to the parent of "m". + /// </summary> + void ResolveMethod(Method m) { + Contract.Requires(m != null); + + try { + currentMethod = m; + + bool warnShadowingOption = resolver.Options.WarnShadowing; // save the original warnShadowing value + bool warnShadowing = false; + // take care of the warnShadowing attribute + if (Attributes.ContainsBool(m.Attributes, "warnShadowing", ref warnShadowing)) { + resolver.Options.WarnShadowing = warnShadowing; // set the value according to the attribute + } + + if (m.IsGhost) { + foreach (TypeParameter p in m.TypeArgs) { + if (p.SupportsEquality) { + ReportWarning(p.tok, + $"type parameter {p.Name} of ghost {m.WhatKind} {m.Name} is declared (==), which is unnecessary because the {m.WhatKind} doesn't contain any compiled code"); + } + } + } + + // Add in-parameters to the scope, but don't care about any duplication errors, since they have already been reported + scope.PushMarker(); + if (m.IsStatic || m is Constructor) { + scope.AllowInstance = false; + } + foreach (Formal p in m.Ins) { + ScopePushAndReport(p, "in-parameter", false); + } + ResolveParameterDefaultValues(m.Ins, m); + + // Start resolving specification... + foreach (AttributedExpression e in m.Req) { + ResolveAttributes(e, new ResolutionContext(m, m is TwoStateLemma), false); + ResolveExpression(e.E, new ResolutionContext(m, m is TwoStateLemma)); + ConstrainTypeExprBool(e.E, "Precondition must be a boolean (got {0})"); + } + + ResolveAttributes(m.Mod, new ResolutionContext(m, false), false); + foreach (FrameExpression fe in m.Mod.Expressions) { + ResolveFrameExpression(fe, FrameExpressionUse.Modifies, m); + if (m.IsLemmaLike) { + ReportError(fe.tok, "{0}s are not allowed to have modifies clauses", m.WhatKind); + } else if (m.IsGhost) { +#if TODO + DisallowNonGhostFieldSpecifiers(fe); +#endif + } + } + ResolveAttributes(m.Decreases, new ResolutionContext(m, false), false); + foreach (Expression e in m.Decreases.Expressions) { + ResolveExpression(e, new ResolutionContext(m, m is TwoStateLemma)); + // any type is fine + } + + if (m is Constructor) { + scope.PopMarker(); + // start the scope again, but this time allowing instance + scope.PushMarker(); + foreach (Formal p in m.Ins) { + ScopePushAndReport(p, "in-parameter", false); + } + } + + // Add out-parameters to a new scope that will also include the outermost-level locals of the body + // Don't care about any duplication errors among the out-parameters, since they have already been reported + scope.PushMarker(); + if (m is ExtremeLemma && m.Outs.Count != 0) { + ReportError(m.Outs[0].tok, "{0}s are not allowed to have out-parameters", m.WhatKind); + } else { + foreach (Formal p in m.Outs) { + ScopePushAndReport(p, "out-parameter", false); + } + } + + // ... continue resolving specification + foreach (AttributedExpression e in m.Ens) { + ResolveAttributes(e, new ResolutionContext(m, true), false); + ResolveExpression(e.E, new ResolutionContext(m, true)); + ConstrainTypeExprBool(e.E, "Postcondition must be a boolean (got {0})"); + } + Constraints.SolveAllTypeConstraints($"specification of {m.WhatKind} '{m.Name}'"); + + // Resolve body + if (m.Body != null) { + var com = m as ExtremeLemma; + if (com != null && com.PrefixLemma != null) { + // The body may mentioned the implicitly declared parameter _k. Throw it into the + // scope before resolving the body. + var k = com.PrefixLemma.Ins[0]; + ScopePushExpectSuccess(k, "_k parameter", false); + } + + dominatingStatementLabels.PushMarker(); + foreach (var req in m.Req) { + if (req.Label != null) { + if (dominatingStatementLabels.Find(req.Label.Name) != null) { + ReportError(req.Label.Tok, "assert label shadows a dominating label"); + } else { + var rr = dominatingStatementLabels.Push(req.Label.Name, req.Label); + Contract.Assert(rr == Scope<Label>.PushResult.Success); // since we just checked for duplicates, we expect the Push to succeed + } + } + } + ResolveBlockStatement(m.Body, ResolutionContext.FromCodeContext(m)); + dominatingStatementLabels.PopMarker(); + Constraints.SolveAllTypeConstraints($"body of {m.WhatKind} '{m.Name}'"); + } + + // attributes are allowed to mention both in- and out-parameters (including the implicit _k, for greatest lemmas) + ResolveAttributes(m, new ResolutionContext(m, m is TwoStateLemma), true); + + resolver.Options.WarnShadowing = warnShadowingOption; // restore the original warnShadowing value + scope.PopMarker(); // for the out-parameters and outermost-level locals + scope.PopMarker(); // for the in-parameters + } + finally { + currentMethod = null; + } + } + + void ResolveFrameExpression(FrameExpression fe, FrameExpressionUse use, ICodeContext codeContext) { + Contract.Requires(fe != null); + Contract.Requires(codeContext != null); + ResolveExpression(fe.E, new ResolutionContext(codeContext, codeContext is TwoStateLemma || use == FrameExpressionUse.Unchanged)); + Constraints.AddGuardedConstraint(() => { + DPreType dp = fe.E.PreType.Normalize() as DPreType; + if (dp == null) { + // no information yet + return false; + } + // A FrameExpression is allowed to have one of the following types: + // C + // collection<C> + // where C is a reference type and collection is set, iset, seq, or multiset. + // In a reads clause, a FrameExpression is additionally allowed to have type + // ... ~> collection<C> + // A FrameExpression can also specify a field name using the syntax FE`fieldName, + // which is allowed if fieldName is a field of C. + var hasArrowType = false; + var hasCollectionType = false; + if (use == FrameExpressionUse.Reads && DPreType.IsArrowType(dp.Decl)) { + hasArrowType = true; + dp = dp.Arguments.Last().Normalize() as DPreType; + if (dp == null) { + // function's image type not yet known + return false; + } + } + if (dp.Decl.Name == "set" || dp.Decl.Name == "iset" || dp.Decl.Name == "seq" || dp.Decl.Name == "multiset") { + hasCollectionType = true; + var elementType = dp.Arguments[0].Normalize(); + dp = elementType as DPreType; + if (dp == null) { + // element type not yet known + Constraints.AddDefaultAdvice(elementType, Advice.Target.Object); + return false; + } + } + + if (!DPreType.IsReferenceTypeDecl(dp.Decl) || (hasArrowType && !hasCollectionType)) { + var expressionMustDenoteObject = "expression must denote an object"; + var collection = "a set/iset/multiset/seq of objects"; + var instead = "(instead got {0})"; + var errorMsgFormat = use switch { + FrameExpressionUse.Reads => + $"a reads-clause {expressionMustDenoteObject}, {collection}, or a function to {collection} {instead}", + FrameExpressionUse.Modifies => + $"a modifies-clause {expressionMustDenoteObject} or {collection} {instead}", + FrameExpressionUse.Unchanged => + $"an unchanged {expressionMustDenoteObject} or {collection} {instead}" + }; + ReportError(fe.E.tok, errorMsgFormat, fe.E.PreType); + } + + if (fe.FieldName != null) { + var (member, tentativeReceiverType) = FindMember(fe.E.tok, dp, fe.FieldName); + Contract.Assert((member == null) == (tentativeReceiverType == null)); // follows from contract of FindMember + if (member == null) { + // error has already been reported by FindMember + } else if (!(member is Field)) { + ReportError(fe.E, "member {0} in type {1} does not refer to a field", fe.FieldName, tentativeReceiverType.Decl.Name); + } else if (member is ConstantField) { + ReportError(fe.E, "expression is not allowed to refer to constant field {0}", fe.FieldName); + } else { + fe.Field = (Field)member; + } + } + + return true; + }); + } + + // ---------------------------------------- Utilities ---------------------------------------- + + public Dictionary<TypeParameter, PreType> BuildPreTypeArgumentSubstitute(Dictionary<TypeParameter, PreType> typeArgumentSubstitutions, DPreType/*?*/ receiverTypeBound = null) { + Contract.Requires(typeArgumentSubstitutions != null); + + var subst = new Dictionary<TypeParameter, PreType>(); + foreach (var entry in typeArgumentSubstitutions) { + subst.Add(entry.Key, entry.Value); + } + +#if SOON + if (SelfTypeSubstitution != null) { + foreach (var entry in SelfTypeSubstitution) { + subst.Add(entry.Key, entry.Value); + } + } +#endif + + if (receiverTypeBound?.Decl is TopLevelDeclWithMembers cl) { + foreach (var entry in cl.ParentFormalTypeParametersToActuals) { + var v = Type2PreType(entry.Value).Substitute(subst); + subst.Add(entry.Key, v); + } + } + + return subst; + } + + // ---------------------------------------- Migration sanity checks ---------------------------------------- + + public void SanityCheckOldAndNewInference(List<TopLevelDecl> declarations) { + var visitor = new PreTypeSanityChecker(this); + foreach (var decl in declarations) { + foreach (var attr in decl.Attributes.AsEnumerable()) { + visitor.Visit(attr.Args); + } + if (decl is RedirectingTypeDecl rtd) { + if (rtd.Constraint != null) { + visitor.Visit(rtd.Constraint); + } + if (rtd.Witness != null) { + visitor.Visit(rtd.Witness); + } + } else if (decl is IteratorDecl iter) { + visitor.Visit(iter); + } else if (decl is TopLevelDeclWithMembers md) { + foreach (var member in md.Members) { + if (member is ConstantField cfield && cfield.Rhs != null) { + visitor.Visit(cfield.Rhs); + } else if (member is Function f) { + visitor.Visit(f); + if (f is ExtremePredicate extremePredicate) { + visitor.Visit(extremePredicate.PrefixPredicate); + } + } else if (member is Method m) { + visitor.Visit(m); + if (m is ExtremeLemma extremeLemma) { + visitor.Visit(extremeLemma.PrefixLemma); + } + } + } + } + } + } + + class PreTypeSanityChecker : BottomUpVisitor { + private PreTypeResolver preTypeResolver; + + public PreTypeSanityChecker(PreTypeResolver preTypeResolver) { + this.preTypeResolver = preTypeResolver; + } + + protected override void VisitOneExpr(Expression expr) { + // compare expr.PreType and expr.Type + if (expr.PreType == null) { + preTypeResolver.ReportWarning(expr.tok, $"sanity check WARNING: no pre-type was computed"); + } else if (expr.Type == null) { + preTypeResolver.ReportError(expr.tok, $"SANITY CHECK FAILED: .PreType is '{expr.PreType}' but .Type is null"); + } else if (PreType.Same(expr.PreType, preTypeResolver.Type2PreType(expr.Type))) { + // all is cool + } else if (expr.PreType is UnusedPreType && expr.Type is TypeProxy) { + // this is expected + } else { + preTypeResolver.ReportError(expr.tok, $"SANITY CHECK FAILED: pre-type '{expr.PreType}' does not correspond to type '{expr.Type}'"); + } + } + } } } diff --git a/Source/DafnyCore/Resolver/PreType/PreTypeResolver.Match.cs b/Source/DafnyCore/Resolver/PreType/PreTypeResolver.Match.cs new file mode 100644 index 00000000000..f38fb69ae17 --- /dev/null +++ b/Source/DafnyCore/Resolver/PreType/PreTypeResolver.Match.cs @@ -0,0 +1,208 @@ +//----------------------------------------------------------------------------- +// +// Copyright by the contributors to the Dafny Project +// SPDX-License-Identifier: MIT +// +//----------------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.Linq; +using ResolutionContext = Microsoft.Dafny.ResolutionContext; + +namespace Microsoft.Dafny { + public partial class PreTypeResolver { + + void ResolveNestedMatchStmt(NestedMatchStmt stmt, ResolutionContext resolutionContext) { + ResolveExpression(stmt.Source, resolutionContext); + + foreach (var mc in stmt.Cases) { + ResolveAttributes(mc, resolutionContext, false); + + scope.PushMarker(); + ResolveExtendedPattern(stmt.Source.tok, mc.Pat, stmt.Source.PreType, false, resolutionContext); + + dominatingStatementLabels.PushMarker(); + mc.Body.ForEach(ss => ResolveStatementWithLabels(ss, resolutionContext)); + dominatingStatementLabels.PopMarker(); + + scope.PopMarker(); + } + } + + void ResolveNestedMatchExpr(NestedMatchExpr expr, ResolutionContext resolutionContext) { + ResolveExpression(expr.Source, resolutionContext); + + expr.PreType = CreatePreTypeProxy("result of match expression"); + foreach (var mc in expr.Cases) { + ResolveAttributes(mc, resolutionContext, false); + + scope.PushMarker(); + ResolveExtendedPattern(expr.Source.tok, mc.Pat, expr.Source.PreType, false, resolutionContext); + + ResolveExpression(mc.Body, resolutionContext); + AddSubtypeConstraint(expr.PreType, mc.Body.PreType, mc.Body.tok, + "type of case bodies do not agree (found {1}, previous types {0})"); + + scope.PopMarker(); + } + } + + /// <summary> + /// Try to make sure "preType" is not an unresolved proxy. If it is a proxy, then partially solve type constraints in hopes + /// of resolving it. If that still doesn't resolve it, then report and error and return "false". + /// Otherwise (that is, upon success), return "true". + /// </summary> + bool InsistOnKnowingPreType(IToken tok, PreType preType) { + if (preType.Normalize() is PreTypeProxy) { + Constraints.PartiallySolveTypeConstraints(null, true); + + if (preType.Normalize() is PreTypeProxy) { + ReportError(tok, "Could not resolve the type of the source of the match expression. Please provide additional typing annotations."); + return false; + } + } + return true; // success: preType.Normalize() is a DPreType + } + + /// <summary> + /// Resolve "pattern" and push onto "scope" all its bound variables. + /// </summary> + public void ResolveExtendedPattern(IToken sourceExprToken, ExtendedPattern pattern, PreType preType, bool inDisjunctivePattern, ResolutionContext resolutionContext) { + if (pattern is DisjunctivePattern dp) { + foreach (var alt in dp.Alternatives) { + ResolveExtendedPattern(sourceExprToken, alt, preType, true, resolutionContext); + } + return; + } + + if (pattern is LitPattern litPattern) { + var lit = litPattern.OptimisticallyDesugaredLit; + ResolveExpression(lit, resolutionContext); + AddSubtypeConstraint(preType, lit.PreType, litPattern.tok, + "literal pattern (of type {1}) cannot be used with source type {0}"); + return; + } + + var idPattern = (IdPattern)pattern; + if (idPattern.Type is not TypeProxy) { + Contract.Assert(idPattern.Arguments == null); // the parser ensures this condition (the ID cannot be followed by both "(...)" and ": ...") + resolver.ResolveType(idPattern.Tok, idPattern.Type, resolutionContext, ResolveTypeOptionEnum.InferTypeProxies, null); + // When a type is supplied, the ID is understood to be a bound variable. + ResolveParameterlessIdPattern(idPattern, preType, inDisjunctivePattern, resolutionContext); + return; + } + + // Note: If the language were to (be extended to) allow qualified names in patterns, then + // that qualified name should be resolved here, which also provides its pre-type. Then, that + // pre-type should be checked to be assignable to "preType". All of this can be done even if + // "preType" is a proxy. + // Maybe the language should change to work this way even for non-qualified names. But as it + // currently stands, "preType" is needed to look up the given ID. + // (End of Note.) + + if (TryResolvingAsConst(idPattern, preType, false, resolutionContext)) { + // the ID is a const with a LiteralExpr RHS, so pick it + return; + } + + // Use "preType" as a guide to looking up the given ID. This requires knowing what "preType" is. + if (!InsistOnKnowingPreType(sourceExprToken, preType)) { + return; + } + var dpreType = (DPreType)preType.Normalize(); + + if (dpreType.Decl is DatatypeDecl dtd && dtd.ConstructorsByName.TryGetValue(idPattern.Id, out var ctor)) { + // the given ID is a datatype constructor + idPattern.Ctor = ctor; + } else if (idPattern.Arguments == null) { + // not a datatype constructor, so either a named constant or a bound variable + ResolveParameterlessIdPattern(idPattern, preType, inDisjunctivePattern, resolutionContext); + return; + } else { + // this is an error; if tuples are involved, specialize the error message + if (idPattern.Id == SystemModuleManager.TupleTypeCtorName(1)) { + ReportError(idPattern.Tok, "parentheses are not allowed around a pattern"); + } else if (idPattern.Id.StartsWith(SystemModuleManager.TupleTypeCtorNamePrefix)) { + ReportError(pattern.Tok, $"tuple type does not match type '{preType}'"); + } else { + ReportError(idPattern.Tok, $"type '{preType}' does not contain a datatype constructor '{idPattern.Id}'"); + } + return; + } + + if (idPattern.Arguments == null) { + if (ctor.Formals.Count == 0) { + // nullary constructor without () -- so convert it to a constructor + idPattern.MakeAConstructor(); + } else { + ReportError(idPattern.Tok, $"constructor '{ctor.Name}' of arity {ctor.Formals.Count} is applied without any arguments"); + return; + } + } + if (idPattern.Arguments.Count != ctor.Formals.Count) { + ReportError(idPattern.Tok, $"constructor '{ctor.Name}' of arity {ctor.Formals.Count} is applied to {idPattern.Arguments.Count} argument(s)"); + return; + } + + var subst = PreType.PreTypeSubstMap(dtd.TypeArgs, dpreType.Arguments); + for (var i = 0; i < idPattern.Arguments.Count; i++) { + var argumentPreType = ctor.Formals[i].PreType.Substitute(subst); + ResolveExtendedPattern(sourceExprToken, idPattern.Arguments[i], argumentPreType, inDisjunctivePattern, resolutionContext); + } + } + + /// <summary> + /// Tries to resolve "idPattern" as a symbolic constant with a LiteralExpr RHS. + /// + /// Return "true" iff "idPattern" is a symbolic constant with a RHS (regardless of what that RHS is). + /// + /// If there is such a RHS and that RHS is a LiteralExpr, then + /// * record the RHS literal as "idPattern.ResolvedLit", and + /// * constrain its type to be assignable to "preType". + /// If there is such a RHS, but that RHS is not a LiteralExpr, then + /// * report an error, if "reportErrors". + /// </summary> + private bool TryResolvingAsConst(IdPattern idPattern, PreType preType, bool reportErrors, ResolutionContext resolutionContext) { + var e = new NameSegment(idPattern.Tok, idPattern.Id, null); + ResolveNameSegment(e, true, null, resolutionContext, false, false); + if (e.ResolvedExpression is MemberSelectExpr { Member: ConstantField { IsStatic: true, Rhs: { } rhs } }) { + if (rhs is LiteralExpr lit) { + // the ID refers to a const whose RHS is a literal + idPattern.ResolvedLit = lit; + AddSubtypeConstraint(preType, lit.PreType, idPattern.Tok, "literal pattern (of type {1}) cannot be used with source type {0}"); + } else if (reportErrors) { + ReportError(idPattern.Tok, $"{idPattern.Id} is not initialized as a constant literal"); + } + return true; + } + return false; + } + + private void ResolveParameterlessIdPattern(IdPattern idPattern, PreType preType, bool inDisjunctivePattern, ResolutionContext resolutionContext) { + Contract.Requires(idPattern.Arguments == null); + + if (idPattern.Type is TypeProxy) { + if (TryResolvingAsConst(idPattern, preType, true, resolutionContext)) { + return; + } + } + + // no other options remain; the ID denotes a new bound variable + + if (inDisjunctivePattern) { + ReportError(idPattern.Tok, "Disjunctive patterns may not bind variables"); + } + + idPattern.BoundVar = new BoundVar(idPattern.Tok, idPattern.Id, idPattern.Type) { + PreType = Type2PreType(idPattern.Type, "case pattern ID") + }; + AddSubtypeConstraint(preType, idPattern.BoundVar.PreType, idPattern.Tok, + "pattern (of type {1}) cannot be used with source type {0}"); + if (!idPattern.IsWildcardPattern) { + resolver.ScopePushAndReport(scope, idPattern.BoundVar, "parameter"); + } + } + } +} diff --git a/Source/DafnyCore/Resolver/PreType/PreTypeToType.cs b/Source/DafnyCore/Resolver/PreType/PreTypeToType.cs index 87e16308db8..0f651fdafcb 100644 --- a/Source/DafnyCore/Resolver/PreType/PreTypeToType.cs +++ b/Source/DafnyCore/Resolver/PreType/PreTypeToType.cs @@ -7,7 +7,7 @@ using System.Collections.Generic; using System.Diagnostics.Contracts; -using Microsoft.Boogie; +using System.Linq; namespace Microsoft.Dafny; @@ -27,8 +27,12 @@ public PreTypeToTypeVisitor() { } public static Type PreType2Type(PreType preType) { + return PreType2Type(preType, true); + } + + public static Type PreType2Type(PreType preType, bool usePrintablePreType) { var pt = (DPreType)preType.Normalize(); // all pre-types should have been filled in and resolved to a non-proxy - if (pt.PrintablePreType != null) { + if (usePrintablePreType && pt.PrintablePreType != null) { pt = pt.PrintablePreType; } switch (pt.Decl.Name) { @@ -58,27 +62,51 @@ public static Type PreType2Type(PreType preType) { break; } var arguments = pt.Arguments.ConvertAll(PreType2Type); - if (pt.Decl is ValuetypeDecl valuetypeDecl) { - return valuetypeDecl.CreateType(arguments); - } else if (pt.Decl is ArrowTypeDecl arrowTypeDecl) { + if (pt.Decl is ArrowTypeDecl arrowTypeDecl) { return new ArrowType(pt.Decl.tok, arrowTypeDecl, arguments); + } else if (pt.Decl is ValuetypeDecl valuetypeDecl) { + return valuetypeDecl.CreateType(arguments); + } else if (pt.Decl is ClassLikeDecl { IsReferenceTypeDecl: true }) { + return new UserDefinedType(pt.Decl.tok, pt.Decl.Name + "?", pt.Decl, arguments); } else { return new UserDefinedType(pt.Decl.tok, pt.Decl.Name, pt.Decl, arguments); } } - protected override void VisitOneDeclaration(TopLevelDecl decl) { - if (decl is NewtypeDecl newtypeDecl) { - UpdateIfOmitted(newtypeDecl.BaseType, newtypeDecl.BasePreType); - } else if (decl is SubsetTypeDecl subsetTypeDecl) { - UpdateIfOmitted(subsetTypeDecl.Var.Type, subsetTypeDecl.Var.PreType); + public void VisitConstantsAndRedirectingTypes(List<TopLevelDecl> declarations) { + foreach (var decl in declarations) { + if (decl is NewtypeDecl newtypeDecl) { + UpdateIfOmitted(newtypeDecl.BaseType, newtypeDecl.BasePreType); + } else if (decl is SubsetTypeDecl subsetTypeDecl) { + UpdateIfOmitted(subsetTypeDecl.Var.Type, subsetTypeDecl.Var.PreType); + } + if (decl is TopLevelDeclWithMembers topLevelDeclWithMembers) { + foreach (var member in topLevelDeclWithMembers.Members.Where(member => member is ConstantField)) { + var constField = (ConstantField)member; + // The type of the const might have been omitted in the program text and then inferred + UpdateIfOmitted(constField.Type, constField.PreType); + } + } } - base.VisitOneDeclaration(decl); } private void UpdateIfOmitted(Type type, PreType preType) { + var preTypeConverted = PreType2Type(preType, false); + UpdateIfOmitted(type, preTypeConverted); + } + + private void UpdateIfOmitted(Type type, Type preTypeConverted) { if (type is TypeProxy { T: null } typeProxy) { - typeProxy.T = PreType2Type(preType); + typeProxy.T = preTypeConverted; + } else { + type = type.NormalizeExpand(); + // TODO: "type" should also be moved up to the parent type that corresponds to "preType.Decl" + var preTypeConvertedExpanded = preTypeConverted.NormalizeExpand(); + Contract.Assert((type as UserDefinedType)?.ResolvedClass == (preTypeConvertedExpanded as UserDefinedType)?.ResolvedClass); + Contract.Assert(type.TypeArgs.Count == preTypeConvertedExpanded.TypeArgs.Count); + for (var i = 0; i < type.TypeArgs.Count; i++) { + UpdateIfOmitted(type.TypeArgs[i], preTypeConverted.TypeArgs[i]); + } } } @@ -88,12 +116,6 @@ private void UpdateTypeOfVariables(IEnumerable<IVariable> variables) { } } - public override void VisitField(Field field) { - // The type of the const might have been omitted in the program text and then inferred - UpdateIfOmitted(field.Type, field.PreType); - base.VisitField(field); - } - protected override void PostVisitOneExpression(Expression expr, IASTVisitorContext context) { if (expr is FunctionCallExpr functionCallExpr) { functionCallExpr.TypeApplication_AtEnclosingClass = functionCallExpr.PreTypeApplication_AtEnclosingClass.ConvertAll(PreType2Type); @@ -115,6 +137,8 @@ protected override void PostVisitOneExpression(Expression expr, IASTVisitorConte datatypeValue.InferredTypeArgs.Add(PreType2Type(preTypeArgument)); } } + } else if (expr is ConversionExpr conversionExpr) { + UpdateIfOmitted(conversionExpr.ToType, conversionExpr.PreType); } if (expr.PreType is UnusedPreType) { @@ -148,6 +172,15 @@ protected override void PostVisitOneStatement(Statement stmt, IASTVisitorContext VisitPattern(varDeclPattern.LHS, context); } else if (stmt is AssignStmt { Rhs: TypeRhs tRhs }) { tRhs.Type = PreType2Type(tRhs.PreType); + if (tRhs.ArrayDimensions != null) { + // In this case, we expect tRhs.PreType to be an array type + var arrayPreType = (DPreType)tRhs.PreType.Normalize(); + Contract.Assert(arrayPreType.Decl is ArrayClassDecl); + Contract.Assert(arrayPreType.Arguments.Count == 1); + UpdateIfOmitted(tRhs.EType, arrayPreType.Arguments[0]); + } else { + UpdateIfOmitted(tRhs.EType, tRhs.PreType); + } } else if (stmt is AssignSuchThatStmt assignSuchThatStmt) { foreach (var lhs in assignSuchThatStmt.Lhss) { VisitExpression(lhs, context); @@ -165,6 +198,8 @@ protected override void PostVisitOneStatement(Statement stmt, IASTVisitorContext PostVisitOneExpression(step, context); } PostVisitOneExpression(calcStmt.Result, context); + } else if (stmt is ForLoopStmt forLoopStmt) { + UpdateIfOmitted(forLoopStmt.LoopIndex.Type, forLoopStmt.LoopIndex.PreType); } else if (stmt is ForallStmt forallStmt) { UpdateTypeOfVariables(forallStmt.BoundVars); } @@ -177,4 +212,26 @@ protected override void PostVisitOneStatement(Statement stmt, IASTVisitorContext } } } + + protected override void VisitExtendedPattern(ExtendedPattern pattern, IASTVisitorContext context) { + switch (pattern) { + case DisjunctivePattern disjunctivePattern: + break; + case LitPattern litPattern: + PostVisitOneExpression(litPattern.OptimisticallyDesugaredLit, context); + break; + case IdPattern idPattern: + if (idPattern.BoundVar != null) { + UpdateIfOmitted(idPattern.BoundVar.Type, idPattern.BoundVar.PreType); + } + if (idPattern.ResolvedLit != null) { + PostVisitOneExpression(idPattern.ResolvedLit, context); + } + break; + default: + Contract.Assert(false); // unexpected case + break; + } + base.VisitExtendedPattern(pattern, context); + } } diff --git a/Source/DafnyCore/Resolver/ProgramResolver.cs b/Source/DafnyCore/Resolver/ProgramResolver.cs index 0847e5299b1..eebc6949b4b 100644 --- a/Source/DafnyCore/Resolver/ProgramResolver.cs +++ b/Source/DafnyCore/Resolver/ProgramResolver.cs @@ -81,6 +81,10 @@ public virtual void Resolve(CancellationToken cancellationToken) { } } + public void AddSystemClass(TopLevelDeclWithMembers topLevelDeclWithMembers, Dictionary<string, MemberDecl> memberDictionary) { + classMembers[topLevelDeclWithMembers] = memberDictionary; + } + private void ProcessDeclarationResolutionResult(Dictionary<ModuleDecl, Action<ModuleDecl>> moduleDeclarationPointers, ModuleDecl decl, ModuleResolutionResult moduleResolutionResult) { moduleDeclarationPointers[decl](moduleResolutionResult.ResolvedDeclaration); @@ -137,6 +141,12 @@ protected virtual Dictionary<TopLevelDeclWithMembers, Dictionary<string, MemberD systemModuleResolver.RevealAllInScope(SystemModuleManager.SystemModule.TopLevelDecls, SystemModuleManager.systemNameInfo.VisibilityScope); SystemModuleManager.ResolveValueTypeDecls(this); + if (Options.Get(CommonOptionBag.TypeSystemRefresh)) { + PreTypeResolver.ResolveDeclarations( + SystemModuleManager.SystemModule.TopLevelDecls.Where(d => d is not ClassDecl).ToList(), + systemModuleResolver, true); + } + // The SystemModule is constructed with all its members already being resolved. Except for // the non-null type corresponding to class types. They are resolved here: var systemModuleClassesWithNonNullTypes = diff --git a/Test/dafny0/Datatypes.dfy b/Test/dafny0/Datatypes.dfy index 748827ffabf..ab30b28d7d0 100644 --- a/Test/dafny0/Datatypes.dfy +++ b/Test/dafny0/Datatypes.dfy @@ -1,4 +1,4 @@ -// RUN: %exits-with 4 %dafny /compile:0 /deprecation:0 /print:"%t.print" /dprint:"%t.dprint" "%s" > "%t" +// RUN: %exits-with 4 %dafny /compile:0 /print:"%t.print" /dprint:"%t.dprint" "%s" > "%t" // RUN: %diff "%s.expect" "%t" datatype List<T> = Nil | Cons(T, List<T>) @@ -125,7 +125,7 @@ class NestedMatchExpr { } } method TestNesting1(a: List<NestedMatchExpr>) - ensures Cadr(a, this) == CadrAlt(a, this); + ensures Cadr(a, this) == CadrAlt(a, this) { match (a) { case Nil => @@ -174,7 +174,7 @@ method Destructors2(d: XList) { } ghost method Lemma_AllCases(d: XList) - ensures d.XNil? || d.XCons?; + ensures d.XNil? || d.XCons? { match (d) { case XNil => @@ -183,7 +183,7 @@ ghost method Lemma_AllCases(d: XList) } method InjectivityTests(d: XList) - requires d != XNil; + requires d != XNil { match (d) { case XCons(a,b) => @@ -198,7 +198,7 @@ method InjectivityTests(d: XList) } method MatchingDestructor(d: XList) returns (r: XList) - ensures r.Car == 5; // error: specification is not well-formed (since r might not be an XCons) + ensures r.Car == 5 // error: specification is not well-formed (since r might not be an XCons) { if (*) { var x0 := d.Car; // error: d might not be an XCons @@ -229,7 +229,7 @@ method Rotate1(t: TripleAndMore) returns (u: TripleAndMore) // ------------- method FwdBug(f: Fwd, initialized: bool) - requires !f.FwdCons?; + requires !f.FwdCons? { match (f) { case FwdNil => @@ -241,7 +241,7 @@ method FwdBug(f: Fwd, initialized: bool) } ghost function FwdBugFunction(f: Fwd): bool - requires !f.FwdCons?; + requires !f.FwdCons? { match f case FwdNil => true @@ -264,7 +264,7 @@ method TestAllCases_Inside(f: Fwd) } class ContainsFwd { - var fwd: Fwd; + var fwd: Fwd method TestCases() { assert fwd.FwdNil? || fwd.FwdCons?; @@ -292,7 +292,7 @@ module MatchExpressionsInArbitraryPositions { datatype AList<T> = ANil | ACons(head: T, tail: AList) | Appendix(b: bool) method M(xs: AList<int>) returns (y: int) - ensures 0 <= y; + ensures 0 <= y { if * { y := match xs // error: missing case Appendix diff --git a/Test/dafny0/ForbidNondeterminismCompile.dfy.expect b/Test/dafny0/ForbidNondeterminismCompile.dfy.expect index 5a39a23a39d..8fa5615a03a 100644 --- a/Test/dafny0/ForbidNondeterminismCompile.dfy.expect +++ b/Test/dafny0/ForbidNondeterminismCompile.dfy.expect @@ -1,4 +1,4 @@ -ForbidNondeterminismCompile.dfy(52,2): Warning: the modify statement with a block statement is deprecated +ForbidNondeterminismCompile.dfy(51,11): Warning: the modify statement with a block statement is deprecated Dafny program verifier finished with 6 verified, 0 errors ForbidNondeterminismCompile.dfy(17,7): Error: nondeterministic assignment forbidden by the --enforce-determinism option diff --git a/Test/dafny0/GhostAllocations-Resolution.dfy.expect b/Test/dafny0/GhostAllocations-Resolution.dfy.expect index cc4c5b3e5f6..cf476f9a6da 100644 --- a/Test/dafny0/GhostAllocations-Resolution.dfy.expect +++ b/Test/dafny0/GhostAllocations-Resolution.dfy.expect @@ -1,8 +1,8 @@ -GhostAllocations-Resolution.dfy(408,4): Warning: the modify statement with a block statement is deprecated -GhostAllocations-Resolution.dfy(432,6): Warning: the modify statement with a block statement is deprecated -GhostAllocations-Resolution.dfy(456,4): Warning: the modify statement with a block statement is deprecated -GhostAllocations-Resolution.dfy(501,6): Warning: the modify statement with a block statement is deprecated -GhostAllocations-Resolution.dfy(537,10): Warning: the modify statement with a block statement is deprecated +GhostAllocations-Resolution.dfy(407,13): Warning: the modify statement with a block statement is deprecated +GhostAllocations-Resolution.dfy(431,15): Warning: the modify statement with a block statement is deprecated +GhostAllocations-Resolution.dfy(455,13): Warning: the modify statement with a block statement is deprecated +GhostAllocations-Resolution.dfy(500,15): Warning: the modify statement with a block statement is deprecated +GhostAllocations-Resolution.dfy(536,19): Warning: the modify statement with a block statement is deprecated GhostAllocations-Resolution.dfy(17,11): Error: ghost variables such as g are allowed only in specification contexts. g was inferred to be ghost based on its declaration or initialization. GhostAllocations-Resolution.dfy(39,11): Error: ghost variables such as g are allowed only in specification contexts. g was inferred to be ghost based on its declaration or initialization. GhostAllocations-Resolution.dfy(47,22): Error: ghost variables such as n' are allowed only in specification contexts. n' was inferred to be ghost based on its declaration or initialization. diff --git a/Test/dafny0/GhostAllocations.dfy.expect b/Test/dafny0/GhostAllocations.dfy.expect index dfd0a078e0a..0b63665eb29 100644 --- a/Test/dafny0/GhostAllocations.dfy.expect +++ b/Test/dafny0/GhostAllocations.dfy.expect @@ -1,5 +1,5 @@ -GhostAllocations.dfy(91,2): Warning: the modify statement with a block statement is deprecated -GhostAllocations.dfy(103,2): Warning: the modify statement with a block statement is deprecated +GhostAllocations.dfy(88,11): Warning: the modify statement with a block statement is deprecated +GhostAllocations.dfy(99,13): Warning: the modify statement with a block statement is deprecated GhostAllocations.dfy(28,11): Error: assertion might not hold GhostAllocations.dfy(31,11): Error: assertion might not hold GhostAllocations.dfy(63,9): Error: assertion might not hold diff --git a/Test/dafny0/IteratorResolution.dfy b/Test/dafny0/IteratorResolution.dfy index 9ad58d08bb3..c13e60c392a 100644 --- a/Test/dafny0/IteratorResolution.dfy +++ b/Test/dafny0/IteratorResolution.dfy @@ -81,8 +81,6 @@ module Mx { var x: int := h1.t; // error: h1 would have to be a GenericIteratorResult<int> } - var h2 := new GenericIteratorResult; // error: constructor is not mentioned - var h3 := new GenericIterator(30); // see two lines down if h3.t == h3.u { assert !h3.t; // error: type mismatch (here or two lines ago) @@ -99,7 +97,9 @@ module Mx { iterator GenericIteratorResult<T(0)>() yields (t: T) { - while (*) { yield; } + while * { + yield; + } } class AnotherClient { @@ -340,3 +340,29 @@ module YieldParameterInitialization { iterator F() yields (ghost y: CompileAutoInit) { } } + +// ---------- more constructor tests ------------------------------- + +module MxConstructors { + method GenericTester() + { + var a: GenericIteratorResult<real> := new GenericIteratorResult; // error: constructor is not mentioned + var b: GenericIteratorResult<real> := new GenericIteratorResult(); + var c: GenericIterator<int> := new GenericIterator; // error: constructor is not mentioned + var d: GenericIterator<int> := new GenericIterator(30); + } + + iterator GenericIterator<T(0)>(t: T) yields (u: T) + { + while true { + yield t; + } + } + + iterator GenericIteratorResult<T(0)>() yields (t: T) + { + while * { + yield; + } + } +} diff --git a/Test/dafny0/IteratorResolution.dfy.expect b/Test/dafny0/IteratorResolution.dfy.expect index 9c62a14e848..985ba4bbf12 100644 --- a/Test/dafny0/IteratorResolution.dfy.expect +++ b/Test/dafny0/IteratorResolution.dfy.expect @@ -1,9 +1,8 @@ IteratorResolution.dfy(22,9): Error: LHS of assignment must denote a mutable field IteratorResolution.dfy(24,9): Error: LHS of assignment must denote a mutable field IteratorResolution.dfy(64,9): Error: LHS of assignment must denote a mutable field -IteratorResolution.dfy(84,13): Error: when allocating an object of type 'GenericIteratorResult', one of its constructor methods must be called IteratorResolution.dfy(69,18): Error: arguments must have comparable types (got _T0 and int) -IteratorResolution.dfy(86,16): Error: incorrect argument type for constructor in-parameter 't' (expected bool, found int) +IteratorResolution.dfy(84,16): Error: incorrect argument type for constructor in-parameter 't' (expected bool, found int) IteratorResolution.dfy(81,19): Error: RHS (of type bool) not assignable to LHS (of type int) IteratorResolution.dfy(129,11): Error: unresolved identifier: _decreases3 IteratorResolution.dfy(131,4): Error: LHS of assignment must denote a mutable field @@ -49,4 +48,6 @@ IteratorResolution.dfy(298,21): Error: type parameter (_T0) passed to type Iter IteratorResolution.dfy(325,23): Error: type of yield-parameter must support auto-initialization (got 'MaybeEmpty') IteratorResolution.dfy(328,23): Error: type of yield-parameter must support auto-initialization (got 'GhostAutoInit') IteratorResolution.dfy(334,29): Error: type of yield-parameter must support auto-initialization (got 'MaybeEmpty') -51 resolution/type errors detected in IteratorResolution.dfy +IteratorResolution.dfy(349,39): Error: when allocating an object of type 'GenericIteratorResult', one of its constructor methods must be called +IteratorResolution.dfy(351,32): Error: when allocating an object of type 'GenericIterator', one of its constructor methods must be called +52 resolution/type errors detected in IteratorResolution.dfy diff --git a/Test/dafny0/ModifyStmt.dfy.expect b/Test/dafny0/ModifyStmt.dfy.expect index 859de01e1e4..b839ba6754f 100644 --- a/Test/dafny0/ModifyStmt.dfy.expect +++ b/Test/dafny0/ModifyStmt.dfy.expect @@ -1,11 +1,11 @@ -ModifyStmt.dfy(135,4): Warning: the modify statement with a block statement is deprecated -ModifyStmt.dfy(143,4): Warning: the modify statement with a block statement is deprecated -ModifyStmt.dfy(150,4): Warning: the modify statement with a block statement is deprecated -ModifyStmt.dfy(162,10): Warning: the modify statement with a block statement is deprecated -ModifyStmt.dfy(163,8): Warning: the modify statement with a block statement is deprecated -ModifyStmt.dfy(164,6): Warning: the modify statement with a block statement is deprecated -ModifyStmt.dfy(165,4): Warning: the modify statement with a block statement is deprecated -ModifyStmt.dfy(180,4): Warning: the modify statement with a block statement is deprecated +ModifyStmt.dfy(133,14): Warning: the modify statement with a block statement is deprecated +ModifyStmt.dfy(140,14): Warning: the modify statement with a block statement is deprecated +ModifyStmt.dfy(148,16): Warning: the modify statement with a block statement is deprecated +ModifyStmt.dfy(160,20): Warning: the modify statement with a block statement is deprecated +ModifyStmt.dfy(158,17): Warning: the modify statement with a block statement is deprecated +ModifyStmt.dfy(157,21): Warning: the modify statement with a block statement is deprecated +ModifyStmt.dfy(155,24): Warning: the modify statement with a block statement is deprecated +ModifyStmt.dfy(178,16): Warning: the modify statement with a block statement is deprecated ModifyStmt.dfy(27,13): Error: assertion might not hold ModifyStmt.dfy(42,4): Error: modify statement might violate context's modifies clause ModifyStmt.dfy(48,4): Error: modify statement might violate context's modifies clause diff --git a/Test/dafny0/ModuleExport.dfy b/Test/dafny0/ModuleExport.dfy index 89f995cf64f..4799d81f669 100644 --- a/Test/dafny0/ModuleExport.dfy +++ b/Test/dafny0/ModuleExport.dfy @@ -115,6 +115,17 @@ module J { } } module Client { + import X + method M(c: X.C, c0: X.C?, d: X.D, d0: X.D?) { // all of these types are known + if c0 == null || d0 == null { // fine to compare c0 and d0 with null + } + } + method P() { + var c: X.C; + c := new X.C.Init(); // error: Init is not visible + } + } + module Client' { import X method M(c: X.C, c0: X.C?, d: X.D, d0: X.D?) { // all of these types are known if c0 == null || d0 == null { // fine to compare c0 and d0 with null @@ -123,7 +134,6 @@ module J { method P() { var c: X.C; c := new X.C; // error: must call a constructor - c := new X.C.Init(); // error: alas, no constructor is visible var d := new X.D; // error: even though D has no constructor, the absence of imported constructor does not let us conclude there aren't any } } diff --git a/Test/dafny0/ModuleExport.dfy.expect b/Test/dafny0/ModuleExport.dfy.expect index f026525ea20..1f12667a89f 100644 --- a/Test/dafny0/ModuleExport.dfy.expect +++ b/Test/dafny0/ModuleExport.dfy.expect @@ -9,15 +9,14 @@ ModuleExport.dfy(66,2): Warning: this branch is redundant ModuleExport.dfy(73,19): Error: Public2 must be an export of F to be extended ModuleExport.dfy(74,34): Error: 'g2' must be a member of 'F' to be exported ModuleExport.dfy(100,9): Error: no default export set declared in module: G -ModuleExport.dfy(125,8): Error: when allocating an object of type 'C', one of its constructor methods must be called -ModuleExport.dfy(126,17): Error: member 'Init' has not been imported in this scope and cannot be accessed here -ModuleExport.dfy(126,8): Error: when allocating an object of type 'C', one of its constructor methods must be called -ModuleExport.dfy(127,12): Error: when allocating an object of imported type 'D', one of its constructor methods must be called -ModuleExport.dfy(224,11): Error: Type or type parameter is not declared in this scope: X (did you forget to qualify a name or declare a module import 'opened'?) (note that names in outer modules are not visible in contained modules) -ModuleExport.dfy(250,9): Error: duplicate name of top-level declaration: X -ModuleExport.dfy(259,13): Error: no default export set declared in module: ModuleName4 -ModuleExport.dfy(262,25): Error: no export set 'Y' in module 'ModuleName4' -ModuleExport.dfy(266,9): Error: duplicate name of export set: X -ModuleExport.dfy(272,2): Error: module export contains a cycle: ExportCycle0 -> A -> B -> ExportCycle0 -ModuleExport.dfy(278,9): Error: module export contains a cycle: A -> B -> C -> A -21 resolution/type errors detected in ModuleExport.dfy +ModuleExport.dfy(125,17): Error: member 'Init' has not been imported in this scope and cannot be accessed here +ModuleExport.dfy(136,8): Error: when allocating an object of type 'C', one of its constructor methods must be called +ModuleExport.dfy(137,12): Error: when allocating an object of imported type 'D', one of its constructor methods must be called +ModuleExport.dfy(234,11): Error: Type or type parameter is not declared in this scope: X (did you forget to qualify a name or declare a module import 'opened'?) (note that names in outer modules are not visible in contained modules) +ModuleExport.dfy(260,9): Error: duplicate name of top-level declaration: X +ModuleExport.dfy(269,13): Error: no default export set declared in module: ModuleName4 +ModuleExport.dfy(272,25): Error: no export set 'Y' in module 'ModuleName4' +ModuleExport.dfy(276,9): Error: duplicate name of export set: X +ModuleExport.dfy(282,2): Error: module export contains a cycle: ExportCycle0 -> A -> B -> ExportCycle0 +ModuleExport.dfy(288,9): Error: module export contains a cycle: A -> B -> C -> A +20 resolution/type errors detected in ModuleExport.dfy diff --git a/Test/dafny0/Modules0.dfy b/Test/dafny0/Modules0.dfy index d2cd2f67329..ab294fe86bf 100644 --- a/Test/dafny0/Modules0.dfy +++ b/Test/dafny0/Modules0.dfy @@ -1,4 +1,4 @@ -// RUN: %exits-with 2 %dafny /compile:0 /deprecation:0 /print:"%t.print" /dprint:"%t.dprint" "%s" > "%t" +// RUN: %exits-with 2 %dafny /compile:0 /print:"%t.print" /dprint:"%t.dprint" "%s" > "%t" // RUN: %diff "%s.expect" "%t" // ---------------------- duplicate types within a module @@ -37,7 +37,7 @@ module A { // Note, this has the effect of importing two different T's, import MM = M import NN = N class X { - var t: MM.T; // error: use of the ambiguous name T + var t: MM.T // error: use of the ambiguous name T ghost function F(x: MM.T): // error: use of the ambiguous name T MM.T // error: use of the ambiguous name T { x } @@ -133,10 +133,10 @@ class Ghosty { } class AClassWithSomeField { - var SomeField: int; + var SomeField: int method SpecialFunctions() - modifies this; + modifies this { SomeField := SomeField + 4; var a := old(SomeField); // error: old can only be used in ghost contexts @@ -221,7 +221,7 @@ module BTr { import A = ATr class Y { method N() returns (x: A.X?) - ensures x != null; + ensures x != null { x := new X; } @@ -231,8 +231,8 @@ module BTr { module CTr { import B = BTr_corrected class Z { - var b: B.Y; // fine - var a: B.X; // error: imports don't reach name X explicitly + var b: B.Y // fine + var a: B.X // error: imports don't reach name X explicitly } } module CTs { @@ -264,7 +264,7 @@ module NonLocalB { } class D { method K() returns (b: B?) - ensures b != null; + ensures b != null { return new B; } @@ -311,7 +311,7 @@ module Q_Imp { module Q_M { import Q_Imp method MyMethod(root: Q_Imp.Node, S: set<Node>) - requires root in S; // error: the element type of S does not agree with the type of root + requires root in S // error: the element type of S does not agree with the type of root { var i := new Q_Imp.Node(); var j := new Node; @@ -374,6 +374,6 @@ module BTr_corrected { class Y { constructor () { } method N() returns (x: A.X?) - ensures x != null; + ensures x != null } } diff --git a/Test/dafny0/Modules0.dfy.expect b/Test/dafny0/Modules0.dfy.expect index a95a949d03f..66ad1c0e351 100644 --- a/Test/dafny0/Modules0.dfy.expect +++ b/Test/dafny0/Modules0.dfy.expect @@ -33,7 +33,6 @@ Modules0.dfy(320,11): Error: Type or type parameter is not declared in this scop Modules0.dfy(321,17): Error: module 'Q_Imp' does not declare a type 'Edon' Modules0.dfy(323,13): Error: new can be applied only to class types (got Q_Imp.List<?>) Modules0.dfy(324,23): Error: member 'Create' does not exist in class 'Klassy' -Modules0.dfy(324,10): Error: when allocating an object of type 'Klassy', one of its constructor methods must be called Modules0.dfy(318,13): Error: arguments must have comparable types (got Q_Imp.Node and Node) Modules0.dfy(349,11): Error: a datatype declaration (T) in a refinement module can only refine a datatype declaration or replace an abstract type declaration -35 resolution/type errors detected in Modules0.dfy +34 resolution/type errors detected in Modules0.dfy diff --git a/Test/dafny0/OnDemandResolutionCycle.dfy b/Test/dafny0/OnDemandResolutionCycle.dfy new file mode 100644 index 00000000000..819ea43bcc8 --- /dev/null +++ b/Test/dafny0/OnDemandResolutionCycle.dfy @@ -0,0 +1,24 @@ +// RUN: %exits-with 2 %dafny /compile:0 /typeSystemRefresh:1 "%s" > "%t" +// RUN: %diff "%s.expect" "%t" + +type A = x | x == a // error: cycle +const a: A := 2 + +type B = x | x == FB() // error: cycle +const b := FB() +function FB(): B + +const c0 := c1 // error: cycle +const c1 := c0 + +newtype D = x | x == d // error: cycle +const d: D := 2 + +newtype E = x | x == FE() // error: cycle +const e := FE() +function FE(): E + +newtype F = x | x == f() +function f(): F + +const g := g // error: cycle diff --git a/Test/dafny0/OnDemandResolutionCycle.dfy.expect b/Test/dafny0/OnDemandResolutionCycle.dfy.expect new file mode 100644 index 00000000000..d8338dc9459 --- /dev/null +++ b/Test/dafny0/OnDemandResolutionCycle.dfy.expect @@ -0,0 +1,12 @@ +OnDemandResolutionCycle.dfy(5,6): Error: PRE-TYPE: Cyclic dependency among declarations: a -> A -> a +OnDemandResolutionCycle.dfy(9,9): Error: PRE-TYPE: Cyclic dependency among declarations: FB -> B -> FB -> b +OnDemandResolutionCycle.dfy(7,5): Error: PRE-TYPE: Cyclic dependency among declarations: B -> B -> FB -> b +OnDemandResolutionCycle.dfy(11,6): Error: PRE-TYPE: Cyclic dependency among declarations: c0 -> c1 -> c0 +OnDemandResolutionCycle.dfy(15,6): Error: PRE-TYPE: Cyclic dependency among declarations: d -> D -> d +OnDemandResolutionCycle.dfy(19,9): Error: PRE-TYPE: Cyclic dependency among declarations: FE -> E -> FE -> e +OnDemandResolutionCycle.dfy(17,8): Error: PRE-TYPE: Cyclic dependency among declarations: E -> E -> FE -> e +OnDemandResolutionCycle.dfy(22,9): Error: PRE-TYPE: Cyclic dependency among declarations: f -> F -> f +OnDemandResolutionCycle.dfy(21,8): Error: PRE-TYPE: Cyclic dependency among declarations: F -> F -> f +OnDemandResolutionCycle.dfy(24,6): Error: PRE-TYPE: Cyclic dependency among declarations: g -> g +OnDemandResolutionCycle.dfy(15,14): Error: PRE-TYPE: integer literal used as if it had type D +11 resolution/type errors detected in OnDemandResolutionCycle.dfy diff --git a/Test/dafny0/OnDemandResolutionOrdering.dfy b/Test/dafny0/OnDemandResolutionOrdering.dfy new file mode 100644 index 00000000000..757da5946d8 --- /dev/null +++ b/Test/dafny0/OnDemandResolutionOrdering.dfy @@ -0,0 +1,161 @@ +// RUN: %exits-with 4 %dafny /compile:0 /typeSystemRefresh:1 /print:"%t.print" /rprint:"%t.rprint" "%s" > "%t" +// RUN: %diff "%s.expect" "%t" + +method Str(s: string) { + var t := s; +} + +class Class<XX> { +} + +method MC(c: Class<real>) { + var d: Class := c; +} + +type Synonym<A, Unused> = seq<A> + +method SM(x: Synonym<int, real>, y: seq<bool>) { + var m: seq := y; + + var a := x; + + var b: Synonym<int, bool> := x; // fine + + var k: seq := x; + var y: Synonym<int, bv29> := k; // fine +} + +type ParamSub<X> = s | s == CC.GetEmpty<X>() + +class CC { + static function GetEmpty<Y>(): seq<Y> { + [] + } +} + +method Q0() returns (b: array<ParamSub<real>>, be: ParamSub<real>) +{ + if * { + // The following gives a verification error, because the inferred RHS type is the pre-type array<seq<real>>. + // (Once type improvement for subset types is implemented, this error will go away.) + b := new ParamSub<real>[20]; + } else { + // The following gives a verification error, because the inferred RHS type is the pre-type array<seq<real>>. + // (Once type improvement for subset types is implemented, this error will go away.) + b := new ParamSub[20]; + } + var a := be; + var d: array := b; + var c: ParamSub := b[0]; + + b := new [20]; + var arr := new array<seq<int>>; + var cc := new CC; +} + +type K0 = y | y == C.F(2) witness * +type L0 = y | y == C.G(2) witness * +type M0 = y | y == C.H(2) witness * + +class C { + static function F(x: nat): nat { + var u := x; u + } + static function G<X>(x: X): X { + var u := x; u + } + static function H<X>(x: X): seq<X> { + var u := [x]; u + } + static function Poly<X>(): seq<X> { + [] + } +} + +type K = y | y == C.F(2) witness * +type L = y | y == C.G(2) witness * +type M = y | y == C.H(2) witness * + +type MX<X> = y | y == C.Poly<X>() witness * + +class PolyClass<Z> { + static function StaticPoly<Z>(): seq<Z> { + var zs: seq<Z> := []; + zs + } + function InstancePoly<Z>(): seq<Z> { + var zs: seq<Z> := []; + zs + } + function InstanceMono(): seq<Z> { + var zs: seq<Z> := []; + zs + } +} + +function FF<Y>(): K + + +method Q1() { + var b: array<Six>; +} + +method MM(n: nat, x: int) +{ + var r := n + x; +} + +type Opaque + +type Six = x | 0 <= x witness 7 + +type XParamSub<X> = s | s == XGetEmpty<X>() + +function XGetEmpty<Y>(): seq<Y> { + [] +} + +newtype N = x | x == n witness 2 +const n: int := 2 + +const n' := 2 + +module VariationOnOrdering0 { + type ParamSub<X> = s | s == CC.GetEmpty<X>() + + class CC { + static function GetEmpty<Y>(): seq<Y> { + [] + } + } + + class QQ { + // In this module, Q0 follows ParamSub and GetEmpty + method Q0() returns (b: array<ParamSub<real>>) + { + // The following gives a verification error, because the inferred RHS type is the pre-type array<seq<real>>. + // (Once type improvement for subset types is implemented, this error will go away.) + b := new ParamSub<real>[20]; + } + } +} + +module VariationOnOrdering1 { + class QQ { + // In this module, Q0 precedes ParamSub and GetEmpty + method Q0() returns (b: array<ParamSub<real>>) + { + // The following gives a verification error, because the inferred RHS type is the pre-type array<seq<real>>. + // (Once type improvement for subset types is implemented, this error will go away.) + b := new ParamSub<real>[20]; + } + } + + type ParamSub<X> = s | s == CC.GetEmpty<X>() + + class CC { + static function GetEmpty<Y>(): seq<Y> { + [] + } + } +} diff --git a/Test/dafny0/OnDemandResolutionOrdering.dfy.expect b/Test/dafny0/OnDemandResolutionOrdering.dfy.expect new file mode 100644 index 00000000000..c3d02b20371 --- /dev/null +++ b/Test/dafny0/OnDemandResolutionOrdering.dfy.expect @@ -0,0 +1,6 @@ +OnDemandResolutionOrdering.dfy(138,11): Error: value of expression (of type 'array?<seq<real>>') is not known to be an instance of type 'array<ParamSub<real>>' (possible cause: it may be null) +OnDemandResolutionOrdering.dfy(150,11): Error: value of expression (of type 'array?<seq<real>>') is not known to be an instance of type 'array<ParamSub<real>>' (possible cause: it may be null) +OnDemandResolutionOrdering.dfy(41,9): Error: value of expression (of type 'array?<seq<real>>') is not known to be an instance of type 'array<ParamSub<real>>' (possible cause: it may be null) +OnDemandResolutionOrdering.dfy(45,9): Error: value of expression (of type 'array?<seq<real>>') is not known to be an instance of type 'array<ParamSub<real>>' (possible cause: it may be null) + +Dafny program verifier finished with 10 verified, 4 errors diff --git a/Test/dafny0/ParallelResolveErrors.dfy.expect b/Test/dafny0/ParallelResolveErrors.dfy.expect index d6e621169a1..eee0d123d2c 100644 --- a/Test/dafny0/ParallelResolveErrors.dfy.expect +++ b/Test/dafny0/ParallelResolveErrors.dfy.expect @@ -1,17 +1,17 @@ -ParallelResolveErrors.dfy(217,6): Warning: the modify statement with a block statement is deprecated +ParallelResolveErrors.dfy(210,15): Warning: the modify statement with a block statement is deprecated ParallelResolveErrors.dfy(247,7): Warning: the ... refinement feature in statements is deprecated ParallelResolveErrors.dfy(248,10): Warning: the ... refinement feature in statements is deprecated ParallelResolveErrors.dfy(249,13): Warning: the ... refinement feature in statements is deprecated -ParallelResolveErrors.dfy(255,6): Warning: the modify statement with a block statement is deprecated +ParallelResolveErrors.dfy(249,17): Warning: the modify statement with a block statement is deprecated ParallelResolveErrors.dfy(256,9): Warning: the ... refinement feature in statements is deprecated ParallelResolveErrors.dfy(263,7): Warning: the ... refinement feature in statements is deprecated ParallelResolveErrors.dfy(264,10): Warning: the ... refinement feature in statements is deprecated -ParallelResolveErrors.dfy(271,6): Warning: the modify statement with a block statement is deprecated +ParallelResolveErrors.dfy(265,15): Warning: the modify statement with a block statement is deprecated ParallelResolveErrors.dfy(272,9): Warning: the ... refinement feature in statements is deprecated ParallelResolveErrors.dfy(279,7): Warning: the ... refinement feature in statements is deprecated ParallelResolveErrors.dfy(280,10): Warning: the ... refinement feature in statements is deprecated ParallelResolveErrors.dfy(281,13): Warning: the ... refinement feature in statements is deprecated -ParallelResolveErrors.dfy(287,6): Warning: the modify statement with a block statement is deprecated +ParallelResolveErrors.dfy(281,17): Warning: the modify statement with a block statement is deprecated ParallelResolveErrors.dfy(288,9): Warning: the ... refinement feature in statements is deprecated ParallelResolveErrors.dfy(26,8): Error: assignment to non-ghost variable is not allowed in this context, because the statement is in a ghost context; e.g., it may be guarded by a specification-only expression ParallelResolveErrors.dfy(8,6): Error: a forall statement is not allowed to update a variable it doesn't declare diff --git a/Test/dafny0/Refinement.dfy.expect b/Test/dafny0/Refinement.dfy.expect index 0b5b57fbf10..11f365b5421 100644 --- a/Test/dafny0/Refinement.dfy.expect +++ b/Test/dafny0/Refinement.dfy.expect @@ -7,7 +7,7 @@ Refinement.dfy(203,9): Warning: the ... refinement feature in statements is depr Refinement.dfy(204,13): Warning: the ... refinement feature in statements is deprecated Refinement.dfy(209,13): Warning: the ... refinement feature in statements is deprecated Refinement.dfy(252,11): Warning: the ... refinement feature in statements is deprecated -Refinement.dfy(254,4): Warning: the modify statement with a block statement is deprecated +Refinement.dfy(252,15): Warning: the modify statement with a block statement is deprecated Refinement.dfy(255,7): Warning: the ... refinement feature in statements is deprecated Refinement.dfy(259,7): Warning: the ... refinement feature in statements is deprecated Refinement.dfy(260,10): Warning: the ... refinement feature in statements is deprecated diff --git a/Test/dafny0/ResolutionErrors.dfy b/Test/dafny0/ResolutionErrors.dfy index 05d13ccc365..41f8b581214 100644 --- a/Test/dafny0/ResolutionErrors.dfy +++ b/Test/dafny0/ResolutionErrors.dfy @@ -314,6 +314,7 @@ module MiscMore { } // --------------- constructors ------------------------------------- + // Note, more tests in module ClassConstructorTests below class ClassWithConstructor { var y: int @@ -322,21 +323,9 @@ module MiscMore { constructor InitB() modifies this { y := 20; } // error: don't use "this" in modifies of constructor } - class ClassWithoutConstructor { - method Init() modifies this { } - } - method ConstructorTests() { - var o := new object; // fine: does not have any constructors - - o := new ClassWithoutConstructor; // fine: don't need to call anything particular method - o := new ClassWithoutConstructor.Init(); // this is also fine - - var c := new ClassWithConstructor.InitA(); - c := new ClassWithConstructor; // error: must call a constructor - c := new ClassWithConstructor.NotTheOne(); // error: must call a constructor, not an arbitrary method - c := new ClassWithConstructor.InitB(); + var c := new ClassWithConstructor.InitB(); c.InitB(); // error: not allowed to call constructors except during allocation } @@ -482,16 +471,14 @@ module MiscAgain { method Test() { var i := new Y(5); i := new Y(7); - i := new Y; // error: the class has a constructor, so one must be used + var s := new Luci.Init(5); s := new Luci.FromArray(null); s := new Luci(false); s := new Luci(true); - s := new Luci.M(); // error: there is a constructor, so one must be called - s := new Luci; // error: there is a constructor, so one must be called + var l := new Lamb; l := new Lamb(); // error: there is no default constructor - l := new Lamb.Gwen(); } } @@ -3916,3 +3903,62 @@ module AutoInitTypeCheckRegression { method M<G>(a: AutoStream<G>) // error: the argument to AutoStream is supposed to be an auto-init type method N<G>(g: G) returns (a: AutoStream<G>) // error: the argument to AutoStream is supposed to be an auto-init type } + +module ClassConstructorTests { + class ClassWithConstructor { + var y: int + method NotTheOne() { } + constructor InitA() { } + constructor InitB() { y := 20; } + } + + class ClassWithoutConstructor { + method Init() modifies this { } + } + + method ConstructorTests() + { + var o := new object; // fine: does not have any constructors + + o := new ClassWithoutConstructor; // fine: don't need to call any particular method + o := new ClassWithoutConstructor.Init(); // this is also fine + + var c := new ClassWithConstructor.InitA(); + c := new ClassWithConstructor; // error: must call a constructor + c := new ClassWithConstructor.NotTheOne(); // error: must call a constructor, not an arbitrary method + c := new ClassWithConstructor.InitB(); + } + + class Y { + var data: int + constructor (x: int) + { + data := x; + } + method Test() { + var i := new Y(5); + i := new Y(7); + i := new Y; // error: the class has a constructor, so one must be used + var s := new Luci.Init(5); + s := new Luci.FromArray(null); + s := new Luci(false); + s := new Luci(true); + s := new Luci.M(); // error: there is a constructor, so one must be called + s := new Luci; // error: there is a constructor, so one must be called + var l := new Lamb; // fine, since there are no constructors (only methods) + l := new Lamb.Gwen(); + } + } + + class Luci { + constructor Init(y: int) { } + constructor (nameless: bool) { } + constructor FromArray(a: array<int>) { } + method M() { } + } + + class Lamb { + method Jess() { } + method Gwen() { } + } +} diff --git a/Test/dafny0/ResolutionErrors.dfy.expect b/Test/dafny0/ResolutionErrors.dfy.expect index 96e781e421a..8828428e25f 100644 --- a/Test/dafny0/ResolutionErrors.dfy.expect +++ b/Test/dafny0/ResolutionErrors.dfy.expect @@ -1,5 +1,5 @@ -ResolutionErrors.dfy(322,33): Warning: constructors no longer need 'this' to be listed in modifies clauses -ResolutionErrors.dfy(1892,15): Warning: constructors no longer need 'this' to be listed in modifies clauses +ResolutionErrors.dfy(323,33): Warning: constructors no longer need 'this' to be listed in modifies clauses +ResolutionErrors.dfy(1879,15): Warning: constructors no longer need 'this' to be listed in modifies clauses ResolutionErrors.dfy(13,18): Error: a possibly infinite loop is allowed only if the enclosing method is declared (with 'decreases *') to be possibly non-terminating ResolutionErrors.dfy(25,13): Error: array selection requires an array2 (got array3<T>) ResolutionErrors.dfy(27,13): Error: array selection requires an array4 (got array<T>) @@ -36,599 +36,599 @@ ResolutionErrors.dfy(286,10): Error: return statement is not allowed in this con ResolutionErrors.dfy(306,12): Error: label shadows an enclosing label ResolutionErrors.dfy(311,10): Error: duplicate label ResolutionErrors.dfy(313,10): Error: label shadows a dominating label -ResolutionErrors.dfy(337,6): Error: when allocating an object of type 'ClassWithConstructor', one of its constructor methods must be called -ResolutionErrors.dfy(338,6): Error: when allocating an object of type 'ClassWithConstructor', one of its constructor methods must be called -ResolutionErrors.dfy(340,11): Error: a constructor is allowed to be called only when an object is being allocated -ResolutionErrors.dfy(356,27): Error: arguments must have comparable types (got bool and int) -ResolutionErrors.dfy(354,18): Error: arguments must have comparable types (got int and DTD_List) -ResolutionErrors.dfy(355,18): Error: arguments must have comparable types (got DTD_List and int) -ResolutionErrors.dfy(369,17): Error: ghost variables such as b are allowed only in specification contexts. b was inferred to be ghost based on its declaration or initialization. -ResolutionErrors.dfy(393,7): Error: incorrect argument type at index 1 for method in-parameter 'b' (expected GenericClass<int>, found GenericClass<bool>) (non-variant type parameter would require int = bool) -ResolutionErrors.dfy(407,13): Error: incorrect argument type at index 0 for datatype constructor parameter 'hd' (expected _T0, found int) -ResolutionErrors.dfy(408,9): Error: incorrect argument type at index 0 for datatype constructor parameter 'hd' (expected _T0, found int) -ResolutionErrors.dfy(417,8): Error: all lines in a calculation must have the same type (got int after bool) -ResolutionErrors.dfy(421,8): Error: all lines in a calculation must have the same type (got int after bool) -ResolutionErrors.dfy(424,8): Error: first argument to ==> must be of type bool (instead got int) -ResolutionErrors.dfy(424,8): Error: second argument to ==> must be of type bool (instead got int) -ResolutionErrors.dfy(425,12): Error: first argument to ==> must be of type bool (instead got int) -ResolutionErrors.dfy(425,12): Error: second argument to ==> must be of type bool (instead got int) -ResolutionErrors.dfy(426,12): Error: first argument to ==> must be of type bool (instead got int) -ResolutionErrors.dfy(426,12): Error: second argument to ==> must be of type bool (instead got int) -ResolutionErrors.dfy(424,8): Error: first argument to ==> must be of type bool (instead got int) -ResolutionErrors.dfy(424,8): Error: second argument to ==> must be of type bool (instead got int) -ResolutionErrors.dfy(430,12): Error: first argument to ==> must be of type bool (instead got int) -ResolutionErrors.dfy(430,12): Error: second argument to ==> must be of type bool (instead got int) -ResolutionErrors.dfy(429,8): Error: first argument to ==> must be of type bool (instead got int) -ResolutionErrors.dfy(429,8): Error: second argument to ==> must be of type bool (instead got int) -ResolutionErrors.dfy(416,8): Error: type of + must be of a numeric type, a bitvector type, ORDINAL, char, a sequence type, or a set-like or map-like type (instead got bool) -ResolutionErrors.dfy(416,8): Error: arguments must have comparable types (got bool and int) -ResolutionErrors.dfy(416,8): Error: arguments must have comparable types (got bool and int) -ResolutionErrors.dfy(420,8): Error: arguments must have comparable types (got bool and int) -ResolutionErrors.dfy(420,8): Error: arguments must have comparable types (got bool and int) -ResolutionErrors.dfy(454,13): Error: in a hint, calls are allowed only to lemmas -ResolutionErrors.dfy(456,10): Error: a hint is not allowed to make heap updates -ResolutionErrors.dfy(458,10): Error: a hint is not allowed to update a variable it doesn't declare -ResolutionErrors.dfy(479,4): Error: More than one anonymous constructor -ResolutionErrors.dfy(485,8): Error: when allocating an object of type 'Y', one of its constructor methods must be called -ResolutionErrors.dfy(490,8): Error: when allocating an object of type 'Luci', one of its constructor methods must be called -ResolutionErrors.dfy(491,8): Error: when allocating an object of type 'Luci', one of its constructor methods must be called -ResolutionErrors.dfy(493,15): Error: class Lamb does not have an anonymous constructor -ResolutionErrors.dfy(546,7): Error: RHS (of type List<A>) not assignable to LHS (of type List<B>) (covariant type parameter would require A <: B) -ResolutionErrors.dfy(551,7): Error: RHS (of type List<A>) not assignable to LHS (of type List<B>) (covariant type parameter would require A <: B) -ResolutionErrors.dfy(565,23): Error: type of case bodies do not agree (found Tree<_T1, _T0>, previous types Tree<_T0, _T1>) (covariant type parameter 0 would require _T1 <: _T0) -ResolutionErrors.dfy(577,30): Error: Wrong number of type arguments (0 instead of 2) passed to datatype: Tree -ResolutionErrors.dfy(592,20): Error: unresolved identifier: w -ResolutionErrors.dfy(611,8): Error: the type of this local variable is underspecified -ResolutionErrors.dfy(612,25): Error: the type of this variable is underspecified -ResolutionErrors.dfy(612,23): Error: type parameter 'T' (inferred to be '?') in the function call to 'P' could not be determined -ResolutionErrors.dfy(612,18): Error: type of bound variable 'z' could not be determined; please specify the type explicitly -ResolutionErrors.dfy(625,13): Error: a lemma is not allowed to use 'new' -ResolutionErrors.dfy(626,9): Error: a lemma is not allowed to use 'new' -ResolutionErrors.dfy(635,16): Error: only ghost methods can be called from this context -ResolutionErrors.dfy(642,15): Error: only ghost methods can be called from this context -ResolutionErrors.dfy(652,17): Error: a hint is not allowed to use 'new' -ResolutionErrors.dfy(667,14): Error: new allocation not supported in aggregate assignments -ResolutionErrors.dfy(674,14): Error: a forall statement is not allowed to use 'new' -ResolutionErrors.dfy(674,11): Error: assignment to array element is not allowed in this context, because the statement is in a ghost context; e.g., it may be guarded by a specification-only expression -ResolutionErrors.dfy(690,26): Error: second argument to "in" must be a set, multiset, or sequence with elements of type int, or a map with domain int (instead got bool) -ResolutionErrors.dfy(685,18): Error: second argument to "in" must be a set, multiset, or sequence with elements of type int, or a map with domain int (instead got ?) -ResolutionErrors.dfy(702,13): Error: lemmas are not allowed to have modifies clauses -ResolutionErrors.dfy(729,22): Error: a possibly infinite loop is allowed only if the enclosing method is declared (with 'decreases *') to be possibly non-terminating -ResolutionErrors.dfy(762,22): Error: a possibly infinite loop is allowed only if the enclosing method is declared (with 'decreases *') to be possibly non-terminating -ResolutionErrors.dfy(795,17): Error: the method returns 1 value but is assigned to 0 variable (all return values must be assigned) -ResolutionErrors.dfy(816,4): Error: ghost variables such as y are allowed only in specification contexts. y was inferred to be ghost based on its declaration or initialization. -ResolutionErrors.dfy(827,40): Error: ghost variables such as y are allowed only in specification contexts. y was inferred to be ghost based on its declaration or initialization. -ResolutionErrors.dfy(850,6): Error: RHS (of type B) not assignable to LHS (of type object) -ResolutionErrors.dfy(852,6): Error: RHS (of type B) not assignable to LHS (of type object) -ResolutionErrors.dfy(857,6): Error: RHS (of type G) not assignable to LHS (of type object) -ResolutionErrors.dfy(858,6): Error: RHS (of type Dt) not assignable to LHS (of type object) -ResolutionErrors.dfy(859,6): Error: RHS (of type CoDt) not assignable to LHS (of type object) -ResolutionErrors.dfy(851,6): Error: RHS (of type int) not assignable to LHS (of type object) -ResolutionErrors.dfy(871,13): Error: a modifies-clause expression must denote an object or a set/iset/multiset/seq of objects (instead got int) -ResolutionErrors.dfy(875,16): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) -ResolutionErrors.dfy(887,14): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) -ResolutionErrors.dfy(895,16): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) -ResolutionErrors.dfy(905,20): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) -ResolutionErrors.dfy(916,18): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) -ResolutionErrors.dfy(938,10): Error: LHS of assignment must denote a mutable field -ResolutionErrors.dfy(939,10): Error: LHS of assignment must denote a mutable field -ResolutionErrors.dfy(940,9): Error: cannot assign to a range of array elements (try the 'forall' statement) -ResolutionErrors.dfy(941,9): Error: cannot assign to a range of array elements (try the 'forall' statement) -ResolutionErrors.dfy(942,5): Error: cannot assign to a range of array elements (try the 'forall' statement) -ResolutionErrors.dfy(943,5): Error: cannot assign to a range of array elements (try the 'forall' statement) -ResolutionErrors.dfy(932,4): Error: LHS of array assignment must denote an array element (found seq<int>) -ResolutionErrors.dfy(933,4): Error: LHS of array assignment must denote an array element (found seq<int>) -ResolutionErrors.dfy(955,11): Error: unresolved identifier: s -ResolutionErrors.dfy(974,18): Error: member '3' does not exist in datatype '_tuple#3' -ResolutionErrors.dfy(974,28): Error: member 'x' does not exist in datatype '_tuple#2' -ResolutionErrors.dfy(973,18): Error: condition is expected to be of type bool, but is int -ResolutionErrors.dfy(967,39): Error: RHS (of type (int, real, int)) not assignable to LHS (of type (int, real, int, real)) -ResolutionErrors.dfy(966,34): Error: RHS (of type (int, int, real)) not assignable to LHS (of type (int, real, int)) (covariant type parameter 1 would require int <: real) -ResolutionErrors.dfy(966,34): Error: RHS (of type (int, int, real)) not assignable to LHS (of type (int, real, int)) (covariant type parameter 2 would require real <: int) -ResolutionErrors.dfy(998,12): Error: type of left argument to % (int) must agree with the result type (real) -ResolutionErrors.dfy(998,12): Error: arguments to % must be integer-numeric or bitvector types (got real) -ResolutionErrors.dfy(997,19): Error: type of right argument to / (int) must agree with the result type (real) -ResolutionErrors.dfy(1025,11): Error: Wrong number of type arguments (2 instead of 1) passed to non-null type: array3 -ResolutionErrors.dfy(1026,11): Error: Wrong number of type arguments (2 instead of 1) passed to non-null type: C -ResolutionErrors.dfy(1037,7): Error: duplicate name of top-level declaration: BadSyn2 -ResolutionErrors.dfy(1034,17): Error: Wrong number of type arguments (0 instead of 1) passed to datatype: List -ResolutionErrors.dfy(1035,17): Error: Type or type parameter is not declared in this scope: badName (did you forget to qualify a name or declare a module import 'opened'?) (note that names in outer modules are not visible in contained modules) -ResolutionErrors.dfy(1036,22): Error: Type or type parameter is not declared in this scope: X (did you forget to qualify a name or declare a module import 'opened'?) (note that names in outer modules are not visible in contained modules) -ResolutionErrors.dfy(1043,7): Error: type-synonym cycle: A -> A -ResolutionErrors.dfy(1046,7): Error: cycle among redirecting types (newtypes, subset types, type synonyms): A -> B -> A -ResolutionErrors.dfy(1050,7): Error: cycle among redirecting types (newtypes, subset types, type synonyms): A -> B -> A -ResolutionErrors.dfy(1059,11): Error: because of cyclic dependencies among constructor argument types, no instances of datatype 'D' can be constructed -ResolutionErrors.dfy(1062,7): Error: cycle among redirecting types (newtypes, subset types, type synonyms): A -> B -> A -ResolutionErrors.dfy(1067,7): Error: cycle among redirecting types (newtypes, subset types, type synonyms): A -> B -> A -ResolutionErrors.dfy(1072,7): Error: type-synonym cycle: A -> A -ResolutionErrors.dfy(1079,25): Error: unresolved identifier: x -ResolutionErrors.dfy(1082,22): Error: unresolved identifier: x -ResolutionErrors.dfy(1085,25): Error: unresolved identifier: x -ResolutionErrors.dfy(1087,21): Error: unresolved identifier: x -ResolutionErrors.dfy(1089,21): Error: unresolved identifier: x -ResolutionErrors.dfy(1092,21): Error: unresolved identifier: x -ResolutionErrors.dfy(1099,35): Error: Wrong number of type arguments (2 instead of 1) passed to abstract type: P -ResolutionErrors.dfy(1111,13): Error: Type or type parameter is not declared in this scope: BX (did you forget to qualify a name or declare a module import 'opened'?) (note that names in outer modules are not visible in contained modules) -ResolutionErrors.dfy(1121,6): Error: RHS (of type P<int>) not assignable to LHS (of type P<bool>) (non-variant type parameter would require bool = int) -ResolutionErrors.dfy(1126,6): Error: RHS (of type P<A>) not assignable to LHS (of type P<B>) (non-variant type parameter would require B = A) -ResolutionErrors.dfy(1131,6): Error: RHS (of type P<A>) not assignable to LHS (of type P<int>) (non-variant type parameter would require int = A) -ResolutionErrors.dfy(1132,6): Error: RHS (of type P<int>) not assignable to LHS (of type P<A>) (non-variant type parameter would require A = int) -ResolutionErrors.dfy(1137,13): Error: arguments must have comparable types (got P<int> and P<X>) -ResolutionErrors.dfy(1138,13): Error: arguments must have comparable types (got P<bool> and P<X>) -ResolutionErrors.dfy(1139,13): Error: arguments must have comparable types (got P<int> and P<bool>) -ResolutionErrors.dfy(1150,13): Error: new can be applied only to class types (got JJ) -ResolutionErrors.dfy(1158,37): Error: a set comprehension involved in a function definition is not allowed to depend on the set of allocated references, but values of 'o' (of type 'object') may contain references (see documentation for 'older' parameters) -ResolutionErrors.dfy(1159,31): Error: a set comprehension involved in a function definition is not allowed to depend on the set of allocated references, but values of 'o' (of type 'object') may contain references (see documentation for 'older' parameters) -ResolutionErrors.dfy(1165,27): Error: set comprehensions in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'o' -ResolutionErrors.dfy(1173,15): Error: arguments to / must be numeric or bitvector types (got set<bool>) -ResolutionErrors.dfy(1180,20): Error: a call to a possibly non-terminating method is allowed only if the calling method is also declared (with 'decreases *') to be possibly non-terminating -ResolutionErrors.dfy(1195,16): Error: a possibly infinite loop is allowed only if the enclosing method is declared (with 'decreases *') to be possibly non-terminating -ResolutionErrors.dfy(1260,13): Error: type parameter 'PT' (inferred to be '?') in the function call to 'P' could not be determined -ResolutionErrors.dfy(1261,14): Error: the type of this variable is underspecified -ResolutionErrors.dfy(1261,19): Error: type parameter 'QT' (inferred to be '?') in the function call to 'Q' could not be determined -ResolutionErrors.dfy(1261,20): Error: the type of this expression is underspecified -ResolutionErrors.dfy(1262,4): Error: type parameter 'MT' (inferred to be '?') to the method 'M' could not be determined -ResolutionErrors.dfy(1263,8): Error: the type of this variable is underspecified -ResolutionErrors.dfy(1263,13): Error: type parameter 'NT' (inferred to be '?') to the method 'N' could not be determined -ResolutionErrors.dfy(1264,8): Error: the type of this variable is underspecified -ResolutionErrors.dfy(1265,8): Error: the type of this variable is underspecified -ResolutionErrors.dfy(1266,8): Error: the type of this local variable is underspecified -ResolutionErrors.dfy(1267,8): Error: the type of this variable is underspecified +ResolutionErrors.dfy(329,11): Error: a constructor is allowed to be called only when an object is being allocated +ResolutionErrors.dfy(345,27): Error: arguments must have comparable types (got bool and int) +ResolutionErrors.dfy(343,18): Error: arguments must have comparable types (got int and DTD_List) +ResolutionErrors.dfy(344,18): Error: arguments must have comparable types (got DTD_List and int) +ResolutionErrors.dfy(358,17): Error: ghost variables such as b are allowed only in specification contexts. b was inferred to be ghost based on its declaration or initialization. +ResolutionErrors.dfy(382,7): Error: incorrect argument type at index 1 for method in-parameter 'b' (expected GenericClass<int>, found GenericClass<bool>) (non-variant type parameter would require int = bool) +ResolutionErrors.dfy(396,13): Error: incorrect argument type at index 0 for datatype constructor parameter 'hd' (expected _T0, found int) +ResolutionErrors.dfy(397,9): Error: incorrect argument type at index 0 for datatype constructor parameter 'hd' (expected _T0, found int) +ResolutionErrors.dfy(406,8): Error: all lines in a calculation must have the same type (got int after bool) +ResolutionErrors.dfy(410,8): Error: all lines in a calculation must have the same type (got int after bool) +ResolutionErrors.dfy(413,8): Error: first argument to ==> must be of type bool (instead got int) +ResolutionErrors.dfy(413,8): Error: second argument to ==> must be of type bool (instead got int) +ResolutionErrors.dfy(414,12): Error: first argument to ==> must be of type bool (instead got int) +ResolutionErrors.dfy(414,12): Error: second argument to ==> must be of type bool (instead got int) +ResolutionErrors.dfy(415,12): Error: first argument to ==> must be of type bool (instead got int) +ResolutionErrors.dfy(415,12): Error: second argument to ==> must be of type bool (instead got int) +ResolutionErrors.dfy(413,8): Error: first argument to ==> must be of type bool (instead got int) +ResolutionErrors.dfy(413,8): Error: second argument to ==> must be of type bool (instead got int) +ResolutionErrors.dfy(419,12): Error: first argument to ==> must be of type bool (instead got int) +ResolutionErrors.dfy(419,12): Error: second argument to ==> must be of type bool (instead got int) +ResolutionErrors.dfy(418,8): Error: first argument to ==> must be of type bool (instead got int) +ResolutionErrors.dfy(418,8): Error: second argument to ==> must be of type bool (instead got int) +ResolutionErrors.dfy(405,8): Error: type of + must be of a numeric type, a bitvector type, ORDINAL, char, a sequence type, or a set-like or map-like type (instead got bool) +ResolutionErrors.dfy(405,8): Error: arguments must have comparable types (got bool and int) +ResolutionErrors.dfy(405,8): Error: arguments must have comparable types (got bool and int) +ResolutionErrors.dfy(409,8): Error: arguments must have comparable types (got bool and int) +ResolutionErrors.dfy(409,8): Error: arguments must have comparable types (got bool and int) +ResolutionErrors.dfy(443,13): Error: in a hint, calls are allowed only to lemmas +ResolutionErrors.dfy(445,10): Error: a hint is not allowed to make heap updates +ResolutionErrors.dfy(447,10): Error: a hint is not allowed to update a variable it doesn't declare +ResolutionErrors.dfy(468,4): Error: More than one anonymous constructor +ResolutionErrors.dfy(481,15): Error: class Lamb does not have an anonymous constructor +ResolutionErrors.dfy(533,7): Error: RHS (of type List<A>) not assignable to LHS (of type List<B>) (covariant type parameter would require A <: B) +ResolutionErrors.dfy(538,7): Error: RHS (of type List<A>) not assignable to LHS (of type List<B>) (covariant type parameter would require A <: B) +ResolutionErrors.dfy(552,23): Error: type of case bodies do not agree (found Tree<_T1, _T0>, previous types Tree<_T0, _T1>) (covariant type parameter 0 would require _T1 <: _T0) +ResolutionErrors.dfy(564,30): Error: Wrong number of type arguments (0 instead of 2) passed to datatype: Tree +ResolutionErrors.dfy(579,20): Error: unresolved identifier: w +ResolutionErrors.dfy(598,8): Error: the type of this local variable is underspecified +ResolutionErrors.dfy(599,25): Error: the type of this variable is underspecified +ResolutionErrors.dfy(599,23): Error: type parameter 'T' (inferred to be '?') in the function call to 'P' could not be determined +ResolutionErrors.dfy(599,18): Error: type of bound variable 'z' could not be determined; please specify the type explicitly +ResolutionErrors.dfy(612,13): Error: a lemma is not allowed to use 'new' +ResolutionErrors.dfy(613,9): Error: a lemma is not allowed to use 'new' +ResolutionErrors.dfy(622,16): Error: only ghost methods can be called from this context +ResolutionErrors.dfy(629,15): Error: only ghost methods can be called from this context +ResolutionErrors.dfy(639,17): Error: a hint is not allowed to use 'new' +ResolutionErrors.dfy(654,14): Error: new allocation not supported in aggregate assignments +ResolutionErrors.dfy(661,14): Error: a forall statement is not allowed to use 'new' +ResolutionErrors.dfy(661,11): Error: assignment to array element is not allowed in this context, because the statement is in a ghost context; e.g., it may be guarded by a specification-only expression +ResolutionErrors.dfy(677,26): Error: second argument to "in" must be a set, multiset, or sequence with elements of type int, or a map with domain int (instead got bool) +ResolutionErrors.dfy(672,18): Error: second argument to "in" must be a set, multiset, or sequence with elements of type int, or a map with domain int (instead got ?) +ResolutionErrors.dfy(689,13): Error: lemmas are not allowed to have modifies clauses +ResolutionErrors.dfy(716,22): Error: a possibly infinite loop is allowed only if the enclosing method is declared (with 'decreases *') to be possibly non-terminating +ResolutionErrors.dfy(749,22): Error: a possibly infinite loop is allowed only if the enclosing method is declared (with 'decreases *') to be possibly non-terminating +ResolutionErrors.dfy(782,17): Error: the method returns 1 value but is assigned to 0 variable (all return values must be assigned) +ResolutionErrors.dfy(803,4): Error: ghost variables such as y are allowed only in specification contexts. y was inferred to be ghost based on its declaration or initialization. +ResolutionErrors.dfy(814,40): Error: ghost variables such as y are allowed only in specification contexts. y was inferred to be ghost based on its declaration or initialization. +ResolutionErrors.dfy(837,6): Error: RHS (of type B) not assignable to LHS (of type object) +ResolutionErrors.dfy(839,6): Error: RHS (of type B) not assignable to LHS (of type object) +ResolutionErrors.dfy(844,6): Error: RHS (of type G) not assignable to LHS (of type object) +ResolutionErrors.dfy(845,6): Error: RHS (of type Dt) not assignable to LHS (of type object) +ResolutionErrors.dfy(846,6): Error: RHS (of type CoDt) not assignable to LHS (of type object) +ResolutionErrors.dfy(838,6): Error: RHS (of type int) not assignable to LHS (of type object) +ResolutionErrors.dfy(858,13): Error: a modifies-clause expression must denote an object or a set/iset/multiset/seq of objects (instead got int) +ResolutionErrors.dfy(862,16): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) +ResolutionErrors.dfy(874,14): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) +ResolutionErrors.dfy(882,16): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) +ResolutionErrors.dfy(892,20): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) +ResolutionErrors.dfy(903,18): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) +ResolutionErrors.dfy(925,10): Error: LHS of assignment must denote a mutable field +ResolutionErrors.dfy(926,10): Error: LHS of assignment must denote a mutable field +ResolutionErrors.dfy(927,9): Error: cannot assign to a range of array elements (try the 'forall' statement) +ResolutionErrors.dfy(928,9): Error: cannot assign to a range of array elements (try the 'forall' statement) +ResolutionErrors.dfy(929,5): Error: cannot assign to a range of array elements (try the 'forall' statement) +ResolutionErrors.dfy(930,5): Error: cannot assign to a range of array elements (try the 'forall' statement) +ResolutionErrors.dfy(919,4): Error: LHS of array assignment must denote an array element (found seq<int>) +ResolutionErrors.dfy(920,4): Error: LHS of array assignment must denote an array element (found seq<int>) +ResolutionErrors.dfy(942,11): Error: unresolved identifier: s +ResolutionErrors.dfy(961,18): Error: member '3' does not exist in datatype '_tuple#3' +ResolutionErrors.dfy(961,28): Error: member 'x' does not exist in datatype '_tuple#2' +ResolutionErrors.dfy(960,18): Error: condition is expected to be of type bool, but is int +ResolutionErrors.dfy(954,39): Error: RHS (of type (int, real, int)) not assignable to LHS (of type (int, real, int, real)) +ResolutionErrors.dfy(953,34): Error: RHS (of type (int, int, real)) not assignable to LHS (of type (int, real, int)) (covariant type parameter 1 would require int <: real) +ResolutionErrors.dfy(953,34): Error: RHS (of type (int, int, real)) not assignable to LHS (of type (int, real, int)) (covariant type parameter 2 would require real <: int) +ResolutionErrors.dfy(985,12): Error: type of left argument to % (int) must agree with the result type (real) +ResolutionErrors.dfy(985,12): Error: arguments to % must be integer-numeric or bitvector types (got real) +ResolutionErrors.dfy(984,19): Error: type of right argument to / (int) must agree with the result type (real) +ResolutionErrors.dfy(1012,11): Error: Wrong number of type arguments (2 instead of 1) passed to non-null type: array3 +ResolutionErrors.dfy(1013,11): Error: Wrong number of type arguments (2 instead of 1) passed to non-null type: C +ResolutionErrors.dfy(1024,7): Error: duplicate name of top-level declaration: BadSyn2 +ResolutionErrors.dfy(1021,17): Error: Wrong number of type arguments (0 instead of 1) passed to datatype: List +ResolutionErrors.dfy(1022,17): Error: Type or type parameter is not declared in this scope: badName (did you forget to qualify a name or declare a module import 'opened'?) (note that names in outer modules are not visible in contained modules) +ResolutionErrors.dfy(1023,22): Error: Type or type parameter is not declared in this scope: X (did you forget to qualify a name or declare a module import 'opened'?) (note that names in outer modules are not visible in contained modules) +ResolutionErrors.dfy(1030,7): Error: type-synonym cycle: A -> A +ResolutionErrors.dfy(1033,7): Error: cycle among redirecting types (newtypes, subset types, type synonyms): A -> B -> A +ResolutionErrors.dfy(1037,7): Error: cycle among redirecting types (newtypes, subset types, type synonyms): A -> B -> A +ResolutionErrors.dfy(1046,11): Error: because of cyclic dependencies among constructor argument types, no instances of datatype 'D' can be constructed +ResolutionErrors.dfy(1049,7): Error: cycle among redirecting types (newtypes, subset types, type synonyms): A -> B -> A +ResolutionErrors.dfy(1054,7): Error: cycle among redirecting types (newtypes, subset types, type synonyms): A -> B -> A +ResolutionErrors.dfy(1059,7): Error: type-synonym cycle: A -> A +ResolutionErrors.dfy(1066,25): Error: unresolved identifier: x +ResolutionErrors.dfy(1069,22): Error: unresolved identifier: x +ResolutionErrors.dfy(1072,25): Error: unresolved identifier: x +ResolutionErrors.dfy(1074,21): Error: unresolved identifier: x +ResolutionErrors.dfy(1076,21): Error: unresolved identifier: x +ResolutionErrors.dfy(1079,21): Error: unresolved identifier: x +ResolutionErrors.dfy(1086,35): Error: Wrong number of type arguments (2 instead of 1) passed to abstract type: P +ResolutionErrors.dfy(1098,13): Error: Type or type parameter is not declared in this scope: BX (did you forget to qualify a name or declare a module import 'opened'?) (note that names in outer modules are not visible in contained modules) +ResolutionErrors.dfy(1108,6): Error: RHS (of type P<int>) not assignable to LHS (of type P<bool>) (non-variant type parameter would require bool = int) +ResolutionErrors.dfy(1113,6): Error: RHS (of type P<A>) not assignable to LHS (of type P<B>) (non-variant type parameter would require B = A) +ResolutionErrors.dfy(1118,6): Error: RHS (of type P<A>) not assignable to LHS (of type P<int>) (non-variant type parameter would require int = A) +ResolutionErrors.dfy(1119,6): Error: RHS (of type P<int>) not assignable to LHS (of type P<A>) (non-variant type parameter would require A = int) +ResolutionErrors.dfy(1124,13): Error: arguments must have comparable types (got P<int> and P<X>) +ResolutionErrors.dfy(1125,13): Error: arguments must have comparable types (got P<bool> and P<X>) +ResolutionErrors.dfy(1126,13): Error: arguments must have comparable types (got P<int> and P<bool>) +ResolutionErrors.dfy(1137,13): Error: new can be applied only to class types (got JJ) +ResolutionErrors.dfy(1145,37): Error: a set comprehension involved in a function definition is not allowed to depend on the set of allocated references, but values of 'o' (of type 'object') may contain references (see documentation for 'older' parameters) +ResolutionErrors.dfy(1146,31): Error: a set comprehension involved in a function definition is not allowed to depend on the set of allocated references, but values of 'o' (of type 'object') may contain references (see documentation for 'older' parameters) +ResolutionErrors.dfy(1152,27): Error: set comprehensions in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'o' +ResolutionErrors.dfy(1160,15): Error: arguments to / must be numeric or bitvector types (got set<bool>) +ResolutionErrors.dfy(1167,20): Error: a call to a possibly non-terminating method is allowed only if the calling method is also declared (with 'decreases *') to be possibly non-terminating +ResolutionErrors.dfy(1182,16): Error: a possibly infinite loop is allowed only if the enclosing method is declared (with 'decreases *') to be possibly non-terminating +ResolutionErrors.dfy(1247,13): Error: type parameter 'PT' (inferred to be '?') in the function call to 'P' could not be determined +ResolutionErrors.dfy(1248,14): Error: the type of this variable is underspecified +ResolutionErrors.dfy(1248,19): Error: type parameter 'QT' (inferred to be '?') in the function call to 'Q' could not be determined +ResolutionErrors.dfy(1248,20): Error: the type of this expression is underspecified +ResolutionErrors.dfy(1249,4): Error: type parameter 'MT' (inferred to be '?') to the method 'M' could not be determined +ResolutionErrors.dfy(1250,8): Error: the type of this variable is underspecified +ResolutionErrors.dfy(1250,13): Error: type parameter 'NT' (inferred to be '?') to the method 'N' could not be determined +ResolutionErrors.dfy(1251,8): Error: the type of this variable is underspecified +ResolutionErrors.dfy(1252,8): Error: the type of this variable is underspecified +ResolutionErrors.dfy(1253,8): Error: the type of this local variable is underspecified +ResolutionErrors.dfy(1254,8): Error: the type of this variable is underspecified +ResolutionErrors.dfy(1255,8): Error: the type of this local variable is underspecified +ResolutionErrors.dfy(1259,26): Error: the type of this variable is underspecified +ResolutionErrors.dfy(1259,21): Error: type of bound variable 's' could not be determined; please specify the type explicitly +ResolutionErrors.dfy(1260,31): Error: the type of this variable is underspecified +ResolutionErrors.dfy(1260,21): Error: type of bound variable 's' could not be determined; please specify the type explicitly +ResolutionErrors.dfy(1261,30): Error: the type of this variable is underspecified +ResolutionErrors.dfy(1261,21): Error: type of bound variable 'c' could not be determined; please specify the type explicitly ResolutionErrors.dfy(1268,8): Error: the type of this local variable is underspecified -ResolutionErrors.dfy(1272,26): Error: the type of this variable is underspecified -ResolutionErrors.dfy(1272,21): Error: type of bound variable 's' could not be determined; please specify the type explicitly -ResolutionErrors.dfy(1273,31): Error: the type of this variable is underspecified -ResolutionErrors.dfy(1273,21): Error: type of bound variable 's' could not be determined; please specify the type explicitly -ResolutionErrors.dfy(1274,30): Error: the type of this variable is underspecified -ResolutionErrors.dfy(1274,21): Error: type of bound variable 'c' could not be determined; please specify the type explicitly -ResolutionErrors.dfy(1281,8): Error: the type of this local variable is underspecified -ResolutionErrors.dfy(1284,29): Error: type of bound variable 'c' could not be determined; please specify the type explicitly -ResolutionErrors.dfy(1295,21): Error: Type or type parameter is not declared in this scope: X (did you forget to qualify a name or declare a module import 'opened'?) (note that names in outer modules are not visible in contained modules) -ResolutionErrors.dfy(1296,24): Error: Type or type parameter is not declared in this scope: X (did you forget to qualify a name or declare a module import 'opened'?) (note that names in outer modules are not visible in contained modules) -ResolutionErrors.dfy(1333,16): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (y) -ResolutionErrors.dfy(1350,18): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) -ResolutionErrors.dfy(1378,15): Error: The name Inner ambiguously refers to a type in one of the modules A, B (try qualifying the type name with the module name) -ResolutionErrors.dfy(1388,29): Error: ghost variables such as tmp are allowed only in specification contexts. tmp was inferred to be ghost based on its declaration or initialization. -ResolutionErrors.dfy(1390,49): Error: ghost variables such as a0 are allowed only in specification contexts. a0 was inferred to be ghost based on its declaration or initialization. -ResolutionErrors.dfy(1390,54): Error: ghost variables such as a1 are allowed only in specification contexts. a1 was inferred to be ghost based on its declaration or initialization. -ResolutionErrors.dfy(1399,33): Error: set argument type must support equality (got (int, int -> bool)) -ResolutionErrors.dfy(1411,11): Error: name of type (X) is used as a variable -ResolutionErrors.dfy(1411,16): Error: name of type (X) is used as a variable -ResolutionErrors.dfy(1412,11): Error: name of module (Y) is used as a variable -ResolutionErrors.dfy(1412,16): Error: name of module (Y) is used as a variable -ResolutionErrors.dfy(1413,11): Error: name of type (X) is used as a variable -ResolutionErrors.dfy(1414,11): Error: name of module (Y) is used as a variable -ResolutionErrors.dfy(1419,16): Error: name of type (X) is used as a variable -ResolutionErrors.dfy(1420,16): Error: name of module (Y) is used as a variable -ResolutionErrors.dfy(1421,4): Error: name of type (X) is used as a variable -ResolutionErrors.dfy(1422,4): Error: name of module (Y) is used as a variable -ResolutionErrors.dfy(1432,9): Error: type of RHS of assign-such-that statement must be boolean (got int) -ResolutionErrors.dfy(1431,11): Error: type of left argument to + (int) must agree with the result type (bool) -ResolutionErrors.dfy(1431,11): Error: type of right argument to + (int) must agree with the result type (bool) -ResolutionErrors.dfy(1431,11): Error: type of + must be of a numeric type, a bitvector type, ORDINAL, char, a sequence type, or a set-like or map-like type (instead got bool) -ResolutionErrors.dfy(1433,13): Error: type of RHS of assign-such-that statement must be boolean (got int) -ResolutionErrors.dfy(1436,15): Error: type of left argument to + (int) must agree with the result type (bool) -ResolutionErrors.dfy(1436,15): Error: type of right argument to + (int) must agree with the result type (bool) -ResolutionErrors.dfy(1436,15): Error: type of + must be of a numeric type, a bitvector type, ORDINAL, char, a sequence type, or a set-like or map-like type (instead got bool) -ResolutionErrors.dfy(1452,29): Error: in a hint, calls are allowed only to lemmas -ResolutionErrors.dfy(1454,17): Error: in a hint, calls are allowed only to lemmas -ResolutionErrors.dfy(1479,20): Error: in a hint, calls are allowed only to lemmas -ResolutionErrors.dfy(1488,24): Error: in a hint, calls are allowed only to lemmas -ResolutionErrors.dfy(1501,18): Error: assignment to non-ghost field is not allowed in this context, because this is a ghost function -ResolutionErrors.dfy(1502,10): Error: a hint is not allowed to make heap updates -ResolutionErrors.dfy(1503,20): Error: in a hint, calls are allowed only to lemmas -ResolutionErrors.dfy(1506,21): Error: a loop in a hint is not allowed to use 'modifies' clauses -ResolutionErrors.dfy(1523,24): Error: in a hint, calls are allowed only to lemmas -ResolutionErrors.dfy(1530,18): Error: assignment to non-ghost field is not allowed in this context, because the statement is in a ghost context; e.g., it may be guarded by a specification-only expression -ResolutionErrors.dfy(1531,10): Error: a hint is not allowed to make heap updates -ResolutionErrors.dfy(1532,11): Error: in a hint, calls are allowed only to lemmas -ResolutionErrors.dfy(1535,21): Error: a loop in a hint is not allowed to use 'modifies' clauses -ResolutionErrors.dfy(1558,29): Error: in a statement expression, calls are allowed only to lemmas -ResolutionErrors.dfy(1570,16): Error: a possibly infinite loop is allowed only if the enclosing method is declared (with 'decreases *') to be possibly non-terminating -ResolutionErrors.dfy(1588,12): Error: a 'break break break' statement is allowed only in contexts with 3 enclosing loops, but the current context only has 2 -ResolutionErrors.dfy(1600,20): Error: a ghost field is allowed only in specification contexts -ResolutionErrors.dfy(1607,9): Error: ghost variables such as g are allowed only in specification contexts. g was inferred to be ghost based on its declaration or initialization. -ResolutionErrors.dfy(1613,4): Error: non-ghost variable cannot be assigned a value that depends on a ghost -ResolutionErrors.dfy(1630,8): Error: print statement is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression) -ResolutionErrors.dfy(1639,29): Error: ghost variables such as z are allowed only in specification contexts. z was inferred to be ghost based on its declaration or initialization. -ResolutionErrors.dfy(1647,10): Error: the type of the bound variable 't' could not be determined -ResolutionErrors.dfy(1647,10): Error: the type of the bound variable 't' could not be determined -ResolutionErrors.dfy(1647,10): Error: the type of the bound variable 't' could not be determined -ResolutionErrors.dfy(1647,10): Error: the type of the bound variable 't' could not be determined -ResolutionErrors.dfy(1665,15): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) -ResolutionErrors.dfy(1667,10): Error: assignment to non-ghost field is not allowed in this context, because this is a ghost method -ResolutionErrors.dfy(1692,15): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) -ResolutionErrors.dfy(1694,25): Error: assignment to non-ghost variable is not allowed in this context, because the statement is in a ghost context; e.g., it may be guarded by a specification-only expression -ResolutionErrors.dfy(1695,35): Error: assignment to non-ghost variable is not allowed in this context, because the statement is in a ghost context; e.g., it may be guarded by a specification-only expression -ResolutionErrors.dfy(1705,4): Error: 'decreases *' is not allowed on ghost loops -ResolutionErrors.dfy(1709,8): Error: assignment to non-ghost variable is not allowed in this context, because the statement is in a ghost context; e.g., it may be guarded by a specification-only expression -ResolutionErrors.dfy(1719,4): Error: 'decreases *' is not allowed on ghost loops -ResolutionErrors.dfy(1723,29): Error: assignment to non-ghost variable is not allowed in this context, because the statement is in a ghost context; e.g., it may be guarded by a specification-only expression -ResolutionErrors.dfy(1731,21): Error: the type of the bound variable 'u' could not be determined -ResolutionErrors.dfy(1732,23): Error: the type of the bound variable 'u' could not be determined -ResolutionErrors.dfy(1735,27): Error: the type of the bound variable 'u' could not be determined -ResolutionErrors.dfy(1739,40): Error: the type of the bound variable 'u' could not be determined -ResolutionErrors.dfy(1741,38): Error: the type of the bound variable 'u' could not be determined -ResolutionErrors.dfy(1785,19): Error: Type or type parameter is not declared in this scope: realint (did you forget to qualify a name or declare a module import 'opened'?) (note that names in outer modules are not visible in contained modules) -ResolutionErrors.dfy(1793,44): Error: range of comprehension must be of type bool (instead got C) -ResolutionErrors.dfy(1800,21): Error: Duplicate member name: P -ResolutionErrors.dfy(1802,17): Error: Duplicate member name: L -ResolutionErrors.dfy(1810,4): Error: second argument to && must be of type bool (instead got int) -ResolutionErrors.dfy(1808,17): Error: Function body type mismatch (expected int, got bool) -ResolutionErrors.dfy(1814,4): Error: second argument to && must be of type bool (instead got int) -ResolutionErrors.dfy(1818,4): Error: second argument to || must be of type bool (instead got int) -ResolutionErrors.dfy(1816,17): Error: Function body type mismatch (expected int, got bool) -ResolutionErrors.dfy(1822,4): Error: second argument to || must be of type bool (instead got int) -ResolutionErrors.dfy(1826,8): Error: second argument to || must be of type bool (instead got int) -ResolutionErrors.dfy(1824,17): Error: Function body type mismatch (expected int, got bool) -ResolutionErrors.dfy(1847,6): Error: in the first division of the constructor body (before 'new;'), 'this' can only be used to assign to its fields -ResolutionErrors.dfy(1848,11): Error: in the first division of the constructor body (before 'new;'), 'this' can only be used to assign to its fields -ResolutionErrors.dfy(1848,15): Error: in the first division of the constructor body (before 'new;'), 'this' can only be used to assign to its fields -ResolutionErrors.dfy(1849,16): Error: in the first division of the constructor body (before 'new;'), 'this' can only be used to assign to its fields -ResolutionErrors.dfy(1850,6): Error: in the first division of the constructor body (before 'new;'), 'this' can only be used to assign to its fields -ResolutionErrors.dfy(1853,6): Error: in the first division of the constructor body (before 'new;'), 'this' can only be used to assign to its fields -ResolutionErrors.dfy(1854,19): Error: in the first division of the constructor body (before 'new;'), 'this' can only be used to assign to its fields -ResolutionErrors.dfy(1855,8): Error: in the first division of the constructor body (before 'new;'), 'this' can only be used to assign to its fields -ResolutionErrors.dfy(1857,8): Error: in the first division of the constructor body (before 'new;'), 'this' can only be used to assign to its fields -ResolutionErrors.dfy(1858,13): Error: in the first division of the constructor body (before 'new;'), 'this' can only be used to assign to its fields -ResolutionErrors.dfy(1859,13): Error: in the first division of the constructor body (before 'new;'), 'this' can only be used to assign to its fields -ResolutionErrors.dfy(1860,14): Error: in the first division of the constructor body (before 'new;'), 'this' can only be used to assign to its fields -ResolutionErrors.dfy(1891,15): Error: 'this' is not allowed in a 'static' context -ResolutionErrors.dfy(1893,16): Error: 'this' is not allowed in a 'static' context -ResolutionErrors.dfy(1909,8): Error: return statement is not allowed before 'new;' in a constructor -ResolutionErrors.dfy(1935,5): Error: type parameter (G) passed to method P must support auto-initialization (got F) (perhaps try declaring type parameter 'F' on line 1928 as 'F(0)', which says it can only be instantiated with a type that supports auto-initialization) -ResolutionErrors.dfy(1937,5): Error: type parameter (G) passed to method P must support auto-initialization (got Y) (perhaps try declaring abstract type 'Y' on line 1925 as 'Y(0)', which says it can only be instantiated with a type that supports auto-initialization) -ResolutionErrors.dfy(1974,5): Error: type parameter (G) passed to method P must support auto-initialization (got SixOrMore) -ResolutionErrors.dfy(1975,5): Error: type parameter (G) passed to method P must support auto-initialization (got AnotherSixOrMore) -ResolutionErrors.dfy(1976,5): Error: type parameter (G) passed to method P must support auto-initialization (got MySixOrMore) -ResolutionErrors.dfy(1977,5): Error: type parameter (G) passed to method P must support auto-initialization (got UnclearA) -ResolutionErrors.dfy(1993,17): Error: type parameter (G) passed to method P must support auto-initialization (got SSixOrMore) -ResolutionErrors.dfy(1994,24): Error: type parameter (G) passed to method P must support auto-initialization (got SAnotherSixOrMore) -ResolutionErrors.dfy(1995,19): Error: type parameter (G) passed to method P must support auto-initialization (got SMySixOrMore) -ResolutionErrors.dfy(1996,16): Error: type parameter (G) passed to method P must support auto-initialization (got SUnclearA) -ResolutionErrors.dfy(2026,7): Error: type 'B2', which does not support auto-initialization, is used to refine an abstract type that expects auto-initialization -ResolutionErrors.dfy(2027,7): Error: type 'B3', which does not support auto-initialization, is used to refine an abstract type that expects auto-initialization -ResolutionErrors.dfy(2031,7): Error: type 'C3', which may be empty, is used to refine an abstract type expected to be nonempty -ResolutionErrors.dfy(2061,4): Error: type parameter 'Q' is not allowed to change the requirement of supporting auto-initialization -ResolutionErrors.dfy(2064,4): Error: type parameter 'R' is not allowed to change the requirement of supporting auto-initialization -ResolutionErrors.dfy(2051,7): Error: type declaration 'A1' is not allowed to change the requirement of supporting auto-initialization -ResolutionErrors.dfy(2052,7): Error: type declaration 'A2' is not allowed to change the requirement of being nonempty -ResolutionErrors.dfy(2053,7): Error: type declaration 'B0' is not allowed to change the requirement of supporting auto-initialization -ResolutionErrors.dfy(2055,7): Error: type declaration 'B2' is not allowed to change the requirement of supporting auto-initialization -ResolutionErrors.dfy(2056,7): Error: type declaration 'C0' is not allowed to change the requirement of being nonempty -ResolutionErrors.dfy(2057,7): Error: type declaration 'C1' is not allowed to change the requirement of supporting auto-initialization -ResolutionErrors.dfy(2047,5): Error: type parameter (G) passed to method P must support auto-initialization (got Z.XYZ) -ResolutionErrors.dfy(2110,33): Error: type of yield-parameter must support auto-initialization (got 'T') -ResolutionErrors.dfy(2118,13): Error: a ghost function is allowed only in specification contexts -ResolutionErrors.dfy(2132,8): Error: an ORDINAL type is not allowed to be used as a type argument +ResolutionErrors.dfy(1271,29): Error: type of bound variable 'c' could not be determined; please specify the type explicitly +ResolutionErrors.dfy(1282,21): Error: Type or type parameter is not declared in this scope: X (did you forget to qualify a name or declare a module import 'opened'?) (note that names in outer modules are not visible in contained modules) +ResolutionErrors.dfy(1283,24): Error: Type or type parameter is not declared in this scope: X (did you forget to qualify a name or declare a module import 'opened'?) (note that names in outer modules are not visible in contained modules) +ResolutionErrors.dfy(1320,16): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (y) +ResolutionErrors.dfy(1337,18): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) +ResolutionErrors.dfy(1365,15): Error: The name Inner ambiguously refers to a type in one of the modules A, B (try qualifying the type name with the module name) +ResolutionErrors.dfy(1375,29): Error: ghost variables such as tmp are allowed only in specification contexts. tmp was inferred to be ghost based on its declaration or initialization. +ResolutionErrors.dfy(1377,49): Error: ghost variables such as a0 are allowed only in specification contexts. a0 was inferred to be ghost based on its declaration or initialization. +ResolutionErrors.dfy(1377,54): Error: ghost variables such as a1 are allowed only in specification contexts. a1 was inferred to be ghost based on its declaration or initialization. +ResolutionErrors.dfy(1386,33): Error: set argument type must support equality (got (int, int -> bool)) +ResolutionErrors.dfy(1398,11): Error: name of type (X) is used as a variable +ResolutionErrors.dfy(1398,16): Error: name of type (X) is used as a variable +ResolutionErrors.dfy(1399,11): Error: name of module (Y) is used as a variable +ResolutionErrors.dfy(1399,16): Error: name of module (Y) is used as a variable +ResolutionErrors.dfy(1400,11): Error: name of type (X) is used as a variable +ResolutionErrors.dfy(1401,11): Error: name of module (Y) is used as a variable +ResolutionErrors.dfy(1406,16): Error: name of type (X) is used as a variable +ResolutionErrors.dfy(1407,16): Error: name of module (Y) is used as a variable +ResolutionErrors.dfy(1408,4): Error: name of type (X) is used as a variable +ResolutionErrors.dfy(1409,4): Error: name of module (Y) is used as a variable +ResolutionErrors.dfy(1419,9): Error: type of RHS of assign-such-that statement must be boolean (got int) +ResolutionErrors.dfy(1418,11): Error: type of left argument to + (int) must agree with the result type (bool) +ResolutionErrors.dfy(1418,11): Error: type of right argument to + (int) must agree with the result type (bool) +ResolutionErrors.dfy(1418,11): Error: type of + must be of a numeric type, a bitvector type, ORDINAL, char, a sequence type, or a set-like or map-like type (instead got bool) +ResolutionErrors.dfy(1420,13): Error: type of RHS of assign-such-that statement must be boolean (got int) +ResolutionErrors.dfy(1423,15): Error: type of left argument to + (int) must agree with the result type (bool) +ResolutionErrors.dfy(1423,15): Error: type of right argument to + (int) must agree with the result type (bool) +ResolutionErrors.dfy(1423,15): Error: type of + must be of a numeric type, a bitvector type, ORDINAL, char, a sequence type, or a set-like or map-like type (instead got bool) +ResolutionErrors.dfy(1439,29): Error: in a hint, calls are allowed only to lemmas +ResolutionErrors.dfy(1441,17): Error: in a hint, calls are allowed only to lemmas +ResolutionErrors.dfy(1466,20): Error: in a hint, calls are allowed only to lemmas +ResolutionErrors.dfy(1475,24): Error: in a hint, calls are allowed only to lemmas +ResolutionErrors.dfy(1488,18): Error: assignment to non-ghost field is not allowed in this context, because this is a ghost function +ResolutionErrors.dfy(1489,10): Error: a hint is not allowed to make heap updates +ResolutionErrors.dfy(1490,20): Error: in a hint, calls are allowed only to lemmas +ResolutionErrors.dfy(1493,21): Error: a loop in a hint is not allowed to use 'modifies' clauses +ResolutionErrors.dfy(1510,24): Error: in a hint, calls are allowed only to lemmas +ResolutionErrors.dfy(1517,18): Error: assignment to non-ghost field is not allowed in this context, because the statement is in a ghost context; e.g., it may be guarded by a specification-only expression +ResolutionErrors.dfy(1518,10): Error: a hint is not allowed to make heap updates +ResolutionErrors.dfy(1519,11): Error: in a hint, calls are allowed only to lemmas +ResolutionErrors.dfy(1522,21): Error: a loop in a hint is not allowed to use 'modifies' clauses +ResolutionErrors.dfy(1545,29): Error: in a statement expression, calls are allowed only to lemmas +ResolutionErrors.dfy(1557,16): Error: a possibly infinite loop is allowed only if the enclosing method is declared (with 'decreases *') to be possibly non-terminating +ResolutionErrors.dfy(1575,12): Error: a 'break break break' statement is allowed only in contexts with 3 enclosing loops, but the current context only has 2 +ResolutionErrors.dfy(1587,20): Error: a ghost field is allowed only in specification contexts +ResolutionErrors.dfy(1594,9): Error: ghost variables such as g are allowed only in specification contexts. g was inferred to be ghost based on its declaration or initialization. +ResolutionErrors.dfy(1600,4): Error: non-ghost variable cannot be assigned a value that depends on a ghost +ResolutionErrors.dfy(1617,8): Error: print statement is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression) +ResolutionErrors.dfy(1626,29): Error: ghost variables such as z are allowed only in specification contexts. z was inferred to be ghost based on its declaration or initialization. +ResolutionErrors.dfy(1634,10): Error: the type of the bound variable 't' could not be determined +ResolutionErrors.dfy(1634,10): Error: the type of the bound variable 't' could not be determined +ResolutionErrors.dfy(1634,10): Error: the type of the bound variable 't' could not be determined +ResolutionErrors.dfy(1634,10): Error: the type of the bound variable 't' could not be determined +ResolutionErrors.dfy(1652,15): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) +ResolutionErrors.dfy(1654,10): Error: assignment to non-ghost field is not allowed in this context, because this is a ghost method +ResolutionErrors.dfy(1679,15): Error: in a ghost context, only ghost fields can be mentioned as modifies frame targets (x) +ResolutionErrors.dfy(1681,25): Error: assignment to non-ghost variable is not allowed in this context, because the statement is in a ghost context; e.g., it may be guarded by a specification-only expression +ResolutionErrors.dfy(1682,35): Error: assignment to non-ghost variable is not allowed in this context, because the statement is in a ghost context; e.g., it may be guarded by a specification-only expression +ResolutionErrors.dfy(1692,4): Error: 'decreases *' is not allowed on ghost loops +ResolutionErrors.dfy(1696,8): Error: assignment to non-ghost variable is not allowed in this context, because the statement is in a ghost context; e.g., it may be guarded by a specification-only expression +ResolutionErrors.dfy(1706,4): Error: 'decreases *' is not allowed on ghost loops +ResolutionErrors.dfy(1710,29): Error: assignment to non-ghost variable is not allowed in this context, because the statement is in a ghost context; e.g., it may be guarded by a specification-only expression +ResolutionErrors.dfy(1718,21): Error: the type of the bound variable 'u' could not be determined +ResolutionErrors.dfy(1719,23): Error: the type of the bound variable 'u' could not be determined +ResolutionErrors.dfy(1722,27): Error: the type of the bound variable 'u' could not be determined +ResolutionErrors.dfy(1726,40): Error: the type of the bound variable 'u' could not be determined +ResolutionErrors.dfy(1728,38): Error: the type of the bound variable 'u' could not be determined +ResolutionErrors.dfy(1772,19): Error: Type or type parameter is not declared in this scope: realint (did you forget to qualify a name or declare a module import 'opened'?) (note that names in outer modules are not visible in contained modules) +ResolutionErrors.dfy(1780,44): Error: range of comprehension must be of type bool (instead got C) +ResolutionErrors.dfy(1787,21): Error: Duplicate member name: P +ResolutionErrors.dfy(1789,17): Error: Duplicate member name: L +ResolutionErrors.dfy(1797,4): Error: second argument to && must be of type bool (instead got int) +ResolutionErrors.dfy(1795,17): Error: Function body type mismatch (expected int, got bool) +ResolutionErrors.dfy(1801,4): Error: second argument to && must be of type bool (instead got int) +ResolutionErrors.dfy(1805,4): Error: second argument to || must be of type bool (instead got int) +ResolutionErrors.dfy(1803,17): Error: Function body type mismatch (expected int, got bool) +ResolutionErrors.dfy(1809,4): Error: second argument to || must be of type bool (instead got int) +ResolutionErrors.dfy(1813,8): Error: second argument to || must be of type bool (instead got int) +ResolutionErrors.dfy(1811,17): Error: Function body type mismatch (expected int, got bool) +ResolutionErrors.dfy(1834,6): Error: in the first division of the constructor body (before 'new;'), 'this' can only be used to assign to its fields +ResolutionErrors.dfy(1835,11): Error: in the first division of the constructor body (before 'new;'), 'this' can only be used to assign to its fields +ResolutionErrors.dfy(1835,15): Error: in the first division of the constructor body (before 'new;'), 'this' can only be used to assign to its fields +ResolutionErrors.dfy(1836,16): Error: in the first division of the constructor body (before 'new;'), 'this' can only be used to assign to its fields +ResolutionErrors.dfy(1837,6): Error: in the first division of the constructor body (before 'new;'), 'this' can only be used to assign to its fields +ResolutionErrors.dfy(1840,6): Error: in the first division of the constructor body (before 'new;'), 'this' can only be used to assign to its fields +ResolutionErrors.dfy(1841,19): Error: in the first division of the constructor body (before 'new;'), 'this' can only be used to assign to its fields +ResolutionErrors.dfy(1842,8): Error: in the first division of the constructor body (before 'new;'), 'this' can only be used to assign to its fields +ResolutionErrors.dfy(1844,8): Error: in the first division of the constructor body (before 'new;'), 'this' can only be used to assign to its fields +ResolutionErrors.dfy(1845,13): Error: in the first division of the constructor body (before 'new;'), 'this' can only be used to assign to its fields +ResolutionErrors.dfy(1846,13): Error: in the first division of the constructor body (before 'new;'), 'this' can only be used to assign to its fields +ResolutionErrors.dfy(1847,14): Error: in the first division of the constructor body (before 'new;'), 'this' can only be used to assign to its fields +ResolutionErrors.dfy(1878,15): Error: 'this' is not allowed in a 'static' context +ResolutionErrors.dfy(1880,16): Error: 'this' is not allowed in a 'static' context +ResolutionErrors.dfy(1896,8): Error: return statement is not allowed before 'new;' in a constructor +ResolutionErrors.dfy(1922,5): Error: type parameter (G) passed to method P must support auto-initialization (got F) (perhaps try declaring type parameter 'F' on line 1915 as 'F(0)', which says it can only be instantiated with a type that supports auto-initialization) +ResolutionErrors.dfy(1924,5): Error: type parameter (G) passed to method P must support auto-initialization (got Y) (perhaps try declaring abstract type 'Y' on line 1912 as 'Y(0)', which says it can only be instantiated with a type that supports auto-initialization) +ResolutionErrors.dfy(1961,5): Error: type parameter (G) passed to method P must support auto-initialization (got SixOrMore) +ResolutionErrors.dfy(1962,5): Error: type parameter (G) passed to method P must support auto-initialization (got AnotherSixOrMore) +ResolutionErrors.dfy(1963,5): Error: type parameter (G) passed to method P must support auto-initialization (got MySixOrMore) +ResolutionErrors.dfy(1964,5): Error: type parameter (G) passed to method P must support auto-initialization (got UnclearA) +ResolutionErrors.dfy(1980,17): Error: type parameter (G) passed to method P must support auto-initialization (got SSixOrMore) +ResolutionErrors.dfy(1981,24): Error: type parameter (G) passed to method P must support auto-initialization (got SAnotherSixOrMore) +ResolutionErrors.dfy(1982,19): Error: type parameter (G) passed to method P must support auto-initialization (got SMySixOrMore) +ResolutionErrors.dfy(1983,16): Error: type parameter (G) passed to method P must support auto-initialization (got SUnclearA) +ResolutionErrors.dfy(2013,7): Error: type 'B2', which does not support auto-initialization, is used to refine an abstract type that expects auto-initialization +ResolutionErrors.dfy(2014,7): Error: type 'B3', which does not support auto-initialization, is used to refine an abstract type that expects auto-initialization +ResolutionErrors.dfy(2018,7): Error: type 'C3', which may be empty, is used to refine an abstract type expected to be nonempty +ResolutionErrors.dfy(2048,4): Error: type parameter 'Q' is not allowed to change the requirement of supporting auto-initialization +ResolutionErrors.dfy(2051,4): Error: type parameter 'R' is not allowed to change the requirement of supporting auto-initialization +ResolutionErrors.dfy(2038,7): Error: type declaration 'A1' is not allowed to change the requirement of supporting auto-initialization +ResolutionErrors.dfy(2039,7): Error: type declaration 'A2' is not allowed to change the requirement of being nonempty +ResolutionErrors.dfy(2040,7): Error: type declaration 'B0' is not allowed to change the requirement of supporting auto-initialization +ResolutionErrors.dfy(2042,7): Error: type declaration 'B2' is not allowed to change the requirement of supporting auto-initialization +ResolutionErrors.dfy(2043,7): Error: type declaration 'C0' is not allowed to change the requirement of being nonempty +ResolutionErrors.dfy(2044,7): Error: type declaration 'C1' is not allowed to change the requirement of supporting auto-initialization +ResolutionErrors.dfy(2034,5): Error: type parameter (G) passed to method P must support auto-initialization (got Z.XYZ) +ResolutionErrors.dfy(2097,33): Error: type of yield-parameter must support auto-initialization (got 'T') +ResolutionErrors.dfy(2105,13): Error: a ghost function is allowed only in specification contexts +ResolutionErrors.dfy(2119,8): Error: an ORDINAL type is not allowed to be used as a type argument +ResolutionErrors.dfy(2120,8): Error: an ORDINAL type is not allowed to be used as a type argument +ResolutionErrors.dfy(2122,19): Error: type parameter 'G' (passed in as 'ORDINAL') to function call 'F' is not allowed to use ORDINAL +ResolutionErrors.dfy(2123,9): Error: type parameter 'G' (passed in as 'ORDINAL') to function call 'F'' is not allowed to use ORDINAL +ResolutionErrors.dfy(2124,9): Error: type parameter 'G' (passed in as '(char, ORDINAL)') to function call 'F'' is not allowed to use ORDINAL +ResolutionErrors.dfy(2125,18): Error: type parameter 'G' (passed in as 'ORDINAL') to the function 'F'' is not allowed to use ORDINAL +ResolutionErrors.dfy(2126,4): Error: type parameter 'G' (passed in as 'ORDINAL') to the method 'ParameterizedMethod' is not allowed to use ORDINAL +ResolutionErrors.dfy(2130,8): Error: an ORDINAL type is not allowed to be used as a type argument +ResolutionErrors.dfy(2132,14): Error: an ORDINAL type is not allowed to be used as a type argument ResolutionErrors.dfy(2133,8): Error: an ORDINAL type is not allowed to be used as a type argument -ResolutionErrors.dfy(2135,19): Error: type parameter 'G' (passed in as 'ORDINAL') to function call 'F' is not allowed to use ORDINAL -ResolutionErrors.dfy(2136,9): Error: type parameter 'G' (passed in as 'ORDINAL') to function call 'F'' is not allowed to use ORDINAL -ResolutionErrors.dfy(2137,9): Error: type parameter 'G' (passed in as '(char, ORDINAL)') to function call 'F'' is not allowed to use ORDINAL -ResolutionErrors.dfy(2138,18): Error: type parameter 'G' (passed in as 'ORDINAL') to the function 'F'' is not allowed to use ORDINAL -ResolutionErrors.dfy(2139,4): Error: type parameter 'G' (passed in as 'ORDINAL') to the method 'ParameterizedMethod' is not allowed to use ORDINAL -ResolutionErrors.dfy(2143,8): Error: an ORDINAL type is not allowed to be used as a type argument -ResolutionErrors.dfy(2145,14): Error: an ORDINAL type is not allowed to be used as a type argument -ResolutionErrors.dfy(2146,8): Error: an ORDINAL type is not allowed to be used as a type argument -ResolutionErrors.dfy(2147,8): Error: an ORDINAL type is not allowed to be used as a type argument -ResolutionErrors.dfy(2148,8): Error: an ORDINAL type is not allowed to be used as a type argument -ResolutionErrors.dfy(2150,8): Error: an ORDINAL type is not allowed to be used as a type argument -ResolutionErrors.dfy(2153,8): Error: an ORDINAL type is not allowed to be used as a type argument -ResolutionErrors.dfy(2153,8): Error: an ORDINAL type is not allowed to be used as a type argument -ResolutionErrors.dfy(2154,8): Error: an ORDINAL type is not allowed to be used as a type argument -ResolutionErrors.dfy(2154,8): Error: an ORDINAL type is not allowed to be used as a type argument -ResolutionErrors.dfy(2154,8): Error: an ORDINAL type is not allowed to be used as a type argument -ResolutionErrors.dfy(2154,8): Error: an ORDINAL type is not allowed to be used as a type argument -ResolutionErrors.dfy(2156,25): Error: an ORDINAL type is not allowed to be used as a type argument -ResolutionErrors.dfy(2182,36): Error: Name of yield-parameter is used by another member of the iterator: u -ResolutionErrors.dfy(2183,37): Error: Name of implicit yield-history variable 'u' is already used by another member of the iterator -ResolutionErrors.dfy(2207,15): Error: To access members of class 'MyClass', write 'MyClass', not 'MyClass?' -ResolutionErrors.dfy(2218,15): Error: name of type (MyClass) is used as a variable -ResolutionErrors.dfy(2219,15): Error: name of type (MyClass?) is used as a variable -ResolutionErrors.dfy(2232,17): Error: To access members of class 'MyClass', write 'MyClass', not 'MyClass?' -ResolutionErrors.dfy(2243,17): Error: name of type (MyClass) is used as a variable -ResolutionErrors.dfy(2244,17): Error: name of type (MyClass?) is used as a variable -ResolutionErrors.dfy(2253,8): Error: static non-ghost const field 'X' of type 'Odd' (which does not have a default compiled value) must give a defining value -ResolutionErrors.dfy(2256,8): Error: static non-ghost const field 'Y' of type 'MyClass' (which does not have a default compiled value) must give a defining value -ResolutionErrors.dfy(2257,14): Error: static ghost const field 'Y'' of type 'MyClass' (which may be empty) must give a defining value -ResolutionErrors.dfy(2261,17): Error: static non-ghost const field 'W' of type 'MyClass' (which does not have a default compiled value) must give a defining value -ResolutionErrors.dfy(2263,17): Error: static non-ghost const field 'O' of type 'Odd' (which does not have a default compiled value) must give a defining value -ResolutionErrors.dfy(2269,17): Error: static non-ghost const field 'W' of type 'MyClass' (which does not have a default compiled value) must give a defining value -ResolutionErrors.dfy(2271,17): Error: static non-ghost const field 'O' of type 'Odd' (which does not have a default compiled value) must give a defining value -ResolutionErrors.dfy(2279,8): Error: class 'Instance' with fields without known initializers, like 'w' of type 'MyClass', must declare a constructor -ResolutionErrors.dfy(2285,8): Error: class 'GhostCl' with fields without known initializers, like 'z' of type 'MyClass', must declare a constructor -ResolutionErrors.dfy(2295,6): Error: LHS of assignment must denote a mutable field -ResolutionErrors.dfy(2296,10): Error: LHS of assignment must denote a mutable field -ResolutionErrors.dfy(2303,6): Error: LHS of assignment must denote a mutable field -ResolutionErrors.dfy(2310,8): Error: LHS of assignment must denote a mutable field of 'this' -ResolutionErrors.dfy(2327,18): Error: a ghost const field is allowed only in specification contexts -ResolutionErrors.dfy(2324,20): Error: a ghost const field is allowed only in specification contexts -ResolutionErrors.dfy(2343,9): Error: quantifiers in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'i' -ResolutionErrors.dfy(2346,9): Error: quantifiers in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'i' -ResolutionErrors.dfy(2354,22): Error: a set comprehension involved in a const field definition is not allowed to depend on the set of allocated references, but values of 'c' (of type 'Class') may contain references (see documentation for 'older' parameters) -ResolutionErrors.dfy(2352,24): Error: a set comprehension involved in a const field definition is not allowed to depend on the set of allocated references, but values of 'c' (of type 'Class') may contain references (see documentation for 'older' parameters) -ResolutionErrors.dfy(2355,36): Error: a set comprehension involved in a newtype definition is not allowed to depend on the set of allocated references, but values of 'c' (of type 'Class') may contain references (see documentation for 'older' parameters) -ResolutionErrors.dfy(2356,34): Error: a set comprehension involved in a subset type definition is not allowed to depend on the set of allocated references, but values of 'c' (of type 'Class') may contain references (see documentation for 'older' parameters) -ResolutionErrors.dfy(2361,18): Error: set comprehensions in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'c' -ResolutionErrors.dfy(2362,18): Error: set comprehensions in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'c' -ResolutionErrors.dfy(2368,19): Error: a set comprehension involved in a predicate definition is not allowed to depend on the set of allocated references, but values of 'c' (of type 'Class') may contain references (see documentation for 'older' parameters) -ResolutionErrors.dfy(2376,35): Error: a const field definition is not allowed to depend on the set of allocated references -ResolutionErrors.dfy(2374,37): Error: a const field definition is not allowed to depend on the set of allocated references -ResolutionErrors.dfy(2377,49): Error: a newtype definition is not allowed to depend on the set of allocated references -ResolutionErrors.dfy(2378,47): Error: a subset type definition is not allowed to depend on the set of allocated references -ResolutionErrors.dfy(2383,32): Error: a predicate definition is not allowed to depend on the set of allocated references -ResolutionErrors.dfy(2391,39): Error: a const field definition is not allowed to depend on the set of allocated references -ResolutionErrors.dfy(2389,41): Error: a const field definition is not allowed to depend on the set of allocated references -ResolutionErrors.dfy(2392,53): Error: a newtype definition is not allowed to depend on the set of allocated references -ResolutionErrors.dfy(2393,51): Error: a subset type definition is not allowed to depend on the set of allocated references -ResolutionErrors.dfy(2398,36): Error: a predicate definition is not allowed to depend on the set of allocated references -ResolutionErrors.dfy(2405,31): Error: the value returned by an abstemious function must come from invoking a co-constructor -ResolutionErrors.dfy(2441,31): Error: the value returned by an abstemious function must come from invoking a co-constructor -ResolutionErrors.dfy(2448,32): Error: an abstemious function is allowed to invoke a codatatype destructor only on its parameters -ResolutionErrors.dfy(2453,12): Error: an abstemious function is allowed to codatatype-match only on its parameters -ResolutionErrors.dfy(2460,9): Error: an abstemious function is not allowed to check codatatype equality -ResolutionErrors.dfy(2462,14): Error: an abstemious function is not allowed to check codatatype equality -ResolutionErrors.dfy(2487,19): Error: type parameter 'G' (passed in as 'ORDINAL') to function call 'F' is not allowed to use ORDINAL -ResolutionErrors.dfy(2488,13): Error: type parameter 'G' (passed in as 'ORDINAL') to function call 'F'' is not allowed to use ORDINAL -ResolutionErrors.dfy(2489,13): Error: type parameter 'G' (passed in as '(char, ORDINAL)') to function call 'F'' is not allowed to use ORDINAL -ResolutionErrors.dfy(2490,18): Error: type parameter 'G' (passed in as 'ORDINAL') to the function 'F'' is not allowed to use ORDINAL -ResolutionErrors.dfy(2491,4): Error: type parameter 'G' (passed in as 'ORDINAL') to the lemma 'ParameterizedLemma' is not allowed to use ORDINAL -ResolutionErrors.dfy(2492,18): Error: type of bound variable 'r' ('ORDINAL') is not allowed to use type ORDINAL -ResolutionErrors.dfy(2493,18): Error: type of bound variable 'r' ('(ORDINAL, int)') is not allowed to use type ORDINAL -ResolutionErrors.dfy(2494,26): Error: type of bound variable 'r' ('ORDINAL') is not allowed to use type ORDINAL -ResolutionErrors.dfy(2495,17): Error: type of bound variable 'r' ('ORDINAL') is not allowed to use type ORDINAL -ResolutionErrors.dfy(2496,18): Error: type of bound variable 'r' ('ORDINAL') is not allowed to use type ORDINAL -ResolutionErrors.dfy(2497,24): Error: type of bound variable 'r' ('ORDINAL') is not allowed to use type ORDINAL -ResolutionErrors.dfy(2508,25): Error: an ORDINAL type is not allowed to be used as a type argument -ResolutionErrors.dfy(2509,17): Error: type of bound variable 'yt' ('ORDINAL') is not allowed to use type ORDINAL -ResolutionErrors.dfy(2506,8): Error: an ORDINAL type is not allowed to be used as a type argument -ResolutionErrors.dfy(2506,8): Error: an ORDINAL type is not allowed to be used as a type argument -ResolutionErrors.dfy(2505,8): Error: an ORDINAL type is not allowed to be used as a type argument -ResolutionErrors.dfy(2502,8): Error: an ORDINAL type is not allowed to be used as a type argument -ResolutionErrors.dfy(2500,8): Error: an ORDINAL type is not allowed to be used as a type argument -ResolutionErrors.dfy(2499,8): Error: an ORDINAL type is not allowed to be used as a type argument -ResolutionErrors.dfy(2498,8): Error: an ORDINAL type is not allowed to be used as a type argument -ResolutionErrors.dfy(2497,14): Error: an ORDINAL type is not allowed to be used as a type argument -ResolutionErrors.dfy(2495,8): Error: an ORDINAL type is not allowed to be used as a type argument +ResolutionErrors.dfy(2134,8): Error: an ORDINAL type is not allowed to be used as a type argument +ResolutionErrors.dfy(2135,8): Error: an ORDINAL type is not allowed to be used as a type argument +ResolutionErrors.dfy(2137,8): Error: an ORDINAL type is not allowed to be used as a type argument +ResolutionErrors.dfy(2140,8): Error: an ORDINAL type is not allowed to be used as a type argument +ResolutionErrors.dfy(2140,8): Error: an ORDINAL type is not allowed to be used as a type argument +ResolutionErrors.dfy(2141,8): Error: an ORDINAL type is not allowed to be used as a type argument +ResolutionErrors.dfy(2141,8): Error: an ORDINAL type is not allowed to be used as a type argument +ResolutionErrors.dfy(2141,8): Error: an ORDINAL type is not allowed to be used as a type argument +ResolutionErrors.dfy(2141,8): Error: an ORDINAL type is not allowed to be used as a type argument +ResolutionErrors.dfy(2143,25): Error: an ORDINAL type is not allowed to be used as a type argument +ResolutionErrors.dfy(2169,36): Error: Name of yield-parameter is used by another member of the iterator: u +ResolutionErrors.dfy(2170,37): Error: Name of implicit yield-history variable 'u' is already used by another member of the iterator +ResolutionErrors.dfy(2194,15): Error: To access members of class 'MyClass', write 'MyClass', not 'MyClass?' +ResolutionErrors.dfy(2205,15): Error: name of type (MyClass) is used as a variable +ResolutionErrors.dfy(2206,15): Error: name of type (MyClass?) is used as a variable +ResolutionErrors.dfy(2219,17): Error: To access members of class 'MyClass', write 'MyClass', not 'MyClass?' +ResolutionErrors.dfy(2230,17): Error: name of type (MyClass) is used as a variable +ResolutionErrors.dfy(2231,17): Error: name of type (MyClass?) is used as a variable +ResolutionErrors.dfy(2240,8): Error: static non-ghost const field 'X' of type 'Odd' (which does not have a default compiled value) must give a defining value +ResolutionErrors.dfy(2243,8): Error: static non-ghost const field 'Y' of type 'MyClass' (which does not have a default compiled value) must give a defining value +ResolutionErrors.dfy(2244,14): Error: static ghost const field 'Y'' of type 'MyClass' (which may be empty) must give a defining value +ResolutionErrors.dfy(2248,17): Error: static non-ghost const field 'W' of type 'MyClass' (which does not have a default compiled value) must give a defining value +ResolutionErrors.dfy(2250,17): Error: static non-ghost const field 'O' of type 'Odd' (which does not have a default compiled value) must give a defining value +ResolutionErrors.dfy(2256,17): Error: static non-ghost const field 'W' of type 'MyClass' (which does not have a default compiled value) must give a defining value +ResolutionErrors.dfy(2258,17): Error: static non-ghost const field 'O' of type 'Odd' (which does not have a default compiled value) must give a defining value +ResolutionErrors.dfy(2266,8): Error: class 'Instance' with fields without known initializers, like 'w' of type 'MyClass', must declare a constructor +ResolutionErrors.dfy(2272,8): Error: class 'GhostCl' with fields without known initializers, like 'z' of type 'MyClass', must declare a constructor +ResolutionErrors.dfy(2282,6): Error: LHS of assignment must denote a mutable field +ResolutionErrors.dfy(2283,10): Error: LHS of assignment must denote a mutable field +ResolutionErrors.dfy(2290,6): Error: LHS of assignment must denote a mutable field +ResolutionErrors.dfy(2297,8): Error: LHS of assignment must denote a mutable field of 'this' +ResolutionErrors.dfy(2314,18): Error: a ghost const field is allowed only in specification contexts +ResolutionErrors.dfy(2311,20): Error: a ghost const field is allowed only in specification contexts +ResolutionErrors.dfy(2330,9): Error: quantifiers in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'i' +ResolutionErrors.dfy(2333,9): Error: quantifiers in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'i' +ResolutionErrors.dfy(2341,22): Error: a set comprehension involved in a const field definition is not allowed to depend on the set of allocated references, but values of 'c' (of type 'Class') may contain references (see documentation for 'older' parameters) +ResolutionErrors.dfy(2339,24): Error: a set comprehension involved in a const field definition is not allowed to depend on the set of allocated references, but values of 'c' (of type 'Class') may contain references (see documentation for 'older' parameters) +ResolutionErrors.dfy(2342,36): Error: a set comprehension involved in a newtype definition is not allowed to depend on the set of allocated references, but values of 'c' (of type 'Class') may contain references (see documentation for 'older' parameters) +ResolutionErrors.dfy(2343,34): Error: a set comprehension involved in a subset type definition is not allowed to depend on the set of allocated references, but values of 'c' (of type 'Class') may contain references (see documentation for 'older' parameters) +ResolutionErrors.dfy(2348,18): Error: set comprehensions in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'c' +ResolutionErrors.dfy(2349,18): Error: set comprehensions in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'c' +ResolutionErrors.dfy(2355,19): Error: a set comprehension involved in a predicate definition is not allowed to depend on the set of allocated references, but values of 'c' (of type 'Class') may contain references (see documentation for 'older' parameters) +ResolutionErrors.dfy(2363,35): Error: a const field definition is not allowed to depend on the set of allocated references +ResolutionErrors.dfy(2361,37): Error: a const field definition is not allowed to depend on the set of allocated references +ResolutionErrors.dfy(2364,49): Error: a newtype definition is not allowed to depend on the set of allocated references +ResolutionErrors.dfy(2365,47): Error: a subset type definition is not allowed to depend on the set of allocated references +ResolutionErrors.dfy(2370,32): Error: a predicate definition is not allowed to depend on the set of allocated references +ResolutionErrors.dfy(2378,39): Error: a const field definition is not allowed to depend on the set of allocated references +ResolutionErrors.dfy(2376,41): Error: a const field definition is not allowed to depend on the set of allocated references +ResolutionErrors.dfy(2379,53): Error: a newtype definition is not allowed to depend on the set of allocated references +ResolutionErrors.dfy(2380,51): Error: a subset type definition is not allowed to depend on the set of allocated references +ResolutionErrors.dfy(2385,36): Error: a predicate definition is not allowed to depend on the set of allocated references +ResolutionErrors.dfy(2392,31): Error: the value returned by an abstemious function must come from invoking a co-constructor +ResolutionErrors.dfy(2428,31): Error: the value returned by an abstemious function must come from invoking a co-constructor +ResolutionErrors.dfy(2435,32): Error: an abstemious function is allowed to invoke a codatatype destructor only on its parameters +ResolutionErrors.dfy(2440,12): Error: an abstemious function is allowed to codatatype-match only on its parameters +ResolutionErrors.dfy(2447,9): Error: an abstemious function is not allowed to check codatatype equality +ResolutionErrors.dfy(2449,14): Error: an abstemious function is not allowed to check codatatype equality +ResolutionErrors.dfy(2474,19): Error: type parameter 'G' (passed in as 'ORDINAL') to function call 'F' is not allowed to use ORDINAL +ResolutionErrors.dfy(2475,13): Error: type parameter 'G' (passed in as 'ORDINAL') to function call 'F'' is not allowed to use ORDINAL +ResolutionErrors.dfy(2476,13): Error: type parameter 'G' (passed in as '(char, ORDINAL)') to function call 'F'' is not allowed to use ORDINAL +ResolutionErrors.dfy(2477,18): Error: type parameter 'G' (passed in as 'ORDINAL') to the function 'F'' is not allowed to use ORDINAL +ResolutionErrors.dfy(2478,4): Error: type parameter 'G' (passed in as 'ORDINAL') to the lemma 'ParameterizedLemma' is not allowed to use ORDINAL +ResolutionErrors.dfy(2479,18): Error: type of bound variable 'r' ('ORDINAL') is not allowed to use type ORDINAL +ResolutionErrors.dfy(2480,18): Error: type of bound variable 'r' ('(ORDINAL, int)') is not allowed to use type ORDINAL +ResolutionErrors.dfy(2481,26): Error: type of bound variable 'r' ('ORDINAL') is not allowed to use type ORDINAL +ResolutionErrors.dfy(2482,17): Error: type of bound variable 'r' ('ORDINAL') is not allowed to use type ORDINAL +ResolutionErrors.dfy(2483,18): Error: type of bound variable 'r' ('ORDINAL') is not allowed to use type ORDINAL +ResolutionErrors.dfy(2484,24): Error: type of bound variable 'r' ('ORDINAL') is not allowed to use type ORDINAL +ResolutionErrors.dfy(2495,25): Error: an ORDINAL type is not allowed to be used as a type argument +ResolutionErrors.dfy(2496,17): Error: type of bound variable 'yt' ('ORDINAL') is not allowed to use type ORDINAL +ResolutionErrors.dfy(2493,8): Error: an ORDINAL type is not allowed to be used as a type argument +ResolutionErrors.dfy(2493,8): Error: an ORDINAL type is not allowed to be used as a type argument +ResolutionErrors.dfy(2492,8): Error: an ORDINAL type is not allowed to be used as a type argument +ResolutionErrors.dfy(2489,8): Error: an ORDINAL type is not allowed to be used as a type argument +ResolutionErrors.dfy(2487,8): Error: an ORDINAL type is not allowed to be used as a type argument +ResolutionErrors.dfy(2486,8): Error: an ORDINAL type is not allowed to be used as a type argument ResolutionErrors.dfy(2485,8): Error: an ORDINAL type is not allowed to be used as a type argument -ResolutionErrors.dfy(2484,8): Error: an ORDINAL type is not allowed to be used as a type argument -ResolutionErrors.dfy(2541,11): Error: no label 'L' in scope at this time -ResolutionErrors.dfy(2544,10): Error: label shadows a dominating label -ResolutionErrors.dfy(2552,10): Error: label shadows a dominating label -ResolutionErrors.dfy(2624,23): Error: no label 'Treasure' in scope at this time -ResolutionErrors.dfy(2625,19): Error: no label 'WonderfulLabel' in scope at this time -ResolutionErrors.dfy(2627,23): Error: no label 'FutureLabel' in scope at this time -ResolutionErrors.dfy(2636,13): Error: no label 'Treasure' in scope at this time -ResolutionErrors.dfy(2637,13): Error: no label 'WonderfulLabel' in scope at this time -ResolutionErrors.dfy(2639,13): Error: no label 'FutureLabel' in scope at this time -ResolutionErrors.dfy(2648,13): Error: no label 'Treasure' in scope at this time -ResolutionErrors.dfy(2649,13): Error: no label 'WonderfulLabel' in scope at this time -ResolutionErrors.dfy(2651,13): Error: no label 'FutureLabel' in scope at this time -ResolutionErrors.dfy(2680,26): Error: type parameter (G) passed to method GimmieOne must support auto-initialization (got Yt<GW>) -ResolutionErrors.dfy(2693,50): Error: type of the receiver is not fully determined at this program point -ResolutionErrors.dfy(2719,11): Error: name of type (Cache) is used as a variable -ResolutionErrors.dfy(2719,17): Error: incorrect type for selection into ? (got X) -ResolutionErrors.dfy(2727,13): Warning: the quantifier has the form 'exists x :: A ==> B', which most often is a typo for 'exists x :: A && B'; if you think otherwise, rewrite as 'exists x :: (A ==> B)' or 'exists x :: !A || B' to suppress this warning -ResolutionErrors.dfy(2737,13): Warning: the quantifier has the form 'exists x :: A ==> B', which most often is a typo for 'exists x :: A && B'; if you think otherwise, rewrite as 'exists x :: (A ==> B)' or 'exists x :: !A || B' to suppress this warning -ResolutionErrors.dfy(2770,13): Error: a call to a ghost function is allowed only in specification contexts (consider declaring the function without the 'ghost' keyword) -ResolutionErrors.dfy(2771,13): Error: a call to a ghost function is allowed only in specification contexts (consider declaring the function without the 'ghost' keyword) -ResolutionErrors.dfy(2773,11): Error: ghost variables such as g are allowed only in specification contexts. g was inferred to be ghost based on its declaration or initialization. -ResolutionErrors.dfy(2794,4): Error: ghost variables such as g are allowed only in specification contexts. g was inferred to be ghost based on its declaration or initialization. -ResolutionErrors.dfy(2804,15): Error: a call to a ghost function is allowed only in specification contexts (consider declaring the function without the 'ghost' keyword) -ResolutionErrors.dfy(2805,22): Error: a call to a ghost function is allowed only in specification contexts (consider declaring the function without the 'ghost' keyword) -ResolutionErrors.dfy(2811,15): Error: a call to a ghost function is allowed only in specification contexts (consider declaring the function without the 'ghost' keyword) -ResolutionErrors.dfy(2812,22): Error: a call to a ghost function is allowed only in specification contexts (consider declaring the function without the 'ghost' keyword) -ResolutionErrors.dfy(2829,23): Error: type of left argument to * (int) must agree with the result type (bool) -ResolutionErrors.dfy(2829,23): Error: type of * must be of a numeric type, bitvector type, or a set-like type (instead got bool) -ResolutionErrors.dfy(2828,13): Error: not resolving module 'V' because there were errors in resolving its nested module 'W' -ResolutionErrors.dfy(2838,21): Error: type of left argument to * (int) must agree with the result type (bool) -ResolutionErrors.dfy(2838,21): Error: type of * must be of a numeric type, bitvector type, or a set-like type (instead got bool) -ResolutionErrors.dfy(2837,11): Error: not resolving module 'V' because there were errors in resolving its nested module 'W' -ResolutionErrors.dfy(2824,9): Error: not resolving module 'ErrorsFromNestedModules' because there were errors in resolving its nested module 'U' -ResolutionErrors.dfy(2846,11): Error: duplicate name of top-level declaration: G -ResolutionErrors.dfy(2852,11): Error: duplicate name of top-level declaration: H -ResolutionErrors.dfy(2868,4): Error: ghost variables such as y are allowed only in specification contexts. y was inferred to be ghost based on its declaration or initialization. -ResolutionErrors.dfy(2870,20): Error: ghost variables such as y are allowed only in specification contexts. y was inferred to be ghost based on its declaration or initialization. -ResolutionErrors.dfy(2879,6): Error: ghost variables such as i are allowed only in specification contexts. i was inferred to be ghost based on its declaration or initialization. -ResolutionErrors.dfy(2880,4): Error: ghost variables such as b are allowed only in specification contexts. b was inferred to be ghost based on its declaration or initialization. -ResolutionErrors.dfy(2889,6): Error: ghost variables such as i are allowed only in specification contexts. i was inferred to be ghost based on its declaration or initialization. -ResolutionErrors.dfy(2890,8): Error: ghost variables such as i are allowed only in specification contexts. i was inferred to be ghost based on its declaration or initialization. -ResolutionErrors.dfy(2891,4): Error: ghost variables such as b are allowed only in specification contexts. b was inferred to be ghost based on its declaration or initialization. -ResolutionErrors.dfy(2903,13): Error: expression is not allowed to refer to constant field x -ResolutionErrors.dfy(2905,22): Error: expression is not allowed to refer to constant field x -ResolutionErrors.dfy(2916,13): Error: arguments must be of a set or multiset type (got map<X, Y>) -ResolutionErrors.dfy(2926,4): Error: expect statement is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression) -ResolutionErrors.dfy(2932,11): Error: quantifiers in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'i' -ResolutionErrors.dfy(2933,21): Error: ghost variables such as g are allowed only in specification contexts. g was inferred to be ghost based on its declaration or initialization. -ResolutionErrors.dfy(2944,15): Error: RHS (of type X) not assignable to LHS (of type X) -ResolutionErrors.dfy(2948,10): Error: type of corresponding source/RHS (X) does not match type of bound variable (X) -ResolutionErrors.dfy(2976,16): Error: sequence update requires the value to have the element type of the sequence (got Trait) -ResolutionErrors.dfy(2980,11): Error: multiset update requires domain element to be of type Elem (got Trait) -ResolutionErrors.dfy(2985,13): Error: map update requires domain element to be of type Elem (got Trait) -ResolutionErrors.dfy(2987,18): Error: map update requires the value to have the range type Elem (got Trait) -ResolutionErrors.dfy(3012,5): Error: type parameter (F) passed to method Q must support auto-initialization (got Y) (perhaps try declaring type parameter 'Y' on line 3007 as 'Y(0)', which says it can only be instantiated with a type that supports auto-initialization) -ResolutionErrors.dfy(3015,5): Error: type parameter (F) passed to method Q must support auto-initialization (got Z) (perhaps try declaring type parameter 'Z' on line 3007 as 'Z(0)', which says it can only be instantiated with a type that supports auto-initialization) -ResolutionErrors.dfy(3016,5): Error: type parameter (G) passed to method P must support nonempty (got Z) (perhaps try declaring type parameter 'Z' on line 3007 as 'Z(00)', which says it can only be instantiated with a nonempty type) -ResolutionErrors.dfy(3025,9): Error: type parameter (F) passed to function FQ must support auto-initialization (got Y) (perhaps try declaring type parameter 'Y' on line 3020 as 'Y(0)', which says it can only be instantiated with a type that supports auto-initialization) -ResolutionErrors.dfy(3028,9): Error: type parameter (F) passed to function FQ must support auto-initialization (got Z) (perhaps try declaring type parameter 'Z' on line 3020 as 'Z(0)', which says it can only be instantiated with a type that supports auto-initialization) -ResolutionErrors.dfy(3029,9): Error: type parameter (G) passed to function FP must support nonempty (got Z) (perhaps try declaring type parameter 'Z' on line 3020 as 'Z(00)', which says it can only be instantiated with a nonempty type) -ResolutionErrors.dfy(3046,9): Error: a call to a ghost function is allowed only in specification contexts (consider declaring the function without the 'ghost' keyword) -ResolutionErrors.dfy(3047,9): Error: a call to a ghost predicate is allowed only in specification contexts (consider declaring the predicate without the 'ghost' keyword) -ResolutionErrors.dfy(3048,9): Error: a call to a least predicate is allowed only in specification contexts -ResolutionErrors.dfy(3049,9): Error: a call to a greatest predicate is allowed only in specification contexts -ResolutionErrors.dfy(3050,9): Error: a call to a twostate function is allowed only in specification contexts -ResolutionErrors.dfy(3051,9): Error: a call to a twostate predicate is allowed only in specification contexts -ResolutionErrors.dfy(3068,9): Error: function 'F0' expects 0 type arguments (got 1) -ResolutionErrors.dfy(3070,9): Error: function 'F2' expects 2 type arguments (got 1) -ResolutionErrors.dfy(3071,9): Error: function 'F0' expects 0 type arguments (got 2) -ResolutionErrors.dfy(3072,9): Error: function 'F1' expects 1 type argument (got 2) -ResolutionErrors.dfy(3080,4): Error: method 'M0' expects 0 type arguments (got 1) -ResolutionErrors.dfy(3082,4): Error: method 'M2' expects 2 type arguments (got 1) -ResolutionErrors.dfy(3083,4): Error: method 'M0' expects 0 type arguments (got 2) -ResolutionErrors.dfy(3084,4): Error: method 'M1' expects 1 type argument (got 2) -ResolutionErrors.dfy(3097,10): Error: ghost variables such as c are allowed only in specification contexts. c was inferred to be ghost based on its declaration or initialization. -ResolutionErrors.dfy(3101,14): Error: ghost variables such as t are allowed only in specification contexts. t was inferred to be ghost based on its declaration or initialization. -ResolutionErrors.dfy(3106,10): Error: ghost variables such as a' are allowed only in specification contexts. a' was inferred to be ghost based on its declaration or initialization. -ResolutionErrors.dfy(3107,10): Error: ghost variables such as c' are allowed only in specification contexts. c' was inferred to be ghost based on its declaration or initialization. -ResolutionErrors.dfy(3131,9): Error: type parameter (T) passed to function MustBeNonempty must support nonempty (got PossiblyEmpty) -ResolutionErrors.dfy(3136,9): Error: type parameter (T) passed to function MustBeNonempty must support nonempty (got Z) (perhaps try declaring type parameter 'Z' on line 3127 as 'Z(00)', which says it can only be instantiated with a nonempty type) -ResolutionErrors.dfy(3138,9): Error: type parameter (T) passed to function MustBeAutoInit must support auto-initialization (got PossiblyEmpty) -ResolutionErrors.dfy(3139,9): Error: type parameter (T) passed to function MustBeAutoInit must support auto-initialization (got Nonempty) -ResolutionErrors.dfy(3143,9): Error: type parameter (T) passed to function MustBeAutoInit must support auto-initialization (got Z) (perhaps try declaring type parameter 'Z' on line 3127 as 'Z(0)', which says it can only be instantiated with a type that supports auto-initialization) -ResolutionErrors.dfy(3147,9): Error: type parameter (T) passed to function MustSupportEquality must support equality (got NoEquality) -ResolutionErrors.dfy(3150,9): Error: type parameter (T) passed to function MustSupportEquality must support equality (got Z) (perhaps try declaring type parameter 'Z' on line 3127 as 'Z(==)', which says it can only be instantiated with a type that supports equality) -ResolutionErrors.dfy(3155,9): Error: type parameter (T) passed to function NoReferences must support no references (got Class?) -ResolutionErrors.dfy(3157,9): Error: type parameter (T) passed to function NoReferences must support no references (got Z) (perhaps try declaring type parameter 'Z' on line 3127 as 'Z(!new)', which says it can only be instantiated with a type that contains no references) -ResolutionErrors.dfy(3164,9): Error: type parameter (T) passed to function MustBeNonempty must support nonempty (got PossiblyEmpty) -ResolutionErrors.dfy(3170,9): Error: type parameter (T) passed to function MustBeAutoInit must support auto-initialization (got PossiblyEmpty) -ResolutionErrors.dfy(3185,9): Error: type parameter (T) passed to function NoReferences must support no references (got Class?) -ResolutionErrors.dfy(3194,12): Error: == can only be applied to expressions of types that support equality (got T) (perhaps try declaring type parameter 'T' on line 3192 as 'T(==)', which says it can only be instantiated with a type that supports equality) -ResolutionErrors.dfy(3196,7): Error: == can only be applied to expressions of types that support equality (got T) (perhaps try declaring type parameter 'T' on line 3192 as 'T(==)', which says it can only be instantiated with a type that supports equality) -ResolutionErrors.dfy(3199,12): Error: type parameter (T) passed to function GetInt must support equality (got NoEquality) -ResolutionErrors.dfy(3201,7): Error: type parameter (T) passed to function GetInt must support equality (got NoEquality) -ResolutionErrors.dfy(3204,19): Error: type parameter (T) passed to function GetInt must support equality (got NoEquality) -ResolutionErrors.dfy(3212,13): Error: == can only be applied to expressions of types that support equality (got T) (perhaps try declaring type parameter 'T' on line 3211 as 'T(==)', which says it can only be instantiated with a type that supports equality) -ResolutionErrors.dfy(3217,13): Error: == can only be applied to expressions of types that support equality (got T) (perhaps try declaring type parameter 'T' on line 3211 as 'T(==)', which says it can only be instantiated with a type that supports equality) -ResolutionErrors.dfy(3219,23): Error: == can only be applied to expressions of types that support equality (got T) (perhaps try declaring type parameter 'T' on line 3211 as 'T(==)', which says it can only be instantiated with a type that supports equality) -ResolutionErrors.dfy(3221,14): Error: type parameter 0 (T) passed to type QuadEq must support equality (got seq<T>) -ResolutionErrors.dfy(3222,15): Error: type parameter 1 (U) passed to type QuadEq must support equality (got seq<T>) -ResolutionErrors.dfy(3231,15): Error: == can only be applied to expressions of types that support equality (got T) (perhaps try declaring type parameter 'T' on line 3228 as 'T(==)', which says it can only be instantiated with a type that supports equality) -ResolutionErrors.dfy(3240,15): Error: == can only be applied to expressions of types that support equality (got T) (perhaps try declaring type parameter 'T' on line 3228 as 'T(==)', which says it can only be instantiated with a type that supports equality) +ResolutionErrors.dfy(2484,14): Error: an ORDINAL type is not allowed to be used as a type argument +ResolutionErrors.dfy(2482,8): Error: an ORDINAL type is not allowed to be used as a type argument +ResolutionErrors.dfy(2472,8): Error: an ORDINAL type is not allowed to be used as a type argument +ResolutionErrors.dfy(2471,8): Error: an ORDINAL type is not allowed to be used as a type argument +ResolutionErrors.dfy(2528,11): Error: no label 'L' in scope at this time +ResolutionErrors.dfy(2531,10): Error: label shadows a dominating label +ResolutionErrors.dfy(2539,10): Error: label shadows a dominating label +ResolutionErrors.dfy(2611,23): Error: no label 'Treasure' in scope at this time +ResolutionErrors.dfy(2612,19): Error: no label 'WonderfulLabel' in scope at this time +ResolutionErrors.dfy(2614,23): Error: no label 'FutureLabel' in scope at this time +ResolutionErrors.dfy(2623,13): Error: no label 'Treasure' in scope at this time +ResolutionErrors.dfy(2624,13): Error: no label 'WonderfulLabel' in scope at this time +ResolutionErrors.dfy(2626,13): Error: no label 'FutureLabel' in scope at this time +ResolutionErrors.dfy(2635,13): Error: no label 'Treasure' in scope at this time +ResolutionErrors.dfy(2636,13): Error: no label 'WonderfulLabel' in scope at this time +ResolutionErrors.dfy(2638,13): Error: no label 'FutureLabel' in scope at this time +ResolutionErrors.dfy(2667,26): Error: type parameter (G) passed to method GimmieOne must support auto-initialization (got Yt<GW>) +ResolutionErrors.dfy(2680,50): Error: type of the receiver is not fully determined at this program point +ResolutionErrors.dfy(2706,11): Error: name of type (Cache) is used as a variable +ResolutionErrors.dfy(2706,17): Error: incorrect type for selection into ? (got X) +ResolutionErrors.dfy(2714,13): Warning: the quantifier has the form 'exists x :: A ==> B', which most often is a typo for 'exists x :: A && B'; if you think otherwise, rewrite as 'exists x :: (A ==> B)' or 'exists x :: !A || B' to suppress this warning +ResolutionErrors.dfy(2724,13): Warning: the quantifier has the form 'exists x :: A ==> B', which most often is a typo for 'exists x :: A && B'; if you think otherwise, rewrite as 'exists x :: (A ==> B)' or 'exists x :: !A || B' to suppress this warning +ResolutionErrors.dfy(2757,13): Error: a call to a ghost function is allowed only in specification contexts (consider declaring the function without the 'ghost' keyword) +ResolutionErrors.dfy(2758,13): Error: a call to a ghost function is allowed only in specification contexts (consider declaring the function without the 'ghost' keyword) +ResolutionErrors.dfy(2760,11): Error: ghost variables such as g are allowed only in specification contexts. g was inferred to be ghost based on its declaration or initialization. +ResolutionErrors.dfy(2781,4): Error: ghost variables such as g are allowed only in specification contexts. g was inferred to be ghost based on its declaration or initialization. +ResolutionErrors.dfy(2791,15): Error: a call to a ghost function is allowed only in specification contexts (consider declaring the function without the 'ghost' keyword) +ResolutionErrors.dfy(2792,22): Error: a call to a ghost function is allowed only in specification contexts (consider declaring the function without the 'ghost' keyword) +ResolutionErrors.dfy(2798,15): Error: a call to a ghost function is allowed only in specification contexts (consider declaring the function without the 'ghost' keyword) +ResolutionErrors.dfy(2799,22): Error: a call to a ghost function is allowed only in specification contexts (consider declaring the function without the 'ghost' keyword) +ResolutionErrors.dfy(2816,23): Error: type of left argument to * (int) must agree with the result type (bool) +ResolutionErrors.dfy(2816,23): Error: type of * must be of a numeric type, bitvector type, or a set-like type (instead got bool) +ResolutionErrors.dfy(2815,13): Error: not resolving module 'V' because there were errors in resolving its nested module 'W' +ResolutionErrors.dfy(2825,21): Error: type of left argument to * (int) must agree with the result type (bool) +ResolutionErrors.dfy(2825,21): Error: type of * must be of a numeric type, bitvector type, or a set-like type (instead got bool) +ResolutionErrors.dfy(2824,11): Error: not resolving module 'V' because there were errors in resolving its nested module 'W' +ResolutionErrors.dfy(2811,9): Error: not resolving module 'ErrorsFromNestedModules' because there were errors in resolving its nested module 'U' +ResolutionErrors.dfy(2833,11): Error: duplicate name of top-level declaration: G +ResolutionErrors.dfy(2839,11): Error: duplicate name of top-level declaration: H +ResolutionErrors.dfy(2855,4): Error: ghost variables such as y are allowed only in specification contexts. y was inferred to be ghost based on its declaration or initialization. +ResolutionErrors.dfy(2857,20): Error: ghost variables such as y are allowed only in specification contexts. y was inferred to be ghost based on its declaration or initialization. +ResolutionErrors.dfy(2866,6): Error: ghost variables such as i are allowed only in specification contexts. i was inferred to be ghost based on its declaration or initialization. +ResolutionErrors.dfy(2867,4): Error: ghost variables such as b are allowed only in specification contexts. b was inferred to be ghost based on its declaration or initialization. +ResolutionErrors.dfy(2876,6): Error: ghost variables such as i are allowed only in specification contexts. i was inferred to be ghost based on its declaration or initialization. +ResolutionErrors.dfy(2877,8): Error: ghost variables such as i are allowed only in specification contexts. i was inferred to be ghost based on its declaration or initialization. +ResolutionErrors.dfy(2878,4): Error: ghost variables such as b are allowed only in specification contexts. b was inferred to be ghost based on its declaration or initialization. +ResolutionErrors.dfy(2890,13): Error: expression is not allowed to refer to constant field x +ResolutionErrors.dfy(2892,22): Error: expression is not allowed to refer to constant field x +ResolutionErrors.dfy(2903,13): Error: arguments must be of a set or multiset type (got map<X, Y>) +ResolutionErrors.dfy(2913,4): Error: expect statement is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression) +ResolutionErrors.dfy(2919,11): Error: quantifiers in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce or compile a bounded set of values for 'i' +ResolutionErrors.dfy(2920,21): Error: ghost variables such as g are allowed only in specification contexts. g was inferred to be ghost based on its declaration or initialization. +ResolutionErrors.dfy(2931,15): Error: RHS (of type X) not assignable to LHS (of type X) +ResolutionErrors.dfy(2935,10): Error: type of corresponding source/RHS (X) does not match type of bound variable (X) +ResolutionErrors.dfy(2963,16): Error: sequence update requires the value to have the element type of the sequence (got Trait) +ResolutionErrors.dfy(2967,11): Error: multiset update requires domain element to be of type Elem (got Trait) +ResolutionErrors.dfy(2972,13): Error: map update requires domain element to be of type Elem (got Trait) +ResolutionErrors.dfy(2974,18): Error: map update requires the value to have the range type Elem (got Trait) +ResolutionErrors.dfy(2999,5): Error: type parameter (F) passed to method Q must support auto-initialization (got Y) (perhaps try declaring type parameter 'Y' on line 2994 as 'Y(0)', which says it can only be instantiated with a type that supports auto-initialization) +ResolutionErrors.dfy(3002,5): Error: type parameter (F) passed to method Q must support auto-initialization (got Z) (perhaps try declaring type parameter 'Z' on line 2994 as 'Z(0)', which says it can only be instantiated with a type that supports auto-initialization) +ResolutionErrors.dfy(3003,5): Error: type parameter (G) passed to method P must support nonempty (got Z) (perhaps try declaring type parameter 'Z' on line 2994 as 'Z(00)', which says it can only be instantiated with a nonempty type) +ResolutionErrors.dfy(3012,9): Error: type parameter (F) passed to function FQ must support auto-initialization (got Y) (perhaps try declaring type parameter 'Y' on line 3007 as 'Y(0)', which says it can only be instantiated with a type that supports auto-initialization) +ResolutionErrors.dfy(3015,9): Error: type parameter (F) passed to function FQ must support auto-initialization (got Z) (perhaps try declaring type parameter 'Z' on line 3007 as 'Z(0)', which says it can only be instantiated with a type that supports auto-initialization) +ResolutionErrors.dfy(3016,9): Error: type parameter (G) passed to function FP must support nonempty (got Z) (perhaps try declaring type parameter 'Z' on line 3007 as 'Z(00)', which says it can only be instantiated with a nonempty type) +ResolutionErrors.dfy(3033,9): Error: a call to a ghost function is allowed only in specification contexts (consider declaring the function without the 'ghost' keyword) +ResolutionErrors.dfy(3034,9): Error: a call to a ghost predicate is allowed only in specification contexts (consider declaring the predicate without the 'ghost' keyword) +ResolutionErrors.dfy(3035,9): Error: a call to a least predicate is allowed only in specification contexts +ResolutionErrors.dfy(3036,9): Error: a call to a greatest predicate is allowed only in specification contexts +ResolutionErrors.dfy(3037,9): Error: a call to a twostate function is allowed only in specification contexts +ResolutionErrors.dfy(3038,9): Error: a call to a twostate predicate is allowed only in specification contexts +ResolutionErrors.dfy(3055,9): Error: function 'F0' expects 0 type arguments (got 1) +ResolutionErrors.dfy(3057,9): Error: function 'F2' expects 2 type arguments (got 1) +ResolutionErrors.dfy(3058,9): Error: function 'F0' expects 0 type arguments (got 2) +ResolutionErrors.dfy(3059,9): Error: function 'F1' expects 1 type argument (got 2) +ResolutionErrors.dfy(3067,4): Error: method 'M0' expects 0 type arguments (got 1) +ResolutionErrors.dfy(3069,4): Error: method 'M2' expects 2 type arguments (got 1) +ResolutionErrors.dfy(3070,4): Error: method 'M0' expects 0 type arguments (got 2) +ResolutionErrors.dfy(3071,4): Error: method 'M1' expects 1 type argument (got 2) +ResolutionErrors.dfy(3084,10): Error: ghost variables such as c are allowed only in specification contexts. c was inferred to be ghost based on its declaration or initialization. +ResolutionErrors.dfy(3088,14): Error: ghost variables such as t are allowed only in specification contexts. t was inferred to be ghost based on its declaration or initialization. +ResolutionErrors.dfy(3093,10): Error: ghost variables such as a' are allowed only in specification contexts. a' was inferred to be ghost based on its declaration or initialization. +ResolutionErrors.dfy(3094,10): Error: ghost variables such as c' are allowed only in specification contexts. c' was inferred to be ghost based on its declaration or initialization. +ResolutionErrors.dfy(3118,9): Error: type parameter (T) passed to function MustBeNonempty must support nonempty (got PossiblyEmpty) +ResolutionErrors.dfy(3123,9): Error: type parameter (T) passed to function MustBeNonempty must support nonempty (got Z) (perhaps try declaring type parameter 'Z' on line 3114 as 'Z(00)', which says it can only be instantiated with a nonempty type) +ResolutionErrors.dfy(3125,9): Error: type parameter (T) passed to function MustBeAutoInit must support auto-initialization (got PossiblyEmpty) +ResolutionErrors.dfy(3126,9): Error: type parameter (T) passed to function MustBeAutoInit must support auto-initialization (got Nonempty) +ResolutionErrors.dfy(3130,9): Error: type parameter (T) passed to function MustBeAutoInit must support auto-initialization (got Z) (perhaps try declaring type parameter 'Z' on line 3114 as 'Z(0)', which says it can only be instantiated with a type that supports auto-initialization) +ResolutionErrors.dfy(3134,9): Error: type parameter (T) passed to function MustSupportEquality must support equality (got NoEquality) +ResolutionErrors.dfy(3137,9): Error: type parameter (T) passed to function MustSupportEquality must support equality (got Z) (perhaps try declaring type parameter 'Z' on line 3114 as 'Z(==)', which says it can only be instantiated with a type that supports equality) +ResolutionErrors.dfy(3142,9): Error: type parameter (T) passed to function NoReferences must support no references (got Class?) +ResolutionErrors.dfy(3144,9): Error: type parameter (T) passed to function NoReferences must support no references (got Z) (perhaps try declaring type parameter 'Z' on line 3114 as 'Z(!new)', which says it can only be instantiated with a type that contains no references) +ResolutionErrors.dfy(3151,9): Error: type parameter (T) passed to function MustBeNonempty must support nonempty (got PossiblyEmpty) +ResolutionErrors.dfy(3157,9): Error: type parameter (T) passed to function MustBeAutoInit must support auto-initialization (got PossiblyEmpty) +ResolutionErrors.dfy(3172,9): Error: type parameter (T) passed to function NoReferences must support no references (got Class?) +ResolutionErrors.dfy(3181,12): Error: == can only be applied to expressions of types that support equality (got T) (perhaps try declaring type parameter 'T' on line 3179 as 'T(==)', which says it can only be instantiated with a type that supports equality) +ResolutionErrors.dfy(3183,7): Error: == can only be applied to expressions of types that support equality (got T) (perhaps try declaring type parameter 'T' on line 3179 as 'T(==)', which says it can only be instantiated with a type that supports equality) +ResolutionErrors.dfy(3186,12): Error: type parameter (T) passed to function GetInt must support equality (got NoEquality) +ResolutionErrors.dfy(3188,7): Error: type parameter (T) passed to function GetInt must support equality (got NoEquality) +ResolutionErrors.dfy(3191,19): Error: type parameter (T) passed to function GetInt must support equality (got NoEquality) +ResolutionErrors.dfy(3199,13): Error: == can only be applied to expressions of types that support equality (got T) (perhaps try declaring type parameter 'T' on line 3198 as 'T(==)', which says it can only be instantiated with a type that supports equality) +ResolutionErrors.dfy(3204,13): Error: == can only be applied to expressions of types that support equality (got T) (perhaps try declaring type parameter 'T' on line 3198 as 'T(==)', which says it can only be instantiated with a type that supports equality) +ResolutionErrors.dfy(3206,23): Error: == can only be applied to expressions of types that support equality (got T) (perhaps try declaring type parameter 'T' on line 3198 as 'T(==)', which says it can only be instantiated with a type that supports equality) +ResolutionErrors.dfy(3208,14): Error: type parameter 0 (T) passed to type QuadEq must support equality (got seq<T>) +ResolutionErrors.dfy(3209,15): Error: type parameter 1 (U) passed to type QuadEq must support equality (got seq<T>) +ResolutionErrors.dfy(3218,15): Error: == can only be applied to expressions of types that support equality (got T) (perhaps try declaring type parameter 'T' on line 3215 as 'T(==)', which says it can only be instantiated with a type that supports equality) +ResolutionErrors.dfy(3227,15): Error: == can only be applied to expressions of types that support equality (got T) (perhaps try declaring type parameter 'T' on line 3215 as 'T(==)', which says it can only be instantiated with a type that supports equality) +ResolutionErrors.dfy(3245,11): Error: type parameter (T) passed to function MustBeNonempty must support nonempty (got PossiblyEmpty) +ResolutionErrors.dfy(3246,11): Error: type parameter (T) passed to function MustBeAutoInit must support auto-initialization (got PossiblyEmpty) +ResolutionErrors.dfy(3247,11): Error: type parameter (T) passed to function MustBeAutoInit must support auto-initialization (got Nonempty) +ResolutionErrors.dfy(3248,11): Error: type parameter (T) passed to function MustSupportEquality must support equality (got NoEquality) +ResolutionErrors.dfy(3249,11): Error: type parameter (T) passed to function NoReferences must support no references (got Class?) +ResolutionErrors.dfy(3253,47): Error: type parameter (T) passed to function MustBeNonempty must support nonempty (got PossiblyEmpty) +ResolutionErrors.dfy(3254,12): Error: type parameter (T) passed to function MustBeNonempty must support nonempty (got PossiblyEmpty) ResolutionErrors.dfy(3258,11): Error: type parameter (T) passed to function MustBeNonempty must support nonempty (got PossiblyEmpty) ResolutionErrors.dfy(3259,11): Error: type parameter (T) passed to function MustBeAutoInit must support auto-initialization (got PossiblyEmpty) ResolutionErrors.dfy(3260,11): Error: type parameter (T) passed to function MustBeAutoInit must support auto-initialization (got Nonempty) ResolutionErrors.dfy(3261,11): Error: type parameter (T) passed to function MustSupportEquality must support equality (got NoEquality) ResolutionErrors.dfy(3262,11): Error: type parameter (T) passed to function NoReferences must support no references (got Class?) -ResolutionErrors.dfy(3266,47): Error: type parameter (T) passed to function MustBeNonempty must support nonempty (got PossiblyEmpty) +ResolutionErrors.dfy(3266,50): Error: type parameter (T) passed to function MustBeNonempty must support nonempty (got PossiblyEmpty) ResolutionErrors.dfy(3267,12): Error: type parameter (T) passed to function MustBeNonempty must support nonempty (got PossiblyEmpty) -ResolutionErrors.dfy(3271,11): Error: type parameter (T) passed to function MustBeNonempty must support nonempty (got PossiblyEmpty) -ResolutionErrors.dfy(3272,11): Error: type parameter (T) passed to function MustBeAutoInit must support auto-initialization (got PossiblyEmpty) -ResolutionErrors.dfy(3273,11): Error: type parameter (T) passed to function MustBeAutoInit must support auto-initialization (got Nonempty) -ResolutionErrors.dfy(3274,11): Error: type parameter (T) passed to function MustSupportEquality must support equality (got NoEquality) -ResolutionErrors.dfy(3275,11): Error: type parameter (T) passed to function NoReferences must support no references (got Class?) -ResolutionErrors.dfy(3279,50): Error: type parameter (T) passed to function MustBeNonempty must support nonempty (got PossiblyEmpty) -ResolutionErrors.dfy(3280,12): Error: type parameter (T) passed to function MustBeNonempty must support nonempty (got PossiblyEmpty) -ResolutionErrors.dfy(3283,12): Error: type parameter (T) passed to function MustSupportEquality must support equality (got NoEquality) -ResolutionErrors.dfy(3287,12): Error: type parameter (T) passed to function MustSupportEquality must support equality (got NoEquality) -ResolutionErrors.dfy(3292,53): Error: type parameter (T) passed to function MustBeNonempty must support nonempty (got PossiblyEmpty) -ResolutionErrors.dfy(3295,63): Error: type parameter (T) passed to function MustBeNonempty must support nonempty (got PossiblyEmpty) -ResolutionErrors.dfy(3312,6): Error: ghost variables such as m are allowed only in specification contexts. m was inferred to be ghost based on its declaration or initialization. -ResolutionErrors.dfy(3316,8): Error: non-ghost variable cannot be assigned a value that depends on a ghost -ResolutionErrors.dfy(3320,18): Error: ghost variables such as m are allowed only in specification contexts. m was inferred to be ghost based on its declaration or initialization. -ResolutionErrors.dfy(3346,6): Error: type parameter (T) passed to function MustBeNonempty must support nonempty (got PossiblyEmpty) -ResolutionErrors.dfy(3352,6): Error: type parameter (T) passed to function MustBeAutoInit must support auto-initialization (got PossiblyEmpty) -ResolutionErrors.dfy(3353,6): Error: type parameter (T) passed to function MustBeAutoInit must support auto-initialization (got Nonempty) -ResolutionErrors.dfy(3360,6): Error: type parameter (T) passed to function MustSupportEquality must support equality (got NoEquality) -ResolutionErrors.dfy(3367,6): Error: type parameter (T) passed to function NoReferences must support no references (got Class?) -ResolutionErrors.dfy(3373,9): Error: type parameter (T) passed to function MustBeNonempty must support nonempty (got PossiblyEmpty) -ResolutionErrors.dfy(3379,9): Error: type parameter (T) passed to function MustBeAutoInit must support auto-initialization (got PossiblyEmpty) -ResolutionErrors.dfy(3394,9): Error: type parameter (T) passed to function NoReferences must support no references (got Class?) -ResolutionErrors.dfy(3442,7): Error: ghost variables such as p are allowed only in specification contexts. p was inferred to be ghost based on its declaration or initialization. -ResolutionErrors.dfy(3456,21): Error: a loop in a hint is not allowed to use 'modifies' clauses -ResolutionErrors.dfy(3463,21): Error: a loop in a hint is not allowed to use 'modifies' clauses -ResolutionErrors.dfy(3492,9): Error: the argument of a fresh expression must denote an object or a set or sequence of objects (instead got multiset<object>) -ResolutionErrors.dfy(3493,9): Error: the argument of a fresh expression must denote an object or a set or sequence of objects (instead got map<object, int>) -ResolutionErrors.dfy(3494,9): Error: the argument of a fresh expression must denote an object or a set or sequence of objects (instead got map<int, object>) -ResolutionErrors.dfy(3495,9): Error: the argument of a fresh expression must denote an object or a set or sequence of objects (instead got imap<object, object>) -ResolutionErrors.dfy(3500,9): Error: the argument of a fresh expression must denote an object or a set or sequence of objects (instead got int) -ResolutionErrors.dfy(3501,9): Error: the argument of a fresh expression must denote an object or a set or sequence of objects (instead got set<bool>) -ResolutionErrors.dfy(3502,9): Error: the argument of a fresh expression must denote an object or a set or sequence of objects (instead got iset<bv8>) -ResolutionErrors.dfy(3503,9): Error: the argument of a fresh expression must denote an object or a set or sequence of objects (instead got seq<int>) -ResolutionErrors.dfy(3508,9): Error: the argument of a fresh expression must denote an object or a set or sequence of objects (instead got int -> int) -ResolutionErrors.dfy(3509,9): Error: the argument of a fresh expression must denote an object or a set or sequence of objects (instead got int -> object) -ResolutionErrors.dfy(3510,9): Error: the argument of a fresh expression must denote an object or a set or sequence of objects (instead got int -> set<object>) -ResolutionErrors.dfy(3511,9): Error: the argument of a fresh expression must denote an object or a set or sequence of objects (instead got int -> seq<object>) -ResolutionErrors.dfy(3512,9): Error: the argument of a fresh expression must denote an object or a set or sequence of objects (instead got set<object> -> int) -ResolutionErrors.dfy(3531,19): Error: an unchanged expression must denote an object or a set/iset/multiset/seq of objects (instead got map<object, int>) -ResolutionErrors.dfy(3532,19): Error: an unchanged expression must denote an object or a set/iset/multiset/seq of objects (instead got map<int, object>) -ResolutionErrors.dfy(3533,19): Error: an unchanged expression must denote an object or a set/iset/multiset/seq of objects (instead got imap<object, object>) -ResolutionErrors.dfy(3538,19): Error: an unchanged expression must denote an object or a set/iset/multiset/seq of objects (instead got int) -ResolutionErrors.dfy(3539,19): Error: an unchanged expression must denote an object or a set/iset/multiset/seq of objects (instead got set<bool>) -ResolutionErrors.dfy(3540,19): Error: an unchanged expression must denote an object or a set/iset/multiset/seq of objects (instead got iset<bv8>) -ResolutionErrors.dfy(3541,19): Error: an unchanged expression must denote an object or a set/iset/multiset/seq of objects (instead got seq<int>) -ResolutionErrors.dfy(3550,19): Error: an unchanged expression must denote an object or a set/iset/multiset/seq of objects (instead got int -> int) -ResolutionErrors.dfy(3551,19): Error: an unchanged expression must denote an object or a set/iset/multiset/seq of objects (instead got int -> object) -ResolutionErrors.dfy(3552,19): Error: an unchanged expression must denote an object or a set/iset/multiset/seq of objects (instead got int -> set<object>) -ResolutionErrors.dfy(3553,19): Error: an unchanged expression must denote an object or a set/iset/multiset/seq of objects (instead got int -> iset<object>) -ResolutionErrors.dfy(3554,19): Error: an unchanged expression must denote an object or a set/iset/multiset/seq of objects (instead got int -> seq<object>) -ResolutionErrors.dfy(3555,19): Error: an unchanged expression must denote an object or a set/iset/multiset/seq of objects (instead got set<object> -> int) -ResolutionErrors.dfy(3556,19): Error: an unchanged expression must denote an object or a set/iset/multiset/seq of objects (instead got bool -> multiset<object>) -ResolutionErrors.dfy(3557,19): Error: an unchanged expression must denote an object or a set/iset/multiset/seq of objects (instead got bool -> map<object, object>) -ResolutionErrors.dfy(3572,13): Error: a modifies-clause expression must denote an object or a set/iset/multiset/seq of objects (instead got map<object, int>) -ResolutionErrors.dfy(3573,13): Error: a modifies-clause expression must denote an object or a set/iset/multiset/seq of objects (instead got map<int, object>) -ResolutionErrors.dfy(3574,13): Error: a modifies-clause expression must denote an object or a set/iset/multiset/seq of objects (instead got imap<object, object>) -ResolutionErrors.dfy(3579,13): Error: a modifies-clause expression must denote an object or a set/iset/multiset/seq of objects (instead got int) -ResolutionErrors.dfy(3580,13): Error: a modifies-clause expression must denote an object or a set/iset/multiset/seq of objects (instead got set<bool>) -ResolutionErrors.dfy(3581,13): Error: a modifies-clause expression must denote an object or a set/iset/multiset/seq of objects (instead got iset<bv8>) -ResolutionErrors.dfy(3582,13): Error: a modifies-clause expression must denote an object or a set/iset/multiset/seq of objects (instead got seq<int>) -ResolutionErrors.dfy(3590,13): Error: a modifies-clause expression must denote an object or a set/iset/multiset/seq of objects (instead got int -> int) -ResolutionErrors.dfy(3591,13): Error: a modifies-clause expression must denote an object or a set/iset/multiset/seq of objects (instead got int -> object) -ResolutionErrors.dfy(3592,13): Error: a modifies-clause expression must denote an object or a set/iset/multiset/seq of objects (instead got int -> set<object>) -ResolutionErrors.dfy(3593,13): Error: a modifies-clause expression must denote an object or a set/iset/multiset/seq of objects (instead got int -> iset<object>) -ResolutionErrors.dfy(3594,13): Error: a modifies-clause expression must denote an object or a set/iset/multiset/seq of objects (instead got int -> seq<object>) -ResolutionErrors.dfy(3595,13): Error: a modifies-clause expression must denote an object or a set/iset/multiset/seq of objects (instead got set<object> -> int) -ResolutionErrors.dfy(3596,13): Error: a modifies-clause expression must denote an object or a set/iset/multiset/seq of objects (instead got bool -> multiset<object>) -ResolutionErrors.dfy(3597,13): Error: a modifies-clause expression must denote an object or a set/iset/multiset/seq of objects (instead got bool -> map<object, object>) -ResolutionErrors.dfy(3613,10): Error: a reads-clause expression must denote an object, a set/iset/multiset/seq of objects, or a function to a set/iset/multiset/seq of objects (instead got map<object, int>) -ResolutionErrors.dfy(3614,10): Error: a reads-clause expression must denote an object, a set/iset/multiset/seq of objects, or a function to a set/iset/multiset/seq of objects (instead got map<int, object>) -ResolutionErrors.dfy(3615,10): Error: a reads-clause expression must denote an object, a set/iset/multiset/seq of objects, or a function to a set/iset/multiset/seq of objects (instead got imap<object, object>) -ResolutionErrors.dfy(3621,10): Error: a reads-clause expression must denote an object, a set/iset/multiset/seq of objects, or a function to a set/iset/multiset/seq of objects (instead got int) -ResolutionErrors.dfy(3622,10): Error: a reads-clause expression must denote an object, a set/iset/multiset/seq of objects, or a function to a set/iset/multiset/seq of objects (instead got set<bool>) -ResolutionErrors.dfy(3623,10): Error: a reads-clause expression must denote an object, a set/iset/multiset/seq of objects, or a function to a set/iset/multiset/seq of objects (instead got iset<bv8>) -ResolutionErrors.dfy(3624,10): Error: a reads-clause expression must denote an object, a set/iset/multiset/seq of objects, or a function to a set/iset/multiset/seq of objects (instead got seq<int>) -ResolutionErrors.dfy(3633,10): Error: a reads-clause expression must denote an object, a set/iset/multiset/seq of objects, or a function to a set/iset/multiset/seq of objects (instead got int -> int) -ResolutionErrors.dfy(3634,10): Error: a reads-clause expression must denote an object, a set/iset/multiset/seq of objects, or a function to a set/iset/multiset/seq of objects (instead got int -> object) -ResolutionErrors.dfy(3638,10): Error: a reads-clause expression must denote an object, a set/iset/multiset/seq of objects, or a function to a set/iset/multiset/seq of objects (instead got set<object> -> int) -ResolutionErrors.dfy(3640,10): Error: a reads-clause expression must denote an object, a set/iset/multiset/seq of objects, or a function to a set/iset/multiset/seq of objects (instead got bool -> map<object, object>) -ResolutionErrors.dfy(3659,12): Error: a 'break break break continue' statement is allowed only in contexts with 4 enclosing loops, but the current context only has 3 -ResolutionErrors.dfy(3696,27): Error: continue label must designate a loop: X -ResolutionErrors.dfy(3698,27): Error: continue label must designate a loop: Y0 -ResolutionErrors.dfy(3700,27): Error: continue label must designate a loop: Y1 -ResolutionErrors.dfy(3702,27): Error: continue label must designate a loop: Z -ResolutionErrors.dfy(3712,4): Error: a non-labeled 'break' statement is allowed only in loops -ResolutionErrors.dfy(3716,4): Error: a non-labeled 'continue' statement is allowed only in loops -ResolutionErrors.dfy(3722,19): Error: a non-labeled 'break' statement is allowed only in loops -ResolutionErrors.dfy(3723,19): Error: a non-labeled 'continue' statement is allowed only in loops -ResolutionErrors.dfy(3725,28): Error: continue label must designate a loop: X -ResolutionErrors.dfy(3742,21): Error: a non-labeled 'break' statement is allowed only in loops -ResolutionErrors.dfy(3743,21): Error: a non-labeled 'continue' statement is allowed only in loops -ResolutionErrors.dfy(3744,27): Error: break label is undefined or not in scope: L -ResolutionErrors.dfy(3745,30): Error: continue label is undefined or not in scope: L -ResolutionErrors.dfy(3758,8): Error: ghost-context continue statement is not allowed to continue out of non-ghost loop -ResolutionErrors.dfy(3767,8): Error: ghost-context break statement is not allowed to break out of non-ghost loop -ResolutionErrors.dfy(3775,8): Error: ghost-context continue statement is not allowed to continue out of non-ghost loop -ResolutionErrors.dfy(3790,10): Error: ghost-context continue statement is not allowed to continue out of non-ghost loop -ResolutionErrors.dfy(3813,10): Error: ghost-context continue statement is not allowed to continue out of non-ghost loop -ResolutionErrors.dfy(3869,13): Error: 'this' is not allowed in a 'static' context -ResolutionErrors.dfy(3869,18): Error: type of the receiver is not fully determined at this program point -ResolutionErrors.dfy(3878,13): Error: 'this' is not allowed in a 'static' context -ResolutionErrors.dfy(3878,18): Error: type of the receiver is not fully determined at this program point -ResolutionErrors.dfy(3896,22): Error: 'this' is not allowed in a 'static' context +ResolutionErrors.dfy(3270,12): Error: type parameter (T) passed to function MustSupportEquality must support equality (got NoEquality) +ResolutionErrors.dfy(3274,12): Error: type parameter (T) passed to function MustSupportEquality must support equality (got NoEquality) +ResolutionErrors.dfy(3279,53): Error: type parameter (T) passed to function MustBeNonempty must support nonempty (got PossiblyEmpty) +ResolutionErrors.dfy(3282,63): Error: type parameter (T) passed to function MustBeNonempty must support nonempty (got PossiblyEmpty) +ResolutionErrors.dfy(3299,6): Error: ghost variables such as m are allowed only in specification contexts. m was inferred to be ghost based on its declaration or initialization. +ResolutionErrors.dfy(3303,8): Error: non-ghost variable cannot be assigned a value that depends on a ghost +ResolutionErrors.dfy(3307,18): Error: ghost variables such as m are allowed only in specification contexts. m was inferred to be ghost based on its declaration or initialization. +ResolutionErrors.dfy(3333,6): Error: type parameter (T) passed to function MustBeNonempty must support nonempty (got PossiblyEmpty) +ResolutionErrors.dfy(3339,6): Error: type parameter (T) passed to function MustBeAutoInit must support auto-initialization (got PossiblyEmpty) +ResolutionErrors.dfy(3340,6): Error: type parameter (T) passed to function MustBeAutoInit must support auto-initialization (got Nonempty) +ResolutionErrors.dfy(3347,6): Error: type parameter (T) passed to function MustSupportEquality must support equality (got NoEquality) +ResolutionErrors.dfy(3354,6): Error: type parameter (T) passed to function NoReferences must support no references (got Class?) +ResolutionErrors.dfy(3360,9): Error: type parameter (T) passed to function MustBeNonempty must support nonempty (got PossiblyEmpty) +ResolutionErrors.dfy(3366,9): Error: type parameter (T) passed to function MustBeAutoInit must support auto-initialization (got PossiblyEmpty) +ResolutionErrors.dfy(3381,9): Error: type parameter (T) passed to function NoReferences must support no references (got Class?) +ResolutionErrors.dfy(3429,7): Error: ghost variables such as p are allowed only in specification contexts. p was inferred to be ghost based on its declaration or initialization. +ResolutionErrors.dfy(3443,21): Error: a loop in a hint is not allowed to use 'modifies' clauses +ResolutionErrors.dfy(3450,21): Error: a loop in a hint is not allowed to use 'modifies' clauses +ResolutionErrors.dfy(3479,9): Error: the argument of a fresh expression must denote an object or a set or sequence of objects (instead got multiset<object>) +ResolutionErrors.dfy(3480,9): Error: the argument of a fresh expression must denote an object or a set or sequence of objects (instead got map<object, int>) +ResolutionErrors.dfy(3481,9): Error: the argument of a fresh expression must denote an object or a set or sequence of objects (instead got map<int, object>) +ResolutionErrors.dfy(3482,9): Error: the argument of a fresh expression must denote an object or a set or sequence of objects (instead got imap<object, object>) +ResolutionErrors.dfy(3487,9): Error: the argument of a fresh expression must denote an object or a set or sequence of objects (instead got int) +ResolutionErrors.dfy(3488,9): Error: the argument of a fresh expression must denote an object or a set or sequence of objects (instead got set<bool>) +ResolutionErrors.dfy(3489,9): Error: the argument of a fresh expression must denote an object or a set or sequence of objects (instead got iset<bv8>) +ResolutionErrors.dfy(3490,9): Error: the argument of a fresh expression must denote an object or a set or sequence of objects (instead got seq<int>) +ResolutionErrors.dfy(3495,9): Error: the argument of a fresh expression must denote an object or a set or sequence of objects (instead got int -> int) +ResolutionErrors.dfy(3496,9): Error: the argument of a fresh expression must denote an object or a set or sequence of objects (instead got int -> object) +ResolutionErrors.dfy(3497,9): Error: the argument of a fresh expression must denote an object or a set or sequence of objects (instead got int -> set<object>) +ResolutionErrors.dfy(3498,9): Error: the argument of a fresh expression must denote an object or a set or sequence of objects (instead got int -> seq<object>) +ResolutionErrors.dfy(3499,9): Error: the argument of a fresh expression must denote an object or a set or sequence of objects (instead got set<object> -> int) +ResolutionErrors.dfy(3518,19): Error: an unchanged expression must denote an object or a set/iset/multiset/seq of objects (instead got map<object, int>) +ResolutionErrors.dfy(3519,19): Error: an unchanged expression must denote an object or a set/iset/multiset/seq of objects (instead got map<int, object>) +ResolutionErrors.dfy(3520,19): Error: an unchanged expression must denote an object or a set/iset/multiset/seq of objects (instead got imap<object, object>) +ResolutionErrors.dfy(3525,19): Error: an unchanged expression must denote an object or a set/iset/multiset/seq of objects (instead got int) +ResolutionErrors.dfy(3526,19): Error: an unchanged expression must denote an object or a set/iset/multiset/seq of objects (instead got set<bool>) +ResolutionErrors.dfy(3527,19): Error: an unchanged expression must denote an object or a set/iset/multiset/seq of objects (instead got iset<bv8>) +ResolutionErrors.dfy(3528,19): Error: an unchanged expression must denote an object or a set/iset/multiset/seq of objects (instead got seq<int>) +ResolutionErrors.dfy(3537,19): Error: an unchanged expression must denote an object or a set/iset/multiset/seq of objects (instead got int -> int) +ResolutionErrors.dfy(3538,19): Error: an unchanged expression must denote an object or a set/iset/multiset/seq of objects (instead got int -> object) +ResolutionErrors.dfy(3539,19): Error: an unchanged expression must denote an object or a set/iset/multiset/seq of objects (instead got int -> set<object>) +ResolutionErrors.dfy(3540,19): Error: an unchanged expression must denote an object or a set/iset/multiset/seq of objects (instead got int -> iset<object>) +ResolutionErrors.dfy(3541,19): Error: an unchanged expression must denote an object or a set/iset/multiset/seq of objects (instead got int -> seq<object>) +ResolutionErrors.dfy(3542,19): Error: an unchanged expression must denote an object or a set/iset/multiset/seq of objects (instead got set<object> -> int) +ResolutionErrors.dfy(3543,19): Error: an unchanged expression must denote an object or a set/iset/multiset/seq of objects (instead got bool -> multiset<object>) +ResolutionErrors.dfy(3544,19): Error: an unchanged expression must denote an object or a set/iset/multiset/seq of objects (instead got bool -> map<object, object>) +ResolutionErrors.dfy(3559,13): Error: a modifies-clause expression must denote an object or a set/iset/multiset/seq of objects (instead got map<object, int>) +ResolutionErrors.dfy(3560,13): Error: a modifies-clause expression must denote an object or a set/iset/multiset/seq of objects (instead got map<int, object>) +ResolutionErrors.dfy(3561,13): Error: a modifies-clause expression must denote an object or a set/iset/multiset/seq of objects (instead got imap<object, object>) +ResolutionErrors.dfy(3566,13): Error: a modifies-clause expression must denote an object or a set/iset/multiset/seq of objects (instead got int) +ResolutionErrors.dfy(3567,13): Error: a modifies-clause expression must denote an object or a set/iset/multiset/seq of objects (instead got set<bool>) +ResolutionErrors.dfy(3568,13): Error: a modifies-clause expression must denote an object or a set/iset/multiset/seq of objects (instead got iset<bv8>) +ResolutionErrors.dfy(3569,13): Error: a modifies-clause expression must denote an object or a set/iset/multiset/seq of objects (instead got seq<int>) +ResolutionErrors.dfy(3577,13): Error: a modifies-clause expression must denote an object or a set/iset/multiset/seq of objects (instead got int -> int) +ResolutionErrors.dfy(3578,13): Error: a modifies-clause expression must denote an object or a set/iset/multiset/seq of objects (instead got int -> object) +ResolutionErrors.dfy(3579,13): Error: a modifies-clause expression must denote an object or a set/iset/multiset/seq of objects (instead got int -> set<object>) +ResolutionErrors.dfy(3580,13): Error: a modifies-clause expression must denote an object or a set/iset/multiset/seq of objects (instead got int -> iset<object>) +ResolutionErrors.dfy(3581,13): Error: a modifies-clause expression must denote an object or a set/iset/multiset/seq of objects (instead got int -> seq<object>) +ResolutionErrors.dfy(3582,13): Error: a modifies-clause expression must denote an object or a set/iset/multiset/seq of objects (instead got set<object> -> int) +ResolutionErrors.dfy(3583,13): Error: a modifies-clause expression must denote an object or a set/iset/multiset/seq of objects (instead got bool -> multiset<object>) +ResolutionErrors.dfy(3584,13): Error: a modifies-clause expression must denote an object or a set/iset/multiset/seq of objects (instead got bool -> map<object, object>) +ResolutionErrors.dfy(3600,10): Error: a reads-clause expression must denote an object, a set/iset/multiset/seq of objects, or a function to a set/iset/multiset/seq of objects (instead got map<object, int>) +ResolutionErrors.dfy(3601,10): Error: a reads-clause expression must denote an object, a set/iset/multiset/seq of objects, or a function to a set/iset/multiset/seq of objects (instead got map<int, object>) +ResolutionErrors.dfy(3602,10): Error: a reads-clause expression must denote an object, a set/iset/multiset/seq of objects, or a function to a set/iset/multiset/seq of objects (instead got imap<object, object>) +ResolutionErrors.dfy(3608,10): Error: a reads-clause expression must denote an object, a set/iset/multiset/seq of objects, or a function to a set/iset/multiset/seq of objects (instead got int) +ResolutionErrors.dfy(3609,10): Error: a reads-clause expression must denote an object, a set/iset/multiset/seq of objects, or a function to a set/iset/multiset/seq of objects (instead got set<bool>) +ResolutionErrors.dfy(3610,10): Error: a reads-clause expression must denote an object, a set/iset/multiset/seq of objects, or a function to a set/iset/multiset/seq of objects (instead got iset<bv8>) +ResolutionErrors.dfy(3611,10): Error: a reads-clause expression must denote an object, a set/iset/multiset/seq of objects, or a function to a set/iset/multiset/seq of objects (instead got seq<int>) +ResolutionErrors.dfy(3620,10): Error: a reads-clause expression must denote an object, a set/iset/multiset/seq of objects, or a function to a set/iset/multiset/seq of objects (instead got int -> int) +ResolutionErrors.dfy(3621,10): Error: a reads-clause expression must denote an object, a set/iset/multiset/seq of objects, or a function to a set/iset/multiset/seq of objects (instead got int -> object) +ResolutionErrors.dfy(3625,10): Error: a reads-clause expression must denote an object, a set/iset/multiset/seq of objects, or a function to a set/iset/multiset/seq of objects (instead got set<object> -> int) +ResolutionErrors.dfy(3627,10): Error: a reads-clause expression must denote an object, a set/iset/multiset/seq of objects, or a function to a set/iset/multiset/seq of objects (instead got bool -> map<object, object>) +ResolutionErrors.dfy(3646,12): Error: a 'break break break continue' statement is allowed only in contexts with 4 enclosing loops, but the current context only has 3 +ResolutionErrors.dfy(3683,27): Error: continue label must designate a loop: X +ResolutionErrors.dfy(3685,27): Error: continue label must designate a loop: Y0 +ResolutionErrors.dfy(3687,27): Error: continue label must designate a loop: Y1 +ResolutionErrors.dfy(3689,27): Error: continue label must designate a loop: Z +ResolutionErrors.dfy(3699,4): Error: a non-labeled 'break' statement is allowed only in loops +ResolutionErrors.dfy(3703,4): Error: a non-labeled 'continue' statement is allowed only in loops +ResolutionErrors.dfy(3709,19): Error: a non-labeled 'break' statement is allowed only in loops +ResolutionErrors.dfy(3710,19): Error: a non-labeled 'continue' statement is allowed only in loops +ResolutionErrors.dfy(3712,28): Error: continue label must designate a loop: X +ResolutionErrors.dfy(3729,21): Error: a non-labeled 'break' statement is allowed only in loops +ResolutionErrors.dfy(3730,21): Error: a non-labeled 'continue' statement is allowed only in loops +ResolutionErrors.dfy(3731,27): Error: break label is undefined or not in scope: L +ResolutionErrors.dfy(3732,30): Error: continue label is undefined or not in scope: L +ResolutionErrors.dfy(3745,8): Error: ghost-context continue statement is not allowed to continue out of non-ghost loop +ResolutionErrors.dfy(3754,8): Error: ghost-context break statement is not allowed to break out of non-ghost loop +ResolutionErrors.dfy(3762,8): Error: ghost-context continue statement is not allowed to continue out of non-ghost loop +ResolutionErrors.dfy(3777,10): Error: ghost-context continue statement is not allowed to continue out of non-ghost loop +ResolutionErrors.dfy(3800,10): Error: ghost-context continue statement is not allowed to continue out of non-ghost loop +ResolutionErrors.dfy(3856,13): Error: 'this' is not allowed in a 'static' context +ResolutionErrors.dfy(3856,18): Error: type of the receiver is not fully determined at this program point +ResolutionErrors.dfy(3865,13): Error: 'this' is not allowed in a 'static' context +ResolutionErrors.dfy(3865,18): Error: type of the receiver is not fully determined at this program point +ResolutionErrors.dfy(3883,22): Error: 'this' is not allowed in a 'static' context +ResolutionErrors.dfy(3851,22): Error: 'this' is not allowed in a 'static' context +ResolutionErrors.dfy(3851,27): Error: type of the receiver is not fully determined at this program point +ResolutionErrors.dfy(3857,12): Error: 'this' is not allowed in a 'static' context +ResolutionErrors.dfy(3857,17): Error: type of the receiver is not fully determined at this program point +ResolutionErrors.dfy(3855,25): Error: 'this' is not allowed in a 'static' context +ResolutionErrors.dfy(3855,30): Error: type of the receiver is not fully determined at this program point +ResolutionErrors.dfy(3862,22): Error: 'this' is not allowed in a 'static' context +ResolutionErrors.dfy(3862,27): Error: type of the receiver is not fully determined at this program point +ResolutionErrors.dfy(3866,12): Error: 'this' is not allowed in a 'static' context +ResolutionErrors.dfy(3866,17): Error: type of the receiver is not fully determined at this program point ResolutionErrors.dfy(3864,22): Error: 'this' is not allowed in a 'static' context ResolutionErrors.dfy(3864,27): Error: type of the receiver is not fully determined at this program point -ResolutionErrors.dfy(3870,12): Error: 'this' is not allowed in a 'static' context -ResolutionErrors.dfy(3870,17): Error: type of the receiver is not fully determined at this program point -ResolutionErrors.dfy(3868,25): Error: 'this' is not allowed in a 'static' context -ResolutionErrors.dfy(3868,30): Error: type of the receiver is not fully determined at this program point -ResolutionErrors.dfy(3875,22): Error: 'this' is not allowed in a 'static' context -ResolutionErrors.dfy(3875,27): Error: type of the receiver is not fully determined at this program point -ResolutionErrors.dfy(3879,12): Error: 'this' is not allowed in a 'static' context -ResolutionErrors.dfy(3879,17): Error: type of the receiver is not fully determined at this program point -ResolutionErrors.dfy(3877,22): Error: 'this' is not allowed in a 'static' context -ResolutionErrors.dfy(3877,27): Error: type of the receiver is not fully determined at this program point -ResolutionErrors.dfy(3881,23): Error: 'this' is not allowed in a 'static' context -ResolutionErrors.dfy(3881,28): Error: type of the receiver is not fully determined at this program point -ResolutionErrors.dfy(3895,32): Error: 'this' is not allowed in a 'static' context -ResolutionErrors.dfy(3898,29): Error: 'this' is not allowed in a 'static' context -ResolutionErrors.dfy(3897,33): Error: 'this' is not allowed in a 'static' context -ResolutionErrors.dfy(3900,29): Error: 'this' is not allowed in a 'static' context -ResolutionErrors.dfy(3899,41): Error: 'this' is not allowed in a 'static' context -ResolutionErrors.dfy(3885,23): Error: 'this' is not allowed in a 'static' context -ResolutionErrors.dfy(3885,28): Error: type of the receiver is not fully determined at this program point -ResolutionErrors.dfy(3904,21): Error: 'this' is not allowed in a 'static' context -ResolutionErrors.dfy(3904,26): Error: type of the receiver is not fully determined at this program point -ResolutionErrors.dfy(3913,20): Error: type parameter (G) passed to type AutoStream must support auto-initialization (got G) (perhaps try declaring type parameter 'G' on line 3913 as 'G(0)', which says it can only be instantiated with a type that supports auto-initialization) -ResolutionErrors.dfy(3914,25): Error: type parameter (G) passed to type AutoStream must support auto-initialization (got G) (perhaps try declaring type parameter 'G' on line 3914 as 'G(0)', which says it can only be instantiated with a type that supports auto-initialization) -ResolutionErrors.dfy(3916,17): Error: type parameter (G) passed to type AutoStream must support auto-initialization (got G) (perhaps try declaring type parameter 'G' on line 3916 as 'G(0)', which says it can only be instantiated with a type that supports auto-initialization) -ResolutionErrors.dfy(3917,32): Error: type parameter (G) passed to type AutoStream must support auto-initialization (got G) (perhaps try declaring type parameter 'G' on line 3917 as 'G(0)', which says it can only be instantiated with a type that supports auto-initialization) +ResolutionErrors.dfy(3868,23): Error: 'this' is not allowed in a 'static' context +ResolutionErrors.dfy(3868,28): Error: type of the receiver is not fully determined at this program point +ResolutionErrors.dfy(3882,32): Error: 'this' is not allowed in a 'static' context +ResolutionErrors.dfy(3885,29): Error: 'this' is not allowed in a 'static' context +ResolutionErrors.dfy(3884,33): Error: 'this' is not allowed in a 'static' context +ResolutionErrors.dfy(3887,29): Error: 'this' is not allowed in a 'static' context +ResolutionErrors.dfy(3886,41): Error: 'this' is not allowed in a 'static' context +ResolutionErrors.dfy(3872,23): Error: 'this' is not allowed in a 'static' context +ResolutionErrors.dfy(3872,28): Error: type of the receiver is not fully determined at this program point +ResolutionErrors.dfy(3891,21): Error: 'this' is not allowed in a 'static' context +ResolutionErrors.dfy(3891,26): Error: type of the receiver is not fully determined at this program point +ResolutionErrors.dfy(3900,20): Error: type parameter (G) passed to type AutoStream must support auto-initialization (got G) (perhaps try declaring type parameter 'G' on line 3900 as 'G(0)', which says it can only be instantiated with a type that supports auto-initialization) +ResolutionErrors.dfy(3901,25): Error: type parameter (G) passed to type AutoStream must support auto-initialization (got G) (perhaps try declaring type parameter 'G' on line 3901 as 'G(0)', which says it can only be instantiated with a type that supports auto-initialization) +ResolutionErrors.dfy(3903,17): Error: type parameter (G) passed to type AutoStream must support auto-initialization (got G) (perhaps try declaring type parameter 'G' on line 3903 as 'G(0)', which says it can only be instantiated with a type that supports auto-initialization) +ResolutionErrors.dfy(3904,32): Error: type parameter (G) passed to type AutoStream must support auto-initialization (got G) (perhaps try declaring type parameter 'G' on line 3904 as 'G(0)', which says it can only be instantiated with a type that supports auto-initialization) +ResolutionErrors.dfy(3927,6): Error: when allocating an object of type 'ClassWithConstructor', one of its constructor methods must be called +ResolutionErrors.dfy(3928,6): Error: when allocating an object of type 'ClassWithConstructor', one of its constructor methods must be called +ResolutionErrors.dfy(3941,8): Error: when allocating an object of type 'Y', one of its constructor methods must be called +ResolutionErrors.dfy(3946,8): Error: when allocating an object of type 'Luci', one of its constructor methods must be called +ResolutionErrors.dfy(3947,8): Error: when allocating an object of type 'Luci', one of its constructor methods must be called 629 resolution/type errors detected in ResolutionErrors.dfy diff --git a/Test/dafny0/TypeInferenceRefresh.dfy b/Test/dafny0/TypeInferenceRefresh.dfy new file mode 100644 index 00000000000..4de0fec2cda --- /dev/null +++ b/Test/dafny0/TypeInferenceRefresh.dfy @@ -0,0 +1,1061 @@ +// RUN: %exits-with 4 %dafny /compile:0 /typeSystemRefresh:1 "%s" > "%t" +// RUN: %diff "%s.expect" "%t" + +datatype Color = BlueX | WhiteX | PastelX +{ + predicate IsFailure() { + WhiteX? || BlueX? + } + function PropagateFailure(): int { + 15 + } + function Extract(): real { + if BlueX? then 3.09 else 9.03 + } +} + +function FxF(x: int): bool + +method CallF0() { + var b0 := FxF(15); + var f: int -> bool := FxF; + var b1 := f(15); + assert b0 == b1; +} + +method CallF1() { + var b0 := FxF(15); + var f := FxF; + var b1 := f(15); + assert b0 == b1; +} + +class ClassForOld { + var u: int + method Old() + modifies this + { + u := u + 1; + assert old(u) == u - 1; + if old(u) == 5 { + var g := 10; + } + } + method Unchanged() { + assert unchanged(this); + } + method New(a': array<int>) returns (r: ClassForOld, a: array<int>) + ensures fresh(r) + ensures !fresh(a) + ensures !fresh(var o := null; o) + ensures !fresh(null) + { + var m := var o := null; o; + r := new ClassForOld; + a := a'; + } +} + +method ToMultiset(s: set<int>, q: seq<real>) { + var r0 := multiset(s); + var r1 := multiset(q); +} + +method CreateLambdaAndSequence() { + var f := i => 2 * i; + var s := seq(15, f); +} + +datatype Colors = Blue | Yellow | Gray(n: nat) +{ + method PrintMe() { + if (this == Blue) { + print "blue"; + } else if (this == Yellow) { + print "yellow"; + } else { + print "gray ", n; + } + print "\n"; + } +} + +module A { + type T + datatype BaseType = BaseType(t: T) + + predicate P(d: BaseType) + + class XYZ { + static predicate ABC(d: BaseType) + } + + type SubsetType = d: BaseType | P(d) + witness * + type SubsetType' = d: BaseType | d == d + witness * + type SubsetType'' = d: BaseType | XYZ.ABC(d) + witness * + + method M0(dp: SubsetType, tt: T) { + var dp0: SubsetType := [dp][0]; + var dp': SubsetType := dp0.(t := tt); // error: does not satisfy SubsetType + } + + method M1(dp: SubsetType, tt: T) { + var dp0 := [dp][0]; +//SOON: var dp': SubsetType := dp0.(t := tt); // error: does not satisfy SubsetType + } +} + +method Bv() { + var bv: bv6 := 8; + var o: ORDINAL := 8; +} +method SUpdate(s: seq<real>, m0: map<real, bool>, m1: imap<real, bool>, mm: multiset<bv6>) + requires |s| == 10 +{ + var s' := s[6 := 3.2]; + var m0' := m0[3.2 := true]; + var m1' := m1[3.2 := true]; + var mm' := mm[8 := 100]; +} + +method MultiDimArray(m: array3<real>) + requires m.Length0 == m.Length1 == m.Length2 == 10 +{ + var r := m[2, 4, 6]; + var b := r == 2.7; +} + +method LittleArray(a: array<real>) + requires 10 <= a.Length +{ + var s := a [2..3]; +} +function Qf(x: int, a: array<int>): bool + requires x <= a.Length + reads a +{ + var m := map[2 := true, 3 := false, 4 := false]; + var u := m[3]; + var v := true; + var w := m[3] == true; + var ww := u == v; +true//SOON: forall i :: 0 <= i < x ==> m[i] == true // error: domain +} + +trait AsTr { } +class AsCl extends AsTr { } + +method Is(clIn: AsCl) { + var b; + b := clIn is AsTr; + b := clIn is object; + b := clIn is AsCl?; + b := clIn is AsTr?; + b := clIn is object?; +} + +method As(clIn: AsCl, ch: char) returns (cl: AsCl) { + var tr: AsTr; + var obj: object; + tr := clIn as AsTr; + obj := clIn as AsTr; + obj := clIn as object; + cl := tr as AsCl; + cl := obj as AsCl; + + var x: int; + var ord: ORDINAL; + x := ch as int; + ord := ch as ORDINAL; +} + +method As?(clIn: AsCl) returns (cl: AsCl?) { + var tr: AsTr?; + var obj: object?; + tr := clIn as AsTr?; + obj := clIn as AsTr?; + obj := clIn as object?; + cl := tr as AsCl?; + cl := obj as AsCl?; +} + +datatype BlackWhite = White | Gray(int) + +method Dtv(b: bool) returns (c: BlackWhite) { + var d := White; + var e := BlackWhite.Gray(15); + c := if b then BlackWhite.Gray(10) else BlackWhite.Gray(20); + assert c.Gray?; +} + +newtype XX = y: YY | true +type YY = z: int | true +type ZZ = y: YY | true + +newtype jnt8 = x | + var lo := -0x80; + var hi := 0x80; + lo <= x < hi + +newtype int8 = x | + - 0x80 <= x < 0x80 + +method TooBigDiv(a: int8) { + var b := a; + var u := false; + u := !u; + var q := a != 0; + var k := + var xyz := 3; xyz; + var l := 3 + if u then 2 else 1; + + if + case true => +//SOON: var x := a / (0-1); // error: result may not be an int8 (if a is -128) + case true => + var minusOne := -1; + var y := a % minusOne; // fine + case a != 0 => + var z := (0-1) % a; // fine +} + +method Good(a: int8) + requires a != -127-1 +{ + var x := a / -1; // fine +} + +class Global { + static function G(x: int): int { x+x } + static method N(ghost x: int, g: Global) returns (ghost r: int) + ensures r == Global.G(x) + { + if + case true => + r := G(x); + case true => + r := G(x+0); + case true => + r := g.G(x); + case true => + var g: Global? := null; + r := g.G(x); + case true => + r := Global.G(x); + } +} + +method Mxy(x: int, y: int) { + var b := x == y; + var m, n; + b := m == n; + n := 'n'; +} + +module Inheritance { + trait Trait { } + class A extends Trait { } + class B extends Trait { } + class C<X, Y, Z> extends Trait { } + class D<X(0)> { + var x: X + var y: X + } + class Cell { + var data: int + } + + method FInt() returns (r: int) { + var d := new D; + var u: int := d.x; + r := d.y; + } + method FIntCell() returns (r: int) { + var c := new Cell; + var u := c.data; + r := u; + } + method FCell(c: Cell) { + var x := c.data; + } + + method S0(o: object, t: Trait, a: A, b: B) + { + var oo := o; + var x := t; + var y := a; + } + + method S1(o: object, t: Trait, a: A, b: B) + { + var z := a; + z := a; + z := b; + z := t; + z := o; + } + + method S2(o: object, t: Trait, a: A, b: B) + { + var uu := a; + } + + method S3(o: object?, t: Trait?, a: A?, b: B?, c: C?<int, bool, Trait?>) returns (aa: A?, c3: C?<bool, int, Trait?>) + { + var uu; + aa := uu; + var uu3; + c3 := uu3; + } + + method S4(o: object?, t: Trait?, a: A?, b: B?, c: C?<int, bool, Trait?>) returns (aa: A?, c3: C?<bool, int, Trait?>) + { + var n := null; + } + + method S6(o: object?, t: Trait?, a: A?, b: B?, c: C?<int, bool, Trait?>) returns (aa: A?, c3: C?<bool, int, Trait?>) + { + var oo := o; + var tt := t; + tt := null; + var a3 := a; + } +} + +newtype MyInt = int + +type MyNatSynonym = nat + +function F(x: int): int { + 5 +} + +function G(x: int): int { + x +} + +function H(x: int): int { + x % 5 +} + +function I(x: MyInt): MyInt { + x % 5 +} + +method M(x: int, m: MyInt, n: nat, n': MyNatSynonym) { + var y, z, w, q; + y := x; + w := 2; + w := x; + z := x; + q := 3; + q := m; + y := n; + y := n'; +} + +method A0(s: seq<int>) { + var t; + t := s; + var u; + u := [2, 3]; + var m := map[3 := true]; +} + +method A1(k: MyInt) { + var g, h; + var p := map[g := 3, true := h]; + h := k; +} + +method A2() { + var g; + var s := [g]; + g := true; +} + +method A3() { + var u; + u := [2, 3]; + var v := []; + var b := 2 in v; +} + +method B0() { + var a := true; + var b; + var c := b ==> a; + var d := (a || a) <== b && (a <==> c); +} + +method MMap() { + var a: map<int, bool>, b; + var c := a - b; +} + +function Qfx(a: map<int, real>): int + requires 3 in a.Keys +{ + var w := a[3] == 3.14; + 17 +} + +class XyzClass { + method New(c: XyzClass', b: bool, r': XyzClass) returns (r: XyzClass) + ensures var q := if b then r else c; true + { + r := r'; + } +} +type XyzClass' = c: XyzClass? | true witness * + +function {:opaque} OpaqueFunction(): int { 12 } + +method Reveal() { + assert A: true; + reveal A; + reveal OpaqueFunction(); +} + +lemma Calc(a: bool, b: bool, c: int, d: int, e: int) + requires c <= d <= e + requires a + requires b ==> e <= c + requires B: b + ensures e <= d +{ + calc ==> { + a; + c <= d; + == { reveal B; } + e <= d; + } +} + +class CellToModify { + var data: int +} + +method Modify(b: bool) { + var c := new CellToModify; + modify c; + modify c { // warning: deprecated statement + if b { + c.data := 20; + } + } +} + +module Patterns { + datatype Color = Red | Gray(n: nat) + + method VarPattern(c: Color) returns (x: int) { + if c != Red { + var Gray(mm) := c; + x := mm; + } + } + + method M(c: Color) returns (x: int) { + match c + case Red => + case Gray(oo) => x := oo; + } + + function LetPattern(c: Color): int { + if c == Red then 3 else + var Gray(pp) := c; + pp + } + + function F(c: Color): int { + match c + case Red => 3 + case Gray(oo) => oo + } +} + +method WhileLoops() returns (k: int) { + var i := 250; + while 2 < i { + i := i - 1; + k := k + i; + } + var ii := 0; + while ii < 10 { + var u: RomanC := ii; + ii := ii + 1; + } +} + +method ForLoops() returns (k: int) { + for i := 250 downto 2 { + k := k + i; + } + for i := 0 to 10 + { + var u: RomanC := i; + } +} + +newtype RomanC = x | 0 <= x < 100 + +method LoopAlternatives(n: nat) { + var a, b := 0, n; + while + decreases b - a + case a < b => b := b - 1; + case a < b => a := a + 1; +} + +module TypeParameterResolution { + type A + + class Class<B> { + var aa: A + var bb: B + constructor() + method M<C>() { + var a: A; + var b: B; + var c: C; + } + function F<D>(a: A, b: B, d: D): int { + var a': A := a; + var b': B := b; + var d': D := d; + 3 + } + } + + type SS<X(!new)> = o: int | assert forall x: X :: var y: X := x; true; 0 <= o witness * + + datatype Datatype<B> = Ctor { + method M<C>() { + var a: A; + var b: B; + var c: C; + } + function F<D>(a: A, b: B, d: D): int { + var a': A := a; + var b': B := b; + var d': D := d; + 3 + } + } + + type Opaque<B> { + method M<C>() { + var a: A; + var b: B; + var c: C; + } + function F<D>(a: A, b: B, d: D): int { + var a': A := a; + var b': B := b; + var d': D := d; + 3 + } + } +} + +module FunctionApplications { + function Fn<X>(xp: X): (real, X) + + method NewArrayInit(n: nat) returns (g: int ~> real) { + var fn1 := x => 3.00; + var u1 := fn1(100); + + var v := Fn(100); + + var fn := (_, q) => 3.00; + var u := fn(100, 100); + + var arr := new real[n](_ => 3.00); + } +} + +module ForallStmt { + method AggregateAssignment(s: set<int>, a: array<real>) + requires forall x :: x in s ==> 0 <= x < a.Length + modifies a + { + forall i | i in s { + a[i] := 35.50; + } + } + + function Plus(x: nat, y: nat): nat { + if x == 0 then y else 1 + Plus(x - 1, y) + } + + lemma DistributePlus(a: nat, x: nat, y: nat) + ensures Plus(a + x, y) == a + Plus(x, y) + { + if a != 0 { + calc { + Plus(a + x, y); + == + 1 + Plus(a - 1 + x, y); + == { DistributePlus(a - 1, x, y); } + 1 + (a - 1) + Plus(x, y); + == + a + Plus(x, y); + } + } + } + + lemma Associative(x: nat, y: nat, z: nat) + ensures Plus(Plus(x, y), z) == Plus(x, Plus(y, z)) + { + if x != 0 { + calc { + Plus(Plus(x, y), z); + == // def. Plus + Plus(1 + Plus(x - 1, y), z); + == // def. Plus + 1 + Plus(Plus(x - 1, y), z); + == { Associative(x - 1, y, z); } + 1 + Plus(x - 1, Plus(y, z)); + == // def. Plus + Plus(x, Plus(y, z)); + } + } + } + + lemma AllAssociative() + ensures forall x, y, z :: Plus(Plus(x, y), z) == Plus(x, Plus(y, z)) // error (x3): x,y,z are int's, not nat's + { + forall x, y, z { + Associative(x, y, z); // error (x3): x,y,z are int's, not nat's + } + } +} + +module Variance { + method CollectionVariance<X>(b: array<X>) returns (r: set<object>, o: object, m: map<object, object>) { + o := b; + r := {b}; + m := map[o := o]; + m := map[b := o]; + m := map[o := b]; + } + + method ArrowCovariance<A, B, X>(arr: array<X>) returns (f: () -> object, g: A -> object, h: (A, B) -> object) { + f := () => arr; + g := a => arr; + h := (a, b) => arr; + } + + method ArrowContraariance<A, B, X>(arr: array<X>) returns (f: () -> int, g: array<X> -> int, h: (array<X>, array<X>) -> int) { + f := () => 3; + g := (a: object) => 4; + h := (a: array?<X>, b: object) => 5; + } +} + +module ReferenceTypeParents { + class Vector<X> { } + + method M<X>(arr: array<X>, v: Vector<X>) returns (repr: set<object>) { + repr := {v, arr}; + } + + method E<X>(arr: array<X>, r: set<object>) returns (repr: set<object>) { + repr := r + {arr}; + } +} + +module PartiallySolveBeforeFindingNames { + datatype Option<X> = None | Some(value: X) + method GetIt<X>(i: nat, arr: array<Option<X>>) + requires i < arr.Length && arr[i].Some? + { + var a := arr[i]; + var b := a.value; + } +} + +module Frames { + class C { + var x: int + var y: int + } + + function A0(): set<C> + function A1(): iset<C> + function A2(): seq<C> + function A3(): multiset<C> + + function F(o: object, s: set<C>, ss: iset<C>, sq: seq<C>, ms: multiset<C>): int + reads o + reads s + reads ss + reads sq + reads ms + reads s`x + reads ss`x + reads sq`x + reads ms`x + reads A0 + reads A1 +// reads A2 // TODO +// reads A3 // TODO +// reads A0`x // TODO +// reads A1`x // TODO + reads A2`x + reads A3`x + + method M(o: object, s: set<C>, ss: iset<C>, sq: seq<C>, ms: multiset<C>) + modifies o + modifies s + modifies ss + modifies sq + modifies ms + modifies s`x + modifies ss`x + modifies sq`x + modifies ms`x + { + modify o; + modify s; + modify ss; + modify sq; + modify ms; + modify s`x; + modify ss`x; + modify sq`x; + modify ms`x; + } + + method U(oo: set<object>, o: object, s: set<C>, ss: iset<C>, sq: seq<C>, ms: multiset<C>) + modifies oo + ensures unchanged(o) + ensures unchanged(s) + ensures unchanged(ss) + ensures unchanged(sq) + ensures unchanged(ms) + ensures unchanged(s`x) + ensures unchanged(ss`x) + ensures unchanged(sq`x) + ensures unchanged(ms`x) + { + } +} + +module NeverNever { + type Never = x: int | false witness * + + method Test() { + var n; // type of 'n' is inferred to be Never, but since 'n' is never used, the verifier has nothing to complain about + if false { + var u: Never; + n := u; + } + } +} + + +/**************************************************************************************** + ******** TO DO ************************************************************************* + **************************************************************************************** +// ------------------ +// https://github.com/dafny-lang/dafny/issues/2134 +/* +newtype A = b | P(b) +newtype B = a: A | true + +predicate P(b: B) +*/ + +// ------------------ +// There was never a test for the error message that comes out here: + +datatype Color = White | Gray(int) +datatype ParametricColor<X, Y> = Blue | Red(X) | Green(Y) + +method DatatypeValues() { + var w := White<int>; // error (no hint, since the datatype doesn't take any type parameters) + var b := Blue<int>; // error: with hint (since the datatype takes _some_ number of type parameters) + var g := Gray<int>(2); + var r := Red<int>(3); +} + +// ------------------ +// Clement suggested the following problem to try through the new type inference. +// On 5 April 2022, he said: + +// Below is a test for your new type inference. Let me know if you would like me to post it as an issue. +// +// In brief, we have no way today to specify the return type of a lambda: it’s always inferred. This results in issues like below: + +function method {:opaque} MaxF<T>(f: T ~> int, ts: seq<T>, default: int) : (m: int) + reads f.reads + requires forall t | t in ts :: f.requires(t) + requires forall t | t in ts :: default <= f(t) + ensures if ts == [] then m == default else exists t | t in ts :: f(t) == m + ensures forall t | t in ts :: f(t) <= m + ensures default <= m + +datatype Tree = + | Leaf(i: int) + | Branch(trs: seq<Tree>) +{ + function method Depth() : nat { + match this { + case Leaf(_) => 0 + case Branch(trs) => + // var fn : Tree --> nat := (t: Tree) requires t in trs => t.Depth(); + 1 + MaxF((t: Tree) requires t in trs => t.Depth(), trs, 0) + } + } +} + +// Dafny rejects the call to MaxF, claiming that forall t | t in ts :: default <= f(t) might not hold. But default is 0 and f(t) +// has type nat, so it should hold — and in fact just uncommenting the definition of fn above solves the issue… even if fn isn’t used. + + +// ------------------ +// Can the following example (from S) be improved to not need the explicit seq32<Principal> type annotations? + +type seq32<X> = s: seq<X> | |s| < 0x8000_0000 +function method seqSize<X>(s: seq32<X>): nat32 { + |s| +} +type nat32 = x: int | 0 <= x < 0x8000_0000 + +type Context +type Principal +datatype Option<X> = None | Some(val: X) + +class Sean { + function method principalFromContext(c: Context): Option<Principal> + + function principalsFromContexts(ctxs: seq32<Context>): (res: Option<seq32<Principal>>) + ensures res.Some? ==> |ctxs| == |res.val| + ensures res.Some? ==> forall i :: 0 <= i < |ctxs| ==> principalFromContext(ctxs[i]).Some?; + ensures res.Some? ==> forall i:: 0 <= i < |ctxs| ==> res.val[i] == principalFromContext(ctxs[i]).val + ensures res.None? ==> exists i :: 0 <= i < |ctxs| && principalFromContext(ctxs[i]).None? + { + var empty: seq32<Principal> := []; + if |ctxs| == 0 then Some(empty) else match principalFromContext(ctxs[0]) { + case None => None + case Some(principal) => + match principalsFromContexts(ctxs[1..]) { + case None => None + case Some(principals) => + // TODO: Remove when dafny supports type ascription + var principals1: seq32<Principal> := [principal] + principals; + Some(principals1) + } + } + } by method { + var principals: seq32<Principal> := []; + for i := 0 to seqSize(ctxs) + invariant seqSize(principals) == i + invariant forall j :: 0 <= j < i ==> principalFromContext(ctxs[j]).Some? + invariant forall j :: 0 <= j < i ==> principals[j] == principalFromContext(ctxs[j]).val + { + var principal := principalFromContext(ctxs[i]); + if principal.None? { + return None; + } + principals := principals + [principal.val]; + } + assert principals == principalsFromContexts(ctxs).val; + return Some(principals); + } +} + +// ------------------ +// From Clement: + +method copy<T>(a: array<T>) returns (a': array<T>) { + a' := new T[a.Length](k requires k < a.Length reads a => a[k]); +} + +// The lambda in a new T is supposed to take a nat, but Dafny infers k to be an int and rejects a[k] + +// ------------------ +// In this program, one has to write "n + d != 0" instead of "n != -d", because of a previously known problem with type inference + +predicate method ge0'(n: int) + ensures ge0'(n) <==> 0 <= n +{ + downup_search'(n, 0) +} + +function method Abs(n: int): nat { + if n < 0 then -n else n +} + +predicate method downup_search'(n: int, d: nat) + requires d <= Abs(n) + ensures downup_search'(n, d) <==> d <= n + decreases Abs(n) - d +{ + n == d || (n + d != 0 && downup_search'(n, d + 1)) + /* + if n - d == 0 then + true + else if n + d == 0 then + false + else + downup_search'(n, d + 1) + */ +} + +// ------------------ +// The following used to not work: +module OrderingIssue_PreviouslyBroken { + newtype N = x: MM | 0 <= x < 100 + newtype MM = x | 0 <= x < 100 +} +// whereas the following did work. +module OrderingIssue_Fine { + newtype MM = x | 0 <= x < 100 + newtype N = x: MM | 0 <= x < 100 +} + +// ------------------------ +// From Marianna: + +const int32_MIN: int := -0x8000_0000 +const int32_MAX: int := 0x7fff_ffff +newtype int32 = x | int32_MIN <= x <= int32_MAX + +const nat31_MIN: int32 := 0 +const nat31_MAX: int32 := int32_MAX as int32 +type nat31 = x: int32 | nat31_MIN <= x <= nat31_MAX + +method Works() { + var x: int32 := 0; +} + +method DoesNotWork() { + var x: nat31 := 0; // gives error: int not assignable to nat31 +} + +method Workaround() { + var x: nat31 := 0 as int32; +} + +// ------------------------ +// Also, see examples in https://github.com/dafny-lang/dafny/issues/1731 + + +// ------------------------ +// From https://github.com/dafny-lang/dafny/issues/1292: + +datatype List <T> = None | Cons (hd: T, tl: List<T>) + +method m (x: List<int>) { + match x + case None => {assert 4 > 3;} + case Cons(None, t) => {assert 4 > 3;} +} +****************************************************************************************/ + +/* The following test case may work with the new type inference, but did not with the old one. + +method LitTest() { + var c; // inferred to be bool + match c + case false => + case true => +} + +*/ + +/* Here's are tests for a match where a case is given by a const. + - For the first test, it used to be that this would spill out an unused local variable with that name (FIVE). + - The second test checks what happens if the const case label is also given an explicit type. + Previously, this would interpret "FIVE" as a const, and it would check that the type was correct. + Now, the explicit type causes it to be interpreted as a bound variable. + - The third test used to breeze through Dafny without any complaints, even though the type "int" makes no sense here. + Now, a pattern with an explicit type is always interpreted as a bound variable. + +const FIVE: int := 5 + +method Five(x: int) { + match x { + case FIVE => assert x == 5; + case _ => + } + match x { + case FIVE: int => + assert x == 5; // error: x may be anything, since FIVE is a bound variable + case _ => + } +} + +datatype Color = Blue | Green + +match Colors(c: Color) { + match c + case Blue: int => // error: because of the ": int", Blue is interpreted as a bound variable, and its type doesn't match that of "c" +} + + */ + +/* Some additional match tests + +method TupleTests(a: (int, ghost real), b: (), c: (ghost bool)) { + match a { + case (x, y) => + var z0 := x; + var z1 := y; + print z0, "\n"; + } + + match b { + case () => + var u := b; + print u, "\n"; + } + + match c { + case _ => print c, "\n"; + } + match c { + case (x) => //print x, "\n"; + } +} + + */ + +/* +datatype Cell<T> = Cell(value: T) + +const X := 1 + +method q() { + var c; + match c { + case X => // the literal 1 + case Xyz => // a bound variable + } +} + +datatype YT = Y +const Y := 2 + +method r() { + var c: Cell; + match c { + case Cell(Y) => // the literal 2 + case Cell(_) => + } +} + +method s() { + var c: Cell; + match c { + case Cell(Y: real) => // bound variable + case Cell(_) => // redundant + } +} + */ diff --git a/Test/dafny0/TypeInferenceRefresh.dfy.expect b/Test/dafny0/TypeInferenceRefresh.dfy.expect new file mode 100644 index 00000000000..4c077d28556 --- /dev/null +++ b/Test/dafny0/TypeInferenceRefresh.dfy.expect @@ -0,0 +1,15 @@ +TypeInferenceRefresh.dfy(445,11): Warning: the modify statement with a block statement is deprecated +TypeInferenceRefresh.dfy(102,31): Error: value does not satisfy the subset constraints of 'SubsetType' +TypeInferenceRefresh.dfy(630,40): Error: value does not satisfy the subset constraints of 'nat' +TypeInferenceRefresh.dfy(630,43): Error: value does not satisfy the subset constraints of 'nat' +TypeInferenceRefresh.dfy(630,47): Error: value does not satisfy the subset constraints of 'nat' +TypeInferenceRefresh.dfy(633,18): Error: value does not satisfy the subset constraints of 'nat' +TypeInferenceRefresh.dfy(633,21): Error: value does not satisfy the subset constraints of 'nat' +TypeInferenceRefresh.dfy(633,24): Error: value does not satisfy the subset constraints of 'nat' +TypeInferenceRefresh.dfy(704,10): Error: function precondition could not be proved +TypeInferenceRefresh.dfy(704,10): Error: insufficient reads clause to invoke function +TypeInferenceRefresh.dfy(709,10): Error: function precondition could not be proved +TypeInferenceRefresh.dfy(709,10): Error: insufficient reads clause to invoke function +TypeInferenceRefresh.dfy(710,10): Error: function precondition could not be proved + +Dafny program verifier finished with 62 verified, 12 errors diff --git a/Test/dafny0/TypeInferenceRefreshErrors.dfy b/Test/dafny0/TypeInferenceRefreshErrors.dfy new file mode 100644 index 00000000000..fa1db888c56 --- /dev/null +++ b/Test/dafny0/TypeInferenceRefreshErrors.dfy @@ -0,0 +1,225 @@ +// RUN: %exits-with 2 %dafny /compile:0 /typeSystemRefresh:1 "%s" > "%t" +// RUN: %diff "%s.expect" "%t" + +module Frames { + class C { + var x: int + var y: int + } + + // The following was accepted by the old type checking, but it caused a crash in the + // translator. Now, we disallow it. + function ToC(): C + function RegressionTest(): int + reads ToC // error: type not allowed: () -> C + + function ToSetReal(): set<real> + function ToMap(): map<object, object> + function F(r: real, s: set<real>): int + reads r // error: not a reference type + reads s // error: not a collection of reference type + reads ToSetReal // error: not a function to a collection of reference type + reads ToMap // error: not a function to a collection of reference type +} + +module As { + class C { } + class D { } + method M(c: C, d: D, obj: object) { + var cc: C; + var dd: D; + cc := obj as C; + dd := obj as D; + cc := d as C; // error: incompatible types + dd := c as D; // error: incompatible types + } +} + +module Underspecification0 { + method P() { + var u; + var w := !u; // error: type is underspecified, so ! operator is not understood + } +} + +module Underspecification1 { + class E<T> { } + + /* SOON + method M(obj: object) { + var ee := obj as E; // error: type parameter of E is underspecified + assert (obj as E) == (obj as E); // error: type parameter of E is underspecified + assert (obj as E) == (obj as E<set>); // error: type parameter of set is underspecified + assert (obj as E) == (obj as E<set<int>>); + } + */ +} + +module Underspecification2 { + method Q(m: map, n: map) { // fine, because of type-parameter elision rules + var o := m + n; + } + + method R() { + var m: map; // error: type is underspecified + var n: map; // error: type is underspecified + var o; // error: type is underspecified + o := m + n; // error: type of + is underspecified + } +} + +module Underspecification3 { + type Synonym<X, Unused> = seq<X> + + method Underspecification() { + // Regression: In the old type inference, the following line was not considered to be an error. + var d: Synonym := [100, 101]; // error: type underspecified + } +} + +module Underspecification4 { + type SubsetType<X, Unused> = s: seq<X> | |s| == 0 + + method Underspecification() { + // Regression: In the old type inference, the following would pass and would then crash the verifier: + var e: SubsetType := [100, 101]; // error: type underspecified + } +} + +module Underspecification5 { + type Synonym<A, Unused> = seq<A> + + method SM(x: Synonym<int, real>, y: seq<bool>) { + var m: seq := y; + + var a := x; + + var b: Synonym := x; // error: type underspecified + + var k: seq := x; + var y: Synonym := k; // error: type underspecified + } +} + +/* + * The following example causes Dafny 4.0 to crash (after reporting the expected error). + +datatype R = R(int, int) + +method M() { + var pair: (int, int) := (20, 30); + match pair + case R(x, y) => // bogus: should not be allowed to match a pair against an R constructor + print x + y, "\n"; +} + */ + +/* An additional match test + +method TupleTests(d: bv7) { + match d { + case (y) => // error: parentheses not allowed around pattern + } +} + + */ + +/* +module TooLargeCaseLiteral { + method Test(bv: bv7) { + match bv { + case 84848484848484848 => // error (BUG: this is missed by Dafny 4.0) + case _ => + } + } +} + +module CaseLiteralWrongType { + method Test(bv: bv7, r: real) { + match bv { + case 2.18 => // error: wrong type // BUG: crashes Dafny 4.0 + } + match r { + case 13 => // error: wrong type + case -0 => // error: wrong type + case 0 => // error: wrong type + } + match r { + case 15 => // error: wrong type // BUG: causes malformed Boogie in Dafny 4.0 + case -15 => // error: wrong type // BUG: causes malformed Boogie in Dafny 4.0 + case -0 => // error: wrong type // BUG: causes malformed Boogie in Dafny 4.0 + case false => // error: wrong type // BUG: causes malformed Boogie in Dafny 4.0 + } + } +} + +module NegativeCaseLabels { + newtype int8 = x | -128 <= x < 128 + + method NegativeLabels(a: int, nt: int8, bv: bv7, o: ORDINAL, r: real) { + match a { + case -3 => + case -0 => + case 0 => // redundant + case _ => + } + + match nt { + case -3 => + case -0 => + case 0 => // redundant + case _ => + } + + match bv { + case -3 => // error + case -0 => // error + case 0 => + case _ => + } + + match o { + case -3 => // error + case -0 => // error + case 0 => + case _ => + } + + match r { + case 2.18 => + case -2.18 => + case -0.0 => + case 0.0 => // redundant + case _ => + } + } +} + +module RedundanCaseLiterals { + newtype int8 = x | -128 <= x < 128 + + method Tests(a: int, nt: int8, r: real) { + match a { + case -3 => + case -0 => + case 0 => // redundant + case _ => + } + + match nt { + case -3 => + case -0 => + case 0 => // redundant + case _ => + } + + match r { + case 2.18 => + case -2.18 => + case -0.0 => + case 0.0 => // redundant + case _ => + } + } +} + */ diff --git a/Test/dafny0/TypeInferenceRefreshErrors.dfy.expect b/Test/dafny0/TypeInferenceRefreshErrors.dfy.expect new file mode 100644 index 00000000000..f4dd68fe09a --- /dev/null +++ b/Test/dafny0/TypeInferenceRefreshErrors.dfy.expect @@ -0,0 +1,17 @@ +TypeInferenceRefreshErrors.dfy(14,10): Error: PRE-TYPE: a reads-clause expression must denote an object, a set/iset/multiset/seq of objects, or a function to a set/iset/multiset/seq of objects (instead got () ~> C?) +TypeInferenceRefreshErrors.dfy(19,10): Error: PRE-TYPE: a reads-clause expression must denote an object, a set/iset/multiset/seq of objects, or a function to a set/iset/multiset/seq of objects (instead got real) +TypeInferenceRefreshErrors.dfy(20,10): Error: PRE-TYPE: a reads-clause expression must denote an object, a set/iset/multiset/seq of objects, or a function to a set/iset/multiset/seq of objects (instead got set<real>) +TypeInferenceRefreshErrors.dfy(21,10): Error: PRE-TYPE: a reads-clause expression must denote an object, a set/iset/multiset/seq of objects, or a function to a set/iset/multiset/seq of objects (instead got () ~> set<real>) +TypeInferenceRefreshErrors.dfy(22,10): Error: PRE-TYPE: a reads-clause expression must denote an object, a set/iset/multiset/seq of objects, or a function to a set/iset/multiset/seq of objects (instead got () ~> map<object?, object?>) +TypeInferenceRefreshErrors.dfy(33,12): Error: PRE-TYPE: type cast to reference type 'C?' must be from an expression assignable to it (got 'D?') +TypeInferenceRefreshErrors.dfy(34,12): Error: PRE-TYPE: type cast to reference type 'D?' must be from an expression assignable to it (got 'C?') +TypeInferenceRefreshErrors.dfy(41,13): Error: PRE-TYPE: logical/bitwise negation expects a boolean or bitvector argument (instead got ?0) +TypeInferenceRefreshErrors.dfy(64,8): Error: PRE-TYPE: the type ('map<?8, ?9>') of this local variable is underspecified +TypeInferenceRefreshErrors.dfy(65,8): Error: PRE-TYPE: the type ('map<?10, ?11>') of this local variable is underspecified +TypeInferenceRefreshErrors.dfy(66,8): Error: PRE-TYPE: the type ('map<?18, ?19>') of this local variable is underspecified +TypeInferenceRefreshErrors.dfy(67,11): Error: PRE-TYPE: the type ('map<?16, ?17>') of this expression is underspecified +TypeInferenceRefreshErrors.dfy(76,8): Error: PRE-TYPE: the type ('Synonym<int, ?4>') of this variable is underspecified +TypeInferenceRefreshErrors.dfy(85,8): Error: the type of this local variable is underspecified +TypeInferenceRefreshErrors.dfy(97,8): Error: PRE-TYPE: the type ('Synonym<int, ?3>') of this variable is underspecified +TypeInferenceRefreshErrors.dfy(100,8): Error: PRE-TYPE: the type ('Synonym<int, ?6>') of this variable is underspecified +16 resolution/type errors detected in TypeInferenceRefreshErrors.dfy diff --git a/Test/dafny4/ClassRefinement.dfy.verifier.expect b/Test/dafny4/ClassRefinement.dfy.verifier.expect index 543e77303b5..7e1c9137a16 100644 --- a/Test/dafny4/ClassRefinement.dfy.verifier.expect +++ b/Test/dafny4/ClassRefinement.dfy.verifier.expect @@ -2,5 +2,5 @@ ClassRefinement.dfy(68,9): Warning: the ... refinement feature in statements is ClassRefinement.dfy(69,13): Warning: the ... refinement feature in statements is deprecated ClassRefinement.dfy(74,9): Warning: the ... refinement feature in statements is deprecated ClassRefinement.dfy(75,13): Warning: the ... refinement feature in statements is deprecated -ClassRefinement.dfy(77,6): Warning: the modify statement with a block statement is deprecated +ClassRefinement.dfy(75,17): Warning: the modify statement with a block statement is deprecated ClassRefinement.dfy(78,13): Warning: the ... refinement feature in statements is deprecated diff --git a/Test/exports/ExportResolve.dfy b/Test/exports/ExportResolve.dfy index 9225f900bbe..426e7f07774 100644 --- a/Test/exports/ExportResolve.dfy +++ b/Test/exports/ExportResolve.dfy @@ -603,7 +603,7 @@ module StarsGoodClient_All { module StarsGoodClient_AllAndMore { import S = StarsGood`ProvideAllAndThenSomeMore - method M(b: S.B, c: S.C) { + method M(b: S.B, c: S.C, d: S.D) { var f0 := b.F(); var g0 := b.G(); var u0 := c.u; @@ -614,16 +614,9 @@ module StarsGoodClient_AllAndMore { r0 := S.E.PI; r0 := S.F.PI; - var d: S.D; - - d := new S.D; // error: no constructors of D are known, but that doesn't mean there aren't any - var u1 := d.u; - - var e := new S.E; // error: it is not known if E has any constructors or not, so this is not allowed - var f: S.F; if * { - f.M(); // error: to use d, it must first be initialized + f.M(); // error: to use f, it must first be initialized f := new S.F.FromInt(5); // error: FromInt has not been exported, and it also isn't known that F is a class type } else { f := S.F.Make(); @@ -632,3 +625,15 @@ module StarsGoodClient_AllAndMore { } } } + +module StarsGoodClient_AllAndMore' { + import S = StarsGood`ProvideAllAndThenSomeMore + method M() { + var d: S.D; + + d := new S.D; // error: no constructors of D are known, but that doesn't mean there aren't any + var u1 := d.u; + + var e := new S.E; // error: it is not known if E has any constructors or not, so this is not allowed + } +} diff --git a/Test/exports/ExportResolve.dfy.expect b/Test/exports/ExportResolve.dfy.expect index 1e175ca6c8e..d641ad7253a 100644 --- a/Test/exports/ExportResolve.dfy.expect +++ b/Test/exports/ExportResolve.dfy.expect @@ -113,9 +113,9 @@ ExportResolve.dfy(590,16): Error: member 'u' has not been imported in this scope ExportResolve.dfy(595,19): Error: member 'FromInt' does not exist in type 'F' or cannot be part of type name ExportResolve.dfy(595,11): Error: new can be applied only to class types (got S.F.FromInt) ExportResolve.dfy(599,18): Error: member 'u' has not been imported in this scope and cannot be accessed here -ExportResolve.dfy(619,6): Error: when allocating an object of type 'D', one of its constructor methods must be called -ExportResolve.dfy(622,10): Error: when allocating an object of imported type 'E', one of its constructor methods must be called -ExportResolve.dfy(627,19): Error: member 'FromInt' does not exist in type 'F' or cannot be part of type name -ExportResolve.dfy(627,11): Error: new can be applied only to class types (got S.F.FromInt) -ExportResolve.dfy(631,18): Error: member 'u' has not been imported in this scope and cannot be accessed here +ExportResolve.dfy(620,19): Error: member 'FromInt' does not exist in type 'F' or cannot be part of type name +ExportResolve.dfy(620,11): Error: new can be applied only to class types (got S.F.FromInt) +ExportResolve.dfy(624,18): Error: member 'u' has not been imported in this scope and cannot be accessed here +ExportResolve.dfy(634,6): Error: when allocating an object of type 'D', one of its constructor methods must be called +ExportResolve.dfy(637,10): Error: when allocating an object of imported type 'E', one of its constructor methods must be called 120 resolution/type errors detected in ExportResolve.dfy diff --git a/Test/git-issues/git-issue-1252.dfy.expect b/Test/git-issues/git-issue-1252.dfy.expect index 8edb030a1ef..2c02325d163 100644 --- a/Test/git-issues/git-issue-1252.dfy.expect +++ b/Test/git-issues/git-issue-1252.dfy.expect @@ -1,4 +1,4 @@ -git-issue-1252.dfy(41,2): Warning: the modify statement with a block statement is deprecated +git-issue-1252.dfy(37,16): Warning: the modify statement with a block statement is deprecated git-issue-1252.dfy(30,11): Error: target object might be null git-issue-1252.dfy(37,11): Error: target object might be null git-issue-1252.dfy(45,13): Error: target object might be null diff --git a/Test/git-issues/git-issue-4272.dfy b/Test/git-issues/git-issue-4272.dfy new file mode 100644 index 00000000000..32f8bcfff50 --- /dev/null +++ b/Test/git-issues/git-issue-4272.dfy @@ -0,0 +1,17 @@ +// RUN: %dafny /compile:0 /typeSystemRefresh:1 "%s" > "%t" +// RUN: %diff "%s.expect" "%t" + +module Bar { + class Foo { + // The following line once used to give an error, because newtype "b1" had not yet been resolved + const c0: b1 := 4 + } + newtype b1 = x | 0 <= x < 11/2 +} + +module Zar { + newtype b1 = x | 0 <= x < 11/2 + class Foo { + const c0: b1 := 4 + } +} diff --git a/Test/git-issues/git-issue-4272.dfy.expect b/Test/git-issues/git-issue-4272.dfy.expect new file mode 100644 index 00000000000..ba00363fc08 --- /dev/null +++ b/Test/git-issues/git-issue-4272.dfy.expect @@ -0,0 +1,2 @@ + +Dafny program verifier finished with 4 verified, 0 errors diff --git a/Test/traits/GeneralTraits.dfy b/Test/traits/GeneralTraits.dfy new file mode 100644 index 00000000000..34dd5f6093b --- /dev/null +++ b/Test/traits/GeneralTraits.dfy @@ -0,0 +1,150 @@ +// RUN: %exits-with 2 %dafny /typeSystemRefresh:1 /generalTraits:1 "%s" > "%t" +// RUN: %diff "%s.expect" "%t" + +module Tests { + trait Parent { } + + class Class extends Parent { } + datatype Dt extends Parent = Blue | Red + codatatype CoDt extends Parent = InfiniteBlue | InfiniteRed + type Abstract extends Parent + newtype MyInt extends Parent = int + newtype MyConstrainedInt extends Parent = x | 0 <= x < 10 + + method M(d: Dt, a: Abstract) { + var p: Parent; + p := d; + p := a; + } +} + +module BadObjectExtensions { + trait Parent extends object { } + class Class extends Parent { } + datatype RefDt extends Parent = Grey | Orange // error: datatype cannot extend object + codatatype CoDt extends Parent = InfiniteBlue | InfiniteRed // error: datatype cannot extend object + type RefAbstract extends Parent // error: abstract type cannot extend object + newtype MyInt extends Parent = int // error: abstract type cannot extend object + newtype MyConstrainedInt extends Parent = x | 0 <= x < 10 // error: abstract type cannot extend object +} + +module ExportThings { + export Revealthem + reveals Trait, Class, Dt, CoDt, Abstract, MyInt, MyConstrainedInt + reveals TraitSub, AnotherClass + reveals ProvidedAbstractType + reveals RevealedAbstractType + export ProvideThem // error: inconsistent export set + provides Trait, Class, Dt, CoDt, Abstract, MyInt, MyConstrainedInt + provides TraitSub, AnotherClass + provides ProvidedAbstractType + reveals RevealedAbstractType + + trait Trait { } + + class Class extends Trait { } + datatype Dt extends Trait = Grey | Orange + codatatype CoDt extends Trait = InfiniteBlue | InfiniteRed + type Abstract extends Trait + newtype MyInt extends Trait = int + newtype MyConstrainedInt extends Trait = x | 0 <= x < 10 + + trait TraitSub extends Trait { } + class AnotherClass extends TraitSub { } + + type ProvidedAbstractType extends Trait { } // fine + type RevealedAbstractType extends Trait { } // error: the "extends" clause is exported, but Trait is not known to be a trait +} + +module ComparableTypes0 { + trait TraitA { } + trait TraitB extends TraitA { } + trait TraitC extends TraitA { } + newtype MyInt extends TraitB = x | 0 <= x < 100 + datatype Dt extends TraitB = Grey | Orange + + method Tests(o: object, a: TraitA, b: TraitB, c: TraitC, mi: MyInt, dt: Dt) { + var r; + r := mi == mi; + + r := o == mi; // error: object and MyInt are incomparable + r := c == mi; // error: TraitC and MyInt are incomparable + + r := mi == o; // error: MyInt and object are incomparable + r := mi == c; // error: MyInt and TraitC are incomparable + + r := dt == dt; + + r := o == dt; // error: object and Dt are incomparable + r := c == dt; // error: TraitC and Dt are incomparable + + r := dt == o; // error: Dt and object are incomparable + r := dt == c; // error: Dt and TraitC are incomparable + } +} + +module ComparableTypes1 { + trait TraitA { } + trait TraitB extends TraitA { } + trait TraitC extends TraitA { } + newtype MyInt extends TraitB = x | 0 <= x < 100 + datatype Dt extends TraitB = Grey | Orange + + method Tests(a: TraitA, b: TraitB, c: TraitC, mi: MyInt, dt: Dt) { + var r; + r := a == mi; // error: TraitA does not support equality + r := b == mi; // error: TraitB does not support equality + + r := mi == a; // error: TraitA does not support equality + r := mi == b; // error: TraitB does not support equality + + r := a == dt; // error: TraitA does not support equality + r := b == dt; // error: TraitB does not support equality + + r := dt == a; // error: TraitA does not support equality + r := dt == b; // error: TraitB does not support equality + + r := a == Grey; // error: TraitA does not support equality + r := Grey == a; // error: TraitA does not support equality + } +} + +// This module contains litmus tests that members can be looked up in built-in types, user-defined +// types in the current module, and user-defined types in an imported module. +module MemberLookups { + module Library { + trait LibTrait { + static const n: nat := 18 + const r: nat + } + } + + module Client { + import L = Library + + trait Parent { + static const m: nat := 18 + const k: nat + } + + method TestParent(p: Parent) { + var u := Parent.m; + var v := p.m; + var w := p.k; + } + + method TestLibrary(t: L.LibTrait) { + var a := L.LibTrait.n; + var b := t.n; + var c := t.r; + } + + method Bitvectors(v: bv13) { + var w := v.RotateLeft(2); + } + + method Reals(r: real) returns (x: int) { + x := r.Floor; + } + } +} diff --git a/Test/traits/GeneralTraits.dfy.expect b/Test/traits/GeneralTraits.dfy.expect new file mode 100644 index 00000000000..828027a9f7e --- /dev/null +++ b/Test/traits/GeneralTraits.dfy.expect @@ -0,0 +1,26 @@ +GeneralTraits.dfy(24,25): Error: datatype is not allowed to extend 'Parent', because it is a reference type +GeneralTraits.dfy(25,26): Error: codatatype is not allowed to extend 'Parent', because it is a reference type +GeneralTraits.dfy(26,27): Error: abstract type is not allowed to extend 'Parent', because it is a reference type +GeneralTraits.dfy(27,24): Error: newtype is not allowed to extend 'Parent', because it is a reference type +GeneralTraits.dfy(28,35): Error: newtype is not allowed to extend 'Parent', because it is a reference type +GeneralTraits.dfy(56,36): Error: Raised while checking export set ProvideThem: a abstract type can only extend traits (found 'Trait') +GeneralTraits.dfy(37,9): Error: This export set is not consistent: ProvideThem +GeneralTraits.dfy(70,11): Error: PRE-TYPE: arguments must have comparable types (got object? and MyInt) +GeneralTraits.dfy(71,11): Error: PRE-TYPE: arguments must have comparable types (got TraitC and MyInt) +GeneralTraits.dfy(73,12): Error: PRE-TYPE: arguments must have comparable types (got MyInt and object?) +GeneralTraits.dfy(74,12): Error: PRE-TYPE: arguments must have comparable types (got MyInt and TraitC) +GeneralTraits.dfy(78,11): Error: PRE-TYPE: arguments must have comparable types (got object? and Dt) +GeneralTraits.dfy(79,11): Error: PRE-TYPE: arguments must have comparable types (got TraitC and Dt) +GeneralTraits.dfy(81,12): Error: PRE-TYPE: arguments must have comparable types (got Dt and object?) +GeneralTraits.dfy(82,12): Error: PRE-TYPE: arguments must have comparable types (got Dt and TraitC) +GeneralTraits.dfy(95,9): Error: == can only be applied to expressions of types that support equality (got TraitA) +GeneralTraits.dfy(96,9): Error: == can only be applied to expressions of types that support equality (got TraitB) +GeneralTraits.dfy(98,15): Error: == can only be applied to expressions of types that support equality (got TraitA) +GeneralTraits.dfy(99,15): Error: == can only be applied to expressions of types that support equality (got TraitB) +GeneralTraits.dfy(101,9): Error: == can only be applied to expressions of types that support equality (got TraitA) +GeneralTraits.dfy(102,9): Error: == can only be applied to expressions of types that support equality (got TraitB) +GeneralTraits.dfy(104,15): Error: == can only be applied to expressions of types that support equality (got TraitA) +GeneralTraits.dfy(105,15): Error: == can only be applied to expressions of types that support equality (got TraitB) +GeneralTraits.dfy(107,9): Error: == can only be applied to expressions of types that support equality (got TraitA) +GeneralTraits.dfy(108,17): Error: == can only be applied to expressions of types that support equality (got TraitA) +25 resolution/type errors detected in GeneralTraits.dfy diff --git a/Test/traits/GeneralTraitsCompile.dfy b/Test/traits/GeneralTraitsCompile.dfy new file mode 100644 index 00000000000..ba491c9b971 --- /dev/null +++ b/Test/traits/GeneralTraitsCompile.dfy @@ -0,0 +1,442 @@ +// RUN: %testDafnyForEachCompiler "%s" -- --general-traits --type-system-refresh + +method Main() { + Tests.Test(); + InstanceMemberInheritance.Test(); + StaticMemberInheritanceAccessViaName.Test(); + StaticMemberInheritanceAccessViaReceiver.Test(); + NiceStarterTests.Test(); + print "done\n"; +} + +module Tests { + method Test() { + var c: Class := new Class; + var d: Dt := Blue; + var co: CoDt := InfiniteBlue; + var mi: MyInt := 65; + var mc: MyConstrainedInt := 6; + + M(c, d, co, mi, mc); + P(c); + P(d); + P(co); + P(mi); + P(mc); + Q(c, d, co, mi, mc); + } + + trait Parent { } + + class Class extends Parent { } + datatype Dt extends Parent = Blue | Red + codatatype CoDt extends Parent = InfiniteBlue | InfiniteRed + newtype MyInt extends Parent = int + newtype MyConstrainedInt extends Parent = x | 0 <= x < 10 + + method M(c: Class, d: Dt, co: CoDt, mi: MyInt, mc: MyConstrainedInt) { + var p: Parent; + p := c; + assert p is Class; + p := d; + assert p is Dt; + p := co; + assert p is CoDt; + p := mi; + assert p is MyInt; + p := mc; + assert p is MyConstrainedInt; + } + + method P(p: Parent) + requires p is Class || p is Dt || p is CoDt || p is MyInt || p is MyConstrainedInt + { + if + case p is Class => + var x: Class; + x := p as Class; + case p is Dt => + var x: Dt; + x := p as Dt; + case p is CoDt => + var x: CoDt; + x := p as CoDt; + case p is MyInt => + var x: MyInt; + x := p as MyInt; + case p is MyConstrainedInt => + var x: MyConstrainedInt; + x := p as MyConstrainedInt; + } + + method Q(c: Class, d: Dt, co: CoDt, mi: MyInt, mc: MyConstrainedInt) { + var c: Class, d: Dt, co: CoDt, mi: MyInt, mc: MyConstrainedInt := c, d, co, mi, mc; + var p: Parent; + + p := c; + c := p as Class; + + p := d; + d := p as Dt; + + p := co; + co := p as CoDt; + + p := mi; + mi := p as MyInt; + + p := mc; + mc := p as MyConstrainedInt; + } +} + +// ----- test inheritance of instance members + +module InstanceMemberInheritance { + method Test() { + var p; + p := TestClass(); + TestParent(p); + p := TestDatatype(); + TestParent(p); + p := TestCoDatatype(); + TestParent(p); + p := TestMyInt(); + TestParent(p); + p := TestMyConstrainedInt(); + TestParent(p); + } + + trait Parent { + const m: nat := 18 + const n: nat + function F(): int { + 10 + } + function G(): int + method M() { + print "hello M, "; + } + method P() + } + + method TestParent(p: Parent) { + assert p.m == 18 && p.F() == 10; + print p.m, " ", p.n, " ", p.F(), " ", p.G(), "\n"; // 18 0 10 <...11> + p.M(); // hello M, + p.P(); // hello <...Class>.P + print "-----\n"; + } + + // ----- class + + class Class extends Parent { + function G(): int { + 11 + } + method P() { + print "hello Class.P\n"; + } + } + + method TestClass() returns (p: Parent) { + var x := new Class; + assert x.m == 18 && x.F() == 10 && x.G() == 11; + print x.m, " ", x.n, " ", x.F(), " ", x.G(), "\n"; // 18 0 10 11 + x.M(); // hello M, + x.P(); // hello Class.P + return x; + } + + // ----- datatype + + datatype Datatype extends Parent = DtOne + { + function G(): int { + 12 + } + method P() { + print "hello Dt.P\n"; + } + } + + method TestDatatype() returns (p: Parent) { + var x := DtOne; + assert x.m == 18 && x.F() == 10 && x.G() == 12; + print x.m, " ", x.n, " ", x.F(), " ", x.G(), "\n"; // 18 0 10 12 + x.M(); // hello M, + x.P(); // hello Datatype.P + return x; + } + + // ----- codatatype + + codatatype CoDatatype extends Parent = CoOne + { + function G(): int { + 13 + } + method P() { + print "hello CoDatatype.P\n"; + } + } + + method TestCoDatatype() returns (p: Parent) { + var x := CoOne; + assert x.m == 18 && x.F() == 10 && x.G() == 13; + print x.m, " ", x.n, " ", x.F(), " ", x.G(), "\n"; // 18 0 10 13 + x.M(); // hello M, + x.P(); // hello CoDatatype.P + return x; + } + + // ----- newtype without constraint + + newtype MyInt extends Parent = int { + function G(): int { + 15 + } + method P() { + print "hello MyInt.P\n"; + } + } + + method TestMyInt() returns (p: Parent) { + var x: MyInt := 100; + assert x.m == 18 && x.F() == 10 && x.G() == 15; + print x.m, " ", x.n, " ", x.F(), " ", x.G(), "\n"; // 18 0 10 15 + x.M(); // hello M, + x.P(); // hello MyInt.P + return x; + } + + // ----- newtype with constraint + + newtype MyConstrainedInt extends Parent = x: int | 0 <= x < 10 + { + function G(): int { + 16 + } + method P() { + print "hello MyConstrainedInt.P\n"; + } + } + + method TestMyConstrainedInt() returns (p: Parent) { + var x: MyConstrainedInt := 7; + assert x.m == 18 && x.F() == 10 && x.G() == 16; + print x.m, " ", x.n, " ", x.F(), " ", x.G(), "\n"; // 18 0 10 16 + x.M(); // hello M, + x.P(); // hello MyConstrainedInt.P + return x; + } +} + +module StaticMemberInheritanceAccessViaName { + method Test() { + TestParent(); + TestClass(); + TestDatatype(); + TestCoDatatype(); + TestMyInt(); + TestMyConstrainedInt(); + print "=====\n"; + } + + trait Parent { + static const m: nat := 18 + static const n: nat + static function F(): int { + 10 + } + static method M() { + print "hello static-via-name M\n"; + } + } + + method TestParent() { + assert Parent.m == 18 && Parent.F() == 10; + print Parent.m, " ", Parent.n, " ", Parent.F(), "\n"; // 18 0 10 + Parent.M(); // hello static-via-name M + print "-----\n"; + } + + // ----- class + + class Class extends Parent { + } + + method TestClass() { + assert Class.m == 18 && Class.F() == 10; + print Class.m, " ", Class.n, " ", Class.F(), "\n"; // 18 0 10 + Class.M(); // hello static-via-name M + } + + // ----- datatype + + datatype Datatype extends Parent = DtOne + + method TestDatatype() { + assert Datatype.m == 18 && Datatype.F() == 10; + print Datatype.m, " ", Datatype.n, " ", Datatype.F(), "\n"; // 18 0 10 + Datatype.M(); // hello static-via-name M + } + + // ----- codatatype + + codatatype CoDatatype extends Parent = CoOne + + method TestCoDatatype() { + assert CoDatatype.m == 18 && CoDatatype.F() == 10; + print CoDatatype.m, " ", CoDatatype.n, " ", CoDatatype.F(), "\n"; // 18 0 10 + CoDatatype.M(); // hello static-via-name M + } + + // ----- newtype without constraint + + newtype MyInt extends Parent = int + + method TestMyInt() { + assert MyInt.m == 18 && MyInt.F() == 10; + print MyInt.m, " ", MyInt.n, " ", MyInt.F(), "\n"; // 18 0 10 + MyInt.M(); // hello static-via-name M + } + + // ----- newtype with constraint + + newtype MyConstrainedInt extends Parent = x: int | 0 <= x < 10 + + method TestMyConstrainedInt() { + assert MyConstrainedInt.m == 18 && MyConstrainedInt.F() == 10; + print MyConstrainedInt.m, " ", MyConstrainedInt.n, " ", MyConstrainedInt.F(),"\n"; // 18 0 10 + MyConstrainedInt.M(); // hello static-via-name M + } +} + +module StaticMemberInheritanceAccessViaReceiver { + method Test() { + var p; + p := TestClass(); + TestParent(p); + p := TestDatatype(); + TestParent(p); + p := TestCoDatatype(); + TestParent(p); + p := TestMyInt(); + TestParent(p); + p := TestMyConstrainedInt(); + TestParent(p); + } + + trait Parent { + static const m: nat := 18 + static const n: nat + static function F(): int { + 10 + } + static method M() { + print "hello static-via-receiver M\n"; + } + } + + method TestParent(p: Parent) { + assert p.m == 18 && p.F() == 10; + print p.m, " ", p.n, " ", p.F(), "\n"; // 18 0 10 + p.M(); // hello static-via-receiver M + print "-----\n"; + } + + // ----- class + + class Class extends Parent { + } + + method TestClass() returns (p: Parent) { + var x := new Class; + assert x.m == 18 && x.F() == 10; + print x.m, " ", x.n, " ", x.F(), "\n"; // 18 0 10 + x.M(); // hello static-via-receiver M + return x; + } + + // ----- datatype + + datatype Datatype extends Parent = DtOne + + method TestDatatype() returns (p: Parent) { + var x := DtOne; + assert x.m == 18 && x.F() == 10; + print x.m, " ", x.n, " ", x.F(), "\n"; // 18 0 10 + x.M(); // hello static-via-receiver M + return x; + } + + // ----- codatatype + + codatatype CoDatatype extends Parent = CoOne + + method TestCoDatatype() returns (p: Parent) { + var x := CoOne; + assert x.m == 18 && x.F() == 10; + print x.m, " ", x.n, " ", x.F(), "\n"; // 18 0 10 + x.M(); // hello static-via-receiver M + return x; + } + + // ----- newtype without constraint + + newtype MyInt extends Parent = int + + method TestMyInt() returns (p: Parent) { + var x: MyInt := 100; + assert x.m == 18 && x.F() == 10; + print x.m, " ", x.n, " ", x.F(), "\n"; // 18 0 10 + x.M(); // hello static-via-receiver M + return x; + } + + // ----- newtype with constraint + + newtype MyConstrainedInt extends Parent = x: int | 0 <= x < 10 + + method TestMyConstrainedInt() returns (p: Parent) { + var x: MyConstrainedInt := 7; + assert x.m == 18 && x.F() == 10; + print x.m, " ", x.n, " ", x.F(),"\n"; // 18 0 10 + x.M(); // hello static-via-receiver M + return x; + } +} + +module NiceStarterTests { + trait Parent { + method MyMethod<Y(0)>(a: int) returns (r: int) + } + + datatype Color<X(0)> extends Parent = Blue | Gray(n: nat) + { + method MyMethod<Y(0)>(a: int) returns (r: int) { + var x: X; + var y: Y; + r := a + a + 3; + } + } + + class MyClass<X(0)> extends Parent + { + method MyMethod<Y(0)>(a: int) returns (r: int) { + var x: X; + var y: Y; + r := a + 3; + } + } + + method Test() { + var u := Color<real>.Gray(15); + var s := u.MyMethod<bool>(10); + + var p: Parent := u; + var t := p.MyMethod<bool>(10); + print s, " ", t, "\n"; // 23 23 + } +} diff --git a/Test/traits/GeneralTraitsCompile.dfy.expect b/Test/traits/GeneralTraitsCompile.dfy.expect new file mode 100644 index 00000000000..18964f47e86 --- /dev/null +++ b/Test/traits/GeneralTraitsCompile.dfy.expect @@ -0,0 +1,66 @@ +18 0 10 11 +hello M, hello Class.P +18 0 10 11 +hello M, hello Class.P +----- +18 0 10 12 +hello M, hello Dt.P +18 0 10 12 +hello M, hello Dt.P +----- +18 0 10 13 +hello M, hello CoDatatype.P +18 0 10 13 +hello M, hello CoDatatype.P +----- +18 0 10 15 +hello M, hello MyInt.P +18 0 10 15 +hello M, hello MyInt.P +----- +18 0 10 16 +hello M, hello MyConstrainedInt.P +18 0 10 16 +hello M, hello MyConstrainedInt.P +----- +18 0 10 +hello static-via-name M +----- +18 0 10 +hello static-via-name M +18 0 10 +hello static-via-name M +18 0 10 +hello static-via-name M +18 0 10 +hello static-via-name M +18 0 10 +hello static-via-name M +===== +18 0 10 +hello static-via-receiver M +18 0 10 +hello static-via-receiver M +----- +18 0 10 +hello static-via-receiver M +18 0 10 +hello static-via-receiver M +----- +18 0 10 +hello static-via-receiver M +18 0 10 +hello static-via-receiver M +----- +18 0 10 +hello static-via-receiver M +18 0 10 +hello static-via-receiver M +----- +18 0 10 +hello static-via-receiver M +18 0 10 +hello static-via-receiver M +----- +23 23 +done diff --git a/Test/traits/GeneralTraitsVerify.dfy b/Test/traits/GeneralTraitsVerify.dfy new file mode 100644 index 00000000000..8def00b24b0 --- /dev/null +++ b/Test/traits/GeneralTraitsVerify.dfy @@ -0,0 +1,471 @@ +// RUN: %exits-with 4 %dafny /typeSystemRefresh:1 /generalTraits:1 "%s" > "%t" +// RUN: %diff "%s.expect" "%t" + +module Tests { + trait Parent { } + + class Class extends Parent { } + datatype Dt extends Parent = Blue | Red + codatatype CoDt extends Parent = InfiniteBlue | InfiniteRed + type Abstract extends Parent + newtype MyInt extends Parent = int + newtype MyConstrainedInt extends Parent = x | 0 <= x < 10 + + method M(c: Class, d: Dt, co: CoDt, a: Abstract, mi: MyInt, mc: MyConstrainedInt) { + var p: Parent; + p := c; + assert p is Class; + p := d; + assert p is Dt; + p := co; + assert p is CoDt; + p := a; + assert p is Abstract; + p := mi; + assert p is MyInt; + p := mc; + assert p is MyConstrainedInt; + } + + method N0(p: Parent) { + if + case true => + var x: Class; + x := p as Class; // error + case true => + var x: Dt; + x := p as Dt; // error + case true => + var x: CoDt; + x := p as CoDt; // error + case true => + var x: Abstract; + x := p as Abstract; // error + } + + method N1(p: Parent) { + if + case true => + var x: MyInt; + x := p as MyInt; // error + case true => + var x: MyConstrainedInt; + x := p as MyConstrainedInt; // error + } + + method P(p: Parent) { + if + case p is Class => + var x: Class; + x := p as Class; + case p is Dt => + var x: Dt; + x := p as Dt; + case p is CoDt => + var x: CoDt; + x := p as CoDt; + case p is Abstract => + var x: Abstract; + x := p as Abstract; + case p is MyInt => + var x: MyInt; + x := p as MyInt; + case p is MyConstrainedInt => + var x: MyConstrainedInt; + x := p as MyConstrainedInt; + case true => + } + + method Q(c: Class, d: Dt, co: CoDt, a: Abstract, mi: MyInt, mc: MyConstrainedInt) { + var c: Class, d: Dt, co: CoDt, a: Abstract, mi: MyInt, mc: MyConstrainedInt := c, d, co, a, mi, mc; + var p: Parent; + + p := c; + c := p as Class; + + p := d; + d := p as Dt; + + p := co; + co := p as CoDt; + + p := a; + a := p as Abstract; + + p := mi; + mi := p as MyInt; + + p := mc; + mc := p as MyConstrainedInt; + } +} + +// ----- test inheritance of instance members + +module InstanceMemberInheritance { + method Test() { + var p; + p := TestClass(); + TestParent(p); + p := TestDatatype(); + TestParent(p); + p := TestCoDatatype(); + TestParent(p); + // note, can't call TestAbstract, since it's abstract + p := TestMyInt(); + TestParent(p); + p := TestMyConstrainedInt(); + TestParent(p); + } + + trait Parent { + const m: nat := 18 + const n: nat + function F(): int { + 10 + } + function G(): int + method M() { + print "hello M, "; + } + method P() + } + + method TestParent(p: Parent) { + assert p.m == 18 && p.F() == 10; + print p.m, " ", p.n, " ", p.F(), " ", p.G(), "\n"; // 18 0 10 <...11> + p.M(); // hello M, + p.P(); // hello <...Class>.P + print "-----\n"; + } + + // ----- class + + class Class extends Parent { + function G(): int { + 11 + } + method P() { + print "hello Class.P\n"; + } + } + + method TestClass() returns (p: Parent) { + var x := new Class; + assert x.m == 18 && x.F() == 10 && x.G() == 11; + print x.m, " ", x.n, " ", x.F(), " ", x.G(), "\n"; // 18 0 10 11 + x.M(); // hello M, + x.P(); // hello Class.P + return x; + } + + // ----- datatype + + datatype Datatype extends Parent = DtOne + { + function G(): int { + 12 + } + method P() { + print "hello Dt.P\n"; + } + } + + method TestDatatype() returns (p: Parent) { + var x := DtOne; + assert x.m == 18 && x.F() == 10 && x.G() == 12; + print x.m, " ", x.n, " ", x.F(), " ", x.G(), "\n"; // 18 0 10 12 + x.M(); // hello M, + x.P(); // hello Datatype.P + return x; + } + + // ----- codatatype + + codatatype CoDatatype extends Parent = CoOne + { + function G(): int { + 13 + } + method P() { + print "hello CoDatatype.P\n"; + } + } + + method TestCoDatatype() returns (p: Parent) { + var x := CoOne; + assert x.m == 18 && x.F() == 10 && x.G() == 13; + print x.m, " ", x.n, " ", x.F(), " ", x.G(), "\n"; // 18 0 10 13 + x.M(); // hello M, + x.P(); // hello CoDatatype.P + return x; + } + + // ----- abstract type + + type Abstract extends Parent + { + function G(): int { + 14 + } + method P() { + print "hello Abstract.P\n"; + } + } + + method TestAbstract(x: Abstract) returns (p: Parent) { + assert x.m == 18 && x.F() == 10 && x.G() == 14; + print x.m, " ", x.n, " ", x.F(), " ", x.G(), "\n"; // 18 0 10 14 + x.M(); // hello M, + x.P(); // hello Class.P + return x; + } + + // ----- newtype without constraint + + newtype MyInt extends Parent = int { + function G(): int { + 15 + } + method P() { + print "hello MyInt.P\n"; + } + } + + method TestMyInt() returns (p: Parent) { + var x: MyInt := 100; + assert x.m == 18 && x.F() == 10 && x.G() == 15; + print x.m, " ", x.n, " ", x.F(), " ", x.G(), "\n"; // 18 0 10 15 + x.M(); // hello M, + x.P(); // hello MyInt.P + return x; + } + + // ----- newtype with constraint + + newtype MyConstrainedInt extends Parent = x: int | 0 <= x < 10 + { + function G(): int { + 16 + } + method P() { + print "hello MyConstrainedInt.P\n"; + } + } + + method TestMyConstrainedInt() returns (p: Parent) { + var x: MyConstrainedInt := 7; + assert x.m == 18 && x.F() == 10 && x.G() == 16; + print x.m, " ", x.n, " ", x.F(), " ", x.G(), "\n"; // 18 0 10 16 + x.M(); // hello M, + x.P(); // hello MyConstrainedInt.P + return x; + } +} + +module StaticMemberInheritance { + method Test() { + var p; + p := TestClass(); + TestParent(p); + p := TestDatatype(); + TestParent(p); + p := TestCoDatatype(); + TestParent(p); + // note, can't call TestAbstract, since it's abstract + p := TestMyInt(); + TestParent(p); + p := TestMyConstrainedInt(); + TestParent(p); + } + + trait Parent { + static const m: nat := 18 + static const n: nat + static function F(): int { + 10 + } + static method M() { + print "hello M, "; + } + } + + method TestParent(p: Parent) { + assert p.m == 18 && p.F() == 10; + print p.m, " ", p.n, " ", p.F(), "\n"; // 18 0 10 + p.M(); // hello M, + print "-----\n"; + } + + // ----- class + + class Class extends Parent { + } + + method TestClass() returns (p: Parent) { + var x := new Class; + assert x.m == 18 && x.F() == 10; + print x.m, " ", x.n, " ", x.F(), "\n"; // 18 0 10 + x.M(); // hello M, + return x; + } + + // ----- datatype + + datatype Datatype extends Parent = DtOne + + method TestDatatype() returns (p: Parent) { + var x := DtOne; + assert x.m == 18 && x.F() == 10; + print x.m, " ", x.n, " ", x.F(), "\n"; // 18 0 10 + x.M(); // hello M, + return x; + } + + // ----- codatatype + + codatatype CoDatatype extends Parent = CoOne + + method TestCoDatatype() returns (p: Parent) { + var x := CoOne; + assert x.m == 18 && x.F() == 10; + print x.m, " ", x.n, " ", x.F(), "\n"; // 18 0 10 + x.M(); // hello M, + return x; + } + + // ----- abstract type + + type Abstract extends Parent + + method TestAbstract(x: Abstract) returns (p: Parent) { + assert x.m == 18 && x.F() == 10; + print x.m, " ", x.n, " ", x.F(), "\n"; // 18 0 10 + x.M(); // hello M, + return x; + } + + // ----- newtype without constraint + + newtype MyInt extends Parent = int + + method TestMyInt() returns (p: Parent) { + var x: MyInt := 100; + assert x.m == 18 && x.F() == 10; + print x.m, " ", x.n, " ", x.F(), "\n"; // 18 0 10 + x.M(); // hello M, + return x; + } + + // ----- newtype with constraint + + newtype MyConstrainedInt extends Parent = x: int | 0 <= x < 10 + + method TestMyConstrainedInt() returns (p: Parent) { + var x: MyConstrainedInt := 7; + assert x.m == 18 && x.F() == 10; + print x.m, " ", x.n, " ", x.F(),"\n"; // 18 0 10 + x.M(); // hello M, + return x; + } +} + +module Equality { + trait GrandParentTrait { } + + trait ParentTrait extends GrandParentTrait { } + + newtype MyInt extends ParentTrait = x | 0 <= x < 100 + + method Test() { + var mi: MyInt := 15; + var p: ParentTrait := mi; + var g: GrandParentTrait := mi; + + assert mi is MyInt && p is MyInt && g is MyInt; + assert mi is ParentTrait && p is ParentTrait && g is ParentTrait; + assert mi is GrandParentTrait && p is GrandParentTrait && g is GrandParentTrait; + + var w: ParentTrait := g as ParentTrait; + var x: MyInt := p as MyInt; + var x': MyInt := g as MyInt; + var x'': MyInt := mi as MyInt; + + assert x == x' == x'' == x == mi == p == g == w == x; + } +} + +module MoreEquality { + + trait Trait { } + newtype MyInt extends Trait = x | 0 <= x < 100 + newtype YoInt extends Trait = x | 20 <= x < 25 witness 24 + + method Tests() { + var mi: MyInt := 22; + var yi: YoInt := 22; + + var a: Trait := mi; + var b: Trait := yi; + + assert a == mi; + assert b == yi; + assert b == mi; + assert a == yi; + assert a == b; + + assert a is MyInt; + assert a is YoInt; + assert false; // error: the previous two lines should not cause any contradiction + } +} + +module InferredDecreasesClauseForReceiver { + trait Parent { + // The following method and function each gets an automatic "decreases a" (without "this") + method M(a: int) returns (r: int) + function F(a: int): int + } + + datatype Unit<X(0)> extends Parent = Unit + { + // These overrides had better also omit "this" from "decreases a", or else they won't be pass the override tests + method M(a: int) returns (r: int) { + r := a; + } + function F(a: int): int { + a + } + } + + type AbstractType<X(0)> extends Parent { + // These overrides had better also omit "this" from "decreases a", or else they won't be pass the override tests + method M(a: int) returns (r: int) { + r := a; + } + function F(a: int): int { + a + } + } + + class Class<X(0)> extends Parent { + // These overrides had better also omit "this" from "decreases a", or else they won't be pass the override tests + method M(a: int) returns (r: int) { + r := a; + } + function F(a: int): int { + a + } + } + + newtype MyInt extends Parent = int + { + // These overrides had better also omit "this" from "decreases a", or else they won't be pass the override tests + method M(a: int) returns (r: int) { + r := a; + } + function F(a: int): int { + a + } + } +} diff --git a/Test/traits/GeneralTraitsVerify.dfy.expect b/Test/traits/GeneralTraitsVerify.dfy.expect new file mode 100644 index 00000000000..518d3c24e9a --- /dev/null +++ b/Test/traits/GeneralTraitsVerify.dfy.expect @@ -0,0 +1,9 @@ +GeneralTraitsVerify.dfy(34,13): Error: value of expression (of type 'Parent') is not known to be an instance of type 'Class' +GeneralTraitsVerify.dfy(37,13): Error: value of expression (of type 'Parent') is not known to be an instance of type 'Dt' +GeneralTraitsVerify.dfy(40,13): Error: value of expression (of type 'Parent') is not known to be an instance of type 'CoDt' +GeneralTraitsVerify.dfy(43,13): Error: value of expression (of type 'Parent') is not known to be an instance of type 'Abstract' +GeneralTraitsVerify.dfy(50,13): Error: value of expression (of type 'Parent') is not known to be an instance of type 'MyInt' +GeneralTraitsVerify.dfy(53,13): Error: value does not satisfy the subset constraints of 'MyConstrainedInt' +GeneralTraitsVerify.dfy(419,11): Error: assertion might not hold + +Dafny program verifier finished with 48 verified, 7 errors diff --git a/Test/traits/TraitResolution1.dfy.expect b/Test/traits/TraitResolution1.dfy.expect index 631084d2e00..6b7c4568bb5 100644 --- a/Test/traits/TraitResolution1.dfy.expect +++ b/Test/traits/TraitResolution1.dfy.expect @@ -2,21 +2,14 @@ TraitResolution1.dfy(65,22): Error: the type of in-parameter 'x' is different fr TraitResolution1.dfy(89,14): Error: new can be applied only to class types (got A?) TraitResolution1.dfy(90,14): Error: new can be applied only to class types (got ASynonym) TraitResolution1.dfy(93,14): Error: new can be applied only to class types (got B?) -TraitResolution1.dfy(93,11): Error: when allocating an object of type 'B', one of its constructor methods must be called TraitResolution1.dfy(96,14): Error: new can be applied only to class types (got C?<A>) TraitResolution1.dfy(98,14): Error: new can be applied only to class types (got C?<A?>) TraitResolution1.dfy(101,14): Error: new can be applied only to class types (got D?<A>) -TraitResolution1.dfy(101,11): Error: when allocating an object of type 'D', one of its constructor methods must be called TraitResolution1.dfy(103,14): Error: new can be applied only to class types (got D?<A?>) -TraitResolution1.dfy(103,11): Error: when allocating an object of type 'D', one of its constructor methods must be called TraitResolution1.dfy(105,14): Error: new can be applied only to class types (got D<A>) -TraitResolution1.dfy(105,11): Error: when allocating an object of type 'D', one of its constructor methods must be called TraitResolution1.dfy(107,14): Error: new can be applied only to class types (got D<A?>) -TraitResolution1.dfy(107,11): Error: when allocating an object of type 'D', one of its constructor methods must be called TraitResolution1.dfy(108,14): Error: new can be applied only to class types (got DSynonym<A?>) -TraitResolution1.dfy(108,11): Error: when allocating an object of type 'D', one of its constructor methods must be called TraitResolution1.dfy(109,14): Error: new can be applied only to class types (got DSynonym<A?>) -TraitResolution1.dfy(109,11): Error: when allocating an object of type 'D', one of its constructor methods must be called TraitResolution1.dfy(112,14): Error: new can be applied only to class types (got object?) TraitResolution1.dfy(113,14): Error: new can be applied only to class types (got ObjectSynonym) TraitResolution1.dfy(114,14): Error: new can be applied only to class types (got ObjectWithConstraint) @@ -122,4 +115,4 @@ TraitResolution1.dfy(562,13): Error: type parameter 'R' is not allowed to change TraitResolution1.dfy(562,20): Error: type parameter 'S' is not allowed to change the requirement of supporting auto-initialization TraitResolution1.dfy(563,21): Error: type parameter 'R' is not allowed to change the requirement of being nonempty TraitResolution1.dfy(563,28): Error: type parameter 'S' is not allowed to change the requirement of supporting auto-initialization -124 resolution/type errors detected in TraitResolution1.dfy +117 resolution/type errors detected in TraitResolution1.dfy diff --git a/Test/traits/TraitResolution2.dfy.expect b/Test/traits/TraitResolution2.dfy.expect index 20d0c62e267..1237dafaf83 100644 --- a/Test/traits/TraitResolution2.dfy.expect +++ b/Test/traits/TraitResolution2.dfy.expect @@ -2,21 +2,14 @@ TraitResolution2.dfy(70,22): Error: the type of in-parameter 'x' is different fr TraitResolution2.dfy(94,14): Error: new can be applied only to class types (got A?) TraitResolution2.dfy(95,14): Error: new can be applied only to class types (got ASynonym) TraitResolution2.dfy(98,14): Error: new can be applied only to class types (got B?) -TraitResolution2.dfy(98,11): Error: when allocating an object of type 'B', one of its constructor methods must be called TraitResolution2.dfy(101,14): Error: new can be applied only to class types (got C?<A>) TraitResolution2.dfy(103,14): Error: new can be applied only to class types (got C?<A?>) TraitResolution2.dfy(106,14): Error: new can be applied only to class types (got D?<A>) -TraitResolution2.dfy(106,11): Error: when allocating an object of type 'D', one of its constructor methods must be called TraitResolution2.dfy(108,14): Error: new can be applied only to class types (got D?<A?>) -TraitResolution2.dfy(108,11): Error: when allocating an object of type 'D', one of its constructor methods must be called TraitResolution2.dfy(110,14): Error: new can be applied only to class types (got D<A>) -TraitResolution2.dfy(110,11): Error: when allocating an object of type 'D', one of its constructor methods must be called TraitResolution2.dfy(112,14): Error: new can be applied only to class types (got D<A?>) -TraitResolution2.dfy(112,11): Error: when allocating an object of type 'D', one of its constructor methods must be called TraitResolution2.dfy(113,14): Error: new can be applied only to class types (got DSynonym<A?>) -TraitResolution2.dfy(113,11): Error: when allocating an object of type 'D', one of its constructor methods must be called TraitResolution2.dfy(114,14): Error: new can be applied only to class types (got DSynonym<A?>) -TraitResolution2.dfy(114,11): Error: when allocating an object of type 'D', one of its constructor methods must be called TraitResolution2.dfy(117,14): Error: new can be applied only to class types (got object?) TraitResolution2.dfy(118,14): Error: new can be applied only to class types (got ObjectSynonym) TraitResolution2.dfy(119,14): Error: new can be applied only to class types (got ObjectWithConstraint) @@ -82,4 +75,4 @@ TraitResolution2.dfy(369,16): Error: the type of special parameter '_k' of least TraitResolution2.dfy(371,16): Error: the type of special parameter '_k' of least lemma 'M' (nat) must be the same as in the overridden least lemma (ORDINAL) TraitResolution2.dfy(375,20): Error: the type of special parameter '_k' of least predicate 'Q' (ORDINAL) must be the same as in the overridden least predicate (nat) TraitResolution2.dfy(379,16): Error: the type of special parameter '_k' of least lemma 'L' (ORDINAL) must be the same as in the overridden least lemma (nat) -84 resolution/type errors detected in TraitResolution2.dfy +77 resolution/type errors detected in TraitResolution2.dfy From 38a231ab7fa25bbbf58dbd7b09f6bf317fd9ff59 Mon Sep 17 00:00:00 2001 From: Fabio Madge <fmadge@amazon.com> Date: Sat, 5 Aug 2023 01:29:57 +0200 Subject: [PATCH 09/19] fix: Type conversions from unsigned Java types (#4384) Fixes #4152. --- .../DafnyCore/Compilers/Java/Compiler-java.cs | 24 +++++------- .../src/main/java/dafny/DafnySequence.java | 6 +-- .../src/main/java/dafny/Helpers.java | 32 ++++++++++++---- .../TypeConversionsCompile.dfy.java.expect | 38 ------------------- Test/git-issues/git-issue-4152.dfy | 12 ++++++ Test/git-issues/git-issue-4152.dfy.expect | 3 ++ 6 files changed, 52 insertions(+), 63 deletions(-) delete mode 100644 Test/dafny0/TypeConversionsCompile.dfy.java.expect create mode 100644 Test/git-issues/git-issue-4152.dfy create mode 100644 Test/git-issues/git-issue-4152.dfy.expect diff --git a/Source/DafnyCore/Compilers/Java/Compiler-java.cs b/Source/DafnyCore/Compilers/Java/Compiler-java.cs index b66c02773b2..2460a6b07da 100644 --- a/Source/DafnyCore/Compilers/Java/Compiler-java.cs +++ b/Source/DafnyCore/Compilers/Java/Compiler-java.cs @@ -4011,9 +4011,12 @@ protected override void EmitConversionExpr(ConversionExpr e, bool inLetExprBody, if (toType.IsNumericBased(Type.NumericPersuasion.Real)) { // (int or bv or char) -> real Contract.Assert(AsNativeType(toType) == null); + var fromNative = AsNativeType(fromType); wr.Write($"new {DafnyBigRationalClass}("); - if (AsNativeType(fromType) != null) { - wr.Write("java.math.BigInteger.valueOf"); + if (fromNative != null) { + wr.Write(fromNative.LowerBound >= 0 + ? $"{DafnyHelpersClass}.unsignedToBigInteger" + : "java.math.BigInteger.valueOf"); TrParenExpr(arg, wr, inLetExprBody, wStmts); wr.Write(", java.math.BigInteger.ONE)"); } else if (fromType.IsCharType) { @@ -4053,19 +4056,10 @@ protected override void EmitConversionExpr(ConversionExpr e, bool inLetExprBody, } } else if (fromNative != null && toNative == null) { // native (int or bv) -> big-integer (int or bv) - if (fromNative.Sel == NativeType.Selection.ULong) { - // Can't just use .longValue() because that may return a negative - wr.Write($"{DafnyHelpersClass}.unsignedLongToBigInteger"); - TrParenExpr(arg, wr, inLetExprBody, wStmts); - } else { - wr.Write("java.math.BigInteger.valueOf("); - if (fromNative.LowerBound >= 0) { - TrParenExpr($"{GetBoxedNativeTypeName(fromNative)}.toUnsignedLong", arg, wr, inLetExprBody, wStmts); - } else { - TrParenExpr(arg, wr, inLetExprBody, wStmts); - } - wr.Write(")"); - } + wr.Write(fromNative.LowerBound >= 0 + ? $"{DafnyHelpersClass}.unsignedToBigInteger" + : "java.math.BigInteger.valueOf"); + TrParenExpr(arg, wr, inLetExprBody, wStmts); } else if (fromNative != null && NativeTypeSize(toNative) == NativeTypeSize(fromNative)) { // native (int or bv) -> native (int or bv) // Cast between signed and unsigned, which have the same Java type diff --git a/Source/DafnyRuntime/DafnyRuntimeJava/src/main/java/dafny/DafnySequence.java b/Source/DafnyRuntime/DafnyRuntimeJava/src/main/java/dafny/DafnySequence.java index b14f0eaae00..533000c221b 100644 --- a/Source/DafnyRuntime/DafnyRuntimeJava/src/main/java/dafny/DafnySequence.java +++ b/Source/DafnyRuntime/DafnyRuntimeJava/src/main/java/dafny/DafnySequence.java @@ -262,7 +262,7 @@ public T select(long i) { } public T selectUnsigned(long i) { - return select(Helpers.unsignedLongToBigInteger(i)); + return select(Helpers.unsignedToBigInteger(i)); } public T select(BigInteger i) { @@ -326,7 +326,7 @@ public DafnySequence<T> drop(long lo) { } public DafnySequence<T> dropUnsigned(long lo) { - return drop(Helpers.unsignedLongToBigInteger(lo)); + return drop(Helpers.unsignedToBigInteger(lo)); } public DafnySequence<T> drop(BigInteger lo) { @@ -357,7 +357,7 @@ public DafnySequence<T> take(long hi) { } public DafnySequence<T> takeUnsigned(long hi) { - return take(Helpers.unsignedLongToBigInteger(hi)); + return take(Helpers.unsignedToBigInteger(hi)); } public DafnySequence<T> take(BigInteger hi) { diff --git a/Source/DafnyRuntime/DafnyRuntimeJava/src/main/java/dafny/Helpers.java b/Source/DafnyRuntime/DafnyRuntimeJava/src/main/java/dafny/Helpers.java index 4509185855b..9e78dc8c177 100644 --- a/Source/DafnyRuntime/DafnyRuntimeJava/src/main/java/dafny/Helpers.java +++ b/Source/DafnyRuntime/DafnyRuntimeJava/src/main/java/dafny/Helpers.java @@ -248,14 +248,32 @@ public static int unsignedToInt(long x) { return (int)x; } - private final static BigInteger ULONG_LIMIT = new BigInteger("18446744073709551616"); // 0x1_0000_0000_0000_0000 - - public static BigInteger unsignedLongToBigInteger(long l) { - if (0 <= l) { - return BigInteger.valueOf(l); - } else { - return BigInteger.valueOf(l).add(ULONG_LIMIT); + private final static BigInteger BYTE_LIMIT = new BigInteger("256"); // 0x1_00 + private final static BigInteger USHORT_LIMIT = new BigInteger("65536"); // 0x1_0000 + private final static BigInteger UINT_LIMIT = new BigInteger("4294967296"); // 0x1_0000_0000 + private final static BigInteger ULONG_LIMIT = new BigInteger("18446744073709551616"); // 0x1_0000_0000_0000_0000 + + private static BigInteger unsignedToBigInteger_h(BigInteger i, BigInteger LIMIT) { + if (i.signum() == -1) { + i = i.add(LIMIT); } + return i; + } + + public static BigInteger unsignedToBigInteger(byte b){ + return unsignedToBigInteger_h(BigInteger.valueOf(b), BYTE_LIMIT); + } + + public static BigInteger unsignedToBigInteger(short s){ + return unsignedToBigInteger_h(BigInteger.valueOf(s), USHORT_LIMIT); + } + + public static BigInteger unsignedToBigInteger(int i){ + return unsignedToBigInteger_h(BigInteger.valueOf(i), UINT_LIMIT); + } + + public static BigInteger unsignedToBigInteger(long l){ + return unsignedToBigInteger_h(BigInteger.valueOf(l), ULONG_LIMIT); } public static byte divideUnsignedByte(byte a, byte b) { diff --git a/Test/dafny0/TypeConversionsCompile.dfy.java.expect b/Test/dafny0/TypeConversionsCompile.dfy.java.expect deleted file mode 100644 index 7b30c73f066..00000000000 --- a/Test/dafny0/TypeConversionsCompile.dfy.java.expect +++ /dev/null @@ -1,38 +0,0 @@ -3 4 5.0 5 6 -1.0 147573952589676412927 4294967295 127 0 -got 3, expected 3 -got 0, expected 0 -got 5, expected 5 -got 10, expected 10 -got 3.0, expected 3.0 -got 6.0, expected 6.0 -got 2, expected 2 -got 0, expected 0 -got 0.0, expected 0.0 -got -1.0, expected 4294967295.0 -got 127.0, expected 127.0 -got 0, expected 0 -got 0, expected 0 -got 127, expected 127 -got 127, expected 127 -got 5, expected 5 -got 5, expected 5 -got 4294967295, expected 4294967295 -got 5, expected 5 -got 0, expected 0 -got 5, expected 5 -got 5, expected 5 -got 5, expected 5 -got 5, expected 5 -got 0, expected 0 -got 0, expected 0 -got 127, expected 127 -got 127, expected 127 -got 5.0, expected 5.0 -got 14, expected 14 -120 -1 4 8589934592 6345789 -9223372036854775808 -4 4 4 4 -68 68 68 68 -Something about ORDINAL: 143 143 143 147 43 -ORDINAL and bitvectors: 20 20 -false 143 true -true 0 true diff --git a/Test/git-issues/git-issue-4152.dfy b/Test/git-issues/git-issue-4152.dfy new file mode 100644 index 00000000000..728ad2d503c --- /dev/null +++ b/Test/git-issues/git-issue-4152.dfy @@ -0,0 +1,12 @@ +// RUN: %testDafnyForEachCompiler "%s" + +method Main() { + var a: bv8 := 0xFF; + var b: bv16 := 0xFFFF; + var c: bv32 := 0xFFFF_FFFF; + var d: bv64 := 0xFFFF_FFFF_FFFF_FFFF; + var e: bv128 := 0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF; + print a as real, " ", b as real, " ", c as real, " ", d as real , " ", e as real, "\n"; + print a as nat, " ", b as nat, " ", c as nat, " ", d as nat, " ", e as nat, "\n"; + print a as ORDINAL, " ", b as ORDINAL, " ", c as ORDINAL, " ", d as ORDINAL, " ", e as ORDINAL, "\n"; +} diff --git a/Test/git-issues/git-issue-4152.dfy.expect b/Test/git-issues/git-issue-4152.dfy.expect new file mode 100644 index 00000000000..adec490cd62 --- /dev/null +++ b/Test/git-issues/git-issue-4152.dfy.expect @@ -0,0 +1,3 @@ +255.0 65535.0 4294967295.0 18446744073709551615.0 340282366920938463463374607431768211455.0 +255 65535 4294967295 18446744073709551615 340282366920938463463374607431768211455 +255 65535 4294967295 18446744073709551615 340282366920938463463374607431768211455 From 24cc057c4beb07ed698e466a61963e8af6d73e1a Mon Sep 17 00:00:00 2001 From: Rustan Leino <leino@amazon.com> Date: Sat, 5 Aug 2023 20:38:32 -0700 Subject: [PATCH 10/19] fix: Continue to compilation tests after comparing .verifier.expect (#4356) This PR fixes and changes the behavior of `%testDafnyForEachCompiler` tests. The bug that is fixed had caused 16 compiler tests in the Dafny test suite to not run. Here is a description of the new behavior, where _italicized_ parts indicate changes from before: * Verification is expected to go through with a 0 exit code. * If there is a `.verifier.expect` file, then the actual output is expected to contain a blank line followed by a line that starts with `Dafny program verifier`, and this portion of the output will be removed before comparing the output. The remaining output is compared with the contents of the `.verifier.expect` file and is expected to match. * If there is no `.verifier.expect` file, the verifier output minus the `Dafny program verifier` line (see previous bullet) is expected to be empty. * When running the test for each compiler, if the output contains a line starting with `Dafny program verifier`, then _everything up to and include that line is removed_ before comparing the output. This PR adds add test in `Test/metatests`. Fixes #4355 <small>By submitting this pull request, I confirm that my contribution is made under the terms of the [MIT license](https://github.com/dafny-lang/dafny/blob/master/LICENSE.txt).</small> --------- Co-authored-by: Robin Salkeld <salkeldr@amazon.com> --- Source/TestDafny/MultiBackendTest.cs | 47 +++++++++---------- ...stentCompilerBehavior.dfy.testdafny.expect | 10 ---- Test/metatests/TestBeyondVerifierExpect.dfy | 9 ++++ .../TestBeyondVerifierExpect.dfy.expect | 1 + ...tBeyondVerifierExpect.dfy.testdafny.expect | 37 +++++++++++++++ ...stBeyondVerifierExpect.dfy.verifier.expect | 1 + Test/metatests/TestDoesNotVerify.dfy | 8 ++++ Test/metatests/TestDoesNotVerify.dfy.expect | 1 + .../TestDoesNotVerify.dfy.testdafny.expect | 8 ++++ .../TestDoesNotVerify.dfy.verifier.expect | 1 + Test/metatests/TestMissingVerifierExpect.dfy | 9 ++++ .../TestMissingVerifierExpect.dfy.expect | 1 + ...MissingVerifierExpect.dfy.testdafny.expect | 6 +++ Test/metatests/TestWrongVerifierExpect.dfy | 9 ++++ .../TestWrongVerifierExpect.dfy.expect | 1 + ...stWrongVerifierExpect.dfy.testdafny.expect | 7 +++ ...estWrongVerifierExpect.dfy.verifier.expect | 1 + 17 files changed, 123 insertions(+), 34 deletions(-) create mode 100644 Test/metatests/TestBeyondVerifierExpect.dfy create mode 100644 Test/metatests/TestBeyondVerifierExpect.dfy.expect create mode 100644 Test/metatests/TestBeyondVerifierExpect.dfy.testdafny.expect create mode 100644 Test/metatests/TestBeyondVerifierExpect.dfy.verifier.expect create mode 100644 Test/metatests/TestDoesNotVerify.dfy create mode 100644 Test/metatests/TestDoesNotVerify.dfy.expect create mode 100644 Test/metatests/TestDoesNotVerify.dfy.testdafny.expect create mode 100644 Test/metatests/TestDoesNotVerify.dfy.verifier.expect create mode 100644 Test/metatests/TestMissingVerifierExpect.dfy create mode 100644 Test/metatests/TestMissingVerifierExpect.dfy.expect create mode 100644 Test/metatests/TestMissingVerifierExpect.dfy.testdafny.expect create mode 100644 Test/metatests/TestWrongVerifierExpect.dfy create mode 100644 Test/metatests/TestWrongVerifierExpect.dfy.expect create mode 100644 Test/metatests/TestWrongVerifierExpect.dfy.testdafny.expect create mode 100644 Test/metatests/TestWrongVerifierExpect.dfy.verifier.expect diff --git a/Source/TestDafny/MultiBackendTest.cs b/Source/TestDafny/MultiBackendTest.cs index 35907c196a5..09890fce07d 100644 --- a/Source/TestDafny/MultiBackendTest.cs +++ b/Source/TestDafny/MultiBackendTest.cs @@ -94,6 +94,22 @@ private int ForEachCompiler(ForEachCompilerOptions options) { output.WriteLine("Verifying..."); var (exitCode, outputString, error) = RunDafny(options.DafnyCliPath, dafnyArgs); + // If there is a .verifier.expect file, then we expect the output to match the .verifier.expect file contents. Otherwise, we + // expect the output to be empty. + var expectedOutput = ""; + var expectFileForVerifier = $"{options.TestFile}.verifier.expect"; + if (File.Exists(expectFileForVerifier)) { + expectedOutput = File.ReadAllText(expectFileForVerifier); + } + // Chop off the "Dafny program verifier finished with..." trailer + var trailer = new Regex("\r?\nDafny program verifier[^\r\n]*\r?\n").Match(outputString); + var actualOutput = outputString.Remove(trailer.Index, trailer.Length); + var diffMessage = AssertWithDiff.GetDiffMessage(expectedOutput, actualOutput); + if (diffMessage != null) { + output.WriteLine(diffMessage); + return 1; + } + // We expect verification to return exit code 0. if (exitCode != 0) { output.WriteLine("Verification failed. Output:"); output.WriteLine(outputString); @@ -101,26 +117,11 @@ private int ForEachCompiler(ForEachCompilerOptions options) { output.WriteLine(error); return exitCode; } - var expectFileForVerifier = $"{options.TestFile}.verifier.expect"; - if (File.Exists(expectFileForVerifier)) { - var expectedOutput = File.ReadAllText(expectFileForVerifier); - // Chop off the "Dafny program verifier finished with..." trailer - var trailer = new Regex("\r?\nDafny program verifier[^\r\n]*\r?\n").Match(outputString); - var actualOutput = outputString.Remove(trailer.Index, trailer.Length); - var diffMessage = AssertWithDiff.GetDiffMessage(expectedOutput, actualOutput); - if (diffMessage == null) { - return 0; - } - - output.WriteLine(diffMessage); - return 1; - } // Then execute the program for each available compiler. string expectFile = options.TestFile + ".expect"; - var commonExpectedOutput = "\nDafny program verifier did not attempt verification\n" + - File.ReadAllText(expectFile); + var commonExpectedOutput = File.ReadAllText(expectFile); var success = true; foreach (var plugin in dafnyOptions.Plugins) { @@ -132,12 +133,11 @@ private int ForEachCompiler(ForEachCompilerOptions options) { } // Check for backend-specific exceptions (because of known bugs or inconsistencies) - var expectedOutput = commonExpectedOutput; + expectedOutput = commonExpectedOutput; string? checkFile = null; var expectFileForBackend = $"{options.TestFile}.{compiler.TargetId}.expect"; if (File.Exists(expectFileForBackend)) { - expectedOutput = "\nDafny program verifier did not attempt verification\n" + - File.ReadAllText(expectFileForBackend); + expectedOutput = File.ReadAllText(expectFileForBackend); } var checkFileForBackend = $"{options.TestFile}.{compiler.TargetId}.check"; if (File.Exists(checkFileForBackend)) { @@ -185,6 +185,10 @@ private int RunWithCompiler(ForEachCompilerOptions options, IExecutableBackend b }.Concat(options.OtherArgs); var (exitCode, outputString, error) = RunDafny(options.DafnyCliPath, dafnyArgs); + var compilationOutputPrior = new Regex("\r?\nDafny program verifier[^\r\n]*\r?\n").Match(outputString); + if (compilationOutputPrior.Success) { + outputString = outputString.Remove(0, compilationOutputPrior.Index + compilationOutputPrior.Length); + } if (exitCode == 0) { var diffMessage = AssertWithDiff.GetDiffMessage(expectedOutput, outputString); @@ -273,11 +277,6 @@ private static bool IsAllowedOutputLine(IExecutableBackend backend, string line) return true; } - // This is the first non-blank line we expect when we pass /noVerify - if (line == "Dafny program verifier did not attempt verification") { - return true; - } - // This is output if the compiler emits any errors if (line.StartsWith("Wrote textual form of partial target program to")) { return true; diff --git a/Test/metatests/InconsistentCompilerBehavior.dfy.testdafny.expect b/Test/metatests/InconsistentCompilerBehavior.dfy.testdafny.expect index d747e3f2822..63d05550a1b 100644 --- a/Test/metatests/InconsistentCompilerBehavior.dfy.testdafny.expect +++ b/Test/metatests/InconsistentCompilerBehavior.dfy.testdafny.expect @@ -2,8 +2,6 @@ Verifying... Executing on C#... AssertEqualWithDiff() Failure Diff (changing expected into actual): - - Dafny program verifier did not attempt verification -Different than any output +0 @@ -11,8 +9,6 @@ Diff (changing expected into actual): Executing on JavaScript... AssertEqualWithDiff() Failure Diff (changing expected into actual): - - Dafny program verifier did not attempt verification -Different than any output +0 @@ -20,8 +16,6 @@ Diff (changing expected into actual): Executing on Go... AssertEqualWithDiff() Failure Diff (changing expected into actual): - - Dafny program verifier did not attempt verification -Different than any output +0 @@ -29,8 +23,6 @@ Diff (changing expected into actual): Executing on Java... AssertEqualWithDiff() Failure Diff (changing expected into actual): - - Dafny program verifier did not attempt verification -Different than any output +0 @@ -38,8 +30,6 @@ Diff (changing expected into actual): Executing on Python... AssertEqualWithDiff() Failure Diff (changing expected into actual): - - Dafny program verifier did not attempt verification -Different than any output +0 diff --git a/Test/metatests/TestBeyondVerifierExpect.dfy b/Test/metatests/TestBeyondVerifierExpect.dfy new file mode 100644 index 00000000000..dadd3116247 --- /dev/null +++ b/Test/metatests/TestBeyondVerifierExpect.dfy @@ -0,0 +1,9 @@ +// RUN: ! %testDafnyForEachCompiler "%s" > "%t" +// RUN: %diff "%s.testdafny.expect" "%t" + +method Main() { + ghost var n := 15; + if j :| 0 <= j < n { // this gives a no-trigger warning + } + print "hello\n"; +} diff --git a/Test/metatests/TestBeyondVerifierExpect.dfy.expect b/Test/metatests/TestBeyondVerifierExpect.dfy.expect new file mode 100644 index 00000000000..024d23dc14f --- /dev/null +++ b/Test/metatests/TestBeyondVerifierExpect.dfy.expect @@ -0,0 +1 @@ +good bye diff --git a/Test/metatests/TestBeyondVerifierExpect.dfy.testdafny.expect b/Test/metatests/TestBeyondVerifierExpect.dfy.testdafny.expect new file mode 100644 index 00000000000..1152e6c710e --- /dev/null +++ b/Test/metatests/TestBeyondVerifierExpect.dfy.testdafny.expect @@ -0,0 +1,37 @@ +Verifying... +Executing on C#... +AssertEqualWithDiff() Failure +Diff (changing expected into actual): +-good bye ++hello + + +Executing on JavaScript... +AssertEqualWithDiff() Failure +Diff (changing expected into actual): +-good bye ++hello + + +Executing on Go... +AssertEqualWithDiff() Failure +Diff (changing expected into actual): +-good bye ++hello + + +Executing on Java... +AssertEqualWithDiff() Failure +Diff (changing expected into actual): +-good bye ++hello + + +Executing on Python... +AssertEqualWithDiff() Failure +Diff (changing expected into actual): +-good bye ++hello + + +Executing on C++... diff --git a/Test/metatests/TestBeyondVerifierExpect.dfy.verifier.expect b/Test/metatests/TestBeyondVerifierExpect.dfy.verifier.expect new file mode 100644 index 00000000000..dc52d4a07e1 --- /dev/null +++ b/Test/metatests/TestBeyondVerifierExpect.dfy.verifier.expect @@ -0,0 +1 @@ +TestBeyondVerifierExpect.dfy(6,5): Warning: /!\ No terms found to trigger on. diff --git a/Test/metatests/TestDoesNotVerify.dfy b/Test/metatests/TestDoesNotVerify.dfy new file mode 100644 index 00000000000..aec66dca876 --- /dev/null +++ b/Test/metatests/TestDoesNotVerify.dfy @@ -0,0 +1,8 @@ +// RUN: ! %testDafnyForEachCompiler "%s" > "%t" +// RUN: %diff "%s.testdafny.expect" "%t" + +method Main() { + ghost var n := 15; + assert n < 12; // error: the verifier complains about this + print "hello\n"; +} diff --git a/Test/metatests/TestDoesNotVerify.dfy.expect b/Test/metatests/TestDoesNotVerify.dfy.expect new file mode 100644 index 00000000000..ce013625030 --- /dev/null +++ b/Test/metatests/TestDoesNotVerify.dfy.expect @@ -0,0 +1 @@ +hello diff --git a/Test/metatests/TestDoesNotVerify.dfy.testdafny.expect b/Test/metatests/TestDoesNotVerify.dfy.testdafny.expect new file mode 100644 index 00000000000..28812ebda2c --- /dev/null +++ b/Test/metatests/TestDoesNotVerify.dfy.testdafny.expect @@ -0,0 +1,8 @@ +Verifying... +Verification failed. Output: +TestDoesNotVerify.dfy(6,11): Error: assertion might not hold + +Dafny program verifier finished with 0 verified, 1 error + +Error: + diff --git a/Test/metatests/TestDoesNotVerify.dfy.verifier.expect b/Test/metatests/TestDoesNotVerify.dfy.verifier.expect new file mode 100644 index 00000000000..61b04415c49 --- /dev/null +++ b/Test/metatests/TestDoesNotVerify.dfy.verifier.expect @@ -0,0 +1 @@ +TestDoesNotVerify.dfy(6,11): Error: assertion might not hold diff --git a/Test/metatests/TestMissingVerifierExpect.dfy b/Test/metatests/TestMissingVerifierExpect.dfy new file mode 100644 index 00000000000..dadd3116247 --- /dev/null +++ b/Test/metatests/TestMissingVerifierExpect.dfy @@ -0,0 +1,9 @@ +// RUN: ! %testDafnyForEachCompiler "%s" > "%t" +// RUN: %diff "%s.testdafny.expect" "%t" + +method Main() { + ghost var n := 15; + if j :| 0 <= j < n { // this gives a no-trigger warning + } + print "hello\n"; +} diff --git a/Test/metatests/TestMissingVerifierExpect.dfy.expect b/Test/metatests/TestMissingVerifierExpect.dfy.expect new file mode 100644 index 00000000000..ce013625030 --- /dev/null +++ b/Test/metatests/TestMissingVerifierExpect.dfy.expect @@ -0,0 +1 @@ +hello diff --git a/Test/metatests/TestMissingVerifierExpect.dfy.testdafny.expect b/Test/metatests/TestMissingVerifierExpect.dfy.testdafny.expect new file mode 100644 index 00000000000..60892ad9dff --- /dev/null +++ b/Test/metatests/TestMissingVerifierExpect.dfy.testdafny.expect @@ -0,0 +1,6 @@ +Verifying... +AssertEqualWithDiff() Failure +Diff (changing expected into actual): ++TestMissingVerifierExpect.dfy(6,5): Warning: /!\ No terms found to trigger on. ++ + diff --git a/Test/metatests/TestWrongVerifierExpect.dfy b/Test/metatests/TestWrongVerifierExpect.dfy new file mode 100644 index 00000000000..dadd3116247 --- /dev/null +++ b/Test/metatests/TestWrongVerifierExpect.dfy @@ -0,0 +1,9 @@ +// RUN: ! %testDafnyForEachCompiler "%s" > "%t" +// RUN: %diff "%s.testdafny.expect" "%t" + +method Main() { + ghost var n := 15; + if j :| 0 <= j < n { // this gives a no-trigger warning + } + print "hello\n"; +} diff --git a/Test/metatests/TestWrongVerifierExpect.dfy.expect b/Test/metatests/TestWrongVerifierExpect.dfy.expect new file mode 100644 index 00000000000..ce013625030 --- /dev/null +++ b/Test/metatests/TestWrongVerifierExpect.dfy.expect @@ -0,0 +1 @@ +hello diff --git a/Test/metatests/TestWrongVerifierExpect.dfy.testdafny.expect b/Test/metatests/TestWrongVerifierExpect.dfy.testdafny.expect new file mode 100644 index 00000000000..e2e28307304 --- /dev/null +++ b/Test/metatests/TestWrongVerifierExpect.dfy.testdafny.expect @@ -0,0 +1,7 @@ +Verifying... +AssertEqualWithDiff() Failure +Diff (changing expected into actual): +-warning: out of bananas ++TestWrongVerifierExpect.dfy(6,5): Warning: /!\ No terms found to trigger on. + + diff --git a/Test/metatests/TestWrongVerifierExpect.dfy.verifier.expect b/Test/metatests/TestWrongVerifierExpect.dfy.verifier.expect new file mode 100644 index 00000000000..c13ffbd13ac --- /dev/null +++ b/Test/metatests/TestWrongVerifierExpect.dfy.verifier.expect @@ -0,0 +1 @@ +warning: out of bananas From c31932b4b4f77a38e5da9c9f6a7689d8f57346bf Mon Sep 17 00:00:00 2001 From: Alex Chew <alex-chew@users.noreply.github.com> Date: Mon, 7 Aug 2023 01:34:35 -0700 Subject: [PATCH 11/19] feat: LSP rename support (#4365) --- .../CodeActions/CodeActionsTest.cs | 33 +--- .../Lookup/GoToDefinitionTest.cs | 14 +- .../Refactoring/RenameTest.cs | 185 ++++++++++++++++++ .../Util/DocumentEdits.cs | 44 +++++ .../Handlers/DafnyReferencesHandler.cs | 12 +- .../Handlers/DafnyRenameHandler.cs | 71 +++++++ .../Handlers/LanguageServerExtensions.cs | 1 + .../Workspace/ProjectManagerDatabase.cs | 1 + .../Workspace/SymbolTable.cs | 44 +++-- docs/dev/news/4365.feat | 2 + 10 files changed, 349 insertions(+), 58 deletions(-) create mode 100644 Source/DafnyLanguageServer.Test/Refactoring/RenameTest.cs create mode 100644 Source/DafnyLanguageServer.Test/Util/DocumentEdits.cs create mode 100644 Source/DafnyLanguageServer/Handlers/DafnyRenameHandler.cs create mode 100644 docs/dev/news/4365.feat diff --git a/Source/DafnyLanguageServer.Test/CodeActions/CodeActionsTest.cs b/Source/DafnyLanguageServer.Test/CodeActions/CodeActionsTest.cs index 7ab39dcdc69..efe8475bcc5 100644 --- a/Source/DafnyLanguageServer.Test/CodeActions/CodeActionsTest.cs +++ b/Source/DafnyLanguageServer.Test/CodeActions/CodeActionsTest.cs @@ -310,8 +310,9 @@ private async Task TestCodeAction(string source) { codeAction = await RequestResolveCodeAction(codeAction); var textDocumentEdit = codeAction.Edit?.DocumentChanges?.Single().TextDocumentEdit; Assert.NotNull(textDocumentEdit); - var modifiedOutput = string.Join("\n", ApplyEdits(textDocumentEdit, output)).Replace("\r\n", "\n"); - var expectedOutput = string.Join("\n", ApplySingleEdit(ToLines(output), expectedRange, expectedNewText)).Replace("\r\n", "\n"); + var modifiedOutput = DocumentEdits.ApplyEdits(textDocumentEdit, output); + var expectedOutput = + DocumentEdits.ApplyEdit(DocumentEdits.ToLines(output), expectedRange, expectedNewText); Assert.Equal(expectedOutput, modifiedOutput); } } @@ -324,33 +325,5 @@ private async Task TestCodeAction(string source) { public CodeActionTest(ITestOutputHelper output) : base(output) { } - - private static List<string> ApplyEdits(TextDocumentEdit textDocumentEdit, string output) { - var inversedEdits = textDocumentEdit.Edits.ToList() - .OrderByDescending(x => x.Range.Start.Line) - .ThenByDescending(x => x.Range.Start.Character); - var modifiedOutput = ToLines(output); - foreach (var textEdit in inversedEdits) { - modifiedOutput = ApplySingleEdit(modifiedOutput, textEdit.Range, textEdit.NewText); - } - - return modifiedOutput; - } - - private static List<string> ToLines(string output) { - return output.ReplaceLineEndings("\n").Split("\n").ToList(); - } - - private static List<string> ApplySingleEdit(List<string> modifiedOutput, Range range, string newText) { - var lineStart = modifiedOutput[range.Start.Line]; - var lineEnd = modifiedOutput[range.End.Line]; - modifiedOutput[range.Start.Line] = - lineStart.Substring(0, range.Start.Character) + newText + - lineEnd.Substring(range.End.Character); - modifiedOutput = modifiedOutput.Take(range.Start.Line).Concat( - modifiedOutput.Skip(range.End.Line) - ).ToList(); - return modifiedOutput; - } } } diff --git a/Source/DafnyLanguageServer.Test/Lookup/GoToDefinitionTest.cs b/Source/DafnyLanguageServer.Test/Lookup/GoToDefinitionTest.cs index 3de9389870f..2d82c173fe1 100644 --- a/Source/DafnyLanguageServer.Test/Lookup/GoToDefinitionTest.cs +++ b/Source/DafnyLanguageServer.Test/Lookup/GoToDefinitionTest.cs @@ -1,9 +1,6 @@ using Microsoft.Dafny.LanguageServer.IntegrationTest.Extensions; using OmniSharp.Extensions.LanguageServer.Protocol; -using OmniSharp.Extensions.LanguageServer.Protocol.Document; using OmniSharp.Extensions.LanguageServer.Protocol.Models; -using OmniSharp.Extensions.LanguageServer.Protocol.Progress; -using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; @@ -78,6 +75,11 @@ requires Err? await AssertPositionsLineUpWithRanges(source); } + /// <summary> + /// Given <paramref name="source"/> with N positions, for each K from 0 to N exclusive, + /// assert that a RequestDefinition at position K + /// returns either the Kth range, or the range with key K (as a string). + /// </summary> private async Task AssertPositionsLineUpWithRanges(string source) { MarkupTestFile.GetPositionsAndNamedRanges(source, out var cleanSource, out var positions, out var ranges); @@ -126,10 +128,10 @@ public async Task FunctionCallAndGotoOnDeclaration() { await client.OpenDocumentAndWaitAsync(documentItem, CancellationToken); var fibonacciSpecOnItself = (await RequestDefinition(documentItem, positions[0])); - Assert.False(fibonacciSpecOnItself.Any()); + Assert.Single(fibonacciSpecOnItself); var nOnItself = (await RequestDefinition(documentItem, positions[1])); - Assert.False(nOnItself.Any()); + Assert.Single(nOnItself); var fibonacciCall = (await RequestDefinition(documentItem, positions[2])).Single(); Assert.Equal(ranges[0], fibonacciCall.Location!.Range); @@ -209,7 +211,7 @@ method DoIt() { Assert.Equal(ranges[1], usizeReference.Location.Range); var lengthDefinition = (await RequestDefinition(documentItem, positions[1])); - Assert.False(lengthDefinition.Any()); + Assert.Single(lengthDefinition); var providerImport = (await RequestDefinition(documentItem, positions[0])).Single(); Assert.Equal(ranges[0], providerImport.Location!.Range); diff --git a/Source/DafnyLanguageServer.Test/Refactoring/RenameTest.cs b/Source/DafnyLanguageServer.Test/Refactoring/RenameTest.cs new file mode 100644 index 00000000000..2d6d978298c --- /dev/null +++ b/Source/DafnyLanguageServer.Test/Refactoring/RenameTest.cs @@ -0,0 +1,185 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using JetBrains.Annotations; +using Microsoft.Dafny.LanguageServer.IntegrationTest.Util; +using OmniSharp.Extensions.LanguageServer.Protocol.Document; +using OmniSharp.Extensions.LanguageServer.Protocol.Models; +using Xunit; +using Xunit.Abstractions; +using Range = OmniSharp.Extensions.LanguageServer.Protocol.Models.Range; + +namespace Microsoft.Dafny.LanguageServer.IntegrationTest.Refactoring { + public class RenameTest : ClientBasedLanguageServerTest { + [Fact] + public async Task ImplicitProjectFails() { + var source = @" +const i := 0 +".TrimStart(); + + var documentItem = await CreateAndOpenTestDocument(source); + await Assert.ThrowsAnyAsync<Exception>(() => RequestRename(documentItem, new Position(0, 6), "j")); + } + + [Fact] + public async Task InvalidNewNameIsNoOp() { + var documentItem = await CreateAndOpenTestDocument(""); + var workspaceEdit = await RequestRename(documentItem, new Position(0, 0), ""); + Assert.Null(workspaceEdit); + } + + [Fact] + public async Task RenameNonSymbolFails() { + var tempDir = await SetUpProjectFile(); + var documentItem = await CreateAndOpenTestDocument("module Foo {}", Path.Combine(tempDir, "tmp.dfy")); + var workspaceEdit = await RequestRename(documentItem, new Position(0, 6), "space"); + Assert.Null(workspaceEdit); + } + + [Fact] + public async Task RenameDeclarationRenamesUsages() { + var source = @" +const [>><i<] := 0 +method M() { + print [>i<] + [>i<]; +} +".TrimStart(); + + var tempDir = await SetUpProjectFile(); + await AssertRangesRenamed(source, tempDir, "foobar"); + } + + [Fact] + public async Task RenameUsageRenamesDeclaration() { + var source = @" +method [>foobar<]() +method U() { [>><foobar<](); } +".TrimStart(); + + var tempDir = await SetUpProjectFile(); + await AssertRangesRenamed(source, tempDir, "M"); + } + + [Fact] + public async Task RenameUsageRenamesOtherUsages() { + var source = @" +module [>A<] {} +module B { import [>A<] } +module C { import [>><A<] } +module D { import [>A<] } +".TrimStart(); + + var tempDir = await SetUpProjectFile(); + await AssertRangesRenamed(source, tempDir, "AAA"); + } + + [Fact] + public async Task RenameDeclarationAcrossFiles() { + var sourceA = @" +module A { + class [>><C<] {} +} +".TrimStart(); + var sourceB = @" +module B { + import A + method M(c: A.[>C<]) {} +} +".TrimStart(); + + var tempDir = await SetUpProjectFile(); + await AssertRangesRenamed(new[] { sourceA, sourceB }, tempDir, "CCC"); + } + + [Fact] + public async Task RenameUsageAcrossFiles() { + var sourceA = @" +abstract module [>A<] {} +".TrimStart(); + var sourceB = @" +abstract module B { import [>><A<] } +".TrimStart(); + + var tempDir = await SetUpProjectFile(); + await AssertRangesRenamed(new[] { sourceA, sourceB }, tempDir, "AAA"); + } + + /// <summary> + /// Create an empty project file in a new temporary directory, and return the temporary directory's path. + /// </summary> + protected async Task<string> SetUpProjectFile() { + var tempDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + Directory.CreateDirectory(tempDir); + var projectFilePath = Path.Combine(tempDir, DafnyProject.FileName); + await File.WriteAllTextAsync(projectFilePath, ""); + return tempDir; + } + + protected override Task SetUp(Action<DafnyOptions> modifyOptions) { + return base.SetUp(o => { + o.Set(ServerCommand.ProjectMode, true); + modifyOptions?.Invoke(o); + }); + } + + /// <summary> + /// Assert that after requesting a rename to <paramref name="newName"/> + /// at the markup position in <paramref name="source"/> + /// (there must be exactly one markup position), + /// all markup ranges are renamed. + /// </summary> + private async Task AssertRangesRenamed(string source, string tempDir, string newName) { + await AssertRangesRenamed(new[] { source }, tempDir, newName); + } + + private record DocPosRange(TextDocumentItem Document, [CanBeNull] Position Position, ImmutableArray<Range> Ranges); + + /// <summary> + /// Assert that after requesting a rename to <paramref name="newName"/> + /// at the markup position in <paramref name="sources"/> + /// (there must be exactly one markup position among all sources), + /// all markup ranges are renamed. + /// </summary> + private async Task AssertRangesRenamed(IEnumerable<string> sources, string tempDir, string newName) { + var items = sources.Select(async (source, sourceIndex) => { + MarkupTestFile.GetPositionsAndRanges(source, out var cleanSource, + out var positions, out var ranges); + var documentItem = await CreateAndOpenTestDocument(cleanSource, Path.Combine(tempDir, $"tmp{sourceIndex}.dfy")); + Assert.InRange(positions.Count, 0, 1); + return new DocPosRange(documentItem, positions.FirstOrDefault((Position)null), ranges); + }).Select(task => task.Result).ToImmutableList(); + + var itemWithPos = items.Single(item => item.Position != null); + var workspaceEdit = await RequestRename(itemWithPos.Document, itemWithPos.Position, newName); + Assert.NotNull(workspaceEdit.Changes); + + foreach (var (document, _, ranges) in items) { + Assert.Contains(document.Uri, workspaceEdit.Changes); + var editedText = DocumentEdits.ApplyEdits(workspaceEdit.Changes[document.Uri], document.Text); + var expectedChanges = ranges.Select(range => new TextEdit { + Range = range, + NewText = newName, + }); + var expectedText = DocumentEdits.ApplyEdits(expectedChanges, document.Text); + Assert.Equal(expectedText, editedText); + } + } + + private async Task<WorkspaceEdit> RequestRename( + TextDocumentItem documentItem, Position position, string newName) { + await AssertNoResolutionErrors(documentItem); + return await client.RequestRename( + new RenameParams { + TextDocument = documentItem.Uri, + Position = position, + NewName = newName, + }, CancellationToken); + } + + public RenameTest(ITestOutputHelper output) : base(output) { + } + } +} diff --git a/Source/DafnyLanguageServer.Test/Util/DocumentEdits.cs b/Source/DafnyLanguageServer.Test/Util/DocumentEdits.cs new file mode 100644 index 00000000000..3b6448985ff --- /dev/null +++ b/Source/DafnyLanguageServer.Test/Util/DocumentEdits.cs @@ -0,0 +1,44 @@ +using System.Collections.Generic; +using System.Linq; +using OmniSharp.Extensions.LanguageServer.Protocol.Models; + +namespace Microsoft.Dafny.LanguageServer.IntegrationTest.Util; + +public class DocumentEdits { + public static string ApplyEdits(TextDocumentEdit textDocumentEdit, string text) { + return ApplyEdits(textDocumentEdit.Edits, text); + } + + public static string ApplyEdits(IEnumerable<TextEdit> edits, string text) { + var inversedEdits = edits.ToList() + .OrderByDescending(x => x.Range.Start.Line) + .ThenByDescending(x => x.Range.Start.Character); + var modifiedText = ToLines(text); + foreach (var textEdit in inversedEdits) { + modifiedText = ApplyEditLinewise(modifiedText, textEdit.Range, textEdit.NewText); + } + + return string.Join("\n", modifiedText); + } + + + public static List<string> ToLines(string text) { + return text.ReplaceLineEndings("\n").Split("\n").ToList(); + } + + public static string FromLines(List<string> lines) { + return string.Join("\n", lines).ReplaceLineEndings("\n"); + } + + public static string ApplyEdit(List<string> lines, Range range, string newText) { + return FromLines(ApplyEditLinewise(lines, range, newText)); + } + + public static List<string> ApplyEditLinewise(List<string> lines, Range range, string newText) { + var lineStart = lines[range.Start.Line]; + var lineEnd = lines[range.End.Line]; + lines[range.Start.Line] = lineStart[..range.Start.Character] + newText + lineEnd[range.End.Character..]; + lines = lines.Take(range.Start.Line).Concat(lines.Skip(range.End.Line)).ToList(); + return lines; + } +} diff --git a/Source/DafnyLanguageServer/Handlers/DafnyReferencesHandler.cs b/Source/DafnyLanguageServer/Handlers/DafnyReferencesHandler.cs index a7d41ef5286..e1043ca2cca 100644 --- a/Source/DafnyLanguageServer/Handlers/DafnyReferencesHandler.cs +++ b/Source/DafnyLanguageServer/Handlers/DafnyReferencesHandler.cs @@ -1,4 +1,3 @@ -using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.Dafny.LanguageServer.Workspace; @@ -36,14 +35,9 @@ public override async Task<LocationContainer> Handle(ReferenceParams request, Ca var requestUri = request.TextDocument.Uri.ToUri(); var declaration = state.SymbolTable.GetDeclaration(requestUri, request.Position); - - // The declaration graph is not reflexive, so the position might be on a declaration; return references to it - if (declaration == null) { - return state.SymbolTable.GetUsages(requestUri, request.Position).ToArray(); - } - - // If the position is not on a declaration, return references to its declaration - return state.SymbolTable.GetUsages(declaration.Uri.ToUri(), declaration.Range.Start).ToArray(); + return declaration == null + ? new LocationContainer() + : LocationContainer.From(state.SymbolTable.GetUsages(declaration.Uri.ToUri(), declaration.Range.Start)); } } } diff --git a/Source/DafnyLanguageServer/Handlers/DafnyRenameHandler.cs b/Source/DafnyLanguageServer/Handlers/DafnyRenameHandler.cs new file mode 100644 index 00000000000..3e637e45bfd --- /dev/null +++ b/Source/DafnyLanguageServer/Handlers/DafnyRenameHandler.cs @@ -0,0 +1,71 @@ +using System; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Dafny.LanguageServer.Workspace; +using Microsoft.Extensions.Logging; +using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities; +using OmniSharp.Extensions.LanguageServer.Protocol.Document; +using OmniSharp.Extensions.LanguageServer.Protocol.Models; + +namespace Microsoft.Dafny.LanguageServer.Handlers { + /// <summary> + /// LSP handler responsible for project-wide symbol renames. + /// </summary> + public class DafnyRenameHandler : RenameHandlerBase { + private readonly ILogger logger; + private readonly IProjectDatabase projects; + + public DafnyRenameHandler(ILogger<DafnyRenameHandler> logger, IProjectDatabase projects) { + this.logger = logger; + this.projects = projects; + } + + protected override RenameRegistrationOptions CreateRegistrationOptions( + RenameCapability capability, ClientCapabilities clientCapabilities) { + return new RenameRegistrationOptions { + DocumentSelector = DocumentSelector.ForLanguage("dafny") + }; + } + + public override async Task<WorkspaceEdit?> Handle(RenameParams request, CancellationToken cancellationToken) { + if (string.IsNullOrWhiteSpace(request.NewName)) { + // TODO: check identifiers more precisely + return null; + } + + var requestUri = request.TextDocument.Uri.ToUri(); + // Reject rename requests in implicit projects, because we might not find all references within the codebase, + // so a partial rename may result in breaking the codebase + if ((await projects.GetProject(requestUri)).IsImplicitProject) { + throw new Exception("Renaming support requires --project-mode and a Dafny project file (dfyconfig.toml)"); + } + + var state = await projects.GetResolvedDocumentAsyncInternal(request.TextDocument); + if (state == null) { + logger.LogWarning("location requested for unloaded document {DocumentUri}", request.TextDocument.Uri); + return null; + } + + var node = state.SymbolTable.GetNode(requestUri, request.Position); + if (node == null || node.NameToken.val == request.NewName) { + return null; + } + + var declaration = SymbolTable.NodeToLocation(node); + var usages = state.SymbolTable.GetUsages(declaration.Uri.ToUri(), declaration.Range.Start); + var changes = usages + .Append(declaration) + .GroupBy(location => location.Uri) + .ToDictionary( + uriLocations => uriLocations.Key, + uriLocations => uriLocations.Select(location => new TextEdit { + Range = location.Range, + NewText = request.NewName, + })); + return new WorkspaceEdit { + Changes = changes + }; + } + } +} diff --git a/Source/DafnyLanguageServer/Handlers/LanguageServerExtensions.cs b/Source/DafnyLanguageServer/Handlers/LanguageServerExtensions.cs index a371706aa05..bbb742d8353 100644 --- a/Source/DafnyLanguageServer/Handlers/LanguageServerExtensions.cs +++ b/Source/DafnyLanguageServer/Handlers/LanguageServerExtensions.cs @@ -19,6 +19,7 @@ public static LanguageServerOptions WithDafnyHandlers(this LanguageServerOptions .WithHandler<DafnyHoverHandler>() .WithHandler<DafnyDefinitionHandler>() .WithHandler<DafnyReferencesHandler>() + .WithHandler<DafnyRenameHandler>() .WithHandler<DafnyCompletionHandler>() .WithHandler<DafnySignatureHelpHandler>() .WithHandler<DafnyCounterExampleHandler>() diff --git a/Source/DafnyLanguageServer/Workspace/ProjectManagerDatabase.cs b/Source/DafnyLanguageServer/Workspace/ProjectManagerDatabase.cs index 9c880311073..980e61fc1b1 100644 --- a/Source/DafnyLanguageServer/Workspace/ProjectManagerDatabase.cs +++ b/Source/DafnyLanguageServer/Workspace/ProjectManagerDatabase.cs @@ -205,6 +205,7 @@ public static DafnyProject ImplicitProject(Uri uri) { } if (projectFile != null && projectFile.Uri != sourceUri && !serverOptions.Get(ServerCommand.ProjectMode)) { + logger.LogWarning("Project file at {} will be ignored because project mode is disabled", projectFile.Uri); projectFile.Uri = sourceUri; projectFile.IsImplicitProject = true; projectFile.Includes = new[] { sourceUri.LocalPath }; diff --git a/Source/DafnyLanguageServer/Workspace/SymbolTable.cs b/Source/DafnyLanguageServer/Workspace/SymbolTable.cs index 33fc554f0ff..1166fd00ef5 100644 --- a/Source/DafnyLanguageServer/Workspace/SymbolTable.cs +++ b/Source/DafnyLanguageServer/Workspace/SymbolTable.cs @@ -23,10 +23,13 @@ private SymbolTable() { } public SymbolTable(IReadOnlyList<(IDeclarationOrUsage usage, IDeclarationOrUsage declaration)> usages) { - var safeUsages1 = usages.Where(k => k.usage.NameToken.Uri != null).ToList(); - var safeUsages = usages.Where(k => k.usage.NameToken.Uri != null && k.declaration.NameToken.Uri != null).ToList(); - UsageToDeclaration = safeUsages1.DistinctBy(k => k.usage). - ToImmutableDictionary(k => k.usage, k => k.declaration); + var safeUsages1 = usages.Where(k => k.usage.NameToken.Uri != null).ToImmutableList(); + var safeUsages = usages.Where(k => k.usage.NameToken.Uri != null && k.declaration.NameToken.Uri != null).ToImmutableList(); + + var usageDeclarations = safeUsages1.Select(k => KeyValuePair.Create(k.usage, k.declaration)); + var selfDeclarations = safeUsages1.Select(k => KeyValuePair.Create(k.declaration, k.declaration)); + UsageToDeclaration = usageDeclarations.Concat(selfDeclarations).DistinctBy(pair => pair.Key).ToImmutableDictionary(); + DeclarationToUsages = safeUsages1.GroupBy(u => u.declaration).ToImmutableDictionary( g => g.Key, g => (ISet<IDeclarationOrUsage>)g.Select(k => k.usage).ToHashSet()); @@ -46,7 +49,15 @@ public SymbolTable(IReadOnlyList<(IDeclarationOrUsage usage, IDeclarationOrUsage } private readonly Dictionary<Uri, IIntervalTree<Position, IDeclarationOrUsage>> nodePositions = new(); + + /// <summary> + /// Maps each symbol declaration to itself, and each symbol usage to the symbol's declaration. + /// </summary> public ImmutableDictionary<IDeclarationOrUsage, IDeclarationOrUsage> UsageToDeclaration { get; } + + /// <summary> + /// Maps each symbol declaration to usages of the symbol, not including the declaration itself. + /// </summary> private ImmutableDictionary<IDeclarationOrUsage, ISet<IDeclarationOrUsage>> DeclarationToUsages { get; } public ISet<Location> GetUsages(Uri uri, Position position) { @@ -59,16 +70,23 @@ public ISet<Location> GetUsages(Uri uri, Position position) { } public Location? GetDeclaration(Uri uri, Position position) { + var node = GetNode(uri, position); + return node == null ? null : NodeToLocation(node); + } + + internal static Location NodeToLocation(IDeclarationOrUsage node) { + return new Location { + Uri = DocumentUri.From(node.NameToken.Uri), + Range = node.NameToken.GetLspRange() + }; + } + + public IDeclarationOrUsage? GetNode(Uri uri, Position position) { if (!nodePositions.TryGetValue(uri, out var forFile)) { return null; } - - var referenceNodes = forFile.Query(position); - return referenceNodes.Select(node => UsageToDeclaration.GetOrDefault(node, () => (IDeclarationOrUsage?)null)) - .Where(x => x != null).Select( - n => new Location { - Uri = DocumentUri.From(n!.NameToken.Uri), - Range = n.NameToken.GetLspRange() - }).FirstOrDefault(); + return forFile.Query(position) + .Select(node => UsageToDeclaration.GetOrDefault(node, () => (IDeclarationOrUsage?)null)) + .FirstOrDefault(x => x != null); } -} \ No newline at end of file +} diff --git a/docs/dev/news/4365.feat b/docs/dev/news/4365.feat new file mode 100644 index 00000000000..2fbb47a518e --- /dev/null +++ b/docs/dev/news/4365.feat @@ -0,0 +1,2 @@ +Add support for Rename LSP request +- Support requires enabling project mode and defining a Dafny project file From ff64cbf836c0920bade49f5aa4fb9811ec378f26 Mon Sep 17 00:00:00 2001 From: Remy Willems <rwillems@amazon.com> Date: Mon, 7 Aug 2023 18:03:04 +0200 Subject: [PATCH 12/19] Stop sharing verification trees between compilations (#4388) Hopefully fixes non-deterministic failures in verification tree based tests. What we're seeing is that events triggered by update X also end up affecting notifications belonging to update X+1, so this change is a good candidate for fixing those issues. <small>By submitting this pull request, I confirm that my contribution is made under the terms of the [MIT license](https://github.com/dafny-lang/dafny/blob/master/LICENSE.txt).</small> --- .../Workspace/Documents/CompilationAfterParsing.cs | 2 +- .../Workspace/Documents/CompilationAfterTranslation.cs | 2 +- .../DafnyLanguageServer/Workspace/NotificationPublisher.cs | 2 +- .../Notifications/VerificationDiagnosticsParams.cs | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Source/DafnyLanguageServer/Workspace/Documents/CompilationAfterParsing.cs b/Source/DafnyLanguageServer/Workspace/Documents/CompilationAfterParsing.cs index 41ef2a0aee0..53eb8367ca3 100644 --- a/Source/DafnyLanguageServer/Workspace/Documents/CompilationAfterParsing.cs +++ b/Source/DafnyLanguageServer/Workspace/Documents/CompilationAfterParsing.cs @@ -33,7 +33,7 @@ public override IdeState ToIdeState(IdeState previousState) { ResolutionDiagnostics = ResolutionDiagnostics.ToDictionary( kv => kv.Key, kv => (IReadOnlyList<Diagnostic>)kv.Value.Select(d => d.ToLspDiagnostic()).ToList()), - VerificationTree = baseResult.VerificationTree ?? GetVerificationTree() + VerificationTree = baseResult.VerificationTree ?? GetVerificationTree()?.GetCopyForNotification() }; } diff --git a/Source/DafnyLanguageServer/Workspace/Documents/CompilationAfterTranslation.cs b/Source/DafnyLanguageServer/Workspace/Documents/CompilationAfterTranslation.cs index d465fb2af2f..e2b100d5222 100644 --- a/Source/DafnyLanguageServer/Workspace/Documents/CompilationAfterTranslation.cs +++ b/Source/DafnyLanguageServer/Workspace/Documents/CompilationAfterTranslation.cs @@ -52,7 +52,7 @@ public override IdeState ToIdeState(IdeState previousState) { }); return base.ToIdeState(previousState) with { ImplementationsWereUpdated = true, - VerificationTree = GetVerificationTree(), + VerificationTree = GetVerificationTree()?.GetCopyForNotification(), Counterexamples = new List<Counterexample>(Counterexamples), ImplementationIdToView = new Dictionary<ImplementationId, IdeImplementationView>(implementationViewsWithMigratedDiagnostics) }; diff --git a/Source/DafnyLanguageServer/Workspace/NotificationPublisher.cs b/Source/DafnyLanguageServer/Workspace/NotificationPublisher.cs index 0dba4f085f0..d7820c777db 100644 --- a/Source/DafnyLanguageServer/Workspace/NotificationPublisher.cs +++ b/Source/DafnyLanguageServer/Workspace/NotificationPublisher.cs @@ -157,7 +157,7 @@ public void PublishGutterIcons(IdeState state, bool verificationStarted) { var verificationStatusGutter = VerificationStatusGutter.ComputeFrom( root, filesystem.GetVersion(root)!.Value, - state.VerificationTree.Children.Select(child => child.GetCopyForNotification()).ToArray(), + state.VerificationTree.Children, errors, linesCount, verificationStarted diff --git a/Source/DafnyLanguageServer/Workspace/Notifications/VerificationDiagnosticsParams.cs b/Source/DafnyLanguageServer/Workspace/Notifications/VerificationDiagnosticsParams.cs index 9d9c97c3f6f..ff5a0ae55a7 100644 --- a/Source/DafnyLanguageServer/Workspace/Notifications/VerificationDiagnosticsParams.cs +++ b/Source/DafnyLanguageServer/Workspace/Notifications/VerificationDiagnosticsParams.cs @@ -29,7 +29,7 @@ LineVerificationStatus[] PerLineStatus public static VerificationStatusGutter ComputeFrom( DocumentUri uri, int version, - VerificationTree[] verificationTrees, + ICollection<VerificationTree> verificationTrees, Container<Diagnostic> resolutionErrors, int linesCount, bool verificationStarted) { @@ -39,13 +39,13 @@ public static VerificationStatusGutter ComputeFrom( public static LineVerificationStatus[] RenderPerLineDiagnostics( DocumentUri uri, - VerificationTree[] verificationTrees, + ICollection<VerificationTree> verificationTrees, int numberOfLines, bool verificationStarted, Container<Diagnostic> parseAndResolutionErrors) { var result = new LineVerificationStatus[numberOfLines]; - if (verificationTrees.Length == 0 && !parseAndResolutionErrors.Any() && verificationStarted) { + if (verificationTrees.Count == 0 && !parseAndResolutionErrors.Any() && verificationStarted) { for (var line = 0; line < numberOfLines; line++) { result[line] = LineVerificationStatus.Verified; } From 7712b1fd980f661592311cba749678775bf87c2c Mon Sep 17 00:00:00 2001 From: Aaron Tomb <aarotomb@amazon.com> Date: Mon, 7 Aug 2023 11:14:47 -0700 Subject: [PATCH 13/19] Set options in IDE to more closely match CLI (#4374) This makes IDE and CLI resource counts more likely to match. In particular, it makes it so that the Boogie file generated when running the language server with the `--bprint` flag matches the Boogie file generated when running the CLI with the `/print` Boogie flag, except for some comments that don't seem to affect RU counts. This does not, unfortunately, always make the RU counts presented in the IDE match those given by the CLI. I'm not yet sure where the additional discrepancy is coming from. By submitting this pull request, I confirm that my contribution is made under the terms of the MIT license. --- Source/DafnyLanguageServer/Language/DafnyProgramVerifier.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/DafnyLanguageServer/Language/DafnyProgramVerifier.cs b/Source/DafnyLanguageServer/Language/DafnyProgramVerifier.cs index cf86593591f..d715669c683 100644 --- a/Source/DafnyLanguageServer/Language/DafnyProgramVerifier.cs +++ b/Source/DafnyLanguageServer/Language/DafnyProgramVerifier.cs @@ -38,7 +38,7 @@ public async Task<IReadOnlyList<IImplementationTask>> GetVerificationTasksAsync( cancellationToken.ThrowIfCancellationRequested(); var translated = await DafnyMain.LargeStackFactory.StartNew(() => Translator.Translate(program, errorReporter, new Translator.TranslatorFlags(errorReporter.Options) { - InsertChecksums = true, + InsertChecksums = 0 < engine.Options.VerifySnapshots, ReportRanges = true }).ToList(), cancellationToken); From 4b0ea54b8ba6146225c3bf7ee8bd10b7b044949d Mon Sep 17 00:00:00 2001 From: Remy Willems <rwillems@amazon.com> Date: Mon, 7 Aug 2023 22:44:33 +0200 Subject: [PATCH 14/19] Hover and gutter icon project support (#4337) Depends on https://github.com/dafny-lang/dafny/pull/4350 ### Changes - Enable complex hover messages and gutter icons when in project mode - Do not publish gutter icons if the exact same icons have been previously published. ### Testing - Update hover and gutter icon tests so they have project mode turned on <small>By submitting this pull request, I confirm that my contribution is made under the terms of the [MIT license](https://github.com/dafny-lang/dafny/blob/master/LICENSE.txt).</small> --- Source/DafnyCore/Options/DafnyProject.cs | 7 +- .../Resolver/PreType/PreTypeResolve.cs | 4 +- .../DafnyLanguageServerTestBase.cs | 2 +- ...hedLinearVerificationGutterStatusTester.cs | 2 +- .../LinearVerificationGutterStatusTester.cs | 3 +- .../Lookup/HoverVerificationTest.cs | 16 +- .../Handlers/DafnyCodeActionHandler.cs | 2 +- .../Handlers/DafnyHoverHandler.cs | 16 +- .../Handlers/DafnyRenameHandler.cs | 2 +- .../Handlers/DafnyTextDocumentHandler.cs | 6 +- .../Language/IVerificationProgressReporter.cs | 10 +- .../Workspace/CompilationManager.cs | 28 ++-- .../Workspace/Documents/Compilation.cs | 5 +- .../Documents/CompilationAfterParsing.cs | 6 +- .../Documents/CompilationAfterTranslation.cs | 18 +- .../Workspace/INotificationPublisher.cs | 6 +- .../DafnyLanguageServer/Workspace/IdeState.cs | 2 +- .../Workspace/NotificationPublisher.cs | 34 ++-- .../VerificationDiagnosticsParams.cs | 5 +- .../Workspace/ProjectManager.cs | 20 ++- .../Workspace/ProjectManagerDatabase.cs | 5 +- .../Workspace/TextDocumentLoader.cs | 5 +- .../Workspace/VerificationProgressReporter.cs | 156 +++++++++--------- 23 files changed, 193 insertions(+), 167 deletions(-) diff --git a/Source/DafnyCore/Options/DafnyProject.cs b/Source/DafnyCore/Options/DafnyProject.cs index 75fe766c5e9..9b7a7f40d6b 100644 --- a/Source/DafnyCore/Options/DafnyProject.cs +++ b/Source/DafnyCore/Options/DafnyProject.cs @@ -19,13 +19,12 @@ public class DafnyProject : IEquatable<DafnyProject> { public string ProjectName => Uri.ToString(); - public bool IsImplicitProject { get; set; } - [IgnoreDataMember] public Uri Uri { get; set; } public string[] Includes { get; set; } public string[] Excludes { get; set; } public Dictionary<string, object> Options { get; set; } + public bool UsesProjectFile => Path.GetFileName(Uri.LocalPath) == FileName; public static async Task<DafnyProject> Open(IFileSystem fileSystem, Uri uri, TextWriter outputWriter, TextWriter errorWriter) { if (Path.GetFileName(uri.LocalPath) != FileName) { @@ -173,7 +172,7 @@ public bool Equals(DafnyProject other) { var orderedOptions = Options?.OrderBy(kv => kv.Key) ?? Enumerable.Empty<KeyValuePair<string, object>>(); var otherOrderedOptions = other.Options?.OrderBy(kv => kv.Key) ?? Enumerable.Empty<KeyValuePair<string, object>>(); - return Equals(IsImplicitProject, other.IsImplicitProject) && Equals(Uri, other.Uri) && + return Equals(Uri, other.Uri) && NullableSetEqual(Includes?.ToHashSet(), other.Includes) && NullableSetEqual(Excludes?.ToHashSet(), other.Excludes) && orderedOptions.SequenceEqual(otherOrderedOptions, new LambdaEqualityComparer<KeyValuePair<string, object>>( @@ -255,6 +254,6 @@ public override bool Equals(object obj) { } public override int GetHashCode() { - return HashCode.Combine(IsImplicitProject, Uri, Includes, Excludes, Options); + return HashCode.Combine(Uri, Includes, Excludes, Options); } } \ No newline at end of file diff --git a/Source/DafnyCore/Resolver/PreType/PreTypeResolve.cs b/Source/DafnyCore/Resolver/PreType/PreTypeResolve.cs index e08d312455e..a8126e1309f 100644 --- a/Source/DafnyCore/Resolver/PreType/PreTypeResolve.cs +++ b/Source/DafnyCore/Resolver/PreType/PreTypeResolve.cs @@ -5,6 +5,7 @@ // //----------------------------------------------------------------------------- +using System; using System.Collections.Generic; using System.Linq; using System.Diagnostics.Contracts; @@ -1329,7 +1330,8 @@ void ResolveFrameExpression(FrameExpression fe, FrameExpressionUse use, ICodeCon FrameExpressionUse.Modifies => $"a modifies-clause {expressionMustDenoteObject} or {collection} {instead}", FrameExpressionUse.Unchanged => - $"an unchanged {expressionMustDenoteObject} or {collection} {instead}" + $"an unchanged {expressionMustDenoteObject} or {collection} {instead}", + _ => throw new ArgumentOutOfRangeException(nameof(use), use, null) }; ReportError(fe.E.tok, errorMsgFormat, fe.E.PreType); } diff --git a/Source/DafnyLanguageServer.Test/DafnyLanguageServerTestBase.cs b/Source/DafnyLanguageServer.Test/DafnyLanguageServerTestBase.cs index 9e2a8ffa12b..e915cf54418 100644 --- a/Source/DafnyLanguageServer.Test/DafnyLanguageServerTestBase.cs +++ b/Source/DafnyLanguageServer.Test/DafnyLanguageServerTestBase.cs @@ -128,7 +128,7 @@ protected static TextDocumentItem CreateTestDocument(string source, string fileP if (filePath == null) { filePath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName(), $"testFile{fileIndex++}.dfy"); } - if (Path.GetDirectoryName(filePath) == null) { + if (string.IsNullOrEmpty(Path.GetDirectoryName(filePath))) { filePath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName(), filePath); } filePath = Path.GetFullPath(filePath); diff --git a/Source/DafnyLanguageServer.Test/GutterStatus/CachedLinearVerificationGutterStatusTester.cs b/Source/DafnyLanguageServer.Test/GutterStatus/CachedLinearVerificationGutterStatusTester.cs index 5ca91644ac8..98d36dd4405 100644 --- a/Source/DafnyLanguageServer.Test/GutterStatus/CachedLinearVerificationGutterStatusTester.cs +++ b/Source/DafnyLanguageServer.Test/GutterStatus/CachedLinearVerificationGutterStatusTester.cs @@ -28,7 +28,7 @@ await VerifyTrace(@" . S S | I $ | :}", true); } - [Fact(Timeout = MaxTestExecutionTimeMs)] + [Fact] public async Task EnsureCachingDoesNotHideErrors() { await SetUp(options => { options.Set(BoogieOptionBag.Cores, 1U); diff --git a/Source/DafnyLanguageServer.Test/GutterStatus/LinearVerificationGutterStatusTester.cs b/Source/DafnyLanguageServer.Test/GutterStatus/LinearVerificationGutterStatusTester.cs index 41248ae4751..30c261ee918 100644 --- a/Source/DafnyLanguageServer.Test/GutterStatus/LinearVerificationGutterStatusTester.cs +++ b/Source/DafnyLanguageServer.Test/GutterStatus/LinearVerificationGutterStatusTester.cs @@ -25,6 +25,7 @@ protected override async Task SetUp(Action<DafnyOptions> modifyOptions) { void ModifyOptions(DafnyOptions options) { options.Set(ServerCommand.LineVerificationStatus, true); + options.Set(ServerCommand.ProjectMode, true); modifyOptions?.Invoke(options); } await base.SetUp(ModifyOptions); @@ -302,7 +303,7 @@ public async Task VerifyTrace(string codeAndTrace, bool explicitProject, string foreach (var changes in changesList) { ApplyChanges(ref documentItem, changes); traces.AddRange(await GetAllLineVerificationStatuses(documentItem, verificationStatusGutterReceiver, intermediates: intermediates)); - await Projects.GetLastDocumentAsync(documentItem); + await Projects.GetLastDocumentAsync(documentItem).WaitAsync(CancellationToken); } if (testTrace) { diff --git a/Source/DafnyLanguageServer.Test/Lookup/HoverVerificationTest.cs b/Source/DafnyLanguageServer.Test/Lookup/HoverVerificationTest.cs index 228914a64b9..65f0c157f7e 100644 --- a/Source/DafnyLanguageServer.Test/Lookup/HoverVerificationTest.cs +++ b/Source/DafnyLanguageServer.Test/Lookup/HoverVerificationTest.cs @@ -3,6 +3,7 @@ using System.Text.RegularExpressions; using System.Threading.Tasks; using JetBrains.Annotations; +using Microsoft.Boogie; using Microsoft.Dafny.LanguageServer.IntegrationTest.Extensions; using Microsoft.Dafny.LanguageServer.IntegrationTest.Synchronization; using Microsoft.Dafny.LanguageServer.IntegrationTest.Util; @@ -19,6 +20,14 @@ namespace Microsoft.Dafny.LanguageServer.IntegrationTest.Lookup { [Collection("Sequential Collection")] // Let slow tests run sequentially public class HoverVerificationTest : ClientBasedLanguageServerTest { + + protected override Task SetUp(Action<DafnyOptions> modifyOptions) { + return base.SetUp(o => { + o.Set(ServerCommand.ProjectMode, true); + modifyOptions?.Invoke(o); + }); + } + private const int MaxTestExecutionTimeMs = 30000; [Fact(Timeout = MaxTestExecutionTimeMs)] @@ -207,7 +216,7 @@ await AssertHoverMatches(documentItem, (0, 36), ); } - [Fact(Timeout = MaxTestExecutionTimeMs)] + [Fact] public async Task MeaningfulMessageWhenMethodWithoutAssert() { var documentItem = await GetDocumentItem(@" method f(x: int) { @@ -478,12 +487,13 @@ await AssertHoverMatches(documentItem, (2, 22), } private async Task<TextDocumentItem> GetDocumentItem(string source, string filename, bool includeProjectFile) { + var directory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); source = source.TrimStart(); if (includeProjectFile) { - var projectFile = CreateTestDocument("", Path.Combine(Path.GetDirectoryName(filename), DafnyProject.FileName)); + var projectFile = CreateTestDocument("", Path.Combine(directory, DafnyProject.FileName)); await client.OpenDocumentAndWaitAsync(projectFile, CancellationToken); } - var documentItem = CreateTestDocument(source, filename); + var documentItem = CreateTestDocument(source, Path.Combine(directory, filename)); await client.OpenDocumentAndWaitAsync(documentItem, CancellationToken); var document = await Projects.GetLastDocumentAsync(documentItem); Assert.True(document is CompilationAfterTranslation); diff --git a/Source/DafnyLanguageServer/Handlers/DafnyCodeActionHandler.cs b/Source/DafnyLanguageServer/Handlers/DafnyCodeActionHandler.cs index 7bec6c6f593..1a81e012a54 100644 --- a/Source/DafnyLanguageServer/Handlers/DafnyCodeActionHandler.cs +++ b/Source/DafnyLanguageServer/Handlers/DafnyCodeActionHandler.cs @@ -155,5 +155,5 @@ public DafnyCodeActionInput(CompilationAfterParsing compilation, Uri uri) { public CompilationAfterParsing Compilation { get; } public IEnumerable<DafnyDiagnostic> Diagnostics => Compilation.GetDiagnostics(uri); - public VerificationTree? VerificationTree => Compilation.GetVerificationTree(); + public VerificationTree? VerificationTree => Compilation.GetVerificationTree(uri); } diff --git a/Source/DafnyLanguageServer/Handlers/DafnyHoverHandler.cs b/Source/DafnyLanguageServer/Handlers/DafnyHoverHandler.cs index 07941943830..1d3fd8f9f2e 100644 --- a/Source/DafnyLanguageServer/Handlers/DafnyHoverHandler.cs +++ b/Source/DafnyLanguageServer/Handlers/DafnyHoverHandler.cs @@ -116,10 +116,12 @@ public int Compare(AssertionBatchIndex? key1, AssertionBatchIndex? key2) { return null; } - if (state.VerificationTree == null) { + var tree = state.VerificationTrees.GetValueOrDefault(uri); + if (tree == null) { return null; } - foreach (var node in state.VerificationTree.Children.OfType<TopLevelDeclMemberVerificationTree>()) { + + foreach (var node in tree.Children.OfType<TopLevelDeclMemberVerificationTree>()) { if (!node.Range.Contains(position)) { continue; } @@ -128,7 +130,8 @@ public int Compare(AssertionBatchIndex? key1, AssertionBatchIndex? key2) { var information = ""; var orderedAssertionBatches = node.AssertionBatches - .OrderBy(keyValue => keyValue.Key, new AssertionBatchIndexComparer()).Select(keyValuePair => keyValuePair.Value) + .OrderBy(keyValue => keyValue.Key, new AssertionBatchIndexComparer()) + .Select(keyValuePair => keyValuePair.Value) .ToList(); foreach (var assertionBatch in orderedAssertionBatches) { @@ -144,7 +147,9 @@ public int Compare(AssertionBatchIndex? key1, AssertionBatchIndex? key2) { if (information != "") { information += "\n\n"; } - information += GetAssertionInformation(state, position, assertionNode, assertionBatch, assertionIndex, assertionBatchCount, node); + + information += GetAssertionInformation(state, position, assertionNode, assertionBatch, + assertionIndex, assertionBatchCount, node); } assertionIndex++; @@ -154,8 +159,9 @@ public int Compare(AssertionBatchIndex? key1, AssertionBatchIndex? key2) { if (information != "") { return information; } + // Ok no assertion here. Maybe a method? - if (node.Position.Line == position.Line && state.Compilation.Project.IsImplicitProject && node.Uri == state.Compilation.Project.Uri) { + if (node.Position.Line == position.Line) { areMethodStatistics = true; return GetTopLevelInformation(node, orderedAssertionBatches); } diff --git a/Source/DafnyLanguageServer/Handlers/DafnyRenameHandler.cs b/Source/DafnyLanguageServer/Handlers/DafnyRenameHandler.cs index 3e637e45bfd..988f2fc7af4 100644 --- a/Source/DafnyLanguageServer/Handlers/DafnyRenameHandler.cs +++ b/Source/DafnyLanguageServer/Handlers/DafnyRenameHandler.cs @@ -37,7 +37,7 @@ protected override RenameRegistrationOptions CreateRegistrationOptions( var requestUri = request.TextDocument.Uri.ToUri(); // Reject rename requests in implicit projects, because we might not find all references within the codebase, // so a partial rename may result in breaking the codebase - if ((await projects.GetProject(requestUri)).IsImplicitProject) { + if (!(await projects.GetProject(requestUri)).UsesProjectFile) { throw new Exception("Renaming support requires --project-mode and a Dafny project file (dfyconfig.toml)"); } diff --git a/Source/DafnyLanguageServer/Handlers/DafnyTextDocumentHandler.cs b/Source/DafnyLanguageServer/Handlers/DafnyTextDocumentHandler.cs index 9d705f2ad8a..612bfa15b6f 100644 --- a/Source/DafnyLanguageServer/Handlers/DafnyTextDocumentHandler.cs +++ b/Source/DafnyLanguageServer/Handlers/DafnyTextDocumentHandler.cs @@ -83,14 +83,14 @@ public override async Task<Unit> Handle(DidCloseTextDocumentParams notification, return Unit.Value; } - public override Task<Unit> Handle(DidChangeTextDocumentParams notification, CancellationToken cancellationToken) { + public override async Task<Unit> Handle(DidChangeTextDocumentParams notification, CancellationToken cancellationToken) { logger.LogDebug("received change notification {DocumentUri}", notification.TextDocument.Uri); try { - projects.UpdateDocument(notification); + await projects.UpdateDocument(notification); } catch (Exception e) { telemetryPublisher.PublishUnhandledException(e); } - return Unit.Task; + return Unit.Value; } public override Task<Unit> Handle(DidSaveTextDocumentParams notification, CancellationToken cancellationToken) { diff --git a/Source/DafnyLanguageServer/Language/IVerificationProgressReporter.cs b/Source/DafnyLanguageServer/Language/IVerificationProgressReporter.cs index 5b79ff983fa..c867840fcfc 100644 --- a/Source/DafnyLanguageServer/Language/IVerificationProgressReporter.cs +++ b/Source/DafnyLanguageServer/Language/IVerificationProgressReporter.cs @@ -1,19 +1,17 @@ -using System.Diagnostics; +using System; using Microsoft.Boogie; using Microsoft.Dafny.LanguageServer.Workspace; -using Microsoft.Dafny.LanguageServer.Workspace.Notifications; -using VC; namespace Microsoft.Dafny.LanguageServer.Language { /// <summary> /// A callback interface to report verification progress /// </summary> public interface IVerificationProgressReporter { - void RecomputeVerificationTree(CompilationAfterTranslation compilation); - void ReportRealtimeDiagnostics(CompilationAfterTranslation compilation, bool verificationStarted); + void RecomputeVerificationTrees(CompilationAfterTranslation compilation); + void ReportRealtimeDiagnostics(CompilationAfterTranslation compilation, Uri uri, bool verificationStarted); void ReportVerifyImplementationRunning(CompilationAfterTranslation compilation, Implementation implToken); - void ReportEndVerifyImplementation(CompilationAfterTranslation compilation, Implementation implToken, Boogie.VerificationResult verificationResult); + void ReportEndVerifyImplementation(CompilationAfterTranslation compilation, Implementation implToken, VerificationResult verificationResult); void ReportImplementationsBeforeVerification(CompilationAfterTranslation compilation, Implementation[] implementations); void ReportAssertionBatchResult(CompilationAfterTranslation compilation, AssertionBatchResult batchResult); void SetAllUnvisitedMethodsAsVerified(CompilationAfterTranslation compilation); diff --git a/Source/DafnyLanguageServer/Workspace/CompilationManager.cs b/Source/DafnyLanguageServer/Workspace/CompilationManager.cs index 3e50266e2fb..a62dc6af1fe 100644 --- a/Source/DafnyLanguageServer/Workspace/CompilationManager.cs +++ b/Source/DafnyLanguageServer/Workspace/CompilationManager.cs @@ -20,7 +20,7 @@ public delegate CompilationManager CreateCompilationManager( DafnyOptions options, ExecutionEngine boogieEngine, Compilation compilation, - VerificationTree? migratedVerificationTree); + IReadOnlyDictionary<Uri, VerificationTree> migratedVerificationTrees); /// <summary> /// The compilation of a single document version. @@ -41,7 +41,7 @@ public class CompilationManager { private readonly IVerificationProgressReporter verificationProgressReporter; // TODO CompilationManager shouldn't be aware of migration - private readonly VerificationTree? migratedVerificationTree; + private readonly IReadOnlyDictionary<Uri, VerificationTree> migratedVerificationTrees; private TaskCompletionSource started = new(); private readonly IScheduler verificationUpdateScheduler = new EventLoopScheduler(); @@ -68,12 +68,12 @@ public CompilationManager( DafnyOptions options, ExecutionEngine boogieEngine, Compilation compilation, - VerificationTree? migratedVerificationTree + IReadOnlyDictionary<Uri, VerificationTree> migratedVerificationTrees ) { this.options = options; startingCompilation = compilation; this.boogieEngine = boogieEngine; - this.migratedVerificationTree = migratedVerificationTree; + this.migratedVerificationTrees = migratedVerificationTrees; this.documentLoader = documentLoader; this.logger = logger; @@ -102,9 +102,12 @@ private async Task<CompilationAfterParsing> ResolveAsync() { // TODO, let gutter icon publications also used the published CompilationView. var state = documentAfterParsing.InitialIdeState(startingCompilation, options); state = state with { - VerificationTree = migratedVerificationTree ?? state.VerificationTree + VerificationTrees = documentAfterParsing.RootUris.ToDictionary(uri => uri, + uri => migratedVerificationTrees.GetValueOrDefault(uri) ?? new DocumentVerificationTree(documentAfterParsing.Program, uri)) }; - notificationPublisher.PublishGutterIcons(state, false); + foreach (var root in documentAfterParsing.RootUris) { + notificationPublisher.PublishGutterIcons(root, state, false); + } logger.LogDebug($"documentUpdates.HasObservers: {compilationUpdates.HasObservers}, threadId: {Thread.CurrentThread.ManagedThreadId}"); compilationUpdates.OnNext(documentAfterParsing); @@ -178,13 +181,16 @@ public async Task<CompilationAfterTranslation> PrepareVerificationTasksAsync( loaded.ResolutionDiagnostics, verificationTasks, new(), initialViews, - migratedVerificationTree ?? (loaded.Project.IsImplicitProject ? new DocumentVerificationTree(loaded.Program, loaded.Project.Uri) : null) + loaded.RootUris.ToDictionary(uri => uri, + uri => migratedVerificationTrees.GetValueOrDefault(uri) ?? new DocumentVerificationTree(loaded.Program, uri)) ); - verificationProgressReporter.RecomputeVerificationTree(translated); + verificationProgressReporter.RecomputeVerificationTrees(translated); if (ReportGutterStatus) { - verificationProgressReporter.ReportRealtimeDiagnostics(translated, false); + foreach (var uri in translated.RootUris) { + verificationProgressReporter.ReportRealtimeDiagnostics(translated, uri, true); + } } verificationProgressReporter.ReportImplementationsBeforeVerification(translated, verificationTasks.Select(t => t.Implementation).ToArray()); @@ -264,7 +270,9 @@ public void FinishedNotifications(CompilationAfterTranslation compilation) { SetAllUnvisitedMethodsAsVerified(compilation); } - verificationProgressReporter.ReportRealtimeDiagnostics(compilation, true); + foreach (var uri in compilation.RootUris) { + verificationProgressReporter.ReportRealtimeDiagnostics(compilation, uri, true); + } } } diff --git a/Source/DafnyLanguageServer/Workspace/Documents/Compilation.cs b/Source/DafnyLanguageServer/Workspace/Documents/Compilation.cs index cce8604b937..ef0e5a58f59 100644 --- a/Source/DafnyLanguageServer/Workspace/Documents/Compilation.cs +++ b/Source/DafnyLanguageServer/Workspace/Documents/Compilation.cs @@ -36,12 +36,13 @@ public Compilation(int version, DafnyProject project, IReadOnlyList<Uri> rootUri public virtual IEnumerable<DafnyDiagnostic> GetDiagnostics(Uri uri) => Enumerable.Empty<DafnyDiagnostic>(); public IdeState InitialIdeState(Compilation compilation, DafnyOptions options) { - return ToIdeState(new IdeState(compilation, new EmptyNode(), + var program = new EmptyNode(); + return ToIdeState(new IdeState(compilation, program, ImmutableDictionary<Uri, IReadOnlyList<Diagnostic>>.Empty, SymbolTable.Empty(), SignatureAndCompletionTable.Empty(options, compilation.Project), new Dictionary<ImplementationId, IdeImplementationView>(), Array.Empty<Counterexample>(), false, ImmutableDictionary<Uri, IReadOnlyList<Range>>.Empty, - null + compilation.RootUris.ToDictionary(uri => uri, uri => (VerificationTree)new DocumentVerificationTree(program, uri)) )); } diff --git a/Source/DafnyLanguageServer/Workspace/Documents/CompilationAfterParsing.cs b/Source/DafnyLanguageServer/Workspace/Documents/CompilationAfterParsing.cs index 53eb8367ca3..4962a40c2b7 100644 --- a/Source/DafnyLanguageServer/Workspace/Documents/CompilationAfterParsing.cs +++ b/Source/DafnyLanguageServer/Workspace/Documents/CompilationAfterParsing.cs @@ -33,11 +33,11 @@ public override IdeState ToIdeState(IdeState previousState) { ResolutionDiagnostics = ResolutionDiagnostics.ToDictionary( kv => kv.Key, kv => (IReadOnlyList<Diagnostic>)kv.Value.Select(d => d.ToLspDiagnostic()).ToList()), - VerificationTree = baseResult.VerificationTree ?? GetVerificationTree()?.GetCopyForNotification() + VerificationTrees = baseResult.VerificationTrees }; } - public virtual VerificationTree? GetVerificationTree() { - return Project.IsImplicitProject ? new DocumentVerificationTree(Program, Project.Uri) : null; + public virtual VerificationTree GetVerificationTree(Uri uri) { + return new DocumentVerificationTree(Program, uri); } } \ No newline at end of file diff --git a/Source/DafnyLanguageServer/Workspace/Documents/CompilationAfterTranslation.cs b/Source/DafnyLanguageServer/Workspace/Documents/CompilationAfterTranslation.cs index e2b100d5222..448ca6b276a 100644 --- a/Source/DafnyLanguageServer/Workspace/Documents/CompilationAfterTranslation.cs +++ b/Source/DafnyLanguageServer/Workspace/Documents/CompilationAfterTranslation.cs @@ -1,14 +1,8 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Linq; using Microsoft.Boogie; -using Microsoft.Dafny.LanguageServer.Language; -using Microsoft.Dafny.LanguageServer.Language.Symbols; using Microsoft.Dafny.LanguageServer.Workspace.Notifications; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using OmniSharp.Extensions.LanguageServer.Protocol; using OmniSharp.Extensions.LanguageServer.Protocol.Models; namespace Microsoft.Dafny.LanguageServer.Workspace; @@ -20,19 +14,19 @@ public CompilationAfterTranslation( IReadOnlyList<IImplementationTask> verificationTasks, List<Counterexample> counterexamples, Dictionary<ImplementationId, ImplementationView> implementationIdToView, - VerificationTree? verificationTree + Dictionary<Uri, VerificationTree> verificationTrees ) : base(compilationAfterResolution, diagnostics, compilationAfterResolution.SymbolTable, compilationAfterResolution.SignatureAndCompletionTable, compilationAfterResolution.GhostDiagnostics) { - VerificationTree = verificationTree; + VerificationTrees = verificationTrees; VerificationTasks = verificationTasks; Counterexamples = counterexamples; ImplementationIdToView = implementationIdToView; } - public override VerificationTree? GetVerificationTree() { - return VerificationTree; + public override VerificationTree GetVerificationTree(Uri uri) { + return VerificationTrees[uri]; } public override IEnumerable<DafnyDiagnostic> GetDiagnostics(Uri uri) { @@ -52,7 +46,7 @@ public override IdeState ToIdeState(IdeState previousState) { }); return base.ToIdeState(previousState) with { ImplementationsWereUpdated = true, - VerificationTree = GetVerificationTree()?.GetCopyForNotification(), + VerificationTrees = VerificationTrees.ToDictionary(kv => kv.Key, kv => kv.Value.GetCopyForNotification()), Counterexamples = new List<Counterexample>(Counterexamples), ImplementationIdToView = new Dictionary<ImplementationId, IdeImplementationView>(implementationViewsWithMigratedDiagnostics) }; @@ -64,7 +58,7 @@ public override IdeState ToIdeState(IdeState previousState) { /// Can be migrated from a previous document /// The position and the range are never sent to the client. /// </summary> - public VerificationTree? VerificationTree { get; set; } + public Dictionary<Uri, VerificationTree> VerificationTrees { get; set; } public List<Counterexample> Counterexamples { get; set; } public Dictionary<ImplementationId, ImplementationView> ImplementationIdToView { get; set; } } \ No newline at end of file diff --git a/Source/DafnyLanguageServer/Workspace/INotificationPublisher.cs b/Source/DafnyLanguageServer/Workspace/INotificationPublisher.cs index d315c82e472..92caab07ed6 100644 --- a/Source/DafnyLanguageServer/Workspace/INotificationPublisher.cs +++ b/Source/DafnyLanguageServer/Workspace/INotificationPublisher.cs @@ -1,4 +1,6 @@ -namespace Microsoft.Dafny.LanguageServer.Workspace { +using System; + +namespace Microsoft.Dafny.LanguageServer.Workspace { /// <summary> /// Implementations of this interface are responsible to publish the diagnostics /// of a <see cref="Compilation"/> to the LSP client. @@ -13,6 +15,6 @@ public interface INotificationPublisher { /// <summary> /// Publishes the more precise real-time verification diagnostics to the connected LSP client /// </summary> - void PublishGutterIcons(IdeState state, bool verificationStarted); + void PublishGutterIcons(Uri uri, IdeState state, bool verificationStarted); } } diff --git a/Source/DafnyLanguageServer/Workspace/IdeState.cs b/Source/DafnyLanguageServer/Workspace/IdeState.cs index c63dbb54deb..3e84b1e061b 100644 --- a/Source/DafnyLanguageServer/Workspace/IdeState.cs +++ b/Source/DafnyLanguageServer/Workspace/IdeState.cs @@ -30,7 +30,7 @@ public record IdeState( IReadOnlyList<Counterexample> Counterexamples, bool ImplementationsWereUpdated, IReadOnlyDictionary<Uri, IReadOnlyList<Range>> GhostRanges, - VerificationTree? VerificationTree + IReadOnlyDictionary<Uri, VerificationTree> VerificationTrees ) { public int Version => Compilation.Version; diff --git a/Source/DafnyLanguageServer/Workspace/NotificationPublisher.cs b/Source/DafnyLanguageServer/Workspace/NotificationPublisher.cs index d7820c777db..1ce0b6643a9 100644 --- a/Source/DafnyLanguageServer/Workspace/NotificationPublisher.cs +++ b/Source/DafnyLanguageServer/Workspace/NotificationPublisher.cs @@ -9,6 +9,7 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.Extensions.Logging; +using OmniSharp.Extensions.LanguageServer.Protocol; using Range = OmniSharp.Extensions.LanguageServer.Protocol.Models.Range; namespace Microsoft.Dafny.LanguageServer.Workspace { @@ -131,38 +132,41 @@ void PublishForUri(Uri publishUri, Diagnostic[] diagnostics) { } languageServer.TextDocument.PublishDiagnostics(new PublishDiagnosticsParams { Uri = publishUri, - Version = filesystem.GetVersion(publishUri), + Version = filesystem.GetVersion(publishUri) ?? 0, Diagnostics = diagnostics, }); } } } - public void PublishGutterIcons(IdeState state, bool verificationStarted) { + + private Dictionary<Uri, VerificationStatusGutter> previouslyPublishedIcons = new(); + public void PublishGutterIcons(Uri uri, IdeState state, bool verificationStarted) { if (!options.Get(ServerCommand.LineVerificationStatus)) { return; } - if (!state.Compilation.Project.IsImplicitProject) { - return; - } - var root = state.Compilation.Project.Uri; - var errors = state.ResolutionDiagnostics.GetOrDefault(root, Enumerable.Empty<Diagnostic>). + var errors = state.ResolutionDiagnostics.GetOrDefault(uri, Enumerable.Empty<Diagnostic>). Where(x => x.Severity == DiagnosticSeverity.Error).ToList(); - if (state.VerificationTree == null) { - return; - } + var tree = state.VerificationTrees[uri]; - var linesCount = state.VerificationTree.Range.End.Line + 1; + var linesCount = tree.Range.End.Line + 1; var verificationStatusGutter = VerificationStatusGutter.ComputeFrom( - root, - filesystem.GetVersion(root)!.Value, - state.VerificationTree.Children, + DocumentUri.From(uri), + filesystem.GetVersion(uri) ?? 0, + tree.Children, errors, linesCount, verificationStarted ); - languageServer.TextDocument.SendNotification(verificationStatusGutter); + + lock (previouslyPublishedIcons) { + var previous = previouslyPublishedIcons.GetValueOrDefault(uri); + if (previous == null || !previous.PerLineStatus.SequenceEqual(verificationStatusGutter.PerLineStatus)) { + previouslyPublishedIcons[uri] = verificationStatusGutter; + languageServer.TextDocument.SendNotification(verificationStatusGutter); + } + } } private void PublishGhostDiagnostics(IdeState previousState, IdeState state) { diff --git a/Source/DafnyLanguageServer/Workspace/Notifications/VerificationDiagnosticsParams.cs b/Source/DafnyLanguageServer/Workspace/Notifications/VerificationDiagnosticsParams.cs index ff5a0ae55a7..4ae00afe81f 100644 --- a/Source/DafnyLanguageServer/Workspace/Notifications/VerificationDiagnosticsParams.cs +++ b/Source/DafnyLanguageServer/Workspace/Notifications/VerificationDiagnosticsParams.cs @@ -368,7 +368,10 @@ public record DocumentVerificationTree( INode Program, Uri Uri) : VerificationTree("Document", Uri.ToString(), Uri.ToString(), Uri.ToString(), Uri, ComputeRange(Program, Uri), new Position(0, 0)) { - private static Range ComputeRange(INode program, Uri uri) { + private static Range ComputeRange(INode node, Uri uri) { + if (node is not Program program) { + return new Range(0, 0, 0, 0); + } var end = ((Program)program).Files.FirstOrDefault(f => f.RangeToken.Uri == uri)?.EndToken ?? Token.NoToken; while (end.Next != null) { diff --git a/Source/DafnyLanguageServer/Workspace/ProjectManager.cs b/Source/DafnyLanguageServer/Workspace/ProjectManager.cs index e4a01c9b5ea..095bec15d49 100644 --- a/Source/DafnyLanguageServer/Workspace/ProjectManager.cs +++ b/Source/DafnyLanguageServer/Workspace/ProjectManager.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.IO; using System.Linq; using System.Reactive.Disposables; @@ -80,7 +81,7 @@ public ProjectManager( var initialCompilation = CreateInitialCompilation(); observer = createIdeStateObserver(initialCompilation); CompilationManager = createCompilationManager( - options, boogieEngine, initialCompilation, null + options, boogieEngine, initialCompilation, ImmutableDictionary<Uri, VerificationTree>.Empty ); observerSubscription = Disposable.Empty; @@ -96,12 +97,13 @@ private Compilation CreateInitialCompilation() { public void UpdateDocument(DidChangeTextDocumentParams documentChange) { var lastPublishedState = observer.LastPublishedState; - var migratedVerificationTree = lastPublishedState.VerificationTree == null ? null - : relocator.RelocateVerificationTree(lastPublishedState.VerificationTree, documentChange, CancellationToken.None); + var migratedVerificationTrees = lastPublishedState.VerificationTrees.ToDictionary( + kv => kv.Key, kv => + relocator.RelocateVerificationTree(kv.Value, documentChange, CancellationToken.None)); lastPublishedState = lastPublishedState with { ImplementationIdToView = MigrateImplementationViews(documentChange, lastPublishedState.ImplementationIdToView), SignatureAndCompletionTable = relocator.RelocateSymbols(lastPublishedState.SignatureAndCompletionTable, documentChange, CancellationToken.None), - VerificationTree = migratedVerificationTree + VerificationTrees = migratedVerificationTrees }; lock (RecentChanges) { @@ -123,11 +125,11 @@ public void UpdateDocument(DidChangeTextDocumentParams documentChange) { RecentChanges = newChanges.Concat(migratedChanges).Take(MaxRememberedChanges).ToList()!; } - StartNewCompilation(migratedVerificationTree, lastPublishedState); + StartNewCompilation(migratedVerificationTrees, lastPublishedState); TriggerVerificationForFile(documentChange.TextDocument.Uri.ToUri()); } - private void StartNewCompilation(VerificationTree? migratedVerificationTree, + private void StartNewCompilation(IReadOnlyDictionary<Uri, VerificationTree> migratedVerificationTrees, IdeState lastPublishedState) { version++; logger.LogDebug("Clearing result for workCompletedForCurrentVersion"); @@ -138,7 +140,7 @@ private void StartNewCompilation(VerificationTree? migratedVerificationTree, options, boogieEngine, CreateInitialCompilation(), - migratedVerificationTree); + migratedVerificationTrees); observerSubscription.Dispose(); var migratedUpdates = CompilationManager.CompilationUpdates.Select(document => @@ -307,10 +309,10 @@ IntervalTree<Position, Position> GetTree(Uri uri) { public void OpenDocument(Uri uri, bool triggerCompilation) { Interlocked.Increment(ref openFileCount); var lastPublishedState = observer.LastPublishedState; - var migratedVerificationTree = lastPublishedState.VerificationTree; + var migratedVerificationTrees = lastPublishedState.VerificationTrees; if (triggerCompilation) { - StartNewCompilation(migratedVerificationTree, lastPublishedState); + StartNewCompilation(migratedVerificationTrees, lastPublishedState); TriggerVerificationForFile(uri); } } diff --git a/Source/DafnyLanguageServer/Workspace/ProjectManagerDatabase.cs b/Source/DafnyLanguageServer/Workspace/ProjectManagerDatabase.cs index 980e61fc1b1..bdc9ba1505c 100644 --- a/Source/DafnyLanguageServer/Workspace/ProjectManagerDatabase.cs +++ b/Source/DafnyLanguageServer/Workspace/ProjectManagerDatabase.cs @@ -1,6 +1,5 @@ using OmniSharp.Extensions.LanguageServer.Protocol.Models; using System; -using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Runtime.Caching; @@ -184,8 +183,7 @@ public async Task<DafnyProject> GetProject(Uri uri) { public static DafnyProject ImplicitProject(Uri uri) { var implicitProject = new DafnyProject { Includes = new[] { uri.LocalPath }, - Uri = uri, - IsImplicitProject = true + Uri = uri }; return implicitProject; } @@ -207,7 +205,6 @@ public static DafnyProject ImplicitProject(Uri uri) { if (projectFile != null && projectFile.Uri != sourceUri && !serverOptions.Get(ServerCommand.ProjectMode)) { logger.LogWarning("Project file at {} will be ignored because project mode is disabled", projectFile.Uri); projectFile.Uri = sourceUri; - projectFile.IsImplicitProject = true; projectFile.Includes = new[] { sourceUri.LocalPath }; } diff --git a/Source/DafnyLanguageServer/Workspace/TextDocumentLoader.cs b/Source/DafnyLanguageServer/Workspace/TextDocumentLoader.cs index 1b23a0e1c6c..ce7efcc1e5e 100644 --- a/Source/DafnyLanguageServer/Workspace/TextDocumentLoader.cs +++ b/Source/DafnyLanguageServer/Workspace/TextDocumentLoader.cs @@ -111,9 +111,10 @@ private CompilationAfterParsing LoadInternal(DafnyOptions options, Compilation c private IdeState CreateDocumentWithEmptySymbolTable(Compilation compilation, IReadOnlyDictionary<Uri, IReadOnlyList<Diagnostic>> resolutionDiagnostics) { var dafnyOptions = DafnyOptions.Default; + var program = new EmptyNode(); return new IdeState( compilation, - new EmptyNode(), + program, resolutionDiagnostics, SymbolTable.Empty(), SignatureAndCompletionTable.Empty(dafnyOptions, compilation.Project), @@ -121,7 +122,7 @@ private IdeState CreateDocumentWithEmptySymbolTable(Compilation compilation, Array.Empty<Counterexample>(), false, ImmutableDictionary<Uri, IReadOnlyList<Range>>.Empty, - null + ImmutableDictionary<Uri, VerificationTree>.Empty ); } } diff --git a/Source/DafnyLanguageServer/Workspace/VerificationProgressReporter.cs b/Source/DafnyLanguageServer/Workspace/VerificationProgressReporter.cs index f565f3a3f92..f1226f7af26 100644 --- a/Source/DafnyLanguageServer/Workspace/VerificationProgressReporter.cs +++ b/Source/DafnyLanguageServer/Workspace/VerificationProgressReporter.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using Microsoft.Boogie; using Microsoft.Dafny.LanguageServer.Language; @@ -27,9 +28,9 @@ public VerificationProgressReporter(ILogger<VerificationProgressReporter> logger /// Fills up the document with empty verification diagnostics, one for each top-level declarations /// Possibly migrates previous diagnostics /// </summary> - public void RecomputeVerificationTree(CompilationAfterTranslation compilation) { - if (compilation.VerificationTree != null) { - UpdateTree(options, compilation, compilation.VerificationTree); + public void RecomputeVerificationTrees(CompilationAfterTranslation compilation) { + foreach (var tree in compilation.VerificationTrees.Values) { + UpdateTree(options, compilation, tree); } } @@ -73,7 +74,7 @@ void AddAndPossiblyMigrateVerificationTree(VerificationTree verificationTree) { ctor.Name, ctor.GetCompileName(options), ctor.tok.Filepath, - parsedCompilation.Uri.ToUri(), + ctor.Tok.Uri, verificationTreeRange, ctor.tok.GetLspPosition()); AddAndPossiblyMigrateVerificationTree(verificationTree); @@ -100,7 +101,7 @@ void AddAndPossiblyMigrateVerificationTree(VerificationTree verificationTree) { member.Name, member.GetCompileName(options), member.tok.Filepath, - parsedCompilation.Uri.ToUri(), + member.Tok.Uri, verificationTreeRange, member.tok.GetLspPosition()); AddAndPossiblyMigrateVerificationTree(verificationTree); @@ -111,7 +112,7 @@ void AddAndPossiblyMigrateVerificationTree(VerificationTree verificationTree) { member.Name, member.GetCompileName(options), member.tok.Filepath, - parsedCompilation.Uri.ToUri(), + member.Tok.Uri, verificationTreeRange, member.tok.GetLspPosition()); AddAndPossiblyMigrateVerificationTree(verificationTree); @@ -122,7 +123,7 @@ void AddAndPossiblyMigrateVerificationTree(VerificationTree verificationTree) { member.Name, member.GetCompileName(options) + "_by_method", member.tok.Filepath, - parsedCompilation.Uri.ToUri(), + member.Tok.Uri, verificationTreeRangeByMethod, function.ByMethodTok.GetLspPosition()); AddAndPossiblyMigrateVerificationTree(verificationTreeByMethod); @@ -142,7 +143,7 @@ void AddAndPossiblyMigrateVerificationTree(VerificationTree verificationTree) { subsetTypeDecl.Name, subsetTypeDecl.GetCompileName(options), subsetTypeDecl.tok.Filepath, - parsedCompilation.Uri.ToUri(), + subsetTypeDecl.Tok.Uri, verificationTreeRange, subsetTypeDecl.tok.GetLspPosition()); AddAndPossiblyMigrateVerificationTree(verificationTree); @@ -158,63 +159,65 @@ void AddAndPossiblyMigrateVerificationTree(VerificationTree verificationTree) { /// to its original method tree. /// Also set the implementation priority depending on the last edited methods /// </summary> - /// <param name="implementations">The implementations to be verified</param> public virtual void ReportImplementationsBeforeVerification(CompilationAfterTranslation compilation, Implementation[] implementations) { - if (compilation.VerificationTree == null) { - return; - } + var implementationsPerUri = implementations. + GroupBy(i => ((IToken)i.tok).Uri). + ToDictionary(g => g.Key, g => g); + + foreach (var tree in compilation.VerificationTrees.Values) { + // We migrate existing implementations to the new provided ones if they exist. + // (same child number, same file and same position) + foreach (var methodTree in tree.Children) { + methodTree.ResetNewChildren(); + } - // We migrate existing implementations to the new provided ones if they exist. - // (same child number, same file and same position) - foreach (var methodTree in compilation.VerificationTree.Children) { - methodTree.ResetNewChildren(); - } + foreach (var implementation in implementationsPerUri.GetValueOrDefault(tree.Uri) ?? Enumerable.Empty<Implementation>()) { - foreach (var implementation in implementations) { + var targetMethodNode = GetTargetMethodTree(tree, implementation, + out var oldImplementationNode, true); + if (targetMethodNode == null) { + NoMethodNodeAtLogging(tree, "ReportImplementationsBeforeVerification", compilation, implementation); + continue; + } - var targetMethodNode = GetTargetMethodTree(compilation.VerificationTree, implementation, out var oldImplementationNode, true); - if (targetMethodNode == null) { - NoMethodNodeAtLogging("ReportImplementationsBeforeVerification", compilation, implementation); - continue; - } - var newDisplayName = targetMethodNode.DisplayName + " #" + (targetMethodNode.Children.Count + 1) + ":" + - implementation.Name; - var newImplementationNode = new ImplementationVerificationTree( - newDisplayName, - implementation.Name, - targetMethodNode.Filename, - targetMethodNode.Uri, - targetMethodNode.Range, - targetMethodNode.Position - ).WithImplementation(implementation); - if (oldImplementationNode != null) { - newImplementationNode.Children = oldImplementationNode.Children; + var newDisplayName = targetMethodNode.DisplayName + " #" + (targetMethodNode.Children.Count + 1) + ":" + + implementation.Name; + var newImplementationNode = new ImplementationVerificationTree( + newDisplayName, + implementation.Name, + targetMethodNode.Filename, + targetMethodNode.Uri, + targetMethodNode.Range, + targetMethodNode.Position + ).WithImplementation(implementation); + if (oldImplementationNode != null) { + newImplementationNode.Children = oldImplementationNode.Children; + } + + targetMethodNode?.AddNewChild(newImplementationNode); } - targetMethodNode?.AddNewChild(newImplementationNode); - } - foreach (var methodNode in compilation.VerificationTree.Children.OfType<TopLevelDeclMemberVerificationTree>()) { - methodNode.SaveNewChildren(); - if (!methodNode.Children.Any()) { - methodNode.Start(); - methodNode.Stop(); - methodNode.StatusCurrent = CurrentStatus.Current; - methodNode.StatusVerification = GutterVerificationStatus.Verified; + foreach (var methodNode in tree.Children.OfType<TopLevelDeclMemberVerificationTree>()) { + methodNode.SaveNewChildren(); + if (!methodNode.Children.Any()) { + methodNode.Start(); + methodNode.Stop(); + methodNode.StatusCurrent = CurrentStatus.Current; + methodNode.StatusVerification = GutterVerificationStatus.Verified; + } + + methodNode.PropagateChildrenErrorsUp(); + methodNode.RecomputeAssertionBatchNodeDiagnostics(); } - methodNode.PropagateChildrenErrorsUp(); - methodNode.RecomputeAssertionBatchNodeDiagnostics(); } } /// <summary> /// Triggers sending of the current verification diagnostics to the client /// </summary> - public void ReportRealtimeDiagnostics(CompilationAfterTranslation compilation, bool verificationStarted) { - if (compilation.VerificationTree == null) { - return; - } + public void ReportRealtimeDiagnostics(CompilationAfterTranslation compilation, Uri uri, bool verificationStarted) { lock (LockProcessing) { - notificationPublisher.PublishGutterIcons(compilation.InitialIdeState(compilation, options), verificationStarted); + notificationPublisher.PublishGutterIcons(uri, compilation.InitialIdeState(compilation, options), verificationStarted); } } @@ -222,14 +225,13 @@ public void ReportRealtimeDiagnostics(CompilationAfterTranslation compilation, b /// Called when the verifier starts verifying an implementation /// </summary> public void ReportVerifyImplementationRunning(CompilationAfterTranslation compilation, Implementation implementation) { - if (compilation.VerificationTree == null) { - return; - } + var uri = ((IToken)implementation.tok).Uri; + var tree = compilation.VerificationTrees[uri]; lock (LockProcessing) { - var targetMethodNode = GetTargetMethodTree(compilation.VerificationTree, implementation, out var implementationNode); + var targetMethodNode = GetTargetMethodTree(tree, implementation, out var implementationNode); if (targetMethodNode == null) { - NoMethodNodeAtLogging("ReportVerifyImplementationRunning", compilation, implementation); + NoMethodNodeAtLogging(tree, "ReportVerifyImplementationRunning", compilation, implementation); } else { if (!targetMethodNode.Started) { // The same method could be started multiple times for each implementation @@ -243,7 +245,7 @@ public void ReportVerifyImplementationRunning(CompilationAfterTranslation compil } targetMethodNode.PropagateChildrenErrorsUp(); - ReportRealtimeDiagnostics(compilation, true); + ReportRealtimeDiagnostics(compilation, uri, true); } } } @@ -253,13 +255,12 @@ public void ReportVerifyImplementationRunning(CompilationAfterTranslation compil /// </summary> public void ReportEndVerifyImplementation(CompilationAfterTranslation compilation, Implementation implementation, VerificationResult verificationResult) { - if (compilation.VerificationTree == null) { - return; - } + var uri = ((IToken)implementation.tok).Uri; + var tree = compilation.VerificationTrees[uri]; - var targetMethodNode = GetTargetMethodTree(compilation.VerificationTree, implementation, out var implementationNode); + var targetMethodNode = GetTargetMethodTree(tree, implementation, out var implementationNode); if (targetMethodNode == null) { - NoMethodNodeAtLogging("ReportEndVerifyImplementation", compilation, implementation); + NoMethodNodeAtLogging(tree, "ReportEndVerifyImplementation", compilation, implementation); } else if (implementationNode == null) { logger.LogError($"No implementation node at {implementation.tok.filename}:{implementation.tok.line}:{implementation.tok.col}"); } else { @@ -287,17 +288,17 @@ public void ReportEndVerifyImplementation(CompilationAfterTranslation compilatio targetMethodNode.PropagateChildrenErrorsUp(); targetMethodNode.RecomputeAssertionBatchNodeDiagnostics(); - ReportRealtimeDiagnostics(compilation, true); + ReportRealtimeDiagnostics(compilation, uri, true); } } } - private void NoMethodNodeAtLogging(string methodName, CompilationAfterTranslation compilation, Implementation implementation) { + private void NoMethodNodeAtLogging(VerificationTree tree, string methodName, CompilationAfterTranslation compilation, Implementation implementation) { var position = implementation.tok.GetLspPosition(); - var availableMethodNodes = string.Join(",", compilation.VerificationTree!.Children.Select(vt => + var availableMethodNodes = string.Join(",", tree!.Children.Select(vt => $"{vt.Kind} {vt.DisplayName} at {vt.Filename}:{vt.Position.Line}")); logger.LogError( - $"No method found in {methodName}, in document {compilation.Uri} and filename {compilation.VerificationTree.Filename}, " + + $"No method found in {methodName}, in document {compilation.Uri} and filename {tree.Filename}, " + $"no method node at {implementation.tok.filename}:{position.Line}:{position.Character}.\n" + $"Available nodes: " + availableMethodNodes); } @@ -306,17 +307,16 @@ private void NoMethodNodeAtLogging(string methodName, CompilationAfterTranslatio /// Called when a split is finished to be verified /// </summary> public void ReportAssertionBatchResult(CompilationAfterTranslation compilation, AssertionBatchResult batchResult) { - if (compilation.VerificationTree == null) { - return; - } + var uri = ((IToken)batchResult.Implementation.tok).Uri; + var tree = compilation.VerificationTrees[uri]; lock (LockProcessing) { var implementation = batchResult.Implementation; var result = batchResult.Result; // While there is no error, just add successful nodes. - var targetMethodNode = GetTargetMethodTree(compilation.VerificationTree, implementation, out var implementationNode); + var targetMethodNode = GetTargetMethodTree(tree, implementation, out var implementationNode); if (targetMethodNode == null) { - NoMethodNodeAtLogging("ReportAssertionBatchResult", compilation, implementation); + NoMethodNodeAtLogging(tree, "ReportAssertionBatchResult", compilation, implementation); } else if (implementationNode == null) { logger.LogError($"No implementation node at {implementation.tok.filename}:{implementation.tok.line}:{implementation.tok.col}"); } else { @@ -399,18 +399,16 @@ void AddChildOutcome(Counterexample? counterexample, AssertCmd assertCmd, IToken } targetMethodNode.PropagateChildrenErrorsUp(); targetMethodNode.RecomputeAssertionBatchNodeDiagnostics(); - ReportRealtimeDiagnostics(compilation, true); + ReportRealtimeDiagnostics(compilation, uri, true); } } } public void SetAllUnvisitedMethodsAsVerified(CompilationAfterTranslation compilation) { - if (compilation.VerificationTree == null) { - return; - } - - foreach (var tree in compilation.VerificationTree.Children) { - tree.SetVerifiedIfPending(); + foreach (var tree in compilation.VerificationTrees.Values) { + foreach (var childTree in tree.Children) { + childTree.SetVerifiedIfPending(); + } } } From ea54998f0dca4ed091629cc2043bdbd726aab949 Mon Sep 17 00:00:00 2001 From: zafer-esen <zesen@amazon.com> Date: Mon, 7 Aug 2023 18:55:45 -0400 Subject: [PATCH 15/19] Fix: incorrect pruning of axiom with monomorhphization. (#4396) An axiom in DafnyPrelude was incorrectly being pruned away with the `monomorphic` type encoding, because it was losing its (polymorphic) quantifier and trigger. This meant automatic edge inference from triggers was no longer applicable. Moved the axiom in question into a uses clause to prevent it from being pruned. The change has no affect on other type encodings `arguments` (current default) and `predicates`. There is more discussion related to the fix here in [Boogie PR 767](https://github.com/boogie-org/boogie/pull/767). <small>By submitting this pull request, I confirm that my contribution is made under the terms of the [MIT license](https://github.com/dafny-lang/dafny/blob/master/LICENSE.txt).</small> --- Source/DafnyCore/DafnyPrelude.bpl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Source/DafnyCore/DafnyPrelude.bpl b/Source/DafnyCore/DafnyPrelude.bpl index 60740d59b63..43259bb02d7 100644 --- a/Source/DafnyCore/DafnyPrelude.bpl +++ b/Source/DafnyCore/DafnyPrelude.bpl @@ -967,8 +967,9 @@ type Seq T; function Seq#Length<T>(Seq T): int; axiom (forall<T> s: Seq T :: { Seq#Length(s) } 0 <= Seq#Length(s)); -function Seq#Empty<T>(): Seq T; -axiom (forall<T> :: { Seq#Empty(): Seq T } Seq#Length(Seq#Empty(): Seq T) == 0); +function Seq#Empty<T>(): Seq T uses { + axiom (forall<T> :: { Seq#Empty(): Seq T } Seq#Length(Seq#Empty(): Seq T) == 0); +} axiom (forall<T> s: Seq T :: { Seq#Length(s) } (Seq#Length(s) == 0 ==> s == Seq#Empty()) // The following would be a nice fact to include, because it would enable verifying the From 23ff00017b7f24a75eebe61e0bc66b6584c3edc3 Mon Sep 17 00:00:00 2001 From: Remy Willems <rwillems@amazon.com> Date: Tue, 8 Aug 2023 18:09:25 +0200 Subject: [PATCH 16/19] Test stability (#4395) ### Changes - Various changes to help with debugging test stability - A fix to prevent outdated diagnostics from being sent, which could happen in a race condition - An improvement to code related to gutter icons that makes bugs in this less likely ### Testing No additional testing <small>By submitting this pull request, I confirm that my contribution is made under the terms of the [MIT license](https://github.com/dafny-lang/dafny/blob/master/LICENSE.txt).</small> --------- Co-authored-by: Aaron Tomb <aarotomb@amazon.com> --- .../DafnyLanguageServerTestBase.cs | 5 ++- ...hedLinearVerificationGutterStatusTester.cs | 1 + ...entLinearVerificationGutterStatusTester.cs | 2 +- .../LinearVerificationGutterStatusTester.cs | 31 ++++---------- ...eorderingVerificationGutterStatusTester.cs | 11 ++--- ...pleLinearVerificationGutterStatusTester.cs | 1 + .../ProjectFiles/MultipleFilesTest.cs | 17 +++++--- .../Synchronization/DiagnosticsTest.cs | 24 +++++++---- .../Synchronization/VerificationOrderTest.cs | 3 +- .../Unit/CompilationManagerTest.cs | 2 +- .../Util/AssertWithDiff.cs | 4 +- .../Util/ClientBasedLanguageServerTest.cs | 16 +++++--- .../Util/Stringify.cs | 41 ++++++++++--------- .../Various/ExceptionTests.cs | 4 +- .../Handlers/DafnyTextDocumentHandler.cs | 2 +- .../Language/DafnyLangParser.cs | 3 ++ .../Workspace/CompilationManager.cs | 28 +++++++------ .../Workspace/INotificationPublisher.cs | 5 ++- .../Workspace/IdeStateObserver.cs | 10 ++++- .../Workspace/NotificationPublisher.cs | 36 ++++++++++++++-- .../VerificationDiagnosticsParams.cs | 12 ------ .../Workspace/ProjectManagerDatabase.cs | 7 ++-- .../Workspace/VerificationProgressReporter.cs | 4 ++ 23 files changed, 159 insertions(+), 110 deletions(-) diff --git a/Source/DafnyLanguageServer.Test/DafnyLanguageServerTestBase.cs b/Source/DafnyLanguageServer.Test/DafnyLanguageServerTestBase.cs index e915cf54418..c01cf17b76c 100644 --- a/Source/DafnyLanguageServer.Test/DafnyLanguageServerTestBase.cs +++ b/Source/DafnyLanguageServer.Test/DafnyLanguageServerTestBase.cs @@ -54,11 +54,12 @@ ensures true public IProjectDatabase Projects => Server.GetRequiredService<IProjectDatabase>(); - protected DafnyLanguageServerTestBase(ITestOutputHelper output) : base(new JsonRpcTestOptions(LoggerFactory.Create( + protected DafnyLanguageServerTestBase(ITestOutputHelper output, LogLevel dafnyLogLevel = LogLevel.Information) + : base(new JsonRpcTestOptions(LoggerFactory.Create( builder => { builder.AddFilter("OmniSharp.Extensions.JsonRpc", LogLevel.None); builder.AddFilter("OmniSharp", LogLevel.Warning); - builder.AddFilter("Microsoft.Dafny", LogLevel.Information); + builder.AddFilter("Microsoft.Dafny", dafnyLogLevel); builder.AddConsole(); }))) { this.output = new WriterFromOutputHelper(output); diff --git a/Source/DafnyLanguageServer.Test/GutterStatus/CachedLinearVerificationGutterStatusTester.cs b/Source/DafnyLanguageServer.Test/GutterStatus/CachedLinearVerificationGutterStatusTester.cs index 98d36dd4405..2c12c2dd55b 100644 --- a/Source/DafnyLanguageServer.Test/GutterStatus/CachedLinearVerificationGutterStatusTester.cs +++ b/Source/DafnyLanguageServer.Test/GutterStatus/CachedLinearVerificationGutterStatusTester.cs @@ -1,4 +1,5 @@ using System.Threading.Tasks; +using Microsoft.Extensions.Logging; using Xunit; using Xunit.Abstractions; diff --git a/Source/DafnyLanguageServer.Test/GutterStatus/ConcurrentLinearVerificationGutterStatusTester.cs b/Source/DafnyLanguageServer.Test/GutterStatus/ConcurrentLinearVerificationGutterStatusTester.cs index 6703b19569b..f843e2bd7dc 100644 --- a/Source/DafnyLanguageServer.Test/GutterStatus/ConcurrentLinearVerificationGutterStatusTester.cs +++ b/Source/DafnyLanguageServer.Test/GutterStatus/ConcurrentLinearVerificationGutterStatusTester.cs @@ -51,7 +51,7 @@ public async Task EnsuresManyDocumentsCanBeVerifiedAtOnce() { . S [S][ ][I][S][ ]:method H() . S [=][=][-][~][O]: ensures F(1) . S [=][=][-][~][=]:{//Replace: { assert false; - . S [S][ ][I][S][ ]:}", false, $"testfile{i}.dfy", true, true, verificationStatusGutterReceivers[i])); + . S [S][ ][I][S][ ]:}", false, $"EnsuresManyDocumentsCanBeVerifiedAtOnce{i}.dfy", true, true, verificationStatusGutterReceivers[i])); } for (var i = 0; i < MaxSimultaneousVerificationTasks; i++) { diff --git a/Source/DafnyLanguageServer.Test/GutterStatus/LinearVerificationGutterStatusTester.cs b/Source/DafnyLanguageServer.Test/GutterStatus/LinearVerificationGutterStatusTester.cs index 30c261ee918..9a9a461f3ea 100644 --- a/Source/DafnyLanguageServer.Test/GutterStatus/LinearVerificationGutterStatusTester.cs +++ b/Source/DafnyLanguageServer.Test/GutterStatus/LinearVerificationGutterStatusTester.cs @@ -4,10 +4,13 @@ using System.IO; using System.Linq; using System.Text.RegularExpressions; +using System.Threading; using System.Threading.Tasks; using Microsoft.Dafny.LanguageServer.IntegrationTest.Extensions; using Microsoft.Dafny.LanguageServer.IntegrationTest.Util; +using Microsoft.Dafny.LanguageServer.Workspace; using Microsoft.Dafny.LanguageServer.Workspace.Notifications; +using Microsoft.Extensions.Logging; using OmniSharp.Extensions.JsonRpc; using OmniSharp.Extensions.LanguageServer.Client; using OmniSharp.Extensions.LanguageServer.Protocol.Models; @@ -38,25 +41,6 @@ protected override void InitialiseClientHandler(LanguageClientOptions options) { NotificationHandler.For<VerificationStatusGutter>(verificationStatusGutterReceiver.NotificationReceived)); } - public static Dictionary<LineVerificationStatus, string> LineVerificationStatusToString = new() { - { LineVerificationStatus.Nothing, " " }, - { LineVerificationStatus.Scheduled, " . " }, - { LineVerificationStatus.Verifying, " S " }, - { LineVerificationStatus.VerifiedObsolete, " I " }, - { LineVerificationStatus.VerifiedVerifying, " $ " }, - { LineVerificationStatus.Verified, " | " }, - { LineVerificationStatus.ErrorContextObsolete, "[I]" }, - { LineVerificationStatus.ErrorContextVerifying, "[S]" }, - { LineVerificationStatus.ErrorContext, "[ ]" }, - { LineVerificationStatus.AssertionFailedObsolete, "[-]" }, - { LineVerificationStatus.AssertionFailedVerifying, "[~]" }, - { LineVerificationStatus.AssertionFailed, "[=]" }, - { LineVerificationStatus.AssertionVerifiedInErrorContextObsolete, "[o]" }, - { LineVerificationStatus.AssertionVerifiedInErrorContextVerifying, "[Q]" }, - { LineVerificationStatus.AssertionVerifiedInErrorContext, "[O]" }, - { LineVerificationStatus.ResolutionError, @"/!\" } - }; - private static bool IsNotIndicatingProgress(LineVerificationStatus status) { return status != LineVerificationStatus.Scheduled && status != LineVerificationStatus.Verifying && @@ -93,7 +77,7 @@ public static string RenderTrace(List<LineVerificationStatus[]> statusesTrace, L if (line >= statusTrace.Length) { renderedCode += "###"; } else { - renderedCode += LineVerificationStatusToString[statusTrace[line]]; + renderedCode += NotificationPublisher.LineVerificationStatusToString[statusTrace[line]]; } } @@ -301,9 +285,9 @@ public async Task VerifyTrace(string codeAndTrace, bool explicitProject, string var traces = new List<LineVerificationStatus[]>(); traces.AddRange(await GetAllLineVerificationStatuses(documentItem, verificationStatusGutterReceiver, intermediates: intermediates)); foreach (var changes in changesList) { + await Projects.GetLastDocumentAsync(documentItem).WaitAsync(CancellationToken); ApplyChanges(ref documentItem, changes); traces.AddRange(await GetAllLineVerificationStatuses(documentItem, verificationStatusGutterReceiver, intermediates: intermediates)); - await Projects.GetLastDocumentAsync(documentItem).WaitAsync(CancellationToken); } if (testTrace) { @@ -311,7 +295,7 @@ public async Task VerifyTrace(string codeAndTrace, bool explicitProject, string var ignoreQuestionMarks = AcceptQuestionMarks(traceObtained, codeAndTrace); var expected = "\n" + codeAndTrace + "\n"; var actual = "\n" + ignoreQuestionMarks + "\n"; - AssertWithDiff.Equal(expected, actual); + AssertWithDiff.Equal(expected, actual, fileName); } } @@ -339,6 +323,7 @@ public string AcceptQuestionMarks(string traceObtained, string expected) { return toReplaceRegex.Replace(traceObtained, "?"); } - protected LinearVerificationGutterStatusTester(ITestOutputHelper output) : base(output) { + protected LinearVerificationGutterStatusTester(ITestOutputHelper output) : + base(output) { } } diff --git a/Source/DafnyLanguageServer.Test/GutterStatus/ReorderingVerificationGutterStatusTester.cs b/Source/DafnyLanguageServer.Test/GutterStatus/ReorderingVerificationGutterStatusTester.cs index c193882d7cd..f2c3d131379 100644 --- a/Source/DafnyLanguageServer.Test/GutterStatus/ReorderingVerificationGutterStatusTester.cs +++ b/Source/DafnyLanguageServer.Test/GutterStatus/ReorderingVerificationGutterStatusTester.cs @@ -136,9 +136,9 @@ async Task CompareWithExpectation(List<string> expectedSymbols) { var orderAfterChange = await GetFlattenedPositionOrder(semaphoreSlim, source.Token); var orderAfterChangeSymbols = GetSymbols(code, orderAfterChange).ToList(); Assert.True(expectedSymbols.SequenceEqual(orderAfterChangeSymbols), - $"Expected {string.Join(", ", expectedSymbols)} but got {string.Join(", ", orderAfterChangeSymbols)}." + - $"\nOld to new history was: {verificationStatusReceiver.History.Stringify()}"); + $"Expected {string.Join(", ", expectedSymbols)} but got {string.Join(", ", orderAfterChangeSymbols)}"); } catch (OperationCanceledException) { + WriteVerificationHistory(); await output.WriteLineAsync($"Operation cancelled for index {index} when expecting: {string.Join(", ", expectedSymbols)}"); throw; } @@ -199,11 +199,12 @@ public async IAsyncEnumerable<List<Range>> GetRunningOrder(SemaphoreSlim semapho count++; } catch (OperationCanceledException) { - Console.WriteLine("count: " + count); + await output.WriteLineAsync("count: " + count); if (foundStatus != null) { - Console.WriteLine("Found status before timeout: " + string.Join(", ", foundStatus.NamedVerifiables)); + await output.WriteLineAsync("Found status before timeout: " + string.Join(", ", foundStatus.NamedVerifiables)); } - Console.WriteLine($"\nOld to new history was: {verificationStatusReceiver.History.Stringify()}"); + + WriteVerificationHistory(); throw; } diff --git a/Source/DafnyLanguageServer.Test/GutterStatus/SimpleLinearVerificationGutterStatusTester.cs b/Source/DafnyLanguageServer.Test/GutterStatus/SimpleLinearVerificationGutterStatusTester.cs index 1292105a906..6dfdd43e481 100644 --- a/Source/DafnyLanguageServer.Test/GutterStatus/SimpleLinearVerificationGutterStatusTester.cs +++ b/Source/DafnyLanguageServer.Test/GutterStatus/SimpleLinearVerificationGutterStatusTester.cs @@ -1,5 +1,6 @@ using System.Threading.Tasks; using Microsoft.Dafny.LanguageServer.IntegrationTest.Extensions; +using Microsoft.Extensions.Logging; using Xunit; using Xunit.Abstractions; diff --git a/Source/DafnyLanguageServer.Test/ProjectFiles/MultipleFilesTest.cs b/Source/DafnyLanguageServer.Test/ProjectFiles/MultipleFilesTest.cs index b70a5e7db1d..4224b8bd407 100644 --- a/Source/DafnyLanguageServer.Test/ProjectFiles/MultipleFilesTest.cs +++ b/Source/DafnyLanguageServer.Test/ProjectFiles/MultipleFilesTest.cs @@ -6,7 +6,6 @@ using Microsoft.Dafny.LanguageServer.IntegrationTest.Util; using Microsoft.Dafny.LanguageServer.Workspace; using OmniSharp.Extensions.LanguageServer.Protocol.Models; -using Serilog.Core; using Xunit; using Xunit.Abstractions; using Range = OmniSharp.Extensions.LanguageServer.Protocol.Models.Range; @@ -105,10 +104,18 @@ method Bar() { var diagnostics1 = await diagnosticsReceiver.AwaitNextNotificationAsync(CancellationToken); var diagnostics2 = await diagnosticsReceiver.AwaitNextNotificationAsync(CancellationToken); - Assert.Single(diagnostics1.Diagnostics); - Assert.Contains("assertion might not hold", diagnostics1.Diagnostics.First().Message); - Assert.Single(diagnostics2.Diagnostics); - Assert.Contains("assertion might not hold", diagnostics2.Diagnostics.First().Message); + try { + Assert.Single(diagnostics1.Diagnostics); + Assert.Contains("assertion might not hold", diagnostics1.Diagnostics.First().Message); + Assert.Single(diagnostics2.Diagnostics); + Assert.Contains("assertion might not hold", diagnostics2.Diagnostics.First().Message); + } catch (Exception) { + await output.WriteLineAsync($"diagnostics1: {diagnostics1.Stringify()}"); + await output.WriteLineAsync($"diagnostics2: {diagnostics2.Stringify()}"); + var diagnostics3 = await diagnosticsReceiver.AwaitNextNotificationAsync(CancellationToken); + await output.WriteLineAsync($"diagnostics3: {diagnostics3.Stringify()}"); + throw; + } } [Fact] diff --git a/Source/DafnyLanguageServer.Test/Synchronization/DiagnosticsTest.cs b/Source/DafnyLanguageServer.Test/Synchronization/DiagnosticsTest.cs index 787f792681c..30b3bea4040 100644 --- a/Source/DafnyLanguageServer.Test/Synchronization/DiagnosticsTest.cs +++ b/Source/DafnyLanguageServer.Test/Synchronization/DiagnosticsTest.cs @@ -12,6 +12,7 @@ using Newtonsoft.Json; using Xunit.Abstractions; using Xunit; +using Xunit.Sdk; using XunitAssertMessages; using Range = OmniSharp.Extensions.LanguageServer.Protocol.Models.Range; @@ -728,15 +729,17 @@ public async Task OpeningDocumentWithMultipleVerificationCoresReturnsStableDiagn var documentItem = CreateTestDocument(source, $"test_{i}.dfy"); client.OpenDocument(documentItem); var diagnostics = await GetLastDiagnostics(documentItem, cancellationToken); - AssertM.Equal(5, diagnostics.Length, $"Iteration is {i}, Old to new history was: {diagnosticsReceiver.History.Stringify()}"); + try { + AssertM.Equal(5, diagnostics.Length, $"Iteration is {i}"); + } catch (EqualException) { + WriteVerificationHistory(); + } Assert.Equal(MessageSource.Verifier.ToString(), diagnostics[0].Source); Assert.Equal(DiagnosticSeverity.Error, diagnostics[0].Severity); await AssertNoDiagnosticsAreComing(cancellationToken); } } - - [Fact] public async Task OpeningDocumentWithElephantOperatorDoesNotThrowException() { var source = @" @@ -883,11 +886,16 @@ method test() { var documentItem = CreateTestDocument(source); client.OpenDocument(documentItem); var firstVerificationDiagnostics = await diagnosticsReceiver.AwaitNextDiagnosticsAsync(CancellationToken, documentItem); - var secondVerificationDiagnostics = await diagnosticsReceiver.AwaitNextDiagnosticsAsync(CancellationToken, documentItem); - - Assert.Single(firstVerificationDiagnostics); - // Second diagnostic is a timeout exception from SlowToVerify - Assert.Equal(2, secondVerificationDiagnostics.Length); + try { + var secondVerificationDiagnostics = + await diagnosticsReceiver.AwaitNextDiagnosticsAsync(CancellationToken, documentItem); + + Assert.Single(firstVerificationDiagnostics); + // Second diagnostic is a timeout exception from SlowToVerify + Assert.Equal(2, secondVerificationDiagnostics.Length); + } catch (OperationCanceledException) { + await output.WriteLineAsync($"firstVerificationDiagnostics: {firstVerificationDiagnostics}"); + } await AssertNoDiagnosticsAreComing(CancellationToken); } diff --git a/Source/DafnyLanguageServer.Test/Synchronization/VerificationOrderTest.cs b/Source/DafnyLanguageServer.Test/Synchronization/VerificationOrderTest.cs index 562819ad166..bd52c466442 100644 --- a/Source/DafnyLanguageServer.Test/Synchronization/VerificationOrderTest.cs +++ b/Source/DafnyLanguageServer.Test/Synchronization/VerificationOrderTest.cs @@ -6,8 +6,9 @@ using Xunit; using Xunit.Abstractions; -namespace Microsoft.Dafny.LanguageServer.IntegrationTest.Synchronization; +namespace Microsoft.Dafny.LanguageServer.IntegrationTest.Synchronization; +[Collection("Sequential Collection")] public class VerificationOrderTest : ClientBasedLanguageServerTest { [Fact] diff --git a/Source/DafnyLanguageServer.Test/Unit/CompilationManagerTest.cs b/Source/DafnyLanguageServer.Test/Unit/CompilationManagerTest.cs index a31ebf40aa1..afee40a2868 100644 --- a/Source/DafnyLanguageServer.Test/Unit/CompilationManagerTest.cs +++ b/Source/DafnyLanguageServer.Test/Unit/CompilationManagerTest.cs @@ -20,7 +20,7 @@ public async Task CancelUnstartedCompilationLeadsToCancelledTasks() { new Mock<ICompilationStatusNotificationPublisher>().Object, new Mock<IVerificationProgressReporter>().Object, dafnyOptions, - null, new Compilation(0, new DafnyProject(), new Uri[] { }), null); + null, new Compilation(0, new DafnyProject() { Uri = new Uri(Directory.GetCurrentDirectory()) }, new Uri[] { }), null); compilationManager.CancelPendingUpdates(); await Assert.ThrowsAsync<TaskCanceledException>(() => compilationManager.ResolvedCompilation); } diff --git a/Source/DafnyLanguageServer.Test/Util/AssertWithDiff.cs b/Source/DafnyLanguageServer.Test/Util/AssertWithDiff.cs index 003a0f11d92..882162c3609 100644 --- a/Source/DafnyLanguageServer.Test/Util/AssertWithDiff.cs +++ b/Source/DafnyLanguageServer.Test/Util/AssertWithDiff.cs @@ -7,14 +7,14 @@ namespace Microsoft.Dafny.LanguageServer.IntegrationTest.Util; public class AssertWithDiff { - public static void Equal(string expected, string actual) { + public static void Equal(string expected, string actual, string contextMessage) { var diff = InlineDiffBuilder.Instance.BuildDiffModel(expected, actual); if (!diff.HasDifferences) { return; } var message = new StringBuilder(); - message.AppendLine("AssertEqualWithDiff() Failure"); + message.AppendLine($"For {contextMessage}, AssertEqualWithDiff() Failure"); message.AppendLine("Diff (changing expected into actual):"); foreach (var line in diff.Lines) { var prefix = line.Type switch { diff --git a/Source/DafnyLanguageServer.Test/Util/ClientBasedLanguageServerTest.cs b/Source/DafnyLanguageServer.Test/Util/ClientBasedLanguageServerTest.cs index 958062b2a61..01c51dc544a 100644 --- a/Source/DafnyLanguageServer.Test/Util/ClientBasedLanguageServerTest.cs +++ b/Source/DafnyLanguageServer.Test/Util/ClientBasedLanguageServerTest.cs @@ -10,6 +10,7 @@ using Microsoft.Dafny.LanguageServer.IntegrationTest.Extensions; using Microsoft.Dafny.LanguageServer.Workspace; using Microsoft.Dafny.LanguageServer.Workspace.Notifications; +using Microsoft.Extensions.Logging; using OmniSharp.Extensions.JsonRpc; using OmniSharp.Extensions.LanguageServer.Client; using OmniSharp.Extensions.LanguageServer.Protocol.Client; @@ -40,6 +41,9 @@ public class ClientBasedLanguageServerTest : DafnyLanguageServerTestBase, IAsync private static Regex errorTests = new Regex(@"\*\*Error:\*\*|\*\*Success:\*\*"); + protected ClientBasedLanguageServerTest(ITestOutputHelper output, LogLevel dafnyLogLevel = LogLevel.Information) + : base(output, dafnyLogLevel) { + } protected async Task<TextDocumentItem> CreateAndOpenTestDocument(string source, string filePath = null, int version = 1) { @@ -103,11 +107,16 @@ public async Task<NamedVerifiableStatus> WaitForStatus(Range nameRange, Publishe return namedVerifiableStatus; } } catch (OperationCanceledException) { - await output.WriteLineAsync($"\nOld to new history was: {verificationStatusReceiver.History.Stringify()}"); + WriteVerificationHistory(); } } } + protected void WriteVerificationHistory() { + output.WriteLine($"\nOld to new history was:"); + verificationStatusReceiver.History.Stringify(output); + } + public async Task<IList<FileVerificationStatus>> WaitUntilCompletedForUris(int uriCount, CancellationToken cancellationToken) { var result = new List<FileVerificationStatus>(); var donePerUri = new Dictionary<Uri, bool>(); @@ -123,7 +132,7 @@ public async Task<IList<FileVerificationStatus>> WaitUntilCompletedForUris(int u foundStatus.NamedVerifiables.All(n => n.Status >= PublishedVerificationStatus.Error); result.Add(foundStatus); } catch (OperationCanceledException) { - await output.WriteLineAsync($"\nOld to new history was: {verificationStatusReceiver.History.Stringify()}"); + WriteVerificationHistory(); throw; } } @@ -340,7 +349,4 @@ protected Task ApplyChangesAndWaitCompletionAsync(VersionedTextDocumentIdentifie }); return client.WaitForNotificationCompletionAsync(documentItem.Uri, CancellationToken); } - - public ClientBasedLanguageServerTest(ITestOutputHelper output) : base(output) { - } } diff --git a/Source/DafnyLanguageServer.Test/Util/Stringify.cs b/Source/DafnyLanguageServer.Test/Util/Stringify.cs index 9d9a8efb043..23c6c3e1c2d 100644 --- a/Source/DafnyLanguageServer.Test/Util/Stringify.cs +++ b/Source/DafnyLanguageServer.Test/Util/Stringify.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.IO; using System.Linq; using System.Text; @@ -9,44 +10,42 @@ namespace Microsoft.Dafny.LanguageServer.IntegrationTest.Util; public static class StringifyUtil { - public static string Stringify(this object root, bool showNullChildren = false) { - - var builder = new StringBuilder(); + public static void Stringify(this object root, TextWriter writer, bool showNullChildren = false) { void Helper(ImmutableHashSet<object> visited, object? value, int indentation) { if (value == null) { - builder.Append("null"); + writer.Write("null"); return; } if (value is IEnumerable<object> enumerable) { var sep = ""; - builder.Append("[ "); + writer.Write("[ "); var newIndentation = indentation + 2; foreach (var child in enumerable) { - builder.AppendLine(sep); - builder.Append(new String(' ', newIndentation)); + writer.WriteLine(sep); + writer.Write(new String(' ', newIndentation)); Helper(visited, child, newIndentation); sep = ", "; } if (sep != "") { - builder.AppendLine(); - builder.Append(new String(' ', indentation)); + writer.WriteLine(); + writer.Write(new String(' ', indentation)); } - builder.Append("]"); + writer.Write("]"); return; } if (value is string) { - builder.Append($"\"{value}\""); + writer.Write($"\"{value}\""); return; } var type = value.GetType(); if (type.Namespace?.StartsWith("System") == true) { - builder.Append(value); + writer.Write(value); return; } @@ -54,31 +53,35 @@ void Helper(ImmutableHashSet<object> visited, object? value, int indentation) { if (properties.Any(p => p.PropertyType.IsAssignableTo(typeof(IEnumerable<object>)))) { if (visited.Contains(value)) { - builder.Append("<visited>"); + writer.Write("<visited>"); return; } var newVisited = visited.Add(value); - builder.Append(type.Name + " { "); + writer.Write(type.Name + " { "); var objectSep = ""; foreach (var property in properties) { var child = property.GetValue(value); if (!showNullChildren && child == null) { continue; } - builder.Append(objectSep); - builder.Append(property.Name + ": "); + writer.Write(objectSep); + writer.Write(property.Name + ": "); Helper(newVisited, child, indentation); objectSep = ", "; } - builder.Append(" }"); + writer.Write(" }"); } else { - builder.Append(value); + writer.Write(value); } } Helper(ImmutableHashSet.Create<object>(), root, 0); + } - return builder.ToString()!; + public static string Stringify(this object root, bool showNullChildren = false) { + var stringWriter = new StringWriter(); + Stringify(root, stringWriter, showNullChildren); + return stringWriter.ToString(); } } \ No newline at end of file diff --git a/Source/DafnyLanguageServer.Test/Various/ExceptionTests.cs b/Source/DafnyLanguageServer.Test/Various/ExceptionTests.cs index 4c6d4bc2d9f..844b38ef349 100644 --- a/Source/DafnyLanguageServer.Test/Various/ExceptionTests.cs +++ b/Source/DafnyLanguageServer.Test/Various/ExceptionTests.cs @@ -96,7 +96,7 @@ public Task<IReadOnlyList<IImplementationTask>> GetVerificationTasksAsync(Execut CompilationAfterResolution compilation, CancellationToken cancellationToken) { if (tests.CrashOnPrepareVerification) { - throw new Exception("crash"); + throw new Exception("testing crash"); } return verifier.GetVerificationTasksAsync(engine, compilation, cancellationToken); } @@ -118,7 +118,7 @@ public IdeState CreateUnloaded(Compilation compilation) { public Task<CompilationAfterParsing> LoadAsync(DafnyOptions options, Compilation compilation, CancellationToken cancellationToken) { if (tests.CrashOnLoad) { - throw new IOException("crash"); + throw new IOException("testing crash"); } return loader.LoadAsync(options, compilation, cancellationToken); } diff --git a/Source/DafnyLanguageServer/Handlers/DafnyTextDocumentHandler.cs b/Source/DafnyLanguageServer/Handlers/DafnyTextDocumentHandler.cs index 612bfa15b6f..8b931f72cec 100644 --- a/Source/DafnyLanguageServer/Handlers/DafnyTextDocumentHandler.cs +++ b/Source/DafnyLanguageServer/Handlers/DafnyTextDocumentHandler.cs @@ -84,7 +84,7 @@ public override async Task<Unit> Handle(DidCloseTextDocumentParams notification, } public override async Task<Unit> Handle(DidChangeTextDocumentParams notification, CancellationToken cancellationToken) { - logger.LogDebug("received change notification {DocumentUri}", notification.TextDocument.Uri); + logger.LogDebug($"Received change notification {notification.TextDocument.Uri} version {notification.TextDocument.Version}"); try { await projects.UpdateDocument(notification); } catch (Exception e) { diff --git a/Source/DafnyLanguageServer/Language/DafnyLangParser.cs b/Source/DafnyLanguageServer/Language/DafnyLangParser.cs index b32ffc00e2f..ab6757727c4 100644 --- a/Source/DafnyLanguageServer/Language/DafnyLangParser.cs +++ b/Source/DafnyLanguageServer/Language/DafnyLangParser.cs @@ -44,6 +44,9 @@ public Program Parse(Compilation compilation, ErrorReporter reporter, Cancellati foreach (var rootSourceUri in rootSourceUris) { try { dafnyFiles.Add(new DafnyFile(reporter.Options, rootSourceUri, fileSystem.ReadFile(rootSourceUri))); + if (logger.IsEnabled(LogLevel.Trace)) { + logger.LogTrace($"Parsing file with uri {rootSourceUri} and content\n{fileSystem.ReadFile(rootSourceUri).ReadToEnd()}"); + } } catch (IOException) { logger.LogError($"Tried to parse file {rootSourceUri} that could not be found"); } diff --git a/Source/DafnyLanguageServer/Workspace/CompilationManager.cs b/Source/DafnyLanguageServer/Workspace/CompilationManager.cs index a62dc6af1fe..a3f2651f8cb 100644 --- a/Source/DafnyLanguageServer/Workspace/CompilationManager.cs +++ b/Source/DafnyLanguageServer/Workspace/CompilationManager.cs @@ -172,7 +172,7 @@ public async Task<CompilationAfterTranslation> PrepareVerificationTasksAsync( initialViews.Add(implementationId, view); } } catch (ArgumentException) { - logger.LogCritical($"Two different implementation tasks have the same id, second name is {task.Implementation.Name}."); + logger.LogError($"Two different implementation tasks have the same id, second name is {task.Implementation.Name}."); } } @@ -237,11 +237,13 @@ public bool VerifyTask(CompilationAfterTranslation compilation, IImplementationT try { HandleStatusUpdate(compilation, implementationTask, update); } catch (Exception e) { - logger.LogCritical(e, "Caught exception in statusUpdates OnNext."); + logger.LogError(e, "Caught exception in statusUpdates OnNext."); } }, e => { - logger.LogError(e, "Caught error in statusUpdates observable."); + if (e is not OperationCanceledException) { + logger.LogError(e, $"Caught error in statusUpdates observable."); + } StatusUpdateHandlerFinally(); }, StatusUpdateHandlerFinally @@ -251,7 +253,7 @@ void StatusUpdateHandlerFinally() { try { var remainingJobs = Interlocked.Decrement(ref runningVerificationJobs); if (remainingJobs == 0) { - logger.LogDebug($"Calling FinishedNotifications because there are no remaining verification jobs for version {compilation.Version}."); + logger.LogDebug($"Calling FinishedNotifications because there are no remaining verification jobs for {compilation.Uri} version {compilation.Version}."); FinishedNotifications(compilation); } } catch (Exception e) { @@ -263,7 +265,6 @@ void StatusUpdateHandlerFinally() { } public void FinishedNotifications(CompilationAfterTranslation compilation) { - MarkVerificationFinished(); if (ReportGutterStatus) { // All unvisited trees need to set them as "verified" if (!cancellationSource.IsCancellationRequested) { @@ -274,25 +275,26 @@ public void FinishedNotifications(CompilationAfterTranslation compilation) { verificationProgressReporter.ReportRealtimeDiagnostics(compilation, uri, true); } } + + MarkVerificationFinished(); } private void HandleStatusUpdate(CompilationAfterTranslation compilation, IImplementationTask implementationTask, IVerificationStatus boogieStatus) { var id = GetImplementationId(implementationTask.Implementation); var status = StatusFromBoogieStatus(boogieStatus); var implementationRange = implementationTask.Implementation.tok.GetLspRange(true); - logger.LogDebug($"Received status {boogieStatus} for {implementationTask.Implementation.Name}, version {compilation.Counterexamples}"); + var tokenString = implementationTask.Implementation.tok.TokenToString(options); + logger.LogDebug($"Received status {boogieStatus} for {tokenString}, version {compilation.Version}"); if (boogieStatus is Running) { verificationProgressReporter.ReportVerifyImplementationRunning(compilation, implementationTask.Implementation); } if (boogieStatus is BatchCompleted batchCompleted) { - logger.LogDebug($"Received batch completed for {implementationTask.Implementation.tok}"); verificationProgressReporter.ReportAssertionBatchResult(compilation, new AssertionBatchResult(implementationTask.Implementation, batchCompleted.VcResult)); } if (boogieStatus is Completed completed) { - logger.LogDebug($"Received verification task completed for {implementationTask.Implementation.tok}, version {compilation.Counterexamples}"); var verificationResult = completed.Result; foreach (var counterExample in verificationResult.Errors) { compilation.Counterexamples.Add(counterExample); @@ -303,7 +305,7 @@ private void HandleStatusUpdate(CompilationAfterTranslation compilation, IImplem // This loop will ensure that every vc result has been dealt with // before we report that the verification of the implementation is finished foreach (var result in completed.Result.VCResults) { - logger.LogDebug($"Possibly duplicate reporting assertion batch {result.vcNum} as completed in {implementationTask.Implementation.tok}, version {compilation.Counterexamples}"); + logger.LogDebug($"Possibly duplicate reporting assertion batch {result.vcNum} as completed in {tokenString}, version {compilation.Version}"); verificationProgressReporter.ReportAssertionBatchResult(compilation, new AssertionBatchResult(implementationTask.Implementation, result)); } @@ -364,14 +366,14 @@ public void CancelPendingUpdates() { } public void MarkVerificationStarted() { - logger.LogTrace("MarkVerificationStarted called"); + logger.LogDebug($"MarkVerificationStarted called for {startingCompilation.Uri} version {startingCompilation.Version}"); if (verificationCompleted.Task.IsCompleted) { verificationCompleted = new TaskCompletionSource(); } } public void MarkVerificationFinished() { - logger.LogTrace("MarkVerificationFinished called"); + logger.LogDebug($"MarkVerificationFinished called for {startingCompilation.Uri} version {startingCompilation.Version}"); verificationCompleted.TrySetResult(); } @@ -379,10 +381,10 @@ public void MarkVerificationFinished() { t => { if (t.IsCompletedSuccessfully) { #pragma warning disable VSTHRD103 - logger.LogDebug($"LastDocument will return document version {t.Result.Version}"); + logger.LogDebug($"LastDocument {startingCompilation.Uri} will return document version {t.Result.Version}"); return verificationCompleted.Task.ContinueWith( verificationCompletedTask => { - logger.LogDebug($"verificationCompleted finished with status {verificationCompletedTask.Status}"); + logger.LogDebug($"LastDocument returning translated compilation {startingCompilation.Uri} with status {verificationCompletedTask.Status}"); return Task.FromResult<CompilationAfterParsing>(t.Result); }, TaskScheduler.Current).Unwrap(); #pragma warning restore VSTHRD103 diff --git a/Source/DafnyLanguageServer/Workspace/INotificationPublisher.cs b/Source/DafnyLanguageServer/Workspace/INotificationPublisher.cs index 92caab07ed6..1f3593e08be 100644 --- a/Source/DafnyLanguageServer/Workspace/INotificationPublisher.cs +++ b/Source/DafnyLanguageServer/Workspace/INotificationPublisher.cs @@ -1,4 +1,5 @@ -using System; +using System.Threading.Tasks; +using System; namespace Microsoft.Dafny.LanguageServer.Workspace { /// <summary> @@ -10,7 +11,7 @@ public interface INotificationPublisher { /// Publishes the diagnostics of the specified dafny document to the connected LSP client. /// </summary> /// <param name="state">The document whose diagnostics should be published.</param> - void PublishNotifications(IdeState previousState, IdeState state); + Task PublishNotifications(IdeState previousState, IdeState state); /// <summary> /// Publishes the more precise real-time verification diagnostics to the connected LSP client diff --git a/Source/DafnyLanguageServer/Workspace/IdeStateObserver.cs b/Source/DafnyLanguageServer/Workspace/IdeStateObserver.cs index 810a3360d2f..01dbe3e7d06 100644 --- a/Source/DafnyLanguageServer/Workspace/IdeStateObserver.cs +++ b/Source/DafnyLanguageServer/Workspace/IdeStateObserver.cs @@ -38,7 +38,9 @@ public IdeStateObserver(ILogger logger, public void OnCompleted() { var ideState = loader.CreateUnloaded(compilation) with { Compilation = new Compilation(LastPublishedState.Version + 1, LastPublishedState.Compilation.Project, compilation.RootUris) }; - notificationPublisher.PublishNotifications(LastPublishedState, ideState); +#pragma warning disable VSTHRD002 + notificationPublisher.PublishNotifications(LastPublishedState, ideState).Wait(); +#pragma warning restore VSTHRD002 telemetryPublisher.PublishUpdateComplete(); } @@ -72,7 +74,11 @@ public void OnNext(IdeState snapshot) { return; } - notificationPublisher.PublishNotifications(LastPublishedState, snapshot); + // To prevent older updates from being sent after newer ones, we can only run one PublishNotifications at a time. + // So we wait for it here to finish, and the lock in this method prevents more than one from running at a time. +#pragma warning disable VSTHRD002 + notificationPublisher.PublishNotifications(LastPublishedState, snapshot).Wait(); +#pragma warning restore VSTHRD002 LastPublishedState = snapshot; } } diff --git a/Source/DafnyLanguageServer/Workspace/NotificationPublisher.cs b/Source/DafnyLanguageServer/Workspace/NotificationPublisher.cs index 1ce0b6643a9..15c460886b2 100644 --- a/Source/DafnyLanguageServer/Workspace/NotificationPublisher.cs +++ b/Source/DafnyLanguageServer/Workspace/NotificationPublisher.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics; using Microsoft.Dafny.LanguageServer.Workspace.Notifications; using OmniSharp.Extensions.LanguageServer.Protocol.Document; using OmniSharp.Extensions.LanguageServer.Protocol.Models; @@ -30,14 +31,14 @@ public NotificationPublisher(ILogger<NotificationPublisher> logger, ILanguageSer this.filesystem = filesystem; } - public void PublishNotifications(IdeState previousState, IdeState state) { + public async Task PublishNotifications(IdeState previousState, IdeState state) { if (state.Version < previousState.Version) { return; } PublishVerificationStatus(previousState, state); - var _ = PublishDocumentDiagnostics(state); PublishGhostDiagnostics(previousState, state); + await PublishDocumentDiagnostics(state); } private void PublishVerificationStatus(IdeState previousState, IdeState state) { @@ -130,6 +131,7 @@ void PublishForUri(Uri publishUri, Diagnostic[] diagnostics) { // Prevent memory leaks by cleaning up previous state when it's the IDE's initial state. publishedDiagnostics.Remove(publishUri); } + languageServer.TextDocument.PublishDiagnostics(new PublishDiagnosticsParams { Uri = publishUri, Version = filesystem.GetVersion(publishUri) ?? 0, @@ -151,14 +153,22 @@ public void PublishGutterIcons(Uri uri, IdeState state, bool verificationStarted var tree = state.VerificationTrees[uri]; var linesCount = tree.Range.End.Line + 1; + var version = filesystem.GetVersion(uri) ?? 0; var verificationStatusGutter = VerificationStatusGutter.ComputeFrom( DocumentUri.From(uri), - filesystem.GetVersion(uri) ?? 0, + version, tree.Children, errors, linesCount, verificationStarted ); + if (logger.IsEnabled(LogLevel.Trace)) { + var icons = string.Join(' ', verificationStatusGutter.PerLineStatus.Select(s => LineVerificationStatusToString[s])); + logger.LogDebug($"Sending gutter icons for compilation {state.Compilation.Project.Uri}, version {state.Version}, " + + $"icons: {icons}\n" + + $"stacktrace:\n{Environment.StackTrace}"); + }; + lock (previouslyPublishedIcons) { var previous = previouslyPublishedIcons.GetValueOrDefault(uri); @@ -169,6 +179,26 @@ public void PublishGutterIcons(Uri uri, IdeState state, bool verificationStarted } } + + public static Dictionary<LineVerificationStatus, string> LineVerificationStatusToString = new() { + { LineVerificationStatus.Nothing, " " }, + { LineVerificationStatus.Scheduled, " . " }, + { LineVerificationStatus.Verifying, " S " }, + { LineVerificationStatus.VerifiedObsolete, " I " }, + { LineVerificationStatus.VerifiedVerifying, " $ " }, + { LineVerificationStatus.Verified, " | " }, + { LineVerificationStatus.ErrorContextObsolete, "[I]" }, + { LineVerificationStatus.ErrorContextVerifying, "[S]" }, + { LineVerificationStatus.ErrorContext, "[ ]" }, + { LineVerificationStatus.AssertionFailedObsolete, "[-]" }, + { LineVerificationStatus.AssertionFailedVerifying, "[~]" }, + { LineVerificationStatus.AssertionFailed, "[=]" }, + { LineVerificationStatus.AssertionVerifiedInErrorContextObsolete, "[o]" }, + { LineVerificationStatus.AssertionVerifiedInErrorContextVerifying, "[Q]" }, + { LineVerificationStatus.AssertionVerifiedInErrorContext, "[O]" }, + { LineVerificationStatus.ResolutionError, @"/!\" } + }; + private void PublishGhostDiagnostics(IdeState previousState, IdeState state) { var newParams = state.GhostRanges; diff --git a/Source/DafnyLanguageServer/Workspace/Notifications/VerificationDiagnosticsParams.cs b/Source/DafnyLanguageServer/Workspace/Notifications/VerificationDiagnosticsParams.cs index 4ae00afe81f..9b1a009ab92 100644 --- a/Source/DafnyLanguageServer/Workspace/Notifications/VerificationDiagnosticsParams.cs +++ b/Source/DafnyLanguageServer/Workspace/Notifications/VerificationDiagnosticsParams.cs @@ -355,9 +355,6 @@ public bool SetVerifiedIfPending() { } public virtual VerificationTree GetCopyForNotification() { - if (Finished) { - return this;// Won't be modified anymore, no need to duplicate - } return this with { Children = Children.Select(child => child.GetCopyForNotification()).ToList() }; @@ -403,9 +400,6 @@ Position Position new Dictionary<AssertionBatchIndex, AssertionBatchVerificationTree>().ToImmutableDictionary(); public override VerificationTree GetCopyForNotification() { - if (Finished) { - return this;// Won't be modified anymore, no need to duplicate - } return this with { Children = Children.Select(child => child.GetCopyForNotification()).ToList(), AssertionBatches = AssertionBatches @@ -479,9 +473,6 @@ public AssertionBatchVerificationTree WithDuration(DateTime parentStartTime, int return this; } public override VerificationTree GetCopyForNotification() { - if (Finished) { - return this;// Won't be modified anymore, no need to duplicate - } return this with { Children = Children.Select(child => child.GetCopyForNotification()).ToList() }; @@ -514,9 +505,6 @@ Position Position new Dictionary<int, AssertionBatchMetrics>(); public override VerificationTree GetCopyForNotification() { - if (Finished) { - return this;// Won't be modified anymore, no need to duplicate - } return this with { Children = Children.Select(child => child.GetCopyForNotification()).ToList(), AssertionBatchMetrics = new Dictionary<int, AssertionBatchMetrics>(AssertionBatchMetrics).ToImmutableDictionary() diff --git a/Source/DafnyLanguageServer/Workspace/ProjectManagerDatabase.cs b/Source/DafnyLanguageServer/Workspace/ProjectManagerDatabase.cs index bdc9ba1505c..131c8642e61 100644 --- a/Source/DafnyLanguageServer/Workspace/ProjectManagerDatabase.cs +++ b/Source/DafnyLanguageServer/Workspace/ProjectManagerDatabase.cs @@ -12,7 +12,7 @@ namespace Microsoft.Dafny.LanguageServer.Workspace { /// <summary> /// Contains a collection of ProjectManagers /// </summary> - public class ProjectManagerDatabase : IProjectDatabase, IDisposable { + public class ProjectManagerDatabase : IProjectDatabase { private object myLock = new(); public const int ProjectFileCacheExpiryTime = 100; @@ -115,9 +115,10 @@ public async Task CloseDocumentAsync(TextDocumentIdentifier documentId) { }; var manager = await GetProjectManager(documentId, false); if (manager != null) { - return await manager.GetLastDocumentAsync()!; + return await manager.GetLastDocumentAsync(); } + logger.LogDebug($"GetLastDocumentAsync returned null for {documentId.Uri}"); return null; } @@ -203,7 +204,7 @@ public static DafnyProject ImplicitProject(Uri uri) { } if (projectFile != null && projectFile.Uri != sourceUri && !serverOptions.Get(ServerCommand.ProjectMode)) { - logger.LogWarning("Project file at {} will be ignored because project mode is disabled", projectFile.Uri); + logger.LogDebug("Project file at {} will be ignored because project mode is disabled", projectFile.Uri); projectFile.Uri = sourceUri; projectFile.Includes = new[] { sourceUri.LocalPath }; } diff --git a/Source/DafnyLanguageServer/Workspace/VerificationProgressReporter.cs b/Source/DafnyLanguageServer/Workspace/VerificationProgressReporter.cs index f1226f7af26..31335b835d8 100644 --- a/Source/DafnyLanguageServer/Workspace/VerificationProgressReporter.cs +++ b/Source/DafnyLanguageServer/Workspace/VerificationProgressReporter.cs @@ -164,6 +164,10 @@ public virtual void ReportImplementationsBeforeVerification(CompilationAfterTran GroupBy(i => ((IToken)i.tok).Uri). ToDictionary(g => g.Key, g => g); + if (logger.IsEnabled(LogLevel.Debug)) { + logger.LogDebug($"ReportImplementationsBeforeVerification for ${compilation.Project.Uri}, version {compilation.Version}, implementations: " + + $"{string.Join(", ", implementations.Select(i => i.Name))}"); + } foreach (var tree in compilation.VerificationTrees.Values) { // We migrate existing implementations to the new provided ones if they exist. // (same child number, same file and same position) From 3b8d2aef6a6b1a6b0fa0b3d51c8b851688209545 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=C3=ABl=20Mayer?= <MikaelMayer@users.noreply.github.com> Date: Tue, 8 Aug 2023 17:09:09 -0500 Subject: [PATCH 17/19] Chore: Make translation diagnostics available in IDE no matter what (#4359) There are currently only two types translation diagnostics, - "Some instances of this call are not inlined.", which can happen only if there is a trigger in the file, which generates an info diagnostic during resolution. - "Fuel can only increase within a given scope." which can be triggered only if there is already a function with fuel, which thus has a "decreases" info diagnostic during resolution. The fact that they make it to the IDE is almost exceptional because of this remark. Indeed, In the CompilationManager.cs, normally, after verification is prepared, only _previous_ resolution diagnostics are sent back to the IDE under the type `IReadOnlyDictionary<Uri, List<Diagnostic>>` It's just that resolution diagnostics are are using the same list of diagnostics as the resolution ones, so the translation will add information to them, and that list will be updated _if it existed before_. If not, it will get created, but the resolution diagnostics won't have it since it's a snapshot of a dictionary. This PR fixes that behavior, by ensuring the diagnostics sent after translation are the most up to date ones. I don't think it's possible to write a reasonable test of this feature at this stage, because there are no other translation diagnostics that could be triggered without a previous resolution information diagnostic. But that will change later. This PR only prepares the way with a simple change. <small>By submitting this pull request, I confirm that my contribution is made under the terms of the [MIT license](https://github.com/dafny-lang/dafny/blob/master/LICENSE.txt).</small> --- Source/DafnyCore/Plugins/Rewriter.cs | 10 +++++ Source/DafnyCore/Rewriters/IRewriter.cs | 4 ++ Source/DafnyCore/Rewriters/PluginRewriter.cs | 4 ++ Source/DafnyCore/Verifier/Translator.cs | 6 +++ .../PluginsTestWithTranslationError.cs | 37 +++++++++++++++++++ .../Various/PluginsTestWithVerification.cs | 2 +- .../_plugins/PluginsTestTranslationError.cs | 23 ++++++++++++ .../Workspace/CompilationManager.cs | 6 ++- 8 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 Source/DafnyLanguageServer.Test/Various/PluginsTestWithTranslationError.cs create mode 100644 Source/DafnyLanguageServer.Test/_plugins/PluginsTestTranslationError.cs diff --git a/Source/DafnyCore/Plugins/Rewriter.cs b/Source/DafnyCore/Plugins/Rewriter.cs index 5c681bc1103..90d398176eb 100644 --- a/Source/DafnyCore/Plugins/Rewriter.cs +++ b/Source/DafnyCore/Plugins/Rewriter.cs @@ -31,5 +31,15 @@ public virtual void PostResolve(ModuleDefinition moduleDefinition) { public virtual void PostResolve(Program program) { Contract.Requires(program != null); } + + /// <summary> + /// Override this method to obtain the resolved program before the translation pipeline occurs + /// after the individual PostResolve on every module + /// You can also report warnings and errors using reporter.Error + /// </summary> + /// <param name="program">The program before it is translated</param> + public virtual void PreTranslate(Program program) { + Contract.Requires(program != null); + } } } diff --git a/Source/DafnyCore/Rewriters/IRewriter.cs b/Source/DafnyCore/Rewriters/IRewriter.cs index 8ddce0ccfbb..1baf1a280dc 100644 --- a/Source/DafnyCore/Rewriters/IRewriter.cs +++ b/Source/DafnyCore/Rewriters/IRewriter.cs @@ -112,6 +112,10 @@ internal virtual void PostResolve(Program program) { Contract.Requires(program != null); } + internal virtual void PreTranslate(Program program) { + Contract.Requires(program != null); + } + public virtual void PostVerification(Program program) { Contract.Requires(program != null); } diff --git a/Source/DafnyCore/Rewriters/PluginRewriter.cs b/Source/DafnyCore/Rewriters/PluginRewriter.cs index 4bc1775e7be..87a446fc21d 100644 --- a/Source/DafnyCore/Rewriters/PluginRewriter.cs +++ b/Source/DafnyCore/Rewriters/PluginRewriter.cs @@ -14,4 +14,8 @@ internal override void PostResolve(ModuleDefinition moduleDefinition) { internal override void PostResolve(Program program) { internalRewriter.PostResolve(program); } + + internal override void PreTranslate(Program program) { + internalRewriter.PreTranslate(program); + } } \ No newline at end of file diff --git a/Source/DafnyCore/Verifier/Translator.cs b/Source/DafnyCore/Verifier/Translator.cs index 6ec91b9912d..86a40437f61 100644 --- a/Source/DafnyCore/Verifier/Translator.cs +++ b/Source/DafnyCore/Verifier/Translator.cs @@ -866,6 +866,12 @@ public static IEnumerable<ModuleDefinition> VerifiableModules(Program p) { Type.ResetScopes(); + foreach (var plugin in p.Options.Plugins) { + foreach (var rewriter in plugin.GetRewriters(p.Reporter)) { + rewriter.PreTranslate(p); + } + } + foreach (ModuleDefinition outerModule in VerifiableModules(p)) { var translator = new Translator(reporter, flags); diff --git a/Source/DafnyLanguageServer.Test/Various/PluginsTestWithTranslationError.cs b/Source/DafnyLanguageServer.Test/Various/PluginsTestWithTranslationError.cs new file mode 100644 index 00000000000..224a4216180 --- /dev/null +++ b/Source/DafnyLanguageServer.Test/Various/PluginsTestWithTranslationError.cs @@ -0,0 +1,37 @@ +using System.Linq; +using System.Threading.Tasks; +using System.Threading; +using Microsoft.Dafny.LanguageServer.IntegrationTest.Extensions; +using Xunit; +using Xunit.Abstractions; +using XunitAssertMessages; +using Range = OmniSharp.Extensions.LanguageServer.Protocol.Models.Range; + +namespace Microsoft.Dafny.LanguageServer.IntegrationTest.Various; + +public class PluginsTestWithTranslationError : PluginsTestBase { + + protected override string LibraryName => + "PluginsTestTranslationError"; + + protected override string[] CommandLineArgument => + new[] { $@"{LibraryPath},""because\\ \""whatever""" }; + + [Fact] + public async Task EnsureTranslationErrorsAreReportedEvenWithoutResolutionErrors() { + // This code will run with the plugin from PluginsAdvancedTest, but that plugin won't throw an exception on the code below. + var documentItem = CreateTestDocument("function test(): nat { -1 }");// No resolution error + await client.OpenDocumentAndWaitAsync(documentItem, CancellationToken); + var resolutionReport = await diagnosticsReceiver.AwaitNextNotificationAsync(CancellationToken); + Assert.Equal(documentItem.Uri, resolutionReport.Uri); + var verificationReport = await diagnosticsReceiver.AwaitNextNotificationAsync(CancellationToken); + Assert.Equal(documentItem.Uri, verificationReport.Uri); + var diagnostics = verificationReport.Diagnostics.ToArray(); + AssertM.Equal(2, diagnostics.Length, LibraryPath + " did not return two errors."); + Assert.Equal("Translation error that should appear in the code", diagnostics[0].Message); + Assert.Equal(new Range((0, 0), (0, 8)), diagnostics[0].Range); + } + + public PluginsTestWithTranslationError(ITestOutputHelper output) : base(output) { + } +} diff --git a/Source/DafnyLanguageServer.Test/Various/PluginsTestWithVerification.cs b/Source/DafnyLanguageServer.Test/Various/PluginsTestWithVerification.cs index facd695c57f..b6560c3a1e3 100644 --- a/Source/DafnyLanguageServer.Test/Various/PluginsTestWithVerification.cs +++ b/Source/DafnyLanguageServer.Test/Various/PluginsTestWithVerification.cs @@ -25,7 +25,7 @@ public async Task EnsureItIsPossibleToLoadAPluginAndContinueVerification() { var resolutionReport = await diagnosticsReceiver.AwaitNextNotificationAsync(CancellationToken); Assert.Equal(documentItem.Uri, resolutionReport.Uri); var verificationReport = await diagnosticsReceiver.AwaitNextNotificationAsync(CancellationToken); - Assert.Equal(documentItem.Uri, resolutionReport.Uri); + Assert.Equal(documentItem.Uri, verificationReport.Uri); var diagnostics = verificationReport.Diagnostics.ToArray(); AssertM.Equal(2, diagnostics.Length, LibraryPath + " did not raise an error."); Assert.Equal("Plugin Error that does not prevent verification", diagnostics[0].Message); diff --git a/Source/DafnyLanguageServer.Test/_plugins/PluginsTestTranslationError.cs b/Source/DafnyLanguageServer.Test/_plugins/PluginsTestTranslationError.cs new file mode 100644 index 00000000000..1debcc6badc --- /dev/null +++ b/Source/DafnyLanguageServer.Test/_plugins/PluginsTestTranslationError.cs @@ -0,0 +1,23 @@ +using System; +using Microsoft.Dafny; +using Microsoft.Dafny.Plugins; + +namespace PluginsTestTranslationError { + + public class TestConfiguration : PluginConfiguration { + public override Rewriter[] GetRewriters(ErrorReporter errorReporter) { + return new Rewriter[] { new TranslationErrorRewriter(errorReporter) }; + } + } + + public class TranslationErrorRewriter : Rewriter { + public TranslationErrorRewriter(ErrorReporter reporter) : base(reporter) { + } + + public override void PreTranslate(Program program) { + Reporter.Error(MessageSource.Translator, program.GetFirstTopLevelToken(), + "Translation error that should appear in the code"); + } + } + +} \ No newline at end of file diff --git a/Source/DafnyLanguageServer/Workspace/CompilationManager.cs b/Source/DafnyLanguageServer/Workspace/CompilationManager.cs index a3f2651f8cb..aec7a112920 100644 --- a/Source/DafnyLanguageServer/Workspace/CompilationManager.cs +++ b/Source/DafnyLanguageServer/Workspace/CompilationManager.cs @@ -176,9 +176,13 @@ public async Task<CompilationAfterTranslation> PrepareVerificationTasksAsync( } } + // Obtain additional diagnostics from the translation + var errorReporter = (DiagnosticErrorReporter)loaded.Program.Reporter; + var translated = new CompilationAfterTranslation( loaded, - loaded.ResolutionDiagnostics, verificationTasks, + errorReporter.AllDiagnosticsCopy, + verificationTasks, new(), initialViews, loaded.RootUris.ToDictionary(uri => uri, From 203defd315b038e523167514e27f90b96b887148 Mon Sep 17 00:00:00 2001 From: Aleksandr Fedchin <sasha.fedchin@gmail.com> Date: Tue, 8 Aug 2023 23:57:43 -0700 Subject: [PATCH 18/19] [Counterexamples] Fix stack overflow during counterexample extraction for some programs (#4392) Fixes #4391 This PR fixes a potential case of an infinite recursion in Dafny counterexample extraction (exemplified by the added test). The solution is to change the order in which Dafny looks at functions in the counterexample model when trying to deduce the type of a variable. By submitting this pull request, I confirm that my contribution is made under the terms of the MIT license. --------- Co-authored-by: Aleksandr Fedchin <fedchina@amazon.com> --- .../Various/CounterExampleTest.cs | 24 +++++++++++++++++++ .../CounterExampleGeneration/DafnyModel.cs | 20 ++++++++-------- docs/dev/news/4392.fix | 1 + 3 files changed, 35 insertions(+), 10 deletions(-) create mode 100644 docs/dev/news/4392.fix diff --git a/Source/DafnyLanguageServer.Test/Various/CounterExampleTest.cs b/Source/DafnyLanguageServer.Test/Various/CounterExampleTest.cs index d06741c4c26..3555a330c89 100644 --- a/Source/DafnyLanguageServer.Test/Various/CounterExampleTest.cs +++ b/Source/DafnyLanguageServer.Test/Various/CounterExampleTest.cs @@ -1534,6 +1534,30 @@ class C<T> { Assert.True(counterExamples[0].Variables.ContainsKey("this:M.C<M.C$T>")); } + /// <summary> + /// This test case would previously lead to stack overflow because of infinite recursion in GetDafnyType + /// </summary> + [Theory] + [MemberData(nameof(OptionSettings))] + public async Task GetDafnyTypeInfiniteRecursion(List<Action<DafnyOptions>> optionSettings) { + await SetUpOptions(optionSettings); + var source = @" + class Seq { + var s:seq<int> + method test(i0:nat, val0:int, i1:nat, val1:int) + modifies this { + assume 0 <= i0 < i1 < |s|; + s := s[i0 := val0]; + s := s[i1 := val1]; + assert s[0] != 0; + } + } + ".TrimStart(); + var documentItem = CreateTestDocument(source); + await client.OpenDocumentAndWaitAsync(documentItem, CancellationToken); + (await RequestCounterExamples(documentItem.Uri)).ToList(); ; + } + public CounterExampleTest(ITestOutputHelper output) : base(output) { } } diff --git a/Source/DafnyLanguageServer/CounterExampleGeneration/DafnyModel.cs b/Source/DafnyLanguageServer/CounterExampleGeneration/DafnyModel.cs index fea167d23d1..0cb7a6cb420 100644 --- a/Source/DafnyLanguageServer/CounterExampleGeneration/DafnyModel.cs +++ b/Source/DafnyLanguageServer/CounterExampleGeneration/DafnyModel.cs @@ -303,6 +303,16 @@ internal Type GetDafnyType(Model.Element element) { /// This method tries to extract the base type (so seq<char> instead of string) /// </summary> private Type GetDafnyType(Model.Uninterpreted element) { + var finalResult = UnknownType; + foreach (var typeElement in GetIsResults(element)) { + var reconstructedType = ReconstructType(typeElement); + if (reconstructedType is not UserDefinedType userDefinedType) { + return reconstructedType; + } + if (finalResult.Name.EndsWith("?") || finalResult == UnknownType) { + finalResult = userDefinedType; + } + } var seqOperation = fSeqAppend.AppWithResult(element); seqOperation ??= fSeqDrop.AppWithResult(element); seqOperation ??= fSeqTake.AppWithResult(element); @@ -351,16 +361,6 @@ private Type GetDafnyType(Model.Uninterpreted element) { if (fCharToInt.OptEval(element) != null) { return Type.Char; } - var finalResult = UnknownType; - foreach (var typeElement in GetIsResults(element)) { - var reconstructedType = ReconstructType(typeElement); - if (reconstructedType is not UserDefinedType userDefinedType) { - return reconstructedType; - } - if (finalResult.Name.EndsWith("?") || finalResult == UnknownType) { - finalResult = userDefinedType; - } - } if (finalResult != UnknownType) { return finalResult; } diff --git a/docs/dev/news/4392.fix b/docs/dev/news/4392.fix new file mode 100644 index 00000000000..0f7257f0ae3 --- /dev/null +++ b/docs/dev/news/4392.fix @@ -0,0 +1 @@ +Fixed a bug leading to stack overflow during counterexample extraction on some programs. \ No newline at end of file From 195bb6e6694051de8cfff5b87c04cc7b62e655b9 Mon Sep 17 00:00:00 2001 From: Aleksandr Fedchin <sasha.fedchin@gmail.com> Date: Wed, 9 Aug 2023 09:05:45 -0700 Subject: [PATCH 19/19] [Test Generation] Deprecate support for old command line interface (#4385) This PR deprecates support for old command line interface in test generation. Test generation hardcodes some non-standard command-line-options ("predicates" type encoding, enforced determinism, disabled axiom pruning), which is much more easier to enforce via the new command line interface. This also removes quite a bit of code and makes test generation easier to maintain. By submitting this pull request, I confirm that my contribution is made under the terms of the MIT license. --------- Co-authored-by: Aleksandr Fedchin <fedchina@amazon.com> --- Source/DafnyCore/DafnyOptions.cs | 6 +- Source/DafnyCore/TestGenerationOptions.cs | 68 +------------------ Source/DafnyTestGeneration/DeadCodeCommand.cs | 16 ++--- .../GenerateTestsCommand.cs | 34 ++++++---- .../ProgramModification.cs | 2 +- docs/DafnyRef/Options.txt | 18 ----- docs/dev/news/4385.fix | 1 + 7 files changed, 30 insertions(+), 115 deletions(-) create mode 100644 docs/dev/news/4385.fix diff --git a/Source/DafnyCore/DafnyOptions.cs b/Source/DafnyCore/DafnyOptions.cs index 8bcbf9476d3..6eb521625e7 100644 --- a/Source/DafnyCore/DafnyOptions.cs +++ b/Source/DafnyCore/DafnyOptions.cs @@ -792,8 +792,8 @@ protected bool ParseDafnySpecificOption(string name, Bpl.CommandLineParseState p return true; } - // Unless this is an option for test generation, defer to superclass - return TestGenOptions.ParseOption(name, ps) || base.ParseOption(name, ps); + // Defer to superclass + return base.ParseOption(name, ps); } private static string[] ParseInnerArguments(string argumentsString) { @@ -1462,8 +1462,6 @@ focal predicate P to P#[_k-1]. /proverOpt:O:model.compact=false (for z3 version >= 4.8.7), and /proverOpt:O:model.completion=true. ----- Test generation options ----------------------------------------------- -{TestGenOptions.Help} ---- Compilation options --------------------------------------------------- /compile:<n> diff --git a/Source/DafnyCore/TestGenerationOptions.cs b/Source/DafnyCore/TestGenerationOptions.cs index 72110edbb33..02a40421821 100644 --- a/Source/DafnyCore/TestGenerationOptions.cs +++ b/Source/DafnyCore/TestGenerationOptions.cs @@ -5,76 +5,14 @@ namespace Microsoft.Dafny { public class TestGenerationOptions { - - public static readonly string TestInlineAttribute = "testInline"; - public static readonly string TestEntryAttribute = "testEntry"; + public const string TestInlineAttribute = "testInline"; + public const string TestEntryAttribute = "testEntry"; public bool WarnDeadCode = false; public enum Modes { None, Block, Path }; public Modes Mode = Modes.None; public uint SeqLengthLimit = 0; [CanBeNull] public string PrintBpl = null; - public bool DisablePrune = false; + public bool ForcePrune = false; public const uint DefaultTimeLimit = 10; - - public bool ParseOption(string name, Bpl.CommandLineParseState ps) { - var args = ps.args; - - switch (name) { - - case "warnDeadCode": - WarnDeadCode = true; - Mode = Modes.Block; - return true; - - case "generateTestMode": - if (ps.ConfirmArgumentCount(1)) { - Mode = args[ps.i] switch { - "None" => Modes.None, - "Block" => Modes.Block, - "Path" => Modes.Path, - _ => throw new Exception("Invalid value for generateTestMode") - }; - } - return true; - - case "generateTestSeqLengthLimit": - var limit = 0; - if (ps.GetIntArgument(ref limit)) { - SeqLengthLimit = (uint)limit; - } - return true; - - case "generateTestPrintBpl": - if (ps.ConfirmArgumentCount(1)) { - PrintBpl = args[ps.i]; - } - return true; - - case "generateTestNoPrune": - DisablePrune = true; - return true; - } - - return false; - } - - public string Help => @" -/warnDeadCode - Use counterexample generation to warn about potential dead code. -/generateTestMode:<None|Block|Path> - None (default) - Has no effect. - Block - Prints block-coverage tests for the given program. - Path - Prints path-coverage tests for the given program. - Using /definiteAssignment:3, /generateTestNoPrune, - /generateTestSeqLengthLimit, and /loopUnroll is highly recommended - when generating tests. -/generateTestSeqLengthLimit:<n> - Add an axiom that sets the length of all sequences to be no greater - than <n>. 0 (default) indicates no limit. -/generateTestPrintBpl:<fileName> - Print the Boogie code used during test generation. -/generateTestNoPrune - Disable axiom pruning that Dafny uses to speed up verification."; - } } diff --git a/Source/DafnyTestGeneration/DeadCodeCommand.cs b/Source/DafnyTestGeneration/DeadCodeCommand.cs index c985b469028..95764d0a2e5 100644 --- a/Source/DafnyTestGeneration/DeadCodeCommand.cs +++ b/Source/DafnyTestGeneration/DeadCodeCommand.cs @@ -6,16 +6,17 @@ using System.CommandLine; using System.CommandLine.Invocation; using System.Linq; +using Microsoft.Boogie; namespace Microsoft.Dafny; public class DeadCodeCommand : ICommandSpec { public IEnumerable<Option> Options => new Option[] { - // IMPORTANT: Before adding new options, make sure they are - // appropriately copied over in the GenerateTestCommand.CopyForProcedure method GenerateTestsCommand.LoopUnroll, GenerateTestsCommand.SequenceLengthLimit, + GenerateTestsCommand.ForcePrune, + GenerateTestsCommand.PrintBpl, BoogieOptionBag.SolverLog, BoogieOptionBag.SolverOption, BoogieOptionBag.SolverOptionHelp, @@ -32,16 +33,7 @@ public Command Create() { } public void PostProcess(DafnyOptions dafnyOptions, Options options, InvocationContext context) { - // IMPORTANT: Before adding new default options, make sure they are - // appropriately copied over in the GenerateTestCommand.CopyForProcedure method - dafnyOptions.Compile = true; - dafnyOptions.RunAfterCompile = false; - dafnyOptions.ForceCompile = false; - dafnyOptions.ForbidNondeterminism = true; - dafnyOptions.DefiniteAssignmentLevel = 2; - - dafnyOptions.TestGenOptions.Mode = TestGenerationOptions.Modes.Block; + GenerateTestsCommand.PostProcess(dafnyOptions, options, context, TestGenerationOptions.Modes.Block); dafnyOptions.TestGenOptions.WarnDeadCode = true; - dafnyOptions.Set(DafnyConsolePrinter.ShowSnippets, false); } } diff --git a/Source/DafnyTestGeneration/GenerateTestsCommand.cs b/Source/DafnyTestGeneration/GenerateTestsCommand.cs index 8af2fed9e5b..fd20c745353 100644 --- a/Source/DafnyTestGeneration/GenerateTestsCommand.cs +++ b/Source/DafnyTestGeneration/GenerateTestsCommand.cs @@ -4,6 +4,8 @@ using System.CommandLine.Invocation; using System.Linq; using DafnyCore; +using Microsoft.Boogie; + // Copyright by the contributors to the Dafny Project // SPDX-License-Identifier: MIT @@ -23,7 +25,7 @@ public class GenerateTestsCommand : ICommandSpec { BoogieOptionBag.SolverResourceLimit, BoogieOptionBag.VerificationTimeLimit, PrintBpl, - DisablePrune + ForcePrune }.Concat(ICommandSpec.ConsoleOutputOptions). Concat(ICommandSpec.ResolverOptions); @@ -57,8 +59,15 @@ public Command Create() { } public void PostProcess(DafnyOptions dafnyOptions, Options options, InvocationContext context) { - // IMPORTANT: Before adding new default options, make sure they are - // appropriately copied over in the CopyForProcedure method above + var mode = context.ParseResult.GetValueForArgument(modeArgument) switch { + Mode.Path => TestGenerationOptions.Modes.Path, + Mode.Block => TestGenerationOptions.Modes.Block, + _ => throw new ArgumentOutOfRangeException() + }; + PostProcess(dafnyOptions, options, context, mode); + } + + internal static void PostProcess(DafnyOptions dafnyOptions, Options options, InvocationContext context, TestGenerationOptions.Modes mode) { dafnyOptions.CompilerName = "cs"; dafnyOptions.Compile = true; dafnyOptions.RunAfterCompile = false; @@ -66,14 +75,9 @@ public void PostProcess(DafnyOptions dafnyOptions, Options options, InvocationCo dafnyOptions.DeprecationNoise = 0; dafnyOptions.ForbidNondeterminism = true; dafnyOptions.DefiniteAssignmentLevel = 2; + dafnyOptions.TypeEncodingMethod = CoreOptions.TypeEncoding.Predicates; dafnyOptions.Set(DafnyConsolePrinter.ShowSnippets, false); - - var mode = context.ParseResult.GetValueForArgument(modeArgument); - dafnyOptions.TestGenOptions.Mode = mode switch { - Mode.Path => TestGenerationOptions.Modes.Path, - Mode.Block => TestGenerationOptions.Modes.Block, - _ => throw new ArgumentOutOfRangeException() - }; + dafnyOptions.TestGenOptions.Mode = mode; } public static readonly Option<uint> SequenceLengthLimit = new("--length-limit", @@ -86,8 +90,8 @@ public void PostProcess(DafnyOptions dafnyOptions, Options options, InvocationCo "Print the Boogie code used during test generation.") { ArgumentHelpName = "filename" }; - public static readonly Option<bool> DisablePrune = new("--no-prune", - "Disable axiom pruning that Dafny uses to speed up verification.") { + public static readonly Option<bool> ForcePrune = new("--force-prune", + "Enable axiom pruning that Dafny uses to speed up verification. This may negatively affect the quality of tests.") { }; static GenerateTestsCommand() { DafnyOptions.RegisterLegacyBinding(LoopUnroll, (options, value) => { @@ -99,15 +103,15 @@ static GenerateTestsCommand() { DafnyOptions.RegisterLegacyBinding(PrintBpl, (options, value) => { options.TestGenOptions.PrintBpl = value; }); - DafnyOptions.RegisterLegacyBinding(DisablePrune, (options, value) => { - options.TestGenOptions.DisablePrune = value; + DafnyOptions.RegisterLegacyBinding(ForcePrune, (options, value) => { + options.TestGenOptions.ForcePrune = value; }); DooFile.RegisterNoChecksNeeded( LoopUnroll, SequenceLengthLimit, PrintBpl, - DisablePrune + ForcePrune ); } } diff --git a/Source/DafnyTestGeneration/ProgramModification.cs b/Source/DafnyTestGeneration/ProgramModification.cs index 05fff8e5617..1d5376b5a55 100644 --- a/Source/DafnyTestGeneration/ProgramModification.cs +++ b/Source/DafnyTestGeneration/ProgramModification.cs @@ -115,7 +115,7 @@ private static void SetupForCounterexamples(DafnyOptions options) { options.ErrorTrace = 1; options.EnhancedErrorMessages = 1; options.ModelViewFile = "-"; - options.Prune = !options.TestGenOptions.DisablePrune; + options.Prune = options.TestGenOptions.ForcePrune; } /// <summary> diff --git a/docs/DafnyRef/Options.txt b/docs/DafnyRef/Options.txt index 90f89026270..027681972ac 100644 --- a/docs/DafnyRef/Options.txt +++ b/docs/DafnyRef/Options.txt @@ -326,24 +326,6 @@ Usage: dafny [ option ... ] [ filename ... ] /proverOpt:O:model.compact=false (for z3 version >= 4.8.7), and /proverOpt:O:model.completion=true. - ---- Test generation options ----------------------------------------------- - - /warnDeadCode - Use counterexample generation to warn about potential dead code. - /generateTestMode:<None|Block|Path> - None (default) - Has no effect. - Block - Prints block-coverage tests for the given program. - Path - Prints path-coverage tests for the given program. - Using /definiteAssignment:3, /generateTestNoPrune, - /generateTestSeqLengthLimit, and /loopUnroll is highly recommended - when generating tests. - /generateTestSeqLengthLimit:<n> - Add an axiom that sets the length of all sequences to be no greater - than <n>. 0 (default) indicates no limit. - /generateTestPrintBpl:<fileName> - Print the Boogie code used during test generation. - /generateTestNoPrune - Disable axiom pruning that Dafny uses to speed up verification. ---- Compilation options --------------------------------------------------- /compileSuffix:<value> diff --git a/docs/dev/news/4385.fix b/docs/dev/news/4385.fix new file mode 100644 index 00000000000..6b581df269c --- /dev/null +++ b/docs/dev/news/4385.fix @@ -0,0 +1 @@ +Old command line interface for test generation is no longer supported, all calls should use dafny generate-tests \ No newline at end of file