root/trunk/ProjectFortress/src/com/sun/fortress/interpreter/evaluator/values/OverloadedFunction.java

Revision 4192, 35.6 KB (checked in by sukyoungryu, 2 months ago)

[environment] Fixed handling of operators with different fixities as overloaded operators.

Line 
1/*******************************************************************************
2 Copyright 2009 Sun Microsystems, Inc.,
3 4150 Network Circle, Santa Clara, California 95054, U.S.A.
4 All rights reserved.
5
6 U.S. Government Rights - Commercial software.
7 Government users are subject to the Sun Microsystems, Inc. standard
8 license agreement and applicable provisions of the FAR and its supplements.
9
10 Use is subject to license terms.
11
12 This distribution may include materials developed by third parties.
13
14 Sun, Sun Microsystems, the Sun logo and Java are trademarks or registered
15 trademarks of Sun Microsystems, Inc. in the U.S. and other countries.
16 ******************************************************************************/
17
18package com.sun.fortress.interpreter.evaluator.values;
19
20import com.sun.fortress.exceptions.FortressException;
21import static com.sun.fortress.exceptions.InterpreterBug.bug;
22import com.sun.fortress.exceptions.ProgramError;
23import static com.sun.fortress.exceptions.ProgramError.error;
24import static com.sun.fortress.exceptions.ProgramError.errorMsg;
25import com.sun.fortress.interpreter.evaluator.Environment;
26import com.sun.fortress.interpreter.evaluator.EvalType;
27import com.sun.fortress.interpreter.evaluator.EvaluatorBase;
28import com.sun.fortress.interpreter.evaluator.InstantiationLock;
29import com.sun.fortress.interpreter.evaluator.types.*;
30import com.sun.fortress.nodes.IdOrOpOrAnonymousName;
31import com.sun.fortress.nodes.Op;
32import com.sun.fortress.nodes.StaticArg;
33import com.sun.fortress.nodes.StaticParam;
34import com.sun.fortress.nodes_util.NodeUtil;
35import com.sun.fortress.useful.*;
36
37import java.util.*;
38
39public class OverloadedFunction extends Fcn implements Factory1P<List<FType>, Fcn, HasAt> {
40
41    private final boolean debug = false;
42    private final boolean debugMatch = false;
43    /**
44     * Disables ALL consistency checking of overloaded functions.
45     */
46    private final boolean noCheck = false;
47
48    protected volatile List<Overload> overloads = new ArrayList<Overload>();
49    protected List<Overload> pendingOverloads = new ArrayList<Overload>();
50    private Map<Overload, Overload> allOverloadsEver = new Hashtable<Overload, Overload>();
51    private volatile boolean needsInference;
52
53    protected volatile boolean finishedFirst = true; // an empty overload is consistent
54    protected volatile boolean finishedSecond = true;
55    protected IdOrOpOrAnonymousName fnName;
56
57    static final boolean DUMP_EXCLUSION = false;
58    static int excl_skip = 100000;
59
60    public static void exclDump(Object... os) {
61        if (DUMP_EXCLUSION && excl_skip <= 0) {
62            for (Object o : os) {
63                System.out.print(o);
64            }
65        }
66    }
67
68    public static void exclDumpln(Object... os) {
69        if (DUMP_EXCLUSION && excl_skip <= 0) {
70            for (Object o : os) {
71                System.out.print(o);
72            }
73            System.out.println();
74        } else {
75            excl_skip--;
76        }
77
78    }
79
80    public static void exclDumpSkip() {
81        if (DUMP_EXCLUSION && excl_skip > 0) {
82            System.out.print("excl_skip = " + excl_skip + "; ");
83        }
84    }
85
86    BATreeEC<List<FValue>, List<FType>, SingleFcn> cache =
87            new BATreeEC<List<FValue>, List<FType>, SingleFcn>(FValue.asTypesList);
88
89    @Override
90    public boolean needsInference() {
91        return needsInference;
92    }
93
94    public String getString() {
95        if (pendingOverloads.size() > 0) {
96            return Useful.listInDelimiters("{\n\t", overloads, " PENDING BELOW", "\n\t") + Useful.listInDelimiters(
97                    "\n*\t",
98                    pendingOverloads,
99                    "}",
100                    "\n*\t");
101        }
102        return Useful.listInDelimiters("{\n\t", overloads, "}", "\n\t");
103    }
104
105    public boolean getFinished() {
106        return finishedFirst;
107    }
108
109    public boolean getFinishedSecond() {
110        return finishedSecond;
111    }
112
113    public IdOrOpOrAnonymousName getFnName() {
114        return fnName;
115    }
116
117    public boolean seqv(FValue v) {
118        return false;
119    }
120
121    public boolean hasSelfDotMethodInvocation() {
122        return false;
123    }
124
125    public void finishInitializing() {
126        finishInitializingFirstPart();
127        finishInitializingSecondPart();
128        return;
129    }
130
131    /**
132     * The first part of finishing makes sure that all the
133     * Closures in the overload have their types assigned.
134     * It is not possible to Determine the goodness or badness
135     * of an overloading until actual types are known.
136     */
137    public void finishInitializingFirstPart() {
138        if (finishedFirst) return;
139
140        Overload ol;
141        for (int i = 0; i < pendingOverloads.size(); i++) {
142            // Cannot be an iterator -- will get comodification exception
143            // iteration to the growing end is perfectly ok.
144            ol = pendingOverloads.get(i);
145            SingleFcn sfcn = ol.getFn();
146
147            String ps = ol.ps != null ? String.valueOf(ol.ps) + " " : "";
148
149            if (sfcn instanceof FunctionClosure) {
150                FunctionClosure cl = (FunctionClosure) sfcn;
151                if (!cl.getFinished()) cl.finishInitializing();
152
153                if (debug) {
154                    System.err.println("Overload " + ps + cl);
155                }
156
157            } else if (sfcn instanceof Constructor) {
158                Constructor cl = (Constructor) sfcn;
159                if (!cl.getFinished()) cl.finishInitializing();
160
161                if (debug) {
162                    System.err.println("Overload " + ps + cl);
163                }
164
165            } else if (sfcn instanceof GenericConstructor) {
166                if (debug) {
167                    System.err.println("Overload " + ps + sfcn);
168                }
169
170            } else if (sfcn instanceof Dummy_fcn) {
171                if (debug) System.err.println("Overload primitive " + ps + sfcn);
172
173            } else if (sfcn instanceof FGenericFunction) {
174                if (debug) System.err.println("Overload generic " + ps + sfcn);
175
176            } else {
177                bug(errorMsg("Expected a closure or primitive, instead got ", sfcn));
178            }
179
180            if (ol.ps != null) ol.ps.close();
181        }
182        finishedFirst = true;
183    }
184
185    /**
186     * The second part of finishing ensures that the overloadings
187     * are consistent, and assigns a type to the value.
188     */
189    @SuppressWarnings ("unchecked")
190    public synchronized boolean finishInitializingSecondPart() {
191
192        boolean change = false;
193
194        if (finishedSecond) return change;
195
196        while (true) {
197
198            List<Overload> old_pendingOverloads = pendingOverloads;
199            pendingOverloads = new ArrayList<Overload>();
200            List<Overload> new_overloads = new ArrayList<Overload>();
201
202            for (Overload overload : old_pendingOverloads) {
203                // Duplicate detector
204                if (allOverloadsEver.containsKey(overload)) {
205                    SingleFcn thisFn = overload.getFn();
206                    SingleFcn otherFn = allOverloadsEver.get(overload).getFn();
207                    // Debugging output
208                    if (debug) {
209                        String ps = overload.ps != null ? String.valueOf(overload.ps) + " " : "";
210                        System.err.println("Not putting " + ps + overload + "\n   equal to " + otherFn);
211                    }
212                    continue;
213                } else {
214                    change = true;
215                    new_overloads.add(overload);
216                    allOverloadsEver.put(overload, overload);
217                }
218            }
219
220            if (new_overloads.size() == 0) {
221                bless();
222                return change;
223            }
224
225            new_overloads.addAll(overloads);
226
227            // Put shorter parameter lists first (it's a funny sort order).
228            // TODO I don't understand what's "unchecked" about the next line.
229            java.util.Collections.<Overload>sort(new_overloads);
230            ArrayList<FType> ftalist = new ArrayList<FType>(new_overloads.size());
231
232            OverloadComparisonResult ocr = new OverloadComparisonResult();
233
234            for (int i = 0; i < new_overloads.size(); i++) {
235                Overload o1 = new_overloads.get(i);
236                Fcn fn = o1.getFn();
237                if (fn instanceof GenericFunctionOrConstructor) {
238                    needsInference = true;
239                } else {
240                    FType ty = fn.type();
241                    if (ty != null) ftalist.add(ty);
242                }
243
244                if (!noCheck && !o1.guaranteedOK) {
245
246                    for (int j = i - 1; j >= 0; j--) {
247
248                        Overload o2 = new_overloads.get(j);
249                        if (o2.guaranteedOK) continue;
250                        SingleFcn f1 = o1.getFn();
251                        SingleFcn f2 = o2.getFn();
252
253                        if (genericFMAndInstance(f1, f2) || genericFMAndInstance(f2, f1)) continue;
254
255                        ocr.reset();
256                        ocr.completeOverloadingCheck(o1, o2, new_overloads, within);
257
258                    }
259                }
260            }
261            FType ftoa = FTypeOverloadedArrow.make(ftalist);
262            this.setFtypeUnconditionally(ftoa);
263            //String ftoas = ftoa.toString();
264            //System.err.println(ftoas);
265            this.overloads = new_overloads;
266
267            if (!finishedFirst) {
268                // Come here if we generated MORE overloads as a side-effect.
269                finishInitializingFirstPart();
270            }
271
272        }
273    }
274
275    // FUTURE REFACTORING -- the static methods below will
276    // become methods of this class.  The intent is to allow
277    // function-by-function queries from within a trait,
278    // to permit correctness/overlap checking of overrides.
279    public static class OverloadComparisonResult {
280        private int p1better; // set to index where p1 is subtype
281        private int p2better; // set to index where p2 is subtype
282        private boolean meetOk;
283
284        boolean distinct; // known to exclude
285        private int unrelated; // neither subtype nor exclude nor identical
286        private boolean unequal;
287        private boolean sawSymbolic1;
288        private boolean sawSymbolic2;
289        private int selfIndex;
290        private int min;
291        private boolean allObjInstance1;
292        private boolean allObjInstance2;
293        private boolean result1Subtype2Failure;
294        private boolean result2Subtype1Failure;
295
296        private int l1;
297        private int l2;
298        ;
299
300        private boolean rest1;
301        private boolean rest2;
302
303        public OverloadComparisonResult() {
304            reset();
305        }
306
307        public void reset() {
308            p1better = -1; // set to index where p1 is subtype
309            p2better = -1; // set to index where p2 is subtype
310
311            distinct = false; // known to exclude
312            unrelated = -1; // neither subtype nor exclude nor identical
313            unequal = false;
314            sawSymbolic1 = false;
315            sawSymbolic2 = false;
316            selfIndex = -1;
317            min = Integer.MAX_VALUE;
318            allObjInstance1 = true;
319            allObjInstance2 = true;
320            result1Subtype2Failure = false;
321            result2Subtype1Failure = false;
322
323            l1 = -1;
324            l2 = -2;
325            rest1 = false;
326            rest2 = false;
327            meetOk = false;
328
329        }
330
331        public void completeOverloadingCheck(Overload o1,
332                                             Overload o2,
333                                             Collection<Overload> new_overloads,
334                                             Environment within) {
335
336            OverloadComparisonResult ocr = this;
337
338            List<FType> pl1 = o1.getParams();
339            List<FType> pl2 = o2.getParams();
340
341            {
342                l1 = pl1.size();
343                l2 = pl2.size();
344
345                rest1 = (l1 > 0 && pl1.get(l1 - 1) instanceof FTypeRest);
346                rest2 = (l2 > 0 && pl2.get(l2 - 1) instanceof FTypeRest);
347
348                // by construction, l1 is bigger.
349                // (see sort order above)
350                // possibilities
351                // rest1 l2 can be no smaller than l1-1; iterate to l2
352                // rest2 test out to l1
353                // both  test out to l1
354                // neither = required
355
356
357                if (rest2) {
358                    // both, rest2
359                    min = l1;
360                } else if (rest1) {
361                    // rest1
362                    if (l2 < l1 - 1) return;
363                    min = l2;
364                } else {
365                    // neither
366                    if (l1 != l2) return;
367                    min = l1;
368                }
369
370                //    if (!do_continue) {
371
372
373                //                  int p1better = -1; // set to index where p1 is subtype
374                //                  int p2better = -1; // set to index where p2 is subtype
375
376                //                  boolean distinct = false; // known to exclude
377                //                  int unrelated = -1; // neither subtype nor exclude nor identical
378                //                  boolean unequal = false;
379                //                  boolean sawSymbolic1 = false;
380                //                  boolean sawSymbolic2 = false;
381                //                  int selfIndex = -1;
382
383                /* This is a hack for dealing with cases like
384                *
385  trait Bar[\A,nat n\]
386      get():ZZ32 = n
387  end
388
389  object Baz[\A,nat n\]() extends Bar[\A,n\]
390  end
391
392  f[\A\](x:Bar[\A,17\]) = 20
393  g[\A\](x:Baz[\A,17\]) = 21
394  h[\A\](x:Bar[\A,17\]) = 22
395  h[\A\](x:Baz[\A,17\]) = 23
396
397
398
399                */
400                //                  boolean allObjInstance1 = true;
401                //                  boolean allObjInstance2 = true;
402
403                exclDumpln("Checking exclusion of ", pl1, " and ", pl2, ":");
404                for (int k = 0; k < min; k++) {
405                    FType p1 = pl1.get(k);
406                    FType p2 = k < l2 ? pl2.get(k) : pl2.get(l2 - 1);
407                    exclDump(k, ": ", p1, " and ", p2, ", ", p1.getExtends(), " and ", p2.getExtends(), ", ");
408
409                    p1 = deRest(p1);
410                    p2 = deRest(p2);
411
412                    if (p1 == p2 && !p1.isSymbolic() && !p2.isSymbolic()) {
413                        exclDumpln("equal.");
414                        continue;
415                    }
416
417                    allObjInstance1 &= p1 instanceof FTypeObject;
418                    allObjInstance2 &= p2 instanceof FTypeObject;
419
420                    unequal = true;
421
422                    if (o1.getSelfParameterIndex() == k && o1.getSelfParameterIndex() == o2.getSelfParameterIndex()) {
423                        exclDumpln("self params.");
424                        // ONLY set this when the self indices coincide -- otherwise, they obey the same rules.
425                        selfIndex = k;
426                        /*
427                        * Somebody Else's Problem -- if self parameters are different,
428                        * any problems will be flagged at the object level.
429                        */
430                        if (!p1.equals(p2)) distinct = true; // This seems wrong/unnecessary
431                    }
432
433                    if ( o1.getFn().getFnName() instanceof Op &&
434                         o2.getFn().getFnName() instanceof Op &&
435                         ((Op)o1.getFn().getFnName()).getFixity() !=
436                         ((Op)o2.getFn().getFnName()).getFixity() )
437                        distinct = true;
438
439                    if (p1.excludesOther(p2)) {
440                        exclDumpln("distinct.");
441                        distinct = true;
442                    } else {
443
444                        boolean local_unrelated = true;
445                        // Check for subtype constraint.
446                        boolean p1subp2 = p1.subtypeOf(p2);
447                        boolean p2subp1 = p2.subtypeOf(p1);
448                        if (p1subp2 && !p2subp1) {
449                            p1better = k;
450                            local_unrelated = false;
451                            exclDumpln(" left better.");
452                        } else if (p2subp1 && !p1subp2) {
453                            p2better = k;
454                            local_unrelated = false;
455                            exclDumpln(" right better.");
456                        } else if (selfIndex != k) {
457                            if (p1.isSymbolic()) sawSymbolic1 = true;
458
459                            if (p2.isSymbolic()) sawSymbolic2 = true;
460                        }
461                        if (local_unrelated && unrelated == -1) {
462                            // Here we check for self parameters!
463                            if (selfIndex != k) {
464                                unrelated = k;
465                                exclDumpln("Unrelated.");
466                            }
467                        }
468                    }
469                }
470
471                distinct |= unequal && (allObjInstance1 || allObjInstance2);
472            }
473            //      }
474
475            if (!distinct) {
476                if (p1better >= 0 && p2better >= 0) {
477                    meetOk = meetExistsIn(o1, o2, new_overloads);
478                } else {
479                    FType r1 = o1.getFn().getRange();
480                    FType r2 = o2.getFn().getRange();
481                    if (p1better >= 0) {
482                        // subtype rule applies
483                        result1Subtype2Failure = !r1.subtypeOf(r2);
484                    } else if (p2better >= 0) {
485                        // subtype rule applies
486                        result2Subtype1Failure = !r2.subtypeOf(r1);
487                    }
488                }
489            }
490
491
492            describeOverloadingFailure(o1, o2, within, pl1, pl2);
493
494            return;
495        }
496
497        public boolean overloadOk() {
498
499            // exclusion is good.
500            if (distinct) return true;
501
502            // non-ground types need exclusion
503            if (sawSymbolic1 || sawSymbolic2 || unrelated != -1) {
504                return false;
505            }
506
507            // meet rule
508            if (p1better >= 0 && p2better >= 0 && !meetOk) return false;
509
510            // neither is better, not a functional method
511            if (p1better < 0 && p2better < 0 && selfIndex < 0) return false;
512
513            if (result1Subtype2Failure || result2Subtype1Failure) return false;
514
515            return true;
516        }
517
518        private void describeOverloadingFailure(Overload o1,
519                                                Overload o2,
520                                                Environment within,
521                                                List<FType> pl1,
522                                                List<FType> pl2) {
523            if (distinct) return;
524            OverloadComparisonResult ocr = this;
525            if (sawSymbolic1 || sawSymbolic2) {
526                exclDumpSkip();
527                String explanation;
528                if (sawSymbolic1 && sawSymbolic2) explanation = errorMsg("\n", o1, " and\n", o2, " have parameters\n");
529                else if (sawSymbolic1) explanation = errorMsg("\n", o1, " has a parameter\n");
530                else explanation = errorMsg("\n", o2, " has a parameter\n");
531                explanation =
532                        explanation + "with generic type, at least one pair of parameters must have excluding types";
533                error(o1, o2, within, explanation);
534            }
535
536            if (unrelated != -1) {
537                exclDumpSkip();
538                String s1 = parameterName(unrelated, o1);
539                String s2 = parameterName(unrelated, o2);
540
541                String explanation = errorMsg(Ordinal.ordinal(unrelated + 1),
542                                              " parameters ",
543                                              s1,
544                                              ":",
545                                              pl1,
546                                              " and ",
547                                              s2,
548                                              ":",
549                                              pl2,
550                                              " are unrelated (neither subtype, excludes, nor equal) and no excluding pair is present");
551                error(o1, o2, within, explanation);
552            }
553
554            if (p1better >= 0 && p2better >= 0 && !meetOk) {
555                exclDumpSkip();
556                error(o1, o2, within, errorMsg("Overloading of\n\t(first) ",
557                                               o1,
558                                               " and\n\t(second) ",
559                                               o2,
560                                               " fails because\n\t",
561                                               formatParameterComparison(p1better, o1, o2, "more"),
562                                               " but\n\t",
563                                               formatParameterComparison(p2better, o1, o2, "less")));
564            }
565            if (p1better < 0 && p2better < 0 && selfIndex < 0) {
566                exclDumpSkip();
567                String explanation = null;
568                if (l1 == l2 && rest1 == rest2) {
569                    if (unequal) explanation = errorMsg("Overloading of ",
570                                                        o1,
571                                                        " and ",
572                                                        o2,
573                                                        " fails because their parameter lists have potentially overlapping (non-excluding) types");
574                    else explanation = errorMsg("Overloading of ",
575                                                o1,
576                                                " and ",
577                                                o2,
578                                                " fails because their parameter lists have the same types");
579                } else explanation = errorMsg("Overloading of ",
580                                              o1,
581                                              " and ",
582                                              o2,
583                                              " fails because of ambiguity in overlapping rest (...) parameters");
584                error(o1, o2, within, explanation);
585            }
586
587            if (result1Subtype2Failure) {
588                String explanation = errorMsg("Overloading of ",
589                                              o1,
590                                              " and ",
591                                              o2,
592                                              " fails because the first parameter list is a subtype of the second, but the first result is not a subtype of the second");
593                // System.err.println("FAIL " + explanation);
594                error(o1, o2, within, explanation);
595            }
596            if (result2Subtype1Failure) {
597                String explanation = errorMsg("Overloading of ",
598                                              o1,
599                                              " and ",
600                                              o2,
601                                              " fails because the second parameter list is a subtype of the first, but the second result is not a subtype of the first");
602                // System.err.println("FAIL " + explanation);
603                error(o1, o2, within, explanation);
604            }
605
606        }
607    }
608
609    private boolean genericFMAndInstance(SingleFcn f1, SingleFcn f2) {
610        if (f1 instanceof GenericFunctionalMethod && f2 instanceof FunctionalMethod) {
611            GenericFunctionalMethod gfm = (GenericFunctionalMethod) f1;
612            FunctionalMethod fm = (FunctionalMethod) f2;
613            FTraitOrObjectOrGeneric tgfm = gfm.getSelfParameterType();
614            FTraitOrObjectOrGeneric tfm = fm.getSelfParameterType();
615            return tgfm.getDecl() == tfm.getDecl();
616        }
617        return false;
618    }
619
620    static private String formatParameterComparison(int i, Overload o1, Overload o2, String how) {
621        String s1 = parameterName(i, o1);
622        String s2 = parameterName(i, o2);
623        return "(first) " + s1 + " is " + how + " specific than (second) " + s2;
624    }
625
626    /**
627     * @param i
628     * @param f1
629     */
630    static private String parameterName(int i, Overload o) {
631        SingleFcn f1 = o.getFn();
632        String s1;
633        if (f1 instanceof NonPrimitive) {
634            NonPrimitive np = (NonPrimitive) f1;
635            s1 = np.getParameters().get(i).getName();
636        } else {
637            s1 = "parameter " + (i + 1);
638        }
639        return s1;
640    }
641
642    /**
643     * Computes a conservative meet of o1 and o2, and checks for its existence.
644     *
645     * @param o1
646     * @param o2
647     * @param overloads2
648     * @return
649     */
650    static private boolean meetExistsIn(Overload o1, Overload o2, Collection<Overload> overloads2) {
651        List<FType> pl1 = o1.getParams();
652        List<FType> pl2 = o2.getParams();
653
654        Set<List<FType>> meet_set = FTypeTuple.meet(pl1, pl2);
655
656        if (meet_set.size() != 1) return false;
657
658        List<FType> meet = meet_set.iterator().next();
659
660        for (Overload o : overloads2) {
661            if (meet.equals(o.getParams())) return true;
662        }
663        // TODO finish this.
664
665        return false;
666    }
667
668    static private FType deRest(FType p1) {
669        if (p1 instanceof FTypeRest) p1 = ((FTypeRest) p1).getType();
670        return p1;
671    }
672
673    /**
674     * Needs an environment to construct its supertype,
675     * but otherwise it is never examined.
676     *
677     * @param within
678     */
679    public OverloadedFunction(IdOrOpOrAnonymousName fnName, Environment within) {
680        super(within);
681        this.fnName = fnName;
682    }
683
684    public OverloadedFunction(IdOrOpOrAnonymousName fnName, Set<? extends Simple_fcn> ssf, Environment within) {
685        this(fnName, within);
686        for (Simple_fcn sf : ssf) {
687            addOverload(sf);
688        }
689        finishInitializingSecondPart();
690    }
691
692    public void addOverload(SingleFcn fn) {
693        //      if (finishedFirst && !fn.getFinished())
694        //          throw new IllegalStateException("Any functions added after finishedFirst must have types assigned.");
695        addOverload(new Overload(fn));
696    }
697
698    public void addOverload(SingleFcn fn, boolean guaranteedOK) {
699        //      if (finishedFirst && !fn.getFinished())
700        //          throw new IllegalStateException("Any functions added after finishedFirst must have types assigned.");
701        addOverload(new Overload(fn, this, guaranteedOK));
702    }
703
704    public void addOverloads(OverloadedFunction cls) {
705        if (cls == this) return; // Prevents a comodification exception if
706        // we import FortressLibrary a second time.
707
708        List<Overload> clso = cls.overloads;
709        for (Overload cl : clso) {
710            addOverload(cl);
711        }
712        clso = cls.pendingOverloads;
713        try {
714            for (Overload cl : clso) {
715
716                addOverload(cl);
717            }
718        }
719        catch (ConcurrentModificationException ex) {
720            bug("Whoops, concurrent modification");
721        }
722
723    }
724
725    /**
726     * Add an overload to the list of overloads. Not Allowed after the
727     * overloaded function has been (completely) finished.
728     *
729     * @param overload
730     */
731    public void addOverload(Overload overload) {
732
733        if (!finishedSecond) {
734            // Reset finishedFirst -- new overloads can appear as side-effect
735            // of finishing first overloads.
736            finishedFirst = false;
737            pendingOverloads.add(overload);
738            // InstantiationLock.lastOverload = this;
739            // InstantiationLock.lastOverloadThrowable = Useful.backtrace(0, 1000);
740        } else {
741            // InstantiationLock.L.lock();
742            if (debug) System.err.println("Lock " + fnName.stringName());
743            finishedFirst = false;
744            finishedSecond = false;
745            pendingOverloads.add(overload);
746            // InstantiationLock.lastOverload = this;
747            // InstantiationLock.lastOverloadThrowable = Useful.backtrace(0, 1000);
748        }
749
750        if (debug) {
751            DebugletPrintStream ps = DebugletPrintStream.make("OVERLOADS");
752            overload.ps = ps;
753            System.err.println("add " + ps + " " + overload);
754            ps.backtrace().flush();
755        }
756
757    }
758
759    // TODO continue audit of functions in here.
760    @Override
761    public FValue applyInnerPossiblyGeneric(List<FValue> args) {
762
763        SingleFcn best_f = cache.get(args);
764
765        if (best_f == null) {
766
767            best_f = bestMatch(args, overloads);
768
769            if (best_f instanceof FunctionalMethod) {
770                FunctionalMethod fm = (FunctionalMethod) best_f;
771                if (debugMatch) System.err.print("\nRefining functional method " + best_f);
772                best_f = fm.getApplicableClosure(args);
773            }
774            if (best_f instanceof GenericFunctionOrMethod) {
775                return bug(errorMsg("overload res yielded generic ", best_f));
776            }
777
778            if (debugMatch) System.err.println("Choosing " + best_f + " for args " + args);
779            cache.syncPut(args, best_f);
780        }
781
782        return best_f.applyInnerPossiblyGeneric(args);
783    }
784
785    /**
786     * Returns index of best match for args among the overloaded functions.
787     *
788     * @throws Error
789     */
790    public SingleFcn bestMatch(List<FValue> args, List<Overload> someOverloads) throws Error {
791        if (!finishedSecond && InstantiationLock.L.isHeldByCurrentThread()) bug("Cannot call before 'setFinished()'");
792
793        SingleFcn best = bestMatchInternal(args, someOverloads);
794        if (best == null) {
795            // TODO add checks for COERCE, right here.
796            // Replay the test for debugging
797            // best = bestMatchInternal(args, someOverloads);
798            error(errorMsg("Failed to find any matching overload, args = ",
799                           Useful.listInParens(args),
800                           ", overload = ",
801                           this));
802        }
803        return best;
804    }
805
806    private SingleFcn bestMatchInternal(List<FValue> args, List<Overload> someOverloads) {
807        SingleFcn best_sfn = null;
808
809        if (debugMatch) {
810            System.err.println("Seeking best match for " + args);
811        }
812
813        for (Overload o : someOverloads) {
814            if (o.getParams() == null) {
815                bug(errorMsg("Unfinished overloaded function ", this));
816            }
817            SingleFcn sfn = o.getFn();
818
819            List<FValue> oargs = args;
820
821            if (sfn instanceof GenericFunctionOrMethod) {
822                GenericFunctionOrMethod gsfn = (GenericFunctionOrMethod) sfn;
823                try {
824                    sfn = EvaluatorBase.inferAndInstantiateGenericFunction(oargs, gsfn, gsfn.getWithin());
825                    if (debugMatch) System.err.println("Inferred from " + gsfn + " to " + sfn);
826                }
827                catch (FortressException pe) {
828                    if (debugMatch) System.err.println("No match for " + gsfn);
829                    continue; // No match, means no dice.
830                }
831
832            } else if (debugMatch) {
833                System.err.println("Trying w/o instantiation: " + sfn);
834            }
835
836            oargs = sfn.fixupArgCount(args);
837
838            // Non-generic, old code.
839            if (oargs != null && argsMatchTypes(oargs, sfn.getDomain()) &&
840                (best_sfn == null || FTypeTuple.moreSpecificThan(sfn.getDomain(), best_sfn.getDomain()))) {
841                best_sfn = sfn;
842            }
843
844        }
845        return best_sfn;
846    }
847
848    /**
849     * @param args
850     * @param args_len
851     * @param i
852     * @param o
853     * @return
854     */
855    private boolean argsMatchTypes(List<FValue> args, Overload o) {
856        List<FType> l = o.getParams();
857        return argsMatchTypes(args, l);
858    }
859
860    public static boolean argsMatchTypes(List<FValue> args, List<FType> l) {
861        for (int j = 0; j < args.size(); j++) {
862            FValue a = args.get(j);
863            FType t = Useful.clampedGet(l, j).deRest();
864            try {
865                if (!t.typeMatch(a)) {
866                    return false;
867                }
868            }
869            catch (FortressException e) {
870                return false;
871            }
872        }
873        return true;
874    }
875
876    /**
877     * @return Returns the overloads.
878     */
879    public List<Overload> getOverloads() {
880        return overloads;
881    }
882
883    /**
884     * To be used for those overloaded functions that are
885     * "correct by construction" and do not require the
886     * very exciting overload consistency test.
887     */
888    public void bless() {
889        if (finishedSecond) return;
890        finishedSecond = true;
891        finishedFirst = true;
892        if (debug) System.err.println("Unlock " + fnName.stringName());
893    }
894
895    /* This code gives overloaded functions the interface of a set of generic
896     * functions.
897     *
898     */
899
900    private class Factory implements Factory1P<List<FType>, Fcn, HasAt> {
901
902        public Fcn make(List<FType> args, HasAt location) {
903            // TODO finish this.
904
905            SingleFcn f = null;
906            OverloadedFunction of = null;
907
908            for (Overload ol : getOverloads()) {
909                SingleFcn sfcn = ol.getFn();
910                if (sfcn instanceof GenericFunctionOrMethod) {
911                    GenericFunctionOrMethod gf = (GenericFunctionOrMethod) sfcn;
912
913                    // Check that args matches the static parameters of the generic function
914                    // TODO -- can a generic instantiation result in an unfulfillable overloading?
915
916                    if (compatible(args, gf.getStaticParams())) {
917
918                        SingleFcn tf = gf.typeApply(args, location);
919                        if (f == null) {
920                            f = tf;
921                        } else if (of == null) {
922                            of = new OverloadedFunction(getFnName(), getWithin());
923                            of.addOverload(f);
924                            of.addOverload(tf);
925                        } else {
926                            of.addOverload(tf);
927                        }
928                    }
929
930                }
931            }
932            if (of != null) {
933                of.finishInitializing();
934                return of;
935            }
936            if (f != null) return f;
937            return error(location, errorMsg("No matches for instantiation of overloaded function ",
938                                            OverloadedFunction.this,
939                                            " with ",
940                                            Useful.listInParens(args)));
941        }
942    }
943
944    Memo1P<List<FType>, Fcn, HasAt> memo = new Memo1P<List<FType>, Fcn, HasAt>(new Factory());
945
946    public Fcn make(List<FType> l, HasAt location) {
947        return memo.make(l, location);
948    }
949
950
951    public static boolean compatible(List<FType> args, List<StaticParam> val) {
952        if (args.size() != val.size()) return false;
953        for (int i = 0; i < args.size(); i++) {
954            // TODO need to make this check more comprehensive and detailed.
955            FType a = args.get(i);
956            StaticParam p = val.get(i);
957            if (NodeUtil.isTypeParam(p)) {
958                if (a instanceof FTypeNat) return false;
959            }
960        }
961        return true;
962    }
963
964    public Fcn typeApply(List<StaticArg> args, Environment e, HasAt location) {
965        EvalType et = new EvalType(e);
966        // TODO Can combine these two functions if we enhance the memo and factory
967        // to pass two parameters instead of one.
968        ArrayList<FType> argValues = et.forStaticArgList(args);
969
970        return typeApply(argValues, location);
971    }
972
973    /**
974     * Same as typeApply, but with the types evaluated already.
975     *
976     * @param args
977     * @param e
978     * @param within
979     * @param argValues
980     * @return
981     * @throws ProgramError
982     */
983    Fcn typeApply(List<FType> argValues, HasAt location) throws ProgramError {
984        // Need to filter for matching generics in the overloaded type.
985        return make(argValues, location);
986    }
987
988
989}
Note: See TracBrowser for help on using the browser.