Пример #1
0
 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);
 }
Пример #2
0
        private static bool ShallowEq(LiteralExpr expr1, LiteralExpr expr2)
        {
            if (!TriggerUtils.SameNullity(expr1.Value, expr2.Value) || (expr1.Value != null && !expr1.Value.Equals(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
            }
        }
Пример #3
0
        /// <summary>
        /// Collect triggers from the body of each quantifier, and share them
        /// between all quantifiers. This method assumes that all quantifiers
        /// actually come from the same context, and were the result of a split that
        /// gave them all the same variables.
        /// </summary>
        /// <param name="triggersCollector"></param>
        void CollectAndShareTriggers(TriggersCollector triggersCollector)
        {
            List <TriggerTerm> pool = new List <TriggerTerm>();

            foreach (var q in quantifiers)
            {
                var candidates = triggersCollector.CollectTriggers(q.quantifier).Deduplicate(TriggerTerm.Eq);
                // filter out the candidates that was "second-class"
                var filtered = TriggerUtils.Filter(candidates, tr => tr, (tr, _) => !tr.IsTranslatedToFunctionCall(), (tr, _) => { }).ToList();
                // if there are only "second-class" candidates, add them back.
                if (filtered.Count == 0)
                {
                    filtered = candidates;
                }
                pool.AddRange(filtered);
            }
            var distinctPool = pool.Deduplicate(TriggerTerm.Eq);

            foreach (var q in quantifiers)
            {
                q.CandidateTerms = distinctPool; // The list of candidate terms is immutable
                q.Candidates     = TriggerUtils.AllNonEmptySubsets(distinctPool, SubsetGenerationPredicate, q.quantifier.BoundVars).Select(set => set.ToTriggerCandidate()).ToList();
            }
        }
Пример #4
0
        public QuantifierExpr RewriteMatchingLoops(QuantifierWithTriggers q)
        {
            // rewrite quantifier to avoid matching loops
            // before:
            //    assert forall i :: 0 <= i < a.Length-1 ==> a[i] <= a[i+1];
            // after:
            //    assert forall i,j :: j == i+1 ==> 0 <= i < a.Length-1 ==> a[i] <= a[j];
            substMap = new List <Tuple <Expression, IdentifierExpr> >();
            foreach (var m in q.LoopingMatches)
            {
                var e = m.OriginalExpr;
                if (TriggersCollector.IsPotentialTriggerCandidate(e) && triggersCollector.IsTriggerKiller(e))
                {
                    foreach (var sub in e.SubExpressions)
                    {
                        if (triggersCollector.IsTriggerKiller(sub) && (!TriggersCollector.IsPotentialTriggerCandidate(sub)))
                        {
                            var entry = substMap.Find(x => ExprExtensions.ExpressionEq(sub, x.Item1));
                            if (entry == null)
                            {
                                var newBv = new BoundVar(sub.tok, "_t#" + substMap.Count, sub.Type);
                                var ie    = new IdentifierExpr(sub.tok, newBv.Name);
                                ie.Var  = newBv;
                                ie.Type = newBv.Type;
                                substMap.Add(new Tuple <Expression, IdentifierExpr>(sub, ie));
                            }
                        }
                    }
                }
            }

            var expr = (QuantifierExpr)q.quantifier;

            if (substMap.Count > 0)
            {
                var s = new Translator.ExprSubstituter(substMap);
                expr = s.Substitute(q.quantifier) as QuantifierExpr;
            }
            else
            {
                // make a copy of the expr
                if (expr is ForallExpr)
                {
                    expr = new ForallExpr(expr.tok, expr.TypeArgs, expr.BoundVars, expr.Range, expr.Term, TriggerUtils.CopyAttributes(expr.Attributes))
                    {
                        Type = expr.Type, Bounds = expr.Bounds
                    };
                }
                else
                {
                    expr = new ExistsExpr(expr.tok, expr.TypeArgs, expr.BoundVars, expr.Range, expr.Term, TriggerUtils.CopyAttributes(expr.Attributes))
                    {
                        Type = expr.Type, Bounds = expr.Bounds
                    };
                }
            }
            return(expr);
        }
Пример #5
0
        internal static IEnumerable <Expression> SplitQuantifier(ComprehensionExpr quantifier)
        {
            var body   = quantifier.Term;
            var binary = body as BinaryExpr;

            if (quantifier is ForallExpr)
            {
                IEnumerable <Expression> stream;
                if (binary != null && (binary.Op == BinaryExpr.Opcode.Imp || binary.Op == BinaryExpr.Opcode.Or))
                {
                    stream = SplitAndStich(binary, BinaryExpr.Opcode.And);
                }
                else
                {
                    stream = SplitExpr(body, BinaryExpr.Opcode.And);
                }
                foreach (var e in stream)
                {
                    var tok = new NestedToken(quantifier.tok, e.tok);
                    yield return(new ForallExpr(tok, ((ForallExpr)quantifier).TypeArgs, quantifier.BoundVars, quantifier.Range, e, TriggerUtils.CopyAttributes(quantifier.Attributes))
                    {
                        Type = quantifier.Type, Bounds = quantifier.Bounds
                    });
                }
            }
            else if (quantifier is ExistsExpr)
            {
                IEnumerable <Expression> stream;
                if (binary != null && binary.Op == BinaryExpr.Opcode.And)
                {
                    stream = SplitAndStich(binary, BinaryExpr.Opcode.Or);
                }
                else
                {
                    stream = SplitExpr(body, BinaryExpr.Opcode.Or);
                }
                foreach (var e in stream)
                {
                    var tok = new NestedToken(quantifier.tok, e.tok);
                    yield return(new ExistsExpr(tok, ((ExistsExpr)quantifier).TypeArgs, quantifier.BoundVars, quantifier.Range, e, TriggerUtils.CopyAttributes(quantifier.Attributes))
                    {
                        Type = quantifier.Type, Bounds = quantifier.Bounds
                    });
                }
            }
            else
            {
                yield return(quantifier);
            }
        }
Пример #6
0
 private static bool ShallowEq(MemberSelectExpr expr1, MemberSelectExpr expr2)
 {
     return(expr1.MemberName == expr2.MemberName &&
            expr1.Member == expr2.Member &&
            TriggerUtils.SameLists(expr1.TypeApplication, expr2.TypeApplication, TypeEq));
 }
Пример #7
0
 private static bool ShallowEq(NamedExpr expr1, NamedExpr expr2)
 {
     return(expr1.Name == expr2.Name &&
            TriggerUtils.SameNullity(expr1.Contract, expr2.Contract));
 }
Пример #8
0
 private static bool ShallowSameAttributes(Attributes attributes1, Attributes attributes2)
 {
     return(TriggerUtils.SameLists(attributes1.AsEnumerable(), attributes2.AsEnumerable(), ShallowSameSingleAttribute));
 }
Пример #9
0
 internal static IEnumerable <TriggerMatch> SubexpressionsMatchingTrigger(this ComprehensionExpr quantifier, Expression trigger)
 {
     return(quantifier.AllSubExpressions(true, true, true)
            .Select(e => TriggerUtils.PrepareExprForInclusionInTrigger(e).MatchAgainst(trigger, quantifier.BoundVars, e))
            .Where(e => e.HasValue).Select(e => e.Value));
 }
Пример #10
0
        private TriggerAnnotation Annotate(Expression expr)
        {
            TriggerAnnotation cached;

            if (cache.annotations.TryGetValue(expr, out cached))
            {
                return(cached);
            }

            TriggerAnnotation annotation = null; // TODO: Using ApplySuffix fixes the unresolved members problem in GenericSort

            if (expr is LetExpr)
            {
                var le = (LetExpr)expr;
                if (le.LHSs.All(p => p.Var != null) && le.Exact)
                {
                    // Inline the let expression before doing trigger selection.
                    annotation = Annotate(Translator.InlineLet(le));
                }
            }

            if (annotation == null)
            {
                expr.SubExpressions.Iter(e => Annotate(e));

                if (IsPotentialTriggerCandidate(expr))
                {
                    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 MatchExpr)
                {
                    annotation = AnnotateMatchExpr((MatchExpr)expr);
                }
                else if (expr is ComprehensionExpr)
                {
                    annotation = AnnotateComprehensionExpr((ComprehensionExpr)expr);
                }
                else if (expr is ConcreteSyntaxExpression ||
                         expr is LiteralExpr ||
                         expr is ThisExpr ||
                         expr is BoxingCastExpr ||
                         expr is MultiSetFormingExpr ||
                         expr is SeqConstructionExpr)
                {
                    annotation = AnnotateOther(expr, false);
                }
                else
                {
                    annotation = AnnotateOther(expr, true);
                }
            }

            TriggerUtils.DebugTriggers("{0} ({1})\n{2}", Printer.ExprToString(expr), expr.GetType(), annotation);
            cache.annotations[expr] = annotation;
            return(annotation);
        }
Пример #11
0
        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          = ArmadaOptions.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);
            }
        }
Пример #12
0
 private static bool SameTriggerCandidate(TriggerCandidate arg1, TriggerCandidate arg2)
 {
     return(TriggerUtils.SameLists(arg1.Terms, arg2.Terms, TriggerTerm.Eq));
 }
Пример #13
0
 private bool HasSameTriggers(QuantifierWithTriggers one, QuantifierWithTriggers other)
 {
     return(TriggerUtils.SameLists(one.Candidates, other.Candidates, SameTriggerCandidate));
 }
Пример #14
0
 internal void TrimInvalidTriggers()
 {
     Contract.Requires(CandidateTerms != null);
     Contract.Requires(Candidates != null);
     Candidates = TriggerUtils.Filter(Candidates, tr => tr, (tr, _) => tr.MentionsAll(quantifier.BoundVars), (tr, _) => { }).ToList();
 }
Пример #15
0
 // group split quantifier by what triggers they got, and merged them back into one quantifier.
 private void CombineSplitQuantifier()
 {
     if (quantifiers.Count > 1)
     {
         List <QuantifierGroup> groups = new List <QuantifierGroup>();
         groups.Add(new QuantifierGroup(quantifiers[0], new List <ComprehensionExpr> {
             quantifiers[0].quantifier
         }));
         for (int i = 1; i < quantifiers.Count; i++)
         {
             bool found = false;
             for (int j = 0; j < groups.Count; j++)
             {
                 if (HasSameTriggers(quantifiers[i], groups[j].quantifier))
                 {
                     // belong to the same group
                     groups[j].expressions.Add(quantifiers[i].quantifier);
                     found = true;
                     break;
                 }
             }
             if (!found)
             {
                 // start a new group
                 groups.Add(new QuantifierGroup(quantifiers[i], new List <ComprehensionExpr> {
                     quantifiers[i].quantifier
                 }));
             }
         }
         if (groups.Count == quantifiers.Count)
         {
             // have the same number of splits, so no splits are combined.
             return;
         }
         // merge expressions in each group back to one quantifier.
         List <QuantifierWithTriggers> list   = new List <QuantifierWithTriggers>();
         List <Expression>             splits = new List <Expression>();
         foreach (var group in groups)
         {
             QuantifierWithTriggers q = group.quantifier;
             if (q.quantifier is ForallExpr)
             {
                 ForallExpr quantifier = (ForallExpr)q.quantifier;
                 Expression expr       = QuantifiersToExpression(quantifier.tok, BinaryExpr.ResolvedOpcode.And, group.expressions);
                 q.quantifier = new ForallExpr(quantifier.tok, quantifier.TypeArgs, quantifier.BoundVars, quantifier.Range, expr, TriggerUtils.CopyAttributes(quantifier.Attributes))
                 {
                     Type = quantifier.Type, Bounds = quantifier.Bounds
                 };
             }
             else if (q.quantifier is ExistsExpr)
             {
                 ExistsExpr quantifier = (ExistsExpr)q.quantifier;
                 Expression expr       = QuantifiersToExpression(quantifier.tok, BinaryExpr.ResolvedOpcode.Or, group.expressions);
                 q.quantifier = new ExistsExpr(quantifier.tok, quantifier.TypeArgs, quantifier.BoundVars, quantifier.Range, expr, TriggerUtils.CopyAttributes(quantifier.Attributes))
                 {
                     Type = quantifier.Type, Bounds = quantifier.Bounds
                 };
             }
             list.Add(q);
             splits.Add(q.quantifier);
         }
         this.quantifiers = list;
         Contract.Assert(this.expr is QuantifierExpr); // only QuantifierExpr has SplitQuantifier
         ((QuantifierExpr)this.expr).SplitQuantifier = splits;
     }
 }