package freeboogie.tc; import java.util.HashMap; import freeboogie.ast.*; import freeboogie.util.Err; /** * Checks whether the implementations' signatures correspond to the * procedure signatures. It also connects in/out {@code VariableDecl} * arguments of the implementation with the one in the procedure. * (This link is needed later when verifying that the implementation * satisfies the spec that accompanies the procedure.) it produces * errors if an implementation does not have a corresponding procedure * or if there is a type mismatch in the signature. * * @author rgrig * @author reviewed by TODO */ @SuppressWarnings("unused") // unused parameters public class ImplementationChecker extends Transformer { private boolean errors; private GlobalsCollector gc; // connects implementations to procedures private UsageToDefMap<Implementation, Procedure> implProc; // connects implementation parameters to procedure parameters private UsageToDefMap<VariableDecl, VariableDecl> paramMap; // === public interface === /** * Processes the implementations in {@code ast} assuming that {@code p} * maps procedure names to their AST nodes. ({@code GlobalsCollector} provides * such a mapping.) * @param ast the AST to check * @param g the globals collector that can resolve procedure names * @return whether any errors were detected */ public boolean process(Declaration ast, GlobalsCollector g) { errors = false; gc = g; implProc = new UsageToDefMap<Implementation, Procedure>(); paramMap = new UsageToDefMap<VariableDecl, VariableDecl>(); ast.eval(this); return errors; } /** * Returns the map linking procedures to their usages. * @return the map linking procedures to their usages */ public UsageToDefMap<Implementation, Procedure> getImplProc() { return implProc; } /** * Returns the map of implementation in/out parameters to the map * of procedure in/out parameters. * @return the link between implementation and procedure parameters */ public UsageToDefMap<VariableDecl, VariableDecl> getParamMap() { return paramMap; } // === helpers == private void report(AstLocation l, String s) { Err.error("" + l + ": " + s + "."); errors = true; } // assumes {@code a} and {@code b} are lists of {@code VariableDecl} // compares their types and connects them in implDecl // reports type mismatches private void compare(Declaration a, Declaration b) { if (a == null && b == null) return; if (a == null ^ b == null) { report(a==null? b.loc() : a.loc(), "Implementation-Procedure parameter count mismatch"); return; } VariableDecl va = (VariableDecl)a; VariableDecl vb = (VariableDecl)b; if (!TypeUtils.eq(TypeUtils.stripDep(va.getType()), TypeUtils.stripDep(vb.getType()))) { report(va.loc(), "Type should be " + TypeUtils.typeToString(vb.getType())); return; } paramMap.put(va, vb); } // assumes {@code a} and {@code b} are lists of {@code VariableDecl} // checks that a does not have dependent types private void depCheck(Declaration a) { if (a == null) return; VariableDecl va = (VariableDecl)a; if (TypeUtils.hasDep(va.getType())) report(va.loc(), "Dependent type in implementation signature"); } // === visiting implementations === @Override public void see(Implementation implementation, Signature sig, Body body, Declaration tail) { String name = sig.getName(); Procedure p = gc.procDef(name); if (p == null) { report(implementation.loc(), "Implementation without procedure"); return; } implProc.put(implementation, p); Signature psig = p.getSig(); compare(sig.getArgs(), psig.getArgs()); compare(sig.getResults(), psig.getResults()); depCheck(sig.getArgs()); depCheck(sig.getResults()); if (tail != null) tail.eval(this); } }