@Override
 void analyze(Locals variables) {
   captured = variables.getVariable(location, variable);
   if (expected == null) {
     if (captured.type.sort == Definition.Sort.DEF) {
       // dynamic implementation
       defPointer = "D" + variable + "." + call + ",1";
     } else {
       // typed implementation
       defPointer = "S" + captured.type.name + "." + call + ",1";
     }
     actual = Definition.getType("String");
   } else {
     defPointer = null;
     // static case
     if (captured.type.sort != Definition.Sort.DEF) {
       try {
         ref = new FunctionRef(expected, captured.type.name, call, 1);
       } catch (IllegalArgumentException e) {
         throw createError(e);
       }
     }
     actual = expected;
   }
 }
  @Override
  void analyze(Locals locals) {
    if (statements == null || statements.isEmpty()) {
      throw createError(
          new IllegalArgumentException("Cannot generate an empty function [" + name + "]."));
    }

    locals = Locals.newLocalScope(locals);

    AStatement last = statements.get(statements.size() - 1);

    for (AStatement statement : statements) {
      // Note that we do not need to check after the last statement because
      // there is no statement that can be unreachable after the last.
      if (allEscape) {
        throw createError(new IllegalArgumentException("Unreachable statement."));
      }

      statement.lastSource = statement == last;

      statement.analyze(locals);

      methodEscape = statement.methodEscape;
      allEscape = statement.allEscape;
    }

    if (!methodEscape && rtnType.sort != Sort.VOID) {
      throw createError(
          new IllegalArgumentException(
              "Not all paths provide a return value for method [" + name + "]."));
    }

    if (reserved.getMaxLoopCounter() > 0) {
      loop = locals.getVariable(null, FunctionReserved.LOOP);
    }
  }