1.1 --- a/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Mon Jan 21 11:16:28 2013 -0800 1.2 +++ b/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Mon Jan 21 20:13:56 2013 +0000 1.3 @@ -65,6 +65,7 @@ 1.4 1.5 final Attr attr; 1.6 final Check chk; 1.7 + final JCDiagnostic.Factory diags; 1.8 final Enter enter; 1.9 final Infer infer; 1.10 final Log log; 1.11 @@ -83,14 +84,20 @@ 1.12 context.put(deferredAttrKey, this); 1.13 attr = Attr.instance(context); 1.14 chk = Check.instance(context); 1.15 + diags = JCDiagnostic.Factory.instance(context); 1.16 enter = Enter.instance(context); 1.17 infer = Infer.instance(context); 1.18 log = Log.instance(context); 1.19 syms = Symtab.instance(context); 1.20 make = TreeMaker.instance(context); 1.21 types = Types.instance(context); 1.22 + Names names = Names.instance(context); 1.23 + stuckTree = make.Ident(names.empty).setType(Type.noType); 1.24 } 1.25 1.26 + /** shared tree for stuck expressions */ 1.27 + final JCTree stuckTree; 1.28 + 1.29 /** 1.30 * This type represents a deferred type. A deferred type starts off with 1.31 * no information on the underlying expression type. Such info needs to be 1.32 @@ -356,12 +363,11 @@ 1.33 //scan a defensive copy of the node list - this is because a deferred 1.34 //attribution round can add new nodes to the list 1.35 for (DeferredAttrNode deferredAttrNode : List.from(deferredAttrNodes)) { 1.36 - if (!deferredAttrNode.isStuck()) { 1.37 - deferredAttrNode.process(); 1.38 + if (!deferredAttrNode.process()) { 1.39 + stuckVars.addAll(deferredAttrNode.stuckVars); 1.40 + } else { 1.41 deferredAttrNodes.remove(deferredAttrNode); 1.42 progress = true; 1.43 - } else { 1.44 - stuckVars.addAll(deferredAttrNode.stuckVars); 1.45 } 1.46 } 1.47 if (!progress) { 1.48 @@ -404,21 +410,88 @@ 1.49 } 1.50 1.51 /** 1.52 - * is this node stuck? 1.53 + * Process a deferred attribution node. 1.54 + * Invariant: a stuck node cannot be processed. 1.55 */ 1.56 - boolean isStuck() { 1.57 - return stuckVars.nonEmpty(); 1.58 + @SuppressWarnings("fallthrough") 1.59 + boolean process() { 1.60 + switch (mode) { 1.61 + case SPECULATIVE: 1.62 + dt.check(resultInfo, List.<Type>nil(), new StructuralStuckChecker()); 1.63 + return true; 1.64 + case CHECK: 1.65 + if (stuckVars.nonEmpty()) { 1.66 + return false; 1.67 + } else { 1.68 + dt.check(resultInfo, stuckVars, basicCompleter); 1.69 + return true; 1.70 + } 1.71 + default: 1.72 + throw new AssertionError("Bad mode"); 1.73 + } 1.74 } 1.75 1.76 /** 1.77 - * Process a deferred attribution node. 1.78 - * Invariant: a stuck node cannot be processed. 1.79 + * Structural checker for stuck expressions 1.80 */ 1.81 - void process() { 1.82 - if (isStuck()) { 1.83 - throw new IllegalStateException("Cannot process a stuck deferred node"); 1.84 + class StructuralStuckChecker extends TreeScanner implements DeferredTypeCompleter { 1.85 + 1.86 + ResultInfo resultInfo; 1.87 + 1.88 + public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) { 1.89 + this.resultInfo = resultInfo; 1.90 + dt.tree.accept(this); 1.91 + dt.speculativeCache.put(msym, stuckTree, phase); 1.92 + return Type.noType; 1.93 } 1.94 - dt.check(resultInfo); 1.95 + 1.96 + @Override 1.97 + public void visitLambda(JCLambda tree) { 1.98 + Check.CheckContext checkContext = resultInfo.checkContext; 1.99 + Type pt = resultInfo.pt; 1.100 + if (inferenceContext.inferencevars.contains(pt)) { 1.101 + //ok 1.102 + return; 1.103 + } else { 1.104 + //must be a functional descriptor 1.105 + try { 1.106 + Type desc = types.findDescriptorType(pt); 1.107 + if (desc.getParameterTypes().length() != tree.params.length()) { 1.108 + checkContext.report(tree, diags.fragment("incompatible.arg.types.in.lambda")); 1.109 + } 1.110 + } catch (Types.FunctionDescriptorLookupError ex) { 1.111 + checkContext.report(null, ex.getDiagnostic()); 1.112 + } 1.113 + } 1.114 + } 1.115 + 1.116 + @Override 1.117 + public void visitNewClass(JCNewClass tree) { 1.118 + //do nothing 1.119 + } 1.120 + 1.121 + @Override 1.122 + public void visitApply(JCMethodInvocation tree) { 1.123 + //do nothing 1.124 + } 1.125 + 1.126 + @Override 1.127 + public void visitReference(JCMemberReference tree) { 1.128 + Check.CheckContext checkContext = resultInfo.checkContext; 1.129 + Type pt = resultInfo.pt; 1.130 + if (inferenceContext.inferencevars.contains(pt)) { 1.131 + //ok 1.132 + return; 1.133 + } else { 1.134 + try { 1.135 + //TODO: we should speculative determine if there's a match 1.136 + //based on arity - if yes, method is applicable. 1.137 + types.findDescriptorType(pt); 1.138 + } catch (Types.FunctionDescriptorLookupError ex) { 1.139 + checkContext.report(null, ex.getDiagnostic()); 1.140 + } 1.141 + } 1.142 + } 1.143 } 1.144 } 1.145 } 1.146 @@ -624,12 +697,12 @@ 1.147 if (inferenceContext.inferenceVars().contains(pt)) { 1.148 stuckVars.add(pt); 1.149 } 1.150 - if (!types.isFunctionalInterface(pt.tsym)) { 1.151 + if (!types.isFunctionalInterface(pt)) { 1.152 return; 1.153 } 1.154 Type descType = types.findDescriptorType(pt); 1.155 List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes()); 1.156 - if (!TreeInfo.isExplicitLambda(tree) && 1.157 + if (tree.paramKind == JCLambda.ParameterKind.IMPLICIT && 1.158 freeArgVars.nonEmpty()) { 1.159 stuckVars.addAll(freeArgVars); 1.160 } 1.161 @@ -643,7 +716,7 @@ 1.162 stuckVars.add(pt); 1.163 return; 1.164 } 1.165 - if (!types.isFunctionalInterface(pt.tsym)) { 1.166 + if (!types.isFunctionalInterface(pt)) { 1.167 return; 1.168 } 1.169