src/share/classes/com/sun/tools/javac/code/Types.java

changeset 1348
573ceb23beeb
parent 1347
1408af4cd8b0
child 1357
c75be5bc5283
     1.1 --- a/src/share/classes/com/sun/tools/javac/code/Types.java	Thu Oct 04 13:04:53 2012 +0100
     1.2 +++ b/src/share/classes/com/sun/tools/javac/code/Types.java	Fri Oct 05 14:35:24 2012 +0100
     1.3 @@ -79,8 +79,10 @@
     1.4      final boolean allowObjectToPrimitiveCast;
     1.5      final ClassReader reader;
     1.6      final Check chk;
     1.7 +    JCDiagnostic.Factory diags;
     1.8      List<Warner> warnStack = List.nil();
     1.9      final Name capturedName;
    1.10 +    private final FunctionDescriptorLookupError functionDescriptorLookupError;
    1.11  
    1.12      // <editor-fold defaultstate="collapsed" desc="Instantiating">
    1.13      public static Types instance(Context context) {
    1.14 @@ -102,6 +104,8 @@
    1.15          chk = Check.instance(context);
    1.16          capturedName = names.fromString("<captured wildcard>");
    1.17          messages = JavacMessages.instance(context);
    1.18 +        diags = JCDiagnostic.Factory.instance(context);
    1.19 +        functionDescriptorLookupError = new FunctionDescriptorLookupError();
    1.20      }
    1.21      // </editor-fold>
    1.22  
    1.23 @@ -296,6 +300,294 @@
    1.24      }
    1.25      // </editor-fold>
    1.26  
    1.27 +    // <editor-fold defaultstate="collapsed" desc="findSam">
    1.28 +
    1.29 +    /**
    1.30 +     * Exception used to report a function descriptor lookup failure. The exception
    1.31 +     * wraps a diagnostic that can be used to generate more details error
    1.32 +     * messages.
    1.33 +     */
    1.34 +    public static class FunctionDescriptorLookupError extends RuntimeException {
    1.35 +        private static final long serialVersionUID = 0;
    1.36 +
    1.37 +        JCDiagnostic diagnostic;
    1.38 +
    1.39 +        FunctionDescriptorLookupError() {
    1.40 +            this.diagnostic = null;
    1.41 +        }
    1.42 +
    1.43 +        FunctionDescriptorLookupError setMessage(JCDiagnostic diag) {
    1.44 +            this.diagnostic = diag;
    1.45 +            return this;
    1.46 +        }
    1.47 +
    1.48 +        public JCDiagnostic getDiagnostic() {
    1.49 +            return diagnostic;
    1.50 +        }
    1.51 +    }
    1.52 +
    1.53 +    /**
    1.54 +     * A cache that keeps track of function descriptors associated with given
    1.55 +     * functional interfaces.
    1.56 +     */
    1.57 +    class DescriptorCache {
    1.58 +
    1.59 +        private WeakHashMap<TypeSymbol, Entry> _map = new WeakHashMap<TypeSymbol, Entry>();
    1.60 +
    1.61 +        class FunctionDescriptor {
    1.62 +            Symbol descSym;
    1.63 +
    1.64 +            FunctionDescriptor(Symbol descSym) {
    1.65 +                this.descSym = descSym;
    1.66 +            }
    1.67 +
    1.68 +            public Symbol getSymbol() {
    1.69 +                return descSym;
    1.70 +            }
    1.71 +
    1.72 +            public Type getType(Type origin) {
    1.73 +                return memberType(origin, descSym);
    1.74 +            }
    1.75 +        }
    1.76 +
    1.77 +        class Entry {
    1.78 +            final FunctionDescriptor cachedDescRes;
    1.79 +            final int prevMark;
    1.80 +
    1.81 +            public Entry(FunctionDescriptor cachedDescRes,
    1.82 +                    int prevMark) {
    1.83 +                this.cachedDescRes = cachedDescRes;
    1.84 +                this.prevMark = prevMark;
    1.85 +            }
    1.86 +
    1.87 +            boolean matches(int mark) {
    1.88 +                return  this.prevMark == mark;
    1.89 +            }
    1.90 +        }
    1.91 +
    1.92 +        FunctionDescriptor get(TypeSymbol origin) throws FunctionDescriptorLookupError {
    1.93 +            Entry e = _map.get(origin);
    1.94 +            CompoundScope members = membersClosure(origin.type, false);
    1.95 +            if (e == null ||
    1.96 +                    !e.matches(members.getMark())) {
    1.97 +                FunctionDescriptor descRes = findDescriptorInternal(origin, members);
    1.98 +                _map.put(origin, new Entry(descRes, members.getMark()));
    1.99 +                return descRes;
   1.100 +            }
   1.101 +            else {
   1.102 +                return e.cachedDescRes;
   1.103 +            }
   1.104 +        }
   1.105 +
   1.106 +        /**
   1.107 +         * Scope filter used to skip methods that should be ignored during
   1.108 +         * function interface conversion (such as methods overridden by
   1.109 +         * j.l.Object)
   1.110 +         */
   1.111 +        class DescriptorFilter implements Filter<Symbol> {
   1.112 +
   1.113 +            TypeSymbol origin;
   1.114 +
   1.115 +            DescriptorFilter(TypeSymbol origin) {
   1.116 +                this.origin = origin;
   1.117 +            }
   1.118 +
   1.119 +            @Override
   1.120 +            public boolean accepts(Symbol sym) {
   1.121 +                    return sym.kind == Kinds.MTH &&
   1.122 +                            (sym.flags() & ABSTRACT) != 0 &&
   1.123 +                            !overridesObjectMethod(origin, sym) &&
   1.124 +                            notOverridden(sym);
   1.125 +            }
   1.126 +
   1.127 +            private boolean notOverridden(Symbol msym) {
   1.128 +                Symbol impl = ((MethodSymbol)msym).implementation(origin, Types.this, false);
   1.129 +                return impl == null || (impl.flags() & ABSTRACT) != 0;
   1.130 +            }
   1.131 +        };
   1.132 +
   1.133 +        /**
   1.134 +         * Compute the function descriptor associated with a given functional interface
   1.135 +         */
   1.136 +        public FunctionDescriptor findDescriptorInternal(TypeSymbol origin, CompoundScope membersCache) throws FunctionDescriptorLookupError {
   1.137 +            if (!origin.isInterface()) {
   1.138 +                //t must be an interface
   1.139 +                throw failure("not.a.functional.intf");
   1.140 +            }
   1.141 +
   1.142 +            final ListBuffer<Symbol> abstracts = ListBuffer.lb();
   1.143 +            for (Symbol sym : membersCache.getElements(new DescriptorFilter(origin))) {
   1.144 +                Type mtype = memberType(origin.type, sym);
   1.145 +                if (abstracts.isEmpty() ||
   1.146 +                        (sym.name == abstracts.first().name &&
   1.147 +                        overrideEquivalent(mtype, memberType(origin.type, abstracts.first())))) {
   1.148 +                    abstracts.append(sym);
   1.149 +                } else {
   1.150 +                    //the target method(s) should be the only abstract members of t
   1.151 +                    throw failure("not.a.functional.intf.1",
   1.152 +                            diags.fragment("incompatible.abstracts", Kinds.kindName(origin), origin));
   1.153 +                }
   1.154 +            }
   1.155 +            if (abstracts.isEmpty()) {
   1.156 +                //t must define a suitable non-generic method
   1.157 +                throw failure("not.a.functional.intf.1",
   1.158 +                            diags.fragment("no.abstracts", Kinds.kindName(origin), origin));
   1.159 +            } else if (abstracts.size() == 1) {
   1.160 +                if (abstracts.first().type.tag == FORALL) {
   1.161 +                    throw failure("invalid.generic.desc.in.functional.intf",
   1.162 +                            abstracts.first(),
   1.163 +                            Kinds.kindName(origin),
   1.164 +                            origin);
   1.165 +                } else {
   1.166 +                    return new FunctionDescriptor(abstracts.first());
   1.167 +                }
   1.168 +            } else { // size > 1
   1.169 +                for (Symbol msym : abstracts) {
   1.170 +                    if (msym.type.tag == FORALL) {
   1.171 +                        throw failure("invalid.generic.desc.in.functional.intf",
   1.172 +                                abstracts.first(),
   1.173 +                                Kinds.kindName(origin),
   1.174 +                                origin);
   1.175 +                    }
   1.176 +                }
   1.177 +                FunctionDescriptor descRes = mergeDescriptors(origin, abstracts.toList());
   1.178 +                if (descRes == null) {
   1.179 +                    //we can get here if the functional interface is ill-formed
   1.180 +                    ListBuffer<JCDiagnostic> descriptors = ListBuffer.lb();
   1.181 +                    for (Symbol desc : abstracts) {
   1.182 +                        String key = desc.type.getThrownTypes().nonEmpty() ?
   1.183 +                                "descriptor.throws" : "descriptor";
   1.184 +                        descriptors.append(diags.fragment(key, desc.name,
   1.185 +                                desc.type.getParameterTypes(),
   1.186 +                                desc.type.getReturnType(),
   1.187 +                                desc.type.getThrownTypes()));
   1.188 +                    }
   1.189 +                    JCDiagnostic.MultilineDiagnostic incompatibleDescriptors =
   1.190 +                            new JCDiagnostic.MultilineDiagnostic(diags.fragment("incompatible.descs.in.functional.intf",
   1.191 +                            Kinds.kindName(origin), origin), descriptors.toList());
   1.192 +                    throw failure(incompatibleDescriptors);
   1.193 +                }
   1.194 +                return descRes;
   1.195 +            }
   1.196 +        }
   1.197 +
   1.198 +        /**
   1.199 +         * Compute a synthetic type for the target descriptor given a list
   1.200 +         * of override-equivalent methods in the functional interface type.
   1.201 +         * The resulting method type is a method type that is override-equivalent
   1.202 +         * and return-type substitutable with each method in the original list.
   1.203 +         */
   1.204 +        private FunctionDescriptor mergeDescriptors(TypeSymbol origin, List<Symbol> methodSyms) {
   1.205 +            //pick argument types - simply take the signature that is a
   1.206 +            //subsignature of all other signatures in the list (as per JLS 8.4.2)
   1.207 +            List<Symbol> mostSpecific = List.nil();
   1.208 +            outer: for (Symbol msym1 : methodSyms) {
   1.209 +                Type mt1 = memberType(origin.type, msym1);
   1.210 +                for (Symbol msym2 : methodSyms) {
   1.211 +                    Type mt2 = memberType(origin.type, msym2);
   1.212 +                    if (!isSubSignature(mt1, mt2)) {
   1.213 +                        continue outer;
   1.214 +                    }
   1.215 +                }
   1.216 +                mostSpecific = mostSpecific.prepend(msym1);
   1.217 +            }
   1.218 +            if (mostSpecific.isEmpty()) {
   1.219 +                return null;
   1.220 +            }
   1.221 +
   1.222 +
   1.223 +            //pick return types - this is done in two phases: (i) first, the most
   1.224 +            //specific return type is chosen using strict subtyping; if this fails,
   1.225 +            //a second attempt is made using return type substitutability (see JLS 8.4.5)
   1.226 +            boolean phase2 = false;
   1.227 +            Symbol bestSoFar = null;
   1.228 +            while (bestSoFar == null) {
   1.229 +                outer: for (Symbol msym1 : mostSpecific) {
   1.230 +                    Type mt1 = memberType(origin.type, msym1);
   1.231 +                    for (Symbol msym2 : methodSyms) {
   1.232 +                        Type mt2 = memberType(origin.type, msym2);
   1.233 +                        if (phase2 ?
   1.234 +                                !returnTypeSubstitutable(mt1, mt2) :
   1.235 +                                !isSubtypeInternal(mt1.getReturnType(), mt2.getReturnType())) {
   1.236 +                            continue outer;
   1.237 +                        }
   1.238 +                    }
   1.239 +                    bestSoFar = msym1;
   1.240 +                }
   1.241 +                if (phase2) {
   1.242 +                    break;
   1.243 +                } else {
   1.244 +                    phase2 = true;
   1.245 +                }
   1.246 +            }
   1.247 +            if (bestSoFar == null) return null;
   1.248 +
   1.249 +            //merge thrown types - form the intersection of all the thrown types in
   1.250 +            //all the signatures in the list
   1.251 +            List<Type> thrown = null;
   1.252 +            for (Symbol msym1 : methodSyms) {
   1.253 +                Type mt1 = memberType(origin.type, msym1);
   1.254 +                thrown = (thrown == null) ?
   1.255 +                    mt1.getThrownTypes() :
   1.256 +                    chk.intersect(mt1.getThrownTypes(), thrown);
   1.257 +            }
   1.258 +
   1.259 +            final List<Type> thrown1 = thrown;
   1.260 +            return new FunctionDescriptor(bestSoFar) {
   1.261 +                @Override
   1.262 +                public Type getType(Type origin) {
   1.263 +                    Type mt = memberType(origin, getSymbol());
   1.264 +                    return new MethodType(mt.getParameterTypes(), mt.getReturnType(), thrown1, syms.methodClass);
   1.265 +                }
   1.266 +            };
   1.267 +        }
   1.268 +
   1.269 +        boolean isSubtypeInternal(Type s, Type t) {
   1.270 +            return (s.isPrimitive() && t.isPrimitive()) ?
   1.271 +                    isSameType(t, s) :
   1.272 +                    isSubtype(s, t);
   1.273 +        }
   1.274 +
   1.275 +        FunctionDescriptorLookupError failure(String msg, Object... args) {
   1.276 +            return failure(diags.fragment(msg, args));
   1.277 +        }
   1.278 +
   1.279 +        FunctionDescriptorLookupError failure(JCDiagnostic diag) {
   1.280 +            return functionDescriptorLookupError.setMessage(diag);
   1.281 +        }
   1.282 +    }
   1.283 +
   1.284 +    private DescriptorCache descCache = new DescriptorCache();
   1.285 +
   1.286 +    /**
   1.287 +     * Find the method descriptor associated to this class symbol - if the
   1.288 +     * symbol 'origin' is not a functional interface, an exception is thrown.
   1.289 +     */
   1.290 +    public Symbol findDescriptorSymbol(TypeSymbol origin) throws FunctionDescriptorLookupError {
   1.291 +        return descCache.get(origin).getSymbol();
   1.292 +    }
   1.293 +
   1.294 +    /**
   1.295 +     * Find the type of the method descriptor associated to this class symbol -
   1.296 +     * if the symbol 'origin' is not a functional interface, an exception is thrown.
   1.297 +     */
   1.298 +    public Type findDescriptorType(Type origin) throws FunctionDescriptorLookupError {
   1.299 +        return descCache.get(origin.tsym).getType(origin);
   1.300 +    }
   1.301 +
   1.302 +    /**
   1.303 +     * Is given type a functional interface?
   1.304 +     */
   1.305 +    public boolean isFunctionalInterface(TypeSymbol tsym) {
   1.306 +        try {
   1.307 +            findDescriptorSymbol(tsym);
   1.308 +            return true;
   1.309 +        } catch (FunctionDescriptorLookupError ex) {
   1.310 +            return false;
   1.311 +        }
   1.312 +    }
   1.313 +    // </editor-fold>
   1.314 +
   1.315      // <editor-fold defaultstate="collapsed" desc="isSubtype">
   1.316      /**
   1.317       * Is t an unchecked subtype of s?
   1.318 @@ -1215,7 +1507,10 @@
   1.319       * Returns the lower bounds of the formals of a method.
   1.320       */
   1.321      public List<Type> lowerBoundArgtypes(Type t) {
   1.322 -        return map(t.getParameterTypes(), lowerBoundMapping);
   1.323 +        return lowerBounds(t.getParameterTypes());
   1.324 +    }
   1.325 +    public List<Type> lowerBounds(List<Type> ts) {
   1.326 +        return map(ts, lowerBoundMapping);
   1.327      }
   1.328      private final Mapping lowerBoundMapping = new Mapping("lowerBound") {
   1.329              public Type apply(Type t) {
   1.330 @@ -2007,6 +2302,15 @@
   1.331              hasSameArgs(t, erasure(s)) || hasSameArgs(erasure(t), s);
   1.332      }
   1.333  
   1.334 +    public boolean overridesObjectMethod(TypeSymbol origin, Symbol msym) {
   1.335 +        for (Scope.Entry e = syms.objectType.tsym.members().lookup(msym.name) ; e.scope != null ; e = e.next()) {
   1.336 +            if (msym.overrides(e.sym, origin, Types.this, true)) {
   1.337 +                return true;
   1.338 +            }
   1.339 +        }
   1.340 +        return false;
   1.341 +    }
   1.342 +
   1.343      // <editor-fold defaultstate="collapsed" desc="Determining method implementation in given site">
   1.344      class ImplementationCache {
   1.345  

mercurial