diff options
| author | Cliff Click <cliffc@acm.org> | 2026-09-19 10:30:13 -0700 |
|---|---|---|
| committer | Cliff Click <cliffc@acm.org> | 2026-09-19 10:30:13 -0700 |
| commit | bf3e5632ddf21c109f7ef0f61bcc62e2ed0f9d49 (patch) | |
| tree | be2972819600b0a9790fceb882b5464c7c12857a /chapter22/src/test/java/com/seaofnodes | |
| parent | 200162345900136663027b6deae21d72cf30818c (diff) | |
| download | Simple-bf3e5632ddf21c109f7ef0f61bcc62e2ed0f9d49.tar.gz Simple-bf3e5632ddf21c109f7ef0f61bcc62e2ed0f9d49.zip | |
Handle double-negation preserving not-null knowledge
Diffstat (limited to 'chapter22/src/test/java/com/seaofnodes')
| -rw-r--r-- | chapter22/src/test/java/com/seaofnodes/simple/Chapter10Test.java | 39 | ||||
| -rw-r--r-- | chapter22/src/test/java/com/seaofnodes/simple/Eval2.java | 8 |
2 files changed, 46 insertions, 1 deletions
diff --git a/chapter22/src/test/java/com/seaofnodes/simple/Chapter10Test.java b/chapter22/src/test/java/com/seaofnodes/simple/Chapter10Test.java index 712704db..743d5d85 100644 --- a/chapter22/src/test/java/com/seaofnodes/simple/Chapter10Test.java +++ b/chapter22/src/test/java/com/seaofnodes/simple/Chapter10Test.java @@ -7,6 +7,45 @@ import static org.junit.Assert.fail; public class Chapter10Test { + // Issue #246: null-check guards start in Chapter 10; arrays arrive in Chapter 15. + private static final String NULLABLE_POINT_SOURCE = """ + struct Point { int x; }; + Point?[] !points = new Point?[2]; + points[arg] = new Point { x = 42; }; + Point? p = points[1]; + """; + + @Test + public void testNullGuards() { + for( String body : new String[] { + "if (p != null) return p.x; return -1;", + "if (null != p) return p.x; return -1;", + "if (!!!!p) return p.x; return -1;", + "if (!!!p) return -1; return p.x;", + "int b = !!p; if (b) return p.x + b - 1; return -1;" + } ) { + CodeGen code = new CodeGen(NULLABLE_POINT_SOURCE+body).parse().opto().typeCheck(); + assertEquals(body,"-1",Eval2.eval(code,0)); + assertEquals(body,"42",Eval2.eval(code,1)); + } + } + + @Test + public void testNullGuardErrors() { + for( String body : new String[] { + "return p.x;", + "if (!!points) return p.x; return -1;", + "if (!!p) { int x = p.x; } return p.x;" + } ) { + try { + new CodeGen(NULLABLE_POINT_SOURCE+body).parse().opto().typeCheck(); + fail(body); + } catch( RuntimeException e ) { + assertEquals(body,"Might be null accessing 'x'",e.getMessage()); + } + } + } + @Test public void testFuzzer() { CodeGen code = new CodeGen( diff --git a/chapter22/src/test/java/com/seaofnodes/simple/Eval2.java b/chapter22/src/test/java/com/seaofnodes/simple/Eval2.java index 86f0e9db..8303b2c8 100644 --- a/chapter22/src/test/java/com/seaofnodes/simple/Eval2.java +++ b/chapter22/src/test/java/com/seaofnodes/simple/Eval2.java @@ -269,7 +269,7 @@ public abstract class Eval2 { case MulFNode mlf -> d(mlf.in(1)) * d(mlf.in(2)); case MulNode mul -> x(mul.in(1)) * x(mul.in(2)); case NewNode alloc-> alloc(alloc); - case NotNode not -> x(not.in(1)) == 0 ? 1L : 0L; + case NotNode not -> not(not); case OrNode or -> x(or .in(1)) | x(or .in(2)); case ProjNode proj -> proj._type instanceof TypeMem ? "$mem" : val(proj.in(0)); case ReadOnlyNode read -> val(read.in(1)); @@ -286,6 +286,12 @@ public abstract class Eval2 { }; } + private static Object not( NotNode not ) { + Object n = val(not.in(1)); + return ( n==null || (n instanceof Double D && D==0.0) || n instanceof Long L && L==0 ) + ? 1L : 0L; + } + // Fetch without unboxing, searching up-Frame static Object val( Node n ) { return F.get(n); } // Fetch and unbox as primitive long |
