81 |
82 |
82 protected DeferredAttr(Context context) { |
83 protected DeferredAttr(Context context) { |
83 context.put(deferredAttrKey, this); |
84 context.put(deferredAttrKey, this); |
84 attr = Attr.instance(context); |
85 attr = Attr.instance(context); |
85 chk = Check.instance(context); |
86 chk = Check.instance(context); |
|
87 diags = JCDiagnostic.Factory.instance(context); |
86 enter = Enter.instance(context); |
88 enter = Enter.instance(context); |
87 infer = Infer.instance(context); |
89 infer = Infer.instance(context); |
88 log = Log.instance(context); |
90 log = Log.instance(context); |
89 syms = Symtab.instance(context); |
91 syms = Symtab.instance(context); |
90 make = TreeMaker.instance(context); |
92 make = TreeMaker.instance(context); |
91 types = Types.instance(context); |
93 types = Types.instance(context); |
92 } |
94 Names names = Names.instance(context); |
|
95 stuckTree = make.Ident(names.empty).setType(Type.noType); |
|
96 } |
|
97 |
|
98 /** shared tree for stuck expressions */ |
|
99 final JCTree stuckTree; |
93 |
100 |
94 /** |
101 /** |
95 * This type represents a deferred type. A deferred type starts off with |
102 * This type represents a deferred type. A deferred type starts off with |
96 * no information on the underlying expression type. Such info needs to be |
103 * no information on the underlying expression type. Such info needs to be |
97 * discovered through type-checking the deferred type against a target-type. |
104 * discovered through type-checking the deferred type against a target-type. |
354 Set<Type> stuckVars = new LinkedHashSet<Type>(); |
361 Set<Type> stuckVars = new LinkedHashSet<Type>(); |
355 boolean progress = false; |
362 boolean progress = false; |
356 //scan a defensive copy of the node list - this is because a deferred |
363 //scan a defensive copy of the node list - this is because a deferred |
357 //attribution round can add new nodes to the list |
364 //attribution round can add new nodes to the list |
358 for (DeferredAttrNode deferredAttrNode : List.from(deferredAttrNodes)) { |
365 for (DeferredAttrNode deferredAttrNode : List.from(deferredAttrNodes)) { |
359 if (!deferredAttrNode.isStuck()) { |
366 if (!deferredAttrNode.process()) { |
360 deferredAttrNode.process(); |
367 stuckVars.addAll(deferredAttrNode.stuckVars); |
|
368 } else { |
361 deferredAttrNodes.remove(deferredAttrNode); |
369 deferredAttrNodes.remove(deferredAttrNode); |
362 progress = true; |
370 progress = true; |
363 } else { |
|
364 stuckVars.addAll(deferredAttrNode.stuckVars); |
|
365 } |
371 } |
366 } |
372 } |
367 if (!progress) { |
373 if (!progress) { |
368 //remove all variables that have already been instantiated |
374 //remove all variables that have already been instantiated |
369 //from the list of stuck variables |
375 //from the list of stuck variables |
402 stuckVars = List.nil(); |
408 stuckVars = List.nil(); |
403 resultInfo = resultInfo.dup(inferenceContext.asInstType(resultInfo.pt, types)); |
409 resultInfo = resultInfo.dup(inferenceContext.asInstType(resultInfo.pt, types)); |
404 } |
410 } |
405 |
411 |
406 /** |
412 /** |
407 * is this node stuck? |
|
408 */ |
|
409 boolean isStuck() { |
|
410 return stuckVars.nonEmpty(); |
|
411 } |
|
412 |
|
413 /** |
|
414 * Process a deferred attribution node. |
413 * Process a deferred attribution node. |
415 * Invariant: a stuck node cannot be processed. |
414 * Invariant: a stuck node cannot be processed. |
416 */ |
415 */ |
417 void process() { |
416 @SuppressWarnings("fallthrough") |
418 if (isStuck()) { |
417 boolean process() { |
419 throw new IllegalStateException("Cannot process a stuck deferred node"); |
418 switch (mode) { |
420 } |
419 case SPECULATIVE: |
421 dt.check(resultInfo); |
420 dt.check(resultInfo, List.<Type>nil(), new StructuralStuckChecker()); |
|
421 return true; |
|
422 case CHECK: |
|
423 if (stuckVars.nonEmpty()) { |
|
424 return false; |
|
425 } else { |
|
426 dt.check(resultInfo, stuckVars, basicCompleter); |
|
427 return true; |
|
428 } |
|
429 default: |
|
430 throw new AssertionError("Bad mode"); |
|
431 } |
|
432 } |
|
433 |
|
434 /** |
|
435 * Structural checker for stuck expressions |
|
436 */ |
|
437 class StructuralStuckChecker extends TreeScanner implements DeferredTypeCompleter { |
|
438 |
|
439 ResultInfo resultInfo; |
|
440 |
|
441 public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) { |
|
442 this.resultInfo = resultInfo; |
|
443 dt.tree.accept(this); |
|
444 dt.speculativeCache.put(msym, stuckTree, phase); |
|
445 return Type.noType; |
|
446 } |
|
447 |
|
448 @Override |
|
449 public void visitLambda(JCLambda tree) { |
|
450 Check.CheckContext checkContext = resultInfo.checkContext; |
|
451 Type pt = resultInfo.pt; |
|
452 if (inferenceContext.inferencevars.contains(pt)) { |
|
453 //ok |
|
454 return; |
|
455 } else { |
|
456 //must be a functional descriptor |
|
457 try { |
|
458 Type desc = types.findDescriptorType(pt); |
|
459 if (desc.getParameterTypes().length() != tree.params.length()) { |
|
460 checkContext.report(tree, diags.fragment("incompatible.arg.types.in.lambda")); |
|
461 } |
|
462 } catch (Types.FunctionDescriptorLookupError ex) { |
|
463 checkContext.report(null, ex.getDiagnostic()); |
|
464 } |
|
465 } |
|
466 } |
|
467 |
|
468 @Override |
|
469 public void visitNewClass(JCNewClass tree) { |
|
470 //do nothing |
|
471 } |
|
472 |
|
473 @Override |
|
474 public void visitApply(JCMethodInvocation tree) { |
|
475 //do nothing |
|
476 } |
|
477 |
|
478 @Override |
|
479 public void visitReference(JCMemberReference tree) { |
|
480 Check.CheckContext checkContext = resultInfo.checkContext; |
|
481 Type pt = resultInfo.pt; |
|
482 if (inferenceContext.inferencevars.contains(pt)) { |
|
483 //ok |
|
484 return; |
|
485 } else { |
|
486 try { |
|
487 //TODO: we should speculative determine if there's a match |
|
488 //based on arity - if yes, method is applicable. |
|
489 types.findDescriptorType(pt); |
|
490 } catch (Types.FunctionDescriptorLookupError ex) { |
|
491 checkContext.report(null, ex.getDiagnostic()); |
|
492 } |
|
493 } |
|
494 } |
422 } |
495 } |
423 } |
496 } |
424 } |
497 } |
425 |
498 |
426 /** an empty deferred attribution context - all methods throw exceptions */ |
499 /** an empty deferred attribution context - all methods throw exceptions */ |
622 @Override |
695 @Override |
623 public void visitLambda(JCLambda tree) { |
696 public void visitLambda(JCLambda tree) { |
624 if (inferenceContext.inferenceVars().contains(pt)) { |
697 if (inferenceContext.inferenceVars().contains(pt)) { |
625 stuckVars.add(pt); |
698 stuckVars.add(pt); |
626 } |
699 } |
627 if (!types.isFunctionalInterface(pt.tsym)) { |
700 if (!types.isFunctionalInterface(pt)) { |
628 return; |
701 return; |
629 } |
702 } |
630 Type descType = types.findDescriptorType(pt); |
703 Type descType = types.findDescriptorType(pt); |
631 List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes()); |
704 List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes()); |
632 if (!TreeInfo.isExplicitLambda(tree) && |
705 if (tree.paramKind == JCLambda.ParameterKind.IMPLICIT && |
633 freeArgVars.nonEmpty()) { |
706 freeArgVars.nonEmpty()) { |
634 stuckVars.addAll(freeArgVars); |
707 stuckVars.addAll(freeArgVars); |
635 } |
708 } |
636 scanLambdaBody(tree, descType.getReturnType()); |
709 scanLambdaBody(tree, descType.getReturnType()); |
637 } |
710 } |