Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Proof dependency warnings #4542

Merged
merged 56 commits into from
Sep 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
9ed559a
Basic implementation of proof dependency analysis
atomb Jul 20, 2023
b52bec3
Merge branch 'master' into verification-coverage-ids
jtristan Aug 24, 2023
088eca9
Rename utility methods
atomb Aug 23, 2023
adbe5bc
Basic tracking of assignments
atomb Aug 23, 2023
d260984
Track a few more proof dependencies
atomb Aug 24, 2023
d6f9eea
Fix customBoogie.patch
atomb Aug 25, 2023
8bb2303
Fix unit test for slightly different message
atomb Aug 25, 2023
671b7f6
Revert message change for preconditions
atomb Aug 25, 2023
9ab8bfd
Better dependency messages, assignment tracking
atomb Aug 25, 2023
2b8d580
Order text logger output by source location
atomb Aug 25, 2023
ac55f3f
Add test for proof dependency logging
atomb Aug 25, 2023
d40f73a
Adjust test output to account for changes
atomb Aug 25, 2023
595bded
Silence warning
atomb Aug 28, 2023
2804ef9
Remove obsolete statement
atomb Aug 28, 2023
698b067
Sort proof dependencies in text logger
atomb Aug 28, 2023
6803cad
Fix some expected test outputs
atomb Aug 29, 2023
8e098f9
Merge remote-tracking branch 'upstream/master' into verification-cove…
atomb Aug 29, 2023
80d174a
Move ProofDependencyManager to its own file
atomb Aug 30, 2023
5c6deff
Clean up ProofDependency
atomb Aug 30, 2023
6a671dd
Fix duplicate IDs in Boogie code
atomb Aug 30, 2023
3e4a91b
Fix NPE in test generation code
atomb Aug 30, 2023
ea859c5
Merge remote-tracking branch 'upstream/master' into verification-cove…
atomb Aug 30, 2023
50ee917
Merge remote-tracking branch 'upstream/master' into verification-cove…
atomb Aug 30, 2023
9e2ad02
Fix expected test output
atomb Aug 30, 2023
9133cf7
Various small cleanups
atomb Aug 30, 2023
2dc0052
Merge remote-tracking branch 'upstream/master' into verification-cove…
atomb Sep 1, 2023
04fca88
Use structured dependency labels from Boogie
atomb Sep 5, 2023
3c9b47d
Merge remote-tracking branch 'upstream/master' into verification-cove…
atomb Sep 5, 2023
813b190
Limit proof dependency analysis to one core
atomb Sep 5, 2023
5e75656
Fix customBoogie.patch
atomb Sep 5, 2023
1f9f243
Bump Boogie dependency
atomb Sep 6, 2023
c2a7c60
Merge remote-tracking branch 'upstream/master' into verification-cove…
atomb Sep 6, 2023
9e4bd05
Bump Boogie version in dotnet-tools.json, too
atomb Sep 6, 2023
1ced519
Warn about vacuous proofs and unused assumptions
atomb Sep 2, 2023
97f0fc2
Most basic in-IDE reporting of proof dependencies
atomb Sep 1, 2023
0fd5060
Refactor to work with Boogie 3.0.2+
atomb Sep 6, 2023
1989ec8
Display vacuity and redundancy warnings in the IDE
atomb Sep 6, 2023
68ae66d
Don't subtract 1 from columns
atomb Sep 6, 2023
9765ae8
Filter out some vacuity warnings
atomb Sep 12, 2023
a1bfbf1
Fix typo in description
atomb Sep 12, 2023
300c2ff
Merge remote-tracking branch 'upstream/master' into lsp-proof-coverage
atomb Sep 12, 2023
b98b14c
WIP
atomb Sep 12, 2023
7772a21
Remove IDE changes from this branch
atomb Sep 12, 2023
965b3fd
Add test for proof dependency warnings
atomb Sep 12, 2023
0eec7b4
Fix setting of TrackVerificationCoverage option
atomb Sep 12, 2023
570f1a6
Fix typos in .expect files
atomb Sep 12, 2023
32146b1
Fix test to account for :id attributes
atomb Sep 12, 2023
9bc6021
Merge remote-tracking branch 'upstream/master' into proof-dependency-…
atomb Sep 12, 2023
cfcf464
Address review comments
atomb Sep 13, 2023
4b88f75
Merge branch 'master' into proof-dependency-warnings
atomb Sep 14, 2023
5b9fda2
Add release notes entry
atomb Sep 14, 2023
cfa6cd1
Update docs/dev/news/4542.feat
atomb Sep 14, 2023
b82a523
Update release notes and hide options
atomb Sep 14, 2023
1cdd1a0
Add disclaimers to option descriptions
robin-aws Sep 15, 2023
f6958b5
Merge branch 'master' into proof-dependency-warnings
robin-aws Sep 16, 2023
faa1ffa
Merge branch 'master' into proof-dependency-warnings
robin-aws Sep 16, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Source/DafnyCore/AST/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ void ObjectInvariant() {
public SystemModuleManager SystemModuleManager;
public DafnyOptions Options => Reporter.Options;
public ErrorReporter Reporter { get; set; }
public ProofDependencyManager ProofDependencyManager { get; set; }

public ProofDependencyManager ProofDependencyManager { get; set; } = new();

public Program(string name, [Captured] LiteralModuleDecl module, [Captured] SystemModuleManager systemModuleManager, ErrorReporter reporter,
CompilationData compilation) {
Expand Down
3 changes: 2 additions & 1 deletion Source/DafnyCore/DafnyMain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
using System.Threading;
using System.Threading.Tasks;
using DafnyCore;
using DafnyCore.Verifier;
using Microsoft.Boogie;
using Microsoft.Dafny.ProofObligationDescription;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;

Expand Down Expand Up @@ -202,6 +204,5 @@ await options.OutputWriter.WriteLineAsync(
throw new cce.UnreachableException(); // unexpected outcome
}
}

}
}
20 changes: 20 additions & 0 deletions Source/DafnyCore/Options/CommonOptionBag.cs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,18 @@ Note that quantifier variable domains (<- <Domain>) are available in both syntax
"Emits a warning when a constructor name in a case pattern is not followed by parentheses.");
public static readonly Option<bool> WarnShadowing = new("--warn-shadowing",
"Emits a warning if the name of a declared variable caused another variable to be shadowed.");
public static readonly Option<bool> WarnContradictoryAssumptions = new("--warn-contradictory-assumptions", @"
(experimental) Emits a warning if any assertions are proved based on contradictory assumptions (vacuously).
May slow down verification slightly.
May produce spurious warnings.") {
IsHidden = true
};
public static readonly Option<bool> WarnRedundantAssumptions = new("--warn-redundant-assumptions", @"
(experimental) Emits a warning if any `requires` clause or `assume` statement was not needed to complete verification.
May slow down verification slightly.
May produce spurious warnings.") {
IsHidden = true
};

public static readonly Option<bool> IncludeRuntimeOption = new("--include-runtime",
"Include the Dafny runtime as source in the target language.");
Expand Down Expand Up @@ -248,6 +260,12 @@ static CommonOptionBag() {
DafnyOptions.RegisterLegacyBinding(WarningAsErrors, (options, value) => { options.WarningsAsErrors = value; });
DafnyOptions.RegisterLegacyBinding(VerifyIncludedFiles,
(options, value) => { options.VerifyAllModules = value; });
DafnyOptions.RegisterLegacyBinding(WarnContradictoryAssumptions, (options, value) => {
if (value) { options.TrackVerificationCoverage = true; }
});
DafnyOptions.RegisterLegacyBinding(WarnRedundantAssumptions, (options, value) => {
if (value) { options.TrackVerificationCoverage = true; }
});

DafnyOptions.RegisterLegacyBinding(Target, (options, value) => { options.CompilerName = value; });

Expand Down Expand Up @@ -347,6 +365,8 @@ static CommonOptionBag() {
WarnMissingConstructorParenthesis,
UseJavadocLikeDocstringRewriterOption,
IncludeRuntimeOption,
WarnContradictoryAssumptions,
WarnRedundantAssumptions,
DefaultFunctionOpacity
);
}
Expand Down
4 changes: 3 additions & 1 deletion Source/DafnyCore/Options/ICommandSpec.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ static ICommandSpec() {
BoogieOptionBag.SolverLog,
CommonOptionBag.JsonDiagnostics,
BoogieOptionBag.VerificationErrorLimit,
CommonOptionBag.DefaultFunctionOpacity
CommonOptionBag.DefaultFunctionOpacity,
CommonOptionBag.WarnContradictoryAssumptions,
CommonOptionBag.WarnRedundantAssumptions
}.ToList();

public static IReadOnlyList<Option> TranslationOptions = new Option[] {
Expand Down
98 changes: 98 additions & 0 deletions Source/DafnyCore/ProofDependencyWarnings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
using System.Linq;
using DafnyCore.Verifier;
using Microsoft.Dafny.ProofObligationDescription;

namespace Microsoft.Dafny;

public class ProofDependencyWarnings {
public static void WarnAboutSuspiciousDependencies(DafnyOptions dafnyOptions, ErrorReporter reporter, ProofDependencyManager depManager) {
var verificationResults = (dafnyOptions.Printer as DafnyConsolePrinter).VerificationResults.ToList();
var orderedResults =
verificationResults.OrderBy(vr =>
(vr.Implementation.Tok.filename, vr.Implementation.Tok.line, vr.Implementation.Tok.col));
foreach (var (implementation, result) in orderedResults) {
WarnAboutSuspiciousDependenciesForImplementation(dafnyOptions, reporter, depManager, implementation, result);
}
}

public static void WarnAboutSuspiciousDependenciesForImplementation(DafnyOptions dafnyOptions, ErrorReporter reporter, ProofDependencyManager depManager, DafnyConsolePrinter.ImplementationLogEntry logEntry, DafnyConsolePrinter.VerificationResultLogEntry result) {
var potentialDependencies = depManager.GetPotentialDependenciesForDefinition(logEntry.Name);
var usedDependencies =
result
.VCResults
.SelectMany(vcResult => vcResult.CoveredElements.Select(depManager.GetFullIdDependency))
.OrderBy(dep => (dep.RangeString(), dep.Description));
var unusedDependencies =
potentialDependencies
.Except(usedDependencies)
.OrderBy(dep => (dep.RangeString(), dep.Description));

var unusedObligations = unusedDependencies.OfType<ProofObligationDependency>();
var unusedRequires = unusedDependencies.OfType<RequiresDependency>();
var unusedEnsures = unusedDependencies.OfType<EnsuresDependency>();
var unusedAssumeStatements =
unusedDependencies
.OfType<AssumptionDependency>()
.Where(d => d is AssumptionDependency ad && ad.IsAssumeStatement);
if (dafnyOptions.Get(CommonOptionBag.WarnContradictoryAssumptions)) {
foreach (var dep in unusedObligations) {
if (ShouldWarnVacuous(logEntry.Name, dep)) {
reporter.Warning(MessageSource.Verifier, "", dep.Range, $"proved using contradictory assumptions: {dep.Description}");
}
}

foreach (var dep in unusedEnsures) {
if (ShouldWarnVacuous(logEntry.Name, dep)) {
reporter.Warning(MessageSource.Verifier, "", dep.Range, $"ensures clause proved using contradictory assumptions");
}
}
}

if (dafnyOptions.Get(CommonOptionBag.WarnRedundantAssumptions)) {
foreach (var dep in unusedRequires) {
reporter.Warning(MessageSource.Verifier, "", dep.Range, $"unnecessary requires clause");
}

foreach (var dep in unusedAssumeStatements) {
reporter.Warning(MessageSource.Verifier, "", dep.Range, $"unnecessary assumption");
}
}
}

/// <summary>
/// Some proof obligations that don't show up in the dependency list
/// are innocuous. Either they come about because of internal Dafny
/// design choices that the programmer has no control over, or they
/// just aren't meaningful in context. This method identifies cases
/// where it doesn't make sense to issue a warning. Many of these
/// cases should perhaps be eliminated by changing the translator
/// to not generate vacuous proof goals, but that may be a difficult
/// change to make.
/// </summary>
/// <param name="dep">the dependency to examine</param>
/// <returns>false to skip warning about the absence of this
/// dependency, true otherwise</returns>
private static bool ShouldWarnVacuous(string verboseName, ProofDependency dep) {
if (dep is ProofObligationDependency poDep) {
// Dafny generates some assertions about definite assignment whose
// proofs are always vacuous. Since these aren't written by Dafny
// programmers, it's safe to just skip them all.
if (poDep.ProofObligation is DefiniteAssignment) {
return false;
}

// Similarly here
if (poDep.ProofObligation is MatchIsComplete or AlternativeIsComplete) {
return false;
}

}

// Ensures clauses are often proven vacuously during well-formedness checks.
if (verboseName.Contains("well-formedness") && dep is EnsuresDependency) {
return false;
}

return true;
}
}
10 changes: 6 additions & 4 deletions Source/DafnyCore/Verifier/ProofDependency.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public string LocationString() {
}
var fn = Range.StartToken.filename;
var sl = Range.StartToken.line;
var sc = Range.StartToken.col - 1;
var sc = Range.StartToken.col;
return $"{fn}({sl},{sc})";
}

Expand All @@ -37,9 +37,9 @@ public string RangeString() {
}
var fn = Range.StartToken.filename;
var sl = Range.StartToken.line;
var sc = Range.StartToken.col - 1;
var sc = Range.StartToken.col;
var el = Range.EndToken.line;
var ec = Range.EndToken.col - 1;
var ec = Range.EndToken.col;
return $"{fn}({sl},{sc})-({el},{ec})";
}

Expand Down Expand Up @@ -159,10 +159,12 @@ public class AssumptionDependency : ProofDependency {
comment ?? $"assume {OriginalString()}";

private readonly string comment;
public bool IsAssumeStatement { get; }

public AssumptionDependency(string comment, Expression expr) {
public AssumptionDependency(bool isAssumeStatement, string comment, Expression expr) {
this.comment = comment;
this.expr = expr;
this.IsAssumeStatement = isAssumeStatement;
}
}

Expand Down
16 changes: 16 additions & 0 deletions Source/DafnyCore/Verifier/ProofDependencyManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//-----------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using Dafny;
using Bpl = Microsoft.Boogie;
using BplParser = Microsoft.Boogie.Parser;
using Microsoft.Boogie;
Expand All @@ -17,15 +18,30 @@ namespace Microsoft.Dafny {
public class ProofDependencyManager {
// proof dependency tracking state
public Dictionary<string, ProofDependency> ProofDependenciesById { get; } = new();
private Dictionary<string, HashSet<ProofDependency>> idsByMemberName = new();
private UInt64 proofDependencyIdCount = 0;
private string currentDefinition = null;

public string GetProofDependencyId(ProofDependency dep) {
var idString = $"id{proofDependencyIdCount}";
ProofDependenciesById[idString] = dep;
proofDependencyIdCount++;
if (!idsByMemberName.TryGetValue(currentDefinition, out var currentSet)) {
currentSet = new HashSet<ProofDependency>();
idsByMemberName[currentDefinition] = currentSet;
}
currentSet.Add(dep);
return idString;
}

public void SetCurrentDefinition(string defName) {
currentDefinition = defName;
}

public IEnumerable<ProofDependency> GetPotentialDependenciesForDefinition(string defName) {
Copy link
Member

Choose a reason for hiding this comment

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

Ah there's the "potential" word I was looking for :)

return idsByMemberName[defName];
}

// The "id" attribute on a Boogie AST node is used by Boogie to label
// that AST node in the SMT-Lib formula when constructing a verification
// condition.
Expand Down
4 changes: 2 additions & 2 deletions Source/DafnyCore/Verifier/ProofObligationDescription.cs
Original file line number Diff line number Diff line change
Expand Up @@ -620,10 +620,10 @@ public MatchIsComplete(string matchForm, string missing) {

public class AlternativeIsComplete : ProofObligationDescriptionWithNoExpr {
public override string SuccessDescription =>
$"alternative cases cover all possibilties";
$"alternative cases cover all possibilities";

public override string FailureDescription =>
$"alternative cases fail to cover all possibilties";
$"alternative cases fail to cover all possibilities";

public override string ShortDescription => "alternative complete";
}
Expand Down
8 changes: 4 additions & 4 deletions Source/DafnyCore/Verifier/Translator.BoogieFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,8 @@ public static Bpl.AssumeCmd TrAssumeCmd(Bpl.IToken tok, Bpl.Expr expr, Bpl.QKeyV
return attributes == null ? new Bpl.AssumeCmd(tok, expr) : new Bpl.AssumeCmd(tok, expr, attributes);
}

private Bpl.AssumeCmd TrAssumeCmdWithDependencies(ExpressionTranslator etran, Bpl.IToken tok, Expression dafnyExpr, string comment = null, Bpl.QKeyValue attributes = null) {
return TrAssumeCmdWithDependenciesAndExtend(etran, tok, dafnyExpr, e => e, comment, attributes);
private Bpl.AssumeCmd TrAssumeCmdWithDependencies(ExpressionTranslator etran, Bpl.IToken tok, Expression dafnyExpr, string comment = null, bool isAssumeStatement = false, Bpl.QKeyValue attributes = null) {
return TrAssumeCmdWithDependenciesAndExtend(etran, tok, dafnyExpr, e => e, comment, isAssumeStatement, attributes);
}

// This method translates a Dafny expression to a Boogie expression,
Expand All @@ -208,10 +208,10 @@ private Bpl.AssumeCmd TrAssumeCmdWithDependencies(ExpressionTranslator etran, Bp
// expressions, for instance), creates an assume statement in Boogie,
// and then adds information to track that assumption as a potential
// proof dependency.
private Bpl.AssumeCmd TrAssumeCmdWithDependenciesAndExtend(ExpressionTranslator etran, Bpl.IToken tok, Expression dafnyExpr, Func<Bpl.Expr, Bpl.Expr> extendExpr, string comment = null, Bpl.QKeyValue attributes = null) {
private Bpl.AssumeCmd TrAssumeCmdWithDependenciesAndExtend(ExpressionTranslator etran, Bpl.IToken tok, Expression dafnyExpr, Func<Bpl.Expr, Bpl.Expr> extendExpr, string comment = null, bool isAssumeStatement = false, Bpl.QKeyValue attributes = null) {
var expr = etran.TrExpr(dafnyExpr);
var cmd = TrAssumeCmd(tok, extendExpr(expr), attributes);
proofDependencies?.AddProofDependencyId(cmd, dafnyExpr.tok, new AssumptionDependency(comment, dafnyExpr));
proofDependencies?.AddProofDependencyId(cmd, dafnyExpr.tok, new AssumptionDependency(isAssumeStatement, comment, dafnyExpr));
return cmd;
}

Expand Down
4 changes: 4 additions & 0 deletions Source/DafnyCore/Verifier/Translator.ClassMembers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,7 @@ private void AddMethodImpl(Method m, Boogie.Procedure proc, bool wellformednessP
Contract.Requires(currentModule == null && codeContext == null && _tmpIEs.Count == 0 && isAllocContext == null);
Contract.Ensures(currentModule == null && codeContext == null && _tmpIEs.Count == 0 && isAllocContext == null);

proofDependencies.SetCurrentDefinition(proc.VerboseName);
currentModule = m.EnclosingClass.EnclosingModuleDefinition;
codeContext = m;
isAllocContext = new IsAllocContext(options, m.IsGhost);
Expand Down Expand Up @@ -794,6 +795,7 @@ private void AddMethodOverrideCheckImpl(Method m, Boogie.Procedure proc) {
Contract.Requires(currentModule == null && codeContext == null && _tmpIEs.Count == 0 && isAllocContext == null);
Contract.Ensures(currentModule == null && codeContext == null && _tmpIEs.Count == 0 && isAllocContext == null);

proofDependencies.SetCurrentDefinition(proc.VerboseName);
currentModule = m.EnclosingClass.EnclosingModuleDefinition;
codeContext = m;
isAllocContext = new IsAllocContext(options, m.IsGhost);
Expand Down Expand Up @@ -877,6 +879,7 @@ private void AddFunctionOverrideCheckImpl(Function f) {
Contract.Requires(currentModule == null && codeContext == null && _tmpIEs.Count == 0 && isAllocContext != null);
Contract.Ensures(currentModule == null && codeContext == null && _tmpIEs.Count == 0 && isAllocContext != null);

proofDependencies.SetCurrentDefinition(MethodVerboseName(f.FullDafnyName, MethodTranslationKind.OverrideCheck));
#region first procedure, no impl yet
//Function nf = new Function(f.tok, "OverrideCheck_" + f.Name, f.IsStatic, f.IsGhost, f.TypeArgs, f.OpenParen, f.Formals, f.ResultType, f.Req, f.Reads, f.Ens, f.Decreases, f.Body, f.Attributes, f.SignatureEllipsis);
//AddFunction(f);
Expand Down Expand Up @@ -1478,6 +1481,7 @@ private Boogie.Procedure AddMethod(Method m, MethodTranslationKind kind) {
Contract.Ensures(Contract.Result<Boogie.Procedure>() != null);
Contract.Assert(VisibleInScope(m));

proofDependencies.SetCurrentDefinition(MethodVerboseName(m.FullDafnyName, kind));
currentModule = m.EnclosingClass.EnclosingModuleDefinition;
codeContext = m;
isAllocContext = new IsAllocContext(options, m.IsGhost);
Expand Down
6 changes: 3 additions & 3 deletions Source/DafnyCore/Verifier/Translator.TrStatement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,7 @@ private void TrPredicateStmt(PredicateStmt stmt, BoogieStmtListBuilder builder,
// Adding the assume stmt, resetting the stmtContext
stmtContext = StmtType.ASSUME;
adjustFuelForExists = true;
b.Add(TrAssumeCmdWithDependencies(etran, stmt.Tok, stmt.Expr, "assume statement"));
b.Add(TrAssumeCmdWithDependencies(etran, stmt.Tok, stmt.Expr, "assume statement", true));
stmtContext = StmtType.NONE;
}
}
Expand All @@ -606,7 +606,7 @@ private void TrPredicateStmt(PredicateStmt stmt, BoogieStmtListBuilder builder,
// Adding the assume stmt, resetting the stmtContext
stmtContext = StmtType.ASSUME;
adjustFuelForExists = true;
builder.Add(TrAssumeCmdWithDependencies(etran, stmt.Tok, stmt.Expr, "assume statement"));
builder.Add(TrAssumeCmdWithDependencies(etran, stmt.Tok, stmt.Expr, "assume statement", true));
stmtContext = StmtType.NONE;
}
} else if (stmt is ExpectStmt) {
Expand Down Expand Up @@ -634,7 +634,7 @@ private void TrPredicateStmt(PredicateStmt stmt, BoogieStmtListBuilder builder,
var s = (AssumeStmt)stmt;
stmtContext = StmtType.ASSUME;
TrStmt_CheckWellformed(s.Expr, builder, locals, etran, false);
builder.Add(TrAssumeCmdWithDependencies(etran, stmt.Tok, s.Expr, "assume statement", etran.TrAttributes(stmt.Attributes, null)));
builder.Add(TrAssumeCmdWithDependencies(etran, stmt.Tok, s.Expr, "assume statement", true, etran.TrAttributes(stmt.Attributes, null)));
stmtContext = StmtType.NONE; // done with translating assume stmt.
}
this.fuelContext = FuelSetting.PopFuelContext();
Expand Down
Loading
Loading