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

Revision 2924, 35.2 kB (checked in by jmaessen, 2 days ago)

Constructors for strided ranges. You should now be able to use
strided ranges in for loops and the like. Warning: proper handling of
striding for array, string, etc indexing is not yet in place. Lists
will handle it correctly, but they're an isolated case right now.

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