Просмотр исходного кода

resolve-check step 4b: Check resolves a forward designator's type

Starting the designator resolver.  A forward-reference note now carries
its designator node; FlushForward resolves the name, applies the node's
selectors to the base type (field/index/deref) and stores the result via
AST.SetTy.  A forward designator finally has a real type on the AST
(Lower still re-derives its own for emission).

- SymTab.FwdVarResolve now also returns the resolved type.
- Check gains SelType (selector walk over SymTab.FieldType/ArrayElem/
  PtrBase) and LeafName.
- Design attaches the node to the forward note (fref + astDes).

Verified with a temporary differential instrument in LowerDesign (which
independently computes the same type): clean across the suite (incl.
t_fwdvar) and a forward-array test (FwdSel -> 7), and it fires (299) when
the resolver is deliberately broken.  The instrument was removed again.

Suite 190/190; fixpoint OK (3,474,750 bytes).
Eric Streit 1 день назад
Родитель
Сommit
192ad55812
6 измененных файлов с 187 добавлено и 142 удалено
  1. 4 3
      compiler/src/Check.def
  2. 49 7
      compiler/src/Check.mod
  3. 2 2
      compiler/src/M2.atg
  4. 125 125
      compiler/src/M2.lst
  5. 3 3
      compiler/src/SymTab.def
  6. 4 2
      compiler/src/SymTab.mod

+ 4 - 3
compiler/src/Check.def

@@ -13,9 +13,10 @@ PROCEDURE BeginSession (progName: ARRAY OF CHAR);
 PROCEDURE BeginUnit;
 PROCEDURE BeginUnit;
 (* Per-unit setup (called before Parse). *)
 (* Per-unit setup (called before Parse). *)
 
 
-PROCEDURE NoteForward (id: INTEGER);
-(* Records a forward module-level reference noted by the parser (Design);
-   FlushForward resolves it once the unit's declarations are complete. *)
+PROCEDURE NoteForward (id: INTEGER; node: AST.Node);
+(* Records a forward module-level reference noted by the parser (Design)
+   together with its designator node; FlushForward resolves the name and
+   stores the designator's type on that node. *)
 
 
 PROCEDURE FlushForward;
 PROCEDURE FlushForward;
 (* Resolve every noted forward reference against the unit's declarations;
 (* Resolve every noted forward reference against the unit's declarations;

+ 49 - 7
compiler/src/Check.mod

@@ -3,8 +3,8 @@ IMPLEMENTATION MODULE Check;
 (* Resolve / check pass (two-phase, part 2).  Forward module-level
 (* Resolve / check pass (two-phase, part 2).  Forward module-level
    references (a procedure body naming a variable declared further down)
    references (a procedure body naming a variable declared further down)
    are resolved here, after the unit has been parsed and before Lower:
    are resolved here, after the unit has been parsed and before Lower:
-   the placeholder recorded by Design is bound to the real symbol, so
-   resolution no longer depends on declaration order.  See
+   the designator's real type is computed from the now-visible symbol and
+   its selectors, and stored on the AST node.  See
    docs/plan-resolve-check.md. *)
    docs/plan-resolve-check.md. *)
 
 
 IMPORT AST, SymTab, M2S;
 IMPORT AST, SymTab, M2S;
@@ -14,6 +14,40 @@ CONST MaxFwd = 256;
 VAR
 VAR
   nFwd:  CARDINAL;
   nFwd:  CARDINAL;
   fwdId: ARRAY [0 .. MaxFwd - 1] OF INTEGER;
   fwdId: ARRAY [0 .. MaxFwd - 1] OF INTEGER;
+  fwdNd: ARRAY [0 .. MaxFwd - 1] OF AST.Node;
+
+PROCEDURE LeafName (n: AST.Node; VAR s: SymTab.Name);
+(* Text of an identifier leaf node (its child 0 is the text index). *)
+  BEGIN
+    s[0] := CHR(0);
+    IF n >= 0 THEN AST.Txt(AST.Child(n, 0), s) END
+  END LeafName;
+
+PROCEDURE SelType (n: AST.Node; VAR t: SymTab.TypeIndex);
+(* Applies a designator's selectors to its base type. *)
+  VAR i: CARDINAL; sel, leaf: AST.Node; op: INTEGER; fn: SymTab.Name;
+  BEGIN
+    IF n < 0 THEN RETURN END;
+    i := 1;
+    WHILE (i < AST.NChild(n)) AND (t # SymTab.InvalidType) DO
+      sel := AST.Child(n, i);
+      op := AST.Op(sel);
+      IF op = AST.SelField THEN
+        leaf := AST.Child(sel, 0);
+        LeafName(leaf, fn);
+        IF SymTab.FieldExists(t, fn) THEN t := SymTab.FieldType(t, fn)
+        ELSE t := SymTab.InvalidType
+        END
+      ELSIF op = AST.SelIndex THEN
+        t := SymTab.ArrayElem(t)
+      ELSIF op = AST.SelDeref THEN
+        IF SymTab.ClassOf(t) = SymTab.ClPtr THEN t := SymTab.PtrBase(t)
+        ELSE t := SymTab.InvalidType
+        END
+      END;
+      INC(i)
+    END
+  END SelType;
 
 
 PROCEDURE BeginSession (progName: ARRAY OF CHAR);
 PROCEDURE BeginSession (progName: ARRAY OF CHAR);
 BEGIN
 BEGIN
@@ -24,25 +58,33 @@ PROCEDURE BeginUnit;
 BEGIN
 BEGIN
 END BeginUnit;
 END BeginUnit;
 
 
-PROCEDURE NoteForward (id: INTEGER);
-(* Records a forward reference id noted during parse. *)
+PROCEDURE NoteForward (id: INTEGER; node: AST.Node);
+(* Records a forward reference id and its designator node. *)
 BEGIN
 BEGIN
   IF nFwd <= HIGH(fwdId) THEN
   IF nFwd <= HIGH(fwdId) THEN
     fwdId[nFwd] := id;
     fwdId[nFwd] := id;
+    fwdNd[nFwd] := node;
     INC(nFwd)
     INC(nFwd)
   END
   END
 END NoteForward;
 END NoteForward;
 
 
 PROCEDURE FlushForward;
 PROCEDURE FlushForward;
-(* Resolve every noted forward reference; an unresolved name is 201. *)
+(* Resolve every noted forward reference; store the designator's type on
+   its node; an unresolved name is 201. *)
   VAR k: CARDINAL;
   VAR k: CARDINAL;
       nm: SymTab.Name;
       nm: SymTab.Name;
+      t: SymTab.TypeIndex;
 BEGIN
 BEGIN
   k := 0;
   k := 0;
   WHILE k < nFwd DO
   WHILE k < nFwd DO
     SymTab.FwdVarName(fwdId[k], nm);
     SymTab.FwdVarName(fwdId[k], nm);
-    IF (nm[0] # CHR(0)) AND (NOT SymTab.FwdVarResolve(fwdId[k])) THEN
-      M2S.Error(201, M2S.line, M2S.col, M2S.pos)
+    IF nm[0] # CHR(0) THEN
+      IF SymTab.FwdVarResolve(fwdId[k], t) THEN
+        SelType(fwdNd[k], t);
+        AST.SetTy(fwdNd[k], t)
+      ELSE
+        M2S.Error(201, M2S.line, M2S.col, M2S.pos)
+      END
     END;
     END;
     INC(k)
     INC(k)
   END;
   END;

+ 2 - 2
compiler/src/M2.atg

@@ -2157,7 +2157,6 @@ PRODUCTIONS
                                                k := SymTab.KindVar;
                                                k := SymTab.KindVar;
                                                r := SymTab.FwdVarRef(n, k,
                                                r := SymTab.FwdVarRef(n, k,
                                                  fref, t);
                                                  fref, t);
-                                                Check.NoteForward(fref);
                                                 QbeGen.CopyOp("@", q);
                                                 QbeGen.CopyOp("@", q);
                                                sfx := TRUE; fwd := TRUE
                                                sfx := TRUE; fwd := TRUE
                                              ELSE
                                              ELSE
@@ -2281,7 +2280,8 @@ PRODUCTIONS
                                            END; .)
                                            END; .)
       (. astDes := AST.MakeNode(AST.NkDesignator);
       (. astDes := AST.MakeNode(AST.NkDesignator);
          AST.SetChild(astDes, AST.NChild(astDes), AST.MakeLeaf(AST.NkIdent, n));
          AST.SetChild(astDes, AST.NChild(astDes), AST.MakeLeaf(AST.NkIdent, n));
-         IF fwd THEN AST.SetOp(astDes, 1) END; .)
+         IF fwd THEN AST.SetOp(astDes, 1) END;
+          IF fwd THEN Check.NoteForward(fref, astDes) END; .)
       { "[" Expr<it, iq>
       { "[" Expr<it, iq>
                                         (. AST.SetChild(astDes, AST.NChild(astDes),
                                         (. AST.SetChild(astDes, AST.NChild(astDes),
              AST.MakeUn(AST.NkSelector, AST.SelIndex, astCur)); IF t = SymTab.InvalidType THEN
              AST.MakeUn(AST.NkSelector, AST.SelIndex, astCur)); IF t = SymTab.InvalidType THEN

+ 125 - 125
compiler/src/M2.lst

@@ -2176,131 +2176,131 @@ Listing:
  2157                                                 k := SymTab.KindVar;
  2157                                                 k := SymTab.KindVar;
  2158                                                 r := SymTab.FwdVarRef(n, k,
  2158                                                 r := SymTab.FwdVarRef(n, k,
  2159                                                   fref, t);
  2159                                                   fref, t);
- 2160                                                  Check.NoteForward(fref);
- 2161                                                  QbeGen.CopyOp("@", q);
- 2162                                                 sfx := TRUE; fwd := TRUE
- 2163                                               ELSE
- 2164                                                 SemError(201);
- 2165                                                 t :=
- 2166                                                   SymTab.InvalidType;
- 2167                                                 k := -1;
- 2168                                                 QbeGen.CopyOp("0", q)
- 2169                                               END
- 2170                                             ELSE
- 2171                                               t := SymTab.SymType(n);
- 2172                                               k := SymTab.SymKind(n);
- 2173                                               IF k = SymTab.KindConst THEN
- 2174                                                 IF SymTab.Equal(n,
- 2175                                                    "TRUE") THEN
- 2176                                                   t := SymTab.BoolType();
- 2177                                                   QbeGen.CopyOp("1", q)
- 2178                                                 ELSIF SymTab.Equal(n,
- 2179                                                    "FALSE") THEN
- 2180                                                   t := SymTab.BoolType();
- 2181                                                   QbeGen.CopyOp("0", q)
- 2182                                                 ELSIF SymTab.Equal(n,
- 2183                                                    "NIL") THEN
- 2184                                                   QbeGen.CopyOp("0", q)
- 2185                                                 ELSE
- 2186                                                   cls :=
- 2187                                                     SymTab.ClassOf(t);
- 2188                                                   IF (t #
- 2189                                                       SymTab.InvalidType)
- 2190   AND ((cls = SymTab.ClInt)
- 2191                                                      OR (cls
- 2192                                                          = SymTab.ClChar)
- 2193                                                      OR (cls
- 2194                                                          = SymTab.ClEnum)
- 2195                                                      OR (cls
- 2196                                                          = SymTab.ClReal)
- 2197                                                      OR (cls
- 2198                                                          = SymTab.ClLong)
- 2199                                                      OR (cls
- 2200                                                          = SymTab.ClNil)) THEN
- 2201                                                     IF cls = SymTab.ClNil THEN
- 2202                                                       QbeGen.CopyOp("0", q)
- 2203                                                     ELSIF ((cls
- 2204                                                         = SymTab.ClInt)
- 2205                                                       OR (cls
- 2206                                                         = SymTab.ClChar)
- 2207                                                       OR (cls
- 2208                                                         = SymTab.ClEnum)
- 2209                                                       OR (cls
- 2210                                                         = SymTab.ClLong))
- 2211    AND SymTab.GetSymVal(n, cv)
- 2212    AND QbeGen.IsImm(cv) THEN
- 2213                                                       QbeGen.CopyOp(cv, q)
- 2214                                                     ELSE
- 2215                                                       QbeGen.LoadVar(n,
- 2216                                                         cls = SymTab.ClReal,
- 2217                                                         q)
- 2218                                                     END
- 2219                                                   ELSIF (cls = SymTab.ClArray)
- 2220                                                      OR (cls = SymTab.ClRecord)
- 2221                                                      OR (cls = SymTab.ClClass)
- 2222                                                      OR (cls = SymTab.ClStr)
- 2223                                                      OR (cls = SymTab.ClUStr) THEN
- 2224                                                     (* aggregate constant:
- 2225                                                        its value IS the
- 2226                                                        descriptor address *)
- 2227                                                     IF SymTab.GetSymVal(n, cv) THEN
- 2228                                                       QbeGen.CopyOp(cv, q)
- 2229                                                     ELSE
- 2230                                                       QbeGen.CopyOp("0", q)
- 2231                                                     END
- 2232                                                   ELSE
- 2233                                                     IF t #
- 2234                                                        SymTab.InvalidType THEN
- 2235                                                       SemError(230)
- 2236                                                     END;
- 2237                                                     QbeGen.CopyOp("0", q)
- 2238                                                   END
- 2239                                                 END
- 2240                                               ELSIF (k = SymTab.KindVar)
- 2241                                                  OR (k = SymTab.KindParam) THEN
- 2242                                                 cls := SymTab.ClassOf(t);
- 2243                                                 IF (cls # SymTab.ClInt)
- 2244                                                    AND (cls # SymTab.ClBool)
- 2245                                                    AND (cls # SymTab.ClChar)
- 2246                                                    AND (cls # SymTab.ClUChar)
- 2247                                                    AND (cls # SymTab.ClEnum)
- 2248                                                    AND (cls # SymTab.ClReal)
- 2249                                                    AND (cls # SymTab.ClPtr)
- 2250                                                    AND (cls # SymTab.ClProc)
- 2251                                                    AND (cls # SymTab.ClLong)
- 2252                                                    AND (cls # SymTab.ClArray)
- 2253                                                    AND (cls # SymTab.ClSet)
- 2254                                                    AND (cls # SymTab.ClRecord)
- 2255                                                    AND (cls # SymTab.ClUStr)
- 2256                                                    AND (cls # SymTab.ClClass) THEN
- 2257                                                   SemError(230);
- 2258                                                   QbeGen.CopyOp("0", q)
- 2259                                                 ELSE QbeGen.CopyOp("@", q)
- 2260                                                 END
- 2261                                               ELSE QbeGen.CopyOp("0", q);
- 2262                                                 IF k = SymTab.KindImport THEN
- 2263                                                   SemError(230)
- 2264                                                 ELSIF k =
- 2265                                                    SymTab.KindProc THEN
- 2266                                                   (* bare procedure name:
- 2267                                                      a following ArgList
- 2268                                                      makes it a call;
- 2269                                                      otherwise Fact
- 2270                                                      reports 230 *)
- 2271                                                 ELSE
- 2272                                                    IF k = SymTab.KindField THEN
- 2273                                                      IF QbeGen.TopWith(qb) THEN
- 2274                                                        sfx := TRUE
- 2275                                                      ELSE SemError(230);
- 2276                                                        QbeGen.CopyOp("0", q)
- 2277                                                      END
- 2278                                                    END
- 2279                                                 END
- 2280                                               END
- 2281                                             END; .)
- 2282        (. astDes := AST.MakeNode(AST.NkDesignator);
- 2283           AST.SetChild(astDes, AST.NChild(astDes), AST.MakeLeaf(AST.NkIdent, n));
- 2284           IF fwd THEN AST.SetOp(astDes, 1) END; .)
+ 2160                                                  QbeGen.CopyOp("@", q);
+ 2161                                                 sfx := TRUE; fwd := TRUE
+ 2162                                               ELSE
+ 2163                                                 SemError(201);
+ 2164                                                 t :=
+ 2165                                                   SymTab.InvalidType;
+ 2166                                                 k := -1;
+ 2167                                                 QbeGen.CopyOp("0", q)
+ 2168                                               END
+ 2169                                             ELSE
+ 2170                                               t := SymTab.SymType(n);
+ 2171                                               k := SymTab.SymKind(n);
+ 2172                                               IF k = SymTab.KindConst THEN
+ 2173                                                 IF SymTab.Equal(n,
+ 2174                                                    "TRUE") THEN
+ 2175                                                   t := SymTab.BoolType();
+ 2176                                                   QbeGen.CopyOp("1", q)
+ 2177                                                 ELSIF SymTab.Equal(n,
+ 2178                                                    "FALSE") THEN
+ 2179                                                   t := SymTab.BoolType();
+ 2180                                                   QbeGen.CopyOp("0", q)
+ 2181                                                 ELSIF SymTab.Equal(n,
+ 2182                                                    "NIL") THEN
+ 2183                                                   QbeGen.CopyOp("0", q)
+ 2184                                                 ELSE
+ 2185                                                   cls :=
+ 2186                                                     SymTab.ClassOf(t);
+ 2187                                                   IF (t #
+ 2188                                                       SymTab.InvalidType)
+ 2189   AND ((cls = SymTab.ClInt)
+ 2190                                                      OR (cls
+ 2191                                                          = SymTab.ClChar)
+ 2192                                                      OR (cls
+ 2193                                                          = SymTab.ClEnum)
+ 2194                                                      OR (cls
+ 2195                                                          = SymTab.ClReal)
+ 2196                                                      OR (cls
+ 2197                                                          = SymTab.ClLong)
+ 2198                                                      OR (cls
+ 2199                                                          = SymTab.ClNil)) THEN
+ 2200                                                     IF cls = SymTab.ClNil THEN
+ 2201                                                       QbeGen.CopyOp("0", q)
+ 2202                                                     ELSIF ((cls
+ 2203                                                         = SymTab.ClInt)
+ 2204                                                       OR (cls
+ 2205                                                         = SymTab.ClChar)
+ 2206                                                       OR (cls
+ 2207                                                         = SymTab.ClEnum)
+ 2208                                                       OR (cls
+ 2209                                                         = SymTab.ClLong))
+ 2210    AND SymTab.GetSymVal(n, cv)
+ 2211    AND QbeGen.IsImm(cv) THEN
+ 2212                                                       QbeGen.CopyOp(cv, q)
+ 2213                                                     ELSE
+ 2214                                                       QbeGen.LoadVar(n,
+ 2215                                                         cls = SymTab.ClReal,
+ 2216                                                         q)
+ 2217                                                     END
+ 2218                                                   ELSIF (cls = SymTab.ClArray)
+ 2219                                                      OR (cls = SymTab.ClRecord)
+ 2220                                                      OR (cls = SymTab.ClClass)
+ 2221                                                      OR (cls = SymTab.ClStr)
+ 2222                                                      OR (cls = SymTab.ClUStr) THEN
+ 2223                                                     (* aggregate constant:
+ 2224                                                        its value IS the
+ 2225                                                        descriptor address *)
+ 2226                                                     IF SymTab.GetSymVal(n, cv) THEN
+ 2227                                                       QbeGen.CopyOp(cv, q)
+ 2228                                                     ELSE
+ 2229                                                       QbeGen.CopyOp("0", q)
+ 2230                                                     END
+ 2231                                                   ELSE
+ 2232                                                     IF t #
+ 2233                                                        SymTab.InvalidType THEN
+ 2234                                                       SemError(230)
+ 2235                                                     END;
+ 2236                                                     QbeGen.CopyOp("0", q)
+ 2237                                                   END
+ 2238                                                 END
+ 2239                                               ELSIF (k = SymTab.KindVar)
+ 2240                                                  OR (k = SymTab.KindParam) THEN
+ 2241                                                 cls := SymTab.ClassOf(t);
+ 2242                                                 IF (cls # SymTab.ClInt)
+ 2243                                                    AND (cls # SymTab.ClBool)
+ 2244                                                    AND (cls # SymTab.ClChar)
+ 2245                                                    AND (cls # SymTab.ClUChar)
+ 2246                                                    AND (cls # SymTab.ClEnum)
+ 2247                                                    AND (cls # SymTab.ClReal)
+ 2248                                                    AND (cls # SymTab.ClPtr)
+ 2249                                                    AND (cls # SymTab.ClProc)
+ 2250                                                    AND (cls # SymTab.ClLong)
+ 2251                                                    AND (cls # SymTab.ClArray)
+ 2252                                                    AND (cls # SymTab.ClSet)
+ 2253                                                    AND (cls # SymTab.ClRecord)
+ 2254                                                    AND (cls # SymTab.ClUStr)
+ 2255                                                    AND (cls # SymTab.ClClass) THEN
+ 2256                                                   SemError(230);
+ 2257                                                   QbeGen.CopyOp("0", q)
+ 2258                                                 ELSE QbeGen.CopyOp("@", q)
+ 2259                                                 END
+ 2260                                               ELSE QbeGen.CopyOp("0", q);
+ 2261                                                 IF k = SymTab.KindImport THEN
+ 2262                                                   SemError(230)
+ 2263                                                 ELSIF k =
+ 2264                                                    SymTab.KindProc THEN
+ 2265                                                   (* bare procedure name:
+ 2266                                                      a following ArgList
+ 2267                                                      makes it a call;
+ 2268                                                      otherwise Fact
+ 2269                                                      reports 230 *)
+ 2270                                                 ELSE
+ 2271                                                    IF k = SymTab.KindField THEN
+ 2272                                                      IF QbeGen.TopWith(qb) THEN
+ 2273                                                        sfx := TRUE
+ 2274                                                      ELSE SemError(230);
+ 2275                                                        QbeGen.CopyOp("0", q)
+ 2276                                                      END
+ 2277                                                    END
+ 2278                                                 END
+ 2279                                               END
+ 2280                                             END; .)
+ 2281        (. astDes := AST.MakeNode(AST.NkDesignator);
+ 2282           AST.SetChild(astDes, AST.NChild(astDes), AST.MakeLeaf(AST.NkIdent, n));
+ 2283           IF fwd THEN AST.SetOp(astDes, 1) END;
+ 2284            IF fwd THEN Check.NoteForward(fref, astDes) END; .)
  2285        { "[" Expr<it, iq>
  2285        { "[" Expr<it, iq>
  2286                                          (. AST.SetChild(astDes, AST.NChild(astDes),
  2286                                          (. AST.SetChild(astDes, AST.NChild(astDes),
  2287               AST.MakeUn(AST.NkSelector, AST.SelIndex, astCur)); IF t = SymTab.InvalidType THEN
  2287               AST.MakeUn(AST.NkSelector, AST.SelIndex, astCur)); IF t = SymTab.InvalidType THEN

+ 3 - 3
compiler/src/SymTab.def

@@ -451,9 +451,9 @@ PROCEDURE FwdVarRef (name: ARRAY OF CHAR; kind: INTEGER;
 
 
 PROCEDURE FwdVarName (id: INTEGER; VAR name: Name);
 PROCEDURE FwdVarName (id: INTEGER; VAR name: Name);
 (* The identifier behind forward reference id (1-based). *)
 (* The identifier behind forward reference id (1-based). *)
-PROCEDURE FwdVarResolve (id: INTEGER): BOOLEAN;
-(* Resolves forward reference id against the module's declarations:
-   TRUE when the name now exists with the expected kind. *)
+PROCEDURE FwdVarResolve (id: INTEGER; VAR t: TypeIndex): BOOLEAN;
+(* Resolves forward reference id against the unit's declarations: TRUE
+   when the name now exists with the expected kind; t is its type. *)
 
 
 PROCEDURE IntType (): TypeIndex;
 PROCEDURE IntType (): TypeIndex;
 PROCEDURE UCharType (): TypeIndex;
 PROCEDURE UCharType (): TypeIndex;

+ 4 - 2
compiler/src/SymTab.mod

@@ -2610,13 +2610,14 @@ PROCEDURE FwdVarRef (name: ARRAY OF CHAR; kind: INTEGER;
     RETURN TRUE
     RETURN TRUE
   END FwdVarRef;
   END FwdVarRef;
 
 
-PROCEDURE FwdVarResolve (id: INTEGER): BOOLEAN;
+PROCEDURE FwdVarResolve (id: INTEGER; VAR t: TypeIndex): BOOLEAN;
 (* Resolves forward reference id against the unit's declarations.  The
 (* Resolves forward reference id against the unit's declarations.  The
    scope recorded at reference time is used, so this may run after the
    scope recorded at reference time is used, so this may run after the
    module scope has been popped (the resolve/check pass).
    module scope has been popped (the resolve/check pass).
-   TRUE when the name now exists with the expected kind. *)
+   TRUE when the name now exists with the expected kind; t is its type. *)
   VAR node: SymPtr;
   VAR node: SymPtr;
   BEGIN
   BEGIN
+    t := InvalidType;
     IF (id < 1) OR (id > VAL(INTEGER, nFwdVar)) THEN RETURN TRUE END;
     IF (id < 1) OR (id > VAL(INTEGER, nFwdVar)) THEN RETURN TRUE END;
     node := FindScope(fwdVarName[id - 1], fwdVarScope[id - 1]);
     node := FindScope(fwdVarName[id - 1], fwdVarScope[id - 1]);
     IF node = NIL THEN RETURN FALSE END;
     IF node = NIL THEN RETURN FALSE END;
@@ -2627,6 +2628,7 @@ PROCEDURE FwdVarResolve (id: INTEGER): BOOLEAN;
         RETURN FALSE
         RETURN FALSE
       END
       END
     END;
     END;
+    t := node^.typ;
     RETURN TRUE
     RETURN TRUE
   END FwdVarResolve;
   END FwdVarResolve;