langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java
changeset 18911 dcc1e26a8c9c
parent 18910 c967bfda9283
child 18916 d93bea397df9
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java	Wed Jul 17 14:09:46 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java	Wed Jul 17 14:11:41 2013 +0100
@@ -159,7 +159,8 @@
                     !warn.hasNonSilentLint(Lint.LintCategory.UNCHECKED)) {
                 //inject return constraints earlier
                 checkWithinBounds(inferenceContext, warn); //propagation
-                generateReturnConstraints(resultInfo, mt, inferenceContext);
+                Type newRestype = generateReturnConstraints(resultInfo, mt, inferenceContext);
+                mt = (MethodType)types.createMethodTypeWithReturn(mt, newRestype);
                 //propagate outwards if needed
                 if (resultInfo.checkContext.inferenceContext().free(resultInfo.pt)) {
                     //propagate inference context outwards and exit
@@ -209,9 +210,20 @@
      * call occurs in a context where a type T is expected, use the expected
      * type to derive more constraints on the generic method inference variables.
      */
-    void generateReturnConstraints(Attr.ResultInfo resultInfo,
+    Type generateReturnConstraints(Attr.ResultInfo resultInfo,
             MethodType mt, InferenceContext inferenceContext) {
-        Type qtype1 = inferenceContext.asFree(mt.getReturnType());
+        Type from = mt.getReturnType();
+        if (mt.getReturnType().containsAny(inferenceContext.inferencevars) &&
+                resultInfo.checkContext.inferenceContext() != emptyContext) {
+            from = types.capture(from);
+            //add synthetic captured ivars
+            for (Type t : from.getTypeArguments()) {
+                if (t.hasTag(TYPEVAR) && ((TypeVar)t).isCaptured()) {
+                    inferenceContext.addVar((TypeVar)t);
+                }
+            }
+        }
+        Type qtype1 = inferenceContext.asFree(from);
         Type to = returnConstraintTarget(qtype1, resultInfo.pt);
         Assert.check(allowGraphInference || !resultInfo.checkContext.inferenceContext().free(to),
                 "legacy inference engine cannot handle constraints on both sides of a subtyping assertion");
@@ -224,6 +236,7 @@
                     .setMessage("infer.no.conforming.instance.exists",
                     inferenceContext.restvars(), mt.getReturnType(), to);
         }
+        return from;
     }
 
     Type returnConstraintTarget(Type from, Type to) {
@@ -436,7 +449,9 @@
                     EnumSet<IncorporationStep> incorporationSteps = allowGraphInference ?
                             incorporationStepsGraph : incorporationStepsLegacy;
                     for (IncorporationStep is : incorporationSteps) {
-                        is.apply(uv, inferenceContext, warn);
+                        if (is.accepts(uv, inferenceContext)) {
+                            is.apply(uv, inferenceContext, warn);
+                        }
                     }
                 }
                 if (!mlistener.changed || !allowGraphInference) break;
@@ -527,6 +542,11 @@
                     }
                 }
             }
+            @Override
+            boolean accepts(UndetVar uv, InferenceContext inferenceContext) {
+                //applies to all undetvars
+                return true;
+            }
         },
         /**
          * Check consistency of equality constraints. This is a slightly more aggressive
@@ -647,6 +667,7 @@
                 for (Type b : uv.getBounds(InferenceBound.UPPER)) {
                     if (inferenceContext.inferenceVars().contains(b)) {
                         UndetVar uv2 = (UndetVar)inferenceContext.asFree(b);
+                        if (uv2.isCaptured()) continue;
                         //alpha <: beta
                         //0. set beta :> alpha
                         uv2.addBound(InferenceBound.LOWER, uv, infer.types);
@@ -672,6 +693,7 @@
                 for (Type b : uv.getBounds(InferenceBound.LOWER)) {
                     if (inferenceContext.inferenceVars().contains(b)) {
                         UndetVar uv2 = (UndetVar)inferenceContext.asFree(b);
+                        if (uv2.isCaptured()) continue;
                         //alpha :> beta
                         //0. set beta <: alpha
                         uv2.addBound(InferenceBound.UPPER, uv, infer.types);
@@ -697,6 +719,7 @@
                 for (Type b : uv.getBounds(InferenceBound.EQ)) {
                     if (inferenceContext.inferenceVars().contains(b)) {
                         UndetVar uv2 = (UndetVar)inferenceContext.asFree(b);
+                        if (uv2.isCaptured()) continue;
                         //alpha == beta
                         //0. set beta == alpha
                         uv2.addBound(InferenceBound.EQ, uv, infer.types);
@@ -722,6 +745,10 @@
         };
 
         abstract void apply(UndetVar uv, InferenceContext inferenceContext, Warner warn);
+
+        boolean accepts(UndetVar uv, InferenceContext inferenceContext) {
+            return !uv.isCaptured();
+        }
     }
 
     /** incorporation steps to be executed when running in legacy mode */
@@ -1027,13 +1054,36 @@
         UPPER_LEGACY(InferenceBound.UPPER) {
             @Override
             public boolean accepts(UndetVar t, InferenceContext inferenceContext) {
-                return !inferenceContext.free(t.getBounds(ib));
+                return !inferenceContext.free(t.getBounds(ib)) && !t.isCaptured();
             }
 
             @Override
             Type solve(UndetVar uv, InferenceContext inferenceContext) {
                 return UPPER.solve(uv, inferenceContext);
             }
+        },
+        /**
+         * Like the former; the only difference is that this step can only be applied
+         * if all upper/lower bounds are ground.
+         */
+        CAPTURED(InferenceBound.UPPER) {
+            @Override
+            public boolean accepts(UndetVar t, InferenceContext inferenceContext) {
+                return !inferenceContext.free(t.getBounds(InferenceBound.UPPER, InferenceBound.LOWER));
+            }
+
+            @Override
+            Type solve(UndetVar uv, InferenceContext inferenceContext) {
+                Infer infer = inferenceContext.infer();
+                Type upper = UPPER.filterBounds(uv, inferenceContext).nonEmpty() ?
+                        UPPER.solve(uv, inferenceContext) :
+                        infer.syms.objectType;
+                Type lower = LOWER.filterBounds(uv, inferenceContext).nonEmpty() ?
+                        LOWER.solve(uv, inferenceContext) :
+                        infer.syms.botType;
+                CapturedType prevCaptured = (CapturedType)uv.qtype;
+                return new CapturedType(prevCaptured.tsym.name, prevCaptured.tsym.owner, upper, lower, prevCaptured.wildcard);
+            }
         };
 
         final InferenceBound ib;
@@ -1052,7 +1102,7 @@
          * Can the inference variable be instantiated using this step?
          */
         public boolean accepts(UndetVar t, InferenceContext inferenceContext) {
-            return filterBounds(t, inferenceContext).nonEmpty();
+            return filterBounds(t, inferenceContext).nonEmpty() && !t.isCaptured();
         }
 
         /**
@@ -1089,7 +1139,7 @@
 
         EQ(EnumSet.of(InferenceStep.EQ)),
         EQ_LOWER(EnumSet.of(InferenceStep.EQ, InferenceStep.LOWER)),
-        EQ_LOWER_THROWS_UPPER(EnumSet.of(InferenceStep.EQ, InferenceStep.LOWER, InferenceStep.THROWS, InferenceStep.UPPER));
+        EQ_LOWER_THROWS_UPPER_CAPTURED(EnumSet.of(InferenceStep.EQ, InferenceStep.LOWER, InferenceStep.UPPER, InferenceStep.THROWS, InferenceStep.CAPTURED));
 
         final EnumSet<InferenceStep> steps;
 
@@ -1350,12 +1400,26 @@
             Mapping fromTypeVarFun = new Mapping("fromTypeVarFunWithBounds") {
                 // mapping that turns inference variables into undet vars
                 public Type apply(Type t) {
-                    if (t.hasTag(TYPEVAR)) return new UndetVar((TypeVar)t, types);
-                    else return t.map(this);
+                    if (t.hasTag(TYPEVAR)) {
+                        TypeVar tv = (TypeVar)t;
+                        return tv.isCaptured() ?
+                                new CapturedUndetVar((CapturedType)tv, types) :
+                                new UndetVar(tv, types);
+                    } else {
+                        return t.map(this);
+                    }
                 }
             };
 
         /**
+         * add a new inference var to this inference context
+         */
+        void addVar(TypeVar t) {
+            this.undetvars = this.undetvars.prepend(fromTypeVarFun.apply(t));
+            this.inferencevars = this.inferencevars.prepend(t);
+        }
+
+        /**
          * returns the list of free variables (as type-variables) in this
          * inference context
          */