From 1e9a9af1700f67dde62e8ceb81aa16e13de0e3fb Mon Sep 17 00:00:00 2001 From: Clément Pit--Claudel Date: Sun, 7 Jun 2015 02:22:02 -0700 Subject: Add a compatibility layer over BigInteger.Parse Mono currently does not implement support for BigInteger.Parse, so use Int64 if possible, and throw the same error as was previously returned otherwise. This is not too much of a problem in practice, because most of the integers that we actually come across in real-life source files seem to fit in an Int64. --- Source/Dafny/DafnyPipeline.csproj | 1 + 1 file changed, 1 insertion(+) (limited to 'Source/Dafny/DafnyPipeline.csproj') diff --git a/Source/Dafny/DafnyPipeline.csproj b/Source/Dafny/DafnyPipeline.csproj index 74f7dae6..f9540aa0 100644 --- a/Source/Dafny/DafnyPipeline.csproj +++ b/Source/Dafny/DafnyPipeline.csproj @@ -145,6 +145,7 @@ + -- cgit v1.2.3 From e4cefb56b4312d7c2bf88d9ba3c3bfd2e00940e9 Mon Sep 17 00:00:00 2001 From: Clément Pit--Claudel Date: Mon, 13 Jul 2015 11:51:04 -0700 Subject: Register the trigger generator as a a rewriter in the Resolver. --- Source/Dafny/DafnyPipeline.csproj | 5 +++-- Source/Dafny/Rewriter.cs | 29 +++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) (limited to 'Source/Dafny/DafnyPipeline.csproj') diff --git a/Source/Dafny/DafnyPipeline.csproj b/Source/Dafny/DafnyPipeline.csproj index f9540aa0..a1452b8a 100644 --- a/Source/Dafny/DafnyPipeline.csproj +++ b/Source/Dafny/DafnyPipeline.csproj @@ -1,4 +1,4 @@ - + Debug @@ -143,6 +143,7 @@ + @@ -192,4 +193,4 @@ --> - + \ No newline at end of file diff --git a/Source/Dafny/Rewriter.cs b/Source/Dafny/Rewriter.cs index c0a25a82..480b3f61 100644 --- a/Source/Dafny/Rewriter.cs +++ b/Source/Dafny/Rewriter.cs @@ -36,6 +36,35 @@ namespace Microsoft.Dafny } } + public class TriggersRewriter : IRewriter { + Resolver Resolver; + + internal TriggersRewriter(Resolver resolver) { + Contract.Requires(Resolver != null); + this.Resolver = resolver; + } + + public void PreResolve(ModuleDefinition m) { } + + public void PostResolve(ModuleDefinition m) { + foreach (var decl in ModuleDefinition.AllCallables(m.TopLevelDecls)) { + if (decl is Function) { + var function = (Function)decl; + TriggerGenerator.AddTriggers(function.Ens, Resolver); + TriggerGenerator.AddTriggers(function.Req, Resolver); + TriggerGenerator.AddTriggers(function.Body, Resolver); + } else if (decl is Method) { + var method = (Method)decl; + TriggerGenerator.AddTriggers(method.Ens, Resolver); + TriggerGenerator.AddTriggers(method.Req, Resolver); + TriggerGenerator.AddTriggers(method.Body, Resolver); + } + } + } + + public void PostCyclicityResolve(ModuleDefinition m) { } + } + /// /// AutoContracts is an experimental feature that will fill much of the dynamic-frames boilerplate /// into a class. From the user's perspective, what needs to be done is simply: -- cgit v1.2.3 From 8a0df70ffb8d57d1bd210ce2e1c9522ba0967365 Mon Sep 17 00:00:00 2001 From: Clément Pit--Claudel Date: Tue, 18 Aug 2015 18:58:40 -0700 Subject: Refactor the error reporting code The new error reporting system has a simpler interface, isn't tied to the resolver, and contains error source information. --- Source/Dafny/Cloner.cs | 33 +- Source/Dafny/Dafny.atg | 6 +- Source/Dafny/DafnyAst.cs | 20 +- Source/Dafny/DafnyMain.cs | 12 +- Source/Dafny/DafnyPipeline.csproj | 7 +- Source/Dafny/Parser.cs | 34 +- Source/Dafny/RefinementTransformer.cs | 293 ++++---- Source/Dafny/Reporting.cs | 164 +++++ Source/Dafny/Resolver.cs | 1146 +++++++++++++---------------- Source/Dafny/Rewriter.cs | 119 ++- Source/Dafny/Scanner.cs | 18 +- Source/Dafny/Translator.cs | 15 +- Source/Dafny/TriggerGenerator.cs | 4 +- Source/Dafny/Util.cs | 23 - Source/DafnyDriver/DafnyDriver.cs | 35 +- Source/DafnyExtension/DafnyDriver.cs | 77 +- Source/DafnyExtension/IdentifierTagger.cs | 4 +- Source/DafnyExtension/ResolverTagger.cs | 4 +- Source/DafnyServer/DafnyHelper.cs | 17 +- 19 files changed, 1006 insertions(+), 1025 deletions(-) create mode 100644 Source/Dafny/Reporting.cs (limited to 'Source/Dafny/DafnyPipeline.csproj') diff --git a/Source/Dafny/Cloner.cs b/Source/Dafny/Cloner.cs index f959b537..323abc70 100644 --- a/Source/Dafny/Cloner.cs +++ b/Source/Dafny/Cloner.cs @@ -365,6 +365,7 @@ namespace Microsoft.Dafny return new NamedExpr(Tok(e.tok), e.Name, CloneExpr(e.Body)); } else if (expr is ComprehensionExpr) { var e = (ComprehensionExpr)expr; + var tk = Tok(e.tok); var bvs = e.BoundVars.ConvertAll(CloneBoundVar); var range = CloneExpr(e.Range); @@ -703,22 +704,16 @@ namespace Microsoft.Dafny abstract class FixpointCloner : Cloner { protected readonly Expression k; - readonly Resolver resolver; + protected readonly ErrorReporter reporter; readonly string suffix; - protected FixpointCloner(Expression k, Resolver resolver) + protected FixpointCloner(Expression k, ErrorReporter reporter) { Contract.Requires(k != null); - Contract.Requires(resolver != null); + Contract.Requires(reporter != null); this.k = k; - this.resolver = resolver; + this.reporter = reporter; this.suffix = string.Format("#[{0}]", Printer.ExprToString(k)); } - protected void ReportAdditionalInformation(IToken tok, string s) - { - Contract.Requires(tok != null); - Contract.Requires(s != null); - resolver.ReportAdditionalInformation(tok, s + suffix, s.Length); - } } /// @@ -733,12 +728,12 @@ namespace Microsoft.Dafny { readonly bool isCoContext; readonly ISet friendlyCalls; - public FixpointLemmaSpecificationSubstituter(ISet friendlyCalls, Expression k, Resolver resolver, bool isCoContext) - : base(k, resolver) + public FixpointLemmaSpecificationSubstituter(ISet friendlyCalls, Expression k, ErrorReporter reporter, bool isCoContext) + : base(k, reporter) { Contract.Requires(friendlyCalls != null); Contract.Requires(k != null); - Contract.Requires(resolver != null); + Contract.Requires(reporter != null); this.isCoContext = isCoContext; this.friendlyCalls = friendlyCalls; } @@ -758,7 +753,7 @@ namespace Microsoft.Dafny args.Add(CloneExpr(arg)); } var fexp = new FunctionCallExpr(Tok(e.tok), e.Name + "#", receiver, e.OpenParen, args); - ReportAdditionalInformation(e.tok, e.Name); + reporter.Info(MessageSource.Cloner, e.tok, e.Name); return fexp; } } else if (expr is BinaryExpr && isCoContext) { @@ -769,7 +764,7 @@ namespace Microsoft.Dafny var B = CloneExpr(e.E1); var teq = new TernaryExpr(Tok(e.tok), op, k, A, B); var opString = op == TernaryExpr.Opcode.PrefixEqOp ? "==" : "!="; - ReportAdditionalInformation(e.tok, opString); + reporter.Info(MessageSource.Cloner, e.tok, opString); return teq; } } @@ -804,12 +799,12 @@ namespace Microsoft.Dafny class FixpointLemmaBodyCloner : FixpointCloner { readonly FixpointLemma context; - public FixpointLemmaBodyCloner(FixpointLemma context, Expression k, Resolver resolver) - : base(k, resolver) + public FixpointLemmaBodyCloner(FixpointLemma context, Expression k, ErrorReporter reporter) + : base(k, reporter) { Contract.Requires(context != null); Contract.Requires(k != null); - Contract.Requires(resolver != null); + Contract.Requires(reporter != null); this.context = context; } public override AssignmentRhs CloneRHS(AssignmentRhs rhs) { @@ -834,7 +829,7 @@ namespace Microsoft.Dafny apply.Args.ForEach(arg => args.Add(CloneExpr(arg))); var applyClone = new ApplySuffix(Tok(apply.tok), lhsClone, args); var c = new ExprRhs(applyClone); - ReportAdditionalInformation(apply.tok, mse.Member.Name); + reporter.Info(MessageSource.Cloner, apply.tok, mse.Member.Name); return c; } } diff --git a/Source/Dafny/Dafny.atg b/Source/Dafny/Dafny.atg index 8a3bdb0e..07f8e1c4 100644 --- a/Source/Dafny/Dafny.atg +++ b/Source/Dafny/Dafny.atg @@ -55,11 +55,11 @@ public static int Parse (string/*!*/ filename, ModuleDecl module, BuiltIns built /// Returns the number of parsing errors encountered. /// Note: first initialize the Scanner. /// -public static int Parse (string/*!*/ s, string/*!*/ fullFilename, string/*!*/ filename, ModuleDecl module, BuiltIns builtIns, bool verifyThisFile=true) { +public static int Parse (string/*!*/ s, string/*!*/ fullFilename, string/*!*/ filename, ModuleDecl module, BuiltIns builtIns, ErrorReporter reporter, bool verifyThisFile=true) { Contract.Requires(s != null); Contract.Requires(filename != null); Contract.Requires(module != null); - Errors errors = new Errors(); + Errors errors = new Errors(reporter); return Parse(s, fullFilename, filename, module, builtIns, errors, verifyThisFile); } /// @@ -79,7 +79,7 @@ public static int Parse (string/*!*/ s, string/*!*/ fullFilename, string/*!*/ fi Scanner scanner = new Scanner(ms, errors, fullFilename, filename); Parser parser = new Parser(scanner, errors, module, builtIns, verifyThisFile); parser.Parse(); - return parser.errors.count; + return parser.errors.ErrorCount; } public Parser(Scanner/*!*/ scanner, Errors/*!*/ errors, ModuleDecl module, BuiltIns builtIns, bool verifyThisFile=true) : this(scanner, errors) // the real work diff --git a/Source/Dafny/DafnyAst.cs b/Source/Dafny/DafnyAst.cs index 66b91ac2..efe94c66 100644 --- a/Source/Dafny/DafnyAst.cs +++ b/Source/Dafny/DafnyAst.cs @@ -27,20 +27,22 @@ namespace Microsoft.Dafny { public List CompileModules; // filled in during resolution. // Contains the definitions to be used for compilation. - List _additionalInformation = new List(); - public List AdditionalInformation { get { return _additionalInformation; } } public readonly ModuleDecl DefaultModule; public readonly ModuleDefinition DefaultModuleDef; public readonly BuiltIns BuiltIns; public readonly List TranslationTasks; - public Program(string name, [Captured] ModuleDecl module, [Captured] BuiltIns builtIns) { + public readonly ErrorReporter reporter; + + public Program(string name, [Captured] ModuleDecl module, [Captured] BuiltIns builtIns, ErrorReporter reporter) { Contract.Requires(name != null); Contract.Requires(module != null); Contract.Requires(module is LiteralModuleDecl); + Contract.Requires(reporter != null); FullName = name; DefaultModule = module; DefaultModuleDef = (DefaultModuleDecl)((LiteralModuleDecl)module).ModuleDef; BuiltIns = builtIns; + this.reporter = reporter; Modules = new List(); CompileModules = new List(); TranslationTasks = new List(); @@ -330,13 +332,13 @@ namespace Microsoft.Dafny { /// - if "allowed" contains Int and Args contains one BigInteger literal, return true and set value to the BigInteger literal. Otherwise, /// - if "allowed" contains String and Args contains one string literal, return true and set value to the string literal. Otherwise, /// - if "allowed" contains Expression and Args contains one element, return true and set value to the one element (of type Expression). Otherwise, - /// - return false, leave value unmodified, and call errorReporter with an error string. + /// - return false, leave value unmodified, and call reporter with an error string. /// public enum MatchingValueOption { Empty, Bool, Int, String, Expression } - public static bool ContainsMatchingValue(Attributes attrs, string nm, ref object value, IEnumerable allowed, Action errorReporter) { + public static bool ContainsMatchingValue(Attributes attrs, string nm, ref object value, IEnumerable allowed, Action reporter) { Contract.Requires(nm != null); Contract.Requires(allowed != null); - Contract.Requires(errorReporter != null); + Contract.Requires(reporter != null); List args = FindExpressions(attrs, nm); if (args == null) { return false; @@ -344,7 +346,7 @@ namespace Microsoft.Dafny { if (allowed.Contains(MatchingValueOption.Empty)) { return true; } else { - errorReporter("Attribute " + nm + " requires one argument"); + reporter("Attribute " + nm + " requires one argument"); return false; } } else if (args.Count == 1) { @@ -364,11 +366,11 @@ namespace Microsoft.Dafny { value = arg; return true; } else { - errorReporter("Attribute " + nm + " expects an argument in one of the following categories: " + String.Join(", ", allowed)); + reporter("Attribute " + nm + " expects an argument in one of the following categories: " + String.Join(", ", allowed)); return false; } } else { - errorReporter("Attribute " + nm + " cannot have more than one argument"); + reporter("Attribute " + nm + " cannot have more than one argument"); return false; } } diff --git a/Source/Dafny/DafnyMain.cs b/Source/Dafny/DafnyMain.cs index 012ca4df..251d8656 100644 --- a/Source/Dafny/DafnyMain.cs +++ b/Source/Dafny/DafnyMain.cs @@ -29,7 +29,7 @@ namespace Microsoft.Dafny { /// /// Returns null on success, or an error string otherwise. /// - public static string ParseCheck(IList/*!*/ fileNames, string/*!*/ programName, out Program program) + public static string ParseCheck(IList/*!*/ fileNames, string/*!*/ programName, ErrorReporter reporter, out Program program) //modifies Bpl.CommandLineOptions.Clo.XmlSink.*; { Contract.Requires(programName != null); @@ -47,20 +47,20 @@ namespace Microsoft.Dafny { Console.WriteLine("Parsing " + dafnyFileName); } - string err = ParseFile(dafnyFileName, Bpl.Token.NoToken, module, builtIns, new Errors()); + string err = ParseFile(dafnyFileName, Bpl.Token.NoToken, module, builtIns, new Errors(reporter)); if (err != null) { return err; } } if (!DafnyOptions.O.DisallowIncludes) { - string errString = ParseIncludes(module, builtIns, fileNames, new Errors()); + string errString = ParseIncludes(module, builtIns, fileNames, new Errors(reporter)); if (errString != null) { return errString; } } - program = new Program(programName, module, builtIns); + program = new Program(programName, module, builtIns, reporter); MaybePrintProgram(program, DafnyOptions.O.DafnyPrintFile); @@ -70,8 +70,8 @@ namespace Microsoft.Dafny { r.ResolveProgram(program); MaybePrintProgram(program, DafnyOptions.O.DafnyPrintResolvedFile); - if (r.ErrorCount != 0) { - return string.Format("{0} resolution/type errors detected in {1}", r.ErrorCount, program.Name); + if (reporter.Count(ErrorLevel.Error) != 0) { + return string.Format("{0} resolution/type errors detected in {1}", reporter.Count(ErrorLevel.Error), program.Name); } return null; // success diff --git a/Source/Dafny/DafnyPipeline.csproj b/Source/Dafny/DafnyPipeline.csproj index a1452b8a..626bb26a 100644 --- a/Source/Dafny/DafnyPipeline.csproj +++ b/Source/Dafny/DafnyPipeline.csproj @@ -1,4 +1,4 @@ - + Debug @@ -8,7 +8,7 @@ {FE44674A-1633-4917-99F4-57635E6FA740} Library Properties - DafnyPipeline + Microsoft.Dafny DafnyPipeline v4.0 512 @@ -143,6 +143,7 @@ + @@ -193,4 +194,4 @@ --> - \ No newline at end of file + diff --git a/Source/Dafny/Parser.cs b/Source/Dafny/Parser.cs index fd6fb026..2507cacc 100644 --- a/Source/Dafny/Parser.cs +++ b/Source/Dafny/Parser.cs @@ -126,11 +126,11 @@ public static int Parse (string/*!*/ filename, ModuleDecl module, BuiltIns built /// Returns the number of parsing errors encountered. /// Note: first initialize the Scanner. /// -public static int Parse (string/*!*/ s, string/*!*/ fullFilename, string/*!*/ filename, ModuleDecl module, BuiltIns builtIns, bool verifyThisFile=true) { +public static int Parse (string/*!*/ s, string/*!*/ fullFilename, string/*!*/ filename, ModuleDecl module, BuiltIns builtIns, ErrorReporter reporter, bool verifyThisFile=true) { Contract.Requires(s != null); Contract.Requires(filename != null); Contract.Requires(module != null); - Errors errors = new Errors(); + Errors errors = new Errors(reporter); return Parse(s, fullFilename, filename, module, builtIns, errors, verifyThisFile); } /// @@ -150,7 +150,7 @@ public static int Parse (string/*!*/ s, string/*!*/ fullFilename, string/*!*/ fi Scanner scanner = new Scanner(ms, errors, fullFilename, filename); Parser parser = new Parser(scanner, errors, module, builtIns, verifyThisFile); parser.Parse(); - return parser.errors.count; + return parser.errors.ErrorCount; } public Parser(Scanner/*!*/ scanner, Errors/*!*/ errors, ModuleDecl module, BuiltIns builtIns, bool verifyThisFile=true) : this(scanner, errors) // the real work @@ -4426,16 +4426,22 @@ List/*!*/ decreases, ref Attributes decAttrs, ref Attributes mo public class Errors { - public int count = 0; // number of errors detected + readonly ErrorReporter reporter; + public int ErrorCount; + + public Errors(ErrorReporter reporter) { + Contract.Requires(reporter != null); + this.reporter = reporter; + } public void SynErr(string filename, int line, int col, int n) { SynErr(filename, line, col, GetSyntaxErrorString(n)); } - public virtual void SynErr(string filename, int line, int col, string msg) { + public void SynErr(string filename, int line, int col, string msg) { Contract.Requires(msg != null); - Dafny.Util.ReportIssue("Error", filename, line, col, msg); - count++; + ErrorCount++; + reporter.Error(MessageSource.Parser, filename, line, col, msg); } string GetSyntaxErrorString(int n) { @@ -4692,20 +4698,20 @@ public class Errors { public void SemErr(IToken tok, string msg) { // semantic errors Contract.Requires(tok != null); Contract.Requires(msg != null); - Dafny.Util.ReportIssue("Error", tok, msg); - count++; + ErrorCount++; + reporter.Error(MessageSource.Parser, tok, msg); } - public virtual void SemErr(string filename, int line, int col, string msg) { + public void SemErr(string filename, int line, int col, string msg) { Contract.Requires(msg != null); - Dafny.Util.ReportIssue("Error", filename, line, col, msg); - count++; + ErrorCount++; + reporter.Error(MessageSource.Parser, filename, line, col, msg); } - public virtual void Warning(IToken tok, string msg) { // warnings + public void Warning(IToken tok, string msg) { Contract.Requires(tok != null); Contract.Requires(msg != null); - Dafny.Util.ReportIssue("Warning", tok, msg); + reporter.Warning(MessageSource.Parser, tok, msg); } } // Errors diff --git a/Source/Dafny/RefinementTransformer.cs b/Source/Dafny/RefinementTransformer.cs index f430933b..ba558ea6 100644 --- a/Source/Dafny/RefinementTransformer.cs +++ b/Source/Dafny/RefinementTransformer.cs @@ -52,16 +52,19 @@ namespace Microsoft.Dafny public class RefinementTransformer : IRewriter { - ResolutionErrorReporter reporter; - Action additionalInformationReporter; Cloner rawCloner; // This cloner just gives exactly the same thing back. RefinementCloner refinementCloner; // This cloner wraps things in a RefinementTransformer + Program program; - public RefinementTransformer(ResolutionErrorReporter reporter, Action additionalInformationReporter, Program p) { - Contract.Requires(reporter != null); - this.reporter = reporter; - this.additionalInformationReporter = additionalInformationReporter; + + public RefinementTransformer(ErrorReporter reporter) + : base(reporter) { rawCloner = new Cloner(); + } + + public RefinementTransformer(Program p) + : this(p.reporter) { + Contract.Requires(p != null); program = p; } @@ -71,17 +74,7 @@ namespace Microsoft.Dafny private Method currentMethod; public ModuleSignature RefinedSig; // the intention is to use this field only after a successful PreResolve - void ReportAdditionalInformation(IToken token, string text, int length) - { - Contract.Requires(token != null); - Contract.Requires(text != null); - Contract.Requires(0 <= length); - if (additionalInformationReporter != null) { - additionalInformationReporter(new AdditionalInformation { Token = token, Text = text, Length = length }); - } - } - - public void PreResolve(ModuleDefinition m) { + internal override void PreResolve(ModuleDefinition m) { if (m.RefinementBaseRoot != null) { if (Resolver.ResolvePath(m.RefinementBaseRoot, m.RefinementBaseName, out RefinedSig, reporter)) { if (RefinedSig.ModuleDef != null) { @@ -90,17 +83,17 @@ namespace Microsoft.Dafny if (null == m.RefinementBase.ExclusiveRefinement) { m.RefinementBase.ExclusiveRefinement = m; } else { - this.reporter.Error( + reporter.Error(MessageSource.RefinementTransformer, m.tok, "no more than one exclusive refinement may exist for a given module."); } } PreResolveWorker(m); } else { - reporter.Error(m.RefinementBaseName[0], "module ({0}) named as refinement base is not a literal module or simple reference to a literal module", Util.Comma(".", m.RefinementBaseName, x => x.val)); + reporter.Error(MessageSource.RefinementTransformer, m.RefinementBaseName[0], "module ({0}) named as refinement base is not a literal module or simple reference to a literal module", Util.Comma(".", m.RefinementBaseName, x => x.val)); } } else { - reporter.Error(m.RefinementBaseName[0], "module ({0}) named as refinement base does not exist", Util.Comma(".", m.RefinementBaseName, x => x.val)); + reporter.Error(MessageSource.RefinementTransformer, m.RefinementBaseName[0], "module ({0}) named as refinement base does not exist", Util.Comma(".", m.RefinementBaseName, x => x.val)); } } } @@ -135,9 +128,9 @@ namespace Microsoft.Dafny var nw = m.TopLevelDecls[index]; if (d is ModuleDecl) { if (!(nw is ModuleDecl)) { - reporter.Error(nw, "a module ({0}) must refine another module", nw.Name); + reporter.Error(MessageSource.RefinementTransformer, nw, "a module ({0}) must refine another module", nw.Name); } else if (!(d is ModuleFacadeDecl)) { - reporter.Error(nw, "a module ({0}) can only refine a module facade", nw.Name); + reporter.Error(MessageSource.RefinementTransformer, nw, "a module ({0}) can only refine a module facade", nw.Name); } else { ModuleSignature original = ((ModuleFacadeDecl)d).OriginalSignature; ModuleSignature derived = null; @@ -146,72 +139,72 @@ namespace Microsoft.Dafny } else if (nw is ModuleFacadeDecl) { derived = ((ModuleFacadeDecl)nw).Signature; } else { - reporter.Error(nw, "a module ({0}) can only be refined by an alias module or a module facade", d.Name); + reporter.Error(MessageSource.RefinementTransformer, nw, "a module ({0}) can only be refined by an alias module or a module facade", d.Name); } if (derived != null) { // check that the new module refines the previous declaration if (!CheckIsRefinement(derived, original)) - reporter.Error(nw.tok, "a module ({0}) can only be replaced by a refinement of the original module", d.Name); + reporter.Error(MessageSource.RefinementTransformer, nw.tok, "a module ({0}) can only be replaced by a refinement of the original module", d.Name); } } } else if (d is OpaqueTypeDecl) { if (nw is ModuleDecl) { - reporter.Error(nw, "a module ({0}) must refine another module", nw.Name); + reporter.Error(MessageSource.RefinementTransformer, nw, "a module ({0}) must refine another module", nw.Name); } else { bool dDemandsEqualitySupport = ((OpaqueTypeDecl)d).MustSupportEquality; if (nw is OpaqueTypeDecl) { if (dDemandsEqualitySupport != ((OpaqueTypeDecl)nw).MustSupportEquality) { - reporter.Error(nw, "type declaration '{0}' is not allowed to change the requirement of supporting equality", nw.Name); + reporter.Error(MessageSource.RefinementTransformer, nw, "type declaration '{0}' is not allowed to change the requirement of supporting equality", nw.Name); } if (nw.TypeArgs.Count != d.TypeArgs.Count) { - reporter.Error(nw, "type '{0}' is not allowed to change its number of type parameters (got {1}, expected {2})", nw.Name, nw.TypeArgs.Count, d.TypeArgs.Count); + reporter.Error(MessageSource.RefinementTransformer, nw, "type '{0}' is not allowed to change its number of type parameters (got {1}, expected {2})", nw.Name, nw.TypeArgs.Count, d.TypeArgs.Count); } } else if (dDemandsEqualitySupport) { if (nw is ClassDecl) { // fine, as long as "nw" takes the right number of type parameters if (nw.TypeArgs.Count != d.TypeArgs.Count) { - reporter.Error(nw, "opaque type '{0}' is not allowed to be replaced by a class that takes a different number of type parameters (got {1}, expected {2})", nw.Name, nw.TypeArgs.Count, d.TypeArgs.Count); + reporter.Error(MessageSource.RefinementTransformer, nw, "opaque type '{0}' is not allowed to be replaced by a class that takes a different number of type parameters (got {1}, expected {2})", nw.Name, nw.TypeArgs.Count, d.TypeArgs.Count); } } else if (nw is NewtypeDecl) { // fine, as long as "nw" does not take any type parameters if (nw.TypeArgs.Count != 0) { - reporter.Error(nw, "opaque type '{0}', which has {1} type argument{2}, is not allowed to be replaced by a newtype, which takes none", nw.Name, d.TypeArgs.Count, d.TypeArgs.Count == 1 ? "" : "s"); + reporter.Error(MessageSource.RefinementTransformer, nw, "opaque type '{0}', which has {1} type argument{2}, is not allowed to be replaced by a newtype, which takes none", nw.Name, d.TypeArgs.Count, d.TypeArgs.Count == 1 ? "" : "s"); } } else if (nw is CoDatatypeDecl) { - reporter.Error(nw, "a type declaration that requires equality support cannot be replaced by a codatatype"); + reporter.Error(MessageSource.RefinementTransformer, nw, "a type declaration that requires equality support cannot be replaced by a codatatype"); } else { Contract.Assert(nw is IndDatatypeDecl || nw is TypeSynonymDecl); if (nw.TypeArgs.Count != d.TypeArgs.Count) { - reporter.Error(nw, "opaque type '{0}' is not allowed to be replaced by a type that takes a different number of type parameters (got {1}, expected {2})", nw.Name, nw.TypeArgs.Count, d.TypeArgs.Count); + reporter.Error(MessageSource.RefinementTransformer, nw, "opaque type '{0}' is not allowed to be replaced by a type that takes a different number of type parameters (got {1}, expected {2})", nw.Name, nw.TypeArgs.Count, d.TypeArgs.Count); } else { // Here, we need to figure out if the new type supports equality. But we won't know about that until resolution has // taken place, so we defer it until the PostResolve phase. var udt = UserDefinedType.FromTopLevelDecl(nw.tok, nw); postTasks.Enqueue(() => { if (!udt.SupportsEquality) { - reporter.Error(udt.tok, "type '{0}' is used to refine an opaque type with equality support, but '{0}' does not support equality", udt.Name); + reporter.Error(MessageSource.RefinementTransformer, udt.tok, "type '{0}' is used to refine an opaque type with equality support, but '{0}' does not support equality", udt.Name); } }); } } } else if (d.TypeArgs.Count != nw.TypeArgs.Count) { - reporter.Error(nw, "opaque type '{0}' is not allowed to be replaced by a type that takes a different number of type parameters (got {1}, expected {2})", nw.Name, nw.TypeArgs.Count, d.TypeArgs.Count); + reporter.Error(MessageSource.RefinementTransformer, nw, "opaque type '{0}' is not allowed to be replaced by a type that takes a different number of type parameters (got {1}, expected {2})", nw.Name, nw.TypeArgs.Count, d.TypeArgs.Count); } } } else if (nw is OpaqueTypeDecl) { - reporter.Error(nw, "an opaque type declaration ({0}) in a refining module cannot replace a more specific type declaration in the refinement base", nw.Name); + reporter.Error(MessageSource.RefinementTransformer, nw, "an opaque type declaration ({0}) in a refining module cannot replace a more specific type declaration in the refinement base", nw.Name); } else if (nw is DatatypeDecl) { - reporter.Error(nw, "a datatype declaration ({0}) in a refinement module can only replace an opaque type declaration", nw.Name); + reporter.Error(MessageSource.RefinementTransformer, nw, "a datatype declaration ({0}) in a refinement module can only replace an opaque type declaration", nw.Name); } else if (nw is IteratorDecl) { if (d is IteratorDecl) { m.TopLevelDecls[index] = MergeIterator((IteratorDecl)nw, (IteratorDecl)d); } else { - reporter.Error(nw, "an iterator declaration ({0}) is a refining module cannot replace a different kind of declaration in the refinement base", nw.Name); + reporter.Error(MessageSource.RefinementTransformer, nw, "an iterator declaration ({0}) is a refining module cannot replace a different kind of declaration in the refinement base", nw.Name); } } else { Contract.Assert(nw is ClassDecl); if (d is DatatypeDecl) { - reporter.Error(nw, "a class declaration ({0}) in a refining module cannot replace a different kind of declaration in the refinement base", nw.Name); + reporter.Error(MessageSource.RefinementTransformer, nw, "a class declaration ({0}) in a refining module cannot replace a different kind of declaration in the refinement base", nw.Name); } else { m.TopLevelDecls[index] = MergeClass((ClassDecl)nw, (ClassDecl)d); } @@ -238,42 +231,42 @@ namespace Microsoft.Dafny // Second, we need to determine whether the specifications will be compatible // (i.e. substitutable), by translating to Boogie. - var errorCount = reporter.ErrorCount; + var errorCount = reporter.Count(ErrorLevel.Error); foreach (var kv in original.TopLevels) { var d = kv.Value; TopLevelDecl nw; if (derived.TopLevels.TryGetValue(kv.Key, out nw)) { if (d is ModuleDecl) { if (!(nw is ModuleDecl)) { - reporter.Error(nw, "a module ({0}) must refine another module", nw.Name); + reporter.Error(MessageSource.RefinementTransformer, nw, "a module ({0}) must refine another module", nw.Name); } else { CheckIsRefinement(((ModuleDecl)nw).Signature, ((ModuleDecl)d).Signature); } } else if (d is OpaqueTypeDecl) { if (nw is ModuleDecl) { - reporter.Error(nw, "a module ({0}) must refine another module", nw.Name); + reporter.Error(MessageSource.RefinementTransformer, nw, "a module ({0}) must refine another module", nw.Name); } else { bool dDemandsEqualitySupport = ((OpaqueTypeDecl)d).MustSupportEquality; if (nw is OpaqueTypeDecl) { if (dDemandsEqualitySupport != ((OpaqueTypeDecl)nw).MustSupportEquality) { - reporter.Error(nw, "type declaration '{0}' is not allowed to change the requirement of supporting equality", nw.Name); + reporter.Error(MessageSource.RefinementTransformer, nw, "type declaration '{0}' is not allowed to change the requirement of supporting equality", nw.Name); } } else if (dDemandsEqualitySupport) { if (nw is ClassDecl) { // fine, as long as "nw" does not take any type parameters if (nw.TypeArgs.Count != 0) { - reporter.Error(nw, "opaque type '{0}' is not allowed to be replaced by a class that takes type parameters", nw.Name); + reporter.Error(MessageSource.RefinementTransformer, nw, "opaque type '{0}' is not allowed to be replaced by a class that takes type parameters", nw.Name); } } else if (nw is CoDatatypeDecl) { - reporter.Error(nw, "a type declaration that requires equality support cannot be replaced by a codatatype"); + reporter.Error(MessageSource.RefinementTransformer, nw, "a type declaration that requires equality support cannot be replaced by a codatatype"); } else { Contract.Assert(nw is IndDatatypeDecl); if (nw.TypeArgs.Count != 0) { - reporter.Error(nw, "opaque type '{0}' is not allowed to be replaced by a datatype that takes type parameters", nw.Name); + reporter.Error(MessageSource.RefinementTransformer, nw, "opaque type '{0}' is not allowed to be replaced by a datatype that takes type parameters", nw.Name); } else { var udt = new UserDefinedType(nw.tok, nw.Name, nw, new List()); if (!(udt.SupportsEquality)) { - reporter.Error(nw.tok, "datatype '{0}' is used to refine an opaque type with equality support, but '{0}' does not support equality", nw.Name); + reporter.Error(MessageSource.RefinementTransformer, nw.tok, "datatype '{0}' is used to refine an opaque type with equality support, but '{0}' does not support equality", nw.Name); } } } @@ -282,18 +275,18 @@ namespace Microsoft.Dafny } else if (d is DatatypeDecl) { if (nw is DatatypeDecl) { if (d is IndDatatypeDecl && !(nw is IndDatatypeDecl)) { - reporter.Error(nw, "a datatype ({0}) must be replaced by a datatype, not a codatatype", d.Name); + reporter.Error(MessageSource.RefinementTransformer, nw, "a datatype ({0}) must be replaced by a datatype, not a codatatype", d.Name); } else if (d is CoDatatypeDecl && !(nw is CoDatatypeDecl)) { - reporter.Error(nw, "a codatatype ({0}) must be replaced by a codatatype, not a datatype", d.Name); + reporter.Error(MessageSource.RefinementTransformer, nw, "a codatatype ({0}) must be replaced by a codatatype, not a datatype", d.Name); } // check constructors, formals, etc. CheckDatatypesAreRefinements((DatatypeDecl)d, (DatatypeDecl)nw); } else { - reporter.Error(nw, "a {0} ({1}) must be refined by a {0}", d is IndDatatypeDecl ? "datatype" : "codatatype", d.Name); + reporter.Error(MessageSource.RefinementTransformer, nw, "a {0} ({1}) must be refined by a {0}", d is IndDatatypeDecl ? "datatype" : "codatatype", d.Name); } } else if (d is ClassDecl) { if (!(nw is ClassDecl)) { - reporter.Error(nw, "a class declaration ({0}) must be refined by another class declaration", nw.Name); + reporter.Error(MessageSource.RefinementTransformer, nw, "a class declaration ({0}) must be refined by another class declaration", nw.Name); } else { CheckClassesAreRefinements((ClassDecl)nw, (ClassDecl)d); } @@ -301,15 +294,15 @@ namespace Microsoft.Dafny Contract.Assert(false); throw new cce.UnreachableException(); // unexpected toplevel } } else { - reporter.Error(d, "declaration {0} must have a matching declaration in the refining module", d.Name); + reporter.Error(MessageSource.RefinementTransformer, d, "declaration {0} must have a matching declaration in the refining module", d.Name); } } - return errorCount == reporter.ErrorCount; + return errorCount == reporter.Count(ErrorLevel.Error); } private void CheckClassesAreRefinements(ClassDecl nw, ClassDecl d) { if (nw.TypeArgs.Count != d.TypeArgs.Count) { - reporter.Error(nw, "a refining class ({0}) must have the same number of type parameters", nw.Name); + reporter.Error(MessageSource.RefinementTransformer, nw, "a refining class ({0}) must have the same number of type parameters", nw.Name); } else { var map = new Dictionary(); foreach (var mem in nw.Members) { @@ -319,33 +312,33 @@ namespace Microsoft.Dafny MemberDecl newMem; if (map.TryGetValue(m.Name, out newMem)) { if (m.HasStaticKeyword != newMem.HasStaticKeyword) { - reporter.Error(newMem, "member {0} must {1}", m.Name, m.HasStaticKeyword ? "be static" : "not be static"); + reporter.Error(MessageSource.RefinementTransformer, newMem, "member {0} must {1}", m.Name, m.HasStaticKeyword ? "be static" : "not be static"); } if (m is Field) { if (newMem is Field) { var newField = (Field)newMem; if (!ResolvedTypesAreTheSame(newField.Type, ((Field)m).Type)) - reporter.Error(newMem, "field must be refined by a field with the same type (got {0}, expected {1})", newField.Type, ((Field)m).Type); + reporter.Error(MessageSource.RefinementTransformer, newMem, "field must be refined by a field with the same type (got {0}, expected {1})", newField.Type, ((Field)m).Type); if (m.IsGhost || !newField.IsGhost) - reporter.Error(newField, "a field re-declaration ({0}) must be to ghostify the field", newField.Name, nw.Name); + reporter.Error(MessageSource.RefinementTransformer, newField, "a field re-declaration ({0}) must be to ghostify the field", newField.Name, nw.Name); } else { - reporter.Error(newMem, "a field declaration ({1}) must be replaced by a field in the refinement base (not {0})", newMem.Name, nw.Name); + reporter.Error(MessageSource.RefinementTransformer, newMem, "a field declaration ({1}) must be replaced by a field in the refinement base (not {0})", newMem.Name, nw.Name); } } else if (m is Method) { if (newMem is Method) { CheckMethodsAreRefinements((Method)newMem, (Method)m); } else { - reporter.Error(newMem, "method must be refined by a method"); + reporter.Error(MessageSource.RefinementTransformer, newMem, "method must be refined by a method"); } } else if (m is Function) { if (newMem is Function) { CheckFunctionsAreRefinements((Function)newMem, (Function)m); } else { - reporter.Error(newMem, "{0} must be refined by a {0}", m.WhatKind); + reporter.Error(MessageSource.RefinementTransformer, newMem, "{0} must be refined by a {0}", m.WhatKind); } } } else { - reporter.Error(nw is DefaultClassDecl ? nw.Module.tok : nw.tok, "refining {0} must have member {1}", nw is DefaultClassDecl ? "module" : "class", m.Name); + reporter.Error(MessageSource.RefinementTransformer, nw is DefaultClassDecl ? nw.Module.tok : nw.tok, "refining {0} must have member {1}", nw is DefaultClassDecl ? "module" : "class", m.Name); } } } @@ -358,17 +351,17 @@ namespace Microsoft.Dafny Contract.Requires(thing != null); Contract.Requires(parameterKind != null); if (old.Count != nw.Count) { - reporter.Error(tok, "{0} '{1}' is declared with a different number of {2} ({3} instead of {4}) than the corresponding {0} in the module it refines", thing, name, parameterKind, nw.Count, old.Count); + reporter.Error(MessageSource.RefinementTransformer, tok, "{0} '{1}' is declared with a different number of {2} ({3} instead of {4}) than the corresponding {0} in the module it refines", thing, name, parameterKind, nw.Count, old.Count); } else { for (int i = 0; i < old.Count; i++) { var o = old[i]; var n = nw[i]; if (!o.IsGhost && n.IsGhost) { - reporter.Error(n.tok, "{0} '{1}' of {2} {3} cannot be changed, compared to the corresponding {2} in the module it refines, from non-ghost to ghost", parameterKind, n.Name, thing, name); + reporter.Error(MessageSource.RefinementTransformer, n.tok, "{0} '{1}' of {2} {3} cannot be changed, compared to the corresponding {2} in the module it refines, from non-ghost to ghost", parameterKind, n.Name, thing, name); } else if (o.IsGhost && !n.IsGhost) { - reporter.Error(n.tok, "{0} '{1}' of {2} {3} cannot be changed, compared to the corresponding {2} in the module it refines, from ghost to non-ghost", parameterKind, n.Name, thing, name); + reporter.Error(MessageSource.RefinementTransformer, n.tok, "{0} '{1}' of {2} {3} cannot be changed, compared to the corresponding {2} in the module it refines, from ghost to non-ghost", parameterKind, n.Name, thing, name); } else if (!ResolvedTypesAreTheSame(o.Type, n.Type)) { - reporter.Error(n.tok, "the type of {0} '{1}' is different from the type of the same {0} in the corresponding {2} in the module it refines ('{3}' instead of '{4}')", parameterKind, n.Name, thing, n.Type, o.Type); + reporter.Error(MessageSource.RefinementTransformer, n.tok, "the type of {0} '{1}' is different from the type of the same {0} in the corresponding {2} in the module it refines ('{3}' instead of '{4}')", parameterKind, n.Name, thing, n.Type, o.Type); } } } @@ -382,22 +375,22 @@ namespace Microsoft.Dafny private void CheckFunctionsAreRefinements(Function nw, Function f) { if (f is Predicate) { if (!(nw is Predicate)) { - reporter.Error(nw, "a predicate declaration ({0}) can only be refined by a predicate", nw.Name); + reporter.Error(MessageSource.RefinementTransformer, nw, "a predicate declaration ({0}) can only be refined by a predicate", nw.Name); } else { CheckAgreement_TypeParameters(nw.tok, f.TypeArgs, nw.TypeArgs, nw.Name, "predicate", false); CheckAgreementResolvedParameters(nw.tok, f.Formals, nw.Formals, nw.Name, "predicate", "parameter"); } } else if (f is FixpointPredicate) { - reporter.Error(nw, "refinement of {0}s is not supported", f.WhatKind); + reporter.Error(MessageSource.RefinementTransformer, nw, "refinement of {0}s is not supported", f.WhatKind); } else { // f is a plain Function if (nw is Predicate || nw is FixpointPredicate) { - reporter.Error(nw, "a {0} declaration ({1}) can only be refined by a function or function method", nw.IsGhost ? "function" : "function method", nw.Name); + reporter.Error(MessageSource.RefinementTransformer, nw, "a {0} declaration ({1}) can only be refined by a function or function method", nw.IsGhost ? "function" : "function method", nw.Name); } else { CheckAgreement_TypeParameters(nw.tok, f.TypeArgs, nw.TypeArgs, nw.Name, "function", false); CheckAgreementResolvedParameters(nw.tok, f.Formals, nw.Formals, nw.Name, "function", "parameter"); if (!ResolvedTypesAreTheSame(nw.ResultType, f.ResultType)) { - reporter.Error(nw, "the result type of function '{0}' ({1}) differs from the result type of the corresponding function in the module it refines ({2})", nw.Name, nw.ResultType, f.ResultType); + reporter.Error(MessageSource.RefinementTransformer, nw, "the result type of function '{0}' ({1}) differs from the result type of the corresponding function in the module it refines ({2})", nw.Name, nw.ResultType, f.ResultType); } } } @@ -408,7 +401,7 @@ namespace Microsoft.Dafny private void CheckDatatypesAreRefinements(DatatypeDecl dd, DatatypeDecl nn) { CheckAgreement_TypeParameters(nn.tok, dd.TypeArgs, nn.TypeArgs, dd.Name, "datatype", false); if (dd.Ctors.Count != nn.Ctors.Count) { - reporter.Error(nn.tok, "a refining datatype must have the same number of constructors"); + reporter.Error(MessageSource.RefinementTransformer, nn.tok, "a refining datatype must have the same number of constructors"); } else { var map = new Dictionary(); foreach (var ctor in nn.Ctors) { @@ -418,21 +411,21 @@ namespace Microsoft.Dafny DatatypeCtor newCtor; if (map.TryGetValue(ctor.Name, out newCtor)) { if (newCtor.Formals.Count != ctor.Formals.Count) { - reporter.Error(newCtor, "the constructor ({0}) must have the same number of formals as in the refined module", newCtor.Name); + reporter.Error(MessageSource.RefinementTransformer, newCtor, "the constructor ({0}) must have the same number of formals as in the refined module", newCtor.Name); } else { for (int i = 0; i < newCtor.Formals.Count; i++) { var a = ctor.Formals[i]; var b = newCtor.Formals[i]; if (a.HasName) { if (!b.HasName || a.Name != b.Name) - reporter.Error(b, "formal argument {0} in constructor {1} does not have the same name as in the refined module (should be {2})", i, ctor.Name, a.Name); + reporter.Error(MessageSource.RefinementTransformer, b, "formal argument {0} in constructor {1} does not have the same name as in the refined module (should be {2})", i, ctor.Name, a.Name); } if (!ResolvedTypesAreTheSame(a.Type, b.Type)) { - reporter.Error(b, "formal argument {0} in constructor {1} does not have the same type as in the refined module (should be {2}, not {3})", i, ctor.Name, a.Type.ToString(), b.Type.ToString()); + reporter.Error(MessageSource.RefinementTransformer, b, "formal argument {0} in constructor {1} does not have the same type as in the refined module (should be {2}, not {3})", i, ctor.Name, a.Type.ToString(), b.Type.ToString()); } } } } else { - reporter.Error(nn, "the constructor {0} must be present in the refining datatype", ctor.Name); + reporter.Error(MessageSource.RefinementTransformer, nn, "the constructor {0} must be present in the refining datatype", ctor.Name); } } } @@ -501,7 +494,8 @@ namespace Microsoft.Dafny Contract.Assert(false); throw new cce.UnreachableException(); // unexpected type } } - public void PostResolve(ModuleDefinition m) { + + internal override void PostResolve(ModuleDefinition m) { if (m == moduleUnderConstruction) { while (this.postTasks.Count != 0) { var a = postTasks.Dequeue(); @@ -512,8 +506,7 @@ namespace Microsoft.Dafny } moduleUnderConstruction = null; } - public void PostCyclicityResolve(ModuleDefinition m) { - } + Function CloneFunction(IToken tok, Function f, bool isGhost, List moreEnsures, Expression moreBody, Expression replacementBody, bool checkPrevPostconditions, Attributes moreAttributes) { Contract.Requires(tok != null); Contract.Requires(moreBody == null || f is Predicate); @@ -611,26 +604,26 @@ namespace Microsoft.Dafny Contract.Requires(prev != null); if (nw.Requires.Count != 0) { - reporter.Error(nw.Requires[0].E.tok, "a refining iterator is not allowed to add preconditions"); + reporter.Error(MessageSource.RefinementTransformer, nw.Requires[0].E.tok, "a refining iterator is not allowed to add preconditions"); } if (nw.YieldRequires.Count != 0) { - reporter.Error(nw.YieldRequires[0].E.tok, "a refining iterator is not allowed to add yield preconditions"); + reporter.Error(MessageSource.RefinementTransformer, nw.YieldRequires[0].E.tok, "a refining iterator is not allowed to add yield preconditions"); } if (nw.Reads.Expressions.Count != 0) { - reporter.Error(nw.Reads.Expressions[0].E.tok, "a refining iterator is not allowed to extend the reads clause"); + reporter.Error(MessageSource.RefinementTransformer, nw.Reads.Expressions[0].E.tok, "a refining iterator is not allowed to extend the reads clause"); } if (nw.Modifies.Expressions.Count != 0) { - reporter.Error(nw.Modifies.Expressions[0].E.tok, "a refining iterator is not allowed to extend the modifies clause"); + reporter.Error(MessageSource.RefinementTransformer, nw.Modifies.Expressions[0].E.tok, "a refining iterator is not allowed to extend the modifies clause"); } if (nw.Decreases.Expressions.Count != 0) { - reporter.Error(nw.Decreases.Expressions[0].tok, "a refining iterator is not allowed to extend the decreases clause"); + reporter.Error(MessageSource.RefinementTransformer, nw.Decreases.Expressions[0].tok, "a refining iterator is not allowed to extend the decreases clause"); } if (nw.SignatureIsOmitted) { Contract.Assert(nw.TypeArgs.Count == 0); Contract.Assert(nw.Ins.Count == 0); Contract.Assert(nw.Outs.Count == 0); - ReportAdditionalInformation(nw.SignatureEllipsis, Printer.IteratorSignatureToString(prev), 3); + reporter.Info(MessageSource.RefinementTransformer, nw.SignatureEllipsis, Printer.IteratorSignatureToString(prev)); } else { CheckAgreement_TypeParameters(nw.tok, prev.TypeArgs, nw.TypeArgs, nw.Name, "iterator"); CheckAgreement_Parameters(nw.tok, prev.Ins, nw.Ins, nw.Name, "iterator", "in-parameter"); @@ -694,9 +687,9 @@ namespace Microsoft.Dafny if (nwMember is Field) { if (member is Field && TypesAreSyntacticallyEqual(((Field)nwMember).Type, ((Field)member).Type)) { if (member.IsGhost || !nwMember.IsGhost) - reporter.Error(nwMember, "a field re-declaration ({0}) must be to ghostify the field", nwMember.Name, nw.Name); + reporter.Error(MessageSource.RefinementTransformer, nwMember, "a field re-declaration ({0}) must be to ghostify the field", nwMember.Name, nw.Name); } else { - reporter.Error(nwMember, "a field declaration ({0}) in a refining class ({1}) must replace a field in the refinement base", nwMember.Name, nw.Name); + reporter.Error(MessageSource.RefinementTransformer, nwMember, "a field declaration ({0}) in a refining class ({1}) must replace a field in the refinement base", nwMember.Name, nw.Name); } nwMember.RefinementBase = member; @@ -709,38 +702,38 @@ namespace Microsoft.Dafny (isPredicate && !(member is Predicate)) || (isIndPredicate && !(member is InductivePredicate)) || (isCoPredicate && !(member is CoPredicate))) { - reporter.Error(nwMember, "a {0} declaration ({1}) can only refine a {0}", f.WhatKind, nwMember.Name); + reporter.Error(MessageSource.RefinementTransformer, nwMember, "a {0} declaration ({1}) can only refine a {0}", f.WhatKind, nwMember.Name); } else if (f.IsProtected != ((Function)member).IsProtected) { - reporter.Error(f, "a {0} in a refinement module must be declared 'protected' if and only if the refined {0} is", f.WhatKind); + reporter.Error(MessageSource.RefinementTransformer, f, "a {0} in a refinement module must be declared 'protected' if and only if the refined {0} is", f.WhatKind); } else { var prevFunction = (Function)member; if (f.Req.Count != 0) { - reporter.Error(f.Req[0].tok, "a refining {0} is not allowed to add preconditions", f.WhatKind); + reporter.Error(MessageSource.RefinementTransformer, f.Req[0].tok, "a refining {0} is not allowed to add preconditions", f.WhatKind); } if (f.Reads.Count != 0) { - reporter.Error(f.Reads[0].E.tok, "a refining {0} is not allowed to extend the reads clause", f.WhatKind); + reporter.Error(MessageSource.RefinementTransformer, f.Reads[0].E.tok, "a refining {0} is not allowed to extend the reads clause", f.WhatKind); } if (f.Decreases.Expressions.Count != 0) { - reporter.Error(f.Decreases.Expressions[0].tok, "decreases clause on refining {0} not supported", f.WhatKind); + reporter.Error(MessageSource.RefinementTransformer, f.Decreases.Expressions[0].tok, "decreases clause on refining {0} not supported", f.WhatKind); } if (prevFunction.HasStaticKeyword != f.HasStaticKeyword) { - reporter.Error(f, "a function in a refining module cannot be changed from static to non-static or vice versa: {0}", f.Name); + reporter.Error(MessageSource.RefinementTransformer, f, "a function in a refining module cannot be changed from static to non-static or vice versa: {0}", f.Name); } if (!prevFunction.IsGhost && f.IsGhost) { - reporter.Error(f, "a function method cannot be changed into a (ghost) function in a refining module: {0}", f.Name); + reporter.Error(MessageSource.RefinementTransformer, f, "a function method cannot be changed into a (ghost) function in a refining module: {0}", f.Name); } else if (prevFunction.IsGhost && !f.IsGhost && prevFunction.Body != null) { - reporter.Error(f, "a function can be changed into a function method in a refining module only if the function has not yet been given a body: {0}", f.Name); + reporter.Error(MessageSource.RefinementTransformer, f, "a function can be changed into a function method in a refining module only if the function has not yet been given a body: {0}", f.Name); } if (f.SignatureIsOmitted) { Contract.Assert(f.TypeArgs.Count == 0); Contract.Assert(f.Formals.Count == 0); - ReportAdditionalInformation(f.SignatureEllipsis, Printer.FunctionSignatureToString(prevFunction), 3); + reporter.Info(MessageSource.RefinementTransformer, f.SignatureEllipsis, Printer.FunctionSignatureToString(prevFunction)); } else { CheckAgreement_TypeParameters(f.tok, prevFunction.TypeArgs, f.TypeArgs, f.Name, "function"); CheckAgreement_Parameters(f.tok, prevFunction.Formals, f.Formals, f.Name, "function", "parameter"); if (!TypesAreSyntacticallyEqual(prevFunction.ResultType, f.ResultType)) { - reporter.Error(f, "the result type of function '{0}' ({1}) differs from the result type of the corresponding function in the module it refines ({2})", f.Name, f.ResultType, prevFunction.ResultType); + reporter.Error(MessageSource.RefinementTransformer, f, "the result type of function '{0}' ({1}) differs from the result type of the corresponding function in the module it refines ({2})", f.Name, f.ResultType, prevFunction.ResultType); } } @@ -752,9 +745,9 @@ namespace Microsoft.Dafny if (isPredicate && f.IsProtected) { moreBody = f.Body; } else if (isPredicate) { - reporter.Error(nwMember, "a refining predicate is not allowed to extend/change the body unless it is declared 'protected'"); + reporter.Error(MessageSource.RefinementTransformer, nwMember, "a refining predicate is not allowed to extend/change the body unless it is declared 'protected'"); } else { - reporter.Error(nwMember, "a refining function is not allowed to extend/change the body"); + reporter.Error(MessageSource.RefinementTransformer, nwMember, "a refining function is not allowed to extend/change the body"); } } var newF = CloneFunction(f.tok, prevFunction, f.IsGhost, f.Ens, moreBody, replacementBody, prevFunction.Body == null, f.Attributes); @@ -765,14 +758,14 @@ namespace Microsoft.Dafny } else { var m = (Method)nwMember; if (!(member is Method)) { - reporter.Error(nwMember, "a method declaration ({0}) can only refine a method", nwMember.Name); + reporter.Error(MessageSource.RefinementTransformer, nwMember, "a method declaration ({0}) can only refine a method", nwMember.Name); } else { var prevMethod = (Method)member; if (m.Req.Count != 0) { - reporter.Error(m.Req[0].E.tok, "a refining method is not allowed to add preconditions"); + reporter.Error(MessageSource.RefinementTransformer, m.Req[0].E.tok, "a refining method is not allowed to add preconditions"); } if (m.Mod.Expressions.Count != 0) { - reporter.Error(m.Mod.Expressions[0].E.tok, "a refining method is not allowed to extend the modifies clause"); + reporter.Error(MessageSource.RefinementTransformer, m.Mod.Expressions[0].E.tok, "a refining method is not allowed to extend the modifies clause"); } // If the previous method was not specified with "decreases *", then the new method is not allowed to provide any "decreases" clause. // Any "decreases *" clause is not inherited, so if the previous method was specified with "decreases *", then the new method needs @@ -785,23 +778,23 @@ namespace Microsoft.Dafny } else { if (!Contract.Exists(prevMethod.Decreases.Expressions, e => e is WildcardExpr)) { // If the previous loop was not specified with "decreases *", then the new loop is not allowed to provide any "decreases" clause. - reporter.Error(m.Decreases.Expressions[0].tok, "decreases clause on refining method not supported, unless the refined method was specified with 'decreases *'"); + reporter.Error(MessageSource.RefinementTransformer, m.Decreases.Expressions[0].tok, "decreases clause on refining method not supported, unless the refined method was specified with 'decreases *'"); } decreases = m.Decreases; } if (prevMethod.HasStaticKeyword != m.HasStaticKeyword) { - reporter.Error(m, "a method in a refining module cannot be changed from static to non-static or vice versa: {0}", m.Name); + reporter.Error(MessageSource.RefinementTransformer, m, "a method in a refining module cannot be changed from static to non-static or vice versa: {0}", m.Name); } if (prevMethod.IsGhost && !m.IsGhost) { - reporter.Error(m, "a method cannot be changed into a ghost method in a refining module: {0}", m.Name); + reporter.Error(MessageSource.RefinementTransformer, m, "a method cannot be changed into a ghost method in a refining module: {0}", m.Name); } else if (!prevMethod.IsGhost && m.IsGhost) { - reporter.Error(m, "a ghost method cannot be changed into a non-ghost method in a refining module: {0}", m.Name); + reporter.Error(MessageSource.RefinementTransformer, m, "a ghost method cannot be changed into a non-ghost method in a refining module: {0}", m.Name); } if (m.SignatureIsOmitted) { Contract.Assert(m.TypeArgs.Count == 0); Contract.Assert(m.Ins.Count == 0); Contract.Assert(m.Outs.Count == 0); - ReportAdditionalInformation(m.SignatureEllipsis, Printer.MethodSignatureToString(prevMethod), 3); + reporter.Info(MessageSource.RefinementTransformer, m.SignatureEllipsis, Printer.MethodSignatureToString(prevMethod)); } else { CheckAgreement_TypeParameters(m.tok, prevMethod.TypeArgs, m.TypeArgs, m.Name, "method"); CheckAgreement_Parameters(m.tok, prevMethod.Ins, m.Ins, m.Name, "method", "in-parameter"); @@ -833,13 +826,13 @@ namespace Microsoft.Dafny Contract.Requires(name != null); Contract.Requires(thing != null); if (old.Count != nw.Count) { - reporter.Error(tok, "{0} '{1}' is declared with a different number of type parameters ({2} instead of {3}) than the corresponding {0} in the module it refines", thing, name, nw.Count, old.Count); + reporter.Error(MessageSource.RefinementTransformer, tok, "{0} '{1}' is declared with a different number of type parameters ({2} instead of {3}) than the corresponding {0} in the module it refines", thing, name, nw.Count, old.Count); } else { for (int i = 0; i < old.Count; i++) { var o = old[i]; var n = nw[i]; if (o.Name != n.Name && checkNames) { // if checkNames is false, then just treat the parameters positionally. - reporter.Error(n.tok, "type parameters are not allowed to be renamed from the names given in the {0} in the module being refined (expected '{1}', found '{2}')", thing, o.Name, n.Name); + reporter.Error(MessageSource.RefinementTransformer, n.tok, "type parameters are not allowed to be renamed from the names given in the {0} in the module being refined (expected '{1}', found '{2}')", thing, o.Name, n.Name); } else { // This explains what we want to do and why: // switch (o.EqualitySupport) { @@ -859,7 +852,7 @@ namespace Microsoft.Dafny // } // Here's how we actually compute it: if (o.EqualitySupport != TypeParameter.EqualitySupportValue.InferredRequired && o.EqualitySupport != n.EqualitySupport) { - reporter.Error(n.tok, "type parameter '{0}' is not allowed to change the requirement of supporting equality", n.Name); + reporter.Error(MessageSource.RefinementTransformer, n.tok, "type parameter '{0}' is not allowed to change the requirement of supporting equality", n.Name); } } } @@ -872,7 +865,7 @@ namespace Microsoft.Dafny CheckOverrideResolvedParameters(nw.tok, f.Formals, nw.Formals, nw.Name, "function", "parameter"); if (!ResolvedTypesAreTheSame(nw.ResultType, f.ResultType)) { - reporter.Error(nw, "the result type of function '{0}' ({1}) differs from the result type of the corresponding function in the module it overrides ({2})", nw.Name, nw.ResultType, f.ResultType); + reporter.Error(MessageSource.RefinementTransformer, nw, "the result type of function '{0}' ({1}) differs from the result type of the corresponding function in the module it overrides ({2})", nw.Name, nw.ResultType, f.ResultType); } } @@ -892,7 +885,7 @@ namespace Microsoft.Dafny Contract.Requires(thing != null); if (old.Count != nw.Count) { - reporter.Error(tok, "{0} '{1}' is declared with a different number of type parameters ({2} instead of {3}) than the corresponding {0} in the module it overrides", thing, name, nw.Count, old.Count); + reporter.Error(MessageSource.RefinementTransformer, tok, "{0} '{1}' is declared with a different number of type parameters ({2} instead of {3}) than the corresponding {0} in the module it overrides", thing, name, nw.Count, old.Count); } else { @@ -902,14 +895,14 @@ namespace Microsoft.Dafny var n = nw[i]; if (o.Name != n.Name && checkNames) { // if checkNames is false, then just treat the parameters positionally. - reporter.Error(n.tok, "type parameters are not allowed to be renamed from the names given in the {0} in the module being overriden (expected '{1}', found '{2}')", thing, o.Name, n.Name); + reporter.Error(MessageSource.RefinementTransformer, n.tok, "type parameters are not allowed to be renamed from the names given in the {0} in the module being overriden (expected '{1}', found '{2}')", thing, o.Name, n.Name); } else { // Here's how we actually compute it: if (o.EqualitySupport != TypeParameter.EqualitySupportValue.InferredRequired && o.EqualitySupport != n.EqualitySupport) { - reporter.Error(n.tok, "type parameter '{0}' is not allowed to change the requirement of supporting equality", n.Name); + reporter.Error(MessageSource.RefinementTransformer, n.tok, "type parameter '{0}' is not allowed to change the requirement of supporting equality", n.Name); } } } @@ -926,7 +919,7 @@ namespace Microsoft.Dafny Contract.Requires(parameterKind != null); if (old.Count != nw.Count) { - reporter.Error(tok, "{0} '{1}' is declared with a different number of {2} ({3} instead of {4}) than the corresponding {0} in the module it overrides", thing, name, parameterKind, nw.Count, old.Count); + reporter.Error(MessageSource.RefinementTransformer, tok, "{0} '{1}' is declared with a different number of {2} ({3} instead of {4}) than the corresponding {0} in the module it overrides", thing, name, parameterKind, nw.Count, old.Count); } else { @@ -936,15 +929,15 @@ namespace Microsoft.Dafny var n = nw[i]; if (!o.IsGhost && n.IsGhost) { - reporter.Error(n.tok, "{0} '{1}' of {2} {3} cannot be changed, compared to the corresponding {2} in the module it overrides, from non-ghost to ghost", parameterKind, n.Name, thing, name); + reporter.Error(MessageSource.RefinementTransformer, n.tok, "{0} '{1}' of {2} {3} cannot be changed, compared to the corresponding {2} in the module it overrides, from non-ghost to ghost", parameterKind, n.Name, thing, name); } else if (o.IsGhost && !n.IsGhost) { - reporter.Error(n.tok, "{0} '{1}' of {2} {3} cannot be changed, compared to the corresponding {2} in the module it overrides, from ghost to non-ghost", parameterKind, n.Name, thing, name); + reporter.Error(MessageSource.RefinementTransformer, n.tok, "{0} '{1}' of {2} {3} cannot be changed, compared to the corresponding {2} in the module it overrides, from ghost to non-ghost", parameterKind, n.Name, thing, name); } else if (!ResolvedTypesAreTheSame(o.Type, n.Type)) { - reporter.Error(n.tok, "the type of {0} '{1}' is different from the type of the same {0} in the corresponding {2} in the module it overrides ('{3}' instead of '{4}')", parameterKind, n.Name, thing, n.Type, o.Type); + reporter.Error(MessageSource.RefinementTransformer, n.tok, "the type of {0} '{1}' is different from the type of the same {0} in the corresponding {2} in the module it overrides ('{3}' instead of '{4}')", parameterKind, n.Name, thing, n.Type, o.Type); } } } @@ -958,19 +951,19 @@ namespace Microsoft.Dafny Contract.Requires(thing != null); Contract.Requires(parameterKind != null); if (old.Count != nw.Count) { - reporter.Error(tok, "{0} '{1}' is declared with a different number of {2} ({3} instead of {4}) than the corresponding {0} in the module it refines", thing, name, parameterKind, nw.Count, old.Count); + reporter.Error(MessageSource.RefinementTransformer, tok, "{0} '{1}' is declared with a different number of {2} ({3} instead of {4}) than the corresponding {0} in the module it refines", thing, name, parameterKind, nw.Count, old.Count); } else { for (int i = 0; i < old.Count; i++) { var o = old[i]; var n = nw[i]; if (o.Name != n.Name) { - reporter.Error(n.tok, "there is a difference in name of {0} {1} ('{2}' versus '{3}') of {4} {5} compared to corresponding {4} in the module it refines", parameterKind, i, n.Name, o.Name, thing, name); + reporter.Error(MessageSource.RefinementTransformer, n.tok, "there is a difference in name of {0} {1} ('{2}' versus '{3}') of {4} {5} compared to corresponding {4} in the module it refines", parameterKind, i, n.Name, o.Name, thing, name); } else if (!o.IsGhost && n.IsGhost) { - reporter.Error(n.tok, "{0} '{1}' of {2} {3} cannot be changed, compared to the corresponding {2} in the module it refines, from non-ghost to ghost", parameterKind, n.Name, thing, name); + reporter.Error(MessageSource.RefinementTransformer, n.tok, "{0} '{1}' of {2} {3} cannot be changed, compared to the corresponding {2} in the module it refines, from non-ghost to ghost", parameterKind, n.Name, thing, name); } else if (o.IsGhost && !n.IsGhost) { - reporter.Error(n.tok, "{0} '{1}' of {2} {3} cannot be changed, compared to the corresponding {2} in the module it refines, from ghost to non-ghost", parameterKind, n.Name, thing, name); + reporter.Error(MessageSource.RefinementTransformer, n.tok, "{0} '{1}' of {2} {3} cannot be changed, compared to the corresponding {2} in the module it refines, from ghost to non-ghost", parameterKind, n.Name, thing, name); } else if (!TypesAreSyntacticallyEqual(o.Type, n.Type)) { - reporter.Error(n.tok, "the type of {0} '{1}' is different from the type of the same {0} in the corresponding {2} in the module it refines ('{3}' instead of '{4}')", parameterKind, n.Name, thing, n.Type, o.Type); + reporter.Error(MessageSource.RefinementTransformer, n.tok, "the type of {0} '{1}' is different from the type of the same {0} in the corresponding {2} in the module it refines ('{3}' instead of '{4}')", parameterKind, n.Name, thing, n.Type, o.Type); } } } @@ -996,7 +989,7 @@ namespace Microsoft.Dafny } else if (((SkeletonStatement)cur).S == null) { // the "..." matches the empty statement sequence } else { - reporter.Error(cur.Tok, "skeleton statement does not match old statement"); + reporter.Error(MessageSource.RefinementTransformer, cur.Tok, "skeleton statement does not match old statement"); } i++; } else { @@ -1050,7 +1043,7 @@ namespace Microsoft.Dafny Contract.Assert(c.NameReplacements.Count == c.ExprReplacements.Count); for (int k = 0; k < c.NameReplacements.Count; k++) { if (subExprs.ContainsKey(c.NameReplacements[k].val)) { - reporter.Error(c.NameReplacements[k], "replacement definition must contain at most one definition for a given label"); + reporter.Error(MessageSource.RefinementTransformer, c.NameReplacements[k], "replacement definition must contain at most one definition for a given label"); } else subExprs.Add(c.NameReplacements[k].val, c.ExprReplacements[k]); } subber = new SubstitutionCloner(subExprs, rawCloner); @@ -1071,12 +1064,12 @@ namespace Microsoft.Dafny oldS = oldStmt.Body[j]; } if (hoverTextA.Length != 0) { - ReportAdditionalInformation(c.Tok, hoverTextA, 3); + reporter.Info(MessageSource.RefinementTransformer, c.Tok, hoverTextA); } if (subber != null && subber.SubstitutionsMade.Count < subber.Exprs.Count) { foreach (var s in subber.SubstitutionsMade) subber.Exprs.Remove(s); - reporter.Error(c.Tok, "could not find labeled expression(s): " + Util.Comma(", ", subber.Exprs.Keys, x => x)); + reporter.Error(MessageSource.RefinementTransformer, c.Tok, "could not find labeled expression(s): " + Util.Comma(", ", subber.Exprs.Keys, x => x)); } } i++; @@ -1086,7 +1079,7 @@ namespace Microsoft.Dafny Contract.Assert(c.ConditionOmitted); var oldAssume = oldS as PredicateStmt; if (oldAssume == null) { - reporter.Error(cur.Tok, "assert template does not match inherited statement"); + reporter.Error(MessageSource.RefinementTransformer, cur.Tok, "assert template does not match inherited statement"); i++; } else { // Clone the expression, but among the new assert's attributes, indicate @@ -1097,7 +1090,7 @@ namespace Microsoft.Dafny var attrs = refinementCloner.MergeAttributes(oldAssume.Attributes, skel.Attributes); body.Add(new AssertStmt(new Translator.ForceCheckToken(skel.Tok), new Translator.ForceCheckToken(skel.EndTok), e, new Attributes("prependAssertToken", new List(), attrs))); - ReportAdditionalInformation(c.ConditionEllipsis, "assume->assert: " + Printer.ExprToString(e), 3); + reporter.Info(MessageSource.RefinementTransformer, c.ConditionEllipsis, "assume->assert: " + Printer.ExprToString(e)); i++; j++; } @@ -1106,13 +1099,13 @@ namespace Microsoft.Dafny Contract.Assert(c.ConditionOmitted); var oldAssume = oldS as AssumeStmt; if (oldAssume == null) { - reporter.Error(cur.Tok, "assume template does not match inherited statement"); + reporter.Error(MessageSource.RefinementTransformer, cur.Tok, "assume template does not match inherited statement"); i++; } else { var e = refinementCloner.CloneExpr(oldAssume.Expr); var attrs = refinementCloner.MergeAttributes(oldAssume.Attributes, skel.Attributes); body.Add(new AssumeStmt(skel.Tok, skel.EndTok, e, attrs)); - ReportAdditionalInformation(c.ConditionEllipsis, Printer.ExprToString(e), 3); + reporter.Info(MessageSource.RefinementTransformer, c.ConditionEllipsis, Printer.ExprToString(e)); i++; j++; } @@ -1121,7 +1114,7 @@ namespace Microsoft.Dafny Contract.Assert(c.ConditionOmitted); var oldIf = oldS as IfStmt; if (oldIf == null) { - reporter.Error(cur.Tok, "if-statement template does not match inherited statement"); + reporter.Error(MessageSource.RefinementTransformer, cur.Tok, "if-statement template does not match inherited statement"); i++; } else { var resultingThen = MergeBlockStmt(skel.Thn, oldIf.Thn); @@ -1129,7 +1122,7 @@ namespace Microsoft.Dafny var e = refinementCloner.CloneExpr(oldIf.Guard); var r = new IfStmt(skel.Tok, skel.EndTok, e, resultingThen, resultingElse); body.Add(r); - ReportAdditionalInformation(c.ConditionEllipsis, Printer.GuardToString(e), 3); + reporter.Info(MessageSource.RefinementTransformer, c.ConditionEllipsis, Printer.GuardToString(e)); i++; j++; } @@ -1137,16 +1130,16 @@ namespace Microsoft.Dafny var skel = (WhileStmt)S; var oldWhile = oldS as WhileStmt; if (oldWhile == null) { - reporter.Error(cur.Tok, "while-statement template does not match inherited statement"); + reporter.Error(MessageSource.RefinementTransformer, cur.Tok, "while-statement template does not match inherited statement"); i++; } else { Expression guard; if (c.ConditionOmitted) { guard = refinementCloner.CloneExpr(oldWhile.Guard); - ReportAdditionalInformation(c.ConditionEllipsis, Printer.GuardToString(oldWhile.Guard), 3); + reporter.Info(MessageSource.RefinementTransformer, c.ConditionEllipsis, Printer.GuardToString(oldWhile.Guard)); } else { if (oldWhile.Guard != null) { - reporter.Error(skel.Guard.tok, "a skeleton while statement with a guard can only replace a while statement with a non-deterministic guard"); + reporter.Error(MessageSource.RefinementTransformer, skel.Guard.tok, "a skeleton while statement with a guard can only replace a while statement with a non-deterministic guard"); } guard = skel.Guard; } @@ -1162,7 +1155,7 @@ namespace Microsoft.Dafny Contract.Assert(c.ConditionOmitted); var oldModifyStmt = oldS as ModifyStmt; if (oldModifyStmt == null) { - reporter.Error(cur.Tok, "modify template does not match inherited statement"); + reporter.Error(MessageSource.RefinementTransformer, cur.Tok, "modify template does not match inherited statement"); i++; } else { var mod = refinementCloner.CloneSpecFrameExpr(oldModifyStmt.Mod); @@ -1172,13 +1165,13 @@ namespace Microsoft.Dafny } else if (oldModifyStmt.Body == null) { mbody = skel.Body; } else if (skel.Body == null) { - reporter.Error(cur.Tok, "modify template must have a body if the inherited modify statement does"); + reporter.Error(MessageSource.RefinementTransformer, cur.Tok, "modify template must have a body if the inherited modify statement does"); mbody = null; } else { mbody = MergeBlockStmt(skel.Body, oldModifyStmt.Body); } body.Add(new ModifyStmt(skel.Tok, skel.EndTok, mod.Expressions, mod.Attributes, mbody)); - ReportAdditionalInformation(c.ConditionEllipsis, Printer.FrameExprListToString(mod.Expressions), 3); + reporter.Info(MessageSource.RefinementTransformer, c.ConditionEllipsis, Printer.FrameExprListToString(mod.Expressions)); i++; j++; } @@ -1341,7 +1334,7 @@ namespace Microsoft.Dafny sep = "\n"; } if (hoverText.Length != 0) { - ReportAdditionalInformation(skeleton.EndTok, hoverText, 3); + reporter.Info(MessageSource.RefinementTransformer, skeleton.EndTok, hoverText); } return new BlockStmt(skeleton.Tok, skeleton.EndTok, body); } @@ -1447,7 +1440,7 @@ namespace Microsoft.Dafny } else { if (!Contract.Exists(cOld.Decreases.Expressions, e => e is WildcardExpr)) { // If the previous loop was not specified with "decreases *", then the new loop is not allowed to provide any "decreases" clause. - reporter.Error(cNew.Decreases.Expressions[0].tok, "a refining loop can provide a decreases clause only if the loop being refined was declared with 'decreases *'"); + reporter.Error(MessageSource.RefinementTransformer, cNew.Decreases.Expressions[0].tok, "a refining loop can provide a decreases clause only if the loop being refined was declared with 'decreases *'"); } decr = cNew.Decreases; } @@ -1489,9 +1482,9 @@ namespace Microsoft.Dafny void MergeAddStatement(Statement s, List stmtList) { Contract.Requires(s != null); Contract.Requires(stmtList != null); - var prevErrorCount = reporter.ErrorCount; + var prevErrorCount = reporter.Count(ErrorLevel.Error); CheckIsOkayNewStatement(s, new Stack(), 0); - if (reporter.ErrorCount == prevErrorCount) { + if (reporter.Count(ErrorLevel.Error) == prevErrorCount) { stmtList.Add(s); } } @@ -1508,30 +1501,30 @@ namespace Microsoft.Dafny labels.Push(n.Data.Name); } if (s is SkeletonStatement) { - reporter.Error(s, "skeleton statement may not be used here; it does not have a matching statement in what is being replaced"); + reporter.Error(MessageSource.RefinementTransformer, s, "skeleton statement may not be used here; it does not have a matching statement in what is being replaced"); } else if (s is ReturnStmt) { // allow return statements, but make note of that this requires verifying the postcondition ((ReturnStmt)s).ReverifyPost = true; } else if (s is YieldStmt) { - reporter.Error(s, "yield statements are not allowed in skeletons"); + reporter.Error(MessageSource.RefinementTransformer, s, "yield statements are not allowed in skeletons"); } else if (s is BreakStmt) { var b = (BreakStmt)s; if (b.TargetLabel != null ? !labels.Contains(b.TargetLabel) : loopLevels < b.BreakCount) { - reporter.Error(s, "break statement in skeleton is not allowed to break outside the skeleton fragment"); + reporter.Error(MessageSource.RefinementTransformer, s, "break statement in skeleton is not allowed to break outside the skeleton fragment"); } } else if (s is AssignStmt) { // TODO: To be a refinement automatically (that is, without any further verification), only variables and fields defined // in this module are allowed. This needs to be checked. If the LHS refers to an l-value that was not declared within // this module, then either an error should be reported or the Translator needs to know to translate new proof obligations. var a = (AssignStmt)s; - reporter.Error(a.Tok, "cannot have assignment statement"); + reporter.Error(MessageSource.RefinementTransformer, a.Tok, "cannot have assignment statement"); } else if (s is ConcreteUpdateStatement) { postTasks.Enqueue(() => { - CheckIsOkayUpdateStmt((ConcreteUpdateStatement)s, moduleUnderConstruction, reporter); + CheckIsOkayUpdateStmt((ConcreteUpdateStatement)s, moduleUnderConstruction); }); } else if (s is CallStmt) { - reporter.Error(s.Tok, "cannot have call statement"); + reporter.Error(MessageSource.RefinementTransformer, s.Tok, "cannot have call statement"); } else { if (s is WhileStmt || s is AlternativeLoopStmt) { loopLevels++; @@ -1547,7 +1540,7 @@ namespace Microsoft.Dafny } // Checks that statement stmt, defined in the constructed module m, is a refinement of skip in the parent module - void CheckIsOkayUpdateStmt(ConcreteUpdateStatement stmt, ModuleDefinition m, ResolutionErrorReporter reporter) { + void CheckIsOkayUpdateStmt(ConcreteUpdateStatement stmt, ModuleDefinition m) { foreach (var lhs in stmt.Lhss) { var l = lhs.Resolved; if (l is IdentifierExpr) { @@ -1555,23 +1548,23 @@ namespace Microsoft.Dafny Contract.Assert(ident.Var is LocalVariable || ident.Var is Formal); // LHS identifier expressions must be locals or out parameters (ie. formals) if ((ident.Var is LocalVariable && RefinementToken.IsInherited(((LocalVariable)ident.Var).Tok, m)) || ident.Var is Formal) { // for some reason, formals are not considered to be inherited. - reporter.Error(l.tok, "refinement method cannot assign to variable defined in parent module ('{0}')", ident.Var.Name); + reporter.Error(MessageSource.RefinementTransformer, l.tok, "refinement method cannot assign to variable defined in parent module ('{0}')", ident.Var.Name); } } else if (l is MemberSelectExpr) { var member = ((MemberSelectExpr)l).Member; if (RefinementToken.IsInherited(member.tok, m)) { - reporter.Error(l.tok, "refinement method cannot assign to a field defined in parent module ('{0}')", member.Name); + reporter.Error(MessageSource.RefinementTransformer, l.tok, "refinement method cannot assign to a field defined in parent module ('{0}')", member.Name); } } else { // must be an array element - reporter.Error(l.tok, "new assignments in a refinement method can only assign to state that the module defines (which never includes array elements)"); + reporter.Error(MessageSource.RefinementTransformer, l.tok, "new assignments in a refinement method can only assign to state that the module defines (which never includes array elements)"); } } if (stmt is UpdateStmt) { var s = (UpdateStmt)stmt; foreach (var rhs in s.Rhss) { if (rhs.CanAffectPreviouslyKnownExpressions) { - reporter.Error(rhs.Tok, "assignment RHS in refinement method is not allowed to affect previously defined state"); + reporter.Error(MessageSource.RefinementTransformer, rhs.Tok, "assignment RHS in refinement method is not allowed to affect previously defined state"); } } } diff --git a/Source/Dafny/Reporting.cs b/Source/Dafny/Reporting.cs new file mode 100644 index 00000000..c3797574 --- /dev/null +++ b/Source/Dafny/Reporting.cs @@ -0,0 +1,164 @@ +using Microsoft.Boogie; +using System; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.Linq; +using System.Text; + +namespace Microsoft.Dafny { + public enum ErrorLevel { + Info, Warning, Error + } + + public enum MessageSource { + Parser, Resolver, Translator, Rewriter, Other, + RefinementTransformer, + Cloner + } + + public struct ErrorMessage { + public IToken token; + public string message; + public MessageSource source; + } + + public abstract class ErrorReporter { + public bool ErrorsOnly { get; set; } + public Dictionary> AllMessages { get; private set; } + + protected ErrorReporter() { + ErrorsOnly = false; + AllMessages = new Dictionary>(); + AllMessages[ErrorLevel.Error] = new List(); + AllMessages[ErrorLevel.Warning] = new List(); + AllMessages[ErrorLevel.Info] = new List(); + } + + protected bool ShouldDiscard(MessageSource source, ErrorLevel level) { + return ((ErrorsOnly && level != ErrorLevel.Error) || + (!DafnyOptions.O.PrintTooltips && level == ErrorLevel.Info)); + } + + // This is the only thing that needs to be overriden + public virtual bool Message(MessageSource source, ErrorLevel level, IToken tok, string msg) { + var discard = ShouldDiscard(source, level); + + if (!discard) { + AllMessages[level].Add(new ErrorMessage { token = tok, message = msg }); + return true; + } + + return false; + } + + public int Count(ErrorLevel level) { + return AllMessages[level].Count; + } + + public void Error(MessageSource source, IToken tok, string msg) { + Contract.Requires(tok != null); + Contract.Requires(msg != null); + Message(source, ErrorLevel.Error, tok, msg); + } + + // This method required by the Parser + internal void Error(MessageSource source, string filename, int line, int col, string msg) { + var tok = new Token(line, col); + tok.filename = filename; + Error(source, tok, msg); + } + + public void Error(MessageSource source, IToken tok, string msg, params object[] args) { + Contract.Requires(tok != null); + Contract.Requires(msg != null); + Error(source, tok, String.Format(msg, args)); + } + + public void Error(MessageSource source, Declaration d, string msg, params object[] args) { + Contract.Requires(d != null); + Contract.Requires(msg != null); + Error(source, d.tok, msg, args); + } + + public void Error(MessageSource source, Statement s, string msg, params object[] args) { + Contract.Requires(s != null); + Contract.Requires(msg != null); + Error(source, s.Tok, msg, args); + } + + public void Error(MessageSource source, NonglobalVariable v, string msg, params object[] args) { + Contract.Requires(v != null); + Contract.Requires(msg != null); + Error(source, v.tok, msg, args); + } + + public void Error(MessageSource source, Expression e, string msg, params object[] args) { + Contract.Requires(e != null); + Contract.Requires(msg != null); + Error(source, e.tok, msg, args); + } + + public void Warning(MessageSource source, IToken tok, string msg) { + Contract.Requires(tok != null); + Contract.Requires(msg != null); + Message(source, ErrorLevel.Warning, tok, msg); + } + + public void Warning(MessageSource source, IToken tok, string msg, params object[] args) { + Contract.Requires(tok != null); + Contract.Requires(msg != null); + Warning(source, tok, String.Format(msg, args)); + } + + public void Info(MessageSource source, IToken tok, string msg) { + Contract.Requires(tok != null); + Contract.Requires(msg != null); + Message(source, ErrorLevel.Info, tok, msg); + } + + public void Info(MessageSource source, IToken tok, string msg, params object[] args) { + Contract.Requires(tok != null); + Contract.Requires(msg != null); + Info(source, tok, String.Format(msg, args)); + } + + public string ErrorToString(ErrorLevel header, IToken tok, string msg) { + return ErrorToString_Internal(": " + header.ToString(), tok.filename, tok.line, tok.col, ": " + msg); + } + + public string ErrorToString(ErrorLevel header, string filename, int oneBasedLine, int oneBasedColumn, string msg) { + return ErrorToString_Internal(": " + header.ToString(), filename, oneBasedLine, oneBasedColumn, ": " + msg); + } + + public string ErrorToString_Internal(string header, string filename, int oneBasedLine, int oneBasedColumn, string msg) { + return String.Format("{0}({1},{2}){3}{4}", filename, oneBasedLine, oneBasedColumn - 1, header, msg ?? ""); + } + } + + public class ConsoleErrorReporter : ErrorReporter { + private ConsoleColor ColorForLevel(ErrorLevel level) { + switch (level) { + case ErrorLevel.Error: + return ConsoleColor.Red; + case ErrorLevel.Warning: + return ConsoleColor.Yellow; + case ErrorLevel.Info: + return ConsoleColor.Green; + default: + throw new cce.UnreachableException(); + } + } + + public override bool Message(MessageSource source, ErrorLevel level, IToken tok, string msg) { + if (base.Message(source, level, tok, msg)) { + ConsoleColor previousColor = Console.ForegroundColor; + Console.ForegroundColor = ColorForLevel(level); + Console.WriteLine(ErrorToString(level, tok, msg)); + Console.ForegroundColor = previousColor; + return true; + } else { + return false; + } + } + } +} diff --git a/Source/Dafny/Resolver.cs b/Source/Dafny/Resolver.cs index a58d6e6c..db087109 100644 --- a/Source/Dafny/Resolver.cs +++ b/Source/Dafny/Resolver.cs @@ -12,75 +12,11 @@ using Microsoft.Boogie; namespace Microsoft.Dafny { - public class ResolutionErrorReporter - { - public int ErrorCount = 0; - - /// - /// This method is virtual, because it is overridden in the VSX plug-in for Dafny. - /// - public virtual void Error(IToken tok, string msg, params object[] args) { - Contract.Requires(tok != null); - Contract.Requires(msg != null); - ConsoleColor col = Console.ForegroundColor; - Console.ForegroundColor = ConsoleColor.Red; - Dafny.Util.ReportIssue("Error", tok, msg, args); - Console.ForegroundColor = col; - ErrorCount++; - } - public void Error(Declaration d, string msg, params object[] args) { - Contract.Requires(d != null); - Contract.Requires(msg != null); - Error(d.tok, msg, args); - } - public void Error(Statement s, string msg, params object[] args) { - Contract.Requires(s != null); - Contract.Requires(msg != null); - Error(s.Tok, msg, args); - } - public void Error(NonglobalVariable v, string msg, params object[] args) { - Contract.Requires(v != null); - Contract.Requires(msg != null); - Error(v.tok, msg, args); - } - public void Error(Expression e, string msg, params object[] args) { - Contract.Requires(e != null); - Contract.Requires(msg != null); - Error(e.tok, msg, args); - } - - protected bool reportWarnings = true; - /// - /// Set whether or not to report warnings. Return the state of the previous behavior. - /// - public bool ReportWarnings(bool b) { - var old = reportWarnings; - reportWarnings = b; - return old; - } - public virtual void Warning(IToken tok, string msg, params object[] args) { - Contract.Requires(tok != null); - Contract.Requires(msg != null); - if (reportWarnings) { - ConsoleColor col = Console.ForegroundColor; - Console.ForegroundColor = ConsoleColor.Yellow; - Dafny.Util.ReportIssue("Warning", tok, msg, args); - Console.ForegroundColor = col; - } - } - } - - public struct AdditionalInformation - { - public IToken Token; - public string Text; - public int Length; - } - - public class Resolver : ResolutionErrorReporter + public class Resolver { readonly BuiltIns builtIns; + readonly ErrorReporter reporter; ModuleSignature moduleInfo = null; FreshIdGenerator defaultTempVarIdGenerator; @@ -99,18 +35,6 @@ namespace Microsoft.Dafny return defaultTempVarIdGenerator.FreshId(prefix); } - public Action AdditionalInformationReporter; - - internal void ReportAdditionalInformation(IToken token, string text, int length) - { - Contract.Requires(token != null); - Contract.Requires(text != null); - Contract.Requires(0 <= length); //FIXME: KRML: This should (probably) be the length of the token - if (AdditionalInformationReporter != null) { - AdditionalInformationReporter(new AdditionalInformation { Token = token, Text = text, Length = length }); - } - } - interface IAmbiguousThing { /// @@ -259,13 +183,10 @@ namespace Microsoft.Dafny public Resolver(Program prog) { Contract.Requires(prog != null); builtIns = prog.BuiltIns; + reporter = prog.reporter; // Populate the members of the basic types var trunc = new SpecialField(Token.NoToken, "Trunc", "ToBigInteger()", "", "", false, false, false, Type.Int, null); basicTypeMembers[(int)BasicTypeVariety.Real].Add(trunc.Name, trunc); - - if (DafnyOptions.O.PrintTooltips) { - AdditionalInformationReporter = DefaultInformationReporter; - } } [ContractInvariantMethod] @@ -276,26 +197,22 @@ namespace Microsoft.Dafny Contract.Invariant(cce.NonNullDictionaryAndValues(datatypeCtors) && Contract.ForAll(datatypeCtors.Values, v => cce.NonNullDictionaryAndValues(v))); } - public static void DefaultInformationReporter(AdditionalInformation info) { - Dafny.Util.ReportIssue("Info", info.Token, info.Text); - } - public void ResolveProgram(Program prog) { Contract.Requires(prog != null); - var origErrorCount = ErrorCount; + var origErrorCount = reporter.Count(ErrorLevel.Error); //FIXME (Clement): This is used further below, but not in the >0 comparisons in the next few lines. Is that right? var bindings = new ModuleBindings(null); var b = BindModuleNames(prog.DefaultModuleDef, bindings); bindings.BindName("_module", prog.DefaultModule, b); - if (ErrorCount > 0) { return; } // if there were errors, then the implict ModuleBindings data structure invariant + if (reporter.Count(ErrorLevel.Error) > 0) { return; } // if there were errors, then the implict ModuleBindings data structure invariant // is violated, so Processing dependencies will not succeed. ProcessDependencies(prog.DefaultModule, b, dependencies); // check for cycles in the import graph List cycle = dependencies.TryFindCycle(); if (cycle != null) { var cy = Util.Comma(" -> ", cycle, m => m.Name); - Error(cycle[0], "module definition contains a cycle (note: parent modules implicitly depend on submodules): {0}", cy); + reporter.Error(MessageSource.Resolver, cycle[0], "module definition contains a cycle (note: parent modules implicitly depend on submodules): {0}", cy); } - if (ErrorCount > 0) { return; } // give up on trying to resolve anything else + if (reporter.Count(ErrorLevel.Error) > 0) { return; } // give up on trying to resolve anything else // fill in module heights List sortedDecls = dependencies.TopologicallySortedComponents(); @@ -311,16 +228,16 @@ namespace Microsoft.Dafny } var rewriters = new List(); - var refinementTransformer = new RefinementTransformer(this, AdditionalInformationReporter, prog); + var refinementTransformer = new RefinementTransformer(prog); rewriters.Add(refinementTransformer); - rewriters.Add(new AutoContractsRewriter()); - var opaqueRewriter = new OpaqueFunctionRewriter(this); - rewriters.Add(new AutoReqFunctionRewriter(this, opaqueRewriter)); + rewriters.Add(new AutoContractsRewriter(reporter)); + var opaqueRewriter = new OpaqueFunctionRewriter(this.reporter); + rewriters.Add(new AutoReqFunctionRewriter(this.reporter, opaqueRewriter)); rewriters.Add(opaqueRewriter); - rewriters.Add(new TimeLimitRewriter()); + rewriters.Add(new TimeLimitRewriter(reporter)); if (DafnyOptions.O.AutoTriggers) { - rewriters.Add(new TriggersRewriter(this)); + rewriters.Add(new TriggerGeneratingRewriter(this.reporter)); } systemNameInfo = RegisterTopLevelDecls(prog.BuiltIns.SystemModule, false); @@ -365,7 +282,7 @@ namespace Microsoft.Dafny var literalDecl = (LiteralModuleDecl)decl; var m = literalDecl.ModuleDef; - var errorCount = ErrorCount; + var errorCount = reporter.Count(ErrorLevel.Error); foreach (var r in rewriters) { r.PreResolve(m); } @@ -374,19 +291,20 @@ namespace Microsoft.Dafny literalDecl.Signature.Refines = refinementTransformer.RefinedSig; var sig = literalDecl.Signature; // set up environment - var preResolveErrorCount = ErrorCount; + var preResolveErrorCount = reporter.Count(ErrorLevel.Error); ResolveModuleDefinition(m, sig); foreach (var r in rewriters) { - if (ErrorCount != preResolveErrorCount) { + if (reporter.Count(ErrorLevel.Error) != preResolveErrorCount) { break; } r.PostResolve(m); } - if (ErrorCount == errorCount && !m.IsAbstract) { + if (reporter.Count(ErrorLevel.Error) == errorCount && !m.IsAbstract) { // compilation should only proceed if everything is good, including the signature (which preResolveErrorCount does not include); Contract.Assert(!useCompileSignatures); useCompileSignatures = true; // set Resolver-global flag to indicate that Signatures should be followed to their CompiledSignature - var oldWarnings = ReportWarnings(false); // turn off warning reporting for the clone + var oldErrorsOnly = reporter.ErrorsOnly; + reporter.ErrorsOnly = true; // turn off warning reporting for the clone var nw = new Cloner().CloneModuleDefinition(m, m.CompileName + "_Compile"); var compileSig = RegisterTopLevelDecls(nw, true); compileSig.Refines = refinementTransformer.RefinedSig; @@ -394,13 +312,13 @@ namespace Microsoft.Dafny ResolveModuleDefinition(nw, compileSig); prog.CompileModules.Add(nw); useCompileSignatures = false; // reset the flag - ReportWarnings(oldWarnings); + reporter.ErrorsOnly = oldErrorsOnly; } } else if (decl is AliasModuleDecl) { var alias = (AliasModuleDecl)decl; // resolve the path ModuleSignature p; - if (ResolvePath(alias.Root, alias.Path, out p, this)) { + if (ResolvePath(alias.Root, alias.Path, out p, reporter)) { alias.Signature = p; } else { alias.Signature = new ModuleSignature(); // there was an error, give it a valid but empty signature @@ -408,18 +326,18 @@ namespace Microsoft.Dafny } else if (decl is ModuleFacadeDecl) { var abs = (ModuleFacadeDecl)decl; ModuleSignature p; - if (ResolvePath(abs.Root, abs.Path, out p, this)) { + if (ResolvePath(abs.Root, abs.Path, out p, reporter)) { abs.OriginalSignature = p; // ModuleDefinition.ExclusiveRefinement may not be set at this point but ExclusiveRefinementCount will be. if (0 == abs.Root.Signature.ModuleDef.ExclusiveRefinementCount) { abs.Signature = MakeAbstractSignature(p, abs.FullCompileName, abs.Height, prog.Modules); ModuleSignature compileSig; if (abs.CompilePath != null) { - if (ResolvePath(abs.CompileRoot, abs.CompilePath, out compileSig, this)) { + if (ResolvePath(abs.CompileRoot, abs.CompilePath, out compileSig, reporter)) { if (refinementTransformer.CheckIsRefinement(compileSig, p)) { abs.Signature.CompileSignature = compileSig; } else { - Error( + reporter.Error(MessageSource.Resolver, abs.CompilePath[0], "module " + Util.Comma(".", abs.CompilePath, x => x.val) + " must be a refinement of " + Util.Comma(".", abs.Path, x => x.val)); @@ -437,7 +355,7 @@ namespace Microsoft.Dafny } else { Contract.Assert(false); } Contract.Assert(decl.Signature != null); } - if (ErrorCount != origErrorCount) { + if (reporter.Count(ErrorLevel.Error) != origErrorCount) { // do nothing else return; } @@ -493,7 +411,7 @@ namespace Microsoft.Dafny } foreach (var module in prog.Modules) { foreach (var iter in ModuleDefinition.AllIteratorDecls(module.TopLevelDecls)) { - ReportAdditionalInformation(iter.tok, Printer.IteratorClassToString(iter), iter.Name.Length); + reporter.Info(MessageSource.Resolver, iter.tok, Printer.IteratorClassToString(iter)); } } // fill in other additional information @@ -514,19 +432,19 @@ namespace Microsoft.Dafny // Determine, for each function, whether someone tries to adjust its fuel parameter foreach (var module in prog.Modules) { - CheckForFuelAdjustments(module.tok, module.Attributes, module, this); + CheckForFuelAdjustments(module.tok, module.Attributes, module); foreach (var clbl in ModuleDefinition.AllItersAndCallables(module.TopLevelDecls)) { Statement body = null; if (clbl is Method) { body = ((Method)clbl).Body; - CheckForFuelAdjustments(clbl.Tok,((Method)clbl).Attributes, module, this); + CheckForFuelAdjustments(clbl.Tok,((Method)clbl).Attributes, module); } else if (clbl is IteratorDecl) { body = ((IteratorDecl)clbl).Body; - CheckForFuelAdjustments(clbl.Tok, ((IteratorDecl)clbl).Attributes, module, this); + CheckForFuelAdjustments(clbl.Tok, ((IteratorDecl)clbl).Attributes, module); } if (body != null) { var c = new FuelAdjustment_Visitor(this); - c.Visit(body, new FuelAdjustment_Context(module, this)); + c.Visit(body, new FuelAdjustment_Context(module)); } } } @@ -572,7 +490,7 @@ namespace Microsoft.Dafny } // Note, in the following line, we use the location information for "clbl", not "m". These // are the same, except in the case where "clbl" is a CoLemma and "m" is a prefix lemma. - ReportAdditionalInformation(clbl.Tok, s, clbl.Tok.val.Length); + reporter.Info(MessageSource.Resolver, clbl.Tok, s); } } } @@ -595,7 +513,7 @@ namespace Microsoft.Dafny var decr = clbl.Decreases.Expressions; if (DafnyOptions.O.Dafnycc) { if (decr.Count > 1) { - Error(decr[1].tok, "In dafnycc mode, only one decreases expression is allowed"); + reporter.Error(MessageSource.Resolver, decr[1].tok, "In dafnycc mode, only one decreases expression is allowed"); } // In dafnycc mode, only consider first argument if (decr.Count == 0 && clbl.Ins.Count > 0) { @@ -757,11 +675,11 @@ namespace Microsoft.Dafny // resolve var datatypeDependencies = new Graph(); var codatatypeDependencies = new Graph(); - int prevErrorCount = ErrorCount; + int prevErrorCount = reporter.Count(ErrorLevel.Error); ResolveTopLevelDecls_Signatures(m, m.TopLevelDecls, datatypeDependencies, codatatypeDependencies); ResolveAttributes(m.Attributes, new ResolveOpts(new NoContext(m.Module), false)); // Must follow ResolveTopLevelDecls_Signatures, in case attributes refer to members - if (ErrorCount == prevErrorCount) { - ResolveTopLevelDecls_Meat(m.TopLevelDecls, datatypeDependencies, codatatypeDependencies); + if (reporter.Count(ErrorLevel.Error) == prevErrorCount) { + ResolveTopLevelDecls_Core(m.TopLevelDecls, datatypeDependencies, codatatypeDependencies); } } @@ -819,17 +737,17 @@ namespace Microsoft.Dafny var subdecl = (LiteralModuleDecl)tld; var subBindings = BindModuleNames(subdecl.ModuleDef, bindings); if (!bindings.BindName(subdecl.Name, subdecl, subBindings)) { - Error(subdecl.tok, "Duplicate module name: {0}", subdecl.Name); + reporter.Error(MessageSource.Resolver, subdecl.tok, "Duplicate module name: {0}", subdecl.Name); } } else if (tld is ModuleFacadeDecl) { var subdecl = (ModuleFacadeDecl)tld; if (!bindings.BindName(subdecl.Name, subdecl, null)) { - Error(subdecl.tok, "Duplicate module name: {0}", subdecl.Name); + reporter.Error(MessageSource.Resolver, subdecl.tok, "Duplicate module name: {0}", subdecl.Name); } } else if (tld is AliasModuleDecl) { var subdecl = (AliasModuleDecl)tld; if (!bindings.BindName(subdecl.Name, subdecl, null)) { - Error(subdecl.tok, "Duplicate module name: {0}", subdecl.Name); + reporter.Error(MessageSource.Resolver, subdecl.tok, "Duplicate module name: {0}", subdecl.Name); } } } @@ -840,9 +758,9 @@ namespace Microsoft.Dafny if (m.RefinementBaseName != null) { ModuleDecl other; if (!bindings.TryLookup(m.RefinementBaseName[0], out other)) { - Error(m.RefinementBaseName[0], "module {0} named as refinement base does not exist", m.RefinementBaseName[0].val); + reporter.Error(MessageSource.Resolver, m.RefinementBaseName[0], "module {0} named as refinement base does not exist", m.RefinementBaseName[0].val); } else if (other is LiteralModuleDecl && ((LiteralModuleDecl)other).ModuleDef == m) { - Error(m.RefinementBaseName[0], "module cannot refine itself: {0}", m.RefinementBaseName[0].val); + reporter.Error(MessageSource.Resolver, m.RefinementBaseName[0], "module cannot refine itself: {0}", m.RefinementBaseName[0].val); } else { Contract.Assert(other != null); // follows from postcondition of TryGetValue dependencies.AddEdge(decl, other); @@ -866,7 +784,7 @@ namespace Microsoft.Dafny var alias = moduleDecl as AliasModuleDecl; ModuleDecl root; if (!bindings.TryLookupIgnore(alias.Path[0], out root, alias)) - Error(alias.tok, ModuleNotFoundErrorMessage(0, alias.Path)); + reporter.Error(MessageSource.Resolver, alias.tok, ModuleNotFoundErrorMessage(0, alias.Path)); else { dependencies.AddEdge(moduleDecl, root); alias.Root = root; @@ -875,14 +793,14 @@ namespace Microsoft.Dafny var abs = moduleDecl as ModuleFacadeDecl; ModuleDecl root; if (!bindings.TryLookup(abs.Path[0], out root)) - Error(abs.tok, ModuleNotFoundErrorMessage(0, abs.Path)); + reporter.Error(MessageSource.Resolver, abs.tok, ModuleNotFoundErrorMessage(0, abs.Path)); else { dependencies.AddEdge(moduleDecl, root); abs.Root = root; } if (abs.CompilePath != null) { if (!bindings.TryLookup(abs.CompilePath[0], out root)) - Error(abs.tok, ModuleNotFoundErrorMessage(0, abs.CompilePath)); + reporter.Error(MessageSource.Resolver, abs.tok, ModuleNotFoundErrorMessage(0, abs.CompilePath)); else { dependencies.AddEdge(moduleDecl, root); abs.CompileRoot = root; @@ -990,7 +908,7 @@ namespace Microsoft.Dafny Contract.Assert(d != null); // register the class/datatype/module name if (toplevels.ContainsKey(d.Name)) { - Error(d, "Duplicate name of top-level declaration: {0}", d.Name); + reporter.Error(MessageSource.Resolver, d, "Duplicate name of top-level declaration: {0}", d.Name); } else { toplevels[d.Name] = d; sig.TopLevels[d.Name] = d; @@ -1014,7 +932,7 @@ namespace Microsoft.Dafny // First, register the iterator's in- and out-parameters as readonly fields foreach (var p in iter.Ins) { if (members.ContainsKey(p.Name)) { - Error(p, "Name of in-parameter is used by another member of the iterator: {0}", p.Name); + reporter.Error(MessageSource.Resolver, p, "Name of in-parameter is used by another member of the iterator: {0}", p.Name); } else { var field = new SpecialField(p.tok, p.Name, p.CompileName, "", "", p.IsGhost, false, false, p.Type, null); field.EnclosingClass = iter; // resolve here @@ -1024,7 +942,7 @@ namespace Microsoft.Dafny } foreach (var p in iter.Outs) { if (members.ContainsKey(p.Name)) { - Error(p, "Name of yield-parameter is used by another member of the iterator: {0}", p.Name); + reporter.Error(MessageSource.Resolver, p, "Name of yield-parameter is used by another member of the iterator: {0}", p.Name); } else { var field = new SpecialField(p.tok, p.Name, p.CompileName, "", "", p.IsGhost, true, true, p.Type, null); field.EnclosingClass = iter; // resolve here @@ -1036,7 +954,7 @@ namespace Microsoft.Dafny foreach (var p in iter.Outs) { var nm = p.Name + "s"; if (members.ContainsKey(nm)) { - Error(p.tok, "Name of implicit yield-history variable '{0}' is already used by another member of the iterator", p.Name); + reporter.Error(MessageSource.Resolver, p.tok, "Name of implicit yield-history variable '{0}' is already used by another member of the iterator", p.Name); } else { var tp = new SeqType(p.Type.IsSubrangeType ? new IntType() : p.Type); var field = new SpecialField(p.tok, nm, nm, "", "", true, true, false, tp, null); @@ -1108,7 +1026,7 @@ namespace Microsoft.Dafny iter.Member_MoveNext = moveNext; MemberDecl member; if (members.TryGetValue(init.Name, out member)) { - Error(member.tok, "member name '{0}' is already predefined for this iterator", init.Name); + reporter.Error(MessageSource.Resolver, member.tok, "member name '{0}' is already predefined for this iterator", init.Name); } else { members.Add(init.Name, init); iter.Members.Add(init); @@ -1116,13 +1034,13 @@ namespace Microsoft.Dafny // If the name of the iterator is "Valid" or "MoveNext", one of the following will produce an error message. That // error message may not be as clear as it could be, but the situation also seems unlikely to ever occur in practice. if (members.TryGetValue("Valid", out member)) { - Error(member.tok, "member name 'Valid' is already predefined for iterators"); + reporter.Error(MessageSource.Resolver, member.tok, "member name 'Valid' is already predefined for iterators"); } else { members.Add(valid.Name, valid); iter.Members.Add(valid); } if (members.TryGetValue("MoveNext", out member)) { - Error(member.tok, "member name 'MoveNext' is already predefined for iterators"); + reporter.Error(MessageSource.Resolver, member.tok, "member name 'MoveNext' is already predefined for iterators"); } else { members.Add(moveNext.Name, moveNext); iter.Members.Add(moveNext); @@ -1140,7 +1058,7 @@ namespace Microsoft.Dafny members.Add(m.Name, m); if (m is Constructor) { if (cl is TraitDecl) { - Error(m.tok, "a trait is not allowed to declare a constructor"); + reporter.Error(MessageSource.Resolver, m.tok, "a trait is not allowed to declare a constructor"); } else { cl.HasConstructor = true; } @@ -1196,9 +1114,9 @@ namespace Microsoft.Dafny members.Add(extraName, extraMember); } } else if (m is Constructor && !((Constructor)m).HasName) { - Error(m, "More than one anonymous constructor"); + reporter.Error(MessageSource.Resolver, m, "More than one anonymous constructor"); } else { - Error(m, "Duplicate member name: {0}", m.Name); + reporter.Error(MessageSource.Resolver, m, "Duplicate member name: {0}", m.Name); } } if (cl.IsDefaultClass) { @@ -1222,9 +1140,9 @@ namespace Microsoft.Dafny foreach (DatatypeCtor ctor in dt.Ctors) { if (ctor.Name.EndsWith("?")) { - Error(ctor, "a datatype constructor name is not allowed to end with '?'"); + reporter.Error(MessageSource.Resolver, ctor, "a datatype constructor name is not allowed to end with '?'"); } else if (ctors.ContainsKey(ctor.Name)) { - Error(ctor, "Duplicate datatype constructor name: {0}", ctor.Name); + reporter.Error(MessageSource.Resolver, ctor, "Duplicate datatype constructor name: {0}", ctor.Name); } else { ctors.Add(ctor.Name, ctor); @@ -1251,7 +1169,7 @@ namespace Microsoft.Dafny foreach (var formal in ctor.Formals) { bool nameError = false; if (formal.HasName && members.ContainsKey(formal.Name)) { - Error(ctor, "Name of deconstructor is used by another member of the datatype: {0}", formal.Name); + reporter.Error(MessageSource.Resolver, ctor, "Name of deconstructor is used by another member of the datatype: {0}", formal.Name); nameError = true; } var dtor = new DatatypeDestructor(formal.tok, ctor, formal, formal.Name, "dtor_" + formal.CompileName, "", "", formal.IsGhost, formal.Type, null); @@ -1301,8 +1219,7 @@ namespace Microsoft.Dafny } - public static bool ResolvePath(ModuleDecl root, List Path, out ModuleSignature p, ResolutionErrorReporter reporter) { - Contract.Requires(reporter != null); + public static bool ResolvePath(ModuleDecl root, List Path, out ModuleSignature p, ErrorReporter reporter) { p = root.Signature; int i = 1; while (i < Path.Count) { @@ -1311,7 +1228,7 @@ namespace Microsoft.Dafny p = pp; i++; } else { - reporter.Error(Path[i], ModuleNotFoundErrorMessage(i, Path)); + reporter.Error(MessageSource.Resolver, Path[i], ModuleNotFoundErrorMessage(i, Path)); break; } } @@ -1366,7 +1283,7 @@ namespace Microsoft.Dafny { if (!(def.IsDefaultModule)) // _module is allowed to contain abstract modules, but not be abstract itself. Note this presents a challenge to // trusted verification, as toplevels can't be trusted if they invoke abstract module members. - Error(d.tok, "an abstract module can only be imported into other abstract modules, not a concrete one."); + reporter.Error(MessageSource.Resolver, d.tok, "an abstract module can only be imported into other abstract modules, not a concrete one."); } else { // physical modules are allowed everywhere } @@ -1392,7 +1309,7 @@ namespace Microsoft.Dafny if (cycle != null) { Contract.Assert(cycle.Count != 0); var erste = cycle[0]; - Error(erste.Tok, "Cycle among redirecting types (newtypes, type synonyms): {0} -> {1}", Util.Comma(" -> ", cycle, syn => syn.Name), erste.Name); + reporter.Error(MessageSource.Resolver, erste.Tok, "Cycle among redirecting types (newtypes, type synonyms): {0} -> {1}", Util.Comma(" -> ", cycle, syn => syn.Name), erste.Name); } } @@ -1416,14 +1333,14 @@ namespace Microsoft.Dafny new NativeType("long", Int64.MinValue, 0x8000000000000000, "L", false), }; - public void ResolveTopLevelDecls_Meat(List/*!*/ declarations, Graph/*!*/ datatypeDependencies, Graph/*!*/ codatatypeDependencies) { + public void ResolveTopLevelDecls_Core(List/*!*/ declarations, Graph/*!*/ datatypeDependencies, Graph/*!*/ codatatypeDependencies) { Contract.Requires(declarations != null); Contract.Requires(cce.NonNullElements(datatypeDependencies)); Contract.Requires(cce.NonNullElements(codatatypeDependencies)); Contract.Requires(NFBC_Count == 0); Contract.Ensures(NFBC_Count == 0); - int prevErrorCount = ErrorCount; + int prevErrorCount = reporter.Count(ErrorLevel.Error); // Resolve the meat of classes and iterators, the definitions of type synonyms, and the type parameters of all top-level type declarations // First, resolve the newtype declarations and the constraint clauses, including filling in .ResolvedOp fields. This is needed for the @@ -1438,7 +1355,7 @@ namespace Microsoft.Dafny ResolveAttributes(d.Attributes, new ResolveOpts(new NoContext(d.Module), false)); // this check can be done only after it has been determined that the redirected types do not involve cycles if (!dd.BaseType.IsNumericBased()) { - Error(dd.tok, "newtypes must be based on some numeric type (got {0})", dd.BaseType); + reporter.Error(MessageSource.Resolver, dd.tok, "newtypes must be based on some numeric type (got {0})", dd.BaseType); } // type check the constraint, if any if (dd.Var != null) { @@ -1451,10 +1368,10 @@ namespace Microsoft.Dafny ResolveExpression(dd.Constraint, new ResolveOpts(dd, false, true)); Contract.Assert(dd.Constraint.Type != null); // follows from postcondition of ResolveExpression if (!UnifyTypes(dd.Constraint.Type, Type.Bool)) { - Error(dd.Constraint, "newtype constraint must be of type bool (instead got {0})", dd.Constraint.Type); + reporter.Error(MessageSource.Resolver, dd.Constraint, "newtype constraint must be of type bool (instead got {0})", dd.Constraint.Type); } if (!CheckTypeInference_Visitor.IsDetermined(dd.BaseType.NormalizeExpand())) { - Error(dd.tok, "newtype's base type is not fully determined; add an explicit type for '{0}'", dd.Var.Name); + reporter.Error(MessageSource.Resolver, dd.tok, "newtype's base type is not fully determined; add an explicit type for '{0}'", dd.Var.Name); } CheckTypeInference(dd.Constraint); scope.PopMarker(); @@ -1464,7 +1381,7 @@ namespace Microsoft.Dafny // Now, we're ready for the other declarations. foreach (TopLevelDecl d in declarations) { if (d is TraitDecl && d.TypeArgs.Count > 0) { - Error(d, "sorry, traits with type parameters are not supported"); + reporter.Error(MessageSource.Resolver, d, "sorry, traits with type parameters are not supported"); } allTypeParameters.PushMarker(); ResolveTypeParameters(d.TypeArgs, false, d); @@ -1483,15 +1400,15 @@ namespace Microsoft.Dafny allTypeParameters.PopMarker(); } - if (ErrorCount == prevErrorCount) { + if (reporter.Count(ErrorLevel.Error) == prevErrorCount) { foreach (var e in needFiniteBoundsChecks_SetComprehension) { var missingBounds = new List(); CheckTypeInference(e.Range); // we need to resolve operators before the call to DiscoverBounds - e.Bounds = DiscoverBounds(e.tok, e.BoundVars, e.Range, true, false, missingBounds); + e.Bounds = DiscoverBounds(e.tok, e.BoundVars, e.Range, true, false, missingBounds, reporter); if (missingBounds.Count != 0) { e.MissingBounds = missingBounds; foreach (var bv in e.MissingBounds) { - Error(e, "a set comprehension must produce a finite set, but Dafny's heuristics can't figure out how to produce a bounded set of values for '{0}'", bv.Name); + reporter.Error(MessageSource.Resolver, e, "a set comprehension must produce a finite set, but Dafny's heuristics can't figure out how to produce a bounded set of values for '{0}'", bv.Name); } } } @@ -1501,11 +1418,11 @@ namespace Microsoft.Dafny var constraint = e.RHSs[0]; var missingBounds = new List(); CheckTypeInference(constraint); // we need to resolve operators before the call to DiscoverBounds - var allBounds = DiscoverBoundsAux(e.tok, new List(e.BoundVars), constraint, true, true, true, missingBounds); + var allBounds = DiscoverBoundsAux(e.tok, new List(e.BoundVars), constraint, true, true, true, missingBounds, reporter); if (missingBounds.Count != 0) { e.Constraint_MissingBounds = missingBounds; foreach (var bv in e.Constraint_MissingBounds) { - Error(e, "a non-ghost let-such-that constraint must be compilable, but Dafny's heuristics can't figure out how to produce a bounded set of values for '{0}'", bv.Name); + reporter.Error(MessageSource.Resolver, e, "a non-ghost let-such-that constraint must be compilable, but Dafny's heuristics can't figure out how to produce a bounded set of values for '{0}'", bv.Name); } } else { e.Constraint_Bounds = new List(); @@ -1525,7 +1442,7 @@ namespace Microsoft.Dafny nativeTypeMap.Add(nativeType.Name, nativeType); } - if (ErrorCount == prevErrorCount) { + if (reporter.Count(ErrorLevel.Error) == prevErrorCount) { // Check that type inference went well everywhere; this will also fill in the .ResolvedOp field in binary expressions foreach (TopLevelDecl d in declarations) { if (d is IteratorDecl) { @@ -1547,7 +1464,7 @@ namespace Microsoft.Dafny Attributes.MatchingValueOption.Empty, Attributes.MatchingValueOption.Bool, Attributes.MatchingValueOption.String }, - err => Error(dd, err)); + err => reporter.Error(MessageSource.Resolver, dd, err)); if (hasNativeTypeAttr) { if (nativeTypeAttr is bool) { boolNativeType = (bool)nativeTypeAttr; @@ -1556,16 +1473,16 @@ namespace Microsoft.Dafny if (nativeTypeMap.ContainsKey(keyString)) { stringNativeType = nativeTypeMap[keyString]; } else { - Error(dd, "Unsupported nativeType {0}", keyString); + reporter.Error(MessageSource.Resolver, dd, "Unsupported nativeType {0}", keyString); } } } if (stringNativeType != null || boolNativeType == true) { if (!dd.BaseType.IsNumericBased(Type.NumericPersuation.Int)) { - Error(dd, "nativeType can only be used on integral types"); + reporter.Error(MessageSource.Resolver, dd, "nativeType can only be used on integral types"); } if (dd.Var == null) { - Error(dd, "nativeType can only be used if newtype specifies a constraint"); + reporter.Error(MessageSource.Resolver, dd, "nativeType can only be used if newtype specifies a constraint"); } } if (dd.Var != null) { @@ -1588,7 +1505,7 @@ namespace Microsoft.Dafny }; var missingBounds = new List(); var bounds = DiscoverBounds(dd.Constraint.tok, new List { dd.Var }, dd.Constraint, - true, true, missingBounds); + true, true, missingBounds, reporter); List potentialNativeTypes = (stringNativeType != null) ? new List { stringNativeType } : (boolNativeType == false) ? new List() : @@ -1621,18 +1538,18 @@ namespace Microsoft.Dafny } } if (dd.NativeType == null && (boolNativeType == true || stringNativeType != null)) { - Error(dd, "Dafny's heuristics cannot find a compatible native type. " + + reporter.Error(MessageSource.Resolver, dd, "Dafny's heuristics cannot find a compatible native type. " + "Hint: try writing a newtype constraint of the form 'i:int | lowerBound <= i < upperBound && (...any additional constraints...)'"); } if (dd.NativeType != null && stringNativeType == null) { - ReportAdditionalInformation(dd.tok, "{:nativeType \"" + dd.NativeType.Name + "\"}", dd.tok.val.Length); + reporter.Info(MessageSource.Resolver, dd.tok, "{:nativeType \"" + dd.NativeType.Name + "\"}"); } } } } } - if (ErrorCount == prevErrorCount) { + if (reporter.Count(ErrorLevel.Error) == prevErrorCount) { // fill in the postconditions and bodies of prefix lemmas foreach (var com in ModuleDefinition.AllFixpointLemmas(declarations)) { var prefixLemma = com.PrefixLemma; @@ -1646,7 +1563,7 @@ namespace Microsoft.Dafny foreach (var p in com.Ens) { var coConclusions = new HashSet(); CollectFriendlyCallsInFixpointLemmaSpecification(p.E, true, coConclusions, true); - var subst = new FixpointLemmaSpecificationSubstituter(coConclusions, new IdentifierExpr(k.tok, k.Name), this, true); + var subst = new FixpointLemmaSpecificationSubstituter(coConclusions, new IdentifierExpr(k.tok, k.Name), this.reporter, true); var post = subst.CloneExpr(p.E); prefixLemma.Ens.Add(new MaybeFreeExpression(post, p.IsFree)); } @@ -1656,7 +1573,7 @@ namespace Microsoft.Dafny foreach (var p in com.Req) { var antecedents = new HashSet(); CollectFriendlyCallsInFixpointLemmaSpecification(p.E, true, antecedents, false); - var subst = new FixpointLemmaSpecificationSubstituter(antecedents, new IdentifierExpr(k.tok, k.Name), this, false); + var subst = new FixpointLemmaSpecificationSubstituter(antecedents, new IdentifierExpr(k.tok, k.Name), this.reporter, false); var pre = subst.CloneExpr(p.E); prefixLemma.Req.Add(new MaybeFreeExpression(pre, p.IsFree)); } @@ -1665,7 +1582,7 @@ namespace Microsoft.Dafny Contract.Assume(prefixLemma.Body == null); // this is not supposed to have been filled in before if (com.Body != null) { var kMinusOne = new BinaryExpr(com.tok, BinaryExpr.Opcode.Sub, new IdentifierExpr(k.tok, k.Name), new LiteralExpr(com.tok, 1)); - var subst = new FixpointLemmaBodyCloner(com, kMinusOne, this); + var subst = new FixpointLemmaBodyCloner(com, kMinusOne, this.reporter); var mainBody = subst.CloneBlockStmt(com.Body); var kPositive = new BinaryExpr(com.tok, BinaryExpr.Opcode.Lt, new LiteralExpr(com.tok, 0), new IdentifierExpr(k.tok, k.Name)); var condBody = new IfStmt(com.BodyStartTok, mainBody.EndTok, kPositive, mainBody, null); @@ -1699,7 +1616,7 @@ namespace Microsoft.Dafny } } - if (ErrorCount == prevErrorCount) { // because CheckCoCalls requires the given expression to have been successfully resolved + if (reporter.Count(ErrorLevel.Error) == prevErrorCount) { // because CheckCoCalls requires the given expression to have been successfully resolved // Perform the guardedness check on co-datatypes foreach (var repr in ModuleDefinition.AllFunctionSCCs(declarations)) { var module = repr.EnclosingModule; @@ -1734,7 +1651,7 @@ namespace Microsoft.Dafny foreach (var c in coCandidates) { c.CandidateCall.CoCall = FunctionCallExpr.CoCallResolution.Yes; c.EnclosingCoConstructor.IsCoCall = true; - ReportAdditionalInformation(c.CandidateCall.tok, "co-recursive call", c.CandidateCall.Name.Length); + reporter.Info(MessageSource.Resolver, c.CandidateCall.tok, "co-recursive call"); } // Finally, fill in the CoClusterTarget field // Start by setting all the CoClusterTarget fields to CoRecursiveTargetAllTheWay. @@ -1929,11 +1846,11 @@ namespace Microsoft.Dafny // Check here for the presence of any 'ensures' clauses, which are not allowed (because we're not sure // of their soundness) if (fn.Ens.Count != 0) { - Error(fn.Ens[0].tok, "a {0} is not allowed to declare any ensures clause", member.WhatKind); + reporter.Error(MessageSource.Resolver, fn.Ens[0].tok, "a {0} is not allowed to declare any ensures clause", member.WhatKind); } // Also check for 'reads' clauses if (fn.Reads.Count != 0) { - Error(fn.Reads[0].tok, "a {0} is not allowed to declare any reads clause", member.WhatKind); // (why?) + reporter.Error(MessageSource.Resolver, fn.Reads[0].tok, "a {0} is not allowed to declare any reads clause", member.WhatKind); // (why?) } if (fn.Body != null) { FixpointPredicateChecks(fn.Body, fn, CallingPosition.Positive); @@ -1949,7 +1866,7 @@ namespace Microsoft.Dafny var dd = (NewtypeDecl)d; if (dd.Module.CallGraph.GetSCCSize(dd) != 1) { var cycle = Util.Comma(" -> ", dd.Module.CallGraph.GetSCC(dd), clbl => clbl.NameRelativeToModule); - Error(dd.tok, "recursive dependency involving a newtype: " + cycle); + reporter.Error(MessageSource.Resolver, dd.tok, "recursive dependency involving a newtype: " + cycle); } } } @@ -1967,45 +1884,14 @@ namespace Microsoft.Dafny Contract.Requires(resolver != null); this.resolver = resolver; } - public void Error(IToken tok, string msg, params object[] args) { - Contract.Requires(tok != null); - Contract.Requires(msg != null); - Contract.Requires(args != null); - resolver.Error(tok, msg, args); - } - public void Error(Expression expr, string msg, params object[] args) { - Contract.Requires(expr != null); - Contract.Requires(msg != null); - Contract.Requires(args != null); - Error(expr.tok, msg, args); - } } abstract class ResolverTopDownVisitor : TopDownVisitor { - Resolver resolver; + protected Resolver resolver; public ResolverTopDownVisitor(Resolver resolver) { Contract.Requires(resolver != null); this.resolver = resolver; } - protected void Error(IToken tok, string msg, params object[] args) - { - Contract.Requires(tok != null); - Contract.Requires(msg != null); - Contract.Requires(args != null); - resolver.Error(tok, msg, args); - } - protected void Error(Expression expr, string msg, params object[] args) - { - Contract.Requires(expr != null); - Contract.Requires(msg != null); - Contract.Requires(args != null); - Error(expr.tok, msg, args); - } - protected void ReportAdditionalInformation(IToken tok, string text, int length) - { - Contract.Requires(tok != null); - resolver.ReportAdditionalInformation(tok, text, length); - } } #endregion Visitors @@ -2027,12 +1913,12 @@ namespace Microsoft.Dafny if (hasTailRecursionPreference && !tail) { // the user specifically requested no tail recursion, so do nothing else } else if (hasTailRecursionPreference && tail && m.IsGhost) { - Error(m.tok, "tail recursion can be specified only for methods that will be compiled, not for ghost methods"); + reporter.Error(MessageSource.Resolver, m.tok, "tail recursion can be specified only for methods that will be compiled, not for ghost methods"); } else { var module = m.EnclosingClass.Module; var sccSize = module.CallGraph.GetSCCSize(m); if (hasTailRecursionPreference && 2 <= sccSize) { - Error(m.tok, "sorry, tail-call optimizations are not supported for mutually recursive methods"); + reporter.Error(MessageSource.Resolver, m.tok, "sorry, tail-call optimizations are not supported for mutually recursive methods"); } else if (hasTailRecursionPreference || sccSize == 1) { CallStmt tailCall = null; var status = CheckTailRecursive(m.Body.Body, m, ref tailCall, hasTailRecursionPreference); @@ -2040,7 +1926,7 @@ namespace Microsoft.Dafny m.IsTailRecursive = true; if (tailCall != null) { // this means there was at least one recursive call - ReportAdditionalInformation(m.tok, "tail recursive", m.Name.Length); + reporter.Info(MessageSource.Resolver, m.tok, "tail recursive"); } } } @@ -2048,7 +1934,7 @@ namespace Microsoft.Dafny } } else if (member is Function) { var f = (Function)member; - var errorCount = ErrorCount; + var errorCount = reporter.Count(ErrorLevel.Error); f.Req.Iter(CheckTypeInference); f.Ens.Iter(CheckTypeInference); f.Reads.Iter(fe => CheckTypeInference(fe.E)); @@ -2057,10 +1943,10 @@ namespace Microsoft.Dafny CheckTypeInference(f.Body); bool tail = true; if (Attributes.ContainsBool(f.Attributes, "tailrecursion", ref tail) && tail) { - Error(f.tok, "sorry, tail-call functions are not supported"); + reporter.Error(MessageSource.Resolver, f.tok, "sorry, tail-call functions are not supported"); } } - if (errorCount == ErrorCount && f is FixpointPredicate) { + if (errorCount == reporter.Count(ErrorLevel.Error) && f is FixpointPredicate) { var cop = (FixpointPredicate)f; CheckTypeInference_Member(cop.PrefixPredicate); } @@ -2120,7 +2006,7 @@ namespace Microsoft.Dafny if (e != null) { foreach (var bv in e.BoundVars) { if (!IsDetermined(bv.Type.Normalize())) { - Error(bv.tok, "type of bound variable '{0}' could not be determined; please specify the type explicitly", + resolver.reporter.Error(MessageSource.Resolver, bv.tok, "type of bound variable '{0}' could not be determined; please specify the type explicitly", bv.Name); } } @@ -2130,7 +2016,7 @@ namespace Microsoft.Dafny if (e.Member is Function || e.Member is Method) { foreach (var p in e.TypeApplication) { if (!IsDetermined(p.Normalize())) { - Error(e.tok, "type '{0}' to the {2} '{1}' is not determined", p, e.Member.Name, e.Member.WhatKind); + resolver.reporter.Error(MessageSource.Resolver, e.tok, "type '{0}' to the {2} '{1}' is not determined", p, e.Member.Name, e.Member.WhatKind); } } } @@ -2138,7 +2024,7 @@ namespace Microsoft.Dafny var e = (FunctionCallExpr)expr; foreach (var p in e.TypeArgumentSubstitutions) { if (!IsDetermined(p.Value.Normalize())) { - Error(e.tok, "type variable '{0}' in the function call to '{1}' could not be determined{2}", p.Key.Name, e.Name, + resolver.reporter.Error(MessageSource.Resolver, e.tok, "type variable '{0}' in the function call to '{1}' could not be determined{2}", p.Key.Name, e.Name, (e.Name.Contains("reveal_") || e.Name.Contains("_FULL")) //CLEMENT should this be StartsWith and EndsWith? ? ". If you are making an opaque function, make sure that the function can be called." : "" @@ -2150,7 +2036,7 @@ namespace Microsoft.Dafny foreach (var p in e.LHSs) { foreach (var x in p.Vars) { if (!IsDetermined(x.Type.Normalize())) { - Error(e.tok, "the type of the bound variable '{0}' could not be determined", x.Name); + resolver.reporter.Error(MessageSource.Resolver, e.tok, "the type of the bound variable '{0}' could not be determined", x.Name); } } } @@ -2218,7 +2104,7 @@ namespace Microsoft.Dafny var proxy = (TypeProxy)t; if (!UnderspecifiedTypeProxies.Contains(proxy)) { // report an error for this TypeProxy only once - Error(tok, "the type of this {0} is underspecified", what); + resolver.reporter.Error(MessageSource.Resolver, tok, "the type of this {0} is underspecified", what); UnderspecifiedTypeProxies.Add(proxy); } return false; @@ -2274,7 +2160,7 @@ namespace Microsoft.Dafny if (status == TailRecursionStatus.TailCallSpent) { // a tail call cannot be followed by non-ghost code if (reportErrors) { - Error(tailCall.Tok, "this recursive call is not recognized as being tail recursive, because it is followed by non-ghost code"); + reporter.Error(MessageSource.Resolver, tailCall.Tok, "this recursive call is not recognized as being tail recursive, because it is followed by non-ghost code"); } return TailRecursionStatus.NotTailRecursive; } @@ -2322,7 +2208,7 @@ namespace Microsoft.Dafny // all is good } else { if (reportErrors) { - Error(s.Tok, "the recursive call to '{0}' is not tail recursive because the actual out-parameter {1} is not the formal out-parameter '{2}'", s.Method.Name, i, formal.Name); + reporter.Error(MessageSource.Resolver, s.Tok, "the recursive call to '{0}' is not tail recursive because the actual out-parameter {1} is not the formal out-parameter '{2}'", s.Method.Name, i, formal.Name); } return TailRecursionStatus.NotTailRecursive; } @@ -2368,7 +2254,7 @@ namespace Microsoft.Dafny if (status == TailRecursionStatus.NotTailRecursive) { // an error has already been reported } else if (reportErrors) { - Error(tailCall.Tok, "a recursive call inside a loop is not recognized as being a tail call"); + reporter.Error(MessageSource.Resolver, tailCall.Tok, "a recursive call inside a loop is not recognized as being a tail call"); } return TailRecursionStatus.NotTailRecursive; } @@ -2380,7 +2266,7 @@ namespace Microsoft.Dafny if (status == TailRecursionStatus.NotTailRecursive) { // an error has already been reported } else if (reportErrors) { - Error(tailCall.Tok, "a recursive call inside a loop is not recognized as being a tail call"); + reporter.Error(MessageSource.Resolver, tailCall.Tok, "a recursive call inside a loop is not recognized as being a tail call"); } return TailRecursionStatus.NotTailRecursive; } @@ -2395,7 +2281,7 @@ namespace Microsoft.Dafny if (status == TailRecursionStatus.NotTailRecursive) { // an error has already been reported } else if (reportErrors) { - Error(tailCall.Tok, "a recursive call inside a forall statement is not a tail call"); + reporter.Error(MessageSource.Resolver, tailCall.Tok, "a recursive call inside a forall statement is not a tail call"); } return TailRecursionStatus.NotTailRecursive; } @@ -2432,7 +2318,7 @@ namespace Microsoft.Dafny // ------------------------------------------------------------------------------------------------------ #region FuelAdjustmentChecks - protected static void CheckForFuelAdjustments(IToken tok, Attributes attrs, ModuleDefinition currentModule, ResolutionErrorReporter reporter) { + protected void CheckForFuelAdjustments(IToken tok, Attributes attrs, ModuleDefinition currentModule) { List> results = Attributes.FindAllExpressions(attrs, "fuel"); if (results != null) { @@ -2445,7 +2331,7 @@ namespace Microsoft.Dafny if (f != null) { f.IsFueled = true; if (f.IsProtected && currentModule != f.EnclosingClass.Module) { - reporter.Error(tok, "cannot adjust fuel for protected function {0} from another module", f.Name); + reporter.Error(MessageSource.Resolver, tok, "cannot adjust fuel for protected function {0} from another module", f.Name); } } } @@ -2457,10 +2343,8 @@ namespace Microsoft.Dafny public class FuelAdjustment_Context { public ModuleDefinition currentModule; - public ResolutionErrorReporter reporter; - public FuelAdjustment_Context(ModuleDefinition currentModule, ResolutionErrorReporter reporter) { + public FuelAdjustment_Context(ModuleDefinition currentModule) { this.currentModule = currentModule; - this.reporter = reporter; } } @@ -2472,7 +2356,7 @@ namespace Microsoft.Dafny } protected override bool VisitOneStmt(Statement stmt, ref FuelAdjustment_Context st) { - Resolver.CheckForFuelAdjustments(stmt.Tok, stmt.Attributes, st.currentModule, st.reporter); + resolver.CheckForFuelAdjustments(stmt.Tok, stmt.Attributes, st.currentModule); return true; } } @@ -2594,7 +2478,7 @@ namespace Microsoft.Dafny var article = context is InductivePredicate ? "an" : "a"; // we're looking at a recursive call if (!(context is InductivePredicate ? e.Function is InductivePredicate : e.Function is CoPredicate)) { - Error(e, "a recursive call from {0} {1} can go only to other {1}s", article, context.WhatKind); + resolver.reporter.Error(MessageSource.Resolver, e, "a recursive call from {0} {1} can go only to other {1}s", article, context.WhatKind); } else if (cp != CallingPosition.Positive) { var msg = string.Format("{0} {1} can be called recursively only in positive positions", article, context.WhatKind); if (cp == CallingPosition.Neither) { @@ -2603,10 +2487,10 @@ namespace Microsoft.Dafny } else { // the fixpoint-call is not inside an quantifier, so don't bother mentioning the part of existentials/universals in the error message } - Error(e, msg); + resolver.reporter.Error(MessageSource.Resolver, e, msg); } else { e.CoCall = FunctionCallExpr.CoCallResolution.Yes; - ReportAdditionalInformation(e.tok, e.Function.Name + "#[_k - 1]", e.Function.Name.Length); + resolver.reporter.Info(MessageSource.Resolver, e.tok, e.Function.Name + "#[_k - 1]"); } } // do the sub-parts with cp := Neither @@ -2621,7 +2505,7 @@ namespace Microsoft.Dafny if (ModuleDefinition.InSameSCC(context, s.Method)) { // we're looking at a recursive call var article = context is InductivePredicate ? "an" : "a"; - Error(stmt.Tok, "a recursive call from {0} {1} can go only to other {1}s", article, context.WhatKind); + resolver.reporter.Error(MessageSource.Resolver, stmt.Tok, "a recursive call from {0} {1} can go only to other {1}s", article, context.WhatKind); } // do the sub-parts with the same "cp" return true; @@ -2662,7 +2546,7 @@ namespace Microsoft.Dafny if (ModuleDefinition.InSameSCC(context, s.Method)) { // we're looking at a recursive call (to a non-fixpoint-lemma) var article = context is InductiveLemma ? "an" : "a"; - Error(s.Tok, "a recursive call from {0} {1} can go only to other {1}s and prefix lemmas", article, context.WhatKind); + resolver.reporter.Error(MessageSource.Resolver, s.Tok, "a recursive call from {0} {1} can go only to other {1}s and prefix lemmas", article, context.WhatKind); } } } @@ -2674,7 +2558,7 @@ namespace Microsoft.Dafny // the call goes from a colemma context to a non-colemma callee if (ModuleDefinition.InSameSCC(context, e.Function)) { // we're looking at a recursive call (to a non-colemma) - Error(e.tok, "a recursive call from a colemma can go only to other colemmas and prefix lemmas"); + resolver.reporter.Error(MessageSource.Resolver, e.tok, "a recursive call from a colemma can go only to other colemmas and prefix lemmas"); } } } @@ -2733,7 +2617,7 @@ namespace Microsoft.Dafny foreach (var formalTypeArg in s.Method.TypeArgs) { var actualTypeArg = s.MethodSelect.TypeArgumentSubstitutions()[formalTypeArg]; if (formalTypeArg.MustSupportEquality && !actualTypeArg.SupportsEquality) { - Error(s.Tok, "type parameter {0} ({1}) passed to method {2} must support equality (got {3}){4}", i, formalTypeArg.Name, s.Method.Name, actualTypeArg, TypeEqualityErrorMessageHint(actualTypeArg)); + resolver.reporter.Error(MessageSource.Resolver, s.Tok, "type parameter {0} ({1}) passed to method {2} must support equality (got {3}){4}", i, formalTypeArg.Name, s.Method.Name, actualTypeArg, TypeEqualityErrorMessageHint(actualTypeArg)); } i++; } @@ -2788,9 +2672,9 @@ namespace Microsoft.Dafny } else if (e1 != null && e1.Arguments.Count == 0) { // oh yeah! } else if (!t0.SupportsEquality) { - Error(e.E0, "{0} can only be applied to expressions of types that support equality (got {1}){2}", BinaryExpr.OpcodeString(e.Op), t0, TypeEqualityErrorMessageHint(t0)); + resolver.reporter.Error(MessageSource.Resolver, e.E0, "{0} can only be applied to expressions of types that support equality (got {1}){2}", BinaryExpr.OpcodeString(e.Op), t0, TypeEqualityErrorMessageHint(t0)); } else if (!t1.SupportsEquality) { - Error(e.E1, "{0} can only be applied to expressions of types that support equality (got {1}){2}", BinaryExpr.OpcodeString(e.Op), t1, TypeEqualityErrorMessageHint(t1)); + resolver.reporter.Error(MessageSource.Resolver, e.E1, "{0} can only be applied to expressions of types that support equality (got {1}){2}", BinaryExpr.OpcodeString(e.Op), t1, TypeEqualityErrorMessageHint(t1)); } break; default: @@ -2803,12 +2687,12 @@ namespace Microsoft.Dafny case BinaryExpr.ResolvedOpcode.Prefix: case BinaryExpr.ResolvedOpcode.ProperPrefix: if (!t1.SupportsEquality) { - Error(e.E1, "{0} can only be applied to expressions of sequence types that support equality (got {1}){2}", BinaryExpr.OpcodeString(e.Op), t1, TypeEqualityErrorMessageHint(t1)); + resolver.reporter.Error(MessageSource.Resolver, e.E1, "{0} can only be applied to expressions of sequence types that support equality (got {1}){2}", BinaryExpr.OpcodeString(e.Op), t1, TypeEqualityErrorMessageHint(t1)); } else if (!t0.SupportsEquality) { if (e.ResolvedOp == BinaryExpr.ResolvedOpcode.InSet || e.ResolvedOp == BinaryExpr.ResolvedOpcode.NotInSeq) { - Error(e.E0, "{0} can only be applied to expressions of types that support equality (got {1}){2}", BinaryExpr.OpcodeString(e.Op), t0, TypeEqualityErrorMessageHint(t0)); + resolver.reporter.Error(MessageSource.Resolver, e.E0, "{0} can only be applied to expressions of types that support equality (got {1}){2}", BinaryExpr.OpcodeString(e.Op), t0, TypeEqualityErrorMessageHint(t0)); } else { - Error(e.E0, "{0} can only be applied to expressions of sequence types that support equality (got {1}){2}", BinaryExpr.OpcodeString(e.Op), t0, TypeEqualityErrorMessageHint(t0)); + resolver.reporter.Error(MessageSource.Resolver, e.E0, "{0} can only be applied to expressions of sequence types that support equality (got {1}){2}", BinaryExpr.OpcodeString(e.Op), t0, TypeEqualityErrorMessageHint(t0)); } } break; @@ -2834,7 +2718,7 @@ namespace Microsoft.Dafny foreach (var tp in ((ICallable)e.Member).TypeArgs) { var actualTp = e.TypeApplication[e.Member.EnclosingClass.TypeArgs.Count + i]; if (tp.MustSupportEquality && !actualTp.SupportsEquality) { - Error(e.tok, "type parameter {0} ({1}) passed to {5} '{2}' must support equality (got {3}){4}", i, tp.Name, e.Member.Name, actualTp, TypeEqualityErrorMessageHint(actualTp), e.Member.WhatKind); + resolver.reporter.Error(MessageSource.Resolver, e.tok, "type parameter {0} ({1}) passed to {5} '{2}' must support equality (got {3}){4}", i, tp.Name, e.Member.Name, actualTp, TypeEqualityErrorMessageHint(actualTp), e.Member.WhatKind); } i++; } @@ -2846,7 +2730,7 @@ namespace Microsoft.Dafny foreach (var formalTypeArg in e.Function.TypeArgs) { var actualTypeArg = e.TypeArgumentSubstitutions[formalTypeArg]; if (formalTypeArg.MustSupportEquality && !actualTypeArg.SupportsEquality) { - Error(e.tok, "type parameter {0} ({1}) passed to function {2} must support equality (got {3}){4}", i, formalTypeArg.Name, e.Function.Name, actualTypeArg, TypeEqualityErrorMessageHint(actualTypeArg)); + resolver.reporter.Error(MessageSource.Resolver, e.tok, "type parameter {0} ({1}) passed to function {2} must support equality (got {3}){4}", i, formalTypeArg.Name, e.Function.Name, actualTypeArg, TypeEqualityErrorMessageHint(actualTypeArg)); } i++; } @@ -2878,21 +2762,21 @@ namespace Microsoft.Dafny var st = (SetType)type; var argType = st.Arg; if (!argType.SupportsEquality) { - Error(tok, "{2}set argument type must support equality (got {0}){1}", argType, TypeEqualityErrorMessageHint(argType), st.Finite ? "" : "i"); + resolver.reporter.Error(MessageSource.Resolver, tok, "{2}set argument type must support equality (got {0}){1}", argType, TypeEqualityErrorMessageHint(argType), st.Finite ? "" : "i"); } CheckEqualityTypes_Type(tok, argType); } else if (type is MultiSetType) { var argType = ((MultiSetType)type).Arg; if (!argType.SupportsEquality) { - Error(tok, "multiset argument type must support equality (got {0}){1}", argType, TypeEqualityErrorMessageHint(argType)); + resolver.reporter.Error(MessageSource.Resolver, tok, "multiset argument type must support equality (got {0}){1}", argType, TypeEqualityErrorMessageHint(argType)); } CheckEqualityTypes_Type(tok, argType); } else if (type is MapType) { var mt = (MapType)type; if (!mt.Domain.SupportsEquality) { - Error(tok, "{2}map domain type must support equality (got {0}){1}", mt.Domain, TypeEqualityErrorMessageHint(mt.Domain), mt.Finite ? "" : "i"); + resolver.reporter.Error(MessageSource.Resolver, tok, "{2}map domain type must support equality (got {0}){1}", mt.Domain, TypeEqualityErrorMessageHint(mt.Domain), mt.Finite ? "" : "i"); } CheckEqualityTypes_Type(tok, mt.Domain); CheckEqualityTypes_Type(tok, mt.Range); @@ -2918,7 +2802,7 @@ namespace Microsoft.Dafny foreach (var argType in udt.TypeArgs) { var formalTypeArg = formalTypeArgs[i]; if (formalTypeArg.MustSupportEquality && !argType.SupportsEquality) { - Error(tok, "type parameter {0} ({1}) passed to type {2} must support equality (got {3}){4}", i, formalTypeArg.Name, udt.ResolvedClass.Name, argType, TypeEqualityErrorMessageHint(argType)); + resolver.reporter.Error(MessageSource.Resolver, tok, "type parameter {0} ({1}) passed to type {2} must support equality (got {3}){4}", i, formalTypeArg.Name, udt.ResolvedClass.Name, argType, TypeEqualityErrorMessageHint(argType)); } CheckEqualityTypes_Type(tok, argType); i++; @@ -3007,10 +2891,10 @@ namespace Microsoft.Dafny for (int i = 0; i < cs.Method.Ins.Count; i++) { argsSubstMap.Add(cs.Method.Ins[i], cs.Args[i]); } - var substituter = new Translator.AlphaConverting_Substituter(cs.Receiver, argsSubstMap, new Dictionary(), new Translator()); + var substituter = new Translator.AlphaConverting_Substituter(cs.Receiver, argsSubstMap, new Dictionary(), new Translator(resolver.reporter)); foreach (var ens in cs.Method.Ens) { var p = substituter.Substitute(ens.E); // substitute the call's actuals for the method's formals - resolver.ReportAdditionalInformation(s.Tok, "ensures " + Printer.ExprToString(p) + ";", s.Tok.val.Length); + resolver.reporter.Info(MessageSource.Resolver, s.Tok, "ensures " + Printer.ExprToString(p) + ";"); } } } @@ -3088,26 +2972,26 @@ namespace Microsoft.Dafny currentClass = cl; if (cl.TraitsTyp.Count > 0 && cl.TypeArgs.Count > 0) { - Error(cl.tok, "sorry, traits are currently supported only for classes that take no type arguments"); // TODO: do the work to remove this limitation + reporter.Error(MessageSource.Resolver, cl.tok, "sorry, traits are currently supported only for classes that take no type arguments"); // TODO: do the work to remove this limitation } // Resolve names of traits extended foreach (var tt in cl.TraitsTyp) { - var prevErrorCount = ErrorCount; + var prevErrorCount = reporter.Count(ErrorLevel.Error); ResolveType(cl.tok, tt, new NoContext(cl.Module), ResolveTypeOptionEnum.DontInfer, null); - if (ErrorCount == prevErrorCount) { + if (reporter.Count(ErrorLevel.Error) == prevErrorCount) { var udt = tt as UserDefinedType; if (udt != null && udt.ResolvedClass is TraitDecl) { var trait = (TraitDecl)udt.ResolvedClass; //disallowing inheritance in multi module case if (cl.Module != trait.Module) { - Error(udt.tok, "class '{0}' is in a different module than trait '{1}'. A class may only extend a trait in the same module.", cl.Name, trait.FullName); + reporter.Error(MessageSource.Resolver, udt.tok, "class '{0}' is in a different module than trait '{1}'. A class may only extend a trait in the same module.", cl.Name, trait.FullName); } else { // all is good cl.TraitsObj.Add(trait); } } else { - Error(udt != null ? udt.tok : cl.tok, "a class can only extend traits (found '{0}')", tt); + reporter.Error(MessageSource.Resolver, udt != null ? udt.tok : cl.tok, "a class can only extend traits (found '{0}')", tt); } } } @@ -3150,12 +3034,12 @@ namespace Microsoft.Dafny } else if (member is Function) { var f = (Function)member; - var ec = ErrorCount; + var ec = reporter.Count(ErrorLevel.Error); allTypeParameters.PushMarker(); ResolveTypeParameters(f.TypeArgs, true, f); ResolveFunctionSignature(f); allTypeParameters.PopMarker(); - if (f is FixpointPredicate && ec == ErrorCount) { + if (f is FixpointPredicate && ec == reporter.Count(ErrorLevel.Error)) { var ff = ((FixpointPredicate)f).PrefixPredicate; ff.EnclosingClass = cl; allTypeParameters.PushMarker(); @@ -3166,13 +3050,13 @@ namespace Microsoft.Dafny } else if (member is Method) { var m = (Method)member; - var ec = ErrorCount; + var ec = reporter.Count(ErrorLevel.Error); allTypeParameters.PushMarker(); ResolveTypeParameters(m.TypeArgs, true, m); ResolveMethodSignature(m); allTypeParameters.PopMarker(); var com = m as FixpointLemma; - if (com != null && com.PrefixLemma != null && ec == ErrorCount) { + if (com != null && com.PrefixLemma != null && ec == reporter.Count(ErrorLevel.Error)) { var mm = com.PrefixLemma; // resolve signature of the prefix lemma mm.EnclosingClass = cl; @@ -3193,7 +3077,7 @@ namespace Microsoft.Dafny void InheritTraitMembers(ClassDecl cl) { Contract.Requires(cl != null); - var refinementTransformer = new RefinementTransformer(this, AdditionalInformationReporter, null); + var refinementTransformer = new RefinementTransformer(reporter); //merging class members with parent members if any var clMembers = classMembers[cl]; foreach (TraitDecl trait in cl.TraitsObj) { @@ -3213,37 +3097,37 @@ namespace Microsoft.Dafny } else if (traitMember is Function) { var func = (Function)traitMember; if (func.Body == null) { - Error(cl.tok, "class '{0}' does not implement trait function '{1}.{2}'", cl.Name, trait.Name, traitMember.Name); + reporter.Error(MessageSource.Resolver, cl.tok, "class '{0}' does not implement trait function '{1}.{2}'", cl.Name, trait.Name, traitMember.Name); } else if (!func.IsGhost && !func.IsStatic) { cl.InheritedMembers.Add(func); } } else if (traitMember is Method) { var method = (Method)traitMember; if (method.Body == null) { - Error(cl.tok, "class '{0}' does not implement trait method '{1}.{2}'", cl.Name, trait.Name, traitMember.Name); + reporter.Error(MessageSource.Resolver, cl.tok, "class '{0}' does not implement trait method '{1}.{2}'", cl.Name, trait.Name, traitMember.Name); } else if (!method.IsGhost && !method.IsStatic) { cl.InheritedMembers.Add(method); } } } else if (clMember.EnclosingClass != cl) { // The class inherits the member from two places - Error(clMember.tok, "member name '{0}' in class '{1}' inherited from both traits '{2}' and '{3}'", traitMember.Name, cl.Name, clMember.EnclosingClass.Name, trait.Name); + reporter.Error(MessageSource.Resolver, clMember.tok, "member name '{0}' in class '{1}' inherited from both traits '{2}' and '{3}'", traitMember.Name, cl.Name, clMember.EnclosingClass.Name, trait.Name); } else if (traitMember is Field) { // The class is not allowed to do anything with the field other than silently inherit it. if (clMember is Field) { - Error(clMember.tok, "field '{0}' is inherited from trait '{1}' and is not allowed to be re-declared", traitMember.Name, trait.Name); + reporter.Error(MessageSource.Resolver, clMember.tok, "field '{0}' is inherited from trait '{1}' and is not allowed to be re-declared", traitMember.Name, trait.Name); } else { - Error(clMember.tok, "member name '{0}' in class '{1}' clashes with inherited field from trait '{2}'", traitMember.Name, cl.Name, trait.Name); + reporter.Error(MessageSource.Resolver, clMember.tok, "member name '{0}' in class '{1}' clashes with inherited field from trait '{2}'", traitMember.Name, cl.Name, trait.Name); } } else if (traitMember is Method) { var traitMethod = (Method)traitMember; if (traitMethod.Body != null) { // The method was defined in the trait, so the class is not allowed to do anything with the method other than silently inherit it. - Error(clMember.tok, "member '{0}' in class '{1}' overrides fully defined method inherited from trait '{2}'", clMember.Name, cl.Name, trait.Name); + reporter.Error(MessageSource.Resolver, clMember.tok, "member '{0}' in class '{1}' overrides fully defined method inherited from trait '{2}'", clMember.Name, cl.Name, trait.Name); } else if (!(clMember is Method)) { - Error(clMember.tok, "non-method member '{0}' overrides method '{1}' inherited from trait '{2}'", clMember.Name, traitMethod.Name, trait.Name); + reporter.Error(MessageSource.Resolver, clMember.tok, "non-method member '{0}' overrides method '{1}' inherited from trait '{2}'", clMember.Name, traitMethod.Name, trait.Name); } else { var classMethod = (Method)clMember; classMethod.OverriddenMethod = traitMethod; @@ -3255,7 +3139,7 @@ namespace Microsoft.Dafny var traitMethodAllowsNonTermination = Contract.Exists(traitMethod.Decreases.Expressions, e => e is WildcardExpr); var classMethodAllowsNonTermination = Contract.Exists(classMethod.Decreases.Expressions, e => e is WildcardExpr); if (classMethodAllowsNonTermination && !traitMethodAllowsNonTermination) { - Error(classMethod.tok, "not allowed to override a terminating method with a possibly non-terminating method ('{0}')", classMethod.Name); + reporter.Error(MessageSource.Resolver, classMethod.tok, "not allowed to override a terminating method with a possibly non-terminating method ('{0}')", classMethod.Name); } } @@ -3263,9 +3147,9 @@ namespace Microsoft.Dafny var traitFunction = (Function)traitMember; if (traitFunction.Body != null) { // The function was defined in the trait, so the class is not allowed to do anything with the function other than silently inherit it. - Error(clMember.tok, "member '{0}' in class '{1}' overrides fully defined function inherited from trait '{2}'", clMember.Name, cl.Name, trait.Name); + reporter.Error(MessageSource.Resolver, clMember.tok, "member '{0}' in class '{1}' overrides fully defined function inherited from trait '{2}'", clMember.Name, cl.Name, trait.Name); } else if (!(clMember is Function)) { - Error(clMember.tok, "non-function member '{0}' overrides function '{1}' inherited from trait '{2}'", clMember.Name, traitFunction.Name, trait.Name); + reporter.Error(MessageSource.Resolver, clMember.tok, "non-function member '{0}' overrides function '{1}' inherited from trait '{2}'", clMember.Name, traitFunction.Name, trait.Name); } else { var classFunction = (Function)clMember; classFunction.OverriddenFunction = traitFunction; @@ -3298,12 +3182,12 @@ namespace Microsoft.Dafny } else if (member is Function) { var f = (Function)member; - var ec = ErrorCount; + var ec = reporter.Count(ErrorLevel.Error); allTypeParameters.PushMarker(); ResolveTypeParameters(f.TypeArgs, false, f); ResolveFunction(f); allTypeParameters.PopMarker(); - if (f is FixpointPredicate && ec == ErrorCount) { + if (f is FixpointPredicate && ec == reporter.Count(ErrorLevel.Error)) { var ff = ((FixpointPredicate)f).PrefixPredicate; allTypeParameters.PushMarker(); ResolveTypeParameters(ff.TypeArgs, false, ff); @@ -3313,7 +3197,7 @@ namespace Microsoft.Dafny } else if (member is Method) { var m = (Method)member; - var ec = ErrorCount; + var ec = reporter.Count(ErrorLevel.Error); allTypeParameters.PushMarker(); ResolveTypeParameters(m.TypeArgs, false, m); ResolveMethod(m); @@ -3420,7 +3304,7 @@ namespace Microsoft.Dafny // whatever is in scc-cleared now failed to pass the test foreach (var dt in scc) { if (dt.DefaultCtor == null) { - Error(dt, "because of cyclic dependencies among constructor argument types, no instances of datatype '{0}' can be constructed", dt.Name); + reporter.Error(MessageSource.Resolver, dt, "because of cyclic dependencies among constructor argument types, no instances of datatype '{0}' can be constructed", dt.Name); } } return; @@ -3598,12 +3482,12 @@ namespace Microsoft.Dafny Contract.Requires(args != null); foreach (var arg in args) { Contract.Assert(arg != null); - int prevErrors = ErrorCount; + int prevErrors = reporter.Count(ErrorLevel.Error); ResolveExpression(arg, opts); if (!allowGhosts) { CheckIsNonGhost(arg); } - if (prevErrors == ErrorCount) { + if (prevErrors == reporter.Count(ErrorLevel.Error)) { CheckTypeInference(arg); } } @@ -3623,9 +3507,9 @@ namespace Microsoft.Dafny var r = allTypeParameters.Push(tp.Name, tp); if (emitErrors) { if (r == Scope.PushResult.Duplicate) { - Error(tp, "Duplicate type-parameter name: {0}", tp.Name); + reporter.Error(MessageSource.Resolver, tp, "Duplicate type-parameter name: {0}", tp.Name); } else if (r == Scope.PushResult.Shadow) { - Warning(tp.tok, "Shadowed type-parameter name: {0}", tp.Name); + reporter.Warning(MessageSource.Resolver, tp.tok, "Shadowed type-parameter name: {0}", tp.Name); } } } @@ -3649,10 +3533,10 @@ namespace Microsoft.Dafny case Scope.PushResult.Success: break; case Scope.PushResult.Duplicate: - Error(tok, "Duplicate {0} name: {1}", kind, name); + reporter.Error(MessageSource.Resolver, tok, "Duplicate {0} name: {1}", kind, name); break; case Scope.PushResult.Shadow: - Warning(tok, "Shadowed {0} name: {1}", kind, name); + reporter.Warning(MessageSource.Resolver, tok, "Shadowed {0} name: {1}", kind, name); break; } } @@ -3664,7 +3548,7 @@ namespace Microsoft.Dafny Contract.Requires(f != null); scope.PushMarker(); if (f.SignatureIsOmitted) { - Error(f, "function signature can be omitted only in refining functions"); + reporter.Error(MessageSource.Resolver, f, "function signature can be omitted only in refining functions"); } var option = f.TypeArgs.Count == 0 ? new ResolveTypeOption(f) : new ResolveTypeOption(ResolveTypeOptionEnum.AllowPrefix); foreach (Formal p in f.Formals) { @@ -3692,7 +3576,7 @@ namespace Microsoft.Dafny ResolveExpression(r, new ResolveOpts(f, false, true)); Contract.Assert(r.Type != null); // follows from postcondition of ResolveExpression if (!UnifyTypes(r.Type, Type.Bool)) { - Error(r, "Precondition must be a boolean (got {0})", r.Type); + reporter.Error(MessageSource.Resolver, r, "Precondition must be a boolean (got {0})", r.Type); } } foreach (FrameExpression fr in f.Reads) { @@ -3702,7 +3586,7 @@ namespace Microsoft.Dafny ResolveExpression(r, new ResolveOpts(f, false, true)); // since this is a function, the postcondition is still a one-state predicate Contract.Assert(r.Type != null); // follows from postcondition of ResolveExpression if (!UnifyTypes(r.Type, Type.Bool)) { - Error(r, "Postcondition must be a boolean (got {0})", r.Type); + reporter.Error(MessageSource.Resolver, r, "Postcondition must be a boolean (got {0})", r.Type); } } ResolveAttributes(f.Decreases.Attributes, new ResolveOpts(f, false, true)); @@ -3711,14 +3595,14 @@ namespace Microsoft.Dafny // any type is fine } if (f.Body != null) { - var prevErrorCount = ErrorCount; + var prevErrorCount = reporter.Count(ErrorLevel.Error); ResolveExpression(f.Body, new ResolveOpts(f, false)); - if (!f.IsGhost && prevErrorCount == ErrorCount) { + if (!f.IsGhost && prevErrorCount == reporter.Count(ErrorLevel.Error)) { CheckIsNonGhost(f.Body); } Contract.Assert(f.Body.Type != null); // follows from postcondition of ResolveExpression if (!UnifyTypes(f.Body.Type, f.ResultType)) { - Error(f, "Function body type mismatch (expected {0}, got {1})", f.ResultType, f.Body.Type); + reporter.Error(MessageSource.Resolver, f, "Function body type mismatch (expected {0}, got {1})", f.ResultType, f.Body.Type); } } scope.PopMarker(); @@ -3746,7 +3630,7 @@ namespace Microsoft.Dafny t = collType.Arg; } if (!UnifyTypes(t, new ObjectType())) { - Error(fe.E, "a {0}-clause expression must denote an object or a collection of objects (instead got {1})", readsFrame ? "reads" : "modifies", fe.E.Type); + reporter.Error(MessageSource.Resolver, fe.E, "a {0}-clause expression must denote an object or a collection of objects (instead got {1})", readsFrame ? "reads" : "modifies", fe.E.Type); } else if (fe.FieldName != null) { NonProxyType nptype; MemberDecl member = ResolveMember(fe.E.tok, t, fe.FieldName, out nptype); @@ -3754,9 +3638,9 @@ namespace Microsoft.Dafny if (member == null) { // error has already been reported by ResolveMember } else if (!(member is Field)) { - Error(fe.E, "member {0} in type {1} does not refer to a field", fe.FieldName, ctype.Name); + reporter.Error(MessageSource.Resolver, fe.E, "member {0} in type {1} does not refer to a field", fe.FieldName, ctype.Name); } else if (!readsFrame && isGhostContext && !member.IsGhost) { - Error(fe.E, "in a ghost context, only ghost fields can be mentioned as modifies frame targets ({0})", fe.FieldName); + reporter.Error(MessageSource.Resolver, fe.E, "in a ghost context, only ghost fields can be mentioned as modifies frame targets ({0})", fe.FieldName); } else { Contract.Assert(ctype != null && ctype.ResolvedClass != null); // follows from postcondition of ResolveMember fe.Field = (Field)member; @@ -3771,7 +3655,7 @@ namespace Microsoft.Dafny Contract.Requires(m != null); scope.PushMarker(); if (m.SignatureIsOmitted) { - Error(m, "method signature can be omitted only in refining methods"); + reporter.Error(MessageSource.Resolver, m, "method signature can be omitted only in refining methods"); } var option = m.TypeArgs.Count == 0 ? new ResolveTypeOption(m) : new ResolveTypeOption(ResolveTypeOptionEnum.AllowPrefix); // resolve in-parameters @@ -3812,14 +3696,14 @@ namespace Microsoft.Dafny ResolveExpression(e.E, new ResolveOpts(m, false, true)); Contract.Assert(e.E.Type != null); // follows from postcondition of ResolveExpression if (!UnifyTypes(e.E.Type, Type.Bool)) { - Error(e.E, "Precondition must be a boolean (got {0})", e.E.Type); + reporter.Error(MessageSource.Resolver, e.E, "Precondition must be a boolean (got {0})", e.E.Type); } } ResolveAttributes(m.Mod.Attributes, new ResolveOpts(m, false, true)); foreach (FrameExpression fe in m.Mod.Expressions) { ResolveFrameExpression(fe, false, m.IsGhost, m); if (m is Lemma || m is FixpointLemma) { - Error(fe.tok, "{0}s are not allowed to have modifies clauses", m.WhatKind); + reporter.Error(MessageSource.Resolver, fe.tok, "{0}s are not allowed to have modifies clauses", m.WhatKind); } } ResolveAttributes(m.Decreases.Attributes, new ResolveOpts(m, false, true)); @@ -3827,7 +3711,7 @@ namespace Microsoft.Dafny ResolveExpression(e, new ResolveOpts(m, false, true)); // any type is fine if (m.IsGhost && e is WildcardExpr) { - Error(e, "'decreases *' is not allowed on ghost methods"); + reporter.Error(MessageSource.Resolver, e, "'decreases *' is not allowed on ghost methods"); } } @@ -3835,7 +3719,7 @@ namespace Microsoft.Dafny // Don't care about any duplication errors among the out-parameters, since they have already been reported scope.PushMarker(); if (m is FixpointLemma && m.Outs.Count != 0) { - Error(m.Outs[0].tok, "{0}s are not allowed to have out-parameters", m.WhatKind); + reporter.Error(MessageSource.Resolver, m.Outs[0].tok, "{0}s are not allowed to have out-parameters", m.WhatKind); } else { foreach (Formal p in m.Outs) { scope.Push(p.Name, p); @@ -3848,7 +3732,7 @@ namespace Microsoft.Dafny ResolveExpression(e.E, new ResolveOpts(m, true, true)); Contract.Assert(e.E.Type != null); // follows from postcondition of ResolveExpression if (!UnifyTypes(e.E.Type, Type.Bool)) { - Error(e.E, "Postcondition must be a boolean (got {0})", e.E.Type); + reporter.Error(MessageSource.Resolver, e.E, "Postcondition must be a boolean (got {0})", e.E.Type); } } @@ -3896,7 +3780,7 @@ namespace Microsoft.Dafny Contract.Requires(iter != null); scope.PushMarker(); if (iter.SignatureIsOmitted) { - Error(iter, "iterator signature can be omitted only in refining methods"); + reporter.Error(MessageSource.Resolver, iter, "iterator signature can be omitted only in refining methods"); } var option = iter.TypeArgs.Count == 0 ? new ResolveTypeOption(iter) : new ResolveTypeOption(ResolveTypeOptionEnum.AllowPrefix); // resolve the types of the parameters @@ -3918,7 +3802,7 @@ namespace Microsoft.Dafny Contract.Requires(currentClass == null); Contract.Ensures(currentClass == null); - var initialErrorCount = ErrorCount; + var initialErrorCount = reporter.Count(ErrorLevel.Error); // Add in-parameters to the scope, but don't care about any duplication errors, since they have already been reported scope.PushMarker(); @@ -3937,7 +3821,7 @@ namespace Microsoft.Dafny var d = iter.DecreasesFields[i]; if (!UnifyTypes(d.Type, e.Type)) { // bummer, there was a use--and a bad use--of the field before, so this won't be the best of error messages - Error(e, "type of field {0} is {1}, but has been constrained elsewhere to be of type {2}", d.Name, e.Type, d.Type); + reporter.Error(MessageSource.Resolver, e, "type of field {0} is {1}, but has been constrained elsewhere to be of type {2}", d.Name, e.Type, d.Type); } } foreach (FrameExpression fe in iter.Reads.Expressions) { @@ -3950,7 +3834,7 @@ namespace Microsoft.Dafny ResolveExpression(e.E, new ResolveOpts(iter, false, true)); Contract.Assert(e.E.Type != null); // follows from postcondition of ResolveExpression if (!UnifyTypes(e.E.Type, Type.Bool)) { - Error(e.E, "Precondition must be a boolean (got {0})", e.E.Type); + reporter.Error(MessageSource.Resolver, e.E, "Precondition must be a boolean (got {0})", e.E.Type); } } @@ -3966,27 +3850,27 @@ namespace Microsoft.Dafny ResolveExpression(e.E, new ResolveOpts(iter, false, true)); Contract.Assert(e.E.Type != null); // follows from postcondition of ResolveExpression if (!UnifyTypes(e.E.Type, Type.Bool)) { - Error(e.E, "Yield precondition must be a boolean (got {0})", e.E.Type); + reporter.Error(MessageSource.Resolver, e.E, "Yield precondition must be a boolean (got {0})", e.E.Type); } } foreach (MaybeFreeExpression e in iter.YieldEnsures) { ResolveExpression(e.E, new ResolveOpts(iter, true, true)); Contract.Assert(e.E.Type != null); // follows from postcondition of ResolveExpression if (!UnifyTypes(e.E.Type, Type.Bool)) { - Error(e.E, "Yield postcondition must be a boolean (got {0})", e.E.Type); + reporter.Error(MessageSource.Resolver, e.E, "Yield postcondition must be a boolean (got {0})", e.E.Type); } } foreach (MaybeFreeExpression e in iter.Ensures) { ResolveExpression(e.E, new ResolveOpts(iter, true, true)); Contract.Assert(e.E.Type != null); // follows from postcondition of ResolveExpression if (!UnifyTypes(e.E.Type, Type.Bool)) { - Error(e.E, "Postcondition must be a boolean (got {0})", e.E.Type); + reporter.Error(MessageSource.Resolver, e.E, "Postcondition must be a boolean (got {0})", e.E.Type); } } ResolveAttributes(iter.Attributes, new ResolveOpts(iter, false, true)); - var postSpecErrorCount = ErrorCount; + var postSpecErrorCount = reporter.Count(ErrorLevel.Error); // Resolve body if (iter.Body != null) { @@ -4031,7 +3915,7 @@ namespace Microsoft.Dafny Expression frameSet = new SetDisplayExpr(iter.tok, true, modSetSingletons); foreach (var fr in iter.Reads.Expressions) { if (fr.FieldName != null) { - Error(fr.tok, "sorry, a reads clause for an iterator is not allowed to designate specific fields"); + reporter.Error(MessageSource.Resolver, fr.tok, "sorry, a reads clause for an iterator is not allowed to designate specific fields"); } else if (fr.E.Type.IsRefType) { modSetSingletons.Add(fr.E); } else { @@ -4046,7 +3930,7 @@ namespace Microsoft.Dafny frameSet = new SetDisplayExpr(iter.tok, true, modSetSingletons); foreach (var fr in iter.Modifies.Expressions) { if (fr.FieldName != null) { - Error(fr.tok, "sorry, a modifies clause for an iterator is not allowed to designate specific fields"); + reporter.Error(MessageSource.Resolver, fr.tok, "sorry, a modifies clause for an iterator is not allowed to designate specific fields"); } else if (fr.E.Type.IsRefType) { modSetSingletons.Add(fr.E); } else { @@ -4232,7 +4116,7 @@ namespace Microsoft.Dafny // nothing to resolve } else if (type is MapType) { var mt = (MapType)type; - var errorCount = ErrorCount; + var errorCount = reporter.Count(ErrorLevel.Error); int typeArgumentCount = 0; if (mt.HasTypeArg()) { ResolveType(tok, mt.Domain, context, option, defaultTypeArguments); @@ -4253,19 +4137,19 @@ namespace Microsoft.Dafny } // defaults and auto have been applied; check if we now have the right number of arguments if (2 != typeArgumentCount) { - Error(tok, "Wrong number of type arguments ({0} instead of 2) passed to type: {1}", typeArgumentCount, mt.CollectionTypeName); + reporter.Error(MessageSource.Resolver, tok, "Wrong number of type arguments ({0} instead of 2) passed to type: {1}", typeArgumentCount, mt.CollectionTypeName); // add proxy types, to make sure that MapType will have have a non-null Arg/Domain and Range if (typeArgumentCount == 0) { mt.SetTypeArg(new InferredTypeProxy()); } mt.SetRangetype(new InferredTypeProxy()); } - if (errorCount == ErrorCount && (mt.Domain.IsSubrangeType || mt.Range.IsSubrangeType)) { - Error(tok, "sorry, cannot instantiate collection type with a subrange type"); + if (errorCount == reporter.Count(ErrorLevel.Error) && (mt.Domain.IsSubrangeType || mt.Range.IsSubrangeType)) { + reporter.Error(MessageSource.Resolver, tok, "sorry, cannot instantiate collection type with a subrange type"); } } else if (type is CollectionType) { var t = (CollectionType)type; - var errorCount = ErrorCount; + var errorCount = reporter.Count(ErrorLevel.Error); if (t.HasTypeArg()) { ResolveType(tok, t.Arg, context, option, defaultTypeArguments); } else if (option.Opt != ResolveTypeOptionEnum.DontInfer) { @@ -4278,13 +4162,13 @@ namespace Microsoft.Dafny } if (!t.HasTypeArg()) { // defaults and auto have been applied; check if we now have the right number of arguments - Error(tok, "Wrong number of type arguments (0 instead of 1) passed to type: {0}", t.CollectionTypeName); + reporter.Error(MessageSource.Resolver, tok, "Wrong number of type arguments (0 instead of 1) passed to type: {0}", t.CollectionTypeName); // add a proxy type, to make sure that CollectionType will have have a non-null Arg t.SetTypeArg(new InferredTypeProxy()); } - if (errorCount == ErrorCount && t.Arg.IsSubrangeType) { - Error(tok, "sorry, cannot instantiate collection type with a subrange type"); + if (errorCount == reporter.Count(ErrorLevel.Error) && t.Arg.IsSubrangeType) { + reporter.Error(MessageSource.Resolver, tok, "sorry, cannot instantiate collection type with a subrange type"); } } else if (type is UserDefinedType) { @@ -4293,7 +4177,7 @@ namespace Microsoft.Dafny // Apparently, this type has already been resolved return null; } - var prevErrorCount = ErrorCount; + var prevErrorCount = reporter.Count(ErrorLevel.Error); if (t.NamePath is ExprDotName) { var ret = ResolveDotSuffix_Type((ExprDotName)t.NamePath, new ResolveOpts(context, true, true), allowDanglingDotName, option, defaultTypeArguments); if (ret != null) { @@ -4303,10 +4187,10 @@ namespace Microsoft.Dafny var s = (NameSegment)t.NamePath; ResolveNameSegment_Type(s, new ResolveOpts(context, true, true), option, defaultTypeArguments); } - if (ErrorCount == prevErrorCount) { + if (reporter.Count(ErrorLevel.Error) == prevErrorCount) { var r = t.NamePath.Resolved as Resolver_IdentifierExpr; if (r == null || !(r.Type is Resolver_IdentifierExpr.ResolverType_Type)) { - Error(t.tok, "expected type"); + reporter.Error(MessageSource.Resolver, t.tok, "expected type"); } else if (r.Type is Resolver_IdentifierExpr.ResolverType_Type && r.TypeParamDecl != null) { t.ResolvedParam = r.TypeParamDecl; } else if (r.Type is Resolver_IdentifierExpr.ResolverType_Type) { @@ -4328,7 +4212,7 @@ namespace Microsoft.Dafny caller.EnclosingModule.CallGraph.AddEdge(caller, dd); if (caller == dd) { // detect self-loops here, since they don't show up in the graph's SSC methods - Error(dd.tok, "recursive dependency involving a newtype: {0} -> {0}", dd.Name); + reporter.Error(MessageSource.Resolver, dd.tok, "recursive dependency involving a newtype: {0} -> {0}", dd.Name); } } t.ResolvedClass = dd; @@ -4343,7 +4227,7 @@ namespace Microsoft.Dafny } // defaults and auto have been applied; check if we now have the right number of arguments if (d.TypeArgs.Count != t.TypeArgs.Count) { - Error(t.tok, "Wrong number of type arguments ({0} instead of {1}) passed to {2}: {3}", t.TypeArgs.Count, d.TypeArgs.Count, d.WhatKind, t.Name); + reporter.Error(MessageSource.Resolver, t.tok, "Wrong number of type arguments ({0} instead of {1}) passed to {2}: {3}", t.TypeArgs.Count, d.TypeArgs.Count, d.WhatKind, t.Name); } } @@ -4839,14 +4723,14 @@ namespace Microsoft.Dafny ResolveExpression(s.Expr, new ResolveOpts(codeContext, true, true)); Contract.Assert(s.Expr.Type != null); // follows from postcondition of ResolveExpression if (!UnifyTypes(s.Expr.Type, Type.Bool)) { - Error(s.Expr, "condition is expected to be of type {0}, but is {1}", Type.Bool, s.Expr.Type); + reporter.Error(MessageSource.Resolver, s.Expr, "condition is expected to be of type {0}, but is {1}", Type.Bool, s.Expr.Type); } } else if (stmt is PrintStmt) { PrintStmt s = (PrintStmt)stmt; ResolveAttributeArgs(s.Args, new ResolveOpts(codeContext, false, specContextOnly), false); if (specContextOnly) { - Error(stmt, "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)"); + reporter.Error(MessageSource.Resolver, stmt, "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)"); } } else if (stmt is BreakStmt) { @@ -4854,17 +4738,17 @@ namespace Microsoft.Dafny if (s.TargetLabel != null) { Statement target = labeledStatements.Find(s.TargetLabel); if (target == null) { - Error(s, "break label is undefined or not in scope: {0}", s.TargetLabel); + reporter.Error(MessageSource.Resolver, s, "break label is undefined or not in scope: {0}", s.TargetLabel); } else { s.TargetStmt = target; bool targetIsLoop = target is WhileStmt || target is AlternativeLoopStmt; if (specContextOnly && !s.TargetStmt.IsGhost && !inSpecOnlyContext[s.TargetStmt]) { - Error(stmt, "ghost-context break statement is not allowed to break out of non-ghost " + (targetIsLoop ? "loop" : "structure")); + reporter.Error(MessageSource.Resolver, stmt, "ghost-context break statement is not allowed to break out of non-ghost " + (targetIsLoop ? "loop" : "structure")); } } } else { if (loopStack.Count < s.BreakCount) { - Error(s, "trying to break out of more loop levels than there are enclosing loops"); + reporter.Error(MessageSource.Resolver, s, "trying to break out of more loop levels than there are enclosing loops"); } else { Statement target = loopStack[loopStack.Count - s.BreakCount]; if (target.Labels == null) { @@ -4873,7 +4757,7 @@ namespace Microsoft.Dafny } s.TargetStmt = target; if (specContextOnly && !target.IsGhost && !inSpecOnlyContext[target]) { - Error(stmt, "ghost-context break statement is not allowed to break out of non-ghost loop"); + reporter.Error(MessageSource.Resolver, stmt, "ghost-context break statement is not allowed to break out of non-ghost loop"); } } } @@ -4881,11 +4765,11 @@ namespace Microsoft.Dafny } else if (stmt is ProduceStmt) { var kind = stmt is YieldStmt ? "yield" : "return"; if (stmt is YieldStmt && !(codeContext is IteratorDecl)) { - Error(stmt, "yield statement is allowed only in iterators"); + reporter.Error(MessageSource.Resolver, stmt, "yield statement is allowed only in iterators"); } else if (stmt is ReturnStmt && !(codeContext is Method)) { - Error(stmt, "return statement is allowed only in method"); + reporter.Error(MessageSource.Resolver, stmt, "return statement is allowed only in method"); } else if (specContextOnly && !codeContext.IsGhost) { - Error(stmt, "{0} statement is not allowed in this context (because it is guarded by a specification-only expression)", kind); + reporter.Error(MessageSource.Resolver, stmt, "{0} statement is not allowed in this context (because it is guarded by a specification-only expression)", kind); } var s = (ProduceStmt)stmt; if (s.rhss != null) { @@ -4893,7 +4777,7 @@ namespace Microsoft.Dafny if (cmc == null) { // an error has already been reported above } else if (cmc.Outs.Count != s.rhss.Count) { - Error(s, "number of {2} parameters does not match declaration (found {0}, expected {1})", s.rhss.Count, cmc.Outs.Count, kind); + reporter.Error(MessageSource.Resolver, 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. @@ -4986,24 +4870,24 @@ namespace Microsoft.Dafny { if (currentMethod == null) { - Error(local.Tok, "assumption variable can only be declared in a method"); + reporter.Error(MessageSource.Resolver, local.Tok, "assumption variable can only be declared in a method"); } if (!local.IsGhost) { - Error(local.Tok, "assumption variable must be ghost"); + reporter.Error(MessageSource.Resolver, local.Tok, "assumption variable must be ghost"); } if (!(local.Type.IsBoolType)) { - Error(s, "assumption variable must be of type 'bool'"); + reporter.Error(MessageSource.Resolver, s, "assumption variable must be of type 'bool'"); } } } } else if (stmt is AssignStmt) { AssignStmt s = (AssignStmt)stmt; - int prevErrorCount = ErrorCount; + int prevErrorCount = reporter.Count(ErrorLevel.Error); ResolveExpression(s.Lhs, new ResolveOpts(codeContext, true, specContextOnly)); // allow ghosts for now, tighted up below - bool lhsResolvedSuccessfully = ErrorCount == prevErrorCount; + bool lhsResolvedSuccessfully = reporter.Count(ErrorLevel.Error) == prevErrorCount; Contract.Assert(s.Lhs.Type != null); // follows from postcondition of ResolveExpression // check that LHS denotes a mutable variable or a field bool lvalueIsGhost = false; @@ -5016,7 +4900,7 @@ namespace Microsoft.Dafny lvalueIsGhost = var.IsGhost || codeContext.IsGhost; CheckIsLvalue(lhs, codeContext); if (!lvalueIsGhost && specContextOnly) { - Error(stmt, "Assignment to non-ghost variable is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression)"); + reporter.Error(MessageSource.Resolver, stmt, "Assignment to non-ghost variable is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression)"); } var localVar = var as LocalVariable; @@ -5035,7 +4919,7 @@ namespace Microsoft.Dafny } else { - Error(stmt, string.Format("there may be at most one assignment to an assumption variable, the RHS of which must match the expression \"{0} && \"", localVar.Name)); + reporter.Error(MessageSource.Resolver, stmt, string.Format("there may be at most one assignment to an assumption variable, the RHS of which must match the expression \"{0} && \"", localVar.Name)); } } } @@ -5045,12 +4929,12 @@ namespace Microsoft.Dafny lvalueIsGhost = fse.Member.IsGhost; if (!lvalueIsGhost) { if (specContextOnly) { - Error(stmt, "Assignment to non-ghost field is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression)"); + reporter.Error(MessageSource.Resolver, stmt, "Assignment to non-ghost field is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression)"); } else { // It is now that we wish we would have resolved s.Lhs to not allow ghosts. Too late, so we do // the next best thing. if (lhsResolvedSuccessfully && UsesSpecFeatures(fse.Obj)) { - Error(stmt, "Assignment to non-ghost field is not allowed to use specification-only expressions in the receiver"); + reporter.Error(MessageSource.Resolver, stmt, "Assignment to non-ghost field is not allowed to use specification-only expressions in the receiver"); } } } @@ -5062,14 +4946,14 @@ namespace Microsoft.Dafny if (lhsResolvedSuccessfully) { Contract.Assert(slhs.Seq.Type != null); if (specContextOnly) { - Error(stmt, "Assignment to array element is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression)"); + reporter.Error(MessageSource.Resolver, stmt, "Assignment to array element is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression)"); } CheckIsLvalue(slhs, codeContext); } } else if (lhs is MultiSelectExpr) { if (specContextOnly) { - Error(stmt, "Assignment to array element is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression)"); + reporter.Error(MessageSource.Resolver, stmt, "Assignment to array element is not allowed in this context (because this is a ghost method or because the statement is guarded by a specification-only expression)"); } CheckIsLvalue(lhs, codeContext); @@ -5087,7 +4971,7 @@ namespace Microsoft.Dafny } Contract.Assert(rr.Expr.Type != null); // follows from postcondition of ResolveExpression if (!UnifyTypes(lhsType, rr.Expr.Type)) { - Error(stmt, "RHS (of type {0}) not assignable to LHS (of type {1})", rr.Expr.Type, lhsType); + reporter.Error(MessageSource.Resolver, stmt, "RHS (of type {0}) not assignable to LHS (of type {1})", rr.Expr.Type, lhsType); } } else if (s.Rhs is TypeRhs) { TypeRhs rr = (TypeRhs)s.Rhs; @@ -5105,7 +4989,7 @@ namespace Microsoft.Dafny } } if (!UnifyTypes(lhsType, t)) { - Error(stmt, "type {0} is not assignable to LHS (of type {1})", t, lhsType); + reporter.Error(MessageSource.Resolver, stmt, "type {0} is not assignable to LHS (of type {1})", t, lhsType); } } else if (s.Rhs is HavocRhs) { // nothing else to do @@ -5130,12 +5014,12 @@ namespace Microsoft.Dafny IfStmt s = (IfStmt)stmt; bool branchesAreSpecOnly = specContextOnly; if (s.Guard != null) { - int prevErrorCount = ErrorCount; + int prevErrorCount = reporter.Count(ErrorLevel.Error); ResolveExpression(s.Guard, new ResolveOpts(codeContext, true, specContextOnly)); Contract.Assert(s.Guard.Type != null); // follows from postcondition of ResolveExpression - bool successfullyResolved = ErrorCount == prevErrorCount; + bool successfullyResolved = reporter.Count(ErrorLevel.Error) == prevErrorCount; if (!UnifyTypes(s.Guard.Type, Type.Bool)) { - Error(s.Guard, "condition is expected to be of type {0}, but is {1}", Type.Bool, s.Guard.Type); + reporter.Error(MessageSource.Resolver, s.Guard, "condition is expected to be of type {0}, but is {1}", Type.Bool, s.Guard.Type); } if (!specContextOnly && successfullyResolved) { branchesAreSpecOnly = UsesSpecFeatures(s.Guard); @@ -5163,13 +5047,13 @@ namespace Microsoft.Dafny bool bodyMustBeSpecOnly = specContextOnly; var fvs = new HashSet(); if (s.Guard != null) { - int prevErrorCount = ErrorCount; + int prevErrorCount = reporter.Count(ErrorLevel.Error); ResolveExpression(s.Guard, new ResolveOpts(codeContext, true, specContextOnly)); Contract.Assert(s.Guard.Type != null); // follows from postcondition of ResolveExpression - bool successfullyResolved = ErrorCount == prevErrorCount; + bool successfullyResolved = reporter.Count(ErrorLevel.Error) == prevErrorCount; Translator.ComputeFreeVariables(s.Guard, fvs); if (!UnifyTypes(s.Guard.Type, Type.Bool)) { - Error(s.Guard, "condition is expected to be of type {0}, but is {1}", Type.Bool, s.Guard.Type); + reporter.Error(MessageSource.Resolver, s.Guard, "condition is expected to be of type {0}, but is {1}", Type.Bool, s.Guard.Type); } if (!specContextOnly && successfullyResolved) { bodyMustBeSpecOnly = UsesSpecFeatures(s.Guard); @@ -5182,7 +5066,7 @@ namespace Microsoft.Dafny Contract.Assert(inv.E.Type != null); // follows from postcondition of ResolveExpression Translator.ComputeFreeVariables(inv.E, fvs); if (!UnifyTypes(inv.E.Type, Type.Bool)) { - Error(inv.E, "invariant is expected to be of type {0}, but is {1}", Type.Bool, inv.E.Type); + reporter.Error(MessageSource.Resolver, inv.E, "invariant is expected to be of type {0}, but is {1}", Type.Bool, inv.E.Type); } } @@ -5191,9 +5075,9 @@ namespace Microsoft.Dafny ResolveExpression(e, new ResolveOpts(codeContext, true, true)); if (e is WildcardExpr) { if (bodyMustBeSpecOnly) { - Error(e, "'decreases *' is not allowed on ghost loops"); + reporter.Error(MessageSource.Resolver, e, "'decreases *' is not allowed on ghost loops"); } else if (!codeContext.AllowsNontermination && !DafnyOptions.O.Dafnycc) { - Error(e, "a possibly infinite loop is allowed only if the enclosing method is declared (with 'decreases *') to be possibly non-terminating"); + reporter.Error(MessageSource.Resolver, 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 @@ -5225,7 +5109,7 @@ namespace Microsoft.Dafny } } text += "};"; // always terminate with a semi-colon - ReportAdditionalInformation(s.Tok, text, s.Tok.val.Length); + reporter.Info(MessageSource.Resolver, s.Tok, text); } } else if (stmt is AlternativeLoopStmt) { @@ -5235,7 +5119,7 @@ namespace Microsoft.Dafny ResolveExpression(inv.E, new ResolveOpts(codeContext, true, true)); Contract.Assert(inv.E.Type != null); // follows from postcondition of ResolveExpression if (!UnifyTypes(inv.E.Type, Type.Bool)) { - Error(inv.E, "invariant is expected to be of type {0}, but is {1}", Type.Bool, inv.E.Type); + reporter.Error(MessageSource.Resolver, inv.E, "invariant is expected to be of type {0}, but is {1}", Type.Bool, inv.E.Type); } } @@ -5243,9 +5127,9 @@ namespace Microsoft.Dafny ResolveExpression(e, new ResolveOpts(codeContext, true, true)); if (e is WildcardExpr) { if (s.IsGhost) { - Error(e, "'decreases *' is not allowed on ghost loops"); + reporter.Error(MessageSource.Resolver, e, "'decreases *' is not allowed on ghost loops"); } else if (!codeContext.AllowsNontermination && !DafnyOptions.O.Dafnycc) { - Error(e, "a possibly infinite loop is allowed only if the enclosing method is declared (with 'decreases *') to be possibly non-terminating"); + reporter.Error(MessageSource.Resolver, 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 @@ -5254,7 +5138,7 @@ namespace Microsoft.Dafny } else if (stmt is ForallStmt) { var s = (ForallStmt)stmt; - int prevErrorCount = ErrorCount; + int prevErrorCount = reporter.Count(ErrorLevel.Error); scope.PushMarker(); foreach (BoundVar v in s.BoundVars) { ScopePushAndReport(scope, v, "local-variable"); @@ -5263,24 +5147,24 @@ namespace Microsoft.Dafny ResolveExpression(s.Range, new ResolveOpts(codeContext, true, specContextOnly)); Contract.Assert(s.Range.Type != null); // follows from postcondition of ResolveExpression if (!UnifyTypes(s.Range.Type, Type.Bool)) { - Error(stmt, "range restriction in forall statement must be of type bool (instead got {0})", s.Range.Type); + reporter.Error(MessageSource.Resolver, stmt, "range restriction in forall statement must be of type bool (instead got {0})", s.Range.Type); } foreach (var ens in s.Ens) { ResolveExpression(ens.E, new ResolveOpts(codeContext, true, true)); Contract.Assert(ens.E.Type != null); // follows from postcondition of ResolveExpression if (!UnifyTypes(ens.E.Type, Type.Bool)) { - Error(ens.E, "ensures condition is expected to be of type {0}, but is {1}", Type.Bool, ens.E.Type); + reporter.Error(MessageSource.Resolver, ens.E, "ensures condition is expected to be of type {0}, but is {1}", Type.Bool, ens.E.Type); } } // 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.Attributes, new ResolveOpts(codeContext, true, true)); - bool bodyMustBeSpecOnly = specContextOnly || (prevErrorCount == ErrorCount && UsesSpecFeatures(s.Range)); - if (!bodyMustBeSpecOnly && prevErrorCount == ErrorCount) { + bool bodyMustBeSpecOnly = specContextOnly || (prevErrorCount == reporter.Count(ErrorLevel.Error) && UsesSpecFeatures(s.Range)); + if (!bodyMustBeSpecOnly && prevErrorCount == reporter.Count(ErrorLevel.Error)) { var missingBounds = new List(); CheckTypeInference(s.Range); // we need to resolve operators before the call to DiscoverBounds - s.Bounds = DiscoverBounds(s.Tok, s.BoundVars, s.Range, true, false, missingBounds); + s.Bounds = DiscoverBounds(s.Tok, s.BoundVars, s.Range, true, false, missingBounds, reporter); if (missingBounds.Count != 0) { bodyMustBeSpecOnly = true; } @@ -5299,7 +5183,7 @@ namespace Microsoft.Dafny } scope.PopMarker(); - if (prevErrorCount == ErrorCount) { + if (prevErrorCount == reporter.Count(ErrorLevel.Error)) { // 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. @@ -5323,13 +5207,13 @@ namespace Microsoft.Dafny // add the conclusion of the calc as a free postcondition var result = ((CalcStmt)s0).Result; s.Ens.Add(new MaybeFreeExpression(result, true)); - ReportAdditionalInformation(s.Tok, "ensures " + Printer.ExprToString(result) + ";", s.Tok.val.Length); + reporter.Info(MessageSource.Resolver, s.Tok, "ensures " + Printer.ExprToString(result) + ";"); } else { s.Kind = ForallStmt.ParBodyKind.Proof; if (s.Body is BlockStmt && ((BlockStmt)s.Body).Body.Count == 0) { // an empty statement, so don't produce any warning } else { - Warning(s.Tok, "the conclusion of the body of this forall statement will not be known outside the forall statement; consider using an 'ensures' clause"); + reporter.Warning(MessageSource.Resolver, s.Tok, "the conclusion of the body of this forall statement will not be known outside the forall statement; consider using an 'ensures' clause"); } } } @@ -5351,7 +5235,7 @@ namespace Microsoft.Dafny s.IsGhost = specContextOnly; } else if (stmt is CalcStmt) { - var prevErrorCount = ErrorCount; + var prevErrorCount = reporter.Count(ErrorLevel.Error); CalcStmt s = (CalcStmt)stmt; s.IsGhost = true; if (s.Lines.Count > 0) { @@ -5359,12 +5243,12 @@ namespace Microsoft.Dafny ResolveExpression(e0, new ResolveOpts(codeContext, true, true)); Contract.Assert(e0.Type != null); // follows from postcondition of ResolveExpression for (int i = 1; i < s.Lines.Count; i++) { - if (i < s.Lines.Count - 1 || prevErrorCount == ErrorCount) { // do not resolve the dummy step if there were errors, it might generate more errors + if (i < s.Lines.Count - 1 || prevErrorCount == reporter.Count(ErrorLevel.Error)) { // do not resolve the dummy step if there were errors, it might generate more errors var e1 = s.Lines[i]; ResolveExpression(e1, new ResolveOpts(codeContext, true, true)); Contract.Assert(e1.Type != null); // follows from postcondition of ResolveExpression if (!UnifyTypes(e0.Type, e1.Type)) { - Error(e1, "all lines in a calculation must have the same type (got {0} after {1})", e1.Type, e0.Type); + reporter.Error(MessageSource.Resolver, e1, "all lines in a calculation must have the same type (got {0} after {1})", e1.Type, e0.Type); } else { var step = s.StepOps[i - 1].StepExpr(e0, e1); // Use custom line operator ResolveExpression(step, new ResolveOpts(codeContext, true, true)); @@ -5387,7 +5271,7 @@ namespace Microsoft.Dafny loopStack = prevLoopStack; } - if (prevErrorCount == ErrorCount && s.Lines.Count > 0) { + if (prevErrorCount == reporter.Count(ErrorLevel.Error) && 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 s.Result = s.ResultOp.StepExpr(s.Lines.First(), s.Lines.Last()); } else { @@ -5395,13 +5279,13 @@ namespace Microsoft.Dafny } ResolveExpression(s.Result, new ResolveOpts(codeContext, true, true)); Contract.Assert(s.Result != null); - Contract.Assert(prevErrorCount != ErrorCount || s.Steps.Count == s.Hints.Count); + Contract.Assert(prevErrorCount != reporter.Count(ErrorLevel.Error) || s.Steps.Count == s.Hints.Count); } else if (stmt is MatchStmt) { ResolveMatchStmt(stmt, specContextOnly, codeContext); } else if (stmt is SkeletonStatement) { var s = (SkeletonStatement)stmt; - Error(s.Tok, "skeleton statements are allowed only in refining methods"); + reporter.Error(MessageSource.Resolver, s.Tok, "skeleton statements are allowed only in refining methods"); // nevertheless, resolve the underlying statement; hey, why not if (s.S != null) { ResolveStatement(s.S, specContextOnly, codeContext); @@ -5416,10 +5300,10 @@ namespace Microsoft.Dafny DesugarMatchStmtWithTupleExpression(s); bool bodyIsSpecOnly = specContextOnly; - int prevErrorCount = ErrorCount; + int prevErrorCount = reporter.Count(ErrorLevel.Error); ResolveExpression(s.Source, new ResolveOpts(codeContext, true, specContextOnly)); Contract.Assert(s.Source.Type != null); // follows from postcondition of ResolveExpression - bool successfullyResolved = ErrorCount == prevErrorCount; + bool successfullyResolved = reporter.Count(ErrorLevel.Error) == prevErrorCount; if (!specContextOnly && successfullyResolved) { bodyIsSpecOnly = UsesSpecFeatures(s.Source); } @@ -5432,7 +5316,7 @@ namespace Microsoft.Dafny var subst = new Dictionary(); Dictionary ctors; if (dtd == null) { - Error(s.Source, "the type of the match source expression must be a datatype (instead found {0})", s.Source.Type); + reporter.Error(MessageSource.Resolver, s.Source, "the type of the match source expression must be a datatype (instead found {0})", s.Source.Type); ctors = null; } else { Contract.Assert(sourceType != null); // dtd and sourceType are set together above @@ -5462,15 +5346,15 @@ namespace Microsoft.Dafny if (ctors != null) { Contract.Assert(dtd != null); if (!ctors.TryGetValue(mc.Id, out ctor)) { - Error(mc.tok, "member {0} does not exist in datatype {1}", mc.Id, dtd.Name); + reporter.Error(MessageSource.Resolver, mc.tok, "member {0} does not exist in datatype {1}", mc.Id, dtd.Name); } else { Contract.Assert(ctor != null); // follows from postcondition of TryGetValue mc.Ctor = ctor; if (ctor.Formals.Count != mc.Arguments.Count) { - Error(mc.tok, "member {0} has wrong number of formals (found {1}, expected {2})", mc.Id, mc.Arguments.Count, ctor.Formals.Count); + reporter.Error(MessageSource.Resolver, mc.tok, "member {0} has wrong number of formals (found {1}, expected {2})", mc.Id, mc.Arguments.Count, ctor.Formals.Count); } if (memberNamesUsed.Contains(mc.Id)) { - Error(mc.tok, "member {0} appears in more than one case", mc.Id); + reporter.Error(MessageSource.Resolver, mc.tok, "member {0} appears in more than one case", mc.Id); } else { memberNamesUsed.Add(mc.Id); // add mc.Id to the set of names used } @@ -5486,7 +5370,7 @@ namespace Microsoft.Dafny Formal formal = ctor.Formals[i]; Type st = SubstType(formal.Type, subst); if (!UnifyTypes(v.Type, st)) { - Error(stmt, "the declared type of the formal ({0}) does not agree with the corresponding type in the constructor's signature ({1})", v.Type, st); + reporter.Error(MessageSource.Resolver, stmt, "the declared type of the formal ({0}) does not agree with the corresponding type in the constructor's signature ({1})", v.Type, st); } v.IsGhost = formal.IsGhost; @@ -5557,7 +5441,7 @@ namespace Microsoft.Dafny if (me.Source is DatatypeValue) { var e = (DatatypeValue)me.Source; if (e.Arguments.Count < 1) { - Error(me.Tok, "match source tuple needs at least 1 argument"); + reporter.Error(MessageSource.Resolver, me.Tok, "match source tuple needs at least 1 argument"); } else { Expression source = e.Arguments[0]; List cases = new List(); @@ -5566,7 +5450,7 @@ namespace Microsoft.Dafny bool keepOrigToken = true; foreach (MatchCaseStmt mc in me.Cases) { if (mc.CasePatterns == null || mc.CasePatterns.Count != e.Arguments.Count) { - Error(mc.tok, "case arguments count does not match source arguments count"); + reporter.Error(MessageSource.Resolver, mc.tok, "case arguments count does not match source arguments count"); } else { CasePattern cp = mc.CasePatterns[0]; List patterns; @@ -5723,7 +5607,7 @@ namespace Microsoft.Dafny ScopePushAndReport(scope, v, "parameter"); } else { if (scope.Find(v.Name) != null) { - Error(v, "Duplicate parameter name: {0}", v.Name); + reporter.Error(MessageSource.Resolver, v, "Duplicate parameter name: {0}", v.Name); } } } else { @@ -5938,26 +5822,26 @@ namespace Microsoft.Dafny } } s += ";"; // always terminate with a semi-colon, even in the case of an empty decreases clause - ReportAdditionalInformation(loopStmt.Tok, s, loopStmt.Tok.val.Length); + reporter.Info(MessageSource.Resolver, loopStmt.Tok, s); } } private void ResolveConcreteUpdateStmt(ConcreteUpdateStatement s, bool specContextOnly, ICodeContext codeContext) { Contract.Requires(codeContext != null); // First, resolve all LHS's and expression-looking RHS's. - int errorCountBeforeCheckingLhs = ErrorCount; + int errorCountBeforeCheckingLhs = reporter.Count(ErrorLevel.Error); var update = s as UpdateStmt; var lhsNameSet = new HashSet(); // used to check for duplicate identifiers on the left (full duplication checking for references and the like is done during verification) foreach (var lhs in s.Lhss) { - var ec = ErrorCount; + var ec = reporter.Count(ErrorLevel.Error); ResolveExpression(lhs, new ResolveOpts(codeContext, true, specContextOnly)); - if (ec == ErrorCount) { + if (ec == reporter.Count(ErrorLevel.Error)) { if (update == null && specContextOnly && !AssignStmt.LhsIsToGhost(lhs) && !codeContext.IsGhost) { - Error(lhs, "cannot assign to non-ghost variable in a ghost context"); + reporter.Error(MessageSource.Resolver, lhs, "cannot assign to non-ghost variable in a ghost context"); } if (lhs is SeqSelectExpr && !((SeqSelectExpr)lhs).SelectOne) { - Error(lhs, "cannot assign to a range of array elements (try the 'forall' statement)"); + reporter.Error(MessageSource.Resolver, lhs, "cannot assign to a range of array elements (try the 'forall' statement)"); } } } @@ -6018,10 +5902,10 @@ namespace Microsoft.Dafny if (firstEffectfulRhs == null) { if (update.Lhss.Count == 0) { Contract.Assert(update.Rhss.Count == 1); // guaranteed by the parser - Error(update, "expected method call, found expression"); + reporter.Error(MessageSource.Resolver, update, "expected method call, found expression"); } else if (update.Lhss.Count != update.Rhss.Count) { - Error(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 == errorCountBeforeCheckingLhs) { + reporter.Error(MessageSource.Resolver, 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 (reporter.Count(ErrorLevel.Error) == errorCountBeforeCheckingLhs) { // add the statements here in a sequence, but don't use that sequence later for translation (instead, should translate properly as multi-assignment) for (int i = 0; i < update.Lhss.Count; i++) { var a = new AssignStmt(update.Tok, update.EndTok, update.Lhss[i].Resolved, update.Rhss[i]); @@ -6031,19 +5915,19 @@ namespace Microsoft.Dafny } else if (update.CanMutateKnownState) { if (1 < update.Rhss.Count) { - Error(firstEffectfulRhs, "cannot have effectful parameter in multi-return statement."); + reporter.Error(MessageSource.Resolver, 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) { - Error(methodCallInfo.Tok, "cannot have method call in return statement."); + reporter.Error(MessageSource.Resolver, methodCallInfo.Tok, "cannot have method call in return statement."); } else { // we have a TypeRhs Contract.Assert(update.Rhss[0] is 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) { - Error(tr.Tok, "can only have initialization methods which modify at most 'this'."); - } else if (ErrorCount == errorCountBeforeCheckingLhs) { + reporter.Error(MessageSource.Resolver, tr.Tok, "can only have initialization methods which modify at most 'this'."); + } else if (reporter.Count(ErrorLevel.Error) == errorCountBeforeCheckingLhs) { var a = new AssignStmt(update.Tok, update.EndTok, update.Lhss[0].Resolved, tr); update.ResolvedStatements.Add(a); } @@ -6053,17 +5937,17 @@ namespace Microsoft.Dafny } else { // if there was an effectful RHS, that must be the only RHS if (update.Rhss.Count != 1) { - Error(firstEffectfulRhs, "an update statement is allowed an effectful RHS only if there is just one RHS"); + reporter.Error(MessageSource.Resolver, 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) - Error(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 == errorCountBeforeCheckingLhs) { + reporter.Error(MessageSource.Resolver, 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 (reporter.Count(ErrorLevel.Error) == errorCountBeforeCheckingLhs) { var a = new AssignStmt(update.Tok, update.EndTok, update.Lhss[0].Resolved, update.Rhss[0]); update.ResolvedStatements.Add(a); } - } else if (ErrorCount == errorCountBeforeCheckingLhs) { + } else if (reporter.Count(ErrorLevel.Error) == errorCountBeforeCheckingLhs) { // a call statement var resolvedLhss = new List(); foreach (var ll in update.Lhss) { @@ -6090,7 +5974,7 @@ namespace Microsoft.Dafny foreach (var lhs in s.Lhss) { var ide = lhs.Resolved as IdentifierExpr; if (ide == null) { - Error(lhs, "the assign-such-that statement currently only supports local-variable LHSs"); + reporter.Error(MessageSource.Resolver, lhs, "the assign-such-that statement currently only supports local-variable LHSs"); } else { varLhss.Add(ide.Var); } @@ -6098,17 +5982,17 @@ namespace Microsoft.Dafny } s.IsGhost = s.Lhss.TrueForAll(AssignStmt.LhsIsToGhost); - var ec = ErrorCount; + var ec = reporter.Count(ErrorLevel.Error); ResolveExpression(s.Expr, new ResolveOpts(codeContext, true, specContextOnly)); if (!UnifyTypes(s.Expr.Type, Type.Bool)) { - Error(s.Expr, "type of RHS of assign-such-that statement must be boolean (got {0})", s.Expr.Type); + reporter.Error(MessageSource.Resolver, s.Expr, "type of RHS of assign-such-that statement must be boolean (got {0})", s.Expr.Type); } - if (ec == ErrorCount && !s.IsGhost && s.AssumeToken == null && !specContextOnly) { + if (ec == reporter.Count(ErrorLevel.Error) && !s.IsGhost && s.AssumeToken == null && !specContextOnly) { CheckIsNonGhost(s.Expr); var missingBounds = new List(); CheckTypeInference(s.Expr); // we need to resolve operators before the call to DiscoverBoundsAux - var allBounds = DiscoverBoundsAux(s.Tok, varLhss, s.Expr, true, true, true, missingBounds); + var allBounds = DiscoverBoundsAux(s.Tok, varLhss, s.Expr, true, true, true, missingBounds, reporter); if (missingBounds.Count != 0) { s.MissingBounds = missingBounds; // so that an error message can be produced during compilation } else { @@ -6130,12 +6014,12 @@ namespace Microsoft.Dafny bool isGhost = specContextOnly; // first, resolve the guards, which tells us whether or not the entire statement is a ghost statement foreach (var alternative in alternatives) { - int prevErrorCount = ErrorCount; + int prevErrorCount = reporter.Count(ErrorLevel.Error); ResolveExpression(alternative.Guard, new ResolveOpts(codeContext, true, specContextOnly)); Contract.Assert(alternative.Guard.Type != null); // follows from postcondition of ResolveExpression - bool successfullyResolved = ErrorCount == prevErrorCount; + bool successfullyResolved = reporter.Count(ErrorLevel.Error) == prevErrorCount; if (!UnifyTypes(alternative.Guard.Type, Type.Bool)) { - Error(alternative.Guard, "condition is expected to be of type {0}, but is {1}", Type.Bool, alternative.Guard.Type); + reporter.Error(MessageSource.Resolver, alternative.Guard, "condition is expected to be of type {0}, but is {1}", Type.Bool, alternative.Guard.Type); } if (!specContextOnly && successfullyResolved) { isGhost = isGhost || UsesSpecFeatures(alternative.Guard); @@ -6174,11 +6058,11 @@ namespace Microsoft.Dafny var callee = s.Method; Contract.Assert(callee != null); // follows from the invariant of CallStmt if (!isInitCall && callee is Constructor) { - Error(s, "a constructor is allowed to be called only when an object is being allocated"); + reporter.Error(MessageSource.Resolver, s, "a constructor is allowed to be called only when an object is being allocated"); } s.IsGhost = callee.IsGhost; if (specContextOnly && !callee.IsGhost) { - Error(s, "only ghost methods can be called from this context"); + reporter.Error(MessageSource.Resolver, s, "only ghost methods can be called from this context"); } // resolve left-hand sides @@ -6192,49 +6076,49 @@ namespace Microsoft.Dafny int j = 0; foreach (Expression e in s.Args) { bool allowGhost = s.IsGhost || callee.Ins.Count <= j || callee.Ins[j].IsGhost; - var ec = ErrorCount; + var ec = reporter.Count(ErrorLevel.Error); ResolveExpression(e, new ResolveOpts(codeContext, true, allowGhost)); - if (ec == ErrorCount && !allowGhost) { + if (ec == reporter.Count(ErrorLevel.Error) && !allowGhost) { CheckIsNonGhost(e); } j++; } if (callee.Ins.Count != s.Args.Count) { - Error(s, "wrong number of method arguments (got {0}, expected {1})", s.Args.Count, callee.Ins.Count); + reporter.Error(MessageSource.Resolver, s, "wrong number of method arguments (got {0}, expected {1})", s.Args.Count, callee.Ins.Count); } else if (callee.Outs.Count != s.Lhs.Count) { if (isInitCall) { - Error(s, "a method called as an initialization method must not have any result arguments"); + reporter.Error(MessageSource.Resolver, s, "a method called as an initialization method must not have any result arguments"); } else { - Error(s, "wrong number of method result arguments (got {0}, expected {1})", s.Lhs.Count, callee.Outs.Count); + reporter.Error(MessageSource.Resolver, s, "wrong number of method result arguments (got {0}, expected {1})", s.Lhs.Count, callee.Outs.Count); } } else { if (isInitCall) { if (callee.IsStatic) { - Error(s.Tok, "a method called as an initialization method must not be 'static'"); + reporter.Error(MessageSource.Resolver, s.Tok, "a method called as an initialization method must not be 'static'"); } } 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. - Error(s.Receiver, "'this' is not allowed in a 'static' context"); + reporter.Error(MessageSource.Resolver, s.Receiver, "'this' is not allowed in a 'static' context"); } else if (s.Receiver is StaticReceiverExpr) { - Error(s.Receiver, "call to instance method requires an instance"); + reporter.Error(MessageSource.Resolver, s.Receiver, "call to instance method requires an instance"); } } // type check the arguments for (int i = 0; i < callee.Ins.Count; i++) { Type st = SubstType(callee.Ins[i].Type, s.MethodSelect.TypeArgumentSubstitutions()); if (!UnifyTypes(cce.NonNull(s.Args[i].Type), st)) { - Error(s, "incorrect type of method in-parameter {0} (expected {1}, got {2})", i, st, s.Args[i].Type); + reporter.Error(MessageSource.Resolver, s, "incorrect type of method in-parameter {0} (expected {1}, got {2})", i, st, s.Args[i].Type); } } for (int i = 0; i < callee.Outs.Count; i++) { Type st = SubstType(callee.Outs[i].Type, s.MethodSelect.TypeArgumentSubstitutions()); var lhs = s.Lhs[i]; if (!UnifyTypes(cce.NonNull(lhs.Type), st)) { - Error(s, "incorrect type of method out-parameter {0} (expected {1}, got {2})", i, st, lhs.Type); + reporter.Error(MessageSource.Resolver, s, "incorrect type of method out-parameter {0} (expected {1}, got {2})", i, st, lhs.Type); } else { var resolvedLhs = lhs.Resolved; if (!specContextOnly && (s.IsGhost || callee.Outs[i].IsGhost)) { @@ -6246,17 +6130,17 @@ namespace Microsoft.Dafny // the variable was actually declared in this statement, so auto-declare it as ghost ((LocalVariable)ll.Var).MakeGhost(); } else { - Error(s, "actual out-parameter {0} is required to be a ghost variable", i); + reporter.Error(MessageSource.Resolver, s, "actual out-parameter {0} is required to be a ghost variable", i); } } } else if (resolvedLhs is MemberSelectExpr) { var ll = (MemberSelectExpr)resolvedLhs; if (!ll.Member.IsGhost) { - Error(s, "actual out-parameter {0} is required to be a ghost field", i); + reporter.Error(MessageSource.Resolver, s, "actual out-parameter {0} is required to be a ghost field", i); } } else { // this is an array update, and arrays are always non-ghost - Error(s, "actual out-parameter {0} is required to be a ghost variable", i); + reporter.Error(MessageSource.Resolver, s, "actual out-parameter {0} is required to be a ghost variable", i); } } // LHS must denote a mutable field. @@ -6283,7 +6167,7 @@ namespace Microsoft.Dafny } } if (Contract.Exists(callee.Decreases.Expressions, e => e is WildcardExpr) && !codeContext.AllowsNontermination) { - Error(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"); + reporter.Error(MessageSource.Resolver, 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"); } } @@ -6298,26 +6182,26 @@ namespace Microsoft.Dafny if (lhs is IdentifierExpr) { var ll = (IdentifierExpr)lhs; if (!ll.Var.IsMutable) { - Error(lhs, "LHS of assignment must denote a mutable variable"); + reporter.Error(MessageSource.Resolver, 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) { - Error(lhs, "LHS of assignment must denote a mutable field"); + reporter.Error(MessageSource.Resolver, lhs, "LHS of assignment must denote a mutable field"); } } else if (lhs is SeqSelectExpr) { var ll = (SeqSelectExpr)lhs; if (!UnifyTypes(ll.Seq.Type, ResolvedArrayType(ll.Seq.tok, 1, new InferredTypeProxy(), codeContext))) { - Error(ll.Seq, "LHS of array assignment must denote an array element (found {0})", ll.Seq.Type); + reporter.Error(MessageSource.Resolver, ll.Seq, "LHS of array assignment must denote an array element (found {0})", ll.Seq.Type); } if (!ll.SelectOne) { - Error(ll.Seq, "cannot assign to a range of array elements (try the 'forall' statement)"); + reporter.Error(MessageSource.Resolver, 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 { - Error(lhs, "LHS of assignment must denote a mutable variable or field"); + reporter.Error(MessageSource.Resolver, lhs, "LHS of assignment must denote a mutable variable or field"); } } @@ -6333,9 +6217,9 @@ namespace Microsoft.Dafny 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 = labeledStatements.Find(lnode.Name); if (prev == ss) { - Error(lnode.Tok, "duplicate label"); + reporter.Error(MessageSource.Resolver, lnode.Tok, "duplicate label"); } else if (prev != null) { - Error(lnode.Tok, "label shadows an enclosing label"); + reporter.Error(MessageSource.Resolver, lnode.Tok, "label shadows an enclosing label"); } else { var r = labeledStatements.Push(lnode.Name, ss); Contract.Assert(r == Scope.PushResult.Success); // since we just checked for duplicates, we expect the Push to succeed @@ -6357,13 +6241,13 @@ namespace Microsoft.Dafny if (stmt is PredicateStmt) { // cool } else if (stmt is PrintStmt) { - Error(stmt, "print statement is not allowed inside a forall statement"); + reporter.Error(MessageSource.Resolver, stmt, "print statement is not allowed inside a forall statement"); } else if (stmt is BreakStmt) { // this case is checked already in the first pass through the forall-statement body, by doing so from an empty set of labeled statements and resetting the loop-stack } else if (stmt is ReturnStmt) { - Error(stmt, "return statement is not allowed inside a forall statement"); + reporter.Error(MessageSource.Resolver, stmt, "return statement is not allowed inside a forall statement"); } else if (stmt is YieldStmt) { - Error(stmt, "yield statement is not allowed inside a forall statement"); + reporter.Error(MessageSource.Resolver, stmt, "yield statement is not allowed inside a forall statement"); } else if (stmt is AssignSuchThatStmt) { var s = (AssignSuchThatStmt)stmt; foreach (var lhs in s.Lhss) { @@ -6385,9 +6269,9 @@ namespace Microsoft.Dafny var rhs = s.Rhs; // ExprRhs and HavocRhs are fine, but TypeRhs is not if (rhs is TypeRhs) { if (kind == ForallStmt.ParBodyKind.Assign) { - Error(rhs.Tok, "new allocation not supported in forall statements"); + reporter.Error(MessageSource.Resolver, rhs.Tok, "new allocation not supported in forall statements"); } else { - Error(rhs.Tok, "new allocation not allowed in ghost context"); + reporter.Error(MessageSource.Resolver, rhs.Tok, "new allocation not allowed in ghost context"); } } } else if (stmt is CallStmt) { @@ -6396,14 +6280,14 @@ namespace Microsoft.Dafny var idExpr = lhs as IdentifierExpr; if (idExpr != null) { if (scope.ContainsDecl(idExpr.Var)) { - Error(stmt, "body of forall statement is attempting to update a variable declared outside the forall statement"); + reporter.Error(MessageSource.Resolver, stmt, "body of forall statement is attempting to update a variable declared outside the forall statement"); } } else { - Error(stmt, "the body of the enclosing forall statement is not allowed to update heap locations"); + reporter.Error(MessageSource.Resolver, stmt, "the body of the enclosing forall statement is not allowed to update heap locations"); } } if (s.Method.Mod.Expressions.Count != 0) { - Error(stmt, "the body of the enclosing forall statement is not allowed to update heap locations, so any call must be to a method with an empty modifies clause"); + reporter.Error(MessageSource.Resolver, stmt, "the body of the enclosing forall statement is not allowed to update heap locations, so any call must be to a method with an empty modifies clause"); } if (!s.Method.IsGhost) { // The reason for this restriction is that the compiler is going to omit the forall statement altogether--it has @@ -6411,7 +6295,7 @@ namespace Microsoft.Dafny // a method that prints something, all calls to non-ghost methods are disallowed. (Note, if this restriction // is somehow lifted in the future, then it is still necessary to enforce s.Method.Mod.Expressions.Count != 0 for // calls to non-ghost methods.) - Error(s, "the body of the enclosing forall statement is not allowed to call non-ghost methods"); + reporter.Error(MessageSource.Resolver, s, "the body of the enclosing forall statement is not allowed to call non-ghost methods"); } } else if (stmt is BlockStmt) { @@ -6455,7 +6339,7 @@ namespace Microsoft.Dafny var s = (ForallStmt)stmt; switch (s.Kind) { case ForallStmt.ParBodyKind.Assign: - Error(stmt, "a forall statement with heap updates is not allowed inside the body of another forall statement"); + reporter.Error(MessageSource.Resolver, stmt, "a forall statement with heap updates is not allowed inside the body of another forall statement"); break; case ForallStmt.ParBodyKind.Call: case ForallStmt.ParBodyKind.Proof: @@ -6486,10 +6370,10 @@ namespace Microsoft.Dafny var idExpr = lhs as IdentifierExpr; if (idExpr != null) { if (scope.ContainsDecl(idExpr.Var)) { - Error(tok, "body of forall statement is attempting to update a variable declared outside the forall statement"); + reporter.Error(MessageSource.Resolver, tok, "body of forall statement is attempting to update a variable declared outside the forall statement"); } } else if (kind != ForallStmt.ParBodyKind.Assign) { - Error(tok, "the body of the enclosing forall statement is not allowed to update heap locations"); + reporter.Error(MessageSource.Resolver, tok, "the body of the enclosing forall statement is not allowed to update heap locations"); } } @@ -6506,9 +6390,9 @@ namespace Microsoft.Dafny } else if (stmt is BreakStmt) { // already checked while resolving hints } else if (stmt is ReturnStmt) { - Error(stmt, "return statement is not allowed inside a hint"); + reporter.Error(MessageSource.Resolver, stmt, "return statement is not allowed inside a hint"); } else if (stmt is YieldStmt) { - Error(stmt, "yield statement is not allowed inside a hint"); + reporter.Error(MessageSource.Resolver, stmt, "yield statement is not allowed inside a hint"); } else if (stmt is AssignSuchThatStmt) { var s = (AssignSuchThatStmt)stmt; foreach (var lhs in s.Lhss) { @@ -6520,7 +6404,7 @@ namespace Microsoft.Dafny } else if (stmt is CallStmt) { var s = (CallStmt)stmt; if (s.Method.Mod.Expressions.Count != 0) { - Error(stmt, "calls to methods with side-effects are not allowed inside a hint"); + reporter.Error(MessageSource.Resolver, stmt, "calls to methods with side-effects are not allowed inside a hint"); } } else if (stmt is UpdateStmt) { var s = (UpdateStmt)stmt; @@ -6558,7 +6442,7 @@ namespace Microsoft.Dafny } else if (stmt is WhileStmt) { var s = (WhileStmt)stmt; if (s.Mod.Expressions != null && s.Mod.Expressions.Count != 0) { - Error(s.Mod.Expressions[0].tok, "a while statement used inside a hint is not allowed to have a modifies clause"); + reporter.Error(MessageSource.Resolver, s.Mod.Expressions[0].tok, "a while statement used inside a hint is not allowed to have a modifies clause"); } if (s.Body != null) { CheckHintRestrictions(s.Body); @@ -6576,7 +6460,7 @@ namespace Microsoft.Dafny var s = (ForallStmt)stmt; switch (s.Kind) { case ForallStmt.ParBodyKind.Assign: - Error(stmt, "a forall statement with heap updates is not allowed inside a hint"); + reporter.Error(MessageSource.Resolver, stmt, "a forall statement with heap updates is not allowed inside a hint"); break; case ForallStmt.ParBodyKind.Call: case ForallStmt.ParBodyKind.Proof: @@ -6609,9 +6493,9 @@ namespace Microsoft.Dafny void CheckHintLhs(IToken tok, Expression lhs) { var idExpr = lhs as IdentifierExpr; if (idExpr == null) { - Error(tok, "a hint is not allowed to update heap locations"); + reporter.Error(MessageSource.Resolver, tok, "a hint is not allowed to update heap locations"); } else if (scope.ContainsDecl(idExpr.Var)) { - Error(tok, "a hint is not allowed to update a variable declared outside the hint"); + reporter.Error(MessageSource.Resolver, tok, "a hint is not allowed to update a variable declared outside the hint"); } } @@ -6623,7 +6507,7 @@ namespace Microsoft.Dafny // "new" is not allowed in ghost contexts if (specContextOnly) { - Error(rr.Tok, "'new' is not allowed in ghost contexts"); + reporter.Error(MessageSource.Resolver, rr.Tok, "'new' is not allowed in ghost contexts"); } if (rr.Type == null) { if (rr.ArrayDimensions != null) { @@ -6635,7 +6519,7 @@ namespace Microsoft.Dafny Contract.Assert(dim != null); ResolveExpression(dim, new ResolveOpts(codeContext, true)); if (!UnifyTypes(dim.Type, new OperationTypeProxy(true, false, false, false, false, false))) { - Error(stmt, "new must use an integer-based expression for the array size (got {0} for index {1})", dim.Type, i); + reporter.Error(MessageSource.Resolver, stmt, "new must use an integer-based expression for the array size (got {0} for index {1})", dim.Type, i); } i++; } @@ -6645,7 +6529,7 @@ namespace Microsoft.Dafny if (rr.Arguments == null) { ResolveType(stmt.Tok, rr.EType, codeContext, ResolveTypeOptionEnum.InferTypeProxies, null); if (!rr.EType.IsRefType) { - Error(stmt, "new can be applied only to reference types (got {0})", rr.EType); + reporter.Error(MessageSource.Resolver, stmt, "new can be applied only to reference types (got {0})", rr.EType); } } else { string initCallName = null; @@ -6668,18 +6552,18 @@ namespace Microsoft.Dafny initCallTok = rr.Tok; } if (!rr.EType.IsRefType) { - Error(stmt, "new can be applied only to reference types (got {0})", rr.EType); + reporter.Error(MessageSource.Resolver, stmt, "new can be applied only to reference types (got {0})", rr.EType); } else { // ---------- new C.Init(EE) Contract.Assert(initCallName != null); - var prevErrorCount = ErrorCount; + var prevErrorCount = reporter.Count(ErrorLevel.Error); // We want to create a MemberSelectExpr for the initializing method. To do that, we create a throw-away receiver of the appropriate // type, create an dot-suffix expression around this receiver, and then resolve it in the usual way for dot-suffix expressions. var lhs = new ImplicitThisExpr(initCallTok) { Type = rr.EType }; var callLhs = new ExprDotName(initCallTok, lhs, initCallName, ret == null ? null : ret.LastComponent.OptTypeArguments); ResolveDotSuffix(callLhs, true, rr.Arguments, new ResolveOpts(codeContext, true, specContextOnly), true); - if (prevErrorCount == ErrorCount) { + if (prevErrorCount == reporter.Count(ErrorLevel.Error)) { 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) { @@ -6689,7 +6573,7 @@ namespace Microsoft.Dafny callsConstructor = true; } } else { - Error(initCallTok, "object initialization must denote an initializing method or constructor ({0})", initCallName); + reporter.Error(MessageSource.Resolver, initCallTok, "object initialization must denote an initializing method or constructor ({0})", initCallName); } } } @@ -6699,10 +6583,10 @@ namespace Microsoft.Dafny if (udt != null) { var cl = (ClassDecl)udt.ResolvedClass; // cast is guaranteed by the call to rr.EType.IsRefType above, together with the "rr.EType is UserDefinedType" test if (cl is TraitDecl) { - Error(stmt, "new cannot be applied to a trait"); + reporter.Error(MessageSource.Resolver, stmt, "new cannot be applied to a trait"); } if (!callsConstructor && cl.HasConstructor) { - Error(stmt, "when allocating an object of type '{0}', one of its constructor methods must be called", cl.Name); + reporter.Error(MessageSource.Resolver, stmt, "when allocating an object of type '{0}', one of its constructor methods must be called", cl.Name); } } } @@ -6731,7 +6615,7 @@ namespace Microsoft.Dafny } } if (receiverType is TypeProxy) { - Error(tok, "type of the receiver is not fully determined at this program point", receiverType); + reporter.Error(MessageSource.Resolver, tok, "type of the receiver is not fully determined at this program point", receiverType); return null; } Contract.Assert(receiverType is NonProxyType); // there are only two kinds of types: proxies and non-proxies @@ -6744,20 +6628,20 @@ namespace Microsoft.Dafny if (!classMembers[cd].TryGetValue(memberName, out member)) { var kind = cd is IteratorDecl ? "iterator" : "class"; if (memberName == "_ctor") { - Error(tok, "{0} {1} does not have an anonymous constructor", kind, ctype.Name); + reporter.Error(MessageSource.Resolver, tok, "{0} {1} does not have an anonymous constructor", kind, ctype.Name); } else { // search the static members of the enclosing module or its imports if (moduleInfo.StaticMembers.TryGetValue(memberName, out member)) { 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; - Error(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)", memberName, ambiguousMember.ModuleNames()); + reporter.Error(MessageSource.Resolver, 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)", memberName, ambiguousMember.ModuleNames()); } else { nptype = GetReceiverType(tok, member); return member; } } else { - Error(tok, "member {0} does not exist in {2} {1}", memberName, ctype.Name, kind); + reporter.Error(MessageSource.Resolver, tok, "member {0} does not exist in {2} {1}", memberName, ctype.Name, kind); } } return null; @@ -6771,7 +6655,7 @@ namespace Microsoft.Dafny if (dtd != null) { MemberDecl member; if (!datatypeMembers[dtd].TryGetValue(memberName, out member)) { - Error(tok, "member {0} does not exist in datatype {1}", memberName, dtd.Name); + reporter.Error(MessageSource.Resolver, tok, "member {0} does not exist in datatype {1}", memberName, dtd.Name); return null; } else { nptype = (UserDefinedType)receiverType; @@ -6797,7 +6681,7 @@ namespace Microsoft.Dafny } } - Error(tok, "type {0} does not have a member {1}", receiverType, memberName); + reporter.Error(MessageSource.Resolver, tok, "type {0} does not have a member {1}", receiverType, memberName); return null; } @@ -7021,10 +6905,10 @@ namespace Microsoft.Dafny } else if (expr is NegationExpression) { var e = (NegationExpression)expr; - var errorCount = ErrorCount; + var errorCount = reporter.Count(ErrorLevel.Error); ResolveExpression(e.E, opts); e.Type = e.E.Type; - if (errorCount != ErrorCount) { + if (errorCount != reporter.Count(ErrorLevel.Error)) { // there were errors resolving the operand; take the quick way out and // just let the (already erronous) subexpression be what the negation expression // will resolve to @@ -7074,7 +6958,7 @@ namespace Microsoft.Dafny } } else if (expr is ThisExpr) { if (!scope.AllowInstance) { - Error(expr, "'this' is not allowed in a 'static' context"); + reporter.Error(MessageSource.Resolver, expr, "'this' is not allowed in a 'static' context"); } if (currentClass != null) { expr.Type = GetThisType(expr.tok, currentClass); // do this regardless of scope.AllowInstance, for better error reporting @@ -7086,19 +6970,19 @@ namespace Microsoft.Dafny if (e.Var != null) { expr.Type = e.Var.Type; } else { - Error(expr, "Identifier does not denote a local variable, parameter, or bound variable: {0}", e.Name); + reporter.Error(MessageSource.Resolver, expr, "Identifier does not denote a local variable, parameter, or bound variable: {0}", e.Name); } } else if (expr is DatatypeValue) { DatatypeValue dtv = (DatatypeValue)expr; TopLevelDecl d; if (!moduleInfo.TopLevels.TryGetValue(dtv.DatatypeName, out d)) { - Error(expr.tok, "Undeclared datatype: {0}", dtv.DatatypeName); + reporter.Error(MessageSource.Resolver, expr.tok, "Undeclared datatype: {0}", dtv.DatatypeName); } else if (d is AmbiguousTopLevelDecl) { var ad = (AmbiguousTopLevelDecl)d; - Error(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()); + reporter.Error(MessageSource.Resolver, 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 (!(d is DatatypeDecl)) { - Error(expr.tok, "Expected datatype: {0}", dtv.DatatypeName); + reporter.Error(MessageSource.Resolver, expr.tok, "Expected datatype: {0}", dtv.DatatypeName); } else { ResolveDatatypeValue(opts, dtv, (DatatypeDecl)d); } @@ -7110,7 +6994,7 @@ namespace Microsoft.Dafny ResolveExpression(ee, opts); Contract.Assert(ee.Type != null); // follows from postcondition of ResolveExpression if (!UnifyTypes(elementType, ee.Type)) { - Error(ee, "All elements of display must be of the same type (got {0}, but type of previous elements is {1})", ee.Type, elementType); + reporter.Error(MessageSource.Resolver, ee, "All elements of display must be of the same type (got {0}, but type of previous elements is {1})", ee.Type, elementType); } } if (expr is SetDisplayExpr) { @@ -7129,12 +7013,12 @@ namespace Microsoft.Dafny ResolveExpression(p.A, opts); Contract.Assert(p.A.Type != null); // follows from postcondition of ResolveExpression if (!UnifyTypes(domainType, p.A.Type)) { - Error(p.A, "All elements of display must be of the same type (got {0}, but type of previous elements is {1})", p.A.Type, domainType); + reporter.Error(MessageSource.Resolver, p.A, "All elements of display must be of the same type (got {0}, but type of previous elements is {1})", p.A.Type, domainType); } ResolveExpression(p.B, opts); Contract.Assert(p.B.Type != null); // follows from postcondition of ResolveExpression if (!UnifyTypes(rangeType, p.B.Type)) { - Error(p.B, "All elements of display must be of the same type (got {0}, but type of previous elements is {1})", p.B.Type, rangeType); + reporter.Error(MessageSource.Resolver, p.B, "All elements of display must be of the same type (got {0}, but type of previous elements is {1})", p.B.Type, rangeType); } } expr.Type = new MapType(e.Finite, domainType, rangeType); @@ -7142,18 +7026,18 @@ namespace Microsoft.Dafny var e = (NameSegment)expr; ResolveNameSegment(e, true, null, opts, false); if (e.Type is Resolver_IdentifierExpr.ResolverType_Module) { - Error(e.tok, "name of module ({0}) is used as a variable", e.Name); + reporter.Error(MessageSource.Resolver, e.tok, "name of module ({0}) is used as a variable", e.Name); } else if (e.Type is Resolver_IdentifierExpr.ResolverType_Type) { - Error(e.tok, "name of type ({0}) is used as a variable", e.Name); + reporter.Error(MessageSource.Resolver, e.tok, "name of type ({0}) is used as a variable", e.Name); } } else if (expr is ExprDotName) { var e = (ExprDotName)expr; ResolveDotSuffix(e, true, null, opts, false); if (e.Type is Resolver_IdentifierExpr.ResolverType_Module) { - Error(e.tok, "name of module ({0}) is used as a variable", e.SuffixName); + reporter.Error(MessageSource.Resolver, e.tok, "name of module ({0}) is used as a variable", e.SuffixName); } else if (e.Type is Resolver_IdentifierExpr.ResolverType_Type) { - Error(e.tok, "name of type ({0}) is used as a variable", e.SuffixName); + reporter.Error(MessageSource.Resolver, e.tok, "name of type ({0}) is used as a variable", e.SuffixName); } } else if (expr is ApplySuffix) { @@ -7193,7 +7077,7 @@ namespace Microsoft.Dafny var field = (Field)member; e.Member = field; if (e.Obj is StaticReceiverExpr) { - Error(expr, "a field must be selected via an object, not just a class name"); + reporter.Error(MessageSource.Resolver, expr, "a field must be selected via an object, not just a class name"); } var ctype = nptype as UserDefinedType; if (ctype == null) { @@ -7205,7 +7089,7 @@ namespace Microsoft.Dafny e.Type = SubstType(field.Type, subst); } } else { - Error(expr, "member {0} in type {1} does not refer to a field or a function", e.MemberName, nptype); + reporter.Error(MessageSource.Resolver, expr, "member {0} in type {1} does not refer to a field or a function", e.MemberName, nptype); } } else if (expr is SeqSelectExpr) { @@ -7219,7 +7103,7 @@ namespace Microsoft.Dafny Contract.Assert(e.Array.Type != null); // follows from postcondition of ResolveExpression Type elementType = new InferredTypeProxy(); if (!UnifyTypes(e.Array.Type, ResolvedArrayType(e.Array.tok, e.Indices.Count, elementType, opts.codeContext))) { - Error(e.Array, "array selection requires an array{0} (got {1})", e.Indices.Count, e.Array.Type); + reporter.Error(MessageSource.Resolver, e.Array, "array selection requires an array{0} (got {1})", e.Indices.Count, e.Array.Type); } int i = 0; foreach (Expression idx in e.Indices) { @@ -7227,7 +7111,7 @@ namespace Microsoft.Dafny ResolveExpression(idx, opts); Contract.Assert(idx.Type != null); // follows from postcondition of ResolveExpression if (!UnifyTypes(idx.Type, new OperationTypeProxy(true, false, false, false, false, false))) { - Error(idx, "array selection requires integer-based numeric indices (got {0} for index {1})", idx.Type, i); + reporter.Error(MessageSource.Resolver, idx, "array selection requires integer-based numeric indices (got {0} for index {1})", idx.Type, i); } i++; } @@ -7244,42 +7128,42 @@ namespace Microsoft.Dafny ResolveExpression(e.Index, opts); Contract.Assert(e.Index.Type != null); // follows from postcondition of ResolveExpression if (!UnifyTypes(e.Index.Type, Type.Int)) { - Error(e.Index, "sequence update requires integer index (got {0})", e.Index.Type); + reporter.Error(MessageSource.Resolver, e.Index, "sequence update requires integer index (got {0})", e.Index.Type); } ResolveExpression(e.Value, opts); Contract.Assert(e.Value.Type != null); // follows from postcondition of ResolveExpression if (!UnifyTypes(e.Value.Type, elementType)) { - Error(e.Value, "sequence update requires the value to have the element type of the sequence (got {0})", e.Value.Type); + reporter.Error(MessageSource.Resolver, e.Value, "sequence update requires the value to have the element type of the sequence (got {0})", e.Value.Type); } expr.Type = e.Seq.Type; } else if (UnifyTypes(e.Seq.Type, new MapType(true, domainType, rangeType))) { ResolveExpression(e.Index, opts); if (!UnifyTypes(e.Index.Type, domainType)) { - Error(e.Index, "map update requires domain element to be of type {0} (got {1})", domainType, e.Index.Type); + reporter.Error(MessageSource.Resolver, e.Index, "map update requires domain element to be of type {0} (got {1})", domainType, e.Index.Type); } ResolveExpression(e.Value, opts); if (!UnifyTypes(e.Value.Type, rangeType)) { - Error(e.Value, "map update requires the value to have the range type {0} (got {1})", rangeType, e.Value.Type); + reporter.Error(MessageSource.Resolver, e.Value, "map update requires the value to have the range type {0} (got {1})", rangeType, e.Value.Type); } expr.Type = e.Seq.Type; } else if (UnifyTypes(e.Seq.Type, new MapType(false, domainType, rangeType))) { ResolveExpression(e.Index, opts); if (!UnifyTypes(e.Index.Type, domainType)) { - Error(e.Index, "imap update requires domain element to be of type {0} (got {1})", domainType, e.Index.Type); + reporter.Error(MessageSource.Resolver, e.Index, "imap update requires domain element to be of type {0} (got {1})", domainType, e.Index.Type); } ResolveExpression(e.Value, opts); if (!UnifyTypes(e.Value.Type, rangeType)) { - Error(e.Value, "imap update requires the value to have the range type {0} (got {1})", rangeType, e.Value.Type); + reporter.Error(MessageSource.Resolver, e.Value, "imap update requires the value to have the range type {0} (got {1})", rangeType, e.Value.Type); } expr.Type = e.Seq.Type; } else if (UnifyTypes(e.Seq.Type, new MultiSetType(elementType))) { ResolveExpression(e.Index, opts); if (!UnifyTypes(e.Index.Type, elementType)) { - Error(e.Index, "multiset update requires domain element to be of type {0} (got {1})", elementType, e.Index.Type); + reporter.Error(MessageSource.Resolver, e.Index, "multiset update requires domain element to be of type {0} (got {1})", elementType, e.Index.Type); } ResolveExpression(e.Value, opts); if (!UnifyTypes(e.Value.Type, new OperationTypeProxy(true, false, false, false, false, false))) { - Error(e.Value, "multiset update requires integer-based numeric value (got {0})", e.Value.Type); + reporter.Error(MessageSource.Resolver, e.Value, "multiset update requires integer-based numeric value (got {0})", e.Value.Type); } expr.Type = e.Seq.Type; @@ -7297,7 +7181,7 @@ namespace Microsoft.Dafny var ei = (SeqUpdateExpr)eIter; if (!(ei.Index is NameSegment|| (ei.Index is LiteralExpr && ((LiteralExpr)ei.Index).Value is BigInteger))) { - Error(expr, "datatype updates must be to datatype destructors"); + reporter.Error(MessageSource.Resolver, expr, "datatype updates must be to datatype destructors"); } else { string destructor_str = null; @@ -7313,12 +7197,12 @@ namespace Microsoft.Dafny if (IndexToValue.ContainsKey(destructor_str)) { // Don't bother trying to optimize this case; we'd have to drop one of the updates, // which makes resolving the dropped update an annoyance. - Warning(ei.tok, "update to {0} overwritten by another update to {1}", destructor_str, destructor_str); + reporter.Warning(MessageSource.Resolver, ei.tok, "update to {0} overwritten by another update to {1}", destructor_str, destructor_str); break; } MemberDecl member; if (!datatypeMembers[dt].TryGetValue(destructor_str, out member)) { - Error(expr, "member {0} does not exist in datatype {1}", destructor_str, dt.Name); + reporter.Error(MessageSource.Resolver, expr, "member {0} does not exist in datatype {1}", destructor_str, dt.Name); } else { DatatypeDestructor destructor = (DatatypeDestructor)member; if (ctor != null && ctor != destructor.EnclosingCtor) { @@ -7367,7 +7251,7 @@ namespace Microsoft.Dafny expr.Type = e0.Type; } else { - Error(expr, "update requires a sequence, map, or datatype (got {0})", e.Seq.Type); + reporter.Error(MessageSource.Resolver, expr, "update requires a sequence, map, or datatype (got {0})", e.Seq.Type); } } else if (expr is FunctionCallExpr) { @@ -7382,13 +7266,13 @@ namespace Microsoft.Dafny } var fnType = e.Function.Type.AsArrowType; if (fnType == null) { - Error(e.tok, "non-function expression (of type {0}) is called with parameters", e.Function.Type); + reporter.Error(MessageSource.Resolver, e.tok, "non-function expression (of type {0}) is called with parameters", e.Function.Type); } else if (fnType.Arity != e.Args.Count) { - Error(e.tok, "wrong number of arguments to function application (function type '{0}' expects {1}, got {2})", fnType, fnType.Arity, e.Args.Count); + reporter.Error(MessageSource.Resolver, e.tok, "wrong number of arguments to function application (function type '{0}' expects {1}, got {2})", fnType, fnType.Arity, e.Args.Count); } else { for (var i = 0; i < fnType.Arity; i++) { if (!UnifyTypes(fnType.Args[i], e.Args[i].Type)) { - Error(e.Args[i].tok, "type mismatch for argument {0} (function expects {1}, got {2})", i, fnType.Args[i], e.Args[i].Type); + reporter.Error(MessageSource.Resolver, e.Args[i].tok, "type mismatch for argument {0} (function expects {1}, got {2})", i, fnType.Args[i], e.Args[i].Type); } } } @@ -7397,7 +7281,7 @@ namespace Microsoft.Dafny } else if (expr is OldExpr) { OldExpr e = (OldExpr)expr; if (!opts.twoState) { - Error(expr, "old expressions are not allowed in this context"); + reporter.Error(MessageSource.Resolver, expr, "old expressions are not allowed in this context"); } ResolveExpression(e.E, opts); expr.Type = e.E.Type; @@ -7406,7 +7290,7 @@ namespace Microsoft.Dafny MultiSetFormingExpr e = (MultiSetFormingExpr)expr; ResolveExpression(e.E, opts); if (!UnifyTypes(e.E.Type, new SetType(true, new InferredTypeProxy())) && !UnifyTypes(e.E.Type, new SeqType(new InferredTypeProxy()))) { - Error(e.tok, "can only form a multiset from a seq or set."); + reporter.Error(MessageSource.Resolver, e.tok, "can only form a multiset from a seq or set."); } expr.Type = new MultiSetType(e.E.Type.AsCollectionType.Arg); @@ -7417,19 +7301,19 @@ namespace Microsoft.Dafny switch (e.Op) { case UnaryOpExpr.Opcode.Not: if (!UnifyTypes(e.E.Type, Type.Bool)) { - Error(expr, "logical negation expects a boolean argument (instead got {0})", e.E.Type); + reporter.Error(MessageSource.Resolver, expr, "logical negation expects a boolean argument (instead got {0})", e.E.Type); } expr.Type = Type.Bool; break; case UnaryOpExpr.Opcode.Cardinality: if (!UnifyTypes(e.E.Type, new CollectionTypeProxy(new InferredTypeProxy(), false, false))) { - Error(expr, "size operator expects a collection argument (instead got {0})", e.E.Type); + reporter.Error(MessageSource.Resolver, expr, "size operator expects a collection argument (instead got {0})", e.E.Type); } expr.Type = Type.Int; break; case UnaryOpExpr.Opcode.Fresh: if (!opts.twoState) { - Error(expr, "fresh expressions are not allowed in this context"); + reporter.Error(MessageSource.Resolver, expr, "fresh expressions are not allowed in this context"); } // the type of e.E must be either an object or a collection of objects Type t = e.E.Type.NormalizeExpand(); @@ -7444,7 +7328,7 @@ namespace Microsoft.Dafny } else if (t.IsDatatype) { // fine, treat this as the datatype itself. } else { - Error(expr, "the argument of a fresh expression must denote an object or a collection of objects (instead got {0})", e.E.Type); + reporter.Error(MessageSource.Resolver, expr, "the argument of a fresh expression must denote an object or a collection of objects (instead got {0})", e.E.Type); } expr.Type = Type.Bool; break; @@ -7458,14 +7342,14 @@ namespace Microsoft.Dafny ResolveExpression(e.E, opts); if (e.ToType.IsNumericBased(Type.NumericPersuation.Int)) { if (!UnifyTypes(e.E.Type, new OperationTypeProxy(true, true, false, false, false, false))) { - Error(expr, "type conversion to an int-based type is allowed only from numeric types (got {0})", e.E.Type); + reporter.Error(MessageSource.Resolver, expr, "type conversion to an int-based type is allowed only from numeric types (got {0})", e.E.Type); } } else if (e.ToType.IsNumericBased(Type.NumericPersuation.Real)) { if (!UnifyTypes(e.E.Type, new OperationTypeProxy(true, true, false, false, false, false))) { - Error(expr, "type conversion to a real-based type is allowed only from numeric types (got {0})", e.E.Type); + reporter.Error(MessageSource.Resolver, expr, "type conversion to a real-based type is allowed only from numeric types (got {0})", e.E.Type); } } else { - Error(expr, "type conversions are not supported to this type (got {0})", e.ToType); + reporter.Error(MessageSource.Resolver, expr, "type conversions are not supported to this type (got {0})", e.ToType); } e.Type = e.ToType; @@ -7482,10 +7366,10 @@ namespace Microsoft.Dafny case BinaryExpr.Opcode.And: case BinaryExpr.Opcode.Or: if (!UnifyTypes(e.E0.Type, Type.Bool)) { - Error(expr, "first argument to {0} must be of type bool (instead got {1})", BinaryExpr.OpcodeString(e.Op), e.E0.Type); + reporter.Error(MessageSource.Resolver, expr, "first argument to {0} must be of type bool (instead got {1})", BinaryExpr.OpcodeString(e.Op), e.E0.Type); } if (!UnifyTypes(e.E1.Type, Type.Bool)) { - Error(expr, "second argument to {0} must be of type bool (instead got {1})", BinaryExpr.OpcodeString(e.Op), e.E1.Type); + reporter.Error(MessageSource.Resolver, expr, "second argument to {0} must be of type bool (instead got {1})", BinaryExpr.OpcodeString(e.Op), e.E1.Type); } expr.Type = Type.Bool; break; @@ -7506,7 +7390,7 @@ namespace Microsoft.Dafny // unification will succeed. } else { // The types are not comparable and do not unify. It's time for an error message. - Error(expr, "arguments must have the same type (got {0} and {1})", e.E0.Type, e.E1.Type); + reporter.Error(MessageSource.Resolver, expr, "arguments must have the same type (got {0} and {1})", e.E0.Type, e.E1.Type); } expr.Type = Type.Bool; break; @@ -7514,12 +7398,12 @@ namespace Microsoft.Dafny case BinaryExpr.Opcode.Disjoint: // TODO: the error messages are backwards from what (ideally) they should be. this is necessary because UnifyTypes can't backtrack. if (!UnifyTypes(e.E0.Type, e.E1.Type)) { - Error(expr, "arguments must have the same type (got {0} and {1})", e.E0.Type, e.E1.Type); + reporter.Error(MessageSource.Resolver, expr, "arguments must have the same type (got {0} and {1})", e.E0.Type, e.E1.Type); } if (!UnifyTypes(e.E0.Type, new SetType(true, new InferredTypeProxy())) && !UnifyTypes(e.E0.Type, new MultiSetType(new InferredTypeProxy())) && !UnifyTypes(e.E0.Type, new MapType(true, new InferredTypeProxy(), new InferredTypeProxy()))) { - Error(expr, "arguments must be of a [multi]set or map type (got {0})", e.E0.Type); + reporter.Error(MessageSource.Resolver, expr, "arguments must be of a [multi]set or map type (got {0})", e.E0.Type); } expr.Type = Type.Bool; break; @@ -7531,26 +7415,26 @@ namespace Microsoft.Dafny if (UnifyTypes(e.E1.Type, new DatatypeProxy(false, false))) { e.ResolvedOp = BinaryExpr.ResolvedOpcode.RankLt; } else { - Error(expr, "arguments to rank comparison must be datatypes (instead of {0})", e.E1.Type); + reporter.Error(MessageSource.Resolver, expr, "arguments to rank comparison must be datatypes (instead of {0})", e.E1.Type); } expr.Type = Type.Bool; } else if (e.Op == BinaryExpr.Opcode.Lt && e.E1.Type.NormalizeExpand().IsIndDatatype) { if (UnifyTypes(e.E0.Type, new DatatypeProxy(false, true))) { e.ResolvedOp = BinaryExpr.ResolvedOpcode.RankLt; } else { - Error(expr, "arguments to rank comparison must be datatypes (instead of {0})", e.E0.Type); + reporter.Error(MessageSource.Resolver, expr, "arguments to rank comparison must be datatypes (instead of {0})", e.E0.Type); } expr.Type = Type.Bool; } else { bool err = false; bool isComparison = e.Op != BinaryExpr.Opcode.Add; if (!UnifyTypes(e.E0.Type, new OperationTypeProxy(true, true, isComparison, true, true, true))) { - Error(expr, "arguments to {0} must be of a numeric type{2} or a collection type (instead got {1})", BinaryExpr.OpcodeString(e.Op), e.E0.Type, + reporter.Error(MessageSource.Resolver, expr, "arguments to {0} must be of a numeric type{2} or a collection type (instead got {1})", BinaryExpr.OpcodeString(e.Op), e.E0.Type, isComparison ? ", char," : ""); err = true; } if (!UnifyTypes(e.E1.Type, e.E0.Type)) { - Error(expr, "arguments to {0} must have the same type (got {1} and {2})", BinaryExpr.OpcodeString(e.Op), e.E0.Type, e.E1.Type); + reporter.Error(MessageSource.Resolver, expr, "arguments to {0} must have the same type (got {1} and {2})", BinaryExpr.OpcodeString(e.Op), e.E0.Type, e.E1.Type); err = true; } if (isComparison) { @@ -7570,26 +7454,26 @@ namespace Microsoft.Dafny if (UnifyTypes(e.E1.Type, new DatatypeProxy(false, true))) { e.ResolvedOp = BinaryExpr.ResolvedOpcode.RankGt; } else { - Error(expr, "arguments to rank comparison must be datatypes (instead of {0})", e.E1.Type); + reporter.Error(MessageSource.Resolver, expr, "arguments to rank comparison must be datatypes (instead of {0})", e.E1.Type); } expr.Type = Type.Bool; } else if (e.Op == BinaryExpr.Opcode.Gt && (e.E1.Type.NormalizeExpand().IsIndDatatype || e.E1.Type.IsTypeParameter)) { if (UnifyTypes(e.E0.Type, new DatatypeProxy(false, false))) { e.ResolvedOp = BinaryExpr.ResolvedOpcode.RankGt; } else { - Error(expr, "arguments to rank comparison must be datatypes (instead of {0})", e.E0.Type); + reporter.Error(MessageSource.Resolver, expr, "arguments to rank comparison must be datatypes (instead of {0})", e.E0.Type); } expr.Type = Type.Bool; } else { bool err = false; bool isComparison = e.Op == BinaryExpr.Opcode.Gt || e.Op == BinaryExpr.Opcode.Ge; if (!UnifyTypes(e.E0.Type, new OperationTypeProxy(true, true, isComparison, false, true, true))) { - Error(expr, "arguments to {0} must be of a numeric type{2} or a set type (instead got {1})", BinaryExpr.OpcodeString(e.Op), e.E0.Type, + reporter.Error(MessageSource.Resolver, expr, "arguments to {0} must be of a numeric type{2} or a set type (instead got {1})", BinaryExpr.OpcodeString(e.Op), e.E0.Type, isComparison ? ", char, " : ""); err = true; } if (!UnifyTypes(e.E1.Type, e.E0.Type)) { - Error(expr, "arguments to {0} must have the same type (got {1} and {2})", BinaryExpr.OpcodeString(e.Op), e.E0.Type, e.E1.Type); + reporter.Error(MessageSource.Resolver, expr, "arguments to {0} must have the same type (got {1} and {2})", BinaryExpr.OpcodeString(e.Op), e.E0.Type, e.E1.Type); err = true; } if (isComparison) { @@ -7604,27 +7488,27 @@ namespace Microsoft.Dafny case BinaryExpr.Opcode.In: case BinaryExpr.Opcode.NotIn: if (!UnifyTypes(e.E1.Type, new CollectionTypeProxy(e.E0.Type, true, true))) { - Error(expr, "second argument to \"{0}\" must be a set, multiset, or sequence with elements of type {1}, or a map with domain {1} (instead got {2})", BinaryExpr.OpcodeString(e.Op), e.E0.Type, e.E1.Type); + reporter.Error(MessageSource.Resolver, expr, "second argument to \"{0}\" must be a set, multiset, or sequence with elements of type {1}, or a map with domain {1} (instead got {2})", BinaryExpr.OpcodeString(e.Op), e.E0.Type, e.E1.Type); } expr.Type = Type.Bool; break; case BinaryExpr.Opcode.Div: if (!UnifyTypes(e.E0.Type, new OperationTypeProxy(true, true, false, false, false, false))) { - Error(expr, "first argument to {0} must be of numeric type (instead got {1})", BinaryExpr.OpcodeString(e.Op), e.E0.Type); + reporter.Error(MessageSource.Resolver, expr, "first argument to {0} must be of numeric type (instead got {1})", BinaryExpr.OpcodeString(e.Op), e.E0.Type); } if (!UnifyTypes(e.E1.Type, e.E0.Type)) { - Error(expr, "arguments to {0} must have the same type (got {1} and {2})", BinaryExpr.OpcodeString(e.Op), e.E0.Type, e.E1.Type); + reporter.Error(MessageSource.Resolver, expr, "arguments to {0} must have the same type (got {1} and {2})", BinaryExpr.OpcodeString(e.Op), e.E0.Type, e.E1.Type); } expr.Type = e.E0.Type; break; case BinaryExpr.Opcode.Mod: if (!UnifyTypes(e.E0.Type, new OperationTypeProxy(true, false, false, false, false, false))) { - Error(expr, "first argument to {0} must be of type int (instead got {1})", BinaryExpr.OpcodeString(e.Op), e.E0.Type); + reporter.Error(MessageSource.Resolver, expr, "first argument to {0} must be of type int (instead got {1})", BinaryExpr.OpcodeString(e.Op), e.E0.Type); } if (!UnifyTypes(e.E1.Type, e.E0.Type)) { - Error(expr, "second argument to {0} must be of type int (instead got {1})", BinaryExpr.OpcodeString(e.Op), e.E1.Type); + reporter.Error(MessageSource.Resolver, expr, "second argument to {0} must be of type int (instead got {1})", BinaryExpr.OpcodeString(e.Op), e.E1.Type); } expr.Type = e.E0.Type; break; @@ -7644,13 +7528,13 @@ namespace Microsoft.Dafny case TernaryExpr.Opcode.PrefixEqOp: case TernaryExpr.Opcode.PrefixNeqOp: if (!UnifyTypes(e.E0.Type, Type.Int)) { - Error(e.E0, "prefix-equality limit argument must be an integer expression (got {0})", e.E0.Type); + reporter.Error(MessageSource.Resolver, e.E0, "prefix-equality limit argument must be an integer expression (got {0})", e.E0.Type); } if (!UnifyTypes(e.E1.Type, new DatatypeProxy(true))) { - Error(expr, "arguments to prefix equality must be codatatypes (instead of {0})", e.E1.Type); + reporter.Error(MessageSource.Resolver, expr, "arguments to prefix equality must be codatatypes (instead of {0})", e.E1.Type); } if (!UnifyTypes(e.E1.Type, e.E2.Type)) { - Error(expr, "arguments must have the same type (got {0} and {1})", e.E1.Type, e.E2.Type); + reporter.Error(MessageSource.Resolver, expr, "arguments must have the same type (got {0} and {1})", e.E1.Type, e.E2.Type); } expr.Type = Type.Bool; break; @@ -7667,7 +7551,7 @@ namespace Microsoft.Dafny } scope.PushMarker(); if (e.LHSs.Count != e.RHSs.Count) { - Error(expr, "let expression must have same number of LHSs (found {0}) as RHSs (found {1})", e.LHSs.Count, e.RHSs.Count); + reporter.Error(MessageSource.Resolver, 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) { @@ -7681,14 +7565,14 @@ namespace Microsoft.Dafny } if (c == 0) { // Every identifier-looking thing in the pattern resolved to a constructor; that is, this LHS is a constant literal - Error(lhs.tok, "LHS is a constant literal; to be legal, it must introduce at least one bound variable"); + reporter.Error(MessageSource.Resolver, 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) { - Error(expr, "let-such-that expression must have just one RHS (found {0})", e.RHSs.Count); + reporter.Error(MessageSource.Resolver, 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(); @@ -7701,7 +7585,7 @@ namespace Microsoft.Dafny foreach (var rhs in e.RHSs) { ResolveExpression(rhs, opts); if (!UnifyTypes(rhs.Type, Type.Bool)) { - Error(rhs.tok, "type of RHS of let-such-that expression must be boolean (got {0})", rhs.Type); + reporter.Error(MessageSource.Resolver, rhs.tok, "type of RHS of let-such-that expression must be boolean (got {0})", rhs.Type); } } if (!opts.DontCareAboutCompilation && !e.BoundVars.All(bv => bv.IsGhost)) { @@ -7720,7 +7604,7 @@ namespace Microsoft.Dafny e.Type = e.Body.Type; } else if (expr is QuantifierExpr) { QuantifierExpr e = (QuantifierExpr)expr; - int prevErrorCount = ErrorCount; + int prevErrorCount = reporter.Count(ErrorLevel.Error); bool _val = true; bool typeQuantifier = Attributes.ContainsBool(e.Attributes, "typeQuantifier", ref _val) && _val; allTypeParameters.PushMarker(); @@ -7732,19 +7616,19 @@ namespace Microsoft.Dafny ResolveType(v.tok, v.Type, opts.codeContext, option, typeQuantifier ? e.TypeArgs : null); } if (e.TypeArgs.Count > 0 && !typeQuantifier) { - Error(expr, "a quantifier cannot quantify over types. Possible fix: use the experimental attribute :typeQuantifier"); + reporter.Error(MessageSource.Resolver, expr, "a quantifier cannot quantify over types. Possible fix: use the experimental attribute :typeQuantifier"); } if (e.Range != null) { ResolveExpression(e.Range, new ResolveOpts(opts, true)); Contract.Assert(e.Range.Type != null); // follows from postcondition of ResolveExpression if (!UnifyTypes(e.Range.Type, Type.Bool)) { - Error(expr, "range of quantifier must be of type bool (instead got {0})", e.Range.Type); + reporter.Error(MessageSource.Resolver, expr, "range of quantifier must be of type bool (instead got {0})", e.Range.Type); } } ResolveExpression(e.Term, new ResolveOpts(opts, true)); Contract.Assert(e.Term.Type != null); // follows from postcondition of ResolveExpression if (!UnifyTypes(e.Term.Type, Type.Bool)) { - Error(expr, "body of quantifier must be of type bool (instead got {0})", e.Term.Type); + reporter.Error(MessageSource.Resolver, expr, "body of quantifier must be of type bool (instead got {0})", e.Term.Type); } // 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). @@ -7753,10 +7637,10 @@ namespace Microsoft.Dafny allTypeParameters.PopMarker(); expr.Type = Type.Bool; - if (prevErrorCount == ErrorCount) { + if (prevErrorCount == reporter.Count(ErrorLevel.Error)) { var missingBounds = new List(); CheckTypeInference(e.LogicalBody()); // we need to resolve operators before the call to DiscoverBounds - e.Bounds = DiscoverBounds(e.tok, e.BoundVars, e.LogicalBody(), e is ExistsExpr, false, missingBounds); + e.Bounds = DiscoverBounds(e.tok, e.BoundVars, e.LogicalBody(), e is ExistsExpr, false, missingBounds, reporter); if (missingBounds.Count != 0) { // Report errors here about quantifications that depend on the allocation state. var mb = missingBounds; @@ -7764,7 +7648,7 @@ namespace Microsoft.Dafny mb = new List(); // (who cares if we allocate another array; this happens only in the case of a resolution error anyhow) foreach (var bv in missingBounds) { if (bv.Type.IsRefType) { - Error(expr, "a quantifier involved in a function definition is not allowed to depend on the set of allocated references; Dafny's heuristics can't figure out a bound for the values of '{0}'", bv.Name); + reporter.Error(MessageSource.Resolver, expr, "a quantifier involved in a function definition is not allowed to depend on the set of allocated references; Dafny's heuristics can't figure out a bound for the values of '{0}'", bv.Name); } else { mb.Add(bv); } @@ -7778,7 +7662,7 @@ namespace Microsoft.Dafny } else if (expr is SetComprehension) { var e = (SetComprehension)expr; - int prevErrorCount = ErrorCount; + int prevErrorCount = reporter.Count(ErrorLevel.Error); scope.PushMarker(); foreach (BoundVar v in e.BoundVars) { ScopePushAndReport(scope, v, "bound-variable"); @@ -7787,7 +7671,7 @@ namespace Microsoft.Dafny ResolveExpression(e.Range, opts); Contract.Assert(e.Range.Type != null); // follows from postcondition of ResolveExpression if (!UnifyTypes(e.Range.Type, Type.Bool)) { - Error(expr, "range of comprehension must be of type bool (instead got {0})", e.Range.Type); + reporter.Error(MessageSource.Resolver, expr, "range of comprehension must be of type bool (instead got {0})", e.Range.Type); } ResolveExpression(e.Term, opts); Contract.Assert(e.Term.Type != null); // follows from postcondition of ResolveExpression @@ -7804,10 +7688,10 @@ namespace Microsoft.Dafny } else if (expr is MapComprehension) { var e = (MapComprehension)expr; - int prevErrorCount = ErrorCount; + int prevErrorCount = reporter.Count(ErrorLevel.Error); scope.PushMarker(); if (e.BoundVars.Count != 1) { - Error(e.tok, "a map comprehension must have exactly one bound variable."); + reporter.Error(MessageSource.Resolver, e.tok, "a map comprehension must have exactly one bound variable."); } foreach (BoundVar v in e.BoundVars) { ScopePushAndReport(scope, v, "bound-variable"); @@ -7816,7 +7700,7 @@ namespace Microsoft.Dafny ResolveExpression(e.Range, opts); Contract.Assert(e.Range.Type != null); // follows from postcondition of ResolveExpression if (!UnifyTypes(e.Range.Type, Type.Bool)) { - Error(expr, "range of comprehension must be of type bool (instead got {0})", e.Range.Type); + reporter.Error(MessageSource.Resolver, expr, "range of comprehension must be of type bool (instead got {0})", e.Range.Type); } ResolveExpression(e.Term, opts); Contract.Assert(e.Term.Type != null); // follows from postcondition of ResolveExpression @@ -7825,22 +7709,22 @@ namespace Microsoft.Dafny scope.PopMarker(); expr.Type = new MapType(e.Finite, e.BoundVars[0].Type, e.Term.Type); - if (prevErrorCount == ErrorCount) { + if (prevErrorCount == reporter.Count(ErrorLevel.Error)) { var missingBounds = new List(); CheckTypeInference(e.Range); // we need to resolve operators before the call to DiscoverBounds - e.Bounds = DiscoverBounds(e.tok, e.BoundVars, e.Range, true, false, missingBounds); + e.Bounds = DiscoverBounds(e.tok, e.BoundVars, e.Range, true, false, missingBounds, reporter); if (missingBounds.Count != 0) { e.MissingBounds = missingBounds; if (e.Finite) { foreach (var bv in e.MissingBounds) { - Error(expr, "a map comprehension must produce a finite domain, but Dafny's heuristics can't figure out how to produce a bounded set of values for '{0}'", bv.Name); + reporter.Error(MessageSource.Resolver, expr, "a map comprehension must produce a finite domain, but Dafny's heuristics can't figure out how to produce a bounded set of values for '{0}'", bv.Name); } } } } } else if (expr is LambdaExpr) { var e = (LambdaExpr)expr; - int prevErrorCount = ErrorCount; + int prevErrorCount = reporter.Count(ErrorLevel.Error); scope.PushMarker(); foreach (BoundVar v in e.BoundVars) { ScopePushAndReport(scope, v, "bound-variable"); @@ -7851,7 +7735,7 @@ namespace Microsoft.Dafny ResolveExpression(e.Range, opts); Contract.Assert(e.Range.Type != null); // follows from postcondition of ResolveExpression if (!UnifyTypes(e.Range.Type, Type.Bool)) { - Error(expr, "Precondition must be boolean (got {0})", e.Range.Type); + reporter.Error(MessageSource.Resolver, expr, "Precondition must be boolean (got {0})", e.Range.Type); } } @@ -7867,14 +7751,14 @@ namespace Microsoft.Dafny expr.Type = new SetType(true, new ObjectType()); } else if (expr is StmtExpr) { var e = (StmtExpr)expr; - int prevErrorCount = ErrorCount; + int prevErrorCount = reporter.Count(ErrorLevel.Error); ResolveStatement(e.S, true, opts.codeContext); - if (ErrorCount == prevErrorCount) { + if (reporter.Count(ErrorLevel.Error) == prevErrorCount) { var r = e.S as UpdateStmt; if (r != null && r.ResolvedStatements.Count == 1) { var call = r.ResolvedStatements[0] as CallStmt; if (call.Method.Mod.Expressions.Count != 0) { - Error(call, "calls to methods with side-effects are not allowed inside a statement expression"); + reporter.Error(MessageSource.Resolver, call, "calls to methods with side-effects are not allowed inside a statement expression"); } } } @@ -7891,12 +7775,12 @@ namespace Microsoft.Dafny ResolveExpression(e.Els, opts); Contract.Assert(e.Els.Type != null); // follows from postcondition of ResolveExpression if (!UnifyTypes(e.Test.Type, Type.Bool)) { - Error(expr, "guard condition in if-then-else expression must be a boolean (instead got {0})", e.Test.Type); + reporter.Error(MessageSource.Resolver, expr, "guard condition in if-then-else expression must be a boolean (instead got {0})", e.Test.Type); } if (UnifyTypes(e.Thn.Type, e.Els.Type)) { expr.Type = e.Thn.Type; } else { - Error(expr, "the two branches of an if-then-else expression must have the same type (got {0} and {1})", e.Thn.Type, e.Els.Type); + reporter.Error(MessageSource.Resolver, expr, "the two branches of an if-then-else expression must have the same type (got {0} and {1})", e.Thn.Type, e.Els.Type); } } else if (expr is MatchExpr) { @@ -7926,7 +7810,7 @@ namespace Microsoft.Dafny var subst = new Dictionary(); Dictionary ctors; if (dtd == null) { - Error(me.Source, "the type of the match source expression must be a datatype (instead found {0})", me.Source.Type); + reporter.Error(MessageSource.Resolver, me.Source, "the type of the match source expression must be a datatype (instead found {0})", me.Source.Type); ctors = null; } else { Contract.Assert(sourceType != null); // dtd and sourceType are set together above @@ -7955,15 +7839,15 @@ namespace Microsoft.Dafny if (ctors != null) { Contract.Assert(dtd != null); if (!ctors.TryGetValue(mc.Id, out ctor)) { - Error(mc.tok, "member {0} does not exist in datatype {1}", mc.Id, dtd.Name); + reporter.Error(MessageSource.Resolver, mc.tok, "member {0} does not exist in datatype {1}", mc.Id, dtd.Name); } else { Contract.Assert(ctor != null); // follows from postcondition of TryGetValue mc.Ctor = ctor; if (ctor.Formals.Count != mc.Arguments.Count) { - Error(mc.tok, "member {0} has wrong number of formals (found {1}, expected {2})", mc.Id, mc.Arguments.Count, ctor.Formals.Count); + reporter.Error(MessageSource.Resolver, mc.tok, "member {0} has wrong number of formals (found {1}, expected {2})", mc.Id, mc.Arguments.Count, ctor.Formals.Count); } if (memberNamesUsed.Contains(mc.Id)) { - Error(mc.tok, "member {0} appears in more than one case", mc.Id); + reporter.Error(MessageSource.Resolver, mc.tok, "member {0} appears in more than one case", mc.Id); } else { memberNamesUsed.Add(mc.Id); // add mc.Id to the set of names used } @@ -7979,7 +7863,7 @@ namespace Microsoft.Dafny Formal formal = ctor.Formals[i]; Type st = SubstType(formal.Type, subst); if (!UnifyTypes(v.Type, st)) { - Error(expr, "the declared type of the formal ({0}) does not agree with the corresponding type in the constructor's signature ({1})", v.Type, st); + reporter.Error(MessageSource.Resolver, expr, "the declared type of the formal ({0}) does not agree with the corresponding type in the constructor's signature ({1})", v.Type, st); } v.IsGhost = formal.IsGhost; @@ -8006,7 +7890,7 @@ namespace Microsoft.Dafny Contract.Assert(mc.Body.Type != null); // follows from postcondition of ResolveExpression if (!UnifyTypes(expr.Type, mc.Body.Type)) { - Error(mc.Body.tok, "type of case bodies do not agree (found {0}, previous types {1})", mc.Body.Type, expr.Type); + reporter.Error(MessageSource.Resolver, mc.Body.tok, "type of case bodies do not agree (found {0}, previous types {1})", mc.Body.Type, expr.Type); } scope.PopMarker(); } @@ -8044,13 +7928,13 @@ namespace Microsoft.Dafny if (me.Source is DatatypeValue) { var e = (DatatypeValue)me.Source; if (e.Arguments.Count < 1) { - Error(me.tok, "match source tuple needs at least 1 argument"); + reporter.Error(MessageSource.Resolver, me.tok, "match source tuple needs at least 1 argument"); } else { Expression source = e.Arguments[0]; List cases = new List(); foreach (MatchCaseExpr mc in me.Cases) { if (mc.CasePatterns == null || mc.CasePatterns.Count != e.Arguments.Count) { - Error(mc.tok, "case arguments count does not match source arguments count"); + reporter.Error(MessageSource.Resolver, mc.tok, "case arguments count does not match source arguments count"); } else { CasePattern cp = mc.CasePatterns[0]; List patterns; @@ -8342,17 +8226,17 @@ namespace Microsoft.Dafny var v = pat.Var; ResolveType(v.tok, v.Type, context, ResolveTypeOptionEnum.InferTypeProxies, null); if (!UnifyTypes(v.Type, sourceType)) { - Error(v.tok, "type of corresponding source/RHS ({0}) does not match type of bound variable ({1})", sourceType, v.Type); + reporter.Error(MessageSource.Resolver, v.tok, "type of corresponding source/RHS ({0}) does not match type of bound variable ({1})", sourceType, v.Type); } pat.AssembleExpr(null); } else if (dtd == null) { - Error(pat.tok, "to use a pattern, the type of the source/RHS expression must be a datatype (instead found {0})", sourceType); + reporter.Error(MessageSource.Resolver, pat.tok, "to use a pattern, the type of the source/RHS expression must be a datatype (instead found {0})", sourceType); } else if (ctor == null) { - Error(pat.tok, "constructor {0} does not exist in datatype {1}", pat.Id, dtd.Name); + reporter.Error(MessageSource.Resolver, pat.tok, "constructor {0} does not exist in datatype {1}", pat.Id, dtd.Name); } else { var argCount = pat.Arguments == null ? 0 : pat.Arguments.Count; if (ctor.Formals.Count != argCount) { - Error(pat.tok, "pattern for constructor {0} has wrong number of formals (found {1}, expected {2})", pat.Id, argCount, ctor.Formals.Count); + reporter.Error(MessageSource.Resolver, pat.tok, "pattern for constructor {0} has wrong number of formals (found {1}, expected {2})", pat.Id, argCount, ctor.Formals.Count); } // build the type-parameter substitution map for this use of the datatype Contract.Assert(dtd.TypeArgs.Count == udt.TypeArgs.Count); // follows from the type previously having been successfully resolved @@ -8408,7 +8292,7 @@ namespace Microsoft.Dafny foreach (var ty in expr.OptTypeArguments) { ResolveType(expr.tok, ty, opts.codeContext, ResolveTypeOptionEnum.InferTypeProxies, null); if (ty.IsSubrangeType) { - Error(expr.tok, "sorry, cannot instantiate type parameter with a subrange type"); + reporter.Error(MessageSource.Resolver, expr.tok, "sorry, cannot instantiate type parameter with a subrange type"); } } } @@ -8431,7 +8315,7 @@ namespace Microsoft.Dafny if (v != null) { // ----- 0. local variable, parameter, or bound variable if (expr.OptTypeArguments != null) { - Error(expr.tok, "variable '{0}' does not take any type parameters", expr.Name); + reporter.Error(MessageSource.Resolver, expr.tok, "variable '{0}' does not take any type parameters", expr.Name); } var rr = new IdentifierExpr(expr.tok, expr.Name); rr.Var = v; rr.Type = v.Type; @@ -8443,7 +8327,7 @@ namespace Microsoft.Dafny receiver = new StaticReceiverExpr(expr.tok, (ClassDecl)member.EnclosingClass, true); } else { if (!scope.AllowInstance) { - Error(expr.tok, "'this' is not allowed in a 'static' context"); //FIXME: Rephrase this + reporter.Error(MessageSource.Resolver, expr.tok, "'this' is not allowed in a 'static' context"); //FIXME: Rephrase this // nevertheless, set "receiver" to a value so we can continue resolution } receiver = new ImplicitThisExpr(expr.tok); @@ -8454,10 +8338,10 @@ namespace Microsoft.Dafny // ----- 2. datatype constructor if (pair.Item2) { // there is more than one constructor with this name - Error(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, pair.Item1.EnclosingDatatype.Name); + reporter.Error(MessageSource.Resolver, 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, pair.Item1.EnclosingDatatype.Name); } else { if (expr.OptTypeArguments != null) { - Error(expr.tok, "datatype constructor does not take any type parameters ('{0}')", expr.Name); + reporter.Error(MessageSource.Resolver, expr.tok, "datatype constructor does not take any type parameters ('{0}')", expr.Name); } var rr = new DatatypeValue(expr.tok, pair.Item1.EnclosingDatatype.Name, expr.Name, args ?? new List()); ResolveDatatypeValue(opts, rr, pair.Item1.EnclosingDatatype); @@ -8472,7 +8356,7 @@ namespace Microsoft.Dafny // ----- 3. Member of the enclosing module if (decl is AmbiguousTopLevelDecl) { var ad = (AmbiguousTopLevelDecl)decl; - Error(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, ad.ModuleNames()); + reporter.Error(MessageSource.Resolver, 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, ad.ModuleNames()); } 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 expresion. We postpone the rest of the @@ -8486,7 +8370,7 @@ namespace Microsoft.Dafny 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; - Error(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()); + reporter.Error(MessageSource.Resolver, 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 { var receiver = new StaticReceiverExpr(expr.tok, (ClassDecl)member.EnclosingClass, true); r = ResolveExprDotCall(expr.tok, receiver, member, expr.OptTypeArguments, opts.codeContext, allowMethodCall); @@ -8494,7 +8378,7 @@ namespace Microsoft.Dafny } else { // ----- None of the above - Error(expr.tok, "unresolved identifier: {0}", expr.Name); + reporter.Error(MessageSource.Resolver, expr.tok, "unresolved identifier: {0}", expr.Name); } if (r == null) { @@ -8526,7 +8410,7 @@ namespace Microsoft.Dafny foreach (var ty in expr.OptTypeArguments) { ResolveType(expr.tok, ty, opts.codeContext, option, defaultTypeArguments); if (ty.IsSubrangeType) { - Error(expr.tok, "sorry, cannot instantiate type parameter with a subrange type"); + reporter.Error(MessageSource.Resolver, expr.tok, "sorry, cannot instantiate type parameter with a subrange type"); } } } @@ -8550,7 +8434,7 @@ namespace Microsoft.Dafny if (expr.OptTypeArguments == null) { r = new Resolver_IdentifierExpr(expr.tok, tp); } else { - Error(expr.tok, "Type parameter expects no type arguments: {0}", expr.Name); + reporter.Error(MessageSource.Resolver, expr.tok, "Type parameter expects no type arguments: {0}", expr.Name); } #if ASYNC_TASK_TYPES // At the moment, there is no way for a class member to part of a type name, but this changes with async task types } else if (currentClass != null && classMembers.TryGetValue(currentClass, out members) && members.TryGetValue(expr.Name, out member)) { @@ -8572,7 +8456,7 @@ namespace Microsoft.Dafny // ----- 2. Member of the enclosing module if (decl is AmbiguousTopLevelDecl) { var ad = (AmbiguousTopLevelDecl)decl; - Error(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, ad.ModuleNames()); + reporter.Error(MessageSource.Resolver, 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, ad.ModuleNames()); } else { // We have found a module name or a type name, neither of which is a type expression. However, the NameSegment we're // looking at may be followed by a further suffix that makes this into a type expresion. We postpone the rest of the @@ -8594,7 +8478,7 @@ namespace Microsoft.Dafny #endif } else { // ----- None of the above - Error(expr.tok, "Undeclared top-level type or type parameter: {0} (did you forget to qualify a name or declare a module import 'opened?')", expr.Name); + reporter.Error(MessageSource.Resolver, expr.tok, "Undeclared top-level type or type parameter: {0} (did you forget to qualify a name or declare a module import 'opened?')", expr.Name); } if (r == null) { @@ -8615,7 +8499,7 @@ namespace Microsoft.Dafny if (optTypeArguments != null) { // type arguments were supplied; they must be equal in number to those expected if (n != decl.TypeArgs.Count) { - Error(tok, "Wrong number of type arguments ({0} instead of {1}) passed to {2}: {3}", n, decl.TypeArgs.Count, decl.WhatKind, name); + reporter.Error(MessageSource.Resolver, tok, "Wrong number of type arguments ({0} instead of {1}) passed to {2}: {3}", n, decl.TypeArgs.Count, decl.WhatKind, name); } } List tpArgs = new List(); @@ -8667,7 +8551,7 @@ namespace Microsoft.Dafny foreach (var ty in expr.OptTypeArguments) { ResolveType(expr.tok, ty, opts.codeContext, ResolveTypeOptionEnum.InferTypeProxies, null); if (ty.IsSubrangeType) { - Error(expr.tok, "sorry, cannot instantiate type parameter with a subrange type"); + reporter.Error(MessageSource.Resolver, expr.tok, "sorry, cannot instantiate type parameter with a subrange type"); } } } @@ -8690,10 +8574,10 @@ namespace Microsoft.Dafny // ----- 0. datatype constructor if (pair.Item2) { // there is more than one constructor with this name - Error(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}')", expr.SuffixName, pair.Item1.EnclosingDatatype.Name, ((ModuleDecl)ri.Decl).Name); + reporter.Error(MessageSource.Resolver, 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}')", expr.SuffixName, pair.Item1.EnclosingDatatype.Name, ((ModuleDecl)ri.Decl).Name); } else { if (expr.OptTypeArguments != null) { - Error(expr.tok, "datatype constructor does not take any type parameters ('{0}')", expr.SuffixName); + reporter.Error(MessageSource.Resolver, expr.tok, "datatype constructor does not take any type parameters ('{0}')", expr.SuffixName); } var rr = new DatatypeValue(expr.tok, pair.Item1.EnclosingDatatype.Name, expr.SuffixName, args ?? new List()); ResolveExpression(rr, opts); @@ -8708,7 +8592,7 @@ namespace Microsoft.Dafny // ----- 1. Member of the specified module if (decl is AmbiguousTopLevelDecl) { var ad = (AmbiguousTopLevelDecl)decl; - Error(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()); + reporter.Error(MessageSource.Resolver, 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 expresion. We postpone the rest of the @@ -8721,13 +8605,13 @@ namespace Microsoft.Dafny 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; - Error(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()); + reporter.Error(MessageSource.Resolver, 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, (ClassDecl)member.EnclosingClass, true); r = ResolveExprDotCall(expr.tok, receiver, member, expr.OptTypeArguments, opts.codeContext, allowMethodCall); } } else { - Error(expr.tok, "unresolved identifier: {0}", expr.SuffixName); + reporter.Error(MessageSource.Resolver, expr.tok, "unresolved identifier: {0}", expr.SuffixName); } } else if (lhs != null && lhs.Type is Resolver_IdentifierExpr.ResolverType_Type) { @@ -8746,7 +8630,7 @@ namespace Microsoft.Dafny Dictionary members; if (classMembers.TryGetValue(cd, out members) && members.TryGetValue(expr.SuffixName, out member)) { if (!member.IsStatic) { - Error(expr.tok, "accessing member '{0}' requires an instance expression", expr.SuffixName); //FIXME Unify with similar error message + reporter.Error(MessageSource.Resolver, expr.tok, "accessing member '{0}' requires an instance expression", expr.SuffixName); //FIXME Unify with similar error message // nevertheless, continue creating an expression that approximates a correct one } var receiver = new StaticReceiverExpr(expr.tok, (UserDefinedType)ty.NormalizeExpand(), (ClassDecl)member.EnclosingClass, false); @@ -8759,7 +8643,7 @@ namespace Microsoft.Dafny DatatypeCtor ctor; if (datatypeCtors.TryGetValue(dt, out members) && members.TryGetValue(expr.SuffixName, out ctor)) { if (expr.OptTypeArguments != null) { - Error(expr.tok, "datatype constructor does not take any type parameters ('{0}')", expr.SuffixName); + reporter.Error(MessageSource.Resolver, expr.tok, "datatype constructor does not take any type parameters ('{0}')", expr.SuffixName); } var rr = new DatatypeValue(expr.tok, ctor.EnclosingDatatype.Name, expr.SuffixName, args ?? new List()); ResolveDatatypeValue(opts, rr, ctor.EnclosingDatatype); @@ -8772,7 +8656,7 @@ namespace Microsoft.Dafny } } if (r == null) { - Error(expr.tok, "member '{0}' does not exist in type '{1}'", expr.SuffixName, ri.TypeParamDecl != null ? ri.TypeParamDecl.Name : ri.Decl.Name); + reporter.Error(MessageSource.Resolver, expr.tok, "member '{0}' does not exist in type '{1}'", expr.SuffixName, ri.TypeParamDecl != null ? ri.TypeParamDecl.Name : ri.Decl.Name); } } else if (lhs != null) { // ----- 4. Look up name in the type of the Lhs @@ -8832,7 +8716,7 @@ namespace Microsoft.Dafny foreach (var ty in expr.OptTypeArguments) { ResolveType(expr.tok, ty, opts.codeContext, option, defaultTypeArguments); if (ty.IsSubrangeType) { - Error(expr.tok, "sorry, cannot instantiate type parameter with a subrange type"); + reporter.Error(MessageSource.Resolver, expr.tok, "sorry, cannot instantiate type parameter with a subrange type"); } } } @@ -8851,7 +8735,7 @@ namespace Microsoft.Dafny // ----- 0. Member of the specified module if (decl is AmbiguousTopLevelDecl) { var ad = (AmbiguousTopLevelDecl)decl; - Error(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()); + reporter.Error(MessageSource.Resolver, 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. 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. @@ -8869,7 +8753,7 @@ namespace Microsoft.Dafny } #endif } else { - Error(expr.tok, "module '{0}' does not declare a type '{1}'", ri.Decl.Name, expr.SuffixName); + reporter.Error(MessageSource.Resolver, expr.tok, "module '{0}' does not declare a type '{1}'", ri.Decl.Name, expr.SuffixName); } } else if (lhs != null && lhs.Type is Resolver_IdentifierExpr.ResolverType_Type) { @@ -8885,7 +8769,7 @@ namespace Microsoft.Dafny return new ResolveTypeReturn(ty, expr); } if (r == null) { - Error(expr.tok, "member '{0}' does not exist in type '{1}' or cannot be part of type name", expr.SuffixName, ri.TypeParamDecl != null ? ri.TypeParamDecl.Name : ri.Decl.Name); + reporter.Error(MessageSource.Resolver, expr.tok, "member '{0}' does not exist in type '{1}' or cannot be part of type name", expr.SuffixName, ri.TypeParamDecl != null ? ri.TypeParamDecl.Name : ri.Decl.Name); } } @@ -8922,14 +8806,14 @@ namespace Microsoft.Dafny if (member is Field) { if (optTypeArguments != null) { - Error(tok, "a field ({0}) does not take any type arguments (got {1})", member.Name, optTypeArguments.Count); + reporter.Error(MessageSource.Resolver, tok, "a field ({0}) does not take any type arguments (got {1})", member.Name, optTypeArguments.Count); } rr.Type = SubstType(((Field)member).Type, subst); } else if (member is Function) { var fn = (Function)member; int suppliedTypeArguments = optTypeArguments == null ? 0 : optTypeArguments.Count; if (optTypeArguments != null && suppliedTypeArguments != fn.TypeArgs.Count) { - Error(tok, "function '{0}' expects {1} type arguments (got {2})", member.Name, fn.TypeArgs.Count, suppliedTypeArguments); + reporter.Error(MessageSource.Resolver, tok, "function '{0}' expects {1} type arguments (got {2})", member.Name, fn.TypeArgs.Count, suppliedTypeArguments); } rr.TypeApplication = new List(); if (udt != null && udt.ResolvedClass != null) { @@ -8947,11 +8831,11 @@ namespace Microsoft.Dafny var m = (Method)member; if (!allowMethodCall) { // it's a method and method calls are not allowed in the given context - Error(tok, "expression is not allowed to invoke a method ({0})", member.Name); + reporter.Error(MessageSource.Resolver, tok, "expression is not allowed to invoke a method ({0})", member.Name); } int suppliedTypeArguments = optTypeArguments == null ? 0 : optTypeArguments.Count; if (optTypeArguments != null && suppliedTypeArguments != m.TypeArgs.Count) { - Error(tok, "method '{0}' expects {1} type arguments (got {2})", member.Name, m.TypeArgs.Count, suppliedTypeArguments); + reporter.Error(MessageSource.Resolver, tok, "method '{0}' expects {1} type arguments (got {2})", member.Name, m.TypeArgs.Count, suppliedTypeArguments); } rr.TypeApplication = new List(); if (udt != null && udt.ResolvedClass != null) { @@ -8996,7 +8880,7 @@ namespace Microsoft.Dafny Contract.Requires(opts != null); Contract.Ensures(Contract.Result() == null || allowMethodCall); Expression r = null; // upon success, the expression to which the ApplySuffix resolves - var errorCount = ErrorCount; + var errorCount = reporter.Count(ErrorLevel.Error); if (e.Lhs is NameSegment) { r = ResolveNameSegment((NameSegment)e.Lhs, true, e.Args, opts, allowMethodCall); // note, if r is non-null, then e.Args have been resolved and r is a resolved expression that incorporates e.Args @@ -9014,18 +8898,18 @@ namespace Microsoft.Dafny if (fnType == null) { var lhs = e.Lhs.Resolved; if (lhs != null && lhs.Type is Resolver_IdentifierExpr.ResolverType_Module) { - Error(e.tok, "name of module ({0}) is used as a function", ((Resolver_IdentifierExpr)lhs).Decl.Name); + reporter.Error(MessageSource.Resolver, e.tok, "name of module ({0}) is used as a function", ((Resolver_IdentifierExpr)lhs).Decl.Name); } else if (lhs != null && lhs.Type is Resolver_IdentifierExpr.ResolverType_Type) { // It may be a conversion expression var ri = (Resolver_IdentifierExpr)lhs; if (ri.TypeParamDecl != null) { - Error(e.tok, "name of type parameter ({0}) is used as a function", ri.TypeParamDecl.Name); + reporter.Error(MessageSource.Resolver, e.tok, "name of type parameter ({0}) is used as a function", ri.TypeParamDecl.Name); } else { var decl = ri.Decl; var ty = new UserDefinedType(e.tok, decl.Name, decl, ri.TypeArgs); if (ty.AsNewtype != null) { if (e.Args.Count != 1) { - Error(e.tok, "conversion operation to {0} got wrong number of arguments (expected 1, got {1})", decl.Name, e.Args.Count); + reporter.Error(MessageSource.Resolver, e.tok, "conversion operation to {0} got wrong number of arguments (expected 1, got {1})", decl.Name, e.Args.Count); } var conversionArg = 1 <= e.Args.Count ? e.Args[0] : ty.IsNumericBased(Type.NumericPersuation.Int) ? LiteralExpr.CreateIntLiteral(e.tok, 0) : @@ -9037,7 +8921,7 @@ namespace Microsoft.Dafny ResolveExpression(e.Args[i], opts); } } else { - Error(e.tok, "name of type ({0}) is used as a function", decl.Name); + reporter.Error(MessageSource.Resolver, e.tok, "name of type ({0}) is used as a function", decl.Name); } } } else { @@ -9047,10 +8931,10 @@ namespace Microsoft.Dafny var cRhs = new MethodCallInformation(e.tok, mse, e.Args); return cRhs; } else { - Error(e.tok, "method call is not allowed to be used in an expression context ({0})", mse.Member.Name); + reporter.Error(MessageSource.Resolver, e.tok, "method call is not allowed to be used in an expression context ({0})", 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 - Error(e.tok, "non-function expression (of type {0}) is called with parameters", e.Lhs.Type); + reporter.Error(MessageSource.Resolver, e.tok, "non-function expression (of type {0}) is called with parameters", e.Lhs.Type); } } } else { @@ -9058,14 +8942,14 @@ namespace Microsoft.Dafny var callee = mse == null ? null : mse.Member as Function; if (fnType.Arity != e.Args.Count) { var what = callee != null ? string.Format("function '{0}'", callee.Name) : string.Format("function type '{0}'", fnType); - Error(e.tok, "wrong number of arguments to function application ({0} expects {1}, got {2})", what, fnType.Arity, e.Args.Count); + reporter.Error(MessageSource.Resolver, e.tok, "wrong number of arguments to function application ({0} expects {1}, got {2})", what, fnType.Arity, e.Args.Count); } else { for (var i = 0; i < fnType.Arity; i++) { if (!UnifyTypes(fnType.Args[i], e.Args[i].Type)) { - Error(e.Args[i].tok, "type mismatch for argument {0} (function expects {1}, got {2})", i, fnType.Args[i], e.Args[i].Type); + reporter.Error(MessageSource.Resolver, e.Args[i].tok, "type mismatch for argument {0} (function expects {1}, got {2})", i, fnType.Args[i], e.Args[i].Type); } } - if (errorCount != ErrorCount) { + if (errorCount != reporter.Count(ErrorLevel.Error)) { // do nothing else; error has been reported } else if (callee != null) { // produce a FunctionCallExpr instead of an ApplyExpr(MemberSelectExpr) @@ -9090,7 +8974,7 @@ namespace Microsoft.Dafny Contract.Assert(farg.Type != null); // follows from postcondition of ResolveExpression Type s = SubstType(callee.Formals[i].Type, rr.TypeArgumentSubstitutions); if (!UnifyTypes(farg.Type, s)) { - Error(rr, "incorrect type of function argument {0} (expected {1}, got {2})", i, s, farg.Type); + reporter.Error(MessageSource.Resolver, rr, "incorrect type of function argument {0} (expected {1}, got {2})", i, s, farg.Type); } } rr.Type = SubstType(callee.ResultType, rr.TypeArgumentSubstitutions); @@ -9132,12 +9016,12 @@ namespace Microsoft.Dafny DatatypeCtor ctor; if (!datatypeCtors[dt].TryGetValue(dtv.MemberName, out ctor)) { - Error(dtv.tok, "undeclared constructor {0} in datatype {1}", dtv.MemberName, dtv.DatatypeName); + reporter.Error(MessageSource.Resolver, 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 (ctor.Formals.Count != dtv.Arguments.Count) { - Error(dtv.tok, "wrong number of arguments to datatype constructor {0} (found {1}, expected {2})", ctor.Name, dtv.Arguments.Count, ctor.Formals.Count); + reporter.Error(MessageSource.Resolver, dtv.tok, "wrong number of arguments to datatype constructor {0} (found {1}, expected {2})", ctor.Name, dtv.Arguments.Count, ctor.Formals.Count); } } int j = 0; @@ -9148,7 +9032,7 @@ namespace Microsoft.Dafny if (formal != null) { Type st = SubstType(formal.Type, subst); if (!UnifyTypes(arg.Type, st)) { - Error(arg.tok, "incorrect type of datatype constructor argument (found {0}, expected {1})", arg.Type, st); + reporter.Error(MessageSource.Resolver, arg.tok, "incorrect type of datatype constructor argument (found {0}, expected {1})", arg.Type, st); } } j++; @@ -9192,14 +9076,14 @@ namespace Microsoft.Dafny if (expr is IdentifierExpr) { var e = (IdentifierExpr)expr; if (e.Var != null && e.Var.IsGhost) { - Error(expr, "ghost variables are allowed only in specification contexts"); + reporter.Error(MessageSource.Resolver, expr, "ghost variables are allowed only in specification contexts"); return; } } else if (expr is MemberSelectExpr) { var e = (MemberSelectExpr)expr; if (e.Member != null && e.Member.IsGhost) { - Error(expr, "ghost fields are allowed only in specification contexts"); + reporter.Error(MessageSource.Resolver, expr, "ghost fields are allowed only in specification contexts"); return; } @@ -9207,7 +9091,7 @@ namespace Microsoft.Dafny var e = (FunctionCallExpr)expr; if (e.Function != null) { if (e.Function.IsGhost) { - Error(expr, "function calls are allowed only in specification contexts (consider declaring the function a 'function method')"); + reporter.Error(MessageSource.Resolver, expr, "function calls are allowed only in specification contexts (consider declaring the function a 'function method')"); return; } // function is okay, so check all NON-ghost arguments @@ -9232,13 +9116,13 @@ namespace Microsoft.Dafny return; } else if (expr is OldExpr) { - Error(expr, "old expressions are allowed only in specification and ghost contexts"); + reporter.Error(MessageSource.Resolver, expr, "old expressions are allowed only in specification and ghost contexts"); return; } else if (expr is UnaryOpExpr) { var e = (UnaryOpExpr)expr; if (e.Op == UnaryOpExpr.Opcode.Fresh) { - Error(expr, "fresh expressions are allowed only in specification and ghost contexts"); + reporter.Error(MessageSource.Resolver, expr, "fresh expressions are allowed only in specification and ghost contexts"); return; } @@ -9253,7 +9137,7 @@ namespace Microsoft.Dafny switch (e.ResolvedOp_PossiblyStillUndetermined) { case BinaryExpr.ResolvedOpcode.RankGt: case BinaryExpr.ResolvedOpcode.RankLt: - Error(expr, "rank comparisons are allowed only in specification and ghost contexts"); + reporter.Error(MessageSource.Resolver, expr, "rank comparisons are allowed only in specification and ghost contexts"); return; default: break; @@ -9264,7 +9148,7 @@ namespace Microsoft.Dafny switch (e.Op) { case TernaryExpr.Opcode.PrefixEqOp: case TernaryExpr.Opcode.PrefixNeqOp: - Error(expr, "prefix equalities are allowed only in specification and ghost contexts"); + reporter.Error(MessageSource.Resolver, expr, "prefix equalities are allowed only in specification and ghost contexts"); return; default: break; @@ -9294,7 +9178,7 @@ namespace Microsoft.Dafny var e = (QuantifierExpr)expr; if (e.MissingBounds != null) { foreach (var bv in e.MissingBounds) { - Error(expr, "quantifiers in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce a bounded set of values for '{0}'", bv.Name); + reporter.Error(MessageSource.Resolver, expr, "quantifiers in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce a bounded set of values for '{0}'", bv.Name); } return; } @@ -9302,7 +9186,7 @@ namespace Microsoft.Dafny var e = (MapComprehension)expr; if (e.MissingBounds != null && !e.Finite) { foreach (var bv in e.MissingBounds) { - Error(expr, "imaps in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce a bounded set of values for '{0}'", bv.Name); + reporter.Error(MessageSource.Resolver, expr, "imaps in non-ghost contexts must be compilable, but Dafny's heuristics can't figure out how to produce a bounded set of values for '{0}'", bv.Name); } return; } @@ -9339,9 +9223,9 @@ namespace Microsoft.Dafny if (member == null) { // error has already been reported by ResolveMember } else if (member is Method) { - Error(e, "member {0} in type {1} refers to a method, but only functions can be used in this context", e.Name, cce.NonNull(ctype).Name); + reporter.Error(MessageSource.Resolver, e, "member {0} in type {1} refers to a method, but only functions can be used in this context", e.Name, cce.NonNull(ctype).Name); } else if (!(member is Function)) { - Error(e, "member {0} in type {1} does not refer to a function", e.Name, cce.NonNull(ctype).Name); + reporter.Error(MessageSource.Resolver, e, "member {0} in type {1} does not refer to a function", e.Name, cce.NonNull(ctype).Name); } else { Function function = (Function)member; e.Function = function; @@ -9349,10 +9233,10 @@ namespace Microsoft.Dafny ((FixpointPredicate)function).Uses.Add(e); } if (e.Receiver is StaticReceiverExpr && !function.IsStatic) { - Error(e, "an instance function must be selected via an object, not just a class name"); + reporter.Error(MessageSource.Resolver, e, "an instance function must be selected via an object, not just a class name"); } if (function.Formals.Count != e.Args.Count) { - Error(e, "wrong number of function arguments (got {0}, expected {1})", e.Args.Count, function.Formals.Count); + reporter.Error(MessageSource.Resolver, e, "wrong number of function arguments (got {0}, expected {1})", e.Args.Count, function.Formals.Count); } else { Contract.Assert(ctype != null); // follows from postcondition of ResolveMember if (!function.IsStatic) { @@ -9364,9 +9248,9 @@ namespace Microsoft.Dafny // in the event that a static function calls another static function (and note that we need the // type of the receiver in order to find the method, so we could not have made this check // earlier). - Error(e.Receiver, "'this' is not allowed in a 'static' context"); + reporter.Error(MessageSource.Resolver, e.Receiver, "'this' is not allowed in a 'static' context"); } else if (e.Receiver is StaticReceiverExpr) { - Error(e.Receiver, "call to instance function requires an instance"); + reporter.Error(MessageSource.Resolver, e.Receiver, "call to instance function requires an instance"); } } // build the type substitution map @@ -9384,7 +9268,7 @@ namespace Microsoft.Dafny Contract.Assert(farg.Type != null); // follows from postcondition of ResolveExpression Type s = SubstType(function.Formals[i].Type, e.TypeArgumentSubstitutions); if (!UnifyTypes(farg.Type, s)) { - Error(e, "incorrect type of function argument {0} (expected {1}, got {2})", i, s, farg.Type); + reporter.Error(MessageSource.Resolver, e, "incorrect type of function argument {0} (expected {1}, got {2})", i, s, farg.Type); } } e.Type = SubstType(function.ResultType, e.TypeArgumentSubstitutions); @@ -9435,8 +9319,8 @@ namespace Microsoft.Dafny /// /// For a description, see DiscoverBoundsAux. /// - public static List DiscoverBounds(IToken tok, List bvars, Expression expr, bool polarity, bool returnAllBounds, List missingBounds) where VT : IVariable { - var pairs = DiscoverBoundsAux(tok, bvars, expr, polarity, returnAllBounds, false, missingBounds); + public static List DiscoverBounds(IToken tok, List bvars, Expression expr, bool polarity, bool returnAllBounds, List missingBounds, ErrorReporter reporter) where VT : IVariable { + var pairs = DiscoverBoundsAux(tok, bvars, expr, polarity, returnAllBounds, false, missingBounds, reporter); if (pairs == null) { return null; } @@ -9464,7 +9348,7 @@ namespace Microsoft.Dafny /// If "allowAnyIntegers", then integer variables will always be given a bound, but this bound may be WiggleWaggle if /// there is no better bound. /// - public static List>> DiscoverBoundsAux(IToken tok, List bvars, Expression expr, bool polarity, bool returnAllBounds, bool allowAnyIntegers, List missingBounds) where VT : IVariable { + public static List>> DiscoverBoundsAux(IToken tok, List bvars, Expression expr, bool polarity, bool returnAllBounds, bool allowAnyIntegers, List missingBounds, ErrorReporter reporter) where VT : IVariable { Contract.Requires(tok != null); Contract.Requires(bvars != null); Contract.Requires(missingBounds != null); @@ -9483,7 +9367,7 @@ namespace Microsoft.Dafny var allBounds = new List>>(); bool foundError = false; foreach (var bv in bvars) { - var c = TypeConstraint(bv, bv.Type); + var c = TypeConstraint(bv, bv.Type, reporter); expr = polarity ? Expression.CreateAnd(c, expr) : Expression.CreateImplies(c, expr); } for (int j = 0; j < bvars.Count; j++) { @@ -9619,15 +9503,15 @@ namespace Microsoft.Dafny return foundError ? null : allBounds; } - static Expression TypeConstraint(IVariable bv, Type ty) { + static Expression TypeConstraint(IVariable bv, Type ty, ErrorReporter reporter) { Contract.Requires(bv != null); Contract.Requires(ty != null); ty = ty.NormalizeExpand(); var dd = ty.AsNewtype; if (dd != null) { - var c = TypeConstraint(bv, dd.BaseType); + var c = TypeConstraint(bv, dd.BaseType, reporter); if (dd.Var != null) { - c = Expression.CreateAnd(c, new Translator().Substitute(dd.Constraint, dd.Var, Expression.CreateIdentExpr(bv))); + c = Expression.CreateAnd(c, new Translator(reporter).Substitute(dd.Constraint, dd.Var, Expression.CreateIdentExpr(bv))); } return c; } @@ -9971,7 +9855,7 @@ namespace Microsoft.Dafny IndexableTypeProxy expectedType = new IndexableTypeProxy(domainType, elementType, argType, true, true, true); if (!UnifyTypes(e.Seq.Type, expectedType)) { - Error(e, "sequence/array/multiset/map selection requires a sequence, array, multiset, or map (got {0})", e.Seq.Type); + reporter.Error(MessageSource.Resolver, e, "sequence/array/multiset/map selection requires a sequence, array, multiset, or map (got {0})", e.Seq.Type); seqErr = true; } if (!e.SelectOne) // require sequence or array @@ -9979,13 +9863,13 @@ namespace Microsoft.Dafny if (!allowNonUnitArraySelection) { // require seq if (!UnifyTypes(expectedType, new SeqType(new InferredTypeProxy()))) { - Error(e, "selection requires a sequence (got {0})", e.Seq.Type); + reporter.Error(MessageSource.Resolver, e, "selection requires a sequence (got {0})", e.Seq.Type); } } else { if (UnifyTypes(expectedType, new MapType(true, new InferredTypeProxy(), new InferredTypeProxy()))) { - Error(e, "cannot multiselect a map (got {0} as map type)", e.Seq.Type); + reporter.Error(MessageSource.Resolver, e, "cannot multiselect a map (got {0} as map type)", e.Seq.Type); } else if (UnifyTypes(expectedType, new MapType(false, new InferredTypeProxy(), new InferredTypeProxy()))) { - Error(e, "cannot multiselect an imap (got {0} as imap type)", e.Seq.Type); + reporter.Error(MessageSource.Resolver, e, "cannot multiselect an imap (got {0} as imap type)", e.Seq.Type); } } } @@ -9993,7 +9877,7 @@ namespace Microsoft.Dafny ResolveExpression(e.E0, opts); Contract.Assert(e.E0.Type != null); // follows from postcondition of ResolveExpression if (!UnifyTypes(e.E0.Type, domainType)) { - Error(e.E0, "sequence/array/multiset/map selection requires {1} indices (got {0})", e.E0.Type, domainType); + reporter.Error(MessageSource.Resolver, e.E0, "sequence/array/multiset/map selection requires {1} indices (got {0})", e.E0.Type, domainType); } } if (e.E1 != null) { @@ -10001,7 +9885,7 @@ namespace Microsoft.Dafny Contract.Assert(e.E1.Type != null); // follows from postcondition of ResolveExpression var domType = e.E0 == null ? domainType : new OperationTypeProxy(true, false, false, false, false, false); // reuse 'domainType' if .E0 did not use it; otherwise, create a new proxy to allow .E1 to be any integer-based numeric type, independent of the integer-based numeric type used by .E0 if (!UnifyTypes(e.E1.Type, domType)) { - Error(e.E1, "sequence/array/multiset/map selection requires {1} indices (got {0})", e.E1.Type, domType); + reporter.Error(MessageSource.Resolver, e.E1, "sequence/array/multiset/map selection requires {1} indices (got {0})", e.E1.Type, domType); } } if (!seqErr) { @@ -10193,7 +10077,7 @@ namespace Microsoft.Dafny } else { return false; } - } else if (expr is SeqSelectExpr) { + } else if (expr is SeqSelectExpr) { SeqSelectExpr e = (SeqSelectExpr)expr; return UsesSpecFeatures(e.Seq) || (e.E0 != null && UsesSpecFeatures(e.E0)) || diff --git a/Source/Dafny/Rewriter.cs b/Source/Dafny/Rewriter.cs index 4223fb7f..cb71b80d 100644 --- a/Source/Dafny/Rewriter.cs +++ b/Source/Dafny/Rewriter.cs @@ -6,24 +6,25 @@ using IToken = Microsoft.Boogie.IToken; namespace Microsoft.Dafny { - [ContractClass(typeof(IRewriterContracts))] - public interface IRewriter + public abstract class IRewriter { - void PreResolve(ModuleDefinition m); - void PostResolve(ModuleDefinition m); - // After SCC/Cyclicity/Recursivity analysis: - void PostCyclicityResolve(ModuleDefinition m); - } - [ContractClassFor(typeof(IRewriter))] - abstract class IRewriterContracts : IRewriter - { - public void PreResolve(ModuleDefinition m) { + protected readonly ErrorReporter reporter; + + public IRewriter(ErrorReporter reporter) { + Contract.Requires(reporter != null); + this.reporter = reporter; + } + + internal virtual void PreResolve(ModuleDefinition m) { Contract.Requires(m != null); } - public void PostResolve(ModuleDefinition m) { + + internal virtual void PostResolve(ModuleDefinition m) { Contract.Requires(m != null); } - public void PostCyclicityResolve(ModuleDefinition m) { + + // After SCC/Cyclicity/Recursivity analysis: + internal virtual void PostCyclicityResolve(ModuleDefinition m) { Contract.Requires(m != null); } } @@ -37,33 +38,26 @@ namespace Microsoft.Dafny } } - public class TriggersRewriter : IRewriter { - Resolver Resolver; - - internal TriggersRewriter(Resolver resolver) { - Contract.Requires(resolver != null); - this.Resolver = resolver; + public class TriggerGeneratingRewriter : IRewriter { + internal TriggerGeneratingRewriter(ErrorReporter reporter) : base(reporter) { + Contract.Requires(reporter != null); } - public void PreResolve(ModuleDefinition m) { } - - public void PostResolve(ModuleDefinition m) { + internal override void PostResolve(ModuleDefinition m) { foreach (var decl in ModuleDefinition.AllCallables(m.TopLevelDecls)) { if (decl is Function) { var function = (Function)decl; - TriggerGenerator.AddTriggers(function.Ens, Resolver); - TriggerGenerator.AddTriggers(function.Req, Resolver); - TriggerGenerator.AddTriggers(function.Body, Resolver); + //TriggerGenerator.AddTriggers(function.Ens, Resolver); + //TriggerGenerator.AddTriggers(function.Req, Resolver); + //TriggerGenerator.AddTriggers(function.Body, Resolver); } else if (decl is Method) { var method = (Method)decl; - TriggerGenerator.AddTriggers(method.Ens, Resolver); - TriggerGenerator.AddTriggers(method.Req, Resolver); - TriggerGenerator.AddTriggers(method.Body, Resolver); + //TriggerGenerator.AddTriggers(method.Ens, Resolver); + //TriggerGenerator.AddTriggers(method.Req, Resolver); + //TriggerGenerator.AddTriggers(method.Body, Resolver); } } } - - public void PostCyclicityResolve(ModuleDefinition m) { } } /// @@ -106,7 +100,12 @@ namespace Microsoft.Dafny /// public class AutoContractsRewriter : IRewriter { - public void PreResolve(ModuleDefinition m) { + public AutoContractsRewriter(ErrorReporter reporter) + : base(reporter) { + Contract.Requires(reporter != null); + } + + internal override void PreResolve(ModuleDefinition m) { foreach (var d in m.TopLevelDecls) { bool sayYes = true; if (d is ClassDecl && Attributes.ContainsBool(d.Attributes, "autocontracts", ref sayYes) && sayYes) { @@ -162,7 +161,7 @@ namespace Microsoft.Dafny } } - public void PostResolve(ModuleDefinition m) { + internal override void PostResolve(ModuleDefinition m) { foreach (var d in m.TopLevelDecls) { bool sayYes = true; if (d is ClassDecl && Attributes.ContainsBool(d.Attributes, "autocontracts", ref sayYes) && sayYes) { @@ -171,9 +170,6 @@ namespace Microsoft.Dafny } } - public void PostCyclicityResolve(ModuleDefinition m) { - } - void ProcessClassPostResolve(ClassDecl cl) { // Find all fields of a reference type, and make a note of whether or not the reference type has a Repr field. // Also, find the Repr field and the function Valid in class "cl" @@ -416,20 +412,20 @@ namespace Microsoft.Dafny /// specifically asks to see it via the reveal_foo() lemma /// public class OpaqueFunctionRewriter : IRewriter { - readonly ResolutionErrorReporter reporter; protected Dictionary fullVersion; // Given an opaque function, retrieve the full protected Dictionary original; // Given a full version of an opaque function, find the original opaque version protected Dictionary revealOriginal; // Map reveal_* lemmas back to their original functions - public OpaqueFunctionRewriter(ResolutionErrorReporter reporter) - : base() { - this.reporter = reporter; + public OpaqueFunctionRewriter(ErrorReporter reporter) + : base(reporter) { + Contract.Requires(reporter != null); + fullVersion = new Dictionary(); original = new Dictionary(); revealOriginal = new Dictionary(); } - public void PreResolve(ModuleDefinition m) { + internal override void PreResolve(ModuleDefinition m) { foreach (var d in m.TopLevelDecls) { if (d is ClassDecl) { DuplicateOpaqueClassFunctions((ClassDecl)d); @@ -437,7 +433,7 @@ namespace Microsoft.Dafny } } - public void PostResolve(ModuleDefinition m) { + internal override void PostResolve(ModuleDefinition m) { // Fix up the ensures clause of the full version of the function, // since it may refer to the original opaque function foreach (var fn in ModuleDefinition.AllFunctions(m.TopLevelDecls)) { @@ -462,7 +458,7 @@ namespace Microsoft.Dafny } } - public void PostCyclicityResolve(ModuleDefinition m) { + internal override void PostCyclicityResolve(ModuleDefinition m) { // Add layer quantifier if the function is recursive foreach (var decl in ModuleDefinition.AllCallables(m.TopLevelDecls)) { if (decl is Lemma) { @@ -507,7 +503,7 @@ namespace Microsoft.Dafny if (!Attributes.Contains(f.Attributes, "opaque")) { // Nothing to do } else if (f.IsProtected) { - reporter.Error(f.tok, ":opaque is not allowed to be applied to protected functions (this will be allowed when the language introduces 'opaque'/'reveal' as keywords)"); + reporter.Error(MessageSource.Rewriter, f.tok, ":opaque is not allowed to be applied to protected functions (this will be allowed when the language introduces 'opaque'/'reveal' as keywords)"); } else if (!RefinementToken.IsInherited(f.tok, c.Module)) { // Create a copy, which will be the internal version with a full body // which will allow us to verify that the ensures are true @@ -721,19 +717,16 @@ namespace Microsoft.Dafny /// public class AutoReqFunctionRewriter : IRewriter { Function parentFunction; - Resolver resolver; OpaqueFunctionRewriter opaqueInfo; bool containsMatch; // TODO: Track this per-requirement, rather than per-function - public AutoReqFunctionRewriter(Resolver r, OpaqueFunctionRewriter o) { - this.resolver = r; + public AutoReqFunctionRewriter(ErrorReporter reporter, OpaqueFunctionRewriter o) + : base(reporter) { + Contract.Requires(reporter != null); this.opaqueInfo = o; } - public void PreResolve(ModuleDefinition m) { - } - - public void PostResolve(ModuleDefinition m) { + internal override void PostResolve(ModuleDefinition m) { var components = m.CallGraph.TopologicallySortedComponents(); foreach (var scComponent in components) { // Visit the call graph bottom up, so anything we call already has its prequisites calculated @@ -806,9 +799,6 @@ namespace Microsoft.Dafny } } - public void PostCyclicityResolve(ModuleDefinition m) { - } - Expression subVars(List formals, List values, Expression e, Expression f_this) { Contract.Assert(formals != null); Contract.Assert(values != null); @@ -839,7 +829,7 @@ namespace Microsoft.Dafny } if (!tip.Equals("")) { - resolver.ReportAdditionalInformation(f.tok, tip, f.tok.val.Length); + reporter.Info(MessageSource.Rewriter, f.tok, tip); if (DafnyOptions.O.AutoReqPrintFile != null) { using (System.IO.TextWriter writer = new System.IO.StreamWriter(DafnyOptions.O.AutoReqPrintFile, true)) { writer.WriteLine(f.Name); @@ -866,7 +856,7 @@ namespace Microsoft.Dafny } if (!tip.Equals("")) { - resolver.ReportAdditionalInformation(method.tok, tip, method.tok.val.Length); + reporter.Info(MessageSource.Rewriter, method.tok, tip); if (DafnyOptions.O.AutoReqPrintFile != null) { using (System.IO.TextWriter writer = new System.IO.StreamWriter(DafnyOptions.O.AutoReqPrintFile, true)) { writer.WriteLine(method.Name); @@ -1061,7 +1051,7 @@ namespace Microsoft.Dafny Expression allReqsSatisfied = andify(e.Term.tok, auto_reqs); Expression allReqsSatisfiedAndTerm = Expression.CreateAnd(allReqsSatisfied, e.Term); e.UpdateTerm(allReqsSatisfiedAndTerm); - resolver.ReportAdditionalInformation(e.tok, "autoreq added (" + Printer.ExtendedExprToString(allReqsSatisfied) + ") &&", e.tok.val.Length); + reporter.Info(MessageSource.Rewriter, e.tok, "autoreq added (" + Printer.ExtendedExprToString(allReqsSatisfied) + ") &&"); } } else if (expr is SetComprehension) { var e = (SetComprehension)expr; @@ -1108,7 +1098,12 @@ namespace Microsoft.Dafny /// public class TimeLimitRewriter : IRewriter { - public void PreResolve(ModuleDefinition m) { + public TimeLimitRewriter(ErrorReporter reporter) + : base(reporter) { + Contract.Requires(reporter != null); + } + + internal override void PreResolve(ModuleDefinition m) { foreach (var d in m.TopLevelDecls) { if (d is ClassDecl) { var c = (ClassDecl)d; @@ -1136,16 +1131,6 @@ namespace Microsoft.Dafny } } } - - public void PostResolve(ModuleDefinition m) - { - // Nothing to do here - } - - public void PostCyclicityResolve(ModuleDefinition m) { - // Nothing to do here - } - } diff --git a/Source/Dafny/Scanner.cs b/Source/Dafny/Scanner.cs index a73f510d..e6c97f22 100644 --- a/Source/Dafny/Scanner.cs +++ b/Source/Dafny/Scanner.cs @@ -314,8 +314,8 @@ public class Scanner { // [NotDelayed] public Scanner (string/*!*/ fullFilename, string/*!*/ fileName, Errors/*!*/ errorHandler, bool useBaseName = false) : base() { - Contract.Requires(fileName != null); - Contract.Requires(errorHandler != null); + Contract.Requires(fileName != null); + Contract.Requires(errorHandler != null); this.errorHandler = errorHandler; pt = tokens = new Token(); // first token is a dummy t = new Token(); // dummy because t is a non-null field @@ -332,9 +332,9 @@ public class Scanner { // [NotDelayed] public Scanner (Stream/*!*/ s, Errors/*!*/ errorHandler, string/*!*/ fullFilename, string/*!*/ fileName, bool useBaseName = false) : base() { - Contract.Requires(s != null); - Contract.Requires(errorHandler != null); - Contract.Requires(fileName != null); + Contract.Requires(s != null); + Contract.Requires(errorHandler != null); + Contract.Requires(fileName != null); pt = tokens = new Token(); // first token is a dummy t = new Token(); // dummy because t is a non-null field this._buffer = new Buffer(s, true); @@ -344,9 +344,9 @@ public class Scanner { Init(); } - string GetBaseName(string fileName) { - return System.IO.Path.GetFileName(fileName); // Return basename - } + string GetBaseName(string fileName) { + return System.IO.Path.GetFileName(fileName); // Return basename + } void Init() { pos = -1; line = 1; col = 0; @@ -991,6 +991,4 @@ public class Scanner { } // end Scanner public delegate void ErrorProc(int n, string filename, int line, int col); - - } \ No newline at end of file diff --git a/Source/Dafny/Translator.cs b/Source/Dafny/Translator.cs index b8c4b8ec..039aa56f 100644 --- a/Source/Dafny/Translator.cs +++ b/Source/Dafny/Translator.cs @@ -93,9 +93,13 @@ namespace Microsoft.Dafny { } public class Translator { + readonly ErrorReporter reporter; [NotDelayed] - public Translator() { + public Translator(ErrorReporter reporter) { + Contract.Requires(reporter != null); + + this.reporter = reporter; InsertChecksums = 0 < CommandLineOptions.Clo.VerifySnapshots; Bpl.Program boogieProgram = ReadPrelude(); if (boogieProgram != null) { @@ -3609,7 +3613,7 @@ namespace Microsoft.Dafny { Contract.Requires(tok != null); Contract.Ensures(Contract.Result() != null); var col = tok.col + (isEndToken ? tok.val.Length : 0); - string description = Util.ReportIssueToString_Bare(additionalInfo == null ? "" : ": ", tok.filename, tok.line, tok.col, additionalInfo ?? ""); + string description = reporter.ErrorToString_Internal(additionalInfo == null ? "" : ": ", tok.filename, tok.line, tok.col, additionalInfo ?? ""); QKeyValue kv = new QKeyValue(tok, "captureState", new List() { description }, null); return new Bpl.AssumeCmd(tok, Bpl.Expr.True, kv); } @@ -7679,7 +7683,7 @@ namespace Microsoft.Dafny { } var missingBounds = new List(); - var bounds = Resolver.DiscoverBounds(x.tok, new List() { x }, expr, true, true, missingBounds); + var bounds = Resolver.DiscoverBounds(x.tok, new List() { x }, expr, true, true, missingBounds, reporter); if (missingBounds.Count == 0) { foreach (var bound in bounds) { if (bound is ComprehensionExpr.IntBoundedPool) { @@ -12955,9 +12959,8 @@ namespace Microsoft.Dafny { return true; } else { // Skip inlining, as it would cause arbitrary expressions to pop up in the trigger - // CLEMENT: Report inlining issue in a VS plugin friendly way - //CLEMENT this should appear at the outmost call site, not at the innermost. See SnapshotableTrees.dfy - Dafny.Util.ReportIssue("Info", fexp.tok, "Some instances of this call cannot safely be inlined."); + // CLEMENT this should appear at the outmost call site, not at the innermost. See SnapshotableTrees.dfy + reporter.Info(MessageSource.Translator, fexp.tok, "Some instances of this call cannot safely be inlined."); } } diff --git a/Source/Dafny/TriggerGenerator.cs b/Source/Dafny/TriggerGenerator.cs index cf677e0e..04d96b01 100644 --- a/Source/Dafny/TriggerGenerator.cs +++ b/Source/Dafny/TriggerGenerator.cs @@ -513,7 +513,7 @@ namespace Microsoft.Dafny { return; DebugTriggers("== From {0} visiting expr: {1}", new StackFrame(1).GetMethod().Name, Printer.ExprToString(root)); - TriggerGenerator generator = new TriggerGenerator(resolver.ReportAdditionalInformation); + TriggerGenerator generator = new TriggerGenerator(null); generator.AddTriggers_Internal(root); } @@ -522,7 +522,7 @@ namespace Microsoft.Dafny { return; DebugTriggers("== From {0} visiting statement: {1}", new StackFrame(1).GetMethod().Name, Printer.StatementToString(root)); - TriggerGenerator generator = new TriggerGenerator(resolver.ReportAdditionalInformation); + TriggerGenerator generator = new TriggerGenerator(null); generator.AddTriggers_Internal(root); } diff --git a/Source/Dafny/Util.cs b/Source/Dafny/Util.cs index 508d23c6..eaf599e3 100644 --- a/Source/Dafny/Util.cs +++ b/Source/Dafny/Util.cs @@ -67,29 +67,6 @@ namespace Microsoft.Dafny { return res; } - public static void ReportIssue(string header, IToken tok, string msg, params object[] args) { - ReportIssue(header, tok, String.Format(msg, args)); - } - - public static void ReportIssue(string header, IToken tok, string msg) { - ReportIssue(header, tok.filename, tok.line, tok.col, msg); - } - - public static void ReportIssue(string header, string filename, int line, int column, string msg) { - Console.WriteLine(ReportIssueToString(header, filename, line, column, msg)); - } - - public static string ReportIssueToString(string header, string filename, int line, int column, string msg) { - Contract.Requires(header != null); - Contract.Requires(filename != null); - Contract.Requires(msg != null); - return ReportIssueToString_Bare(": " + header, filename, line, column, ": " + msg); - } - - public static string ReportIssueToString_Bare(string header, string filename, int line, int column, string msg) { - return String.Format("{0}({1},{2}){3}{4}", filename, line, column - 1, header, msg ?? ""); - } - /// /// Returns s but with all occurrences of '_' removed. /// diff --git a/Source/DafnyDriver/DafnyDriver.cs b/Source/DafnyDriver/DafnyDriver.cs index d22899ab..4b5ae8d8 100644 --- a/Source/DafnyDriver/DafnyDriver.cs +++ b/Source/DafnyDriver/DafnyDriver.cs @@ -22,7 +22,6 @@ namespace Microsoft.Dafny public class DafnyDriver { - enum ExitValue { VERIFIED = 0, PREPROCESSING_ERROR, DAFNY_ERROR, NOT_VERIFIED } @@ -42,8 +41,7 @@ namespace Microsoft.Dafny { Contract.Requires(cce.NonNullElements(args)); - printer = new DafnyConsolePrinter(); - ExecutionEngine.printer = printer; + ExecutionEngine.printer = new DafnyConsolePrinter(); // For boogie errors DafnyOptions.Install(new DafnyOptions()); @@ -57,14 +55,14 @@ namespace Microsoft.Dafny if (CommandLineOptions.Clo.Files.Count == 0) { - printer.ErrorWriteLine(Console.Out, "*** Error: No input files were specified."); + ExecutionEngine.printer.ErrorWriteLine(Console.Out, "*** Error: No input files were specified."); exitValue = ExitValue.PREPROCESSING_ERROR; goto END; } if (CommandLineOptions.Clo.XmlSink != null) { string errMsg = CommandLineOptions.Clo.XmlSink.Open(); if (errMsg != null) { - printer.ErrorWriteLine(Console.Out, "*** Error: " + errMsg); + ExecutionEngine.printer.ErrorWriteLine(Console.Out, "*** Error: " + errMsg); exitValue = ExitValue.PREPROCESSING_ERROR; goto END; } @@ -87,12 +85,11 @@ namespace Microsoft.Dafny {Contract.Assert(file != null); string extension = Path.GetExtension(file); if (extension != null) { extension = extension.ToLower(); } - if (extension != ".dfy") - { - printer.ErrorWriteLine(Console.Out, "*** Error: '{0}': Filename extension '{1}' is not supported. Input files must be Dafny programs (.dfy).", file, - extension == null ? "" : extension); - exitValue = ExitValue.PREPROCESSING_ERROR; - goto END; + if (extension != ".dfy") { + ExecutionEngine.printer.ErrorWriteLine(Console.Out, "*** Error: '{0}': Filename extension '{1}' is not supported. Input files must be Dafny programs (.dfy).", file, + extension == null ? "" : extension); + exitValue = ExitValue.PREPROCESSING_ERROR; + goto END; } } exitValue = ProcessFiles(CommandLineOptions.Clo.Files); @@ -156,14 +153,15 @@ namespace Microsoft.Dafny using (XmlFileScope xf = new XmlFileScope(CommandLineOptions.Clo.XmlSink, fileNames[fileNames.Count-1])) { Dafny.Program dafnyProgram; + ErrorReporter reporter = new ConsoleErrorReporter(); string programName = fileNames.Count == 1 ? fileNames[0] : "the program"; - string err = Dafny.Main.ParseCheck(fileNames, programName, out dafnyProgram); + string err = Dafny.Main.ParseCheck(fileNames, programName, reporter, out dafnyProgram); if (err != null) { exitValue = ExitValue.DAFNY_ERROR; - printer.ErrorWriteLine(Console.Out, err); + ExecutionEngine.printer.ErrorWriteLine(Console.Out, err); } else if (dafnyProgram != null && !CommandLineOptions.Clo.NoResolve && !CommandLineOptions.Clo.NoTypecheck && DafnyOptions.O.DafnyVerify) { - Dafny.Translator translator = new Dafny.Translator(); + Dafny.Translator translator = new Dafny.Translator(dafnyProgram.reporter); Bpl.Program boogieProgram = translator.Translate(dafnyProgram); if (CommandLineOptions.Clo.PrintFile != null) { @@ -184,12 +182,12 @@ namespace Microsoft.Dafny var allOk = stats.ErrorCount == 0 && stats.InconclusiveCount == 0 && stats.TimeoutCount == 0 && stats.OutOfMemoryCount == 0; switch (oc) { case PipelineOutcome.VerificationCompleted: - printer.WriteTrailer(stats); + ExecutionEngine.printer.WriteTrailer(stats); if ((DafnyOptions.O.Compile && allOk && CommandLineOptions.Clo.ProcsToCheck == null) || DafnyOptions.O.ForceCompile) CompileDafnyProgram(dafnyProgram, fileNames[0]); break; case PipelineOutcome.Done: - printer.WriteTrailer(stats); + ExecutionEngine.printer.WriteTrailer(stats); if (DafnyOptions.O.ForceCompile) CompileDafnyProgram(dafnyProgram, fileNames[0]); break; @@ -265,10 +263,7 @@ namespace Microsoft.Dafny #region Output - - static OutputPrinter printer; - - + class DafnyConsolePrinter : ConsolePrinter { public override void ReportBplError(IToken tok, string message, bool error, TextWriter tw, string category = null) diff --git a/Source/DafnyExtension/DafnyDriver.cs b/Source/DafnyExtension/DafnyDriver.cs index 50d8c2e3..36664a9b 100644 --- a/Source/DafnyExtension/DafnyDriver.cs +++ b/Source/DafnyExtension/DafnyDriver.cs @@ -115,19 +115,21 @@ namespace DafnyLanguage bool ParseAndTypeCheck() { Dafny.ModuleDecl module = new Dafny.LiteralModuleDecl(new Dafny.DefaultModuleDecl(), null); Dafny.BuiltIns builtIns = new Dafny.BuiltIns(); - Dafny.Errors parseErrors = new VSErrors(this); + + var errorReporter = new VSErrorReporter(this); + var parseErrors = new Dafny.Errors(errorReporter); + int errorCount = Dafny.Parser.Parse(_snapshot.GetText(), _filename, _filename, module, builtIns, parseErrors); string errString = Dafny.Main.ParseIncludes(module, builtIns, new List(), parseErrors); if (errorCount != 0 || errString != null) return false; - Dafny.Program program = new Dafny.Program(_filename, module, builtIns); + Dafny.Program program = new Dafny.Program(_filename, module, builtIns, errorReporter); - var r = new VSResolver(program, this); + var r = new Resolver(program); r.ResolveProgram(program); - if (r.ErrorCount != 0) + if (errorReporter.Count(ErrorLevel.Error) != 0) return false; - program.AdditionalInformation.AddRange(r.AdditionalInformation); _program = program; return true; // success } @@ -137,56 +139,31 @@ namespace DafnyLanguage _errors.Add(new DafnyError(filename, line - 1, col - 1, cat, msg, _snapshot, isRecycled, null, System.IO.Path.GetFullPath(this._filename) == filename)); } - class VSErrors : Dafny.Errors - { - DafnyDriver dd; - public VSErrors(DafnyDriver dd) { - this.dd = dd; - } - public override void SynErr(string filename, int line, int col, string msg) { - dd.RecordError(filename, line, col, ErrorCategory.ParseError, msg); - count++; - } - public override void SemErr(string filename, int line, int col, string msg) { - dd.RecordError(filename, line, col, ErrorCategory.ResolveError, msg); - count++; - } - public override void Warning(IToken tok, string msg) { - dd.RecordError(tok.filename, tok.line, tok.col, ErrorCategory.ParseWarning, msg); - } - } - - class VSResolver : Dafny.Resolver + class VSErrorReporter : Dafny.ErrorReporter { DafnyDriver dd; - Dictionary> _additionalInformation = new Dictionary>(); - public List AdditionalInformation { get { return _additionalInformation.Values.SelectMany(i => i).ToList(); } } - public VSResolver(Dafny.Program program, DafnyDriver dd) - : base(program) { + public VSErrorReporter(DafnyDriver dd) { this.dd = dd; - - AdditionalInformationReporter = - (addinfo) - => - { - if (!_additionalInformation.ContainsKey(addinfo.Token)) { - _additionalInformation.Add(addinfo.Token, new HashSet()); - } - _additionalInformation[addinfo.Token].Add(addinfo); - }; - } - - public override void Error(Bpl.IToken tok, string msg, params object[] args) { - string s = string.Format(msg, args); - dd.RecordError(tok.filename, tok.line, tok.col, ErrorCategory.ResolveError, s); - ErrorCount++; } - public override void Warning(IToken tok, string msg, params object[] args) { - if (reportWarnings) { - string s = string.Format(msg, args); - dd.RecordError(tok.filename, tok.line, tok.col, ErrorCategory.ResolveWarning, s); + // TODO: The error tracking could be made better to track the full information returned by Dafny + public override bool Message(MessageSource source, ErrorLevel level, IToken tok, string msg) { + if (base.Message(source, level, tok, msg)) { + switch (level) { + case ErrorLevel.Error: + dd.RecordError(tok.filename, tok.line, tok.col, source == MessageSource.Parser ? ErrorCategory.ParseError : ErrorCategory.ResolveError, msg); + break; + case ErrorLevel.Warning: + dd.RecordError(tok.filename, tok.line, tok.col, source == MessageSource.Parser ? ErrorCategory.ParseWarning : ErrorCategory.ResolveWarning, msg); + break; + case ErrorLevel.Info: + // The AllMessages variable already keeps track of this + break; + } + return true; + } else { + return false; } } } @@ -273,7 +250,7 @@ namespace DafnyLanguage } public static bool Verify(Dafny.Program dafnyProgram, ResolverTagger resolver, string uniqueIdPrefix, string requestId, ErrorReporterDelegate er) { - Dafny.Translator translator = new Dafny.Translator(); + Dafny.Translator translator = new Dafny.Translator(dafnyProgram.reporter); translator.InsertChecksums = true; translator.UniqueIdPrefix = uniqueIdPrefix; Bpl.Program boogieProgram = translator.Translate(dafnyProgram); diff --git a/Source/DafnyExtension/IdentifierTagger.cs b/Source/DafnyExtension/IdentifierTagger.cs index 262dddcd..13991496 100644 --- a/Source/DafnyExtension/IdentifierTagger.cs +++ b/Source/DafnyExtension/IdentifierTagger.cs @@ -136,9 +136,9 @@ namespace DafnyLanguage List newRegions = new List(); - foreach (var addInfo in program.AdditionalInformation) + foreach (var info in program.reporter.AllMessages[ErrorLevel.Info]) { - IdRegion.Add(newRegions, addInfo.Token, addInfo.Text, addInfo.Length); + IdRegion.Add(newRegions, info.token, info.message, info.token.val.Length); } foreach (var module in program.Modules) { diff --git a/Source/DafnyExtension/ResolverTagger.cs b/Source/DafnyExtension/ResolverTagger.cs index 6eaec5a6..0ce68809 100644 --- a/Source/DafnyExtension/ResolverTagger.cs +++ b/Source/DafnyExtension/ResolverTagger.cs @@ -74,10 +74,10 @@ namespace DafnyLanguage switch (err.Category) { case ErrorCategory.ProcessError: case ErrorCategory.ParseError: - case ErrorCategory.ParseWarning: return "syntax error"; // COLOR: red case ErrorCategory.ResolveError: return "compiler error"; // COLOR: blue + case ErrorCategory.ParseWarning: case ErrorCategory.ResolveWarning: return "compiler warning"; // COLOR: blue case ErrorCategory.InternalError: @@ -403,7 +403,7 @@ namespace DafnyLanguage chng(this, new SnapshotSpanEventArgs(new SnapshotSpan(snapshot, 0, snapshot.Length))); } - static TaskErrorCategory CategoryConversion(ErrorCategory cat) + static TaskErrorCategory CategoryConversion(ErrorCategory cat) //CLEMENT: We've lost that info { switch (cat) { diff --git a/Source/DafnyServer/DafnyHelper.cs b/Source/DafnyServer/DafnyHelper.cs index 10d98677..d6c3f5c7 100644 --- a/Source/DafnyServer/DafnyHelper.cs +++ b/Source/DafnyServer/DafnyHelper.cs @@ -30,14 +30,14 @@ namespace Microsoft.Dafny { private string fname; private string source; - private Dafny.Errors errors; + private readonly Dafny.ErrorReporter reporter; private Dafny.Program dafnyProgram; private Bpl.Program boogieProgram; public DafnyHelper(string fname, string source) { this.fname = fname; this.source = source; - this.errors = new Dafny.Errors(); + this.reporter = new Dafny.ConsoleErrorReporter(); } public bool Verify() { @@ -47,10 +47,10 @@ namespace Microsoft.Dafny { private bool Parse() { Dafny.ModuleDecl module = new Dafny.LiteralModuleDecl(new Dafny.DefaultModuleDecl(), null); Dafny.BuiltIns builtIns = new Dafny.BuiltIns(); - var success = (Dafny.Parser.Parse(source, fname, fname, module, builtIns, errors) == 0 && - Dafny.Main.ParseIncludes(module, builtIns, new List(), errors) == null); + var success = (Dafny.Parser.Parse(source, fname, fname, module, builtIns, new Dafny.Errors(reporter)) == 0 && + Dafny.Main.ParseIncludes(module, builtIns, new List(), new Dafny.Errors(reporter)) == null); if (success) { - dafnyProgram = new Dafny.Program(fname, module, builtIns); + dafnyProgram = new Dafny.Program(fname, module, builtIns, reporter); } return success; } @@ -58,11 +58,11 @@ namespace Microsoft.Dafny { private bool Resolve() { var resolver = new Dafny.Resolver(dafnyProgram); resolver.ResolveProgram(dafnyProgram); - return resolver.ErrorCount == 0; + return reporter.Count(ErrorLevel.Error) == 0; } private bool Translate() { - var translator = new Dafny.Translator() { InsertChecksums = true, UniqueIdPrefix = null }; //FIXME check if null is OK for UniqueIdPrefix + var translator = new Dafny.Translator(reporter) { InsertChecksums = true, UniqueIdPrefix = null }; //FIXME check if null is OK for UniqueIdPrefix boogieProgram = translator.Translate(dafnyProgram); // FIXME how are translation errors reported? return true; } @@ -74,7 +74,8 @@ namespace Microsoft.Dafny { ExecutionEngine.CoalesceBlocks(boogieProgram); ExecutionEngine.Inline(boogieProgram); - switch (ExecutionEngine.InferAndVerify(boogieProgram, new PipelineStatistics(), "ServerProgram", null, DateTime.UtcNow.Ticks.ToString())) { // FIXME check if null is ok for error delegate + //FIXME Could capture errors instead of printing them (pass a delegate instead of null) + switch (ExecutionEngine.InferAndVerify(boogieProgram, new PipelineStatistics(), "ServerProgram", null, DateTime.UtcNow.Ticks.ToString())) { case PipelineOutcome.Done: case PipelineOutcome.VerificationCompleted: return true; -- cgit v1.2.3 From 674e30357980e1192ac532f4bd16c529cedc7fdc Mon Sep 17 00:00:00 2001 From: Clément Pit--Claudel Date: Wed, 19 Aug 2015 10:51:44 -0700 Subject: Draft out a more advanced version of trigger generation This new version will include a cleaner pipeline, and trigger splitting. --- Source/Dafny/DafnyPipeline.csproj | 7 +- Source/Dafny/Rewriter.cs | 46 +- Source/Dafny/Translator.cs | 4 +- Source/Dafny/TriggerGenerator.cs | 1064 ------------------------ Source/Dafny/Triggers/QuantifierSplitter.cs | 66 ++ Source/Dafny/Triggers/QuantifiersCollection.cs | 104 +++ Source/Dafny/Triggers/TriggerExtensions.cs | 489 +++++++++++ Source/Dafny/Triggers/TriggerGenerator.cs | 28 + Source/Dafny/Triggers/TriggerUtils.cs | 94 +++ Source/Dafny/Triggers/TriggersCollector.cs | 256 ++++++ Test/dafny0/SeqFromArray.dfy.expect | 3 + 11 files changed, 1089 insertions(+), 1072 deletions(-) delete mode 100644 Source/Dafny/TriggerGenerator.cs create mode 100644 Source/Dafny/Triggers/QuantifierSplitter.cs create mode 100644 Source/Dafny/Triggers/QuantifiersCollection.cs create mode 100644 Source/Dafny/Triggers/TriggerExtensions.cs create mode 100644 Source/Dafny/Triggers/TriggerGenerator.cs create mode 100644 Source/Dafny/Triggers/TriggerUtils.cs create mode 100644 Source/Dafny/Triggers/TriggersCollector.cs (limited to 'Source/Dafny/DafnyPipeline.csproj') diff --git a/Source/Dafny/DafnyPipeline.csproj b/Source/Dafny/DafnyPipeline.csproj index 626bb26a..5a824c36 100644 --- a/Source/Dafny/DafnyPipeline.csproj +++ b/Source/Dafny/DafnyPipeline.csproj @@ -144,7 +144,12 @@ - + + + + + + diff --git a/Source/Dafny/Rewriter.cs b/Source/Dafny/Rewriter.cs index cb71b80d..4e274189 100644 --- a/Source/Dafny/Rewriter.cs +++ b/Source/Dafny/Rewriter.cs @@ -39,22 +39,56 @@ namespace Microsoft.Dafny } public class TriggerGeneratingRewriter : IRewriter { + Triggers.QuantifierCollectionsFinder finder; + internal TriggerGeneratingRewriter(ErrorReporter reporter) : base(reporter) { Contract.Requires(reporter != null); + this.finder = new Triggers.QuantifierCollectionsFinder(reporter); + } + + internal override void PostResolve(ModuleDefinition m) { + foreach (var decl in ModuleDefinition.AllCallables(m.TopLevelDecls)) { //CLEMENT + if (decl is Function) { + var function = (Function)decl; + finder.Visit(function.Ens, null); + finder.Visit(function.Req, null); + if (function.Body != null) { + finder.Visit(function.Body, null); + } + } else if (decl is Method) { + var method = (Method)decl; + finder.Visit(method.Ens, null); + finder.Visit(method.Req, null); + if (method.Body != null) { + finder.Visit(method.Body, null); + } + } + } + } + } + + internal class QuantifierSplittingRewriter : IRewriter { + internal QuantifierSplittingRewriter(ErrorReporter reporter) : base(reporter) { + Contract.Requires(reporter != null); } internal override void PostResolve(ModuleDefinition m) { + var splitter = new Triggers.QuantifierSplitter(); foreach (var decl in ModuleDefinition.AllCallables(m.TopLevelDecls)) { if (decl is Function) { var function = (Function)decl; - //TriggerGenerator.AddTriggers(function.Ens, Resolver); - //TriggerGenerator.AddTriggers(function.Req, Resolver); - //TriggerGenerator.AddTriggers(function.Body, Resolver); + splitter.Visit(function.Ens); + splitter.Visit(function.Req); + if (function.Body != null) { + splitter.Visit(function.Body); + } } else if (decl is Method) { var method = (Method)decl; - //TriggerGenerator.AddTriggers(method.Ens, Resolver); - //TriggerGenerator.AddTriggers(method.Req, Resolver); - //TriggerGenerator.AddTriggers(method.Body, Resolver); + splitter.Visit(method.Ens); + splitter.Visit(method.Req); + if (method.Body != null) { + splitter.Visit(method.Body); + } } } } diff --git a/Source/Dafny/Translator.cs b/Source/Dafny/Translator.cs index 039aa56f..b5d89abd 100644 --- a/Source/Dafny/Translator.cs +++ b/Source/Dafny/Translator.cs @@ -12895,6 +12895,8 @@ namespace Microsoft.Dafny { // that needed to be proved about the function was proved already in the previous module, even without the body definition). } else if (!FunctionBodyIsAvailable(f, currentModule)) { // Don't inline opaque functions or foreign protected functions + } else if (Attributes.Contains(f.Attributes, "no_inline")) { + // User manually prevented inlining } else if (CanSafelyInline(fexp, f)) { // inline this body var body = GetSubstitutedBody(fexp, f, false); @@ -13106,7 +13108,7 @@ namespace Microsoft.Dafny { } private bool CanSafelySubstitute(ISet protectedVariables, IVariable variable, Expression substitution) { - return !(protectedVariables.Contains(variable) && TriggerGenerator.IsTriggerKiller(substitution)); + return !(protectedVariables.Contains(variable) && Dafny.Triggers.TriggersCollector.IsTriggerKiller(substitution)); } private class VariablesCollector: BottomUpVisitor { diff --git a/Source/Dafny/TriggerGenerator.cs b/Source/Dafny/TriggerGenerator.cs deleted file mode 100644 index 04d96b01..00000000 --- a/Source/Dafny/TriggerGenerator.cs +++ /dev/null @@ -1,1064 +0,0 @@ -// #define DEBUG_AUTO_TRIGGERS -#define THROW_UNSUPPORTED_COMPARISONS - -using System; -using System.Collections.Generic; -using System.Linq; -using Microsoft.Boogie; -using System.Diagnostics.Contracts; -using System.Text; -using System.Diagnostics; - -//FIXME Generated triggers should be _triggers -//FIXME: When scoring, do not consider old(x) to be higher than x. - -/* High level note: There are really two processes going on here. One is finding quantifiers; - * the other is walking the subtree corresponding to each quantifier, and finding trigger candidates. - * These two processes are interleaved, because we can look for trigger candidates as we look for - * quantifiers. Since the visitor starts from the bottom of the tree, the recursive annotation - * procedure never causes deep recursion; every call it makes hits the cache that has been built - * during the visiting of lower level nodes. - * - * Note also that it wouldn't be enough to just use the recursive procedure: it doesn't visit - * statements, for example. - */ - -namespace Microsoft.Dafny { - class TriggerCandidate { - internal Expression Expr; - internal ISet Variables; - internal List MatchesInQuantifierBody; - - public override string ToString() { - return Printer.ExprToString(Expr); - } - } - - class MultiTriggerCandidate { - internal List Candidates; - internal List Tags; - internal double Score; - - private List potentialMatchingLoops; - internal List PotentialMatchingLoops { - get { - if (potentialMatchingLoops == null) { - //FIXME could be optimized by looking at the bindings instead of doing full equality - var candidates = Candidates.Deduplicate((x, y) => ExprExtensions.ExpressionEq(x.Expr, y.Expr)); - potentialMatchingLoops = candidates.SelectMany(candidate => candidate.MatchesInQuantifierBody) - .Deduplicate((x, y) => ExprExtensions.ExpressionEq(x.Expr, y.Expr)).Where(tm => tm.CouldCauseLoops(candidates)).ToList(); - } - - return potentialMatchingLoops; - } - } - - internal MultiTriggerCandidate(List candidates) { - Candidates = candidates; - Tags = new List(); - } - - internal bool MentionsAll(List vars) { - var candidates = Candidates; - return vars.All(x => candidates.Any(candidate => candidate.Variables.Contains(x))); //TODO Perfs? - } - - public override string ToString() { - return String.Format("[{0:G2}] {1}", Score, String.Join(", ", Candidates)); - } - - public String AsDafnyAttributeString(bool wrap = true, bool includeTags = false) { - var repr = Candidates.MapConcat(t => Printer.ExprToString(t.Expr), ", "); - if (wrap) { - repr = "{:trigger " + repr + "}"; - } - if (includeTags && Tags != null) { - repr += " (" + String.Join("; ", Tags) + ")"; - } - return repr; - } - } - - - class TriggerAnnotation { - internal bool IsTriggerKiller; - internal ISet Variables; - internal readonly List PrivateCandidates; - internal readonly List ExportedCandidates; - - internal TriggerAnnotation(bool IsTriggerKiller, IEnumerable Variables, - IEnumerable AllCandidates, IEnumerable PrivateCandidates = null) { - this.IsTriggerKiller = IsTriggerKiller; - this.Variables = new HashSet(Variables); - - this.PrivateCandidates = new List(PrivateCandidates == null ? Enumerable.Empty() : PrivateCandidates); - this.ExportedCandidates = new List(AllCandidates == null ? Enumerable.Empty() : AllCandidates.Except(this.PrivateCandidates)); - } - - public override string ToString() { - StringBuilder sb = new StringBuilder(); - string indent = " {0}", nindent = "\n - {0}", subindent = "\n * {0}"; - - sb.AppendFormat(indent, IsTriggerKiller); - - sb.AppendFormat(nindent, "Variables:"); - foreach (var bv in Variables) { - sb.AppendFormat(subindent, bv.Name); - } - - sb.AppendFormat(nindent, "Exported candidates:"); - foreach (var candidate in ExportedCandidates) { - sb.AppendFormat(subindent, candidate); - } - - if (PrivateCandidates.Any()) { - sb.AppendFormat(nindent, "Private candidates:"); - foreach (var candidate in PrivateCandidates) { - sb.AppendFormat(subindent, candidate); - } - } - - return sb.ToString(); - } - } - - public class TriggerGenerator : BottomUpVisitor { - List quantifiers; - Dictionary annotations; - - Action AdditionalInformationReporter; - - private TriggerGenerator(Action additionalInformationReporter) { - Contract.Requires(additionalInformationReporter != null); - this.quantifiers = new List(); - this.annotations = new Dictionary(); - this.AdditionalInformationReporter = additionalInformationReporter; - } - - private List MergeAlterFirst(List a, List b) { - Contract.Requires(a != null); - Contract.Requires(b != null); - a.AddRange(b); - return a; - } - - private ISet MergeAlterFirst(ISet a, ISet b) { - Contract.Requires(a != null); - Contract.Requires(b != null); - a.UnionWith(b); - return a; - } - - private T ReduceAnnotatedSubExpressions(Expression expr, T seed, Func map, Func reduce) { - return expr.SubExpressions.Select(e => map(Annotate(e))) - .Aggregate(seed, (acc, e) => reduce(acc, e)); - } - - private List CollectExportedCandidates(Expression expr) { - return ReduceAnnotatedSubExpressions>(expr, new List(), a => a.ExportedCandidates, MergeAlterFirst); - } - - private ISet CollectVariables(Expression expr) { - return ReduceAnnotatedSubExpressions(expr, new HashSet(), a => a.Variables, MergeAlterFirst); - } - - private bool CollectIsKiller(Expression expr) { - return ReduceAnnotatedSubExpressions(expr, false, a => a.IsTriggerKiller, (a, b) => a || b); - } - - private IEnumerable OnlyPrivateCandidates(List candidates, IEnumerable privateVars) { - return candidates.Where(c => privateVars.Intersect(c.Variables).Any()); //TODO Check perf - } - - private TriggerAnnotation Annotate(Expression expr) { - TriggerAnnotation cached; - if (annotations.TryGetValue(expr, out cached)) { - return cached; - } - - expr.SubExpressions.Iter(e => Annotate(e)); //NOTE: These values are all cached - - TriggerAnnotation annotation; // TODO: Using ApplySuffix fixes the unresolved members problem in GenericSort - if (expr is FunctionCallExpr || expr is SeqSelectExpr || expr is MemberSelectExpr || expr is OldExpr || - (expr is UnaryOpExpr && (((UnaryOpExpr)expr).Op == UnaryOpExpr.Opcode.Cardinality)) || // FIXME || ((UnaryOpExpr)expr).Op == UnaryOpExpr.Opcode.Fresh oesn't work, as fresh is a pretty tricky predicate when it's not about datatypes. See translator.cs:10944 - (expr is BinaryExpr && (((BinaryExpr)expr).Op == BinaryExpr.Opcode.NotIn || ((BinaryExpr)expr).Op == BinaryExpr.Opcode.In))) { - annotation = AnnotatePotentialCandidate(expr); - } else if (expr is QuantifierExpr) { - annotation = AnnotateQuantifier((QuantifierExpr)expr); - } else if (expr is LetExpr) { - annotation = AnnotateLetExpr((LetExpr)expr); - } else if (expr is IdentifierExpr) { - annotation = AnnotateIdentifier((IdentifierExpr)expr); - } else if (expr is ApplySuffix) { - annotation = AnnotateApplySuffix((ApplySuffix)expr); - } else if (expr is ConcreteSyntaxExpression || - expr is LiteralExpr || - expr is OldExpr || - expr is ThisExpr || - expr is BoxingCastExpr || - expr is DatatypeValue) { - annotation = AnnotateOther(expr, false); - } else { - annotation = AnnotateOther(expr, true); - } - - DebugTriggers("{0} ({1})\n{2}", Printer.ExprToString(expr), expr.GetType(), annotation); - annotations[expr] = annotation; - return annotation; - } - - [Conditional("DEBUG_AUTO_TRIGGERS")] - private static void DebugTriggers(string format, params object[] more) { - Console.Error.WriteLine(format, more); - } - - private BinaryExpr.ResolvedOpcode RemoveNotInBinaryExprIn(BinaryExpr.ResolvedOpcode opcode) { - switch(opcode) { - case BinaryExpr.ResolvedOpcode.NotInMap: - return BinaryExpr.ResolvedOpcode.InMap; - case BinaryExpr.ResolvedOpcode.NotInSet: - return BinaryExpr.ResolvedOpcode.InSet; - case BinaryExpr.ResolvedOpcode.NotInSeq: - return BinaryExpr.ResolvedOpcode.InSeq; - case BinaryExpr.ResolvedOpcode.NotInMultiSet: - return BinaryExpr.ResolvedOpcode.InMultiSet; - } - - Contract.Assert(false); - throw new ArgumentException(); - } - - private Expression CleanupExpr(Expression expr, out bool isKiller) { - isKiller = false; - - if (!(expr is BinaryExpr)) { - return expr; - } - - var bexpr = expr as BinaryExpr; - - BinaryExpr new_expr = bexpr; - if (bexpr.Op == BinaryExpr.Opcode.NotIn) { - new_expr = new BinaryExpr(bexpr.tok, BinaryExpr.Opcode.In, bexpr.E0, bexpr.E1); - new_expr.ResolvedOp = RemoveNotInBinaryExprIn(bexpr.ResolvedOp); - new_expr.Type = bexpr.Type; - } - - Expression returned_expr = new_expr; - if (new_expr.ResolvedOp == BinaryExpr.ResolvedOpcode.InMultiSet) { - returned_expr = new SeqSelectExpr(new_expr.tok, true, new_expr.E1, new_expr.E0, null); - returned_expr.Type = bexpr.Type; - isKiller = true; // [a in s] becomes [s[a] > 0], which is a trigger killer - } - - return returned_expr; - } - - private TriggerAnnotation AnnotatePotentialCandidate(Expression expr) { - bool expr_is_killer = false; - var new_expr = CleanupExpr(expr, out expr_is_killer); - var new_candidate = new TriggerCandidate { Expr = new_expr, Variables = CollectVariables(expr) }; - - List collected_candidates = CollectExportedCandidates(expr); - var children_contain_killers = CollectIsKiller(expr); - - if (!children_contain_killers) { - // Add only if the children are not killers; the head has been cleaned up into non-killer form - collected_candidates.Add(new_candidate); - } - - // This new node is a killer if its children were killers, or if it's non-cleaned-up head is a killer - return new TriggerAnnotation(children_contain_killers || expr_is_killer, new_candidate.Variables, collected_candidates); - } - - private TriggerAnnotation AnnotateApplySuffix(ApplySuffix expr) { - // This is a bit tricky. A funcall node is generally meaningful as a trigger candidate, - // but when it's part of an ApplySuffix the function call itself may not resolve properly - // when the second round of resolving is done after modules are duplicated. - // Thus first we annotate expr and create a trigger candidate, and then we remove the - // candidate matching its direct subexpression if needed. Not that function calls are not the - // only possible child here; there can be DatatypeValue nodes, for example (see vstte2012/Combinators.dfy). - var annotation = AnnotatePotentialCandidate(expr); - // Comparing by reference is fine here. Using sets could yield a small speedup - annotation.ExportedCandidates.RemoveAll(candidate => expr.SubExpressions.Contains(candidate.Expr)); - return annotation; - } - - private TriggerAnnotation AnnotateQuantifierOrLetExpr(Expression expr, IEnumerable boundVars) { - var candidates = CollectExportedCandidates(expr); - return new TriggerAnnotation(true, CollectVariables(expr), candidates, OnlyPrivateCandidates(candidates, boundVars)); - } - - private TriggerAnnotation AnnotateQuantifier(QuantifierExpr expr) { - quantifiers.Add(expr); - return AnnotateQuantifierOrLetExpr(expr, expr.BoundVars); - } - - private TriggerAnnotation AnnotateLetExpr(LetExpr expr) { - return AnnotateQuantifierOrLetExpr(expr, expr.BoundVars); - } - - private TriggerAnnotation AnnotateIdentifier(IdentifierExpr expr) { - return new TriggerAnnotation(false, Enumerable.Repeat(expr.Var, 1), null); - } - - private TriggerAnnotation AnnotateOther(Expression expr, bool isTriggerKiller) { - return new TriggerAnnotation(isTriggerKiller || CollectIsKiller(expr), CollectVariables(expr), CollectExportedCandidates(expr)); - } - - private static List CopyAndAdd(List seq, T elem) { - var copy = new List(seq); - copy.Add(elem); - return copy; - } - - private static IEnumerable> AllSubsets(IList source, int offset) { - if (offset >= source.Count) { - yield return new List(); - yield break; - } - - foreach (var subset in AllSubsets(source, offset + 1)) { - yield return CopyAndAdd(subset, source[offset]); - yield return new List(subset); - } - } - - private static IEnumerable> AllNonEmptySubsets(IEnumerable source) { - List all = new List(source); - foreach (var subset in AllSubsets(all, 0)) { - if (subset.Count > 0) { - yield return subset; - } - } - } - - private static bool DefaultCandidateFilteringFunction(TriggerCandidate candidate, QuantifierExpr quantifier) { - //FIXME this will miss rewritten expressions (CleanupExpr). Should introduce an OriginalExpr to compare. - candidate.MatchesInQuantifierBody = quantifier.SubexpressionsMatchingTrigger(candidate.Expr).ToList(); - return true; - } - - private static bool DefaultMultiCandidateFilteringFunction(MultiTriggerCandidate multiCandidate, QuantifierExpr quantifier) { - var allowsLoops = quantifier.Attributes.AsEnumerable().Any(a => a.Name == "loop"); - - if (!allowsLoops && multiCandidate.PotentialMatchingLoops.Any()) { - multiCandidate.Tags.Add(String.Format("matching loop with {0}", multiCandidate.PotentialMatchingLoops.MapConcat(tm => Printer.ExprToString(tm.Expr), ", "))); - } - return multiCandidate.MentionsAll(quantifier.BoundVars) && (allowsLoops || !multiCandidate.PotentialMatchingLoops.Any()); - } - - private static double DefaultMultiCandidateScoringFunction(MultiTriggerCandidate multi_candidate) { - return 1.0; - } - - private static IEnumerable DefaultMultiCandidateSelectionFunction(List multi_candidates) { - return multi_candidates; - } - - // CLEMENT: Make these customizable - internal Func CandidateFilteringFunction = DefaultCandidateFilteringFunction; - internal Func MultiCandidateFilteringFunction = DefaultMultiCandidateFilteringFunction; - internal Func MultiCandidateScoringFunction = DefaultMultiCandidateScoringFunction; - internal Func, IEnumerable> MultiCandidateSelectionFunction = DefaultMultiCandidateSelectionFunction; - - struct MultiCandidatesCollection { - internal List AllCandidates; - internal List SelectedCandidates; - internal List RejectedCandidates; - internal List SelectedMultiCandidates; - internal List RejectedMultiCandidates; - internal List FinalMultiCandidates; - - public MultiCandidatesCollection(QuantifierExpr quantifier, - TriggerAnnotation annotation, - Func CandidateFilteringFunction, - Func MultiCandidateFilteringFunction, - Func MultiCandidateScoringFunction, - Func, IEnumerable> MultiCandidateSelectionFunction) { - - Contract.Requires(annotation != null); - Contract.Requires(quantifier != null); - Contract.Requires(CandidateFilteringFunction != null); - Contract.Requires(MultiCandidateFilteringFunction != null); - Contract.Requires(MultiCandidateScoringFunction != null); - Contract.Requires(MultiCandidateSelectionFunction != null); - - AllCandidates = annotation.PrivateCandidates.Deduplicate((x, y) => ExprExtensions.ExpressionEq(x.Expr, y.Expr)); - Partition(AllCandidates, - x => CandidateFilteringFunction(x, quantifier), out SelectedCandidates, out RejectedCandidates); - Partition(AllNonEmptySubsets(SelectedCandidates).Select(s => new MultiTriggerCandidate(s)), - x => MultiCandidateFilteringFunction(x, quantifier), out SelectedMultiCandidates, out RejectedMultiCandidates); - SelectedMultiCandidates.Iter(x => x.Score = MultiCandidateScoringFunction(x)); - FinalMultiCandidates = MultiCandidateSelectionFunction(SelectedMultiCandidates).ToList(); - } - - private static void Partition(IEnumerable elements, Func predicate, out List positive, out List negative) { - positive = new List(); - negative = new List(); - foreach (var c in elements) { - (predicate(c) ? positive : negative).Add(c); - } - } - - internal string Warning() { - if (AllCandidates.Count == 0) { - return "No triggers found in the body of this quantifier."; - } else if (SelectedCandidates.Count == 0) { - return String.Format("No suitable triggers found. Candidate building blocks for a good trigger where [{0}], but none these terms passed the initial selection stage.", String.Join(", ", AllCandidates)); - } else if (SelectedMultiCandidates.Count == 0) { - return String.Format("No suitable set of triggers found. Candidate building blocks for a good trigger where [{0}], but no subset of these terms passed the subset selection stage.", String.Join(", ", SelectedCandidates)); - } else if (FinalMultiCandidates.Count == 0) { - return String.Format("No suitable set of triggers found. Candidates where [{0}], but none passed the final selection stage.", String.Join(", ", SelectedMultiCandidates)); - } else { - return null; - } - } - - private void WriteIndented(StringBuilder builder, string indent, IEnumerable elements) { - foreach (var element in elements) { - builder.Append(indent).AppendLine(element.ToString()); - } - } - - private void WriteListOfCandidates(StringBuilder builder, string indent, IEnumerable elements) { - if (elements.Any()) { - builder.AppendLine(); - WriteIndented(builder, indent, elements); - } else { - builder.AppendLine(" (None)"); - } - } - - public override string ToString() { - var repr = new StringBuilder(); - var indent = " "; - repr.Append(" All:"); - WriteListOfCandidates(repr, indent, AllCandidates); - repr.Append(" Selected1:"); - WriteListOfCandidates(repr, indent, SelectedCandidates); - repr.Append(" PreFilter:"); - WriteListOfCandidates(repr, indent, AllNonEmptySubsets(AllCandidates).Select(c => String.Join(", ", c))); - repr.Append(" SelectedMulti:"); - WriteListOfCandidates(repr, indent, SelectedMultiCandidates.Select(c => String.Join(", ", c))); - repr.Append(" Final:"); - WriteListOfCandidates(repr, indent, FinalMultiCandidates); - return repr.ToString(); - } - } - - private MultiCandidatesCollection PickMultiTriggers(QuantifierExpr quantifier) { - var annotation = Annotate(quantifier); - DebugTriggers("Quantifier {0}:\n{1}", Printer.ExprToString(quantifier), annotation); - return new MultiCandidatesCollection(quantifier, annotation, CandidateFilteringFunction, MultiCandidateFilteringFunction, MultiCandidateScoringFunction, MultiCandidateSelectionFunction); - } - - private void AddTrigger(QuantifierExpr quantifier) { - DebugTriggers(" Final results:\n{0}", PickMultiTriggers(quantifier)); - - if (quantifier.Attributes.AsEnumerable().Any(aa => aa.Name == "trigger" || aa.Name == "no_trigger")) { - DebugTriggers("Not generating triggers for {0}", Printer.ExprToString(quantifier)); //FIXME: no_trigger is passed down to Boogie - return; - } - - var multi_candidates = PickMultiTriggers(quantifier); - foreach (var multi_candidate in multi_candidates.FinalMultiCandidates) { //TODO: error message for when no triggers found - quantifier.Attributes = new Attributes("trigger", multi_candidate.Candidates.Select(t => t.Expr).ToList(), quantifier.Attributes); - } - - if (multi_candidates.RejectedMultiCandidates.Any()) { - var tooltip = JoinStringsWithHeader("Rejected: ", multi_candidates.RejectedMultiCandidates.Where(candidate => candidate.Tags != null) - .Select(candidate => candidate.AsDafnyAttributeString(true, true))); - AdditionalInformationReporter(quantifier.tok, tooltip, quantifier.tok.val.Length); - } - - if (multi_candidates.FinalMultiCandidates.Any()) { - var tooltip = JoinStringsWithHeader("Triggers: ", multi_candidates.FinalMultiCandidates.Select(multi_candidate => multi_candidate.AsDafnyAttributeString())); - AdditionalInformationReporter(quantifier.tok, tooltip, quantifier.tok.val.Length); - } - - string warning = multi_candidates.Warning(); - if (warning != null) { - // FIXME reenable Resolver.Warning(quantifier.tok, warning); - } - } - - internal static bool IsTriggerKiller(Expression expr) { - var annotation = new TriggerGenerator((x, y, z) => { }).Annotate(expr); - return annotation.IsTriggerKiller; - } - - private string JoinStringsWithHeader(string header, IEnumerable lines) { - return header + String.Join(Environment.NewLine + new String(' ', header.Length), lines); - } - - private void AddTriggers_Internal() { - foreach (var quantifier in quantifiers) { - AddTrigger(quantifier); - } - } - - private void AddTriggers_Internal(Expression root) { - Visit(root); - AddTriggers_Internal(); - } - - private void AddTriggers_Internal(Statement root) { - Visit(root); - AddTriggers_Internal(); - } - - internal static void AddTriggers(Expression root, Resolver resolver) { - if (root == null) - return; - - DebugTriggers("== From {0} visiting expr: {1}", new StackFrame(1).GetMethod().Name, Printer.ExprToString(root)); - TriggerGenerator generator = new TriggerGenerator(null); - generator.AddTriggers_Internal(root); - } - - internal static void AddTriggers(Statement root, Resolver resolver) { - if (root == null) - return; - - DebugTriggers("== From {0} visiting statement: {1}", new StackFrame(1).GetMethod().Name, Printer.StatementToString(root)); - TriggerGenerator generator = new TriggerGenerator(null); - generator.AddTriggers_Internal(root); - } - - internal static void AddTriggers(IEnumerable roots, Resolver resolver) { - DebugTriggers("== From {0} visiting expressions: {1}", new StackFrame(1).GetMethod().Name, - roots.MapConcat(Printer.ExprToString, ", ")); - foreach (var expr in roots) { - AddTriggers(expr, resolver); - } - } - - internal static void AddTriggers(IEnumerable roots, Resolver resolver) { - DebugTriggers("== From {0} visiting expressions: {1}", new StackFrame(1).GetMethod().Name, - roots.MapConcat(root => Printer.ExprToString(root.E), ", ")); - foreach (var expr in roots) { - AddTriggers(expr.E, resolver); - } - } - - protected override void VisitOneExpr(Expression expr) { - Annotate(expr); - } - } - - internal static class DeduplicateExtension { - public static List Deduplicate(this IEnumerable seq, Func eq) { - List deduplicated = new List(); - - foreach (var elem in seq) { - if (!deduplicated.Any(other => eq(elem, other))) { - deduplicated.Add(elem); - } - } - - return deduplicated; - } - } - - static class ExprExtensions { - static IEnumerable AllSubExpressions(this Expression expr, bool strict = false) { - foreach (var subexpr in expr.SubExpressions) { - foreach (var r_subexpr in AllSubExpressions(subexpr, false)) { - yield return r_subexpr; - } - yield return subexpr; - } - - if (expr is StmtExpr) { - foreach (var r_subexpr in AllSubExpressions(((StmtExpr)expr).S, false)) { - yield return r_subexpr; - } - } - - if (!strict) { - yield return expr; - } - } - - private static IEnumerable AllSubExpressions(this Statement stmt, bool strict = false) { - foreach (var subexpr in stmt.SubExpressions) { - foreach (var r_subexpr in AllSubExpressions(subexpr, false)) { - yield return r_subexpr; - } - yield return subexpr; - } - - foreach (var substmt in stmt.SubStatements) { - foreach (var r_subexpr in AllSubExpressions(substmt, false)) { - yield return r_subexpr; - } - } - } - - internal static bool ExpressionEq(this Expression expr1, Expression expr2) { - expr1 = GetResolved(expr1); - expr2 = GetResolved(expr2); - - return ShallowEq_Top(expr1, expr2) && SameLists(expr1.SubExpressions, expr2.SubExpressions, (e1, e2) => ExpressionEq(e1, e2)); - } - - internal static bool ExpressionEqModuloVariableNames(this Expression expr1, Expression expr2) { - expr1 = GetResolved(expr1); - expr2 = GetResolved(expr2); - - if (expr1 is IdentifierExpr) { - return expr2 is IdentifierExpr; - } - - return ShallowEq_Top(expr1, expr2) && SameLists(expr1.SubExpressions, expr2.SubExpressions, (e1, e2) => ExpressionEqModuloVariableNames(e1, e2)); - } - - private static bool MatchesTrigger(this Expression expr, Expression trigger, ISet holes, Dictionary bindings) { - expr = GetResolved(expr); - trigger = GetResolved(trigger); - - if (trigger is IdentifierExpr) { - var var = ((IdentifierExpr)trigger).Var; - - if (holes.Contains(var)) { - Expression existing_binding = null; - if (bindings.TryGetValue(var, out existing_binding)) { - return ExpressionEq(expr, existing_binding); - } else { - bindings[var] = expr; - return true; - } - } - } - - return ShallowEq_Top(expr, trigger) && SameLists(expr.SubExpressions, trigger.SubExpressions, (e1, e2) => MatchesTrigger(e1, e2, holes, bindings)); - } - - internal struct TriggerMatch { - internal Expression Expr; - internal Dictionary Bindings; - - internal bool CouldCauseLoops(IEnumerable candidates) { - // A match for a trigger in the body of a quantifier can be a problem if - // it yields to a matching loop: for example, f(x) is a bad trigger in - // forall x, y :: f(x) = f(f(x)) - // In general, any such match can lead to a loop, but two special cases - // will only lead to a finite number of instantiations: - // 1. The match equals one of the triggers in the set of triggers under - // consideration. For example, { f(x) } a bad trigger above, but the - // pair { f(x), f(f(x)) } is fine (instantiating won't yield new - // matches) - // 2. The match only differs from one of these triggers by variable - // names. This is a superset of the previous case. - var expr = Expr; - return !candidates.Any(c => c.Expr.ExpressionEqModuloVariableNames(expr)); - } - } - - private static TriggerMatch? MatchAgainst(this Expression expr, Expression trigger, ISet holes) { - var bindings = new Dictionary(); - return expr.MatchesTrigger(trigger, holes, bindings) ? new TriggerMatch { Expr = expr, Bindings = bindings } : (TriggerMatch?)null; - } - - internal static IEnumerable SubexpressionsMatchingTrigger(this QuantifierExpr quantifier, Expression trigger) { - return quantifier.Term.AllSubExpressions() - .Select(e => e.MatchAgainst(trigger, new HashSet(quantifier.BoundVars))) - .Where(e => e.HasValue).Select(e => e.Value); - } - - private static bool SameLists(IEnumerable list1, IEnumerable list2, Func comparer) { - if (ReferenceEquals(list1, list2)) { - return true; - } else if ((list1 == null) != (list2 == null)) { - return false; - } - - var it1 = list1.GetEnumerator(); - var it2 = list2.GetEnumerator(); - bool it1_has, it2_has; - bool acc = true; - - do { - it1_has = it1.MoveNext(); - it2_has = it2.MoveNext(); - - if (it1_has == true && it2_has == true) { - acc = acc && comparer(it1.Current, it2.Current); - } - } while (it1_has && it2_has); - - return it1_has == it2_has && acc; - } - - private static bool SameNullity(T x1, T x2) where T : class { - return (x1 == null) == (x2 == null); - } - - private static bool ShallowSameAttributes(Attributes attributes1, Attributes attributes2) { - return SameLists(attributes1.AsEnumerable(), attributes2.AsEnumerable(), ShallowSameSingleAttribute); - } - - private static bool ShallowSameSingleAttribute(Attributes arg1, Attributes arg2) { - return arg1.Name == arg2.Name; - } - - private static bool SameBoundVar(IVariable arg1, IVariable arg2) { - return arg1 == arg2 || - (arg1.Name == arg2.Name && - arg1.CompileName == arg2.CompileName && - arg1.DisplayName == arg2.DisplayName && - arg1.UniqueName == arg2.UniqueName && - arg1.IsGhost == arg2.IsGhost && - arg1.IsMutable == arg2.IsMutable); //FIXME compare types? - } - - private static Expression GetResolved(Expression expr) { - if (expr is ConcreteSyntaxExpression) { - return ((ConcreteSyntaxExpression)expr).ResolvedExpression; - } - return expr; - } - - /// - /// Compares two abstract syntax expressions, looking only at their direct members. Subexpressions and substatements are not compared. - /// - /// - internal static bool ShallowEq_Top(Expression expr1, Expression expr2) { - Contract.Requires(expr1 != null); - Contract.Requires(expr2 != null); - - // We never compare concrete expressions - Contract.Requires(!(expr1 is ConcreteSyntaxExpression)); - Contract.Requires(!(expr2 is ConcreteSyntaxExpression)); - - // CPC: Hey future editor: the following block of code is auto-generated. Just add your own cases at the end. - // This could be a visitor pattern, except I need to visit a pair of nodes. - // It could also be implemented in each individual class. I'd have a slight preference for that. - // This really just wants to use double dispatch. - if (expr1 is UnboxingCastExpr && expr2 is UnboxingCastExpr) { - return ShallowEq((UnboxingCastExpr)expr1, (UnboxingCastExpr)expr2); - } else if (expr1 is BoxingCastExpr && expr2 is BoxingCastExpr) { - return ShallowEq((BoxingCastExpr)expr1, (BoxingCastExpr)expr2); - } else if (expr1 is MatchExpr && expr2 is MatchExpr) { - return ShallowEq((MatchExpr)expr1, (MatchExpr)expr2); - } else if (expr1 is ITEExpr && expr2 is ITEExpr) { - return ShallowEq((ITEExpr)expr1, (ITEExpr)expr2); - } else if (expr1 is StmtExpr && expr2 is StmtExpr) { - return ShallowEq((StmtExpr)expr1, (StmtExpr)expr2); - } else if (expr1 is WildcardExpr && expr2 is WildcardExpr) { - return ShallowEq((WildcardExpr)expr1, (WildcardExpr)expr2); - } else if (expr1 is ComprehensionExpr && expr2 is ComprehensionExpr) { - return ShallowEq((ComprehensionExpr)expr1, (ComprehensionExpr)expr2); - } else if (expr1 is NamedExpr && expr2 is NamedExpr) { - return ShallowEq((NamedExpr)expr1, (NamedExpr)expr2); - } else if (expr1 is LetExpr && expr2 is LetExpr) { - return ShallowEq((LetExpr)expr1, (LetExpr)expr2); - } else if (expr1 is TernaryExpr && expr2 is TernaryExpr) { - return ShallowEq((TernaryExpr)expr1, (TernaryExpr)expr2); - } else if (expr1 is BinaryExpr && expr2 is BinaryExpr) { - return ShallowEq((BinaryExpr)expr1, (BinaryExpr)expr2); - } else if (expr1 is UnaryExpr && expr2 is UnaryExpr) { - return ShallowEq((UnaryExpr)expr1, (UnaryExpr)expr2); - } else if (expr1 is MultiSetFormingExpr && expr2 is MultiSetFormingExpr) { - return ShallowEq((MultiSetFormingExpr)expr1, (MultiSetFormingExpr)expr2); - } else if (expr1 is OldExpr && expr2 is OldExpr) { - return ShallowEq((OldExpr)expr1, (OldExpr)expr2); - } else if (expr1 is FunctionCallExpr && expr2 is FunctionCallExpr) { - return ShallowEq((FunctionCallExpr)expr1, (FunctionCallExpr)expr2); - } else if (expr1 is ApplyExpr && expr2 is ApplyExpr) { - return ShallowEq((ApplyExpr)expr1, (ApplyExpr)expr2); - } else if (expr1 is SeqUpdateExpr && expr2 is SeqUpdateExpr) { - return ShallowEq((SeqUpdateExpr)expr1, (SeqUpdateExpr)expr2); - } else if (expr1 is MultiSelectExpr && expr2 is MultiSelectExpr) { - return ShallowEq((MultiSelectExpr)expr1, (MultiSelectExpr)expr2); - } else if (expr1 is SeqSelectExpr && expr2 is SeqSelectExpr) { - return ShallowEq((SeqSelectExpr)expr1, (SeqSelectExpr)expr2); - } else if (expr1 is MemberSelectExpr && expr2 is MemberSelectExpr) { - return ShallowEq((MemberSelectExpr)expr1, (MemberSelectExpr)expr2); - } else if (expr1 is MapDisplayExpr && expr2 is MapDisplayExpr) { //Note: MapDisplayExpr is not a DisplayExpression - return ShallowEq((MapDisplayExpr)expr1, (MapDisplayExpr)expr2); - } else if (expr1 is DisplayExpression && expr2 is DisplayExpression) { - return ShallowEq((DisplayExpression)expr1, (DisplayExpression)expr2); - } else if (expr1 is IdentifierExpr && expr2 is IdentifierExpr) { - return ShallowEq((IdentifierExpr)expr1, (IdentifierExpr)expr2); - } else if (expr1 is ThisExpr && expr2 is ThisExpr) { - return ShallowEq((ThisExpr)expr1, (ThisExpr)expr2); - } else if (expr1 is DatatypeValue && expr2 is DatatypeValue) { - return ShallowEq((DatatypeValue)expr1, (DatatypeValue)expr2); - } else if (expr1 is LiteralExpr && expr2 is LiteralExpr) { - return ShallowEq((LiteralExpr)expr1, (LiteralExpr)expr2); - } else { - // If this assertion fail, then a new abstract AST node was probably introduced but not registered here. - Contract.Assert(expr1.GetType() != expr2.GetType()); - return false; - } - } - - private static bool ShallowEq(UnboxingCastExpr expr1, UnboxingCastExpr expr2) { - Contract.Requires(false); - throw new InvalidOperationException(); - } - - private static bool ShallowEq(BoxingCastExpr expr1, BoxingCastExpr expr2) { - return expr1.FromType == expr2.FromType && - expr1.ToType == expr2.ToType; - } - - private static bool ShallowEq(MatchExpr expr1, MatchExpr expr2) { - return true; - } - - private static bool ShallowEq(ITEExpr expr1, ITEExpr expr2) { - return true; - } - - private static bool ShallowEq(StmtExpr expr1, StmtExpr expr2) { -#if THROW_UNSUPPORTED_COMPARISONS - Contract.Assume(false); // This kind of expression never appears in a trigger - throw new NotImplementedException(); -#else - return expr1.S == expr2.S; -#endif - } - - private static bool ShallowEq(WildcardExpr expr1, WildcardExpr expr2) { - return true; - } - - private static bool ShallowEq(LambdaExpr expr1, LambdaExpr expr2) { -#if THROW_UNSUPPORTED_COMPARISONS - Contract.Assume(false); // This kind of expression never appears in a trigger - throw new NotImplementedException(); -#else - return expr1.OneShot == expr2.OneShot && - SameLists(expr1.Reads, expr2.Reads, SameFrameExpression); -#endif - } - - private static bool ShallowEq(MapComprehension expr1, MapComprehension expr2) { - return expr1.Finite == expr2.Finite; - } - - private static bool ShallowEq(SetComprehension expr1, SetComprehension expr2) { - return expr1.TermIsImplicit == expr2.TermIsImplicit && //TODO - expr1.Finite == expr2.Finite; - } - - private static bool ShallowEq(ExistsExpr expr1, ExistsExpr expr2) { - return true; - } - - private static bool ShallowEq(ForallExpr expr1, ForallExpr expr2) { - return true; - } - - private static bool ShallowEq(QuantifierExpr expr1, QuantifierExpr expr2) { //FIXME are these TypeArgs still useful? - if (expr1.TypeArgs.Count != expr2.TypeArgs.Count || - !SameNullity(expr1.Range, expr2.Range)) { - return false; - } - - if (expr1 is ExistsExpr && expr2 is ExistsExpr) { - return ShallowEq((ExistsExpr)expr1, (ExistsExpr)expr2); - } else if (expr1 is ForallExpr && expr2 is ForallExpr) { - return ShallowEq((ForallExpr)expr1, (ForallExpr)expr2); - } else { - return false; - } - } - - private static bool ShallowEq(ComprehensionExpr expr1, ComprehensionExpr expr2) { - if (!SameLists(expr1.BoundVars, expr2.BoundVars, SameBoundVar) || - !ShallowSameAttributes(expr1.Attributes, expr2.Attributes) || - // Filled in during resolution: !SameLists(expr1.Bounds, expr2.Bounds, ReferenceCompare) || - // !SameLists(expr1.MissingBounds, expr2.MissingBounds, SameBoundVar) || - !SameNullity(expr1.Range, expr2.Range)) { //TODO Check - return false; - } - - if (expr1 is LambdaExpr && expr2 is LambdaExpr) { - return ShallowEq((LambdaExpr)expr1, (LambdaExpr)expr2); - } else if (expr1 is MapComprehension && expr2 is MapComprehension) { - return ShallowEq((MapComprehension)expr1, (MapComprehension)expr2); - } else if (expr1 is SetComprehension && expr2 is SetComprehension) { - return ShallowEq((SetComprehension)expr1, (SetComprehension)expr2); - } else if (expr1 is QuantifierExpr && expr2 is QuantifierExpr) { - return ShallowEq((QuantifierExpr)expr1, (QuantifierExpr)expr2); - } else { - return false; // ComprehensionExpr is abstract - } - } - - private static bool ShallowEq(NamedExpr expr1, NamedExpr expr2) { - return expr1.Name == expr2.Name && - SameNullity(expr1.Contract, expr2.Contract); - } - - private static bool ShallowEq(LetExpr expr1, LetExpr expr2) { - return expr1.Exact == expr2.Exact && - ShallowSameAttributes(expr1.Attributes, expr2.Attributes); - } - - private static bool ShallowEq(TernaryExpr expr1, TernaryExpr expr2) { - return expr1.Op == expr2.Op; - } - - private static bool ShallowEq(BinaryExpr expr1, BinaryExpr expr2) { - Contract.Requires(expr1.ResolvedOp != BinaryExpr.ResolvedOpcode.YetUndetermined); - Contract.Requires(expr2.ResolvedOp != BinaryExpr.ResolvedOpcode.YetUndetermined); - return expr1.ResolvedOp == expr2.ResolvedOp; - } - - private static bool ShallowEq(ConversionExpr expr1, ConversionExpr expr2) { - return expr1.Type == expr2.Type; //TODO equality on types? - } - - private static bool ShallowEq(UnaryOpExpr expr1, UnaryOpExpr expr2) { - return expr1.Op == expr2.Op; - } - - private static bool ShallowEq(UnaryExpr expr1, UnaryExpr expr2) { - if (expr1 is ConversionExpr && expr2 is ConversionExpr) { - return ShallowEq((ConversionExpr)expr1, (ConversionExpr)expr2); - } else if (expr1 is UnaryOpExpr && expr2 is UnaryOpExpr) { - return ShallowEq((UnaryOpExpr)expr1, (UnaryOpExpr)expr2); - } else { - return false; // UnaryExpr is abstract - } - } - - private static bool ShallowEq(MultiSetFormingExpr expr1, MultiSetFormingExpr expr2) { - return true; - } - - private static bool ShallowEq(OldExpr expr1, OldExpr expr2) { - return true; - } - - private static bool ShallowEq(FunctionCallExpr expr1, FunctionCallExpr expr2) { - return expr1.Name == expr2.Name && - expr1.CoCall == expr2.CoCall && //TODO - expr1.Function == expr2.Function; // TODO TypeArgumentSubstitutions? - } - - private static bool ShallowEq(ApplyExpr expr1, ApplyExpr expr2) { - return true; - } - - private static bool ShallowEq(SeqUpdateExpr expr1, SeqUpdateExpr expr2) { - Contract.Requires(expr1.ResolvedUpdateExpr != null && expr2.ResolvedUpdateExpr != null); - return true; - } - - private static bool ShallowEq(MultiSelectExpr expr1, MultiSelectExpr expr2) { - return true; - } - - private static bool ShallowEq(SeqSelectExpr expr1, SeqSelectExpr expr2) { - return expr1.SelectOne == expr2.SelectOne && - SameNullity(expr1.Seq, expr2.Seq) && - SameNullity(expr1.E0, expr2.E0) && - SameNullity(expr1.E1, expr2.E1); - } - - private static bool ShallowEq(MemberSelectExpr expr1, MemberSelectExpr expr2) { - return expr1.MemberName == expr2.MemberName && - expr1.Member == expr2.Member && - SameLists(expr1.TypeApplication, expr2.TypeApplication, Type.Equals); - } - - private static bool ShallowEq(SeqDisplayExpr expr1, SeqDisplayExpr expr2) { - return true; - } - - private static bool ShallowEq(MapDisplayExpr expr1, MapDisplayExpr expr2) { - return expr1.Finite == expr2.Finite; - } - - private static bool ShallowEq(MultiSetDisplayExpr expr1, MultiSetDisplayExpr expr2) { - return true; - } - - private static bool ShallowEq(SetDisplayExpr expr1, SetDisplayExpr expr2) { - return expr1.Finite == expr2.Finite; - } - - private static bool ShallowEq(DisplayExpression expr1, DisplayExpression expr2) { - if (expr1 is SeqDisplayExpr && expr2 is SeqDisplayExpr) { - return ShallowEq((SeqDisplayExpr)expr1, (SeqDisplayExpr)expr2); - } else if (expr1 is MultiSetDisplayExpr && expr2 is MultiSetDisplayExpr) { - return ShallowEq((MultiSetDisplayExpr)expr1, (MultiSetDisplayExpr)expr2); - } else if (expr1 is SetDisplayExpr && expr2 is SetDisplayExpr) { - return ShallowEq((SetDisplayExpr)expr1, (SetDisplayExpr)expr2); - } else { - return false; - } - } - - private static bool ShallowEq(AutoGhostIdentifierExpr expr1, AutoGhostIdentifierExpr expr2) { - return true; - } - - private static bool ShallowEq(IdentifierExpr expr1, IdentifierExpr expr2) { - if (expr1.Name != expr2.Name || - expr1.Var != expr2.Var) { - return false; - } - - if (expr1 is AutoGhostIdentifierExpr && expr2 is AutoGhostIdentifierExpr) { - return ShallowEq((AutoGhostIdentifierExpr)expr1, (AutoGhostIdentifierExpr)expr2); - } else { - return true; - } - } - - private static bool ShallowEq(ImplicitThisExpr expr1, ImplicitThisExpr expr2) { - return true; - } - - private static bool ShallowEq(ThisExpr expr1, ThisExpr expr2) { - if (expr1 is ImplicitThisExpr && expr2 is ImplicitThisExpr) { - return ShallowEq((ImplicitThisExpr)expr1, (ImplicitThisExpr)expr2); - } else { - return (expr1.GetType() == expr2.GetType()); // LiteralExpr is not abstract - } - } - - private static bool ShallowEq(DatatypeValue expr1, DatatypeValue expr2) { - return // Implied by Ctor equality: expr1.DatatypeName == expr2.DatatypeName && - // Implied by Ctor equality: expr1.MemberName == expr2.MemberName && - expr1.Ctor == expr2.Ctor && - // Contextual information: expr1.IsCoCall == expr2.IsCoCall && - SameLists(expr1.InferredTypeArgs, expr2.InferredTypeArgs, Type.Equals); - } - - private static bool ShallowEq(StringLiteralExpr expr1, StringLiteralExpr expr2) { - return true; - } - - private static bool ShallowEq(CharLiteralExpr expr1, CharLiteralExpr expr2) { - return true; - } - - private static bool ShallowEq(StaticReceiverExpr expr1, StaticReceiverExpr expr2) { - return true; - } - - private static bool ShallowEq(LiteralExpr expr1, LiteralExpr expr2) { - if (expr1.Value != expr2.Value) { - return false; - } - - if (expr1 is StringLiteralExpr && expr2 is StringLiteralExpr) { - return ShallowEq((StringLiteralExpr)expr1, (StringLiteralExpr)expr2); - } else if (expr1 is CharLiteralExpr && expr2 is CharLiteralExpr) { - return ShallowEq((CharLiteralExpr)expr1, (CharLiteralExpr)expr2); - } else if (expr1 is StaticReceiverExpr && expr2 is StaticReceiverExpr) { - return ShallowEq((StaticReceiverExpr)expr1, (StaticReceiverExpr)expr2); - } else { - return (expr1.GetType() == expr2.GetType()); // LiteralExpr is not abstract - } - } - } -} diff --git a/Source/Dafny/Triggers/QuantifierSplitter.cs b/Source/Dafny/Triggers/QuantifierSplitter.cs new file mode 100644 index 00000000..e83feebb --- /dev/null +++ b/Source/Dafny/Triggers/QuantifierSplitter.cs @@ -0,0 +1,66 @@ +using Microsoft.Boogie; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Microsoft.Dafny.Triggers { + class QuantifierSplitter : BottomUpVisitor { + internal enum Quantifier { Forall, Exists } + + internal static IEnumerable BreakQuantifier(Expression expr, Quantifier quantifier) { + expr = expr.Resolved; + var binary = expr as BinaryExpr; + + if (binary == null) { + yield return expr; + yield break; + } + + var e0 = binary.E0; + var e1 = binary.E1; + + if ((quantifier == Quantifier.Forall && binary.Op == BinaryExpr.Opcode.And) || + (quantifier == Quantifier.Exists && binary.Op == BinaryExpr.Opcode.Or)) { + foreach (var e in BreakQuantifier(e0, quantifier)) { yield return e; } + foreach (var e in BreakQuantifier(e1, quantifier)) { yield return e; } + } else if (binary.Op == BinaryExpr.Opcode.Imp) { + if (quantifier == Quantifier.Forall) { + foreach (var e in BreakImplication(e0, e1, quantifier, expr.tok)) { yield return e; } + } else { + yield return new UnaryOpExpr(e1.tok, UnaryOpExpr.Opcode.Not, e1); // FIXME should be broken further + foreach (var e in BreakQuantifier(e1, quantifier)) { yield return e; } + } + } else { + yield return expr; + } + } + + internal static IEnumerable BreakImplication(Expression ante, Expression post, Quantifier quantifier, IToken tok) { // FIXME: should work for exists and && + foreach (var small_post in BreakQuantifier(post, quantifier)) { + var bin_post = small_post as BinaryExpr; + if (bin_post == null || bin_post.Op != BinaryExpr.Opcode.Imp) { + yield return new BinaryExpr(tok, BinaryExpr.Opcode.Imp, ante, small_post); + } else { // bin_post is an implication + var large_ante = new BinaryExpr(ante.tok, BinaryExpr.Opcode.And, ante, bin_post.E0); + foreach (var imp in BreakImplication(large_ante, bin_post.E1, quantifier, tok)) { + yield return imp; + } + } + } + } + + protected override void VisitOneExpr(Expression expr) { //FIXME: This doesn't save the rewritten quantifier + var forall = expr as ForallExpr; + var exists = expr as ExistsExpr; + + if (forall != null && TriggerUtils.NeedsAutoTriggers(forall)) { + var rew = BreakQuantifier(forall.LogicalBody(), Quantifier.Forall); + //Console.WriteLine("!!! {0} => {1}", Printer.ExprToString(expr), rew.MapConcat(Printer.ExprToString, " ||| ")); + } else if (exists != null && TriggerUtils.NeedsAutoTriggers(exists)) { + var rew = BreakQuantifier(exists.LogicalBody(), Quantifier.Exists); + //Console.WriteLine("!!! {0} => {1}", Printer.ExprToString(expr), rew.MapConcat(Printer.ExprToString, " ||| ")); + } + } + } +} diff --git a/Source/Dafny/Triggers/QuantifiersCollection.cs b/Source/Dafny/Triggers/QuantifiersCollection.cs new file mode 100644 index 00000000..3cbe3bd9 --- /dev/null +++ b/Source/Dafny/Triggers/QuantifiersCollection.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +//FIXME Generated triggers should be _triggers +//FIXME: When scoring, do not consider old(x) to be higher than x. + +namespace Microsoft.Dafny.Triggers { + class QuantifierWithTriggers { + internal QuantifierExpr quantifier; + internal List triggers; + + internal QuantifierWithTriggers(QuantifierExpr quantifier) { + this.quantifier = quantifier; + this.triggers = null; + } + + internal void TrimInvalidTriggers() { + triggers = triggers.Where(tr => tr.MentionsAll(quantifier.BoundVars)).ToList(); + } + + public bool QuantifierAlreadyHadTriggers { get { return !TriggerUtils.NeedsAutoTriggers(quantifier); } } + } + + class QuantifiersCollection { + readonly ErrorReporter reporter; + readonly List quantifiers; + + internal QuantifiersCollection(IEnumerable quantifiers, ErrorReporter reporter) { + this.reporter = reporter; + this.quantifiers = quantifiers.Select(q => new QuantifierWithTriggers(q)).ToList(); + } + + void ComputeTriggers() { + CollectAndShareTriggers(); + TrimInvalidTriggers(); + BuildDependenciesGraph(); + SuppressMatchingLoops(); + SelectTriggers(); + } + + void CollectAndShareTriggers() { + var pool = quantifiers.SelectMany(q => TriggersCollector.CollectTriggers(q.quantifier)); + var distinctPool = pool.Deduplicate((x, y) => ExprExtensions.ExpressionEq(x.Expr, y.Expr)); + var multiPool = TriggerUtils.AllNonEmptySubsets(distinctPool).Select(candidates => new MultiTriggerCandidate(candidates)).ToList(); + + foreach (var q in quantifiers) { + if (q.QuantifierAlreadyHadTriggers) { + reporter.Info(MessageSource.Resolver, q.quantifier.tok, "Not generating triggers for this quantifier."); //FIXME: no_trigger is passed down to Boogie + return; + } else { + q.triggers = multiPool; + } + } + } + + private void TrimInvalidTriggers() { + foreach (var q in quantifiers) { + q.TrimInvalidTriggers(); + } + } + + void BuildDependenciesGraph() { + //FIXME + } + + void SuppressMatchingLoops() { + //FIXME + } + + void SelectTriggers() { + //FIXME + } + + private void CommitOne(QuantifierWithTriggers q) { + foreach (var multiCandidate in q.triggers) { //TODO: error message for when no triggers found + q.quantifier.Attributes = new Attributes("trigger", multiCandidate.terms.Select(t => t.Expr).ToList(), q.quantifier.Attributes); + } + + + //TriggerUtils.DebugTriggers(" Final results:\n{0}", PickMultiTriggers(quantifier)); + + //var multi_candidates = PickMultiTriggers(quantifier); + + //if (multi_candidates.RejectedMultiCandidates.Any()) { + // var tooltip = TriggerUtils.JoinStringsWithHeader("Rejected: ", multi_candidates.RejectedMultiCandidates.Where(candidate => candidate.Tags != null) + // .Select(candidate => candidate.AsDafnyAttributeString(true, true))); + // reporter.Info(ErrorSource.Resolver, quantifier.tok, tooltip, quantifier.tok.val.Length); + //} + + //if (multi_candidates.FinalMultiCandidates.Any()) { + // var tooltip = JoinStringsWithHeader("Triggers: ", multi_candidates.FinalMultiCandidates.Select(multi_candidate => multi_candidate.AsDafnyAttributeString())); + // reporter.Info(ErrorSource.Resolver, quantifier.tok, tooltip, quantifier.tok.val.Length); + //} + + //string warning = multi_candidates.Warning(); + //if (warning != null) { + // // FIXME reenable Resolver.Warning(quantifier.tok, warning); + //} + } + + } +} diff --git a/Source/Dafny/Triggers/TriggerExtensions.cs b/Source/Dafny/Triggers/TriggerExtensions.cs new file mode 100644 index 00000000..7bebe1ac --- /dev/null +++ b/Source/Dafny/Triggers/TriggerExtensions.cs @@ -0,0 +1,489 @@ +#define THROW_UNSUPPORTED_COMPARISONS + +using Microsoft.Dafny; +using System; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.Linq; +using System.Text; + +namespace Microsoft.Dafny.Triggers { + internal static class DeduplicateExtension { + public static List Deduplicate(this IEnumerable seq, Func eq) { + List deduplicated = new List(); + + foreach (var elem in seq) { + if (!deduplicated.Any(other => eq(elem, other))) { + deduplicated.Add(elem); + } + } + + return deduplicated; + } + } + + internal static class ExprExtensions { + internal static IEnumerable AllSubExpressions(this Expression expr, bool strict = false) { + foreach (var subexpr in expr.SubExpressions) { + foreach (var r_subexpr in AllSubExpressions(subexpr, false)) { + yield return r_subexpr; + } + yield return subexpr; + } + + if (expr is StmtExpr) { + foreach (var r_subexpr in AllSubExpressions(((StmtExpr)expr).S, false)) { + yield return r_subexpr; + } + } + + if (!strict) { + yield return expr; + } + } + + internal static IEnumerable AllSubExpressions(this Statement stmt, bool strict = false) { + foreach (var subexpr in stmt.SubExpressions) { + foreach (var r_subexpr in AllSubExpressions(subexpr, false)) { + yield return r_subexpr; + } + yield return subexpr; + } + + foreach (var substmt in stmt.SubStatements) { + foreach (var r_subexpr in AllSubExpressions(substmt, false)) { + yield return r_subexpr; + } + } + } + + internal static bool ExpressionEq(this Expression expr1, Expression expr2) { + expr1 = expr1.Resolved; + expr2 = expr2.Resolved; + + return ShallowEq_Top(expr1, expr2) && TriggerUtils.SameLists(expr1.SubExpressions, expr2.SubExpressions, (e1, e2) => ExpressionEq(e1, e2)); + } + + internal static bool ExpressionEqModuloVariableNames(this Expression expr1, Expression expr2) { + expr1 = expr1.Resolved; + expr2 = expr2.Resolved; + + if (expr1 is IdentifierExpr) { + return expr2 is IdentifierExpr; + } + + return ShallowEq_Top(expr1, expr2) && TriggerUtils.SameLists(expr1.SubExpressions, expr2.SubExpressions, (e1, e2) => ExpressionEqModuloVariableNames(e1, e2)); + } + + private static bool MatchesTrigger(this Expression expr, Expression trigger, ISet holes, Dictionary bindings) { + expr = expr.Resolved; + trigger = trigger.Resolved; + + if (trigger is IdentifierExpr) { + var var = ((IdentifierExpr)trigger).Var; + + if (holes.Contains(var)) { + Expression existing_binding = null; + if (bindings.TryGetValue(var, out existing_binding)) { + return ExpressionEq(expr, existing_binding); + } else { + bindings[var] = expr; + return true; + } + } + } + + return ShallowEq_Top(expr, trigger) && TriggerUtils.SameLists(expr.SubExpressions, trigger.SubExpressions, (e1, e2) => MatchesTrigger(e1, e2, holes, bindings)); + } + + internal struct TriggerMatch { + internal Expression Expr; + internal Dictionary Bindings; + + internal bool CouldCauseLoops(IEnumerable candidates) { + // A match for a trigger in the body of a quantifier can be a problem if + // it yields to a matching loop: for example, f(x) is a bad trigger in + // forall x, y :: f(x) = f(f(x)) + // In general, any such match can lead to a loop, but two special cases + // will only lead to a finite number of instantiations: + // 1. The match equals one of the triggers in the set of triggers under + // consideration. For example, { f(x) } a bad trigger above, but the + // pair { f(x), f(f(x)) } is fine (instantiating won't yield new + // matches) + // 2. The match only differs from one of these triggers by variable + // names. This is a superset of the previous case. + var expr = Expr; + return !candidates.Any(c => c.Expr.ExpressionEqModuloVariableNames(expr)); + } + } + + private static TriggerMatch? MatchAgainst(this Expression expr, Expression trigger, ISet holes) { + var bindings = new Dictionary(); + return expr.MatchesTrigger(trigger, holes, bindings) ? new TriggerMatch { Expr = expr, Bindings = bindings } : (TriggerMatch?)null; + } + + internal static IEnumerable SubexpressionsMatchingTrigger(this QuantifierExpr quantifier, Expression trigger) { + return quantifier.Term.AllSubExpressions() + .Select(e => e.MatchAgainst(trigger, new HashSet(quantifier.BoundVars))) + .Where(e => e.HasValue).Select(e => e.Value); + } + + private static bool ShallowSameAttributes(Attributes attributes1, Attributes attributes2) { + return TriggerUtils.SameLists(attributes1.AsEnumerable(), attributes2.AsEnumerable(), ShallowSameSingleAttribute); + } + + private static bool ShallowSameSingleAttribute(Attributes arg1, Attributes arg2) { + return arg1.Name == arg2.Name; + } + + private static bool SameBoundVar(IVariable arg1, IVariable arg2) { + return arg1 == arg2 || + (arg1.Name == arg2.Name && + arg1.CompileName == arg2.CompileName && + arg1.DisplayName == arg2.DisplayName && + arg1.UniqueName == arg2.UniqueName && + arg1.IsGhost == arg2.IsGhost && + arg1.IsMutable == arg2.IsMutable); //FIXME compare types? + } + + /// + /// Compares two abstract syntax expressions, looking only at their direct members. Subexpressions and substatements are not compared. + /// + /// + internal static bool ShallowEq_Top(Expression expr1, Expression expr2) { + Contract.Requires(expr1 != null); + Contract.Requires(expr2 != null); + + // We never compare concrete expressions + Contract.Requires(!(expr1 is ConcreteSyntaxExpression)); + Contract.Requires(!(expr2 is ConcreteSyntaxExpression)); + + // CPC: Hey future editor: the following block of code is auto-generated. Just add your own cases at the end. + // This could be a visitor pattern, except I need to visit a pair of nodes. + // It could also be implemented in each individual class. I'd have a slight preference for that. + // This really just wants to use double dispatch. + if (expr1 is UnboxingCastExpr && expr2 is UnboxingCastExpr) { + return ShallowEq((UnboxingCastExpr)expr1, (UnboxingCastExpr)expr2); + } else if (expr1 is BoxingCastExpr && expr2 is BoxingCastExpr) { + return ShallowEq((BoxingCastExpr)expr1, (BoxingCastExpr)expr2); + } else if (expr1 is MatchExpr && expr2 is MatchExpr) { + return ShallowEq((MatchExpr)expr1, (MatchExpr)expr2); + } else if (expr1 is ITEExpr && expr2 is ITEExpr) { + return ShallowEq((ITEExpr)expr1, (ITEExpr)expr2); + } else if (expr1 is StmtExpr && expr2 is StmtExpr) { + return ShallowEq((StmtExpr)expr1, (StmtExpr)expr2); + } else if (expr1 is WildcardExpr && expr2 is WildcardExpr) { + return ShallowEq((WildcardExpr)expr1, (WildcardExpr)expr2); + } else if (expr1 is ComprehensionExpr && expr2 is ComprehensionExpr) { + return ShallowEq((ComprehensionExpr)expr1, (ComprehensionExpr)expr2); + } else if (expr1 is NamedExpr && expr2 is NamedExpr) { + return ShallowEq((NamedExpr)expr1, (NamedExpr)expr2); + } else if (expr1 is LetExpr && expr2 is LetExpr) { + return ShallowEq((LetExpr)expr1, (LetExpr)expr2); + } else if (expr1 is TernaryExpr && expr2 is TernaryExpr) { + return ShallowEq((TernaryExpr)expr1, (TernaryExpr)expr2); + } else if (expr1 is BinaryExpr && expr2 is BinaryExpr) { + return ShallowEq((BinaryExpr)expr1, (BinaryExpr)expr2); + } else if (expr1 is UnaryExpr && expr2 is UnaryExpr) { + return ShallowEq((UnaryExpr)expr1, (UnaryExpr)expr2); + } else if (expr1 is MultiSetFormingExpr && expr2 is MultiSetFormingExpr) { + return ShallowEq((MultiSetFormingExpr)expr1, (MultiSetFormingExpr)expr2); + } else if (expr1 is OldExpr && expr2 is OldExpr) { + return ShallowEq((OldExpr)expr1, (OldExpr)expr2); + } else if (expr1 is FunctionCallExpr && expr2 is FunctionCallExpr) { + return ShallowEq((FunctionCallExpr)expr1, (FunctionCallExpr)expr2); + } else if (expr1 is ApplyExpr && expr2 is ApplyExpr) { + return ShallowEq((ApplyExpr)expr1, (ApplyExpr)expr2); + } else if (expr1 is SeqUpdateExpr && expr2 is SeqUpdateExpr) { + return ShallowEq((SeqUpdateExpr)expr1, (SeqUpdateExpr)expr2); + } else if (expr1 is MultiSelectExpr && expr2 is MultiSelectExpr) { + return ShallowEq((MultiSelectExpr)expr1, (MultiSelectExpr)expr2); + } else if (expr1 is SeqSelectExpr && expr2 is SeqSelectExpr) { + return ShallowEq((SeqSelectExpr)expr1, (SeqSelectExpr)expr2); + } else if (expr1 is MemberSelectExpr && expr2 is MemberSelectExpr) { + return ShallowEq((MemberSelectExpr)expr1, (MemberSelectExpr)expr2); + } else if (expr1 is MapDisplayExpr && expr2 is MapDisplayExpr) { //Note: MapDisplayExpr is not a DisplayExpression + return ShallowEq((MapDisplayExpr)expr1, (MapDisplayExpr)expr2); + } else if (expr1 is DisplayExpression && expr2 is DisplayExpression) { + return ShallowEq((DisplayExpression)expr1, (DisplayExpression)expr2); + } else if (expr1 is IdentifierExpr && expr2 is IdentifierExpr) { + return ShallowEq((IdentifierExpr)expr1, (IdentifierExpr)expr2); + } else if (expr1 is ThisExpr && expr2 is ThisExpr) { + return ShallowEq((ThisExpr)expr1, (ThisExpr)expr2); + } else if (expr1 is DatatypeValue && expr2 is DatatypeValue) { + return ShallowEq((DatatypeValue)expr1, (DatatypeValue)expr2); + } else if (expr1 is LiteralExpr && expr2 is LiteralExpr) { + return ShallowEq((LiteralExpr)expr1, (LiteralExpr)expr2); + } else { + // If this assertion fail, then a new abstract AST node was probably introduced but not registered here. + Contract.Assert(expr1.GetType() != expr2.GetType()); + return false; + } + } + + private static bool ShallowEq(UnboxingCastExpr expr1, UnboxingCastExpr expr2) { + Contract.Requires(false); + throw new InvalidOperationException(); + } + + private static bool ShallowEq(BoxingCastExpr expr1, BoxingCastExpr expr2) { + return expr1.FromType == expr2.FromType && + expr1.ToType == expr2.ToType; + } + + private static bool ShallowEq(MatchExpr expr1, MatchExpr expr2) { + return true; + } + + private static bool ShallowEq(ITEExpr expr1, ITEExpr expr2) { + return true; + } + + private static bool ShallowEq(StmtExpr expr1, StmtExpr expr2) { +#if THROW_UNSUPPORTED_COMPARISONS + Contract.Assume(false); // This kind of expression never appears in a trigger + throw new NotImplementedException(); +#else + return expr1.S == expr2.S; +#endif + } + + private static bool ShallowEq(WildcardExpr expr1, WildcardExpr expr2) { + return true; + } + + private static bool ShallowEq(LambdaExpr expr1, LambdaExpr expr2) { +#if THROW_UNSUPPORTED_COMPARISONS + Contract.Assume(false); // This kind of expression never appears in a trigger + throw new NotImplementedException(); +#else + return false; +#endif + } + + private static bool ShallowEq(MapComprehension expr1, MapComprehension expr2) { + return expr1.Finite == expr2.Finite; + } + + private static bool ShallowEq(SetComprehension expr1, SetComprehension expr2) { + return expr1.TermIsImplicit == expr2.TermIsImplicit && //TODO + expr1.Finite == expr2.Finite; + } + + private static bool ShallowEq(ExistsExpr expr1, ExistsExpr expr2) { + return true; + } + + private static bool ShallowEq(ForallExpr expr1, ForallExpr expr2) { + return true; + } + + private static bool ShallowEq(QuantifierExpr expr1, QuantifierExpr expr2) { //FIXME are these TypeArgs still useful? + if (expr1.TypeArgs.Count != expr2.TypeArgs.Count || + !TriggerUtils.SameNullity(expr1.Range, expr2.Range)) { + return false; + } + + if (expr1 is ExistsExpr && expr2 is ExistsExpr) { + return ShallowEq((ExistsExpr)expr1, (ExistsExpr)expr2); + } else if (expr1 is ForallExpr && expr2 is ForallExpr) { + return ShallowEq((ForallExpr)expr1, (ForallExpr)expr2); + } else { + return false; + } + } + + private static bool ShallowEq(ComprehensionExpr expr1, ComprehensionExpr expr2) { + if (!TriggerUtils.SameLists(expr1.BoundVars, expr2.BoundVars, SameBoundVar) || + !ShallowSameAttributes(expr1.Attributes, expr2.Attributes) || + // Filled in during resolution: !SameLists(expr1.Bounds, expr2.Bounds, ReferenceCompare) || + // !SameLists(expr1.MissingBounds, expr2.MissingBounds, SameBoundVar) || + !TriggerUtils.SameNullity(expr1.Range, expr2.Range)) { //TODO Check + return false; + } + + if (expr1 is LambdaExpr && expr2 is LambdaExpr) { + return ShallowEq((LambdaExpr)expr1, (LambdaExpr)expr2); + } else if (expr1 is MapComprehension && expr2 is MapComprehension) { + return ShallowEq((MapComprehension)expr1, (MapComprehension)expr2); + } else if (expr1 is SetComprehension && expr2 is SetComprehension) { + return ShallowEq((SetComprehension)expr1, (SetComprehension)expr2); + } else if (expr1 is QuantifierExpr && expr2 is QuantifierExpr) { + return ShallowEq((QuantifierExpr)expr1, (QuantifierExpr)expr2); + } else { + return false; // ComprehensionExpr is abstract + } + } + + private static bool ShallowEq(NamedExpr expr1, NamedExpr expr2) { + return expr1.Name == expr2.Name && + TriggerUtils.SameNullity(expr1.Contract, expr2.Contract); + } + + private static bool ShallowEq(LetExpr expr1, LetExpr expr2) { + return expr1.Exact == expr2.Exact && + ShallowSameAttributes(expr1.Attributes, expr2.Attributes); + } + + private static bool ShallowEq(TernaryExpr expr1, TernaryExpr expr2) { + return expr1.Op == expr2.Op; + } + + private static bool ShallowEq(BinaryExpr expr1, BinaryExpr expr2) { + Contract.Requires(expr1.ResolvedOp != BinaryExpr.ResolvedOpcode.YetUndetermined); + Contract.Requires(expr2.ResolvedOp != BinaryExpr.ResolvedOpcode.YetUndetermined); + return expr1.ResolvedOp == expr2.ResolvedOp; + } + + private static bool ShallowEq(ConversionExpr expr1, ConversionExpr expr2) { + return expr1.Type == expr2.Type; //TODO equality on types? + } + + private static bool ShallowEq(UnaryOpExpr expr1, UnaryOpExpr expr2) { + return expr1.Op == expr2.Op; + } + + private static bool ShallowEq(UnaryExpr expr1, UnaryExpr expr2) { + if (expr1 is ConversionExpr && expr2 is ConversionExpr) { + return ShallowEq((ConversionExpr)expr1, (ConversionExpr)expr2); + } else if (expr1 is UnaryOpExpr && expr2 is UnaryOpExpr) { + return ShallowEq((UnaryOpExpr)expr1, (UnaryOpExpr)expr2); + } else { + return false; // UnaryExpr is abstract + } + } + + private static bool ShallowEq(MultiSetFormingExpr expr1, MultiSetFormingExpr expr2) { + return true; + } + + private static bool ShallowEq(OldExpr expr1, OldExpr expr2) { + return true; + } + + private static bool ShallowEq(FunctionCallExpr expr1, FunctionCallExpr expr2) { + return expr1.Name == expr2.Name && + expr1.CoCall == expr2.CoCall && //TODO + expr1.Function == expr2.Function; // TODO TypeArgumentSubstitutions? + } + + private static bool ShallowEq(ApplyExpr expr1, ApplyExpr expr2) { + return true; + } + + private static bool ShallowEq(SeqUpdateExpr expr1, SeqUpdateExpr expr2) { + Contract.Requires(expr1.ResolvedUpdateExpr != null && expr2.ResolvedUpdateExpr != null); + return true; + } + + private static bool ShallowEq(MultiSelectExpr expr1, MultiSelectExpr expr2) { + return true; + } + + private static bool ShallowEq(SeqSelectExpr expr1, SeqSelectExpr expr2) { + return expr1.SelectOne == expr2.SelectOne && + TriggerUtils.SameNullity(expr1.Seq, expr2.Seq) && + TriggerUtils.SameNullity(expr1.E0, expr2.E0) && + TriggerUtils.SameNullity(expr1.E1, expr2.E1); + } + + private static bool ShallowEq(MemberSelectExpr expr1, MemberSelectExpr expr2) { + return expr1.MemberName == expr2.MemberName && + expr1.Member == expr2.Member && + TriggerUtils.SameLists(expr1.TypeApplication, expr2.TypeApplication, Microsoft.Dafny.Type.Equals); + } + + private static bool ShallowEq(SeqDisplayExpr expr1, SeqDisplayExpr expr2) { + return true; + } + + private static bool ShallowEq(MapDisplayExpr expr1, MapDisplayExpr expr2) { + return expr1.Finite == expr2.Finite; + } + + private static bool ShallowEq(MultiSetDisplayExpr expr1, MultiSetDisplayExpr expr2) { + return true; + } + + private static bool ShallowEq(SetDisplayExpr expr1, SetDisplayExpr expr2) { + return expr1.Finite == expr2.Finite; + } + + private static bool ShallowEq(DisplayExpression expr1, DisplayExpression expr2) { + if (expr1 is SeqDisplayExpr && expr2 is SeqDisplayExpr) { + return ShallowEq((SeqDisplayExpr)expr1, (SeqDisplayExpr)expr2); + } else if (expr1 is MultiSetDisplayExpr && expr2 is MultiSetDisplayExpr) { + return ShallowEq((MultiSetDisplayExpr)expr1, (MultiSetDisplayExpr)expr2); + } else if (expr1 is SetDisplayExpr && expr2 is SetDisplayExpr) { + return ShallowEq((SetDisplayExpr)expr1, (SetDisplayExpr)expr2); + } else { + return false; + } + } + + private static bool ShallowEq(AutoGhostIdentifierExpr expr1, AutoGhostIdentifierExpr expr2) { + return true; + } + + private static bool ShallowEq(IdentifierExpr expr1, IdentifierExpr expr2) { + if (expr1.Name != expr2.Name || + expr1.Var != expr2.Var) { + return false; + } + + if (expr1 is AutoGhostIdentifierExpr && expr2 is AutoGhostIdentifierExpr) { + return ShallowEq((AutoGhostIdentifierExpr)expr1, (AutoGhostIdentifierExpr)expr2); + } else { + return true; + } + } + + private static bool ShallowEq(ImplicitThisExpr expr1, ImplicitThisExpr expr2) { + return true; + } + + private static bool ShallowEq(ThisExpr expr1, ThisExpr expr2) { + if (expr1 is ImplicitThisExpr && expr2 is ImplicitThisExpr) { + return ShallowEq((ImplicitThisExpr)expr1, (ImplicitThisExpr)expr2); + } else { + return (expr1.GetType() == expr2.GetType()); // LiteralExpr is not abstract + } + } + + private static bool ShallowEq(DatatypeValue expr1, DatatypeValue expr2) { + return // Implied by Ctor equality: expr1.DatatypeName == expr2.DatatypeName && + // Implied by Ctor equality: expr1.MemberName == expr2.MemberName && + expr1.Ctor == expr2.Ctor && + // Contextual information: expr1.IsCoCall == expr2.IsCoCall && + TriggerUtils.SameLists(expr1.InferredTypeArgs, expr2.InferredTypeArgs, Microsoft.Dafny.Type.Equals); + } + + private static bool ShallowEq(StringLiteralExpr expr1, StringLiteralExpr expr2) { + return true; + } + + private static bool ShallowEq(CharLiteralExpr expr1, CharLiteralExpr expr2) { + return true; + } + + private static bool ShallowEq(StaticReceiverExpr expr1, StaticReceiverExpr expr2) { + return true; + } + + private static bool ShallowEq(LiteralExpr expr1, LiteralExpr expr2) { + if (expr1.Value != expr2.Value) { + return false; + } + + if (expr1 is StringLiteralExpr && expr2 is StringLiteralExpr) { + return ShallowEq((StringLiteralExpr)expr1, (StringLiteralExpr)expr2); + } else if (expr1 is CharLiteralExpr && expr2 is CharLiteralExpr) { + return ShallowEq((CharLiteralExpr)expr1, (CharLiteralExpr)expr2); + } else if (expr1 is StaticReceiverExpr && expr2 is StaticReceiverExpr) { + return ShallowEq((StaticReceiverExpr)expr1, (StaticReceiverExpr)expr2); + } else { + return (expr1.GetType() == expr2.GetType()); // LiteralExpr is not abstract + } + } + } +} diff --git a/Source/Dafny/Triggers/TriggerGenerator.cs b/Source/Dafny/Triggers/TriggerGenerator.cs new file mode 100644 index 00000000..de4b212b --- /dev/null +++ b/Source/Dafny/Triggers/TriggerGenerator.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Microsoft.Boogie; +using System.Collections.ObjectModel; +using System.Diagnostics.Contracts; + +namespace Microsoft.Dafny.Triggers { //FIXME rename this file + internal class QuantifierCollectionsFinder : TopDownVisitor { + readonly ErrorReporter reporter; + internal List quantifierCollections = new List(); + + public QuantifierCollectionsFinder(ErrorReporter reporter) { + Contract.Requires(reporter != null); + this.reporter = reporter; + } + + protected override bool VisitOneExpr(Expression expr, ref object st) { + var quantifier = expr as QuantifierExpr; + if (quantifier != null) { + quantifierCollections.Add(new QuantifiersCollection(Enumerable.Repeat(quantifier, 1), reporter)); + } //FIXME handle the case of groups of quantifiers resulting from a split + + return true; + } + } +} diff --git a/Source/Dafny/Triggers/TriggerUtils.cs b/Source/Dafny/Triggers/TriggerUtils.cs new file mode 100644 index 00000000..5a118a2f --- /dev/null +++ b/Source/Dafny/Triggers/TriggerUtils.cs @@ -0,0 +1,94 @@ +#define DEBUG_AUTO_TRIGGERS + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.Contracts; +using System.Linq; +using System.Text; + +namespace Microsoft.Dafny.Triggers { + class TriggerUtils { + internal static List CopyAndAdd(List seq, T elem) { + var copy = new List(seq); + copy.Add(elem); + return copy; + } + + internal static IEnumerable> AllSubsets(IList source, int offset) { + if (offset >= source.Count) { + yield return new List(); + yield break; + } + + foreach (var subset in AllSubsets(source, offset + 1)) { + yield return CopyAndAdd(subset, source[offset]); + yield return new List(subset); + } + } + + internal static IEnumerable> AllNonEmptySubsets(IEnumerable source) { + List all = new List(source); + foreach (var subset in AllSubsets(all, 0)) { + if (subset.Count > 0) { + yield return subset; + } + } + } + + internal static List MergeAlterFirst(List a, List b) { + Contract.Requires(a != null); + Contract.Requires(b != null); + a.AddRange(b); + return a; + } + + internal static ISet MergeAlterFirst(ISet a, ISet b) { + Contract.Requires(a != null); + Contract.Requires(b != null); + a.UnionWith(b); + return a; + } + + internal static bool SameLists(IEnumerable list1, IEnumerable list2, Func comparer) { + if (ReferenceEquals(list1, list2)) { + return true; + } else if ((list1 == null) != (list2 == null)) { + return false; + } + + var it1 = list1.GetEnumerator(); + var it2 = list2.GetEnumerator(); + bool it1_has, it2_has; + bool acc = true; + + do { + it1_has = it1.MoveNext(); + it2_has = it2.MoveNext(); + + if (it1_has == true && it2_has == true) { + acc = acc && comparer(it1.Current, it2.Current); + } + } while (it1_has && it2_has); + + return it1_has == it2_has && acc; + } + + internal static bool SameNullity(T x1, T x2) where T : class { + return (x1 == null) == (x2 == null); + } + + internal string JoinStringsWithHeader(string header, IEnumerable lines) { + return header + String.Join(Environment.NewLine + new String(' ', header.Length), lines); + } + + [Conditional("DEBUG_AUTO_TRIGGERS")] + internal static void DebugTriggers(string format, params object[] more) { + Console.Error.WriteLine(format, more); + } + + internal static bool NeedsAutoTriggers(QuantifierExpr quantifier) { + return quantifier.Attributes.AsEnumerable().All(aa => aa.Name != "trigger" && aa.Name != "no_trigger"); + } + } +} diff --git a/Source/Dafny/Triggers/TriggersCollector.cs b/Source/Dafny/Triggers/TriggersCollector.cs new file mode 100644 index 00000000..912a661c --- /dev/null +++ b/Source/Dafny/Triggers/TriggersCollector.cs @@ -0,0 +1,256 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Microsoft.Boogie; +using System.Diagnostics.Contracts; +using System.Diagnostics; + +namespace Microsoft.Dafny.Triggers { + struct TriggerCandidate { + internal Expression Expr { get; set; } + internal ISet Variables { get; set; } + + public override string ToString() { + return Printer.ExprToString(Expr); + } + } + + class MultiTriggerCandidate { + internal List terms { get; set; } + + internal MultiTriggerCandidate(List candidates) { + this.terms = candidates; + } + + internal bool MentionsAll(List vars) { + return vars.All(x => terms.Any(candidate => candidate.Variables.Contains(x))); + } + + public override string ToString() { + return String.Join(", ", terms); + } + + public String AsDafnyAttributeString(bool wrap = true, bool includeTags = false) { + var repr = terms.MapConcat(t => Printer.ExprToString(t.Expr), ", "); + if (wrap) { + repr = "{:trigger " + repr + "}"; + } + return repr; + } + } + + class TriggerAnnotation { + internal bool IsTriggerKiller; + internal ISet Variables; + internal readonly List PrivateTerms; + internal readonly List ExportedTerms; + + internal TriggerAnnotation(bool IsTriggerKiller, IEnumerable Variables, + IEnumerable AllCandidates, IEnumerable PrivateCandidates = null) { + this.IsTriggerKiller = IsTriggerKiller; + this.Variables = new HashSet(Variables); + + this.PrivateTerms = new List(PrivateCandidates == null ? Enumerable.Empty() : PrivateCandidates); + this.ExportedTerms = new List(AllCandidates == null ? Enumerable.Empty() : AllCandidates.Except(this.PrivateTerms)); + } + + public override string ToString() { + StringBuilder sb = new StringBuilder(); + string indent = " {0}", nindent = "\n - {0}", subindent = "\n * {0}"; + + sb.AppendFormat(indent, IsTriggerKiller); + + sb.AppendFormat(nindent, "Variables:"); + foreach (var bv in Variables) { + sb.AppendFormat(subindent, bv.Name); + } + + sb.AppendFormat(nindent, "Exported candidates:"); + foreach (var candidate in ExportedTerms) { + sb.AppendFormat(subindent, candidate); + } + + if (PrivateTerms.Any()) { + sb.AppendFormat(nindent, "Private candidates:"); + foreach (var candidate in PrivateTerms) { + sb.AppendFormat(subindent, candidate); + } + } + + return sb.ToString(); + } + } + + public class TriggersCollector { + Dictionary cache; + + private static TriggersCollector instance = new TriggersCollector(); + + private TriggersCollector() { + this.cache = new Dictionary(); + } + + private T ReduceAnnotatedSubExpressions(Expression expr, T seed, Func map, Func reduce) { + return expr.SubExpressions.Select(e => map(Annotate(e))) + .Aggregate(seed, (acc, e) => reduce(acc, e)); + } + + private List CollectExportedCandidates(Expression expr) { + return ReduceAnnotatedSubExpressions>(expr, new List(), a => a.ExportedTerms, TriggerUtils.MergeAlterFirst); + } + + private ISet CollectVariables(Expression expr) { + return ReduceAnnotatedSubExpressions(expr, new HashSet(), a => a.Variables, TriggerUtils.MergeAlterFirst); + } + + private bool CollectIsKiller(Expression expr) { + return ReduceAnnotatedSubExpressions(expr, false, a => a.IsTriggerKiller, (a, b) => a || b); + } + + private IEnumerable OnlyPrivateCandidates(List candidates, IEnumerable privateVars) { + return candidates.Where(c => privateVars.Intersect(c.Variables).Any()); //TODO Check perf + } + + private TriggerAnnotation Annotate(Expression expr) { + TriggerAnnotation cached; + if (cache.TryGetValue(expr, out cached)) { + return cached; + } + + expr.SubExpressions.Iter(e => Annotate(e)); + + TriggerAnnotation annotation; // TODO: Using ApplySuffix fixes the unresolved members problem in GenericSort + if (expr is FunctionCallExpr || expr is SeqSelectExpr || expr is MemberSelectExpr || expr is OldExpr || + (expr is UnaryOpExpr && (((UnaryOpExpr)expr).Op == UnaryOpExpr.Opcode.Cardinality)) || // FIXME || ((UnaryOpExpr)expr).Op == UnaryOpExpr.Opcode.Fresh doesn't work, as fresh is a pretty tricky predicate when it's not about datatypes. See translator.cs:10944 + (expr is BinaryExpr && (((BinaryExpr)expr).Op == BinaryExpr.Opcode.NotIn || ((BinaryExpr)expr).Op == BinaryExpr.Opcode.In))) { + annotation = AnnotatePotentialCandidate(expr); + } else if (expr is QuantifierExpr) { + annotation = AnnotateQuantifier((QuantifierExpr)expr); + } else if (expr is LetExpr) { + annotation = AnnotateLetExpr((LetExpr)expr); + } else if (expr is IdentifierExpr) { + annotation = AnnotateIdentifier((IdentifierExpr)expr); + } else if (expr is ApplySuffix) { + annotation = AnnotateApplySuffix((ApplySuffix)expr); + } else if (expr is ConcreteSyntaxExpression || + expr is LiteralExpr || + expr is OldExpr || + expr is ThisExpr || + expr is BoxingCastExpr || + expr is DatatypeValue || + expr is SeqDisplayExpr) { //FIXME what abvout other display expressions? + annotation = AnnotateOther(expr, false); + } else { + annotation = AnnotateOther(expr, true); + } + + TriggerUtils.DebugTriggers("{0} ({1})\n{2}", Printer.ExprToString(expr), expr.GetType(), annotation); + cache[expr] = annotation; + return annotation; + } + + private BinaryExpr.ResolvedOpcode RemoveNotInBinaryExprIn(BinaryExpr.ResolvedOpcode opcode) { + switch (opcode) { + case BinaryExpr.ResolvedOpcode.NotInMap: + return BinaryExpr.ResolvedOpcode.InMap; + case BinaryExpr.ResolvedOpcode.NotInSet: + return BinaryExpr.ResolvedOpcode.InSet; + case BinaryExpr.ResolvedOpcode.NotInSeq: + return BinaryExpr.ResolvedOpcode.InSeq; + case BinaryExpr.ResolvedOpcode.NotInMultiSet: + return BinaryExpr.ResolvedOpcode.InMultiSet; + } + + Contract.Assert(false); + throw new ArgumentException(); + } + + private Expression CleanupExpr(Expression expr, out bool isKiller) { + isKiller = false; + + if (!(expr is BinaryExpr)) { + return expr; + } + + var bexpr = expr as BinaryExpr; + + BinaryExpr new_expr = bexpr; + if (bexpr.Op == BinaryExpr.Opcode.NotIn) { + new_expr = new BinaryExpr(bexpr.tok, BinaryExpr.Opcode.In, bexpr.E0, bexpr.E1); + new_expr.ResolvedOp = RemoveNotInBinaryExprIn(bexpr.ResolvedOp); + new_expr.Type = bexpr.Type; + } + + Expression returned_expr = new_expr; + if (new_expr.ResolvedOp == BinaryExpr.ResolvedOpcode.InMultiSet) { + returned_expr = new SeqSelectExpr(new_expr.tok, true, new_expr.E1, new_expr.E0, null); + returned_expr.Type = bexpr.Type; + isKiller = true; // [a in s] becomes [s[a] > 0], which is a trigger killer + } + + return returned_expr; + } + + private TriggerAnnotation AnnotatePotentialCandidate(Expression expr) { + bool expr_is_killer = false; + var new_expr = CleanupExpr(expr, out expr_is_killer); + var new_candidate = new TriggerCandidate { Expr = new_expr, Variables = CollectVariables(expr) }; + + List collected_candidates = CollectExportedCandidates(expr); + var children_contain_killers = CollectIsKiller(expr); + + if (!children_contain_killers) { + // Add only if the children are not killers; the head has been cleaned up into non-killer form + collected_candidates.Add(new_candidate); + } + + // This new node is a killer if its children were killers, or if it's non-cleaned-up head is a killer + return new TriggerAnnotation(children_contain_killers || expr_is_killer, new_candidate.Variables, collected_candidates); + } + + private TriggerAnnotation AnnotateApplySuffix(ApplySuffix expr) { + // This is a bit tricky. A funcall node is generally meaningful as a trigger candidate, + // but when it's part of an ApplySuffix the function call itself may not resolve properly + // when the second round of resolving is done after modules are duplicated. + // Thus first we annotate expr and create a trigger candidate, and then we remove the + // candidate matching its direct subexpression if needed. Note that function calls are not the + // only possible child here; there can be DatatypeValue nodes, for example (see vstte2012/Combinators.dfy). + var annotation = AnnotatePotentialCandidate(expr); + // Comparing by reference is fine here. Using sets could yield a small speedup + annotation.ExportedTerms.RemoveAll(candidate => expr.SubExpressions.Contains(candidate.Expr)); + return annotation; + } + + private TriggerAnnotation AnnotateQuantifierOrLetExpr(Expression expr, IEnumerable boundVars) { + var candidates = CollectExportedCandidates(expr); + return new TriggerAnnotation(true, CollectVariables(expr), candidates, OnlyPrivateCandidates(candidates, boundVars)); + } + + private TriggerAnnotation AnnotateQuantifier(QuantifierExpr expr) { + return AnnotateQuantifierOrLetExpr(expr, expr.BoundVars); + } + + private TriggerAnnotation AnnotateLetExpr(LetExpr expr) { + return AnnotateQuantifierOrLetExpr(expr, expr.BoundVars); + } + + private TriggerAnnotation AnnotateIdentifier(IdentifierExpr expr) { + return new TriggerAnnotation(false, Enumerable.Repeat(expr.Var, 1), null); + } + + private TriggerAnnotation AnnotateOther(Expression expr, bool isTriggerKiller) { + return new TriggerAnnotation(isTriggerKiller || CollectIsKiller(expr), CollectVariables(expr), CollectExportedCandidates(expr)); + } + + // FIXME document that this will contain duplicates + internal static List CollectTriggers(QuantifierExpr quantifier) { + // TODO could check for existing triggers and return that instead, but that require a bit of work to extract the expressions + return instance.Annotate(quantifier).PrivateTerms; + } + + internal static bool IsTriggerKiller(Expression expr) { + return instance.Annotate(expr).IsTriggerKiller; + } + } +} diff --git a/Test/dafny0/SeqFromArray.dfy.expect b/Test/dafny0/SeqFromArray.dfy.expect index af845d3e..5395e298 100644 --- a/Test/dafny0/SeqFromArray.dfy.expect +++ b/Test/dafny0/SeqFromArray.dfy.expect @@ -1,3 +1,6 @@ +SeqFromArray.dfy(56,13): Warning: (!) No terms found to trigger on. +SeqFromArray.dfy(76,17): Warning: (!) No terms found to trigger on. +SeqFromArray.dfy(82,17): Warning: (!) No terms found to trigger on. Dafny program verifier finished with 10 verified, 0 errors Program compiled successfully -- cgit v1.2.3 From 108e634af783601c60555c2e8e75775c3b4041ed Mon Sep 17 00:00:00 2001 From: Clément Pit--Claudel Date: Tue, 18 Aug 2015 08:47:40 -0700 Subject: Small cleanups, fixes, and refactorings In particular, start detecting loops between terms that don't look like each other at the Dafny level, such as {a[x]} and {x in a} (when a is a multiset) --- Source/Dafny/DafnyPipeline.csproj | 2 +- Source/Dafny/Rewriter.cs | 2 +- Source/Dafny/Triggers/QuantifiersCollection.cs | 8 ++-- Source/Dafny/Triggers/QuantifiersCollector.cs | 33 +++++++++++++++ Source/Dafny/Triggers/TriggerExtensions.cs | 15 ++++--- Source/Dafny/Triggers/TriggerGenerator.cs | 32 --------------- Source/Dafny/Triggers/TriggerUtils.cs | 56 ++++++++++++++++++++++++- Source/Dafny/Triggers/TriggersCollector.cs | 57 ++++---------------------- 8 files changed, 111 insertions(+), 94 deletions(-) create mode 100644 Source/Dafny/Triggers/QuantifiersCollector.cs delete mode 100644 Source/Dafny/Triggers/TriggerGenerator.cs (limited to 'Source/Dafny/DafnyPipeline.csproj') diff --git a/Source/Dafny/DafnyPipeline.csproj b/Source/Dafny/DafnyPipeline.csproj index 5a824c36..13a1e53e 100644 --- a/Source/Dafny/DafnyPipeline.csproj +++ b/Source/Dafny/DafnyPipeline.csproj @@ -147,7 +147,7 @@ - + diff --git a/Source/Dafny/Rewriter.cs b/Source/Dafny/Rewriter.cs index 2c00e203..b6409b96 100644 --- a/Source/Dafny/Rewriter.cs +++ b/Source/Dafny/Rewriter.cs @@ -44,7 +44,7 @@ namespace Microsoft.Dafny } internal override void PostCyclicityResolve(ModuleDefinition m) { - var finder = new Triggers.QuantifierCollectionsFinder(reporter); + var finder = new Triggers.QuantifierCollector(reporter); foreach (var decl in ModuleDefinition.AllCallables(m.TopLevelDecls)) { if (decl is Function) { diff --git a/Source/Dafny/Triggers/QuantifiersCollection.cs b/Source/Dafny/Triggers/QuantifiersCollection.cs index cbc212d2..01bceeb7 100644 --- a/Source/Dafny/Triggers/QuantifiersCollection.cs +++ b/Source/Dafny/Triggers/QuantifiersCollection.cs @@ -17,7 +17,7 @@ namespace Microsoft.Dafny.Triggers { internal List Candidates; internal List RejectedCandidates; - internal bool AllowsLoops { get { return quantifier.Attributes.AsEnumerable().Any(a => a.Name == "loop"); } } + internal bool AllowsLoops { get { return TriggerUtils.AllowsMatchingLoops(quantifier); } } internal bool CouldSuppressLoops { get; set; } internal QuantifierWithTriggers(QuantifierExpr quantifier) { @@ -65,8 +65,8 @@ namespace Microsoft.Dafny.Triggers { var multiPool = TriggerUtils.AllNonEmptySubsets(distinctPool, SubsetGenerationPredicate).Select(candidates => new TriggerCandidate(candidates)).ToList(); foreach (var q in quantifiers) { - q.CandidateTerms = distinctPool; - q.Candidates = multiPool; + q.CandidateTerms = distinctPool; //Candidate terms are immutable: no copy needed + q.Candidates = multiPool.Select(candidate => new TriggerCandidate(candidate)).ToList(); } } @@ -116,7 +116,7 @@ namespace Microsoft.Dafny.Triggers { c => !loopingSubterms[c].Any(), c => { looping.Add(c); - c.Annotation = "loop with " + loopingSubterms[c].MapConcat(t => Printer.ExprToString(t.Expr), ", "); + c.Annotation = "loops with " + loopingSubterms[c].MapConcat(t => Printer.ExprToString(t.Expr), ", "); }).ToList(); q.CouldSuppressLoops = safe.Count > 0; diff --git a/Source/Dafny/Triggers/QuantifiersCollector.cs b/Source/Dafny/Triggers/QuantifiersCollector.cs new file mode 100644 index 00000000..a43aae7a --- /dev/null +++ b/Source/Dafny/Triggers/QuantifiersCollector.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Microsoft.Boogie; +using System.Collections.ObjectModel; +using System.Diagnostics.Contracts; + +namespace Microsoft.Dafny.Triggers { //FIXME rename this file + internal class QuantifierCollector : TopDownVisitor { + readonly ErrorReporter reporter; + internal List quantifierCollections = new List(); + + public QuantifierCollector(ErrorReporter reporter) { + Contract.Requires(reporter != null); + this.reporter = reporter; + } + + protected override bool VisitOneExpr(Expression expr, ref object st) { + var quantifier = expr as QuantifierExpr; + if (quantifier != null) { + if (quantifier.SplitQuantifier != null) { + var collection = quantifier.SplitQuantifier.Select(q => q as QuantifierExpr).Where(q => q != null); + quantifierCollections.Add(new QuantifiersCollection(collection, reporter)); + return false; + } else { + quantifierCollections.Add(new QuantifiersCollection(Enumerable.Repeat(quantifier, 1), reporter)); + } + } + return true; + } + } +} diff --git a/Source/Dafny/Triggers/TriggerExtensions.cs b/Source/Dafny/Triggers/TriggerExtensions.cs index 9fbc8a8a..0a0ad547 100644 --- a/Source/Dafny/Triggers/TriggerExtensions.cs +++ b/Source/Dafny/Triggers/TriggerExtensions.cs @@ -110,14 +110,18 @@ namespace Microsoft.Dafny.Triggers { return ShallowEq_Top(expr, trigger) && TriggerUtils.SameLists(expr.SubExpressions, trigger.SubExpressions, (e1, e2) => MatchesTrigger(e1, e2, holes, bindings)); } - private static TriggerMatch? MatchAgainst(this Expression expr, Expression trigger, ISet holes) { + private static TriggerMatch? MatchAgainst(this Expression expr, Expression trigger, IEnumerable holes) { var bindings = new Dictionary(); - return expr.MatchesTrigger(trigger, holes, bindings) ? new TriggerMatch { Expr = expr, Bindings = bindings } : (TriggerMatch?)null; + if (expr.MatchesTrigger(trigger, new HashSet(holes), bindings)) { + return new TriggerMatch { Expr = expr, Bindings = bindings }; + } else { + return null; + } } internal static IEnumerable SubexpressionsMatchingTrigger(this QuantifierExpr quantifier, Expression trigger) { return quantifier.Term.AllSubExpressions() - .Select(e => e.MatchAgainst(trigger, new HashSet(quantifier.BoundVars))) + .Select(e => TriggerUtils.CleanupExprForInclusionInTrigger(e).MatchAgainst(trigger, quantifier.BoundVars)) .Where(e => e.HasValue).Select(e => e.Value); } @@ -136,7 +140,8 @@ namespace Microsoft.Dafny.Triggers { arg1.DisplayName == arg2.DisplayName && arg1.UniqueName == arg2.UniqueName && arg1.IsGhost == arg2.IsGhost && - arg1.IsMutable == arg2.IsMutable); //FIXME compare types? + arg1.IsMutable == arg2.IsMutable && + ((arg1.Type == null && arg2.Type == null) || arg1.Type.Equals(arg2.Type))); } /// @@ -271,7 +276,7 @@ namespace Microsoft.Dafny.Triggers { return true; } - private static bool ShallowEq(QuantifierExpr expr1, QuantifierExpr expr2) { //FIXME are these TypeArgs still useful? + private static bool ShallowEq(QuantifierExpr expr1, QuantifierExpr expr2) { if (!TriggerUtils.SameNullity(expr1.SplitQuantifier, expr2.SplitQuantifier)) { return false; } diff --git a/Source/Dafny/Triggers/TriggerGenerator.cs b/Source/Dafny/Triggers/TriggerGenerator.cs deleted file mode 100644 index e218ad7b..00000000 --- a/Source/Dafny/Triggers/TriggerGenerator.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Microsoft.Boogie; -using System.Collections.ObjectModel; -using System.Diagnostics.Contracts; - -namespace Microsoft.Dafny.Triggers { //FIXME rename this file - internal class QuantifierCollectionsFinder : TopDownVisitor { - readonly ErrorReporter reporter; - internal List quantifierCollections = new List(); - - public QuantifierCollectionsFinder(ErrorReporter reporter) { - Contract.Requires(reporter != null); - this.reporter = reporter; - } - - protected override bool VisitOneExpr(Expression expr, ref object st) { - var quantifier = expr as QuantifierExpr; - if (quantifier != null) { - if (quantifier.SplitQuantifier != null) { - var collection = quantifier.SplitQuantifier.Select(q => q as QuantifierExpr).Where(q => q != null); - quantifierCollections.Add(new QuantifiersCollection(collection, reporter)); - } else { - quantifierCollections.Add(new QuantifiersCollection(Enumerable.Repeat(quantifier, 1), reporter)); - } - } - return true; - } - } -} diff --git a/Source/Dafny/Triggers/TriggerUtils.cs b/Source/Dafny/Triggers/TriggerUtils.cs index 6c6eede2..9ebcf846 100644 --- a/Source/Dafny/Triggers/TriggerUtils.cs +++ b/Source/Dafny/Triggers/TriggerUtils.cs @@ -100,9 +100,63 @@ namespace Microsoft.Dafny.Triggers { Console.Error.WriteLine(format, more); } + internal static bool AllowsMatchingLoops(QuantifierExpr quantifier) { + Contract.Requires(quantifier.SplitQuantifier == null); // Don't call this on a quantifier with a Split clause: it's not a real quantifier + return Attributes.Contains(quantifier.Attributes, "matchingloop"); + } + internal static bool NeedsAutoTriggers(QuantifierExpr quantifier) { Contract.Requires(quantifier.SplitQuantifier == null); // Don't call this on a quantifier with a Split clause: it's not a real quantifier - return quantifier.Attributes.AsEnumerable().All(aa => aa.Name != "trigger" && aa.Name != "no_trigger"); + bool wantsAutoTriggers = true; + return !Attributes.Contains(quantifier.Attributes, "trigger") && + (!Attributes.ContainsBool(quantifier.Attributes, "autotriggers", ref wantsAutoTriggers) || wantsAutoTriggers); + } + + internal static BinaryExpr.ResolvedOpcode RemoveNotInBinaryExprIn(BinaryExpr.ResolvedOpcode opcode) { + switch (opcode) { + case BinaryExpr.ResolvedOpcode.NotInMap: + return BinaryExpr.ResolvedOpcode.InMap; + case BinaryExpr.ResolvedOpcode.NotInSet: + return BinaryExpr.ResolvedOpcode.InSet; + case BinaryExpr.ResolvedOpcode.NotInSeq: + return BinaryExpr.ResolvedOpcode.InSeq; + case BinaryExpr.ResolvedOpcode.NotInMultiSet: + return BinaryExpr.ResolvedOpcode.InMultiSet; + } + + Contract.Assert(false); + throw new ArgumentException(); + } + + internal static Expression CleanupExprForInclusionInTrigger(Expression expr, out bool isKiller) { + isKiller = false; + + if (!(expr is BinaryExpr)) { + return expr; + } + + var bexpr = expr as BinaryExpr; + + BinaryExpr new_expr = bexpr; + if (bexpr.Op == BinaryExpr.Opcode.NotIn) { + new_expr = new BinaryExpr(bexpr.tok, BinaryExpr.Opcode.In, bexpr.E0, bexpr.E1); + new_expr.ResolvedOp = RemoveNotInBinaryExprIn(bexpr.ResolvedOp); + new_expr.Type = bexpr.Type; + } + + Expression returned_expr = new_expr; + if (new_expr.ResolvedOp == BinaryExpr.ResolvedOpcode.InMultiSet) { + returned_expr = new SeqSelectExpr(new_expr.tok, true, new_expr.E1, new_expr.E0, null); + returned_expr.Type = bexpr.Type; + isKiller = true; // [a in s] becomes [s[a] > 0], which is a trigger killer + } + + return returned_expr; + } + + internal static Expression CleanupExprForInclusionInTrigger(Expression expr) { + bool _; + return CleanupExprForInclusionInTrigger(expr, out _); } } } diff --git a/Source/Dafny/Triggers/TriggersCollector.cs b/Source/Dafny/Triggers/TriggersCollector.cs index 9f721d9a..221a4255 100644 --- a/Source/Dafny/Triggers/TriggersCollector.cs +++ b/Source/Dafny/Triggers/TriggersCollector.cs @@ -9,10 +9,11 @@ using System.Diagnostics; namespace Microsoft.Dafny.Triggers { class TriggerTerm { internal Expression Expr { get; set; } + internal Expression OriginalExpr { get; set; } internal ISet Variables { get; set; } public override string ToString() { - return Printer.ExprToString(Expr); + return Printer.ExprToString(OriginalExpr); } internal static bool Eq(TriggerTerm t1, TriggerTerm t2) { @@ -28,16 +29,15 @@ namespace Microsoft.Dafny.Triggers { this.Terms = terms; } - public TriggerCandidate(TriggerCandidate mc, string annotation) { - this.Terms = mc.Terms; - this.Annotation = annotation; + public TriggerCandidate(TriggerCandidate candidate) { + this.Terms = candidate.Terms; } internal bool MentionsAll(List vars) { return vars.All(x => Terms.Any(term => term.Variables.Contains(x))); } - private string Repr { get { return Terms.MapConcat(t => Printer.ExprToString(t.Expr), ", "); } } + private string Repr { get { return String.Join(", ", Terms); } } public override string ToString() { return "{" + Repr + "}" + (String.IsNullOrWhiteSpace(Annotation) ? "" : " (" + Annotation + ")"); @@ -51,7 +51,6 @@ namespace Microsoft.Dafny.Triggers { internal List MatchingSubterms(QuantifierExpr quantifier) { Contract.Requires(quantifier.SplitQuantifier == null); // Don't call this on a quantifier with a Split clause: it's not a real quantifier - //FIXME this will miss rewritten expressions (CleanupExpr). Should introduce an OriginalExpr to compare against. return Terms.SelectMany(term => quantifier.SubexpressionsMatchingTrigger(term.Expr)).Deduplicate(TriggerMatch.Eq); } @@ -166,52 +165,10 @@ namespace Microsoft.Dafny.Triggers { return annotation; } - private BinaryExpr.ResolvedOpcode RemoveNotInBinaryExprIn(BinaryExpr.ResolvedOpcode opcode) { - switch (opcode) { - case BinaryExpr.ResolvedOpcode.NotInMap: - return BinaryExpr.ResolvedOpcode.InMap; - case BinaryExpr.ResolvedOpcode.NotInSet: - return BinaryExpr.ResolvedOpcode.InSet; - case BinaryExpr.ResolvedOpcode.NotInSeq: - return BinaryExpr.ResolvedOpcode.InSeq; - case BinaryExpr.ResolvedOpcode.NotInMultiSet: - return BinaryExpr.ResolvedOpcode.InMultiSet; - } - - Contract.Assert(false); - throw new ArgumentException(); - } - - private Expression CleanupExpr(Expression expr, out bool isKiller) { - isKiller = false; - - if (!(expr is BinaryExpr)) { - return expr; - } - - var bexpr = expr as BinaryExpr; - - BinaryExpr new_expr = bexpr; - if (bexpr.Op == BinaryExpr.Opcode.NotIn) { - new_expr = new BinaryExpr(bexpr.tok, BinaryExpr.Opcode.In, bexpr.E0, bexpr.E1); - new_expr.ResolvedOp = RemoveNotInBinaryExprIn(bexpr.ResolvedOp); - new_expr.Type = bexpr.Type; - } - - Expression returned_expr = new_expr; - if (new_expr.ResolvedOp == BinaryExpr.ResolvedOpcode.InMultiSet) { - returned_expr = new SeqSelectExpr(new_expr.tok, true, new_expr.E1, new_expr.E0, null); - returned_expr.Type = bexpr.Type; - isKiller = true; // [a in s] becomes [s[a] > 0], which is a trigger killer - } - - return returned_expr; - } - private TriggerAnnotation AnnotatePotentialCandidate(Expression expr) { bool expr_is_killer = false; - var new_expr = CleanupExpr(expr, out expr_is_killer); - var new_term = new TriggerTerm { Expr = new_expr, Variables = CollectVariables(expr) }; + var new_expr = TriggerUtils.CleanupExprForInclusionInTrigger(expr, out expr_is_killer); + var new_term = new TriggerTerm { Expr = new_expr, OriginalExpr = expr, Variables = CollectVariables(expr) }; List collected_terms = CollectExportedCandidates(expr); var children_contain_killers = CollectIsKiller(expr); -- cgit v1.2.3 From 045c50afc6261beeb83ab4a2f70e597157c9d796 Mon Sep 17 00:00:00 2001 From: Michael Lowell Roberts Date: Mon, 21 Sep 2015 13:51:16 -0700 Subject: merged IronDafny updates. two unit tests related to traits do not pass if ENABLE_IRONDAFNY is defined but this isn't critical and will be addressed shortly. --- Source/Dafny/Cloner.cs | 28 +++--- Source/Dafny/Compiler.cs | 152 +++++++++++++++++++++------------ Source/Dafny/DafnyAst.cs | 130 +++++++++++++++++++--------- Source/Dafny/DafnyPipeline.csproj | 10 +-- Source/Dafny/RefinementTransformer.cs | 18 ++-- Source/Dafny/Resolver.cs | 156 +++++++++++++++++++++++++++++----- Source/Dafny/Translator.cs | 68 ++++++++------- 7 files changed, 388 insertions(+), 174 deletions(-) (limited to 'Source/Dafny/DafnyPipeline.csproj') diff --git a/Source/Dafny/Cloner.cs b/Source/Dafny/Cloner.cs index dd2eed69..7046f9a4 100644 --- a/Source/Dafny/Cloner.cs +++ b/Source/Dafny/Cloner.cs @@ -40,7 +40,7 @@ namespace Microsoft.Dafny } else if (d is TypeSynonymDecl) { var dd = (TypeSynonymDecl)d; var tps = dd.TypeArgs.ConvertAll(CloneTypeParam); - return new TypeSynonymDecl(Tok(dd.tok), dd.Name, tps, m, CloneType(dd.Rhs), CloneAttributes(dd.Attributes)); + return new TypeSynonymDecl(Tok(dd.tok), dd.Name, tps, m, CloneType(dd.Rhs), CloneAttributes(dd.Attributes), dd); } else if (d is NewtypeDecl) { var dd = (NewtypeDecl)d; if (dd.Var == null) { @@ -61,7 +61,7 @@ namespace Microsoft.Dafny var dd = (CoDatatypeDecl)d; var tps = dd.TypeArgs.ConvertAll(CloneTypeParam); var ctors = dd.Ctors.ConvertAll(CloneCtor); - var dt = new CoDatatypeDecl(Tok(dd.tok), dd.Name, m, tps, ctors, CloneAttributes(dd.Attributes)); + var dt = new CoDatatypeDecl(Tok(dd.tok), dd.Name, m, tps, ctors, CloneAttributes(dd.Attributes), dd); return dt; } else if (d is IteratorDecl) { var dd = (IteratorDecl)d; @@ -97,7 +97,7 @@ namespace Microsoft.Dafny var dd = (TraitDecl)d; var tps = dd.TypeArgs.ConvertAll(CloneTypeParam); var mm = dd.Members.ConvertAll(CloneMember); - var cl = new TraitDecl(Tok(dd.tok), dd.Name, m, tps, mm, CloneAttributes(dd.Attributes)); + var cl = new TraitDecl(Tok(dd.tok), dd.Name, m, tps, mm, CloneAttributes(dd.Attributes), dd); return cl; } } @@ -106,7 +106,7 @@ namespace Microsoft.Dafny var tps = dd.TypeArgs.ConvertAll(CloneTypeParam); var mm = dd.Members.ConvertAll(CloneMember); if (d is DefaultClassDecl) { - return new DefaultClassDecl(m, mm); + return new DefaultClassDecl(m, mm, ((DefaultClassDecl)d)); } else { return new ClassDecl(Tok(dd.tok), dd.Name, m, tps, mm, CloneAttributes(dd.Attributes), dd.TraitsTyp.ConvertAll(CloneType), dd); } @@ -137,7 +137,7 @@ namespace Microsoft.Dafny } public DatatypeCtor CloneCtor(DatatypeCtor ct) { - return new DatatypeCtor(Tok(ct.tok), ct.Name, ct.Formals.ConvertAll(CloneFormal), CloneAttributes(ct.Attributes)); + return new DatatypeCtor(Tok(ct.tok), ct.Name, ct.Formals.ConvertAll(CloneFormal), CloneAttributes(ct.Attributes), ct); } public TypeParameter CloneTypeParam(TypeParameter tp) { @@ -641,16 +641,16 @@ namespace Microsoft.Dafny if (f is Predicate) { return new Predicate(Tok(f.tok), newName, f.HasStaticKeyword, f.IsProtected, f.IsGhost, tps, formals, - req, reads, ens, decreases, body, Predicate.BodyOriginKind.OriginalOrInherited, CloneAttributes(f.Attributes), null); + req, reads, ens, decreases, body, Predicate.BodyOriginKind.OriginalOrInherited, CloneAttributes(f.Attributes), null, f); } else if (f is InductivePredicate) { return new InductivePredicate(Tok(f.tok), newName, f.HasStaticKeyword, f.IsProtected, tps, formals, - req, reads, ens, body, CloneAttributes(f.Attributes), null); + req, reads, ens, body, CloneAttributes(f.Attributes), null, f); } else if (f is CoPredicate) { return new CoPredicate(Tok(f.tok), newName, f.HasStaticKeyword, f.IsProtected, tps, formals, - req, reads, ens, body, CloneAttributes(f.Attributes), null); + req, reads, ens, body, CloneAttributes(f.Attributes), null, f); } else { return new Function(Tok(f.tok), newName, f.HasStaticKeyword, f.IsProtected, f.IsGhost, tps, formals, CloneType(f.ResultType), - req, reads, ens, decreases, body, CloneAttributes(f.Attributes), null); + req, reads, ens, decreases, body, CloneAttributes(f.Attributes), null, f); } } @@ -668,19 +668,19 @@ namespace Microsoft.Dafny var body = CloneBlockStmt(m.Body); if (m is Constructor) { return new Constructor(Tok(m.tok), m.Name, tps, ins, - req, mod, ens, decreases, body, CloneAttributes(m.Attributes), null); + req, mod, ens, decreases, body, CloneAttributes(m.Attributes), null, m); } else if (m is InductiveLemma) { return new InductiveLemma(Tok(m.tok), m.Name, m.HasStaticKeyword, tps, ins, m.Outs.ConvertAll(CloneFormal), - req, mod, ens, decreases, body, CloneAttributes(m.Attributes), null); + req, mod, ens, decreases, body, CloneAttributes(m.Attributes), null, m); } else if (m is CoLemma) { return new CoLemma(Tok(m.tok), m.Name, m.HasStaticKeyword, tps, ins, m.Outs.ConvertAll(CloneFormal), - req, mod, ens, decreases, body, CloneAttributes(m.Attributes), null); + req, mod, ens, decreases, body, CloneAttributes(m.Attributes), null, m); } else if (m is Lemma) { return new Lemma(Tok(m.tok), m.Name, m.HasStaticKeyword, tps, ins, m.Outs.ConvertAll(CloneFormal), - req, mod, ens, decreases, body, CloneAttributes(m.Attributes), null); + req, mod, ens, decreases, body, CloneAttributes(m.Attributes), null, m); } else { return new Method(Tok(m.tok), m.Name, m.HasStaticKeyword, m.IsGhost, tps, ins, m.Outs.ConvertAll(CloneFormal), - req, mod, ens, decreases, body, CloneAttributes(m.Attributes), null); + req, mod, ens, decreases, body, CloneAttributes(m.Attributes), null, m); } } public virtual IToken Tok(IToken tok) { diff --git a/Source/Dafny/Compiler.cs b/Source/Dafny/Compiler.cs index 477acabf..123433bc 100644 --- a/Source/Dafny/Compiler.cs +++ b/Source/Dafny/Compiler.cs @@ -102,7 +102,11 @@ namespace Microsoft.Dafny { } int indent = 0; if (!m.IsDefaultModule) { - wr.WriteLine("namespace @{0} {{", m.CompileName); + var m_prime = m; + while (DafnyOptions.O.IronDafny && m_prime.ClonedFrom != null) { + m_prime = m.ClonedFrom; + } + wr.WriteLine("namespace @{0} {{", m_prime.CompileName); indent += IndentAmount; } foreach (TopLevelDecl d in m.TopLevelDecls) { @@ -687,11 +691,18 @@ namespace Microsoft.Dafny { return formal.HasName ? formal.CompileName : "_a" + i; } + string DtName(DatatypeDecl decl) { + var d = (TopLevelDecl)decl; + while (DafnyOptions.O.IronDafny && d.ClonedFrom != null) { + d = (TopLevelDecl)d.ClonedFrom; + } + return d.Module.IsDefaultModule ? d.CompileName : d.FullCompileName; + } string DtCtorName(DatatypeCtor ctor) { Contract.Requires(ctor != null); Contract.Ensures(Contract.Result() != null); - return ctor.EnclosingDatatype.FullCompileName + "_" + ctor.CompileName; + return DtName(ctor.EnclosingDatatype) + "_" + ctor.CompileName; } string DtCtorDeclartionName(DatatypeCtor ctor) { Contract.Requires(ctor != null); @@ -1123,61 +1134,78 @@ namespace Microsoft.Dafny { Contract.Requires(type != null); Contract.Ensures(Contract.Result() != null); - type = type.NormalizeExpand(); - if (type is TypeProxy) { + var xType = type.NormalizeExpand(); + if (xType is TypeProxy) { // unresolved proxy; just treat as ref, since no particular type information is apparently needed for this type return "object"; } - if (type is BoolType) { + if (xType is BoolType) { return "bool"; - } else if (type is CharType) { + } else if (xType is CharType) { return "char"; - } else if (type is IntType) { + } else if (xType is IntType) { return "BigInteger"; - } else if (type is RealType) { + } else if (xType is RealType) { return "Dafny.BigRational"; - } else if (type.AsNewtype != null) { - NativeType nativeType = type.AsNewtype.NativeType; + } else if (xType.AsNewtype != null) { + NativeType nativeType = xType.AsNewtype.NativeType; if (nativeType != null) { return nativeType.Name; } - return TypeName(type.AsNewtype.BaseType); - } else if (type is ObjectType) { + return TypeName(xType.AsNewtype.BaseType); + } else if (xType is ObjectType) { return "object"; - } else if (type.IsArrayType) { - ArrayClassDecl at = type.AsArrayType; + } else if (xType.IsArrayType) { + ArrayClassDecl at = xType.AsArrayType; Contract.Assert(at != null); // follows from type.IsArrayType - Type elType = UserDefinedType.ArrayElementType(type); + Type elType = UserDefinedType.ArrayElementType(xType); string name = TypeName(elType) + "["; for (int i = 1; i < at.Dims; i++) { name += ","; } return name + "]"; - } else if (type is UserDefinedType) { - var udt = (UserDefinedType)type; - return TypeName_UDT(udt.FullCompileName, udt.TypeArgs); - } else if (type is SetType) { - Type argType = ((SetType)type).Arg; + } else if (xType is UserDefinedType) { + var udt = (UserDefinedType)xType; + var s = udt.FullCompileName; + var rc = udt.ResolvedClass; + if (DafnyOptions.O.IronDafny && + !(xType is ArrowType) && + rc != null && + rc.Module != null && + !rc.Module.IsDefaultModule) { + while (rc.ClonedFrom != null || rc.ExclusiveRefinement != null) { + if (rc.ClonedFrom != null) { + rc = (TopLevelDecl)rc.ClonedFrom; + } else { + Contract.Assert(rc.ExclusiveRefinement != null); + rc = rc.ExclusiveRefinement; + } + } + s = rc.FullCompileName; + } + return TypeName_UDT(s, udt.TypeArgs); + } else if (xType is SetType) { + Type argType = ((SetType)xType).Arg; if (argType is ObjectType) { Error("compilation of set is not supported; consider introducing a ghost"); } return DafnySetClass + "<" + TypeName(argType) + ">"; - } else if (type is SeqType) { - Type argType = ((SeqType)type).Arg; + } else if (xType is SeqType) { + Type argType = ((SeqType)xType).Arg; if (argType is ObjectType) { Error("compilation of seq is not supported; consider introducing a ghost"); } return DafnySeqClass + "<" + TypeName(argType) + ">"; - } else if (type is MultiSetType) { - Type argType = ((MultiSetType)type).Arg; + } else if (xType is MultiSetType) { + Type argType = ((MultiSetType)xType).Arg; if (argType is ObjectType) { Error("compilation of seq is not supported; consider introducing a ghost"); } return DafnyMultiSetClass + "<" + TypeName(argType) + ">"; - } else if (type is MapType) { - Type domType = ((MapType)type).Domain; - Type ranType = ((MapType)type).Range; + } else if (xType is MapType) { + Type domType = ((MapType)xType).Domain; + Type ranType = ((MapType)xType).Range; if (domType is ObjectType || ranType is ObjectType) { Error("compilation of map or map<_, object> is not supported; consider introducing a ghost"); } @@ -1218,36 +1246,52 @@ namespace Microsoft.Dafny { Contract.Requires(type != null); Contract.Ensures(Contract.Result() != null); - type = type.NormalizeExpand(); - if (type is TypeProxy) { + var xType = type.NormalizeExpand(); + if (xType is TypeProxy) { // unresolved proxy; just treat as ref, since no particular type information is apparently needed for this type return "null"; } - if (type is BoolType) { + if (xType is BoolType) { return "false"; - } else if (type is CharType) { + } else if (xType is CharType) { return "'D'"; - } else if (type is IntType) { + } else if (xType is IntType) { return "BigInteger.Zero"; - } else if (type is RealType) { + } else if (xType is RealType) { return "Dafny.BigRational.ZERO"; - } else if (type.AsNewtype != null) { - if (type.AsNewtype.NativeType != null) { + } else if (xType.AsNewtype != null) { + if (xType.AsNewtype.NativeType != null) { return "0"; } - return DefaultValue(type.AsNewtype.BaseType); - } else if (type.IsRefType) { - return string.Format("({0})null", TypeName(type)); - } else if (type.IsDatatype) { - UserDefinedType udt = (UserDefinedType)type; - string s = "@" + udt.FullCompileName; + return DefaultValue(xType.AsNewtype.BaseType); + } else if (xType.IsRefType) { + return string.Format("({0})null", TypeName(xType)); + } else if (xType.IsDatatype) { + var udt = (UserDefinedType)xType; + var s = "@" + udt.FullCompileName; + var rc = udt.ResolvedClass; + if (DafnyOptions.O.IronDafny && + !(xType is ArrowType) && + rc != null && + rc.Module != null && + !rc.Module.IsDefaultModule) { + while (rc.ClonedFrom != null || rc.ExclusiveRefinement != null) { + if (rc.ClonedFrom != null) { + rc = (TopLevelDecl)rc.ClonedFrom; + } else { + Contract.Assert(rc.ExclusiveRefinement != null); + rc = rc.ExclusiveRefinement; + } + } + s = "@" + rc.FullCompileName; + } if (udt.TypeArgs.Count != 0) { s += "<" + TypeNames(udt.TypeArgs) + ">"; } return string.Format("new {0}()", s); - } else if (type.IsTypeParameter) { - var udt = (UserDefinedType)type; + } else if (xType.IsTypeParameter) { + var udt = (UserDefinedType)xType; string s = "default(@" + udt.FullCompileName; if (udt.TypeArgs.Count != 0) { @@ -1255,15 +1299,15 @@ namespace Microsoft.Dafny { } s += ")"; return s; - } else if (type is SetType) { - return DafnySetClass + "<" + TypeName(((SetType)type).Arg) + ">.Empty"; - } else if (type is MultiSetType) { - return DafnyMultiSetClass + "<" + TypeName(((MultiSetType)type).Arg) + ">.Empty"; - } else if (type is SeqType) { - return DafnySeqClass + "<" + TypeName(((SeqType)type).Arg) + ">.Empty"; - } else if (type is MapType) { - return TypeName(type)+".Empty"; - } else if (type is ArrowType) { + } else if (xType is SetType) { + return DafnySetClass + "<" + TypeName(((SetType)xType).Arg) + ">.Empty"; + } else if (xType is MultiSetType) { + return DafnyMultiSetClass + "<" + TypeName(((MultiSetType)xType).Arg) + ">.Empty"; + } else if (xType is SeqType) { + return DafnySeqClass + "<" + TypeName(((SeqType)xType).Arg) + ">.Empty"; + } else if (xType is MapType) { + return TypeName(xType)+".Empty"; + } else if (xType is ArrowType) { return "null"; } else { Contract.Assert(false); throw new cce.UnreachableException(); // unexpected type @@ -2387,7 +2431,7 @@ namespace Microsoft.Dafny { Contract.Assert(dtv.Ctor != null); // since dtv has been successfully resolved var typeParams = dtv.InferredTypeArgs.Count == 0 ? "" : string.Format("<{0}>", TypeNames(dtv.InferredTypeArgs)); - wr.Write("new {0}{1}(", dtv.Ctor.EnclosingDatatype.FullCompileName, typeParams); + wr.Write("new {0}{1}(", DtName(dtv.Ctor.EnclosingDatatype), typeParams); if (!dtv.IsCoCall) { // For an ordinary constructor (that is, one that does not guard any co-recursive calls), generate: // new Dt_Cons( args ) @@ -2857,7 +2901,7 @@ namespace Microsoft.Dafny { var b = (ComprehensionExpr.DatatypeBoundedPool)bound; wr.Write("Dafny.Helpers.QuantDatatype("); - wr.Write("{0}.AllSingletonConstructors, ", b.Decl.FullCompileName); + wr.Write("{0}.AllSingletonConstructors, ", DtName(b.Decl)); } else { Contract.Assert(false); throw new cce.UnreachableException(); // unexpected BoundedPool type } diff --git a/Source/Dafny/DafnyAst.cs b/Source/Dafny/DafnyAst.cs index 9bff2038..600f7473 100644 --- a/Source/Dafny/DafnyAst.cs +++ b/Source/Dafny/DafnyAst.cs @@ -183,7 +183,7 @@ namespace Microsoft.Dafny { null, null, null); readsIS.Function = reads; // just so we can really claim the member declarations are resolved readsIS.TypeArgumentSubstitutions = Util.Dict(tps, tys); // ditto - var arrowDecl = new ArrowTypeDecl(tps, req, reads, SystemModule, DontCompile()); + var arrowDecl = new ArrowTypeDecl(tps, req, reads, SystemModule, DontCompile(), null); arrowTypeDecls.Add(arity, arrowDecl); SystemModule.TopLevelDecls.Add(arrowDecl); } @@ -431,16 +431,33 @@ namespace Microsoft.Dafny { var pt = type as TypeProxy; if (pt != null && pt.T != null) { type = pt.T; - } else { + continue; + } var syn = type.AsTypeSynonym; if (syn != null) { var udt = (UserDefinedType)type; // correctness of cast follows from the AsTypeSynonym != null test. // Instantiate with the actual type arguments type = syn.RhsWithArgument(udt.TypeArgs); + continue; + } + if (DafnyOptions.O.IronDafny && type is UserDefinedType) { + var rc = ((UserDefinedType)type).ResolvedClass; + if (rc != null) { + while (rc.ClonedFrom != null || rc.ExclusiveRefinement != null) { + if (rc.ClonedFrom != null) { + rc = (TopLevelDecl)rc.ClonedFrom; } else { - return type; + Contract.Assert(rc.ExclusiveRefinement != null); + rc = rc.ExclusiveRefinement; + } + } + } + if (rc is TypeSynonymDecl) { + type = ((TypeSynonymDecl)rc).Rhs; + continue; } } + return type; } } @@ -1030,7 +1047,11 @@ namespace Microsoft.Dafny { public string FullCompanionCompileName { get { Contract.Requires(ResolvedClass is TraitDecl); - var s = ResolvedClass.Module.IsDefaultModule ? "" : ResolvedClass.Module.CompileName + "."; + var m = ResolvedClass.Module; + while (DafnyOptions.O.IronDafny && m.ClonedFrom != null) { + m = m.ClonedFrom; + } + var s = m.IsDefaultModule ? "" : m.CompileName + "."; return s + "@_Companion_" + CompileName; } } @@ -1802,6 +1823,16 @@ namespace Microsoft.Dafny { } } + public string RefinementCompileName { + get { + if (ExclusiveRefinement != null) { + return this.ExclusiveRefinement.RefinementCompileName; + } else { + return this.CompileName; + } + } + } + /// /// Determines if "a" and "b" are in the same strongly connected component of the call graph, that is, /// if "a" and "b" are mutually recursive. @@ -1946,6 +1977,7 @@ namespace Microsoft.Dafny { Contract.Requires(cce.NonNullElements(typeArgs)); Module = module; TypeArgs = typeArgs; + ExclusiveRefinement = null; } public string FullName { @@ -1958,6 +1990,13 @@ namespace Microsoft.Dafny { return Module.CompileName + "." + CompileName; } } + + public string FullSanitizedRefinementName { + get { + return Module.RefinementCompileName + "." + CompileName; + } + } + public string FullNameInContext(ModuleDefinition context) { if (Module == context) { return Name; @@ -1974,6 +2013,7 @@ namespace Microsoft.Dafny { } } } + public TopLevelDecl ExclusiveRefinement { get; set; } } public class TraitDecl : ClassDecl @@ -1981,8 +2021,8 @@ namespace Microsoft.Dafny { public override string WhatKind { get { return "trait"; } } public bool IsParent { set; get; } public TraitDecl(IToken tok, string name, ModuleDefinition module, - List typeArgs, [Captured] List members, Attributes attributes) - : base(tok, name, module, typeArgs, members, attributes, null) { } + List typeArgs, [Captured] List members, Attributes attributes, TraitDecl clonedFrom = null) + : base(tok, name, module, typeArgs, members, attributes, null, clonedFrom) { } } public class ClassDecl : TopLevelDecl { @@ -2024,8 +2064,8 @@ namespace Microsoft.Dafny { } public class DefaultClassDecl : ClassDecl { - public DefaultClassDecl(ModuleDefinition module, [Captured] List members) - : base(Token.NoToken, "_default", module, new List(), members, null, null) { + public DefaultClassDecl(ModuleDefinition module, [Captured] List members, DefaultClassDecl clonedFrom = null) + : base(Token.NoToken, "_default", module, new List(), members, null, null, clonedFrom) { Contract.Requires(module != null); Contract.Requires(cce.NonNullElements(members)); } @@ -2058,9 +2098,9 @@ namespace Microsoft.Dafny { public readonly Function Requires; public readonly Function Reads; - public ArrowTypeDecl(List tps, Function req, Function reads, ModuleDefinition module, Attributes attributes) + public ArrowTypeDecl(List tps, Function req, Function reads, ModuleDefinition module, Attributes attributes, ArrowTypeDecl clonedFrom) : base(Token.NoToken, ArrowType.ArrowTypeName(tps.Count - 1), module, tps, - new List { req, reads }, attributes, null) { + new List { req, reads }, attributes, null, clonedFrom) { Contract.Requires(tps != null && 1 <= tps.Count); Contract.Requires(req != null); Contract.Requires(reads != null); @@ -2186,8 +2226,8 @@ namespace Microsoft.Dafny { public CoDatatypeDecl SscRepr; // filled in during resolution public CoDatatypeDecl(IToken tok, string name, ModuleDefinition module, List typeArgs, - [Captured] List ctors, Attributes attributes) - : base(tok, name, module, typeArgs, ctors, attributes) { + [Captured] List ctors, Attributes attributes, CoDatatypeDecl clonedFrom = null) + : base(tok, name, module, typeArgs, ctors, attributes, clonedFrom) { Contract.Requires(tok != null); Contract.Requires(name != null); Contract.Requires(module != null); @@ -2214,8 +2254,8 @@ namespace Microsoft.Dafny { public SpecialField QueryField; // filled in during resolution public List Destructors = new List(); // contents filled in during resolution; includes both implicit (not mentionable in source) and explicit destructors - public DatatypeCtor(IToken tok, string name, [Captured] List formals, Attributes attributes) - : base(tok, name, attributes, null) { + public DatatypeCtor(IToken tok, string name, [Captured] List formals, Attributes attributes, DatatypeCtor clonedFrom = null) + : base(tok, name, attributes, clonedFrom) { Contract.Requires(tok != null); Contract.Requires(name != null); Contract.Requires(cce.NonNullElements(formals)); @@ -2426,8 +2466,8 @@ namespace Microsoft.Dafny { public readonly bool IsGhost; public TopLevelDecl EnclosingClass; // filled in during resolution public MemberDecl RefinementBase; // filled in during the pre-resolution refinement transformation; null if the member is new here - public MemberDecl(IToken tok, string name, bool hasStaticKeyword, bool isGhost, Attributes attributes) - : base(tok, name, attributes, null) { + public MemberDecl(IToken tok, string name, bool hasStaticKeyword, bool isGhost, Attributes attributes, Declaration clonedFrom = null) + : base(tok, name, attributes, clonedFrom) { Contract.Requires(tok != null); Contract.Requires(name != null); HasStaticKeyword = hasStaticKeyword; @@ -2452,6 +2492,14 @@ namespace Microsoft.Dafny { return EnclosingClass.FullSanitizedName + "." + CompileName; } } + public string FullSanitizedRefinementName { + get { + Contract.Requires(EnclosingClass != null); + Contract.Ensures(Contract.Result() != null); + + return EnclosingClass.FullSanitizedRefinementName + "." + CompileName; + } + } public string FullNameInContext(ModuleDefinition context) { Contract.Requires(EnclosingClass != null); Contract.Ensures(Contract.Result() != null); @@ -2658,8 +2706,8 @@ namespace Microsoft.Dafny { { public override string WhatKind { get { return "type synonym"; } } public readonly Type Rhs; - public TypeSynonymDecl(IToken tok, string name, List typeArgs, ModuleDefinition module, Type rhs, Attributes attributes) - : base(tok, name, module, typeArgs, attributes) { + public TypeSynonymDecl(IToken tok, string name, List typeArgs, ModuleDefinition module, Type rhs, Attributes attributes, TypeSynonymDecl clonedFrom = null) + : base(tok, name, module, typeArgs, attributes, clonedFrom) { Contract.Requires(tok != null); Contract.Requires(name != null); Contract.Requires(typeArgs != null); @@ -3043,8 +3091,8 @@ namespace Microsoft.Dafny { public Function(IToken tok, string name, bool hasStaticKeyword, bool isProtected, bool isGhost, List typeArgs, List formals, Type resultType, List req, List reads, List ens, Specification decreases, - Expression body, Attributes attributes, IToken signatureEllipsis) - : base(tok, name, hasStaticKeyword, isGhost, attributes) { + Expression body, Attributes attributes, IToken signatureEllipsis, Declaration clonedFrom = null) + : base(tok, name, hasStaticKeyword, isGhost, attributes, clonedFrom) { Contract.Requires(tok != null); Contract.Requires(name != null); @@ -3099,8 +3147,8 @@ namespace Microsoft.Dafny { public Predicate(IToken tok, string name, bool hasStaticKeyword, bool isProtected, bool isGhost, List typeArgs, List formals, List req, List reads, List ens, Specification decreases, - Expression body, BodyOriginKind bodyOrigin, Attributes attributes, IToken signatureEllipsis) - : base(tok, name, hasStaticKeyword, isProtected, isGhost, typeArgs, formals, new BoolType(), req, reads, ens, decreases, body, attributes, signatureEllipsis) { + Expression body, BodyOriginKind bodyOrigin, Attributes attributes, IToken signatureEllipsis, Declaration clonedFrom = null) + : base(tok, name, hasStaticKeyword, isProtected, isGhost, typeArgs, formals, new BoolType(), req, reads, ens, decreases, body, attributes, signatureEllipsis, clonedFrom) { Contract.Requires(bodyOrigin == Predicate.BodyOriginKind.OriginalOrInherited || body != null); BodyOrigin = bodyOrigin; } @@ -3118,7 +3166,7 @@ namespace Microsoft.Dafny { List typeArgs, Formal k, List formals, List req, List reads, List ens, Specification decreases, Expression body, Attributes attributes, FixpointPredicate fixpointPred) - : base(tok, name, hasStaticKeyword, isProtected, true, typeArgs, formals, new BoolType(), req, reads, ens, decreases, body, attributes, null) { + : base(tok, name, hasStaticKeyword, isProtected, true, typeArgs, formals, new BoolType(), req, reads, ens, decreases, body, attributes, null, null) { Contract.Requires(k != null); Contract.Requires(fixpointPred != null); Contract.Requires(formals != null && 1 <= formals.Count && formals[0] == k); @@ -3135,9 +3183,9 @@ namespace Microsoft.Dafny { public FixpointPredicate(IToken tok, string name, bool hasStaticKeyword, bool isProtected, List typeArgs, List formals, List req, List reads, List ens, - Expression body, Attributes attributes, IToken signatureEllipsis) + Expression body, Attributes attributes, IToken signatureEllipsis, Declaration clonedFrom = null) : base(tok, name, hasStaticKeyword, isProtected, true, typeArgs, formals, new BoolType(), - req, reads, ens, new Specification(new List(), null), body, attributes, signatureEllipsis) { + req, reads, ens, new Specification(new List(), null), body, attributes, signatureEllipsis, clonedFrom) { } /// @@ -3176,9 +3224,9 @@ namespace Microsoft.Dafny { public InductivePredicate(IToken tok, string name, bool hasStaticKeyword, bool isProtected, List typeArgs, List formals, List req, List reads, List ens, - Expression body, Attributes attributes, IToken signatureEllipsis) + Expression body, Attributes attributes, IToken signatureEllipsis, Declaration clonedFrom = null) : base(tok, name, hasStaticKeyword, isProtected, typeArgs, formals, - req, reads, ens, body, attributes, signatureEllipsis) { + req, reads, ens, body, attributes, signatureEllipsis, clonedFrom) { } } @@ -3188,9 +3236,9 @@ namespace Microsoft.Dafny { public CoPredicate(IToken tok, string name, bool hasStaticKeyword, bool isProtected, List typeArgs, List formals, List req, List reads, List ens, - Expression body, Attributes attributes, IToken signatureEllipsis) + Expression body, Attributes attributes, IToken signatureEllipsis, Declaration clonedFrom = null) : base(tok, name, hasStaticKeyword, isProtected, typeArgs, formals, - req, reads, ens, body, attributes, signatureEllipsis) { + req, reads, ens, body, attributes, signatureEllipsis, clonedFrom) { } } @@ -3232,8 +3280,8 @@ namespace Microsoft.Dafny { [Captured] List ens, [Captured] Specification decreases, [Captured] BlockStmt body, - Attributes attributes, IToken signatureEllipsis) - : base(tok, name, hasStaticKeyword, isGhost, attributes) { + Attributes attributes, IToken signatureEllipsis, Declaration clonedFrom = null) + : base(tok, name, hasStaticKeyword, isGhost, attributes, clonedFrom) { Contract.Requires(tok != null); Contract.Requires(name != null); Contract.Requires(cce.NonNullElements(typeArgs)); @@ -3305,8 +3353,8 @@ namespace Microsoft.Dafny { [Captured] List ens, [Captured] Specification decreases, [Captured] BlockStmt body, - Attributes attributes, IToken signatureEllipsis) - : base(tok, name, hasStaticKeyword, true, typeArgs, ins, outs, req, mod, ens, decreases, body, attributes, signatureEllipsis) { + Attributes attributes, IToken signatureEllipsis, Declaration clonedFrom = null) + : base(tok, name, hasStaticKeyword, true, typeArgs, ins, outs, req, mod, ens, decreases, body, attributes, signatureEllipsis, clonedFrom) { } } @@ -3320,8 +3368,8 @@ namespace Microsoft.Dafny { [Captured] List ens, [Captured] Specification decreases, [Captured] BlockStmt body, - Attributes attributes, IToken signatureEllipsis) - : base(tok, name, false, false, typeArgs, ins, new List(), req, mod, ens, decreases, body, attributes, signatureEllipsis) { + Attributes attributes, IToken signatureEllipsis, Declaration clonedFrom = null) + : base(tok, name, false, false, typeArgs, ins, new List(), req, mod, ens, decreases, body, attributes, signatureEllipsis, clonedFrom) { Contract.Requires(tok != null); Contract.Requires(name != null); Contract.Requires(cce.NonNullElements(typeArgs)); @@ -3372,8 +3420,8 @@ namespace Microsoft.Dafny { List ens, Specification decreases, BlockStmt body, - Attributes attributes, IToken signatureEllipsis) - : base(tok, name, hasStaticKeyword, true, typeArgs, ins, outs, req, mod, ens, decreases, body, attributes, signatureEllipsis) { + Attributes attributes, IToken signatureEllipsis, Declaration clonedFrom) + : base(tok, name, hasStaticKeyword, true, typeArgs, ins, outs, req, mod, ens, decreases, body, attributes, signatureEllipsis, clonedFrom) { Contract.Requires(tok != null); Contract.Requires(name != null); Contract.Requires(cce.NonNullElements(typeArgs)); @@ -3398,8 +3446,8 @@ namespace Microsoft.Dafny { List ens, Specification decreases, BlockStmt body, - Attributes attributes, IToken signatureEllipsis) - : base(tok, name, hasStaticKeyword, typeArgs, ins, outs, req, mod, ens, decreases, body, attributes, signatureEllipsis) { + Attributes attributes, IToken signatureEllipsis, Declaration clonedFrom = null) + : base(tok, name, hasStaticKeyword, typeArgs, ins, outs, req, mod, ens, decreases, body, attributes, signatureEllipsis, clonedFrom) { Contract.Requires(tok != null); Contract.Requires(name != null); Contract.Requires(cce.NonNullElements(typeArgs)); @@ -3424,8 +3472,8 @@ namespace Microsoft.Dafny { List ens, Specification decreases, BlockStmt body, - Attributes attributes, IToken signatureEllipsis) - : base(tok, name, hasStaticKeyword, typeArgs, ins, outs, req, mod, ens, decreases, body, attributes, signatureEllipsis) { + Attributes attributes, IToken signatureEllipsis, Declaration clonedFrom = null) + : base(tok, name, hasStaticKeyword, typeArgs, ins, outs, req, mod, ens, decreases, body, attributes, signatureEllipsis, clonedFrom) { Contract.Requires(tok != null); Contract.Requires(name != null); Contract.Requires(cce.NonNullElements(typeArgs)); diff --git a/Source/Dafny/DafnyPipeline.csproj b/Source/Dafny/DafnyPipeline.csproj index 13a1e53e..501a624c 100644 --- a/Source/Dafny/DafnyPipeline.csproj +++ b/Source/Dafny/DafnyPipeline.csproj @@ -1,4 +1,4 @@ - + Debug @@ -41,7 +41,7 @@ full false bin\Debug\ - DEBUG;TRACE + TRACE;DEBUG;NO_ENABLE_IRONDAFNY prompt 4 False @@ -83,7 +83,7 @@ pdbonly true bin\Release\ - TRACE + TRACE;NO_ENABLE_IRONDAFNY prompt 4 AllRules.ruleset @@ -91,7 +91,7 @@ true bin\Checked\ - DEBUG;TRACE + TRACE;DEBUG;NO_ENABLE_IRONDAFNY full AnyCPU prompt @@ -199,4 +199,4 @@ --> - + \ No newline at end of file diff --git a/Source/Dafny/RefinementTransformer.cs b/Source/Dafny/RefinementTransformer.cs index ba558ea6..24d1126f 100644 --- a/Source/Dafny/RefinementTransformer.cs +++ b/Source/Dafny/RefinementTransformer.cs @@ -547,16 +547,16 @@ namespace Microsoft.Dafny if (f is Predicate) { return new Predicate(tok, f.Name, f.HasStaticKeyword, f.IsProtected, isGhost, tps, formals, - req, reads, ens, decreases, body, bodyOrigin, refinementCloner.MergeAttributes(f.Attributes, moreAttributes), null); + req, reads, ens, decreases, body, bodyOrigin, refinementCloner.MergeAttributes(f.Attributes, moreAttributes), null, f); } else if (f is InductivePredicate) { return new InductivePredicate(tok, f.Name, f.HasStaticKeyword, f.IsProtected, tps, formals, - req, reads, ens, body, refinementCloner.MergeAttributes(f.Attributes, moreAttributes), null); + req, reads, ens, body, refinementCloner.MergeAttributes(f.Attributes, moreAttributes), null, f); } else if (f is CoPredicate) { return new CoPredicate(tok, f.Name, f.HasStaticKeyword, f.IsProtected, tps, formals, - req, reads, ens, body, refinementCloner.MergeAttributes(f.Attributes, moreAttributes), null); + req, reads, ens, body, refinementCloner.MergeAttributes(f.Attributes, moreAttributes), null, f); } else { return new Function(tok, f.Name, f.HasStaticKeyword, f.IsProtected, isGhost, tps, formals, refinementCloner.CloneType(f.ResultType), - req, reads, ens, decreases, body, refinementCloner.MergeAttributes(f.Attributes, moreAttributes), null); + req, reads, ens, decreases, body, refinementCloner.MergeAttributes(f.Attributes, moreAttributes), null, f); } } @@ -581,19 +581,19 @@ namespace Microsoft.Dafny var body = newBody ?? refinementCloner.CloneBlockStmt(m.Body); if (m is Constructor) { return new Constructor(new RefinementToken(m.tok, moduleUnderConstruction), m.Name, tps, ins, - req, mod, ens, decreases, body, refinementCloner.MergeAttributes(m.Attributes, moreAttributes), null); + req, mod, ens, decreases, body, refinementCloner.MergeAttributes(m.Attributes, moreAttributes), null, m); } else if (m is InductiveLemma) { return new InductiveLemma(new RefinementToken(m.tok, moduleUnderConstruction), m.Name, m.HasStaticKeyword, tps, ins, m.Outs.ConvertAll(refinementCloner.CloneFormal), - req, mod, ens, decreases, body, refinementCloner.MergeAttributes(m.Attributes, moreAttributes), null); + req, mod, ens, decreases, body, refinementCloner.MergeAttributes(m.Attributes, moreAttributes), null, m); } else if (m is CoLemma) { return new CoLemma(new RefinementToken(m.tok, moduleUnderConstruction), m.Name, m.HasStaticKeyword, tps, ins, m.Outs.ConvertAll(refinementCloner.CloneFormal), - req, mod, ens, decreases, body, refinementCloner.MergeAttributes(m.Attributes, moreAttributes), null); + req, mod, ens, decreases, body, refinementCloner.MergeAttributes(m.Attributes, moreAttributes), null, m); } else if (m is Lemma) { return new Lemma(new RefinementToken(m.tok, moduleUnderConstruction), m.Name, m.HasStaticKeyword, tps, ins, m.Outs.ConvertAll(refinementCloner.CloneFormal), - req, mod, ens, decreases, body, refinementCloner.MergeAttributes(m.Attributes, moreAttributes), null); + req, mod, ens, decreases, body, refinementCloner.MergeAttributes(m.Attributes, moreAttributes), null, m); } else { return new Method(new RefinementToken(m.tok, moduleUnderConstruction), m.Name, m.HasStaticKeyword, m.IsGhost, tps, ins, m.Outs.ConvertAll(refinementCloner.CloneFormal), - req, mod, ens, decreases, body, refinementCloner.MergeAttributes(m.Attributes, moreAttributes), null); + req, mod, ens, decreases, body, refinementCloner.MergeAttributes(m.Attributes, moreAttributes), null, m); } } diff --git a/Source/Dafny/Resolver.cs b/Source/Dafny/Resolver.cs index 899d0a3d..a2ae401a 100644 --- a/Source/Dafny/Resolver.cs +++ b/Source/Dafny/Resolver.cs @@ -853,9 +853,34 @@ namespace Microsoft.Dafny if (useImports || string.Equals(kv.Key, "_default", StringComparison.InvariantCulture)) { TopLevelDecl d; if (sig.TopLevels.TryGetValue(kv.Key, out d)) { - if (DafnyOptions.O.IronDafny && kv.Value.ClonedFrom == d) { + bool resolved = false; + if (DafnyOptions.O.IronDafny) { + // sometimes, we need to compare two type synonyms in order to come up with a decision regarding substitution. + var aliased1 = Object.ReferenceEquals(kv.Value, d); + if (!aliased1) { + var a = d; + while (a.ExclusiveRefinement != null) { + a = a.ExclusiveRefinement; + } + var b = kv.Value; + while (b.ExclusiveRefinement != null) { + b = b.ExclusiveRefinement; + } + if (a is TypeSynonymDecl && b is TypeSynonymDecl) { + aliased1 = UnifyTypes(((TypeSynonymDecl)a).Rhs, ((TypeSynonymDecl)b).Rhs); + } else { + aliased1 = Object.ReferenceEquals(a, b); + } + } + if (aliased1 || + Object.ReferenceEquals(kv.Value.ClonedFrom, d) || + Object.ReferenceEquals(d.ClonedFrom, kv.Value) || + Object.ReferenceEquals(kv.Value.ExclusiveRefinement, d)) { sig.TopLevels[kv.Key] = kv.Value; - } else { + resolved = true; + } + } + if (!resolved) { sig.TopLevels[kv.Key] = AmbiguousTopLevelDecl.Create(moduleDef, d, kv.Value); } } else { @@ -872,7 +897,10 @@ namespace Microsoft.Dafny if (sig.Ctors.TryGetValue(kv.Key, out pair)) { // The same ctor can be imported from two different imports (e.g "diamond" imports), in which case, // they are not duplicates. - if (kv.Value.Item1 != pair.Item1) { + if (!Object.ReferenceEquals(kv.Value.Item1, pair.Item1) && + (!DafnyOptions.O.IronDafny || + (!Object.ReferenceEquals(kv.Value.Item1.ClonedFrom, pair.Item1) && + !Object.ReferenceEquals(kv.Value.Item1, pair.Item1.ClonedFrom)))) { // mark it as a duplicate sig.Ctors[kv.Key] = new Tuple(pair.Item1, true); } @@ -888,7 +916,48 @@ namespace Microsoft.Dafny foreach (var kv in s.StaticMembers) { MemberDecl md; if (sig.StaticMembers.TryGetValue(kv.Key, out md)) { + var resolved = false; + if (DafnyOptions.O.IronDafny) { + var aliased0 = Object.ReferenceEquals(kv.Value, md) || Object.ReferenceEquals(kv.Value.ClonedFrom, md) || Object.ReferenceEquals(md.ClonedFrom, kv.Value); + var aliased1 = aliased0; + if (!aliased0) { + var a = kv.Value.EnclosingClass; + while (a != null && + (a.ExclusiveRefinement != null || a.ClonedFrom != null)) { + if (a.ClonedFrom != null) { + a = (TopLevelDecl)a.ClonedFrom; + } else { + Contract.Assert(a.ExclusiveRefinement != null); + a = a.ExclusiveRefinement; + } + } + var b = md.EnclosingClass; + while (b != null && + (b.ExclusiveRefinement != null || b.ClonedFrom != null)) { + if (b.ClonedFrom != null) { + b = (TopLevelDecl)b.ClonedFrom; + } else { + Contract.Assert(b.ExclusiveRefinement != null); + b = b.ExclusiveRefinement; + } + } + aliased1 = Object.ReferenceEquals(a, b); + } + if (aliased0 || aliased1) { + if (kv.Value.EnclosingClass != null && + md.EnclosingClass != null && + md.EnclosingClass.ExclusiveRefinement != null && + !Object.ReferenceEquals( + kv.Value.EnclosingClass.ExclusiveRefinement, + md.EnclosingClass)) { + sig.StaticMembers[kv.Key] = kv.Value; + } + resolved = true; + } + } + if (!resolved) { sig.StaticMembers[kv.Key] = AmbiguousMemberDecl.Create(moduleDef, md, kv.Value); + } } else { // add new sig.StaticMembers.Add(kv.Key, kv.Value); @@ -1245,6 +1314,14 @@ namespace Microsoft.Dafny var typeRedirectionDependencies = new Graph(); foreach (TopLevelDecl d in declarations) { + if (DafnyOptions.O.IronDafny && d.Module.IsExclusiveRefinement) { + var refinementOf = + def.RefinementBase.TopLevelDecls.Find( + i => String.Equals(i.Name, d.Name, StringComparison.InvariantCulture)); + if (refinementOf != null && refinementOf.ExclusiveRefinement == null) { + refinementOf.ExclusiveRefinement = d; + } + } Contract.Assert(d != null); allTypeParameters.PushMarker(); ResolveTypeParameters(d.TypeArgs, true, d); @@ -1277,9 +1354,13 @@ namespace Microsoft.Dafny if (!def.IsAbstract) { if (decl.Signature.IsGhost) { - if (!(def.IsDefaultModule)) // _module is allowed to contain abstract modules, but not be abstract itself. Note this presents a challenge to + if (// _module is allowed to contain abstract modules, but not be abstract itself. Note this presents a challenge to // trusted verification, as toplevels can't be trusted if they invoke abstract module members. - reporter.Error(MessageSource.Resolver, d.tok, "an abstract module can only be imported into other abstract modules, not a concrete one."); + !def.IsDefaultModule + // [IronDafny] it's possbile for an abstract module to have an exclusive refinement, so it no longer makes sense to disallow this. + && !DafnyOptions.O.IronDafny) + + reporter.Error(MessageSource.Resolver, d.tok, "an abstract module can only be imported into other abstract modules, not a concrete one."); } else { // physical modules are allowed everywhere } @@ -4198,6 +4279,11 @@ namespace Microsoft.Dafny } } else if (d is NewtypeDecl) { var dd = (NewtypeDecl)d; + if (DafnyOptions.O.IronDafny) { + while (dd.ClonedFrom != null) { + dd = (NewtypeDecl)d.ClonedFrom; + } + } var caller = context as ICallable; if (caller != null) { caller.EnclosingModule.CallGraph.AddEdge(caller, dd); @@ -4313,28 +4399,60 @@ namespace Microsoft.Dafny UnifyTypes(((MapType)a).Domain, ((MapType)b).Domain) && UnifyTypes(((MapType)a).Range, ((MapType)b).Range); } else if (a is SeqType) { return b is SeqType && UnifyTypes(((SeqType)a).Arg, ((SeqType)b).Arg); - } else if (a is UserDefinedType) { - if (!(b is UserDefinedType)) { - return false; + } else if (a is UserDefinedType || b is UserDefinedType) { + if (!(a is UserDefinedType) && b is UserDefinedType) { + var x = a; + a = b; + b = x; } + var aa = (UserDefinedType)a; var rca = aa.ResolvedClass; + // traits are currently unfriendly to irondafny features. + if (DafnyOptions.O.IronDafny && !(rca is TraitDecl)) { + if (rca != null) { + while (rca.ClonedFrom != null || rca.ExclusiveRefinement != null) { + if (rca.ClonedFrom != null) { + rca = (TopLevelDecl)rca.ClonedFrom; + } else { + Contract.Assert(rca.ExclusiveRefinement != null); + rca = rca.ExclusiveRefinement; + } + } + } + } + + if (!(b is UserDefinedType)) { + return DafnyOptions.O.IronDafny && rca is TypeSynonymDecl && UnifyTypes(((TypeSynonymDecl)rca).Rhs, b); + } + var bb = (UserDefinedType)b; var rcb = bb.ResolvedClass; - if (DafnyOptions.O.IronDafny) - { - while (rca != null && rca.Module.IsAbstract && rca.ClonedFrom != null) - { - // todo: should ClonedFrom be a TopLevelDecl? - // todo: should ClonedFrom be moved to TopLevelDecl? - rca = (TopLevelDecl)rca.ClonedFrom; + // traits are currently unfriendly to irondafny features. + if (DafnyOptions.O.IronDafny && !(rca is TraitDecl) && !(rcb is TraitDecl)) { + if (rcb != null) { + while (rcb.ClonedFrom != null || rcb.ExclusiveRefinement != null) { + if (rcb.ClonedFrom != null) { + rcb = (TopLevelDecl)rcb.ClonedFrom; + } else { + Contract.Assert(rcb.ExclusiveRefinement != null); + rcb = rcb.ExclusiveRefinement; + } + } } - while (rcb != null && rcb.Module.IsAbstract && rcb.ClonedFrom != null) - { - rcb = (TopLevelDecl)rcb.ClonedFrom; + if (rca is TypeSynonymDecl || rcb is TypeSynonymDecl) { + var aaa = a; + var bbb = b; + if (rca is TypeSynonymDecl) { + aaa = ((TypeSynonymDecl)rca).Rhs; + } + if (rcb is TypeSynonymDecl) { + bbb = ((TypeSynonymDecl)rcb).Rhs; + } + return UnifyTypes(aaa, bbb); } } - if (rca != null && rca == rcb) { + if (rca != null && Object.ReferenceEquals(rca, rcb)) { // these are both resolved class/datatype types Contract.Assert(aa.TypeArgs.Count == bb.TypeArgs.Count); bool successSoFar = true; diff --git a/Source/Dafny/Translator.cs b/Source/Dafny/Translator.cs index 09ca32e0..af8225da 100644 --- a/Source/Dafny/Translator.cs +++ b/Source/Dafny/Translator.cs @@ -9246,41 +9246,41 @@ namespace Microsoft.Dafny { Contract.Requires(type != null); Contract.Ensures(Contract.Result() != null); - type = type.NormalizeExpand(); - - if (type is SetType) { - bool finite = ((SetType)type).Finite; - return FunctionCall(Token.NoToken, finite ? "TSet" : "TISet", predef.Ty, TypeToTy(((CollectionType)type).Arg)); - } else if (type is MultiSetType) { - return FunctionCall(Token.NoToken, "TMultiSet", predef.Ty, TypeToTy(((CollectionType)type).Arg)); - } else if (type is SeqType) { - return FunctionCall(Token.NoToken, "TSeq", predef.Ty, TypeToTy(((CollectionType)type).Arg)); - } else if (type is MapType) { - bool finite = ((MapType)type).Finite; + var normType = type.NormalizeExpand(); + + if (normType is SetType) { + bool finite = ((SetType)normType).Finite; + return FunctionCall(Token.NoToken, finite ? "TSet" : "TISet", predef.Ty, TypeToTy(((CollectionType)normType).Arg)); + } else if (normType is MultiSetType) { + return FunctionCall(Token.NoToken, "TMultiSet", predef.Ty, TypeToTy(((CollectionType)normType).Arg)); + } else if (normType is SeqType) { + return FunctionCall(Token.NoToken, "TSeq", predef.Ty, TypeToTy(((CollectionType)normType).Arg)); + } else if (normType is MapType) { + bool finite = ((MapType)normType).Finite; return FunctionCall(Token.NoToken, finite ? "TMap" : "TIMap", predef.Ty, - TypeToTy(((MapType)type).Domain), - TypeToTy(((MapType)type).Range)); - } else if (type is BoolType) { + TypeToTy(((MapType)normType).Domain), + TypeToTy(((MapType)normType).Range)); + } else if (normType is BoolType) { return new Bpl.IdentifierExpr(Token.NoToken, "TBool", predef.Ty); - } else if (type is CharType) { + } else if (normType is CharType) { return new Bpl.IdentifierExpr(Token.NoToken, "TChar", predef.Ty); - } else if (type is RealType) { + } else if (normType is RealType) { return new Bpl.IdentifierExpr(Token.NoToken, "TReal", predef.Ty); - } else if (type is NatType) { + } else if (normType is NatType) { // (Nat needs to come before Int) return new Bpl.IdentifierExpr(Token.NoToken, "TNat", predef.Ty); - } else if (type is IntType) { + } else if (normType is IntType) { return new Bpl.IdentifierExpr(Token.NoToken, "TInt", predef.Ty); - } else if (type.IsTypeParameter) { - return trTypeParam(type.AsTypeParameter, type.TypeArgs); - } else if (type is ObjectType) { + } else if (normType.IsTypeParameter) { + return trTypeParam(normType.AsTypeParameter, normType.TypeArgs); + } else if (normType is ObjectType) { return ClassTyCon(program.BuiltIns.ObjectDecl, new List()); - } else if (type is UserDefinedType) { + } else if (normType is UserDefinedType) { // Classes, (co-)datatypes - var args = type.TypeArgs.ConvertAll(TypeToTy); - return ClassTyCon(((UserDefinedType)type), args); - } else if (type is ParamTypeProxy) { - return trTypeParam(((ParamTypeProxy)type).orig, null); + var args = normType.TypeArgs.ConvertAll(TypeToTy); + return ClassTyCon(((UserDefinedType)normType), args); + } else if (normType is ParamTypeProxy) { + return trTypeParam(((ParamTypeProxy)normType).orig, null); } else { Contract.Assert(false); throw new cce.UnreachableException(); // unexpected type } @@ -9383,19 +9383,19 @@ namespace Microsoft.Dafny { Contract.Requires(etran != null); Contract.Requires(predef != null); - type = type.NormalizeExpand(); - if (type is TypeProxy) { + var normType = type.NormalizeExpand(); + if (normType is TypeProxy) { // Unresolved proxy // Omit where clause (in other places, unresolved proxies are treated as a reference type; we could do that here too, but // we might as well leave out the where clause altogether). return null; } - if (type is NatType) { + if (normType is NatType) { // nat: // 0 <= x return Bpl.Expr.Le(Bpl.Expr.Literal(0), x); - } else if (type is BoolType || type is IntType || type is RealType) { + } else if (normType is BoolType || normType is IntType || normType is RealType) { // nothing to do return null; /* } else if (type is ArrowType) { @@ -9403,7 +9403,7 @@ namespace Microsoft.Dafny { return null; */ } else { - return BplAnd(MkIs(x, type), MkIsAlloc(x, type, etran.HeapExpr)); + return BplAnd(MkIs(x, normType), MkIsAlloc(x, normType, etran.HeapExpr)); } } @@ -11029,7 +11029,11 @@ namespace Microsoft.Dafny { } var ty = translator.TrType(e.Type); - var id = new Bpl.IdentifierExpr(e.tok, e.Function.FullSanitizedName, ty); + var name = e.Function.FullSanitizedName; + if (DafnyOptions.O.IronDafny) { + name = e.Function.FullSanitizedRefinementName; + } + var id = new Bpl.IdentifierExpr(e.tok, name, ty); bool argsAreLit; var args = FunctionInvocationArguments(e, layerArgument, out argsAreLit); -- cgit v1.2.3