798 }; |
798 }; |
799 lambdaScanner.scan(lambda.body); |
799 lambdaScanner.scan(lambda.body); |
800 } |
800 } |
801 } |
801 } |
802 } |
802 } |
|
803 |
|
804 /** |
|
805 * Does the argument expression {@code expr} need speculative type-checking? |
|
806 */ |
|
807 boolean isDeferred(Env<AttrContext> env, JCExpression expr) { |
|
808 DeferredChecker dc = new DeferredChecker(env); |
|
809 dc.scan(expr); |
|
810 return dc.result.isPoly(); |
|
811 } |
|
812 |
|
813 /** |
|
814 * The kind of an argument expression. This is used by the analysis that |
|
815 * determines as to whether speculative attribution is necessary. |
|
816 */ |
|
817 enum ArgumentExpressionKind { |
|
818 |
|
819 /** kind that denotes poly argument expression */ |
|
820 POLY, |
|
821 /** kind that denotes a standalone expression */ |
|
822 NO_POLY, |
|
823 /** kind that denotes a primitive/boxed standalone expression */ |
|
824 PRIMITIVE; |
|
825 |
|
826 /** |
|
827 * Does this kind denote a poly argument expression |
|
828 */ |
|
829 public final boolean isPoly() { |
|
830 return this == POLY; |
|
831 } |
|
832 |
|
833 /** |
|
834 * Does this kind denote a primitive standalone expression |
|
835 */ |
|
836 public final boolean isPrimitive() { |
|
837 return this == PRIMITIVE; |
|
838 } |
|
839 |
|
840 /** |
|
841 * Compute the kind of a standalone expression of a given type |
|
842 */ |
|
843 static ArgumentExpressionKind standaloneKind(Type type, Types types) { |
|
844 return types.unboxedTypeOrType(type).isPrimitive() ? |
|
845 ArgumentExpressionKind.PRIMITIVE : |
|
846 ArgumentExpressionKind.NO_POLY; |
|
847 } |
|
848 |
|
849 /** |
|
850 * Compute the kind of a method argument expression given its symbol |
|
851 */ |
|
852 static ArgumentExpressionKind methodKind(Symbol sym, Types types) { |
|
853 Type restype = sym.type.getReturnType(); |
|
854 if (sym.type.hasTag(FORALL) && |
|
855 restype.containsAny(((ForAll)sym.type).tvars)) { |
|
856 return ArgumentExpressionKind.POLY; |
|
857 } else { |
|
858 return ArgumentExpressionKind.standaloneKind(restype, types); |
|
859 } |
|
860 } |
|
861 } |
|
862 |
|
863 /** |
|
864 * Tree scanner used for checking as to whether an argument expression |
|
865 * requires speculative attribution |
|
866 */ |
|
867 final class DeferredChecker extends FilterScanner { |
|
868 |
|
869 Env<AttrContext> env; |
|
870 ArgumentExpressionKind result; |
|
871 |
|
872 public DeferredChecker(Env<AttrContext> env) { |
|
873 super(deferredCheckerTags); |
|
874 this.env = env; |
|
875 } |
|
876 |
|
877 @Override |
|
878 public void visitLambda(JCLambda tree) { |
|
879 //a lambda is always a poly expression |
|
880 result = ArgumentExpressionKind.POLY; |
|
881 } |
|
882 |
|
883 @Override |
|
884 public void visitReference(JCMemberReference tree) { |
|
885 //a method reference is always a poly expression |
|
886 result = ArgumentExpressionKind.POLY; |
|
887 } |
|
888 |
|
889 @Override |
|
890 public void visitTypeCast(JCTypeCast tree) { |
|
891 //a cast is always a standalone expression |
|
892 result = ArgumentExpressionKind.NO_POLY; |
|
893 } |
|
894 |
|
895 @Override |
|
896 public void visitConditional(JCConditional tree) { |
|
897 scan(tree.truepart); |
|
898 if (!result.isPrimitive()) { |
|
899 result = ArgumentExpressionKind.POLY; |
|
900 return; |
|
901 } |
|
902 scan(tree.falsepart); |
|
903 result = reduce(ArgumentExpressionKind.PRIMITIVE); |
|
904 } |
|
905 |
|
906 @Override |
|
907 public void visitNewClass(JCNewClass tree) { |
|
908 result = (TreeInfo.isDiamond(tree) || attr.findDiamonds) ? |
|
909 ArgumentExpressionKind.POLY : ArgumentExpressionKind.NO_POLY; |
|
910 } |
|
911 |
|
912 @Override |
|
913 public void visitApply(JCMethodInvocation tree) { |
|
914 Name name = TreeInfo.name(tree.meth); |
|
915 |
|
916 //fast path |
|
917 if (tree.typeargs.nonEmpty() || |
|
918 name == name.table.names._this || |
|
919 name == name.table.names._super) { |
|
920 result = ArgumentExpressionKind.NO_POLY; |
|
921 return; |
|
922 } |
|
923 |
|
924 //slow path |
|
925 final JCExpression rec = tree.meth.hasTag(SELECT) ? |
|
926 ((JCFieldAccess)tree.meth).selected : |
|
927 null; |
|
928 |
|
929 if (rec != null && !isSimpleReceiver(rec)) { |
|
930 //give up if receiver is too complex (to cut down analysis time) |
|
931 result = ArgumentExpressionKind.POLY; |
|
932 return; |
|
933 } |
|
934 |
|
935 Type site = rec != null ? |
|
936 attribSpeculative(rec, env, attr.unknownTypeExprInfo).type : |
|
937 env.enclClass.sym.type; |
|
938 |
|
939 ListBuffer<Type> args = ListBuffer.lb(); |
|
940 for (int i = 0; i < tree.args.length(); i ++) { |
|
941 args.append(Type.noType); |
|
942 } |
|
943 |
|
944 Resolve.LookupHelper lh = rs.new LookupHelper(name, site, args.toList(), List.<Type>nil(), MethodResolutionPhase.VARARITY) { |
|
945 @Override |
|
946 Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) { |
|
947 return rec == null ? |
|
948 rs.findFun(env, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired()) : |
|
949 rs.findMethod(env, site, name, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired(), false); |
|
950 } |
|
951 @Override |
|
952 Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym) { |
|
953 return sym; |
|
954 } |
|
955 }; |
|
956 |
|
957 Symbol sym = rs.lookupMethod(env, tree, site.tsym, rs.arityMethodCheck, lh); |
|
958 |
|
959 if (sym.kind == Kinds.AMBIGUOUS) { |
|
960 Resolve.AmbiguityError err = (Resolve.AmbiguityError)sym.baseSymbol(); |
|
961 result = ArgumentExpressionKind.PRIMITIVE; |
|
962 for (List<Symbol> ambigousSyms = err.ambiguousSyms ; |
|
963 ambigousSyms.nonEmpty() && !result.isPoly() ; |
|
964 ambigousSyms = ambigousSyms.tail) { |
|
965 Symbol s = ambigousSyms.head; |
|
966 if (s.kind == Kinds.MTH) { |
|
967 result = reduce(ArgumentExpressionKind.methodKind(s, types)); |
|
968 } |
|
969 } |
|
970 } else { |
|
971 result = (sym.kind == Kinds.MTH) ? |
|
972 ArgumentExpressionKind.methodKind(sym, types) : |
|
973 ArgumentExpressionKind.NO_POLY; |
|
974 } |
|
975 } |
|
976 //where |
|
977 private boolean isSimpleReceiver(JCTree rec) { |
|
978 switch (rec.getTag()) { |
|
979 case IDENT: |
|
980 return true; |
|
981 case SELECT: |
|
982 return isSimpleReceiver(((JCFieldAccess)rec).selected); |
|
983 case TYPEAPPLY: |
|
984 case TYPEARRAY: |
|
985 return true; |
|
986 case ANNOTATED_TYPE: |
|
987 return isSimpleReceiver(((JCAnnotatedType)rec).underlyingType); |
|
988 default: |
|
989 return false; |
|
990 } |
|
991 } |
|
992 private ArgumentExpressionKind reduce(ArgumentExpressionKind kind) { |
|
993 switch (result) { |
|
994 case PRIMITIVE: return kind; |
|
995 case NO_POLY: return kind.isPoly() ? kind : result; |
|
996 case POLY: return result; |
|
997 default: |
|
998 Assert.error(); |
|
999 return null; |
|
1000 } |
|
1001 } |
|
1002 |
|
1003 @Override |
|
1004 public void visitLiteral(JCLiteral tree) { |
|
1005 Type litType = attr.litType(tree.typetag); |
|
1006 result = ArgumentExpressionKind.standaloneKind(litType, types); |
|
1007 } |
|
1008 |
|
1009 @Override |
|
1010 void skip(JCTree tree) { |
|
1011 result = ArgumentExpressionKind.NO_POLY; |
|
1012 } |
|
1013 } |
|
1014 //where |
|
1015 private EnumSet<JCTree.Tag> deferredCheckerTags = |
|
1016 EnumSet.of(LAMBDA, REFERENCE, PARENS, TYPECAST, |
|
1017 CONDEXPR, NEWCLASS, APPLY, LITERAL); |
803 } |
1018 } |