1 /*
   2  * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package jdk.jshell;
  27 
  28 import com.sun.source.tree.CompilationUnitTree;
  29 import com.sun.source.tree.Tree;
  30 import com.sun.source.util.Trees;
  31 import com.sun.tools.javac.api.JavacTaskImpl;
  32 import com.sun.tools.javac.util.Context;
  33 import java.util.ArrayList;
  34 import java.util.List;
  35 import javax.tools.Diagnostic;
  36 import javax.tools.DiagnosticCollector;
  37 import javax.tools.JavaCompiler;
  38 import javax.tools.JavaFileManager;
  39 import javax.tools.JavaFileObject;
  40 import javax.tools.ToolProvider;
  41 import static jdk.jshell.Util.*;
  42 import com.sun.source.tree.ImportTree;
  43 import com.sun.tools.javac.code.Types;
  44 import com.sun.tools.javac.util.JavacMessages;
  45 import jdk.jshell.MemoryFileManager.OutputMemoryJavaFileObject;
  46 import java.util.Collections;
  47 import java.util.Locale;
  48 import static javax.tools.StandardLocation.CLASS_OUTPUT;
  49 import static jdk.internal.jshell.debug.InternalDebugControl.DBG_GEN;
  50 import java.io.File;
  51 import java.util.Collection;
  52 import java.util.HashMap;
  53 import java.util.LinkedHashMap;
  54 import java.util.Map;
  55 import java.util.stream.Collectors;
  56 import static java.util.stream.Collectors.toList;
  57 import java.util.stream.Stream;
  58 import javax.lang.model.util.Elements;
  59 import javax.tools.FileObject;
  60 import jdk.jshell.MemoryFileManager.SourceMemoryJavaFileObject;
  61 import java.lang.Runtime.Version;
  62 import java.nio.CharBuffer;
  63 import java.util.function.BiFunction;
  64 import com.sun.source.tree.ClassTree;
  65 import com.sun.source.tree.Tree.Kind;
  66 import com.sun.source.util.TaskEvent;
  67 import com.sun.source.util.TaskListener;
  68 import com.sun.tools.javac.api.JavacTaskPool;
  69 import com.sun.tools.javac.code.ClassFinder;
  70 import com.sun.tools.javac.code.Kinds;
  71 import com.sun.tools.javac.code.Symbol;
  72 import com.sun.tools.javac.code.Symbol.ClassSymbol;
  73 import com.sun.tools.javac.code.Symbol.PackageSymbol;
  74 import com.sun.tools.javac.code.Symbol.TypeSymbol;
  75 import com.sun.tools.javac.code.Symbol.VarSymbol;
  76 import com.sun.tools.javac.code.Symtab;
  77 import com.sun.tools.javac.code.Type;
  78 import com.sun.tools.javac.comp.Attr;
  79 import com.sun.tools.javac.comp.AttrContext;
  80 import com.sun.tools.javac.comp.Enter;
  81 import com.sun.tools.javac.comp.Env;
  82 import com.sun.tools.javac.comp.Resolve;
  83 import com.sun.tools.javac.parser.Parser;
  84 import com.sun.tools.javac.parser.ParserFactory;
  85 import com.sun.tools.javac.tree.JCTree.JCExpression;
  86 import com.sun.tools.javac.tree.JCTree.JCTypeCast;
  87 import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
  88 import com.sun.tools.javac.tree.JCTree.Tag;
  89 import com.sun.tools.javac.util.Context.Factory;
  90 import com.sun.tools.javac.util.Log;
  91 import com.sun.tools.javac.util.Log.DiscardDiagnosticHandler;
  92 import com.sun.tools.javac.util.Names;
  93 import static jdk.internal.jshell.debug.InternalDebugControl.DBG_FMGR;
  94 import jdk.jshell.Snippet.Status;
  95 
  96 /**
  97  * The primary interface to the compiler API.  Parsing, analysis, and
  98  * compilation to class files (in memory).
  99  * @author Robert Field
 100  */
 101 class TaskFactory {
 102 
 103     private final JavaCompiler compiler;
 104     private final MemoryFileManager fileManager;
 105     private final JShell state;
 106     private String classpath = System.getProperty("java.class.path");
 107     private final static Version INITIAL_SUPPORTED_VER = Version.parse("9");
 108 
 109     TaskFactory(JShell state) {
 110         this.state = state;
 111         this.compiler = ToolProvider.getSystemJavaCompiler();
 112         if (compiler == null) {
 113             throw new UnsupportedOperationException("Compiler not available, must be run with full JDK 9.");
 114         }
 115         Version current = Version.parse(System.getProperty("java.specification.version"));
 116         if (INITIAL_SUPPORTED_VER.compareToIgnoreOptional(current) > 0)  {
 117             throw new UnsupportedOperationException("Wrong compiler, must be run with full JDK 9.");
 118         }
 119         this.fileManager = new MemoryFileManager(
 120                 compiler.getStandardFileManager(null, null, null), state);
 121         initTaskPool();
 122     }
 123 
 124     void addToClasspath(String path) {
 125         classpath = classpath + File.pathSeparator + path;
 126         List<String> args = new ArrayList<>();
 127         args.add(classpath);
 128         fileManager().handleOption("-classpath", args.iterator());
 129         initTaskPool();
 130     }
 131 
 132     MemoryFileManager fileManager() {
 133         return fileManager;
 134     }
 135 
 136     public <Z> Z parse(String source,
 137                        boolean forceExpression,
 138                        Worker<ParseTask, Z> worker) {
 139         StringSourceHandler sh = new StringSourceHandler();
 140         return runTask(Stream.of(source),
 141                        sh,
 142                        List.of("-XDallowStringFolding=false", "-proc:none",
 143                                "-XDneedsReplParserFactory=" + forceExpression),
 144                        (jti, diagnostics) -> new ParseTask(sh, jti, diagnostics, forceExpression),
 145                        worker);
 146     }
 147 
 148     public <Z> Z analyze(OuterWrap wrap,
 149                          Worker<AnalyzeTask, Z> worker) {
 150         return analyze(Collections.singletonList(wrap), worker);
 151     }
 152 
 153     public <Z> Z analyze(OuterWrap wrap,
 154                          List<String> extraArgs,
 155                          Worker<AnalyzeTask, Z> worker) {
 156         return analyze(Collections.singletonList(wrap), extraArgs, worker);
 157     }
 158 
 159     public <Z> Z analyze(Collection<OuterWrap> wraps,
 160                          Worker<AnalyzeTask, Z> worker) {
 161         return analyze(wraps, Collections.emptyList(), worker);
 162     }
 163 
 164     public <Z> Z analyze(Collection<OuterWrap> wraps,
 165                          List<String> extraArgs,
 166                          Worker<AnalyzeTask, Z> worker) {
 167         WrapSourceHandler sh = new WrapSourceHandler();
 168         List<String> allOptions = new ArrayList<>();
 169 
 170         allOptions.add("--should-stop=at=FLOW");
 171         allOptions.add("-Xlint:unchecked");
 172         allOptions.add("-proc:none");
 173         allOptions.addAll(extraArgs);
 174 
 175         return runTask(wraps.stream(),
 176                        sh,
 177                        allOptions,
 178                        (jti, diagnostics) -> new AnalyzeTask(sh, jti, diagnostics),
 179                        worker);
 180     }
 181 
 182     public <Z> Z compile(Collection<OuterWrap> wraps,
 183                          Worker<CompileTask, Z> worker) {
 184         WrapSourceHandler sh = new WrapSourceHandler();
 185 
 186         return runTask(wraps.stream(),
 187                        sh,
 188                        List.of("-Xlint:unchecked", "-proc:none", "-parameters"),
 189                        (jti, diagnostics) -> new CompileTask(sh, jti, diagnostics),
 190                        worker);
 191     }
 192 
 193     private <S, T extends BaseTask, Z> Z runTask(Stream<S> inputs,
 194                                                  SourceHandler<S> sh,
 195                                                  List<String> options,
 196                                                  BiFunction<JavacTaskImpl, DiagnosticCollector<JavaFileObject>, T> creator,
 197                                                  Worker<T, Z> worker) {
 198             List<String> allOptions = new ArrayList<>(options.size() + state.extraCompilerOptions.size());
 199             allOptions.addAll(options);
 200             allOptions.addAll(state.extraCompilerOptions);
 201             Iterable<? extends JavaFileObject> compilationUnits = inputs
 202                             .map(in -> sh.sourceToFileObject(fileManager, in))
 203                             .collect(Collectors.toList());
 204             DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
 205             state.debug(DBG_FMGR, "Task (%s %s) Options: %s\n", this, compilationUnits, allOptions);
 206             return javacTaskPool.getTask(null, fileManager, diagnostics, allOptions, null,
 207                                          compilationUnits, task -> {
 208                  JavacTaskImpl jti = (JavacTaskImpl) task;
 209                  Context context = jti.getContext();
 210                  DisableAccessibilityResolve.preRegister(context);
 211                  jti.addTaskListener(new TaskListenerImpl(context, state));
 212                  try {
 213                      return worker.withTask(creator.apply(jti, diagnostics));
 214                  } finally {
 215                      //additional cleanup: purge the REPL package:
 216                      Symtab syms = Symtab.instance(context);
 217                      Names names = Names.instance(context);
 218                      PackageSymbol repl = syms.getPackage(syms.unnamedModule, names.fromString(Util.REPL_PACKAGE));
 219                      if (repl != null) {
 220                          for (ClassSymbol clazz : syms.getAllClasses()) {
 221                              if (clazz.packge() == repl) {
 222                                  syms.removeClass(syms.unnamedModule, clazz.flatName());
 223                              }
 224                          }
 225                          repl.members_field = null;
 226                          repl.completer = ClassFinder.instance(context).getCompleter();
 227                      }
 228                  }
 229             });
 230     }
 231 
 232     interface Worker<T extends BaseTask, Z> {
 233         public Z withTask(T task);
 234     }
 235 
 236     // Parse a snippet and return our parse task handler
 237     <Z> Z parse(final String source, Worker<ParseTask, Z> worker) {
 238         return parse(source, false, pt -> {
 239             if (shouldParseAsExpression(pt)) {
 240                 // It failed, it may be an expression being incorrectly
 241                 // parsed as having a leading type variable, example:   a < b
 242                 // Try forcing interpretation as an expression
 243                 return parse(source, true, ept -> {
 244                     if (!ept.getDiagnostics().hasOtherThanNotStatementErrors()) {
 245                         return worker.withTask(ept);
 246                     } else {
 247                         return worker.withTask(pt);
 248                     }
 249                 });
 250             }
 251             return worker.withTask(pt);
 252         });
 253     }
 254         // where
 255         private boolean shouldParseAsExpression(ParseTask pt) {
 256             if (pt.units().isEmpty() || !pt.getDiagnostics().hasOtherThanNotStatementErrors())
 257                 return false;
 258             Tree tree = pt.units().get(0);
 259             if (tree.getKind() == Kind.EXPRESSION_STATEMENT)
 260                 return true;
 261             if (tree.getKind() == Kind.VARIABLE) {
 262                 JCVariableDecl varDecl = (JCVariableDecl) tree;
 263                 if (varDecl.vartype != null && varDecl.vartype.isQuestioned())
 264                     return true;
 265             }
 266             return false;
 267         }
 268 
 269     private interface SourceHandler<T> {
 270 
 271         JavaFileObject sourceToFileObject(MemoryFileManager fm, T t);
 272 
 273         Diag diag(Diagnostic<? extends JavaFileObject> d);
 274     }
 275 
 276     private class StringSourceHandler implements SourceHandler<String> {
 277 
 278         @Override
 279         public JavaFileObject sourceToFileObject(MemoryFileManager fm, String src) {
 280             return fm.createSourceFileObject(src, "$NeverUsedName$", src);
 281         }
 282 
 283         @Override
 284         public Diag diag(final Diagnostic<? extends JavaFileObject> d) {
 285             return new Diag() {
 286 
 287                 @Override
 288                 public boolean isError() {
 289                     return d.getKind() == Diagnostic.Kind.ERROR;
 290                 }
 291 
 292                 @Override
 293                 public long getPosition() {
 294                     return d.getPosition();
 295                 }
 296 
 297                 @Override
 298                 public long getStartPosition() {
 299                     return d.getStartPosition();
 300                 }
 301 
 302                 @Override
 303                 public long getEndPosition() {
 304                     return d.getEndPosition();
 305                 }
 306 
 307                 @Override
 308                 public String getCode() {
 309                     return d.getCode();
 310                 }
 311 
 312                 @Override
 313                 public String getMessage(Locale locale) {
 314                     return expunge(d.getMessage(locale));
 315                 }
 316             };
 317         }
 318     }
 319 
 320     private class WrapSourceHandler implements SourceHandler<OuterWrap> {
 321 
 322         @Override
 323         public JavaFileObject sourceToFileObject(MemoryFileManager fm, OuterWrap w) {
 324             return fm.createSourceFileObject(w, w.classFullName(), w.wrapped());
 325         }
 326 
 327         /**
 328          * Get the source information from the wrap.  If this is external, or
 329          * otherwise does not have wrap info, just use source code.
 330          * @param d the Diagnostic from the compiler
 331          * @return the corresponding Diag
 332          */
 333         @Override
 334         public Diag diag(Diagnostic<? extends JavaFileObject> d) {
 335             JavaFileObject jfo = d.getSource();
 336             return jfo instanceof SourceMemoryJavaFileObject
 337                     ? ((OuterWrap) ((SourceMemoryJavaFileObject) jfo).getOrigin()).wrapDiag(d)
 338                     : new StringSourceHandler().diag(d);
 339         }
 340     }
 341 
 342     /**
 343      * Parse a snippet of code (as a String) using the parser subclass.  Return
 344      * the parse tree (and errors).
 345      */
 346     class ParseTask extends BaseTask {
 347 
 348         private final Iterable<? extends CompilationUnitTree> cuts;
 349         private final List<? extends Tree> units;
 350 
 351         private ParseTask(SourceHandler<String> sh,
 352                           JavacTaskImpl task,
 353                           DiagnosticCollector<JavaFileObject> diagnostics,
 354                           boolean forceExpression) {
 355             super(sh, task, diagnostics);
 356             ReplParserFactory.preRegister(context, forceExpression);
 357             cuts = parse();
 358             units = Util.stream(cuts)
 359                     .flatMap(cut -> {
 360                         List<? extends ImportTree> imps = cut.getImports();
 361                         return (!imps.isEmpty() ? imps : cut.getTypeDecls()).stream();
 362                     })
 363                     .collect(toList());
 364         }
 365 
 366         private Iterable<? extends CompilationUnitTree> parse() {
 367             try {
 368                 return task.parse();
 369             } catch (Exception ex) {
 370                 throw new InternalError("Exception during parse - " + ex.getMessage(), ex);
 371             }
 372         }
 373 
 374         List<? extends Tree> units() {
 375             return units;
 376         }
 377 
 378         @Override
 379         Iterable<? extends CompilationUnitTree> cuTrees() {
 380             return cuts;
 381         }
 382     }
 383 
 384     /**
 385      * Run the normal "analyze()" pass of the compiler over the wrapped snippet.
 386      */
 387     class AnalyzeTask extends BaseTask {
 388 
 389         private final Iterable<? extends CompilationUnitTree> cuts;
 390 
 391         private AnalyzeTask(SourceHandler<OuterWrap> sh,
 392                             JavacTaskImpl task,
 393                             DiagnosticCollector<JavaFileObject> diagnostics) {
 394             super(sh, task, diagnostics);
 395             cuts = analyze();
 396         }
 397 
 398         private Iterable<? extends CompilationUnitTree> analyze() {
 399             try {
 400                 Iterable<? extends CompilationUnitTree> cuts = task.parse();
 401                 task.analyze();
 402                 return cuts;
 403             } catch (Exception ex) {
 404                 throw new InternalError("Exception during analyze - " + ex.getMessage(), ex);
 405             }
 406         }
 407 
 408         @Override
 409         Iterable<? extends CompilationUnitTree> cuTrees() {
 410             return cuts;
 411         }
 412 
 413         Elements getElements() {
 414             return task.getElements();
 415         }
 416 
 417         javax.lang.model.util.Types getTypes() {
 418             return task.getTypes();
 419         }
 420     }
 421 
 422     /**
 423      * Unit the wrapped snippet to class files.
 424      */
 425     class CompileTask extends BaseTask {
 426 
 427         private final Map<OuterWrap, List<OutputMemoryJavaFileObject>> classObjs = new HashMap<>();
 428 
 429         CompileTask(SourceHandler<OuterWrap>sh,
 430                     JavacTaskImpl jti,
 431                     DiagnosticCollector<JavaFileObject> diagnostics) {
 432             super(sh, jti, diagnostics);
 433         }
 434 
 435         boolean compile() {
 436             fileManager.registerClassFileCreationListener(this::listenForNewClassFile);
 437             boolean result = task.call();
 438             fileManager.registerClassFileCreationListener(null);
 439             return result;
 440         }
 441 
 442         // Returns the list of classes generated during this compile.
 443         // Stores the mapping between class name and current compiled bytes.
 444         List<String> classList(OuterWrap w) {
 445             List<OutputMemoryJavaFileObject> l = classObjs.get(w);
 446             if (l == null) {
 447                 return Collections.emptyList();
 448             }
 449             List<String> list = new ArrayList<>();
 450             for (OutputMemoryJavaFileObject fo : l) {
 451                 state.classTracker.setCurrentBytes(fo.getName(), fo.getBytes());
 452                 list.add(fo.getName());
 453             }
 454             return list;
 455         }
 456 
 457         private void listenForNewClassFile(OutputMemoryJavaFileObject jfo, JavaFileManager.Location location,
 458                 String className, JavaFileObject.Kind kind, FileObject sibling) {
 459             //debug("listenForNewClassFile %s loc=%s kind=%s\n", className, location, kind);
 460             if (location == CLASS_OUTPUT) {
 461                 state.debug(DBG_GEN, "Compiler generating class %s\n", className);
 462                 OuterWrap w = ((sibling instanceof SourceMemoryJavaFileObject)
 463                         && (((SourceMemoryJavaFileObject) sibling).getOrigin() instanceof OuterWrap))
 464                         ? (OuterWrap) ((SourceMemoryJavaFileObject) sibling).getOrigin()
 465                         : null;
 466                 classObjs.compute(w, (k, v) -> (v == null)? new ArrayList<>() : v)
 467                         .add(jfo);
 468             }
 469         }
 470 
 471         @Override
 472         Iterable<? extends CompilationUnitTree> cuTrees() {
 473             throw new UnsupportedOperationException("Not supported.");
 474         }
 475     }
 476 
 477     private JavacTaskPool javacTaskPool;
 478 
 479     private void initTaskPool() {
 480         javacTaskPool = new JavacTaskPool(5);
 481     }
 482 
 483     abstract class BaseTask {
 484 
 485         final DiagnosticCollector<JavaFileObject> diagnostics;
 486         final JavacTaskImpl task;
 487         private DiagList diags = null;
 488         private final SourceHandler<?> sourceHandler;
 489         final Context context;
 490         private Types types;
 491         private JavacMessages messages;
 492         private Trees trees;
 493 
 494         private <T>BaseTask(SourceHandler<T> sh,
 495                             JavacTaskImpl task,
 496                             DiagnosticCollector<JavaFileObject> diagnostics) {
 497             this.sourceHandler = sh;
 498             this.task = task;
 499             context = task.getContext();
 500             this.diagnostics = diagnostics;
 501         }
 502 
 503         abstract Iterable<? extends CompilationUnitTree> cuTrees();
 504 
 505         CompilationUnitTree firstCuTree() {
 506             return cuTrees().iterator().next();
 507         }
 508 
 509         Diag diag(Diagnostic<? extends JavaFileObject> diag) {
 510             return sourceHandler.diag(diag);
 511         }
 512 
 513         Context getContext() {
 514             return context;
 515         }
 516 
 517         Types types() {
 518             if (types == null) {
 519                 types = Types.instance(context);
 520             }
 521             return types;
 522         }
 523 
 524         JavacMessages messages() {
 525             if (messages == null) {
 526                 messages = JavacMessages.instance(context);
 527             }
 528             return messages;
 529         }
 530 
 531         Trees trees() {
 532             if (trees == null) {
 533                 trees = Trees.instance(task);
 534             }
 535             return trees;
 536         }
 537 
 538         // ------------------ diags functionality
 539 
 540         DiagList getDiagnostics() {
 541             if (diags == null) {
 542                 LinkedHashMap<String, Diag> diagMap = new LinkedHashMap<>();
 543                 for (Diagnostic<? extends JavaFileObject> in : diagnostics.getDiagnostics()) {
 544                     Diag d = diag(in);
 545                     String uniqueKey = d.getCode() + ":" + d.getPosition() + ":" + d.getMessage(PARSED_LOCALE);
 546                     diagMap.put(uniqueKey, d);
 547                 }
 548                 diags = new DiagList(diagMap.values());
 549             }
 550             return diags;
 551         }
 552 
 553         boolean hasErrors() {
 554             return getDiagnostics().hasErrors();
 555         }
 556 
 557         String shortErrorMessage() {
 558             StringBuilder sb = new StringBuilder();
 559             for (Diag diag : getDiagnostics()) {
 560                 for (String line : diag.getMessage(PARSED_LOCALE).split("\\r?\\n")) {
 561                     if (!line.trim().startsWith("location:")) {
 562                         sb.append(line);
 563                     }
 564                 }
 565             }
 566             return sb.toString();
 567         }
 568 
 569         void debugPrintDiagnostics(String src) {
 570             for (Diag diag : getDiagnostics()) {
 571                 state.debug(DBG_GEN, "ERROR --\n");
 572                 for (String line : diag.getMessage(PARSED_LOCALE).split("\\r?\\n")) {
 573                     if (!line.trim().startsWith("location:")) {
 574                         state.debug(DBG_GEN, "%s\n", line);
 575                     }
 576                 }
 577                 int start = (int) diag.getStartPosition();
 578                 int end = (int) diag.getEndPosition();
 579                 if (src != null) {
 580                     String[] srcLines = src.split("\\r?\\n");
 581                     for (String line : srcLines) {
 582                         state.debug(DBG_GEN, "%s\n", line);
 583                     }
 584 
 585                     StringBuilder sb = new StringBuilder();
 586                     for (int i = 0; i < start; ++i) {
 587                         sb.append(' ');
 588                     }
 589                     sb.append('^');
 590                     if (end > start) {
 591                         for (int i = start + 1; i < end; ++i) {
 592                             sb.append('-');
 593                         }
 594                         sb.append('^');
 595                     }
 596                     state.debug(DBG_GEN, "%s\n", sb.toString());
 597                 }
 598                 state.debug(DBG_GEN, "printDiagnostics start-pos = %d ==> %d -- wrap = %s\n",
 599                         diag.getStartPosition(), start, this);
 600                 state.debug(DBG_GEN, "Code: %s\n", diag.getCode());
 601                 state.debug(DBG_GEN, "Pos: %d (%d - %d) -- %s\n", diag.getPosition(),
 602                         diag.getStartPosition(), diag.getEndPosition(), diag.getMessage(null));
 603             }
 604         }
 605     }
 606 
 607     /**The variable types inferred for "var"s may be non-denotable.
 608      * jshell desugars these variables into fields, and fields must have
 609      * a denotable type. So these fields are declared with some simpler denotable
 610      * type, and the listener here enhances the types of the fields to be the full
 611      * inferred types. This is mainly when the inferred type contains:
 612      * -intersection types (e.g. <Z extends Runnable&CharSequence> Z get() {...} var z = get();)
 613      * -types that are inaccessible at the given place
 614      *
 615      * This type enhancement does not need to do anything about anonymous classes, as these
 616      * are desugared into member classes.
 617      */
 618     private static final class TaskListenerImpl implements TaskListener {
 619 
 620         private final Context context;
 621         private final JShell state;
 622         /* Keep the original (declaration) types of the fields that were enhanced.
 623          * The declaration types need to be put back before writing the fields
 624          * into classfiles.*/
 625         private final Map<VarSymbol, Type> var2OriginalType = new HashMap<>();
 626 
 627         public TaskListenerImpl(Context context, JShell state) {
 628             this.context = context;
 629             this.state = state;
 630         }
 631 
 632         @Override
 633         public void started(TaskEvent e) {
 634             if (e.getKind() != TaskEvent.Kind.GENERATE)
 635                 return ;
 636             //clear enhanced types in fields we are about to write to the classfiles:
 637             for (Tree clazz : e.getCompilationUnit().getTypeDecls()) {
 638                 ClassTree ct = (ClassTree) clazz;
 639 
 640                 for (Tree member : ct.getMembers()) {
 641                     if (member.getKind() != Tree.Kind.VARIABLE)
 642                         continue;
 643                     VarSymbol vsym = ((JCVariableDecl) member).sym;
 644                     Type original = var2OriginalType.remove(vsym);
 645                     if (original != null) {
 646                         vsym.type = original;
 647                     }
 648                 }
 649             }
 650         }
 651 
 652         private boolean variablesSet = false;
 653 
 654         @Override
 655         public void finished(TaskEvent e) {
 656             if (e.getKind() != TaskEvent.Kind.ENTER || variablesSet)
 657                 return ;
 658             state.maps
 659                  .snippetList()
 660                  .stream()
 661                  .filter(s -> s.status() == Status.VALID)
 662                  .filter(s -> s.kind() == Snippet.Kind.VAR)
 663                  .filter(s -> s.subKind() == Snippet.SubKind.VAR_DECLARATION_WITH_INITIALIZER_SUBKIND ||
 664                               s.subKind() == Snippet.SubKind.TEMP_VAR_EXPRESSION_SUBKIND)
 665                  .forEach(s -> setVariableType((VarSnippet) s));
 666             variablesSet = true;
 667         }
 668 
 669         /* If the snippet contain enhanced types, enhance the type of
 670          * the variable from snippet s to be the enhanced type.
 671          */
 672         private void setVariableType(VarSnippet s) {
 673             String typeName = s.fullTypeName;
 674 
 675             if (typeName == null)
 676                 return ;
 677 
 678             Symtab syms = Symtab.instance(context);
 679             Names names = Names.instance(context);
 680             Log log  = Log.instance(context);
 681             ParserFactory parserFactory = ParserFactory.instance(context);
 682             Attr attr = Attr.instance(context);
 683             Enter enter = Enter.instance(context);
 684             DisableAccessibilityResolve rs = (DisableAccessibilityResolve) Resolve.instance(context);
 685 
 686             //find the variable:
 687             ClassSymbol clazz = syms.getClass(syms.unnamedModule, names.fromString(s.classFullName()));
 688             if (clazz == null || !clazz.isCompleted())
 689                 return;
 690             VarSymbol field = (VarSymbol) clazz.members().findFirst(names.fromString(s.name()), sym -> sym.kind == Kinds.Kind.VAR);
 691 
 692             if (field != null && !var2OriginalType.containsKey(field)) {
 693                 //if it was not enhanced yet:
 694                 //ignore any errors:
 695                 JavaFileObject prev = log.useSource(null);
 696                 DiscardDiagnosticHandler h = new DiscardDiagnosticHandler(log);
 697                 try {
 698                     //parse the type as a cast, i.e. "(<typeName>) x". This is to support
 699                     //intersection types:
 700                     CharBuffer buf = CharBuffer.wrap(("(" + typeName +")x\u0000").toCharArray(), 0, typeName.length() + 3);
 701                     Parser parser = parserFactory.newParser(buf, false, false, false);
 702                     JCExpression expr = parser.parseExpression();
 703                     if (expr.hasTag(Tag.TYPECAST)) {
 704                         //if parsed OK, attribute and set the type:
 705                         var2OriginalType.put(field, field.type);
 706 
 707                         JCTypeCast tree = (JCTypeCast) expr;
 708                         rs.runWithoutAccessChecks(() -> {
 709                             field.type = attr.attribType(tree.clazz,
 710                                                          enter.getEnvs().iterator().next().enclClass.sym);
 711                         });
 712                     }
 713                 } finally {
 714                     log.popDiagnosticHandler(h);
 715                     log.useSource(prev);
 716                 }
 717             }
 718         }
 719     }
 720 
 721     private static final class DisableAccessibilityResolve extends Resolve {
 722 
 723         public static void preRegister(Context context) {
 724             if (context.get(Marker.class) == null) {
 725                 context.put(resolveKey, ((Factory<Resolve>) c -> new DisableAccessibilityResolve(c)));
 726                 context.put(Marker.class, new Marker());
 727             }
 728         }
 729 
 730         private boolean noAccessChecks;
 731 
 732         public DisableAccessibilityResolve(Context context) {
 733             super(context);
 734         }
 735 
 736         /**Run the given Runnable with all access checks disabled.
 737          *
 738          * @param r Runnnable to run
 739          */
 740         public void runWithoutAccessChecks(Runnable r) {
 741             boolean prevNoAccessCheckes = noAccessChecks;
 742             try {
 743                 noAccessChecks = true;
 744                 r.run();
 745             } finally {
 746                 noAccessChecks = prevNoAccessCheckes;
 747             }
 748         }
 749 
 750         @Override
 751         public boolean isAccessible(Env<AttrContext> env, TypeSymbol c, boolean checkInner) {
 752             if (noAccessChecks) return true;
 753             return super.isAccessible(env, c, checkInner);
 754         }
 755 
 756         @Override
 757         public boolean isAccessible(Env<AttrContext> env, Type site, Symbol sym, boolean checkInner) {
 758             if (noAccessChecks) return true;
 759             return super.isAccessible(env, site, sym, checkInner);
 760         }
 761 
 762         private static final class Marker {}
 763     }
 764 
 765 }