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 $
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 $