bool RewriteMatchingLoop() { if (expr is QuantifierExpr) { QuantifierExpr quantifier = (QuantifierExpr)expr; var l = new List <QuantifierWithTriggers>(); List <Expression> splits = new List <Expression>(); bool rewritten = false; foreach (var q in quantifiers) { if (TriggerUtils.NeedsAutoTriggers(q.quantifier) && TriggerUtils.WantsMatchingLoopRewrite(q.quantifier)) { var matchingLoopRewriter = new MatchingLoopRewriter(); var qq = matchingLoopRewriter.RewriteMatchingLoops(q); splits.Add(qq); l.Add(new QuantifierWithTriggers(qq)); rewritten = true; } else { // don't rewrite the quantifier if we are not auto generate triggers. // This is because rewriting introduces new boundvars and will cause // user provided triggers not mention all boundvars splits.Add(q.quantifier); l.Add(q); } } if (rewritten) { quantifier.SplitQuantifier = splits; quantifiers = l; return(true); } } return(false); }
private void CommitOne(QuantifierWithTriggers q, bool addHeader) { var errorLevel = ErrorLevel.Info; var msg = new StringBuilder(); var indent = addHeader ? " " : ""; bool suppressWarnings = Attributes.Contains(q.quantifier.Attributes, "nowarn"); if (!TriggerUtils.NeedsAutoTriggers(q.quantifier)) // NOTE: split and autotriggers attributes are passed down to Boogie { var extraMsg = TriggerUtils.WantsAutoTriggers(q.quantifier) ? "" : " Note that {:autotriggers false} can cause instabilities. Consider using {:nowarn}, {:matchingloop} (not great either), or a manual trigger instead."; msg.AppendFormat("Not generating triggers for \"{0}\".{1}", Printer.ExprToString(q.quantifier.Term), extraMsg).AppendLine(); } else { if (addHeader) { msg.AppendFormat("For expression \"{0}\":", Printer.ExprToString(q.quantifier.Term)).AppendLine(); } foreach (var candidate in q.Candidates) { q.quantifier.Attributes = new Attributes("trigger", candidate.Terms.Select(t => t.Expr).ToList(), q.quantifier.Attributes); } AddTriggersToMessage("Selected triggers:", q.Candidates, msg, indent); AddTriggersToMessage("Rejected triggers:", q.RejectedCandidates, msg, indent, true); #if QUANTIFIER_WARNINGS var WARN_TAG = DafnyOptions.O.UnicodeOutput ? "⚠ " : "/!\\ "; var WARN_TAG_OVERRIDE = suppressWarnings ? "(Suppressed warning) " : WARN_TAG; var WARN_LEVEL = suppressWarnings ? ErrorLevel.Info : ErrorLevel.Warning; var WARN = indent + WARN_TAG_OVERRIDE; if (!q.CandidateTerms.Any()) { errorLevel = WARN_LEVEL; msg.Append(WARN).AppendLine("No terms found to trigger on."); } else if (!q.Candidates.Any()) { errorLevel = WARN_LEVEL; msg.Append(WARN).AppendLine("No trigger covering all quantified variables found."); } else if (!q.CouldSuppressLoops && !q.AllowsLoops) { errorLevel = WARN_LEVEL; msg.Append(WARN).AppendLine("Suppressing loops would leave this expression without triggers."); } else if (suppressWarnings) { errorLevel = ErrorLevel.Warning; msg.Append(indent).Append(WARN_TAG).AppendLine("There is no warning here to suppress."); } #endif } if (msg.Length > 0) { var msgStr = msg.ToString().TrimEnd("\r\n ".ToCharArray()); reporter.Message(MessageSource.Rewriter, errorLevel, q.quantifier.tok, msgStr); } }