code: JCLambda attribSpeculativeLambda(JCLambda that, Env<AttrContext> env, ResultInfo resultInfo) {
          ListBuffer<JCStatement> stats = new ListBuffer<>();
          stats.addAll(that.params);
          if (that.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
              stats.add(make.Return((JCExpression)that.body));
          } else {
              stats.add((JCBlock)that.body);
          }
          JCBlock lambdaBlock = make.Block(0, stats.toList());
          Env<AttrContext> localEnv = attr.lambdaEnv(that, env);
          try {
              localEnv.info.returnResult = resultInfo;
              JCBlock speculativeTree = (JCBlock)attribSpeculative(lambdaBlock, localEnv, resultInfo);
              List<JCVariableDecl> args = speculativeTree.getStatements().stream()
                      .filter(s -> s.hasTag(Tag.VARDEF))
                      .map(t -> (JCVariableDecl)t)
                      .collect(List.collector());
              JCTree lambdaBody = speculativeTree.getStatements().last();
              if (lambdaBody.hasTag(Tag.RETURN)) {
                  lambdaBody = ((JCReturn)lambdaBody).expr;
              }
              JCLambda speculativeLambda = make.Lambda(args, lambdaBody);
              attr.preFlow(speculativeLambda);
              flow.analyzeLambda(env, speculativeLambda, make, false);
              return speculativeLambda;
          } finally {
              localEnv.info.scope.leave();
          }
      }
docs: Performs speculative attribution of a lambda body and returns the speculative lambda tree,
  in the absence of a target-type. Since {@link Attr#visitLambda(JCLambda)} cannot type-check
  lambda bodies w/o a suitable target-type, this routine 'unrolls' the lambda by turning it
  into a regular block, speculatively type-checks the block and then puts back the pieces.