diff options
5 files changed, 40 insertions, 15 deletions
diff --git a/chapter28b/src/main/java/com/seaofnodes/simple/Parser.java b/chapter28b/src/main/java/com/seaofnodes/simple/Parser.java index b9cd9658..8410bf5c 100644 --- a/chapter28b/src/main/java/com/seaofnodes/simple/Parser.java +++ b/chapter28b/src/main/java/com/seaofnodes/simple/Parser.java @@ -101,6 +101,9 @@ public class Parser { ScopeNode _continueScope; // Merge all the while-continues here ScopeNode _returnScope; // Merge all the function exits here Ary<FRefNode> _frefs; // Forward refs created during this parse + // Layouts needed by field accesses in this source file. Resolve after + // parsing, since a later local struct declaration can satisfy the use. + public final LinkedHashSet<String> _requiredTypes = new LinkedHashSet<>(); TypeStruct _ctorOpenStruct; // Open struct being initialized by an allocation constructor block. // Constructor exit types survive scope teardown until all fields are known. // A null entry denotes a constructor with no returning path. @@ -171,6 +174,7 @@ public class Parser { assert _frefs == null; _lexer = new Lexer(ref); _frefs = new Ary<>(FRefNode.class); + _requiredTypes.clear(); // Starting Scope has control, memory, initial arguments _scope = new ScopeNode(); _scope.define(ScopeNode.CTRL, Type.CONTROL , false, null, _lexer); @@ -2751,6 +2755,8 @@ public class Parser { } // Field offset for an unknown type public Node fldoff( Node n, String name ) { + if( n._type instanceof TypeMemPtr ptr && ptr._obj._fref ) + _requiredTypes.add(ptr._obj._name); return new FldOffNode(n,name,loc()).peephole(); } public Node peep( Node n ) { diff --git a/chapter28b/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java b/chapter28b/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java index c2cd657f..561fdece 100644 --- a/chapter28b/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java +++ b/chapter28b/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java @@ -625,14 +625,6 @@ public class CodeGen { // Last check for bad programs public CodeGen typeCheck() { return phase(Phase.TypeCheck, _phase==Phase.FinalizeIR, () -> TypeCheck.run(this)); } - public static TypeStruct requiredStruct(Node n) { - // CNC: remove? cleanup? - if( n instanceof NewNode alloc ) return alloc._ts; - if( n instanceof ConFldOffNode off ) return off._ts; - if( n instanceof FldOffNode off && off.in(0)._type instanceof TypeMemPtr ptr ) return ptr._obj; - return null; - } - // --------------------------- // TypeCheck queued surviving CLInits during its existing error walk. public CodeGen lower() { diff --git a/chapter28b/src/main/java/com/seaofnodes/simple/codegen/ParseAll.java b/chapter28b/src/main/java/com/seaofnodes/simple/codegen/ParseAll.java index 10b8fd9b..1d9731fc 100644 --- a/chapter28b/src/main/java/com/seaofnodes/simple/codegen/ParseAll.java +++ b/chapter28b/src/main/java/com/seaofnodes/simple/codegen/ParseAll.java @@ -198,13 +198,9 @@ public abstract class ParseAll { } private static void addRequiredTypes(CodeGen code, CompUnit cunit) { - LinkedHashSet<String> required = new LinkedHashSet<>(); - code._stop.walk(n -> { - TypeStruct ts = CodeGen.requiredStruct(n); - if( ts!=null && ts._fref ) required.add(ts._name); - return null; - }); - for( String typeName : required ) { + for( String typeName : code.P._requiredTypes ) { + // A forward use can have been resolved later in this source file. + if( Parser.TYPES.get(typeName) instanceof TypeStruct ts && !ts._fref ) continue; try { CompUnit xcunit = findRequiredType(code,cunit,typeName); if( xcunit != null ) diff --git a/chapter28b/src/test/java/com/seaofnodes/simple/IncrementalBuildTest.java b/chapter28b/src/test/java/com/seaofnodes/simple/IncrementalBuildTest.java index 3c53c004..d8f7ef34 100644 --- a/chapter28b/src/test/java/com/seaofnodes/simple/IncrementalBuildTest.java +++ b/chapter28b/src/test/java/com/seaofnodes/simple/IncrementalBuildTest.java @@ -10,6 +10,21 @@ import org.junit.Test; import static org.junit.Assert.*; public class IncrementalBuildTest { + @Test public void testRequiredTypesBelongToTheirSource() throws Exception { + Path base = Path.of("build/objs/incremental"); + Files.createDirectories(base); + Path root = Files.createTempDirectory(base,"required-types-"); + Path src = Files.createDirectory(root.resolve("src")), obj = Files.createDirectory(root.resolve("obj")); + write(src,"App","val marker = 0;",1000); + write(src,"App/Main","return A.x+C.y;",1000); + write(src,"App/A","int x = 0; val readB = { B b -> b.x; };",1000); + write(src,"App/B","int x = 0;",1000); + write(src,"App/C","int y = 0;",1000); + CodeGen code = new CodeGen(src.toString(),obj.toString(),null,"App/Main",null,123,true,TypeInteger.BOT) + .parse(); + ParseAllTestSupport.checkRequiredTypes(code); + } + @Test public void testTransitiveSourceChange() throws Exception { Path base=Path.of("build/objs/incremental"); Files.createDirectories(base); diff --git a/chapter28b/src/test/java/com/seaofnodes/simple/codegen/ParseAllTestSupport.java b/chapter28b/src/test/java/com/seaofnodes/simple/codegen/ParseAllTestSupport.java new file mode 100644 index 00000000..2ce97a8e --- /dev/null +++ b/chapter28b/src/test/java/com/seaofnodes/simple/codegen/ParseAllTestSupport.java @@ -0,0 +1,16 @@ +package com.seaofnodes.simple.codegen; + +import static org.junit.Assert.*; + +public class ParseAllTestSupport { + public static void checkRequiredTypes(CodeGen code) { + CompUnit a = code._compunits.get("App/A"); + CompUnit b = code._compunits.get("App/B"); + CompUnit c = code._compunits.get("App/C"); + assertNotNull(b); + assertTrue(a._deps.find(b)!=-1); + // C was parsed after A, while B's layout was still unresolved. + // Only A used that layout; C must not inherit A's build dependency. + assertNull(c._deps); + } +} |
