Skip to content

Commit 186c2af

Browse files
committed
Fix generic parameter count
1 parent 676012b commit 186c2af

File tree

4 files changed

+88
-34
lines changed

4 files changed

+88
-34
lines changed

README.md

+4-2
Original file line numberDiff line numberDiff line change
@@ -1310,7 +1310,9 @@ To run scripts as a standalone application you can download the interpreter. The
13101310
be installed on the host machine. Once you have downloaded the interpreter you can begin running scripts right
13111311
away. All you need to do is specify the script file relative to the current directory.
13121312
1313-
Download - [http://tern-lang.org/tern.zip](http://tern-lang.org/tern.zip)
1313+
| Platform | Description | Download |
1314+
| ------------- | ------------- | ------ |
1315+
| Java | Command line interpreter for Java and Android | [Download](http://tern-lang.org/tern.zip) |
13141316
13151317
### Development Environment
13161318
@@ -1324,7 +1326,7 @@ code can be done by setting break points.
13241326
| ------------- | ------------- | ------ |
13251327
| Windows | This build uses Chrome Embedded Framework compatible with 64-bit Windows | [Download](http://tern-lang.org/download/ternd-windows.zip) |
13261328
| Linux | This build uses Chrome Embedded Framework compatible with 64-bit Linux | [Download](http://tern-lang.org/download/ternd-linux.tar.gz) |
1327-
| Mac | This build uses Chrome Embedded Framework compatible with 64-bit Mac | [Download](http://tern-lang.org/download/ternd-mac.tar.gz) |
1329+
| Mac | This build uses Chrome Embedded Framework compatible with 64-bit Mac | [Download](http://tern-lang.org/download/ternd-mac.zip) |
13281330
13291331
#### Breakpoints
13301332

tern-compile/src/test/java/org/ternlang/compile/ModuleTest.java

+25
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,27 @@ public class ModuleTest extends ScriptTestCase {
6464
"}\n"+
6565
"F.call().success(this::println);\n";
6666

67+
private static final String SOURCE_5 =
68+
"import util.concurrent.atomic.AtomicInteger;\n"+
69+
"module TimeParser {\n"+
70+
" const DAYS = ['Mon', 'Tue', 'Wed', 'Thur', 'Fri', 'Sat', 'Sun'];\n"+
71+
"\n"+
72+
" parseTime(time){\n"+
73+
" let count = 0;\n"+
74+
"\n"+
75+
" for(day in DAYS){\n"+
76+
" count++;\n"+
77+
" }\n"+
78+
" return 0;\n"+
79+
" }\n"+
80+
"}\n"+
81+
"\n"+
82+
"let x = TimeParser.parseTime('');\n"+
83+
"let c = AtomicInteger();\n"+
84+
"println(c.getAndIncrement());\n"+
85+
"assert c.get() == 1;\n"+
86+
"Thread.sleep(1000);\n";
87+
6788

6889
public void testModuleInnerClass() throws Exception {
6990
assertScriptExecutes(SOURCE_1);
@@ -100,4 +121,8 @@ public void onException(Context context, Exception result) {
100121
}
101122
});
102123
}
124+
125+
public void testModuleHasOnlyOneThread() throws Exception {
126+
assertScriptExecutes(SOURCE_5);
127+
}
103128
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package org.ternlang.compile.staticanalysis;
2+
3+
public class InvalidGenericCountTest extends CompileTestCase {
4+
5+
private static final String FAILURE_1 =
6+
"func fun<A, B>(a: A): B {\n"+
7+
" return null;\n"+
8+
"}\n"+
9+
"fun<Double, Double, Double>(1.0).intValue();\n";
10+
11+
public void testGenericFunction() throws Exception {
12+
assertCompileError(FAILURE_1, "Generic parameter count for 'default.fun(a: Object)' is invalid in /default.tern at line 4");
13+
}
14+
}

tern-core/src/main/java/org/ternlang/core/constraint/transform/AttributeRule.java

+45-32
Original file line numberDiff line numberDiff line change
@@ -51,46 +51,59 @@ protected Scope getScope(Scope scope) {
5151

5252
if(count > 0) {
5353
ScopeTable table = scope.getTable();
54-
ScopeState state = scope.getState();
55-
Constraint first = table.getConstraint(start);
54+
Address address = AddressCache.getAddress(count);
55+
Constraint parameter = table.getConstraint(address);
56+
57+
if(parameter != null) {
58+
throw new InternalStateException("Generic parameter count for '" + attribute + "' is invalid");
59+
}
60+
return getScope(scope, count);
61+
}
62+
return scope;
63+
}
64+
65+
private Scope getScope(Scope scope, int count) {
66+
List<Constraint> defaults = attribute.getGenerics();
67+
ScopeTable table = scope.getTable();
68+
ScopeState state = scope.getState();
69+
Constraint first = table.getConstraint(start);
5670

57-
for(int i = 0; i < count; i++) {
58-
Address address = AddressCache.getAddress(i);
59-
Constraint parameter = table.getConstraint(address);
60-
Constraint constraint = defaults.get(i);
61-
String name = constraint.getName(scope);
62-
Constraint existing = state.getConstraint(name);
71+
for(int i = 0; i < count; i++) {
72+
Address address = AddressCache.getAddress(i);
73+
Constraint parameter = table.getConstraint(address);
74+
Constraint constraint = defaults.get(i);
75+
String name = constraint.getName(scope);
76+
Constraint existing = state.getConstraint(name);
6377

64-
if(parameter != null) {
65-
Type require = constraint.getType(scope);
66-
Type actual = parameter.getType(scope);
78+
if(parameter != null) {
79+
Type require = constraint.getType(scope);
80+
Type actual = parameter.getType(scope);
6781

68-
if(!checker.isInstanceOf(scope, actual, require)) {
69-
throw new InternalStateException("Generic parameter '" + name +"' does not match '" + constraint + "'");
70-
}
71-
if(existing != null) {
72-
Type current = existing.getType(scope);
82+
if(!checker.isInstanceOf(scope, actual, require)) {
83+
throw new InternalStateException("Generic parameter '" + name +"' does not match '" + constraint + "'");
84+
}
85+
if(existing != null) {
86+
Type current = existing.getType(scope);
7387

74-
if(current != actual) {
75-
throw new InternalStateException("Generic parameter '" + name +"' has already been declared");
76-
}
77-
} else {
78-
state.addConstraint(name, parameter);
88+
if(current != actual) {
89+
throw new InternalStateException("Generic parameter '" + name +"' has already been declared");
7990
}
8091
} else {
81-
if(first != null) {
82-
throw new InternalStateException("Generic parameter '" + name +"' not specified");
83-
}
84-
if(existing != null) {
85-
Type require = mapper.map(scope, constraint);
86-
Type current = mapper.map(scope, existing);
92+
state.addConstraint(name, parameter);
93+
}
94+
} else {
95+
if(first != null) {
96+
throw new InternalStateException("Generic parameter '" + name +"' not specified");
97+
}
98+
if(existing != null) {
99+
Type require = mapper.map(scope, constraint);
100+
Type current = mapper.map(scope, existing);
87101

88-
if (current != require) {
89-
throw new InternalStateException("Generic parameter '" + name + "' has already been declared");
90-
}
91-
} else {
92-
state.addConstraint(name, constraint);
102+
if (current != require) {
103+
throw new InternalStateException("Generic parameter '" + name + "' has already been declared");
93104
}
105+
} else {
106+
state.addConstraint(name, constraint);
94107
}
95108
}
96109
}

0 commit comments

Comments
 (0)