diff a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java
@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.  Oracle designates this
@@ -196,19 +196,73 @@
         UPWARDS() {
             @Override
             ProjectionKind complement() {
                 return DOWNWARDS;
             }
+
+            @Override
+            boolean allowIntersectionTypes() {
+                return true;
+            }
+
+            @Override
+            ProjectionKind withIntersectionTypes(boolean allowIntersectionTypes) {
+                return allowIntersectionTypes ? this : UPWARDS_NO_INTERSECTION;
+            }
         },
         DOWNWARDS() {
             @Override
             ProjectionKind complement() {
                 return UPWARDS;
             }
+
+            @Override
+            boolean allowIntersectionTypes() {
+                return true;
+            }
+
+            @Override
+            ProjectionKind withIntersectionTypes(boolean allowIntersectionTypes) {
+                return allowIntersectionTypes ? this : DOWNWARDS_NO_INTERSECTION;
+            }
+        },
+        UPWARDS_NO_INTERSECTION() {
+            @Override
+            ProjectionKind complement() {
+                return DOWNWARDS_NO_INTERSECTION;
+            }
+
+            @Override
+            boolean allowIntersectionTypes() {
+                return false;
+            }
+
+            @Override
+            ProjectionKind withIntersectionTypes(boolean allowIntersectionTypes) {
+                return allowIntersectionTypes ? UPWARDS : this;
+            }
+        },
+        DOWNWARDS_NO_INTERSECTION() {
+            @Override
+            ProjectionKind complement() {
+                return UPWARDS_NO_INTERSECTION;
+            }
+
+            @Override
+            boolean allowIntersectionTypes() {
+                return false;
+            }
+
+            @Override
+            ProjectionKind withIntersectionTypes(boolean allowIntersectionTypes) {
+                return allowIntersectionTypes ? DOWNWARDS : this;
+            }
         };
 
         abstract ProjectionKind complement();
+        abstract boolean allowIntersectionTypes();
+        abstract ProjectionKind withIntersectionTypes(boolean allowIntersectionTypes);
     }
 
     /**
      * This visitor performs upwards and downwards projections on types.
      *
@@ -243,15 +297,22 @@
             this.vars = vars;
         }
 
         @Override
         public Type visitClassType(ClassType t, ProjectionKind pkind) {
-            if (t.isCompound()) {
-                List<Type> components = directSupertypes(t);
-                List<Type> components1 = components.map(c -> c.map(this, pkind));
-                if (components == components1) return t;
-                else return makeIntersectionType(components1);
+            if (t.isUnion() || t.isIntersection()) {
+                if (pkind.allowIntersectionTypes()) {
+                    List<Type> components = directSupertypes(t);
+                    List<Type> components1 = components.map(c -> c.map(this, pkind));
+                    if (components == components1) return t;
+                    else return makeIntersectionType(components1);
+                } else if (t.isIntersection()) {
+                    return visit(((IntersectionClassType)t).getExplicitComponents().head, pkind);
+                } else {
+                    Assert.check(t.isUnion());
+                    return visit(((UnionClassType)t).getLub(), pkind);
+                }
             } else {
                 Type outer = t.getEnclosingType();
                 Type outer1 = visit(outer, pkind);
                 List<Type> typarams = t.getTypeArguments();
                 List<Type> formals = t.tsym.type.getTypeArguments();
@@ -302,13 +363,15 @@
                 if (seen.add(t)) {
                     try {
                         final Type bound;
                         switch (pkind) {
                             case UPWARDS:
+                            case UPWARDS_NO_INTERSECTION:
                                 bound = t.getUpperBound();
                                 break;
                             case DOWNWARDS:
+                            case DOWNWARDS_NO_INTERSECTION:
                                 bound = (t.getLowerBound() == null) ?
                                         syms.botType :
                                         t.getLowerBound();
                                 break;
                             default:
@@ -319,20 +382,20 @@
                     } finally {
                         seen.remove(t);
                     }
                 } else {
                     //cycle
-                    return pkind == ProjectionKind.UPWARDS ?
+                    return (pkind == ProjectionKind.UPWARDS || pkind == ProjectionKind.UPWARDS_NO_INTERSECTION) ?
                             syms.objectType : syms.botType;
                 }
             } else {
                 return t;
             }
         }
 
         private Type mapTypeArgument(Type site, Type declaredBound, Type t, ProjectionKind pkind) {
-            return t.containsAny(vars) ?
+            return (t.containsAny(vars) || (!pkind.allowIntersectionTypes() && !chk.checkDenotable(t))) ?
                     t.map(new TypeArgumentProjection(site, declaredBound), pkind) :
                     t;
         }
 
         class TypeArgumentProjection extends TypeMapping<ProjectionKind> {
@@ -346,25 +409,25 @@
             }
 
             @Override
             public Type visitType(Type t, ProjectionKind pkind) {
                 //type argument is some type containing restricted vars
-                if (pkind == ProjectionKind.DOWNWARDS) {
+                if (pkind == ProjectionKind.DOWNWARDS || pkind == ProjectionKind.DOWNWARDS_NO_INTERSECTION) {
                     //not defined
                     return syms.botType;
                 }
-                Type upper = t.map(TypeProjection.this, ProjectionKind.UPWARDS);
+                Type upper = t.map(TypeProjection.this, ProjectionKind.UPWARDS.withIntersectionTypes(pkind.allowIntersectionTypes()));
                 Type lower = t.map(TypeProjection.this, ProjectionKind.DOWNWARDS);
                 List<Type> formals = site.tsym.type.getTypeArguments();
                 BoundKind bk;
                 Type bound;
                 if (!isSameType(upper, syms.objectType) &&
                         (declaredBound.containsAny(formals) ||
                          !isSubtype(declaredBound, upper))) {
                     bound = upper;
                     bk = EXTENDS;
-                } else if (!lower.hasTag(BOT)) {
+                } else if (!lower.hasTag(BOT) && (!lower.isIntersection() || pkind.allowIntersectionTypes())) {
                     bound = lower;
                     bk = SUPER;
                 } else {
                     bound = syms.objectType;
                     bk = UNBOUND;
@@ -383,12 +446,12 @@
                         if (bound.hasTag(BOT)) {
                             return syms.botType;
                         }
                         break;
                     case SUPER:
-                        bound = wt.type.map(TypeProjection.this, pkind.complement());
-                        if (bound.hasTag(BOT)) {
+                        bound = wt.type.map(TypeProjection.this, pkind.withIntersectionTypes(true).complement());
+                        if (bound.hasTag(BOT) || (bound.isIntersection() && !pkind.allowIntersectionTypes())) {
                             bound = syms.objectType;
                             bk = UNBOUND;
                         }
                         break;
                 }
@@ -412,11 +475,24 @@
      * @param t the type to be projected
      * @param vars the set of type variables to be mapped
      * @return the type obtained as result of the projection
      */
     public Type upward(Type t, List<Type> vars) {
-        return t.map(new TypeProjection(vars), ProjectionKind.UPWARDS);
+        return upward(t, true, vars);
+    }
+
+    /**
+     * Computes an upward projection of given type, and vars. See {@link TypeProjection}.
+     *
+     * @param t the type to be projected
+     * @param allowIntersection whether intersection types should be allowed in the projection
+     * @param vars the set of type variables to be mapped
+     * @return the type obtained as result of the projection
+     */
+    public Type upward(Type t, boolean allowIntersection, List<Type> vars) {
+        return t.map(new TypeProjection(vars),
+                allowIntersection ? ProjectionKind.UPWARDS : ProjectionKind.UPWARDS_NO_INTERSECTION);
     }
 
     /**
      * Computes the set of captured variables mentioned in a given type. See {@link CaptureScanner}.
      * This routine is typically used to computed the input set of variables to be used during
@@ -5320,6 +5396,12 @@
         isDerivedRawCache.clear();
         implCache._map.clear();
         membersCache._map.clear();
         closureCache.clear();
     }
+
+    // code reflection
+
+    public boolean isQuoted(Type type) {
+        return type.tsym == syms.quotedType.tsym;
+    }
 }
