526 uv.substBounds(inferenceContext.inferenceVars(), inferenceContext.instTypes(), infer.types); |
525 uv.substBounds(inferenceContext.inferenceVars(), inferenceContext.instTypes(), infer.types); |
527 infer.checkCompatibleUpperBounds(uv, inferenceContext); |
526 infer.checkCompatibleUpperBounds(uv, inferenceContext); |
528 if (uv.inst != null) { |
527 if (uv.inst != null) { |
529 Type inst = uv.inst; |
528 Type inst = uv.inst; |
530 for (Type u : uv.getBounds(InferenceBound.UPPER)) { |
529 for (Type u : uv.getBounds(InferenceBound.UPPER)) { |
531 if (!infer.types.isSubtypeUnchecked(inst, inferenceContext.asFree(u), warn)) { |
530 if (!isSubtype(inst, inferenceContext.asFree(u), warn, infer)) { |
532 infer.reportBoundError(uv, BoundErrorKind.UPPER); |
531 infer.reportBoundError(uv, BoundErrorKind.UPPER); |
533 } |
532 } |
534 } |
533 } |
535 for (Type l : uv.getBounds(InferenceBound.LOWER)) { |
534 for (Type l : uv.getBounds(InferenceBound.LOWER)) { |
536 if (!infer.types.isSubtypeUnchecked(inferenceContext.asFree(l), inst, warn)) { |
535 if (!isSubtype(inferenceContext.asFree(l), inst, warn, infer)) { |
537 infer.reportBoundError(uv, BoundErrorKind.LOWER); |
536 infer.reportBoundError(uv, BoundErrorKind.LOWER); |
538 } |
537 } |
539 } |
538 } |
540 for (Type e : uv.getBounds(InferenceBound.EQ)) { |
539 for (Type e : uv.getBounds(InferenceBound.EQ)) { |
541 if (!infer.types.isSameType(inst, inferenceContext.asFree(e))) { |
540 if (!isSameType(inst, inferenceContext.asFree(e), infer)) { |
542 infer.reportBoundError(uv, BoundErrorKind.EQ); |
541 infer.reportBoundError(uv, BoundErrorKind.EQ); |
543 } |
542 } |
544 } |
543 } |
545 } |
544 } |
546 } |
545 } |
559 public void apply(UndetVar uv, InferenceContext inferenceContext, Warner warn) { |
558 public void apply(UndetVar uv, InferenceContext inferenceContext, Warner warn) { |
560 Infer infer = inferenceContext.infer(); |
559 Infer infer = inferenceContext.infer(); |
561 Type eq = null; |
560 Type eq = null; |
562 for (Type e : uv.getBounds(InferenceBound.EQ)) { |
561 for (Type e : uv.getBounds(InferenceBound.EQ)) { |
563 Assert.check(!inferenceContext.free(e)); |
562 Assert.check(!inferenceContext.free(e)); |
564 if (eq != null && !infer.types.isSameType(e, eq)) { |
563 if (eq != null && !isSameType(e, eq, infer)) { |
565 infer.reportBoundError(uv, BoundErrorKind.EQ); |
564 infer.reportBoundError(uv, BoundErrorKind.EQ); |
566 } |
565 } |
567 eq = e; |
566 eq = e; |
568 for (Type l : uv.getBounds(InferenceBound.LOWER)) { |
567 for (Type l : uv.getBounds(InferenceBound.LOWER)) { |
569 Assert.check(!inferenceContext.free(l)); |
568 Assert.check(!inferenceContext.free(l)); |
570 if (!infer.types.isSubtypeUnchecked(l, e, warn)) { |
569 if (!isSubtype(l, e, warn, infer)) { |
571 infer.reportBoundError(uv, BoundErrorKind.BAD_EQ_LOWER); |
570 infer.reportBoundError(uv, BoundErrorKind.BAD_EQ_LOWER); |
572 } |
571 } |
573 } |
572 } |
574 for (Type u : uv.getBounds(InferenceBound.UPPER)) { |
573 for (Type u : uv.getBounds(InferenceBound.UPPER)) { |
575 if (inferenceContext.free(u)) continue; |
574 if (inferenceContext.free(u)) continue; |
576 if (!infer.types.isSubtypeUnchecked(e, u, warn)) { |
575 if (!isSubtype(e, u, warn, infer)) { |
577 infer.reportBoundError(uv, BoundErrorKind.BAD_EQ_UPPER); |
576 infer.reportBoundError(uv, BoundErrorKind.BAD_EQ_UPPER); |
578 } |
577 } |
579 } |
578 } |
580 } |
579 } |
581 } |
580 } |
587 public void apply(UndetVar uv, InferenceContext inferenceContext, Warner warn) { |
586 public void apply(UndetVar uv, InferenceContext inferenceContext, Warner warn) { |
588 Infer infer = inferenceContext.infer(); |
587 Infer infer = inferenceContext.infer(); |
589 for (Type e : uv.getBounds(InferenceBound.EQ)) { |
588 for (Type e : uv.getBounds(InferenceBound.EQ)) { |
590 if (e.containsAny(inferenceContext.inferenceVars())) continue; |
589 if (e.containsAny(inferenceContext.inferenceVars())) continue; |
591 for (Type u : uv.getBounds(InferenceBound.UPPER)) { |
590 for (Type u : uv.getBounds(InferenceBound.UPPER)) { |
592 if (!infer.types.isSubtypeUnchecked(e, inferenceContext.asFree(u), warn)) { |
591 if (!isSubtype(e, inferenceContext.asFree(u), warn, infer)) { |
593 infer.reportBoundError(uv, BoundErrorKind.BAD_EQ_UPPER); |
592 infer.reportBoundError(uv, BoundErrorKind.BAD_EQ_UPPER); |
594 } |
593 } |
595 } |
594 } |
596 for (Type l : uv.getBounds(InferenceBound.LOWER)) { |
595 for (Type l : uv.getBounds(InferenceBound.LOWER)) { |
597 if (!infer.types.isSubtypeUnchecked(inferenceContext.asFree(l), e, warn)) { |
596 if (!isSubtype(inferenceContext.asFree(l), e, warn, infer)) { |
598 infer.reportBoundError(uv, BoundErrorKind.BAD_EQ_LOWER); |
597 infer.reportBoundError(uv, BoundErrorKind.BAD_EQ_LOWER); |
599 } |
598 } |
600 } |
599 } |
601 } |
600 } |
602 } |
601 } |
670 if (inferenceContext.inferenceVars().contains(b)) { |
669 if (inferenceContext.inferenceVars().contains(b)) { |
671 UndetVar uv2 = (UndetVar)inferenceContext.asFree(b); |
670 UndetVar uv2 = (UndetVar)inferenceContext.asFree(b); |
672 if (uv2.isCaptured()) continue; |
671 if (uv2.isCaptured()) continue; |
673 //alpha <: beta |
672 //alpha <: beta |
674 //0. set beta :> alpha |
673 //0. set beta :> alpha |
675 uv2.addBound(InferenceBound.LOWER, uv, infer.types); |
674 addBound(InferenceBound.LOWER, uv2, inferenceContext.asInstType(uv.qtype), infer); |
676 //1. copy alpha's lower to beta's |
675 //1. copy alpha's lower to beta's |
677 for (Type l : uv.getBounds(InferenceBound.LOWER)) { |
676 for (Type l : uv.getBounds(InferenceBound.LOWER)) { |
678 uv2.addBound(InferenceBound.LOWER, inferenceContext.asInstType(l), infer.types); |
677 addBound(InferenceBound.LOWER, uv2, inferenceContext.asInstType(l), infer); |
679 } |
678 } |
680 //2. copy beta's upper to alpha's |
679 //2. copy beta's upper to alpha's |
681 for (Type u : uv2.getBounds(InferenceBound.UPPER)) { |
680 for (Type u : uv2.getBounds(InferenceBound.UPPER)) { |
682 uv.addBound(InferenceBound.UPPER, inferenceContext.asInstType(u), infer.types); |
681 addBound(InferenceBound.UPPER, uv, inferenceContext.asInstType(u), infer); |
683 } |
682 } |
684 } |
683 } |
685 } |
684 } |
686 } |
685 } |
687 }, |
686 }, |
696 if (inferenceContext.inferenceVars().contains(b)) { |
695 if (inferenceContext.inferenceVars().contains(b)) { |
697 UndetVar uv2 = (UndetVar)inferenceContext.asFree(b); |
696 UndetVar uv2 = (UndetVar)inferenceContext.asFree(b); |
698 if (uv2.isCaptured()) continue; |
697 if (uv2.isCaptured()) continue; |
699 //alpha :> beta |
698 //alpha :> beta |
700 //0. set beta <: alpha |
699 //0. set beta <: alpha |
701 uv2.addBound(InferenceBound.UPPER, uv, infer.types); |
700 addBound(InferenceBound.UPPER, uv2, inferenceContext.asInstType(uv.qtype), infer); |
702 //1. copy alpha's upper to beta's |
701 //1. copy alpha's upper to beta's |
703 for (Type u : uv.getBounds(InferenceBound.UPPER)) { |
702 for (Type u : uv.getBounds(InferenceBound.UPPER)) { |
704 uv2.addBound(InferenceBound.UPPER, inferenceContext.asInstType(u), infer.types); |
703 addBound(InferenceBound.UPPER, uv2, inferenceContext.asInstType(u), infer); |
705 } |
704 } |
706 //2. copy beta's lower to alpha's |
705 //2. copy beta's lower to alpha's |
707 for (Type l : uv2.getBounds(InferenceBound.LOWER)) { |
706 for (Type l : uv2.getBounds(InferenceBound.LOWER)) { |
708 uv.addBound(InferenceBound.LOWER, inferenceContext.asInstType(l), infer.types); |
707 addBound(InferenceBound.LOWER, uv, inferenceContext.asInstType(l), infer); |
709 } |
708 } |
710 } |
709 } |
711 } |
710 } |
712 } |
711 } |
713 }, |
712 }, |
722 if (inferenceContext.inferenceVars().contains(b)) { |
721 if (inferenceContext.inferenceVars().contains(b)) { |
723 UndetVar uv2 = (UndetVar)inferenceContext.asFree(b); |
722 UndetVar uv2 = (UndetVar)inferenceContext.asFree(b); |
724 if (uv2.isCaptured()) continue; |
723 if (uv2.isCaptured()) continue; |
725 //alpha == beta |
724 //alpha == beta |
726 //0. set beta == alpha |
725 //0. set beta == alpha |
727 uv2.addBound(InferenceBound.EQ, uv, infer.types); |
726 addBound(InferenceBound.EQ, uv2, inferenceContext.asInstType(uv.qtype), infer); |
728 //1. copy all alpha's bounds to beta's |
727 //1. copy all alpha's bounds to beta's |
729 for (InferenceBound ib : InferenceBound.values()) { |
728 for (InferenceBound ib : InferenceBound.values()) { |
730 for (Type b2 : uv.getBounds(ib)) { |
729 for (Type b2 : uv.getBounds(ib)) { |
731 if (b2 != uv2) { |
730 if (b2 != uv2) { |
732 uv2.addBound(ib, inferenceContext.asInstType(b2), infer.types); |
731 addBound(ib, uv2, inferenceContext.asInstType(b2), infer); |
733 } |
732 } |
734 } |
733 } |
735 } |
734 } |
736 //2. copy all beta's bounds to alpha's |
735 //2. copy all beta's bounds to alpha's |
737 for (InferenceBound ib : InferenceBound.values()) { |
736 for (InferenceBound ib : InferenceBound.values()) { |
738 for (Type b2 : uv2.getBounds(ib)) { |
737 for (Type b2 : uv2.getBounds(ib)) { |
739 if (b2 != uv) { |
738 if (b2 != uv) { |
740 uv.addBound(ib, inferenceContext.asInstType(b2), infer.types); |
739 addBound(ib, uv, inferenceContext.asInstType(b2), infer); |
741 } |
740 } |
742 } |
741 } |
743 } |
742 } |
744 } |
743 } |
745 } |
744 } |
748 |
747 |
749 abstract void apply(UndetVar uv, InferenceContext inferenceContext, Warner warn); |
748 abstract void apply(UndetVar uv, InferenceContext inferenceContext, Warner warn); |
750 |
749 |
751 boolean accepts(UndetVar uv, InferenceContext inferenceContext) { |
750 boolean accepts(UndetVar uv, InferenceContext inferenceContext) { |
752 return !uv.isCaptured(); |
751 return !uv.isCaptured(); |
|
752 } |
|
753 |
|
754 boolean isSubtype(Type s, Type t, Warner warn, Infer infer) { |
|
755 return doIncorporationOp(IncorporationBinaryOpKind.IS_SUBTYPE, s, t, warn, infer); |
|
756 } |
|
757 |
|
758 boolean isSameType(Type s, Type t, Infer infer) { |
|
759 return doIncorporationOp(IncorporationBinaryOpKind.IS_SAME_TYPE, s, t, null, infer); |
|
760 } |
|
761 |
|
762 void addBound(InferenceBound ib, UndetVar uv, Type b, Infer infer) { |
|
763 doIncorporationOp(opFor(ib), uv, b, null, infer); |
|
764 } |
|
765 |
|
766 IncorporationBinaryOpKind opFor(InferenceBound boundKind) { |
|
767 switch (boundKind) { |
|
768 case EQ: |
|
769 return IncorporationBinaryOpKind.ADD_EQ_BOUND; |
|
770 case LOWER: |
|
771 return IncorporationBinaryOpKind.ADD_LOWER_BOUND; |
|
772 case UPPER: |
|
773 return IncorporationBinaryOpKind.ADD_UPPER_BOUND; |
|
774 default: |
|
775 Assert.error("Can't get here!"); |
|
776 return null; |
|
777 } |
|
778 } |
|
779 |
|
780 boolean doIncorporationOp(IncorporationBinaryOpKind opKind, Type op1, Type op2, Warner warn, Infer infer) { |
|
781 IncorporationBinaryOp newOp = infer.new IncorporationBinaryOp(opKind, op1, op2); |
|
782 Boolean res = infer.incorporationCache.get(newOp); |
|
783 if (res == null) { |
|
784 infer.incorporationCache.put(newOp, res = newOp.apply(warn)); |
|
785 } |
|
786 return res; |
753 } |
787 } |
754 } |
788 } |
755 |
789 |
756 /** incorporation steps to be executed when running in legacy mode */ |
790 /** incorporation steps to be executed when running in legacy mode */ |
757 EnumSet<IncorporationStep> incorporationStepsLegacy = EnumSet.of(IncorporationStep.EQ_CHECK_LEGACY); |
791 EnumSet<IncorporationStep> incorporationStepsLegacy = EnumSet.of(IncorporationStep.EQ_CHECK_LEGACY); |
758 |
792 |
759 /** incorporation steps to be executed when running in graph mode */ |
793 /** incorporation steps to be executed when running in graph mode */ |
760 EnumSet<IncorporationStep> incorporationStepsGraph = |
794 EnumSet<IncorporationStep> incorporationStepsGraph = |
761 EnumSet.complementOf(EnumSet.of(IncorporationStep.EQ_CHECK_LEGACY)); |
795 EnumSet.complementOf(EnumSet.of(IncorporationStep.EQ_CHECK_LEGACY)); |
|
796 |
|
797 /** |
|
798 * Three kinds of basic operation are supported as part of an incorporation step: |
|
799 * (i) subtype check, (ii) same type check and (iii) bound addition (either |
|
800 * upper/lower/eq bound). |
|
801 */ |
|
802 enum IncorporationBinaryOpKind { |
|
803 IS_SUBTYPE() { |
|
804 @Override |
|
805 boolean apply(Type op1, Type op2, Warner warn, Types types) { |
|
806 return types.isSubtypeUnchecked(op1, op2, warn); |
|
807 } |
|
808 }, |
|
809 IS_SAME_TYPE() { |
|
810 @Override |
|
811 boolean apply(Type op1, Type op2, Warner warn, Types types) { |
|
812 return types.isSameType(op1, op2); |
|
813 } |
|
814 }, |
|
815 ADD_UPPER_BOUND() { |
|
816 @Override |
|
817 boolean apply(Type op1, Type op2, Warner warn, Types types) { |
|
818 UndetVar uv = (UndetVar)op1; |
|
819 uv.addBound(InferenceBound.UPPER, op2, types); |
|
820 return true; |
|
821 } |
|
822 }, |
|
823 ADD_LOWER_BOUND() { |
|
824 @Override |
|
825 boolean apply(Type op1, Type op2, Warner warn, Types types) { |
|
826 UndetVar uv = (UndetVar)op1; |
|
827 uv.addBound(InferenceBound.LOWER, op2, types); |
|
828 return true; |
|
829 } |
|
830 }, |
|
831 ADD_EQ_BOUND() { |
|
832 @Override |
|
833 boolean apply(Type op1, Type op2, Warner warn, Types types) { |
|
834 UndetVar uv = (UndetVar)op1; |
|
835 uv.addBound(InferenceBound.EQ, op2, types); |
|
836 return true; |
|
837 } |
|
838 }; |
|
839 |
|
840 abstract boolean apply(Type op1, Type op2, Warner warn, Types types); |
|
841 } |
|
842 |
|
843 /** |
|
844 * This class encapsulates a basic incorporation operation; incorporation |
|
845 * operations takes two type operands and a kind. Each operation performed |
|
846 * during an incorporation round is stored in a cache, so that operations |
|
847 * are not executed unnecessarily (which would potentially lead to adding |
|
848 * same bounds over and over). |
|
849 */ |
|
850 class IncorporationBinaryOp { |
|
851 |
|
852 IncorporationBinaryOpKind opKind; |
|
853 Type op1; |
|
854 Type op2; |
|
855 |
|
856 IncorporationBinaryOp(IncorporationBinaryOpKind opKind, Type op1, Type op2) { |
|
857 this.opKind = opKind; |
|
858 this.op1 = op1; |
|
859 this.op2 = op2; |
|
860 } |
|
861 |
|
862 @Override |
|
863 public boolean equals(Object o) { |
|
864 if (!(o instanceof IncorporationBinaryOp)) { |
|
865 return false; |
|
866 } else { |
|
867 IncorporationBinaryOp that = (IncorporationBinaryOp)o; |
|
868 return opKind == that.opKind && |
|
869 types.isSameType(op1, that.op1, true) && |
|
870 types.isSameType(op2, that.op2, true); |
|
871 } |
|
872 } |
|
873 |
|
874 @Override |
|
875 public int hashCode() { |
|
876 int result = opKind.hashCode(); |
|
877 result *= 127; |
|
878 result += types.hashCode(op1); |
|
879 result *= 127; |
|
880 result += types.hashCode(op2); |
|
881 return result; |
|
882 } |
|
883 |
|
884 boolean apply(Warner warn) { |
|
885 return opKind.apply(op1, op2, warn, types); |
|
886 } |
|
887 } |
|
888 |
|
889 /** an incorporation cache keeps track of all executed incorporation-related operations */ |
|
890 Map<IncorporationBinaryOp, Boolean> incorporationCache = |
|
891 new HashMap<IncorporationBinaryOp, Boolean>(); |
762 |
892 |
763 /** |
893 /** |
764 * Make sure that the upper bounds we got so far lead to a solvable inference |
894 * Make sure that the upper bounds we got so far lead to a solvable inference |
765 * variable by making sure that a glb exists. |
895 * variable by making sure that a glb exists. |
766 */ |
896 */ |
892 */ |
1022 */ |
893 abstract class LeafSolver implements GraphStrategy { |
1023 abstract class LeafSolver implements GraphStrategy { |
894 public Node pickNode(InferenceGraph g) { |
1024 public Node pickNode(InferenceGraph g) { |
895 Assert.check(!g.nodes.isEmpty(), "No nodes to solve!"); |
1025 Assert.check(!g.nodes.isEmpty(), "No nodes to solve!"); |
896 return g.nodes.get(0); |
1026 return g.nodes.get(0); |
|
1027 } |
|
1028 |
|
1029 boolean isSubtype(Type s, Type t, Warner warn, Infer infer) { |
|
1030 return doIncorporationOp(IncorporationBinaryOpKind.IS_SUBTYPE, s, t, warn, infer); |
|
1031 } |
|
1032 |
|
1033 boolean isSameType(Type s, Type t, Infer infer) { |
|
1034 return doIncorporationOp(IncorporationBinaryOpKind.IS_SAME_TYPE, s, t, null, infer); |
|
1035 } |
|
1036 |
|
1037 void addBound(InferenceBound ib, UndetVar uv, Type b, Infer infer) { |
|
1038 doIncorporationOp(opFor(ib), uv, b, null, infer); |
|
1039 } |
|
1040 |
|
1041 IncorporationBinaryOpKind opFor(InferenceBound boundKind) { |
|
1042 switch (boundKind) { |
|
1043 case EQ: |
|
1044 return IncorporationBinaryOpKind.ADD_EQ_BOUND; |
|
1045 case LOWER: |
|
1046 return IncorporationBinaryOpKind.ADD_LOWER_BOUND; |
|
1047 case UPPER: |
|
1048 return IncorporationBinaryOpKind.ADD_UPPER_BOUND; |
|
1049 default: |
|
1050 Assert.error("Can't get here!"); |
|
1051 return null; |
|
1052 } |
|
1053 } |
|
1054 |
|
1055 boolean doIncorporationOp(IncorporationBinaryOpKind opKind, Type op1, Type op2, Warner warn, Infer infer) { |
|
1056 IncorporationBinaryOp newOp = infer.new IncorporationBinaryOp(opKind, op1, op2); |
|
1057 Boolean res = infer.incorporationCache.get(newOp); |
|
1058 if (res == null) { |
|
1059 infer.incorporationCache.put(newOp, res = newOp.apply(warn)); |
|
1060 } |
|
1061 return res; |
897 } |
1062 } |
898 } |
1063 } |
899 |
1064 |
900 /** |
1065 /** |
901 * This solver uses an heuristic to pick the best leaf - the heuristic |
1066 * This solver uses an heuristic to pick the best leaf - the heuristic |