Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4682458

generics: stack overflow during type inference

XMLWordPrintable

    • mantis
    • generic
    • solaris_8

      The following (probably broken) implementation of purely functional
      balanced binary trees in GJ causes the prototype JSR14 compiler to
      crash with a stack overflow with apparently infinite recursion in
      type inference. No diagnostic precedes the crash, so I have no workaround.

      frog:~/gjc-work/Functional $ ls -la
      total 9
      drwxrwxr-x 3 gafter 512 May 9 10:59 .
      drwxr-sr-x 25 gafter 1024 May 2 16:12 ..
      -rw-rw-r-- 1 gafter 64 Apr 27 22:33 Makefile
      -rw-rw-r-- 1 gafter 128 Apr 27 21:00 Map.java
      -rw-rw-r-- 1 gafter 3880 May 9 10:51 TreeMap.java
      drwxr-xr-x 2 gafter 512 May 9 10:59 classes
      frog:~/gjc-work/Functional $ cat Makefile
      all:
              newjavac -gj -source 1.4 -d classes Map.java TreeMap.java
      frog:~/gjc-work/Functional $ cat Map.java
      package java.func;

      interface Map<K,V> {
          Map<K,V> put(K key, V value);
          V get(K key);
          Map<K,V> remove(Object key);
      }
      frog:~/gjc-work/Functional $ cat TreeMap.java
      package java.func;

      class TreeMap<K extends Comparable<K>,V> implements Map<K,V> {
          private static final int MAXDEPTHDIFF = 1;

          final TreeMap<K,V> left;
          final K key;
          final V value;
          final TreeMap<K,V> right;
          final int depth;

          private static TreeMap EMPTY = new TreeMap();
          private TreeMap() {
              return; // use default values
          }
          private TreeMap(TreeMap<K,V> left,
                          K key,
                          V value,
                          TreeMap<K,V> right) {
              this.left = left;
              this.key = key;
              this.value = value;
              this.right = right;
              this.depth = max(left.depth, right.depth) + 1;
          }
          private static int max(int left, int right) {
              return (left < right) ? right : left;
          }
          private static
              <K extends Comparable<K>,V>
                         TreeMap<K,V>
                         make(TreeMap<K,V> left,
                              K key,
                              V value,
                              TreeMap<K,V> right) {
              assert (left.depth + MAXDEPTHDIFF) >= right.depth;
              assert (right.depth + MAXDEPTHDIFF) >= left.depth;
              return new TreeMap<K,V>(left, key, value, right);
          }

          private static
              <K extends Comparable<K>,V>
                         TreeMap<K,V>
                         concat(TreeMap<K,V> left,
                                K key,
                                V value,
                                TreeMap<K,V> right) {
              return
                  (left.depth > right.depth+MAXDEPTHDIFF)
                  ? concat(left.left,
                           left.key, left.value,
                           concat(left.right, key, value, right))
                  : (left.depth+MAXDEPTHDIFF < right.depth)
                  ? concat(concat(left, key, value, right.left),
                           right.key, right.value,
                           right.right)
                  : make(left, key, value, right);
          }

          private static
              <K extends Comparable<K>,V>
                         TreeMap<K,V>
                         concat(TreeMap<K,V> left, TreeMap<K,V> right) {
              return (left.depth >= right.depth)
                  ? concat(left.left, left.key, left.value, concat(left.right, right))
                  : concat(concat(left, right.left), right.key, right.value, right.right);
          }

          public static
              <K extends Comparable<K>,V>
                         TreeMap<K,V>
                         create() {
              return (TreeMap<K,V>) EMPTY;
          }

          public TreeMap<K,V> put(K key, V value) {
              if (this == EMPTY)
                  return make(this, key, value, this);
              int compare = key.compareTo(this.key);
              return
                  (compare == 0) ? make(this.left, key, value, this.right)
                  : (compare < 0) ? concat(this.left.put(key, value), this.right)
                  : concat(this.left, this.right.put(key, value));
          }

          public V get(K key) {
              if (this == EMPTY) return null;
              int compare = key.compareTo(this.key);
              return
                  (compare == 0) ? value
                  : (compare < 0) ? left.get(key)
                  : right.get(key);
          }

          public TreeMap<K,V> remove(Object key) {
              if (this == EMPTY) return this;
              int compare = key.compareTo(this.key);
              if (compare == 0) return concat(this.left, this.right);
              if (compare < 0) {
                  TreeMap<K,V> newLeft = left.remove(key);
                  return
                      (newLeft == left) ? this
                      : concat(newLeft, this.key, this.value, this.right);
              }
              assert compare > 0;
              TreeMap<K,V> newRight = right.remove(key);
              return
                  (newRight == right) ? this
                  : concat(this.left, this.key, this.value, newRight);
          }

          public static void main(String[] args) {
              int n = 1000;
              Integer[] keys = new Integer[n];
              Integer[] values = new Integer[n];
              TreeMap<Integer,Integer> map = TreeMap.create();
              for (int i=0; i<n; i++) {
                  Integer key = keys[i] = new Integer(10*i + Math.random(10));
                  Integer value = values[i] = new Integer(Math.random(n<<1));
                  map = map.put(key, value);
              }
              for (int i=0; i<n; i++) {
                  Integer value = map.get(keys[i]);
                  if (value != values[i]) throw new Error(String.valueOf(value));
              }
              for (int i=0; i<n/2; i++) {
                  Integer value = map.get(keys[i]);
                  map = map.remove(value);
              }
              for (int i=0; i<n/2; i++) {
                  Integer value = map.get(keys[i]);
                  if (value != null) throw new Error(String.valueOf(values[i]));
              }
              for (int i=n/2; i<n; i++) {
                  Integer value = map.get(keys[i]);
                  if (value != values[i]) throw new Error(String.valueOf(value));
              }
          }
      }
      frog:~/gjc-work/Functional $ newjavac -gj -source 1.4 *.java 2>&1 | head -25


      The system is out of resources.
      Consult the following stack trace for details.
      java.lang.StackOverflowError
              at com.sun.tools.javac.v8.code.Type$ClassType.map(Type.java:899)
              at com.sun.tools.javac.v8.comp.Infer$4.apply(Infer.java:284)
              at com.sun.tools.javac.v8.comp.Infer$4.apply(Infer.java:282)
              at com.sun.tools.javac.v8.code.Type.map(Type.java:87)
              at com.sun.tools.javac.v8.code.Type$ClassType.map(Type.java:902)
              at com.sun.tools.javac.v8.comp.Infer$4.apply(Infer.java:284)
              at com.sun.tools.javac.v8.comp.Infer$4.apply(Infer.java:282)
              at com.sun.tools.javac.v8.code.Type.map(Type.java:87)
              at com.sun.tools.javac.v8.code.Type$ClassType.map(Type.java:902)
              at com.sun.tools.javac.v8.comp.Infer$4.apply(Infer.java:284)
              at com.sun.tools.javac.v8.comp.Infer$4.apply(Infer.java:282)
              at com.sun.tools.javac.v8.code.Type.map(Type.java:87)
              at com.sun.tools.javac.v8.code.Type$ClassType.map(Type.java:902)
              at com.sun.tools.javac.v8.comp.Infer$4.apply(Infer.java:284)
              at com.sun.tools.javac.v8.comp.Infer$4.apply(Infer.java:282)
              at com.sun.tools.javac.v8.code.Type.map(Type.java:87)
              at com.sun.tools.javac.v8.code.Type$ClassType.map(Type.java:902)
              at com.sun.tools.javac.v8.comp.Infer$4.apply(Infer.java:284)
              at com.sun.tools.javac.v8.comp.Infer$4.apply(Infer.java:282)
              at com.sun.tools.javac.v8.code.Type.map(Type.java:87)
      frog:~/gjc-work/Functional $

            gafter Neal Gafter (Inactive)
            gafter Neal Gafter (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: