Skip to content

Commit 7f07e1a

Browse files
committed
Removed Unknown Reference
This removes the concept of an "unknown" reference. This is replaced by a strategy which does not box references to open records. This works because we cannot assign entirely to them.
1 parent 9ac459d commit 7f07e1a

14 files changed

+157
-35
lines changed

src/main/java/wyjs/tasks/JavaScriptCompiler.java

Lines changed: 53 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -443,15 +443,22 @@ public Term constructArrayAccessLVal(Expr.ArrayAccess expr, Term source, Term in
443443

444444
@Override
445445
public Term constructDereferenceLVal(Expr.Dereference expr, Term operand) {
446-
return new PropertyAccess(operand, "$ref");
446+
Type.Reference type = expr.getOperand().getType().as(Type.Reference.class);
447+
//
448+
if (isBoxedType(type)) {
449+
return new PropertyAccess(operand, "$ref");
450+
} else {
451+
return operand;
452+
}
447453
}
448454

449455
@Override
450456
public Term constructFieldDereferenceLVal(Expr.FieldDereference expr, Term operand) {
451-
Type type = expr.getOperand().getType();
457+
Type.Reference type = expr.getOperand().getType().as(Type.Reference.class);
452458
//
453-
if (!isUnknownReference(type)) {
454-
// Known types are explicitly wrapped, whilst unknown types are not.
459+
if (isBoxedType(type)) {
460+
// Immutable types must be explicitly boxed since they cannot be updated in
461+
// place.
455462
operand = new PropertyAccess(operand, "$ref");
456463
}
457464
return new PropertyAccess(operand, expr.getField().get());
@@ -583,14 +590,22 @@ public Term constructConstant(Expr.Constant expr) {
583590

584591
@Override
585592
public Term constructDereference(Expr.Dereference expr, Term operand) {
586-
return new PropertyAccess(operand, "$ref");
593+
Type.Reference type = expr.getOperand().getType().as(Type.Reference.class);
594+
if(isBoxedType(type)) {
595+
// Immutable types must be explicitly boxed since they cannot be updated in
596+
// place.
597+
return new PropertyAccess(operand, "$ref");
598+
} else {
599+
return operand;
600+
}
587601
}
588602

589603
@Override
590604
public Term constructFieldDereference(Expr.FieldDereference expr, Term operand) {
591-
Type type = expr.getOperand().getType();
592-
if (!isUnknownReference(type)) {
593-
// Known types are explicitly wrapped, whilst unknown types are not.
605+
Type.Reference type = expr.getOperand().getType().as(Type.Reference.class);
606+
if (isBoxedType(type)) {
607+
// Immutable types must be explicitly boxed since they cannot be updated in
608+
// place.
594609
operand = new PropertyAccess(operand, "$ref");
595610
}
596611
return new PropertyAccess(operand, expr.getField().get());
@@ -736,8 +751,15 @@ public Term constructLambdaAccess(Expr.LambdaAccess expr) {
736751

737752
@Override
738753
public Term constructNew(Expr.New expr, Term operand) {
739-
// known types must be converted into references
740-
return new Operator(Kind.NEW,WY_REF(operand));
754+
Type.Reference type = expr.getType().as(Type.Reference.class);
755+
//
756+
if (isBoxedType(type)) {
757+
// Immutable types must be boxed as they cannot be updated in place. All other
758+
// types don't need to be boxed.
759+
return new Operator(Kind.NEW,WY_REF(operand));
760+
} else {
761+
return operand;
762+
}
741763
}
742764

743765
@Override
@@ -1991,6 +2013,27 @@ private boolean areStrictSubtypes(Type type, List<? extends Type> types) {
19912013
return true;
19922014
}
19932015

2016+
/**
2017+
* Check whether a given type is immutable or not. An immutable type is one
2018+
* which needs to be boxed for a reference to it to be generated.
2019+
*
2020+
* @return
2021+
*/
2022+
public boolean isBoxedType(Type.Reference type) {
2023+
Type element = type.getElement();
2024+
// Strip away nominal info
2025+
while(element instanceof Type.Nominal) {
2026+
Type.Nominal n = (Type.Nominal) element;
2027+
element = n.getConcreteType();
2028+
}
2029+
//
2030+
if(element instanceof Type.Record) {
2031+
Type.Record r = (Type.Record) element;
2032+
return !r.isOpen();
2033+
} else {
2034+
return true;
2035+
}
2036+
}
19942037

19952038
/**
19962039
* Return true if the type in question can be copied directly. More
@@ -2028,19 +2071,6 @@ private boolean isCopyable(Type type) {
20282071
}
20292072
}
20302073

2031-
private boolean isUnknownReference(Type type) {
2032-
if (type instanceof Type.Reference) {
2033-
Type.Reference t = (Type.Reference) type;
2034-
return t.isUnknown();
2035-
} else if(type instanceof Type.Nominal) {
2036-
Type.Nominal t = (Type.Nominal) type;
2037-
Decl.Type td = t.getLink().getTarget();
2038-
return isUnknownReference(td.getType());
2039-
} else {
2040-
return false;
2041-
}
2042-
}
2043-
20442074
/**
20452075
* Check whether the given type has any subtypes other than that of the given
20462076
* kind. For example, <code>int|{int f}</code> has a subtype other than a record
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
type Handler is { function handler(int)->int }
2+
type nHandler is null | Handler
3+
4+
function instanceof(nHandler attr) -> bool:
5+
if attr is Handler:
6+
return true
7+
else:
8+
return false
9+
10+
function id(int x) -> (int y):
11+
return x
12+
13+
public export method test():
14+
assume instanceof(null) == false
15+
assume instanceof({handler: &id}) == true
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
public export method test():
22
&(int[]) c = new [0,1,2]
33
&(int[]) d = c
4-
*c = [3,4,5]
4+
(*c)[0] = 3
5+
(*c)[1] = 4
6+
(*c)[2] = 5
57
assume (*c) == [3,4,5]
68
assume (*d) == [3,4,5]
79

tests/valid/Reference_Valid_17.whiley

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
public export method test():
22
&(null|(int[])) c = new (null|(int[])) [1,2,3]
33
&(null|(int[])) d = c
4-
*c = [4,5,6]
5-
assume (*c) == [4,5,6]
6-
assume (*d) == [4,5,6]
4+
assume (*c) == [1,2,3]
5+
assume (*d) == [1,2,3]
76
*c = (null|(int[])) null
87
assume (*c) == null
98
assume (*d) == null

tests/valid/Reference_Valid_18.whiley

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@ type Point is {int x, int y}
33
public export method test():
44
&(Point|(int[])) c = new (Point|(int[])) [1,2,3]
55
&(Point|(int[])) d = c
6-
*c = [4,5,6]
7-
assume (*c) == [4,5,6]
8-
assume (*d) == [4,5,6]
6+
assume (*c) == [1,2,3]
7+
assume (*d) == [1,2,3]
98
*c = {x:1,y:2}
109
assume (*c) == {x:1,y:2}
1110
assume (*d) == {x:1,y:2}

tests/valid/Reference_Valid_20.whiley

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ type Element is {
88
}
99
public export method test():
1010
&Element p_elem = new {nodeType:1, nodeValue:2}
11-
&?Node p_node = p_elem
11+
&Node p_node = p_elem
1212
//
1313
assume p_node->nodeType == 1
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
public type Event is { int timeStamp }
2+
public type MouseEvent is { bool altKey }
3+
public type iohandler<E,T> is function(E,T)->(T)
4+
5+
public type MouseEventAttribute<T> is {
6+
iohandler<MouseEvent,T> handler
7+
}
8+
9+
public type Attribute<T> is null | MouseEventAttribute<T>
10+
11+
function f<T>(Attribute<T> attr) -> int:
12+
if attr is MouseEventAttribute<T>:
13+
return 0
14+
else:
15+
return 1
16+
17+
function h(MouseEvent e, int t) -> int:
18+
if e.altKey:
19+
return t + 1
20+
else:
21+
return t - 1
22+
23+
public export method test():
24+
assume f<int>(null) == 1
25+
assume f<int>({handler: &h}) == 0
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
type Handler<T> is { function handler(T)->T }
2+
type nHandler<T> is null | Handler<T>
3+
4+
function instanceof<T>(nHandler<T> attr) -> bool:
5+
if attr is Handler<T>:
6+
return true
7+
else:
8+
return false
9+
10+
function id(int x) -> (int y):
11+
return x
12+
13+
public export method test():
14+
assume instanceof<int>(null) == false
15+
assume instanceof<int>({handler: &id}) == true
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
public type Node<T> is {T f} | int
2+
3+
public function div<T>(Node<T>[] children) -> Node<T>:
4+
return 0
5+
6+
function to_folder_html(Node<int> h) -> Node<int>:
7+
return div([h])
8+
9+
public export method test():
10+
//
11+
assume to_folder_html({f:0}) == 0
12+
assume to_folder_html(0) == 0

tests/valid/Tuple_Valid_6.whiley

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
type handler_t<T> is function(T)->(T,T)
2+
3+
function apply<T>(T k, handler_t<T> h) -> (T a, T b):
4+
return h(k)
5+
6+
function dup(int x) -> (int a, int b)
7+
ensures (a == x) && (a == b):
8+
return (x,x)
9+
10+
public export method test():
11+
assume apply(1,&dup) == (1,1)
12+
assume apply(2,&dup) == (2,2)

0 commit comments

Comments
 (0)